@contentful/experiences-visual-editor-react 1.42.4-prerelease-20250702T1207-37b3bfc.0 → 2.0.0-beta.1
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 +3 -2
- package/dist/index.js +736 -189
- package/dist/index.js.map +1 -1
- package/dist/renderApp.js +3589 -3042
- package/dist/renderApp.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import styleInject from 'style-inject';
|
|
2
2
|
import React, { useEffect, useRef, useState, useCallback, forwardRef, useLayoutEffect, useMemo } from 'react';
|
|
3
3
|
import { z } from 'zod';
|
|
4
|
-
import { omit, isArray, isEqual, get as get$
|
|
4
|
+
import { omit, isArray, isEqual, get as get$2 } from 'lodash-es';
|
|
5
5
|
import md5 from 'md5';
|
|
6
6
|
import { BLOCKS } from '@contentful/rich-text-types';
|
|
7
|
-
import { create } from 'zustand';
|
|
7
|
+
import { create, useStore } from 'zustand';
|
|
8
8
|
import { Droppable, Draggable, DragDropContext } from '@hello-pangea/dnd';
|
|
9
9
|
import { produce } from 'immer';
|
|
10
10
|
import '@contentful/rich-text-react-renderer';
|
|
@@ -126,14 +126,6 @@ const CF_STYLE_ATTRIBUTES = [
|
|
|
126
126
|
'cfTextBold',
|
|
127
127
|
'cfTextItalic',
|
|
128
128
|
'cfTextUnderline',
|
|
129
|
-
// For backwards compatibility
|
|
130
|
-
// we need to keep those in this constant array
|
|
131
|
-
// so that omit() in <VisualEditorBlock> and <CompositionBlock>
|
|
132
|
-
// can filter them out and not pass as props
|
|
133
|
-
'cfBackgroundImageScaling',
|
|
134
|
-
'cfBackgroundImageAlignment',
|
|
135
|
-
'cfBackgroundImageAlignmentVertical',
|
|
136
|
-
'cfBackgroundImageAlignmentHorizontal',
|
|
137
129
|
];
|
|
138
130
|
const EMPTY_CONTAINER_HEIGHT$1 = '80px';
|
|
139
131
|
const DEFAULT_IMAGE_WIDTH = '500px';
|
|
@@ -1099,6 +1091,24 @@ propertyName, resolveDesignTokens = true) => {
|
|
|
1099
1091
|
return valuesByBreakpoint;
|
|
1100
1092
|
}
|
|
1101
1093
|
};
|
|
1094
|
+
/** Overwrites the default value breakpoint by breakpoint. If a breakpoint
|
|
1095
|
+
* is not overwritten, it will fall back to the default. */
|
|
1096
|
+
function mergeDesignValuesByBreakpoint(defaultValue, overwriteValue) {
|
|
1097
|
+
if (!defaultValue || !overwriteValue) {
|
|
1098
|
+
return defaultValue ?? overwriteValue;
|
|
1099
|
+
}
|
|
1100
|
+
const mergedValuesByBreakpoint = { ...defaultValue.valuesByBreakpoint };
|
|
1101
|
+
for (const [breakpointId, value] of Object.entries(overwriteValue.valuesByBreakpoint)) {
|
|
1102
|
+
if (!isValidBreakpointValue(value)) {
|
|
1103
|
+
continue;
|
|
1104
|
+
}
|
|
1105
|
+
mergedValuesByBreakpoint[breakpointId] = value;
|
|
1106
|
+
}
|
|
1107
|
+
return {
|
|
1108
|
+
type: 'DesignValue',
|
|
1109
|
+
valuesByBreakpoint: mergedValuesByBreakpoint,
|
|
1110
|
+
};
|
|
1111
|
+
}
|
|
1102
1112
|
|
|
1103
1113
|
const CF_DEBUG_KEY$1 = 'cf_debug';
|
|
1104
1114
|
/**
|
|
@@ -1220,11 +1230,19 @@ const getElementCoordinates = (element) => {
|
|
|
1220
1230
|
});
|
|
1221
1231
|
};
|
|
1222
1232
|
|
|
1223
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1224
1233
|
const isLinkToAsset = (variable) => {
|
|
1225
|
-
if (
|
|
1234
|
+
if (variable === null || typeof variable !== 'object')
|
|
1235
|
+
return false;
|
|
1236
|
+
// The `'prop' in` pattern is informing TypeScript of the object shape, no need to cast `as`.
|
|
1237
|
+
if (!('sys' in variable))
|
|
1226
1238
|
return false;
|
|
1227
|
-
if (typeof variable !== 'object')
|
|
1239
|
+
if (variable.sys === null || typeof variable.sys !== 'object')
|
|
1240
|
+
return false;
|
|
1241
|
+
if (!('linkType' in variable.sys))
|
|
1242
|
+
return false;
|
|
1243
|
+
if (!('id' in variable.sys))
|
|
1244
|
+
return false;
|
|
1245
|
+
if (!('type' in variable.sys))
|
|
1228
1246
|
return false;
|
|
1229
1247
|
return (variable.sys?.linkType === 'Asset' &&
|
|
1230
1248
|
typeof variable.sys?.id === 'string' &&
|
|
@@ -1232,20 +1250,20 @@ const isLinkToAsset = (variable) => {
|
|
|
1232
1250
|
variable.sys?.type === 'Link');
|
|
1233
1251
|
};
|
|
1234
1252
|
|
|
1235
|
-
const isLink = (maybeLink) => {
|
|
1253
|
+
const isLink$1 = (maybeLink) => {
|
|
1236
1254
|
if (maybeLink === null)
|
|
1237
1255
|
return false;
|
|
1238
1256
|
if (typeof maybeLink !== 'object')
|
|
1239
1257
|
return false;
|
|
1240
1258
|
const link = maybeLink;
|
|
1241
|
-
return Boolean(link.sys?.id) && link.sys?.type === 'Link';
|
|
1259
|
+
return Boolean(link.sys?.id) && link.sys?.type === 'Link' && Boolean(link.sys?.linkType);
|
|
1242
1260
|
};
|
|
1243
1261
|
|
|
1244
1262
|
/**
|
|
1245
1263
|
* This module encapsulates format of the path to a deep reference.
|
|
1246
1264
|
*/
|
|
1247
|
-
const parseDataSourcePathIntoFieldset = (path) => {
|
|
1248
|
-
const parsedPath = parseDeepPath(path);
|
|
1265
|
+
const parseDataSourcePathIntoFieldset$1 = (path) => {
|
|
1266
|
+
const parsedPath = parseDeepPath$1(path);
|
|
1249
1267
|
if (null === parsedPath) {
|
|
1250
1268
|
throw new Error(`Cannot parse path '${path}' as deep path`);
|
|
1251
1269
|
}
|
|
@@ -1258,7 +1276,7 @@ const parseDataSourcePathIntoFieldset = (path) => {
|
|
|
1258
1276
|
* @returns
|
|
1259
1277
|
*/
|
|
1260
1278
|
const parseDataSourcePathWithL1DeepBindings = (path) => {
|
|
1261
|
-
const parsedPath = parseDeepPath(path);
|
|
1279
|
+
const parsedPath = parseDeepPath$1(path);
|
|
1262
1280
|
if (null === parsedPath) {
|
|
1263
1281
|
throw new Error(`Cannot parse path '${path}' as deep path`);
|
|
1264
1282
|
}
|
|
@@ -1275,14 +1293,14 @@ const parseDataSourcePathWithL1DeepBindings = (path) => {
|
|
|
1275
1293
|
* - /6J8eA60yXwdm5eyUh9fX6/fields/mainStory/~locale
|
|
1276
1294
|
* @returns
|
|
1277
1295
|
*/
|
|
1278
|
-
const isDeepPath = (deepPathCandidate) => {
|
|
1279
|
-
const deepPathParsed = parseDeepPath(deepPathCandidate);
|
|
1296
|
+
const isDeepPath$1 = (deepPathCandidate) => {
|
|
1297
|
+
const deepPathParsed = parseDeepPath$1(deepPathCandidate);
|
|
1280
1298
|
if (!deepPathParsed) {
|
|
1281
1299
|
return false;
|
|
1282
1300
|
}
|
|
1283
1301
|
return deepPathParsed.fields.length > 1;
|
|
1284
1302
|
};
|
|
1285
|
-
const parseDeepPath = (deepPathCandidate) => {
|
|
1303
|
+
const parseDeepPath$1 = (deepPathCandidate) => {
|
|
1286
1304
|
// ALGORITHM:
|
|
1287
1305
|
// We start with deep path in form:
|
|
1288
1306
|
// /uuid123/fields/mainStory/~locale/fields/cover/~locale/fields/title/~locale
|
|
@@ -1308,7 +1326,7 @@ const parseDeepPath = (deepPathCandidate) => {
|
|
|
1308
1326
|
return /^fields\/[^/^~]+\/~locale$/.test(fieldChunk.join('/'));
|
|
1309
1327
|
};
|
|
1310
1328
|
const deepPathSegments = deepPathCandidate.split('/');
|
|
1311
|
-
const chunks = chunkSegments(deepPathSegments, { startNextChunkOnElementEqualTo: 'fields' });
|
|
1329
|
+
const chunks = chunkSegments$1(deepPathSegments, { startNextChunkOnElementEqualTo: 'fields' });
|
|
1312
1330
|
if (chunks.length <= 1) {
|
|
1313
1331
|
return null; // malformed path, even regular paths have at least 2 chunks
|
|
1314
1332
|
}
|
|
@@ -1328,7 +1346,7 @@ const parseDeepPath = (deepPathCandidate) => {
|
|
|
1328
1346
|
fields: fieldChunks.map((fieldChunk) => fieldChunk[1]), // pick only fieldName eg. from ['fields','mainStory', '~locale'] we pick `mainStory`
|
|
1329
1347
|
};
|
|
1330
1348
|
};
|
|
1331
|
-
const chunkSegments = (segments, { startNextChunkOnElementEqualTo }) => {
|
|
1349
|
+
const chunkSegments$1 = (segments, { startNextChunkOnElementEqualTo }) => {
|
|
1332
1350
|
const chunks = [];
|
|
1333
1351
|
let currentChunk = [];
|
|
1334
1352
|
const isSegmentBeginningOfChunk = (segment) => segment === startNextChunkOnElementEqualTo;
|
|
@@ -1429,11 +1447,6 @@ const transformVisibility = (value) => {
|
|
|
1429
1447
|
// Don't explicitly set anything when visible to not overwrite values like `grid` or `flex`.
|
|
1430
1448
|
return {};
|
|
1431
1449
|
};
|
|
1432
|
-
// TODO: Remove in next major version v2 since the change is 17 months old
|
|
1433
|
-
// Keep this for backwards compatibility - deleting this would be a breaking change
|
|
1434
|
-
// because existing components on a users experience will have the width value as fill
|
|
1435
|
-
// rather than 100%
|
|
1436
|
-
const transformFill = (value) => (value === 'fill' ? '100%' : value);
|
|
1437
1450
|
const transformGridColumn = (span) => {
|
|
1438
1451
|
if (!span) {
|
|
1439
1452
|
return {};
|
|
@@ -1478,34 +1491,6 @@ const transformBackgroundImage = (cfBackgroundImageUrl, cfBackgroundImageOptions
|
|
|
1478
1491
|
return;
|
|
1479
1492
|
}
|
|
1480
1493
|
let [horizontalAlignment, verticalAlignment] = alignment.trim().split(/\s+/, 2);
|
|
1481
|
-
// Special case for handling single values
|
|
1482
|
-
// for backwards compatibility with single values 'right','left', 'center', 'top','bottom'
|
|
1483
|
-
if (horizontalAlignment && !verticalAlignment) {
|
|
1484
|
-
const singleValue = horizontalAlignment;
|
|
1485
|
-
switch (singleValue) {
|
|
1486
|
-
case 'left':
|
|
1487
|
-
horizontalAlignment = 'left';
|
|
1488
|
-
verticalAlignment = 'center';
|
|
1489
|
-
break;
|
|
1490
|
-
case 'right':
|
|
1491
|
-
horizontalAlignment = 'right';
|
|
1492
|
-
verticalAlignment = 'center';
|
|
1493
|
-
break;
|
|
1494
|
-
case 'center':
|
|
1495
|
-
horizontalAlignment = 'center';
|
|
1496
|
-
verticalAlignment = 'center';
|
|
1497
|
-
break;
|
|
1498
|
-
case 'top':
|
|
1499
|
-
horizontalAlignment = 'center';
|
|
1500
|
-
verticalAlignment = 'top';
|
|
1501
|
-
break;
|
|
1502
|
-
case 'bottom':
|
|
1503
|
-
horizontalAlignment = 'center';
|
|
1504
|
-
verticalAlignment = 'bottom';
|
|
1505
|
-
break;
|
|
1506
|
-
// just fall down to the normal validation logic for horiz and vert
|
|
1507
|
-
}
|
|
1508
|
-
}
|
|
1509
1494
|
const isHorizontalValid = ['left', 'right', 'center'].includes(horizontalAlignment);
|
|
1510
1495
|
const isVerticalValid = ['top', 'bottom', 'center'].includes(verticalAlignment);
|
|
1511
1496
|
horizontalAlignment = isHorizontalValid ? horizontalAlignment : 'left';
|
|
@@ -1590,8 +1575,8 @@ const buildCfStyles = (values) => {
|
|
|
1590
1575
|
margin: values.cfMargin,
|
|
1591
1576
|
padding: values.cfPadding,
|
|
1592
1577
|
backgroundColor: values.cfBackgroundColor,
|
|
1593
|
-
width:
|
|
1594
|
-
height:
|
|
1578
|
+
width: values.cfWidth || values.cfImageOptions?.width,
|
|
1579
|
+
height: values.cfHeight || values.cfImageOptions?.height,
|
|
1595
1580
|
maxWidth: values.cfMaxWidth,
|
|
1596
1581
|
...transformGridColumn(values.cfColumnSpan),
|
|
1597
1582
|
...transformBorderStyle(values.cfBorder),
|
|
@@ -1697,13 +1682,13 @@ const getOptimizedBackgroundImageAsset = (file, widthStyle, quality = '100%', fo
|
|
|
1697
1682
|
};
|
|
1698
1683
|
|
|
1699
1684
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1700
|
-
function get(obj, path) {
|
|
1685
|
+
function get$1(obj, path) {
|
|
1701
1686
|
if (!path.length) {
|
|
1702
1687
|
return obj;
|
|
1703
1688
|
}
|
|
1704
1689
|
try {
|
|
1705
1690
|
const [currentPath, ...nextPath] = path;
|
|
1706
|
-
return get(obj[currentPath], nextPath);
|
|
1691
|
+
return get$1(obj[currentPath], nextPath);
|
|
1707
1692
|
}
|
|
1708
1693
|
catch (err) {
|
|
1709
1694
|
return undefined;
|
|
@@ -1711,7 +1696,7 @@ function get(obj, path) {
|
|
|
1711
1696
|
}
|
|
1712
1697
|
|
|
1713
1698
|
const getBoundValue = (entryOrAsset, path) => {
|
|
1714
|
-
const value = get(entryOrAsset, path.split('/').slice(2, -1));
|
|
1699
|
+
const value = get$1(entryOrAsset, path.split('/').slice(2, -1));
|
|
1715
1700
|
return value && typeof value == 'object' && value.url
|
|
1716
1701
|
? value.url
|
|
1717
1702
|
: value;
|
|
@@ -1741,7 +1726,9 @@ const transformRichText = (entryOrAsset, entityStore, path) => {
|
|
|
1741
1726
|
}
|
|
1742
1727
|
if (typeof value === 'object' && value.nodeType === BLOCKS.DOCUMENT) {
|
|
1743
1728
|
// resolve any links to assets/entries/hyperlinks
|
|
1744
|
-
|
|
1729
|
+
// we need to clone, as we want to keep the original Entity in the EntityStore intact,
|
|
1730
|
+
// and resolveLinks() is mutating the node object.
|
|
1731
|
+
const richTextDocument = structuredClone(value);
|
|
1745
1732
|
resolveLinks(richTextDocument, entityStore);
|
|
1746
1733
|
return richTextDocument;
|
|
1747
1734
|
}
|
|
@@ -1796,7 +1783,7 @@ const transformMedia = (asset, variables, resolveDesignValue, variableName, path
|
|
|
1796
1783
|
let value;
|
|
1797
1784
|
// If it is not a deep path and not pointing to the file of the asset,
|
|
1798
1785
|
// it is just pointing to a normal field and therefore we just resolve the value as normal field
|
|
1799
|
-
if (!isDeepPath(path) && !lastPathNamedSegmentEq(path, 'file')) {
|
|
1786
|
+
if (!isDeepPath$1(path) && !lastPathNamedSegmentEq(path, 'file')) {
|
|
1800
1787
|
return getBoundValue(asset, path);
|
|
1801
1788
|
}
|
|
1802
1789
|
//TODO: this will be better served by injectable type transformers instead of if statement
|
|
@@ -1854,104 +1841,97 @@ const transformMedia = (asset, variables, resolveDesignValue, variableName, path
|
|
|
1854
1841
|
}
|
|
1855
1842
|
return asset.fields.file?.url;
|
|
1856
1843
|
};
|
|
1857
|
-
|
|
1858
|
-
const isAsset = (value) => {
|
|
1844
|
+
const isEntry$1 = (value) => {
|
|
1859
1845
|
return (null !== value &&
|
|
1860
1846
|
typeof value === 'object' &&
|
|
1861
1847
|
'sys' in value &&
|
|
1862
|
-
value.sys?.type === '
|
|
1848
|
+
value.sys?.type === 'Entry');
|
|
1863
1849
|
};
|
|
1864
|
-
const
|
|
1850
|
+
const isAsset$1 = (value) => {
|
|
1865
1851
|
return (null !== value &&
|
|
1866
1852
|
typeof value === 'object' &&
|
|
1867
1853
|
'sys' in value &&
|
|
1868
|
-
value.sys?.type === '
|
|
1854
|
+
value.sys?.type === 'Asset');
|
|
1869
1855
|
};
|
|
1870
1856
|
|
|
1871
1857
|
function getResolvedEntryFromLink(entryOrAsset, path, entityStore) {
|
|
1872
|
-
if (isAsset(entryOrAsset)) {
|
|
1858
|
+
if (isAsset$1(entryOrAsset)) {
|
|
1873
1859
|
return entryOrAsset;
|
|
1874
1860
|
}
|
|
1875
|
-
else if (!isEntry(entryOrAsset)) {
|
|
1861
|
+
else if (!isEntry$1(entryOrAsset)) {
|
|
1876
1862
|
throw new Error(`Expected an Entry or Asset, but got: ${JSON.stringify(entryOrAsset)}`);
|
|
1877
1863
|
}
|
|
1878
|
-
const
|
|
1864
|
+
const fieldName = path.split('/').slice(2, -1);
|
|
1865
|
+
const value = get$1(entryOrAsset, fieldName);
|
|
1879
1866
|
let resolvedEntity;
|
|
1880
|
-
if (isAsset(value) || isEntry(value)) {
|
|
1867
|
+
if (isAsset$1(value) || isEntry$1(value)) {
|
|
1881
1868
|
// In some cases, reference fields are already resolved
|
|
1882
1869
|
resolvedEntity = value;
|
|
1883
1870
|
}
|
|
1884
1871
|
else if (value?.sys.type === 'Link') {
|
|
1885
1872
|
// Look up the reference in the entity store
|
|
1886
1873
|
resolvedEntity = entityStore.getEntityFromLink(value);
|
|
1887
|
-
if (!resolvedEntity) {
|
|
1888
|
-
return;
|
|
1889
|
-
}
|
|
1890
1874
|
}
|
|
1891
1875
|
else {
|
|
1892
|
-
console.warn(`
|
|
1876
|
+
console.warn(`When attempting to follow link in field '${fieldName}' of entity, the value is expected to be a link, but got: ${JSON.stringify(value)}`, { entity: entryOrAsset });
|
|
1877
|
+
return;
|
|
1878
|
+
}
|
|
1879
|
+
// no need to make structuredClone(entityStore.getEntityFromLink(value)) because
|
|
1880
|
+
// we provide component with the original Object.frozen object of the entity.
|
|
1881
|
+
// As we don't resolve L3 and don't mutate the entity before returning anymore,
|
|
1882
|
+
// we don't need to make a copy of the entity. And even provide better referential integrity
|
|
1883
|
+
// for the component for the same entity.
|
|
1884
|
+
if (!resolvedEntity) {
|
|
1893
1885
|
return;
|
|
1894
1886
|
}
|
|
1895
|
-
//resolve any embedded links - we currently only support 2 levels deep
|
|
1896
|
-
const fields = resolvedEntity.fields || {};
|
|
1897
|
-
Object.entries(fields).forEach(([fieldKey, field]) => {
|
|
1898
|
-
if (field && field.sys?.type === 'Link') {
|
|
1899
|
-
const entity = entityStore.getEntityFromLink(field);
|
|
1900
|
-
if (entity) {
|
|
1901
|
-
resolvedEntity.fields[fieldKey] = entity;
|
|
1902
|
-
}
|
|
1903
|
-
}
|
|
1904
|
-
else if (field && Array.isArray(field)) {
|
|
1905
|
-
resolvedEntity.fields[fieldKey] = field.map((innerField) => {
|
|
1906
|
-
if (innerField && innerField.sys?.type === 'Link') {
|
|
1907
|
-
const entity = entityStore.getEntityFromLink(innerField);
|
|
1908
|
-
if (entity) {
|
|
1909
|
-
return entity;
|
|
1910
|
-
}
|
|
1911
|
-
}
|
|
1912
|
-
return innerField;
|
|
1913
|
-
});
|
|
1914
|
-
}
|
|
1915
|
-
});
|
|
1916
1887
|
return resolvedEntity;
|
|
1917
1888
|
}
|
|
1918
1889
|
|
|
1890
|
+
const excludeUndefined = (value) => {
|
|
1891
|
+
return value !== undefined;
|
|
1892
|
+
};
|
|
1919
1893
|
function getArrayValue(entryOrAsset, path, entityStore) {
|
|
1894
|
+
// NOTE: Not sure if we need this if-statement,
|
|
1895
|
+
// as it is NOT possible to bind to Array variable an Asset
|
|
1896
|
+
// (as Assets don't have multi-reference fields) unless it's a degenerate case.
|
|
1920
1897
|
if (entryOrAsset.sys.type === 'Asset') {
|
|
1921
1898
|
return entryOrAsset;
|
|
1922
1899
|
}
|
|
1923
|
-
const
|
|
1900
|
+
const fieldName = path.split('/').slice(2, -1);
|
|
1901
|
+
const arrayValue = get$1(entryOrAsset, fieldName);
|
|
1924
1902
|
if (!isArray(arrayValue)) {
|
|
1925
|
-
console.warn(`Expected
|
|
1903
|
+
console.warn(`A field '${fieldName}' of an entity was bound to an Array variable. Expected value of that field to be an array, but got: ${JSON.stringify(arrayValue)}`, { entity: entryOrAsset });
|
|
1926
1904
|
return;
|
|
1927
1905
|
}
|
|
1928
|
-
const result = arrayValue
|
|
1906
|
+
const result = arrayValue
|
|
1907
|
+
.map((value) => {
|
|
1929
1908
|
if (typeof value === 'string') {
|
|
1930
|
-
return value;
|
|
1909
|
+
return value; // handles case where Text array is bound (in [Content Model] tab of the platform, select Text and make it a list)
|
|
1931
1910
|
}
|
|
1932
1911
|
else if (value?.sys?.type === 'Link') {
|
|
1933
1912
|
const resolvedEntity = entityStore.getEntityFromLink(value);
|
|
1934
1913
|
if (!resolvedEntity) {
|
|
1914
|
+
// We return undefined, which means that entity wasn't availble in the Entity Store due to:
|
|
1915
|
+
// - because it's archived entity (and they normally wouldn't be sent to the Entity Store)
|
|
1916
|
+
// - bug where some entity wasn't added to the Entity Store
|
|
1917
|
+
// BTW, deleted entities shouldn't even be possible here as they require CT deletion first and that shouldn't allow us to load them at all)
|
|
1935
1918
|
return;
|
|
1936
1919
|
}
|
|
1937
|
-
//resolve any embedded links - we currently only support 2 levels deep
|
|
1938
|
-
const fields = resolvedEntity.fields || {};
|
|
1939
|
-
Object.entries(fields).forEach(([fieldKey, field]) => {
|
|
1940
|
-
if (field && field.sys?.type === 'Link') {
|
|
1941
|
-
const entity = entityStore.getEntityFromLink(field);
|
|
1942
|
-
if (entity) {
|
|
1943
|
-
resolvedEntity.fields[fieldKey] = entity;
|
|
1944
|
-
}
|
|
1945
|
-
}
|
|
1946
|
-
});
|
|
1947
1920
|
return resolvedEntity;
|
|
1948
1921
|
}
|
|
1949
1922
|
else {
|
|
1950
1923
|
console.warn(`Expected value to be a string or Link, but got: ${JSON.stringify(value)}`);
|
|
1951
1924
|
return undefined;
|
|
1952
1925
|
}
|
|
1953
|
-
})
|
|
1954
|
-
|
|
1926
|
+
})
|
|
1927
|
+
.filter(excludeUndefined);
|
|
1928
|
+
// eg. imagine you have multi-referene field with 3 links to archived entries,
|
|
1929
|
+
// all of them will be undefined on previous step and will be filtered out
|
|
1930
|
+
// of resultWithoutUndefined. Instead of passing to component an empty array,
|
|
1931
|
+
// we pass undefined. This means that develloper making custom component
|
|
1932
|
+
// does not have to handle empty array case. But only undefiened, which signals:
|
|
1933
|
+
// user didn't bind anything; user bound to reference field which is unset; all references are archived
|
|
1934
|
+
return result.length > 0 ? result : undefined;
|
|
1955
1935
|
}
|
|
1956
1936
|
|
|
1957
1937
|
const transformBoundContentValue = (variables, entityStore, binding, resolveDesignValue, variableName, variableType, path) => {
|
|
@@ -2110,11 +2090,22 @@ const sendMessage = (eventType, data) => {
|
|
|
2110
2090
|
}, '*');
|
|
2111
2091
|
};
|
|
2112
2092
|
|
|
2093
|
+
function deepFreeze$1(obj) {
|
|
2094
|
+
const propNames = Object.getOwnPropertyNames(obj);
|
|
2095
|
+
for (const name of propNames) {
|
|
2096
|
+
const value = obj[name];
|
|
2097
|
+
if (value && typeof value === 'object') {
|
|
2098
|
+
deepFreeze$1(value);
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
return Object.freeze(obj);
|
|
2102
|
+
}
|
|
2103
|
+
|
|
2113
2104
|
/**
|
|
2114
2105
|
* Base Store for entities
|
|
2115
2106
|
* Can be extended for the different loading behaviours (editor, production, ..)
|
|
2116
2107
|
*/
|
|
2117
|
-
class EntityStoreBase {
|
|
2108
|
+
let EntityStoreBase$1 = class EntityStoreBase {
|
|
2118
2109
|
constructor({ entities, locale }) {
|
|
2119
2110
|
/* serialized */ this.entryMap = new Map();
|
|
2120
2111
|
/* serialized */ this.assetMap = new Map();
|
|
@@ -2130,11 +2121,11 @@ class EntityStoreBase {
|
|
|
2130
2121
|
this.addEntity(entity);
|
|
2131
2122
|
}
|
|
2132
2123
|
getEntryOrAsset(linkOrEntryOrAsset, path) {
|
|
2133
|
-
if (isDeepPath(path)) {
|
|
2124
|
+
if (isDeepPath$1(path)) {
|
|
2134
2125
|
return this.getDeepEntry(linkOrEntryOrAsset, path);
|
|
2135
2126
|
}
|
|
2136
2127
|
let entity;
|
|
2137
|
-
if (isLink(linkOrEntryOrAsset)) {
|
|
2128
|
+
if (isLink$1(linkOrEntryOrAsset)) {
|
|
2138
2129
|
const resolvedEntity = linkOrEntryOrAsset.sys.linkType === 'Entry'
|
|
2139
2130
|
? this.entryMap.get(linkOrEntryOrAsset.sys.id)
|
|
2140
2131
|
: this.assetMap.get(linkOrEntryOrAsset.sys.id);
|
|
@@ -2144,7 +2135,7 @@ class EntityStoreBase {
|
|
|
2144
2135
|
}
|
|
2145
2136
|
entity = resolvedEntity;
|
|
2146
2137
|
}
|
|
2147
|
-
else if (isAsset(linkOrEntryOrAsset) || isEntry(linkOrEntryOrAsset)) {
|
|
2138
|
+
else if (isAsset$1(linkOrEntryOrAsset) || isEntry$1(linkOrEntryOrAsset)) {
|
|
2148
2139
|
// We already have the complete entity in preview & delivery (resolved by the CMA client)
|
|
2149
2140
|
entity = linkOrEntryOrAsset;
|
|
2150
2141
|
}
|
|
@@ -2166,7 +2157,7 @@ class EntityStoreBase {
|
|
|
2166
2157
|
console.warn(`Unresolved entity reference: ${entityLink.sys.linkType} with ID ${entityLink.sys.id}`);
|
|
2167
2158
|
return;
|
|
2168
2159
|
}
|
|
2169
|
-
return get(entity, path);
|
|
2160
|
+
return get$1(entity, path);
|
|
2170
2161
|
}
|
|
2171
2162
|
getEntityFromLink(link) {
|
|
2172
2163
|
const resolvedEntity = link.sys.linkType === 'Entry'
|
|
@@ -2178,6 +2169,22 @@ class EntityStoreBase {
|
|
|
2178
2169
|
}
|
|
2179
2170
|
return resolvedEntity;
|
|
2180
2171
|
}
|
|
2172
|
+
getAssetById(assetId) {
|
|
2173
|
+
const asset = this.assetMap.get(assetId);
|
|
2174
|
+
if (!asset) {
|
|
2175
|
+
console.warn(`Asset with ID "${assetId}" is not found in the store`);
|
|
2176
|
+
return;
|
|
2177
|
+
}
|
|
2178
|
+
return asset;
|
|
2179
|
+
}
|
|
2180
|
+
getEntryById(entryId) {
|
|
2181
|
+
const entry = this.entryMap.get(entryId);
|
|
2182
|
+
if (!entry) {
|
|
2183
|
+
console.warn(`Entry with ID "${entryId}" is not found in the store`);
|
|
2184
|
+
return;
|
|
2185
|
+
}
|
|
2186
|
+
return entry;
|
|
2187
|
+
}
|
|
2181
2188
|
getEntitiesFromMap(type, ids) {
|
|
2182
2189
|
const resolved = [];
|
|
2183
2190
|
const missing = [];
|
|
@@ -2196,11 +2203,13 @@ class EntityStoreBase {
|
|
|
2196
2203
|
};
|
|
2197
2204
|
}
|
|
2198
2205
|
addEntity(entity) {
|
|
2199
|
-
if (isAsset(entity)) {
|
|
2200
|
-
|
|
2206
|
+
if (isAsset$1(entity)) {
|
|
2207
|
+
// cloned and frozen
|
|
2208
|
+
this.assetMap.set(entity.sys.id, deepFreeze$1(structuredClone(entity)));
|
|
2201
2209
|
}
|
|
2202
|
-
else if (isEntry(entity)) {
|
|
2203
|
-
|
|
2210
|
+
else if (isEntry$1(entity)) {
|
|
2211
|
+
// cloned and frozen
|
|
2212
|
+
this.entryMap.set(entity.sys.id, deepFreeze$1(structuredClone(entity)));
|
|
2204
2213
|
}
|
|
2205
2214
|
else {
|
|
2206
2215
|
throw new Error(`Attempted to add an entity to the store that is neither Asset nor Entry: '${JSON.stringify(entity)}'`);
|
|
@@ -2253,7 +2262,7 @@ class EntityStoreBase {
|
|
|
2253
2262
|
resolvedFieldset.push([entityToResolveFieldsFrom, field, _localeQualifier]);
|
|
2254
2263
|
break;
|
|
2255
2264
|
}
|
|
2256
|
-
const fieldValue = get(entityToResolveFieldsFrom, ['fields', field]);
|
|
2265
|
+
const fieldValue = get$1(entityToResolveFieldsFrom, ['fields', field]);
|
|
2257
2266
|
if (undefined === fieldValue) {
|
|
2258
2267
|
return {
|
|
2259
2268
|
resolvedFieldset,
|
|
@@ -2261,7 +2270,7 @@ class EntityStoreBase {
|
|
|
2261
2270
|
reason: `Cannot resolve field Link<${entityToResolveFieldsFrom.sys.type}>(sys.id=${entityToResolveFieldsFrom.sys.id}).fields[${field}] as field value is not defined`,
|
|
2262
2271
|
};
|
|
2263
2272
|
}
|
|
2264
|
-
else if (isLink(fieldValue)) {
|
|
2273
|
+
else if (isLink$1(fieldValue)) {
|
|
2265
2274
|
const entity = this.getEntityFromLink(fieldValue);
|
|
2266
2275
|
if (entity === undefined) {
|
|
2267
2276
|
return {
|
|
@@ -2273,7 +2282,7 @@ class EntityStoreBase {
|
|
|
2273
2282
|
resolvedFieldset.push([entityToResolveFieldsFrom, field, _localeQualifier]);
|
|
2274
2283
|
entityToResolveFieldsFrom = entity; // we move up
|
|
2275
2284
|
}
|
|
2276
|
-
else if (isAsset(fieldValue) || isEntry(fieldValue)) {
|
|
2285
|
+
else if (isAsset$1(fieldValue) || isEntry$1(fieldValue)) {
|
|
2277
2286
|
resolvedFieldset.push([entityToResolveFieldsFrom, field, _localeQualifier]);
|
|
2278
2287
|
entityToResolveFieldsFrom = fieldValue; // we move up
|
|
2279
2288
|
}
|
|
@@ -2290,13 +2299,13 @@ class EntityStoreBase {
|
|
|
2290
2299
|
isFullyResolved: true,
|
|
2291
2300
|
};
|
|
2292
2301
|
};
|
|
2293
|
-
const headEntity = isLink(linkOrEntryOrAsset)
|
|
2302
|
+
const headEntity = isLink$1(linkOrEntryOrAsset)
|
|
2294
2303
|
? this.getEntityFromLink(linkOrEntryOrAsset)
|
|
2295
2304
|
: linkOrEntryOrAsset;
|
|
2296
2305
|
if (undefined === headEntity) {
|
|
2297
2306
|
return;
|
|
2298
2307
|
}
|
|
2299
|
-
const unresolvedFieldset = parseDataSourcePathIntoFieldset(path);
|
|
2308
|
+
const unresolvedFieldset = parseDataSourcePathIntoFieldset$1(path);
|
|
2300
2309
|
// The purpose here is to take this intermediate representation of the deep-path
|
|
2301
2310
|
// and to follow the links to the leaf-entity and field
|
|
2302
2311
|
// in case we can't follow till the end, we should signal that there was null-reference in the path
|
|
@@ -2322,13 +2331,13 @@ class EntityStoreBase {
|
|
|
2322
2331
|
locale: this.locale,
|
|
2323
2332
|
};
|
|
2324
2333
|
}
|
|
2325
|
-
}
|
|
2334
|
+
};
|
|
2326
2335
|
|
|
2327
2336
|
/**
|
|
2328
2337
|
* EntityStore which resolves entries and assets from the editor
|
|
2329
2338
|
* over the sendMessage and subscribe functions.
|
|
2330
2339
|
*/
|
|
2331
|
-
class EditorEntityStore extends EntityStoreBase {
|
|
2340
|
+
class EditorEntityStore extends EntityStoreBase$1 {
|
|
2332
2341
|
constructor({ entities, locale, sendMessage, subscribe, timeoutDuration = 3000, }) {
|
|
2333
2342
|
super({ entities, locale });
|
|
2334
2343
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -2465,7 +2474,6 @@ class EditorModeEntityStore extends EditorEntityStore {
|
|
|
2465
2474
|
};
|
|
2466
2475
|
};
|
|
2467
2476
|
super({ entities, sendMessage, subscribe, locale, timeoutDuration: REQUEST_TIMEOUT });
|
|
2468
|
-
this.locale = locale;
|
|
2469
2477
|
}
|
|
2470
2478
|
/**
|
|
2471
2479
|
* This function collects and returns the list of requested entries and assets. Additionally, it checks
|
|
@@ -2495,11 +2503,91 @@ class EditorModeEntityStore extends EditorEntityStore {
|
|
|
2495
2503
|
if (!entity) {
|
|
2496
2504
|
return;
|
|
2497
2505
|
}
|
|
2498
|
-
const fieldValue = get(entity, path);
|
|
2506
|
+
const fieldValue = get$1(entity, path);
|
|
2499
2507
|
return transformAssetFileToUrl(fieldValue);
|
|
2500
2508
|
}
|
|
2501
2509
|
}
|
|
2502
2510
|
|
|
2511
|
+
let UninitializedEntityStore$1 = class UninitializedEntityStore extends EntityStoreBase$1 {
|
|
2512
|
+
constructor() {
|
|
2513
|
+
super({ entities: [], locale: 'uninitialized-locale-in-uninitialized-entity-store' });
|
|
2514
|
+
}
|
|
2515
|
+
};
|
|
2516
|
+
|
|
2517
|
+
const inMemoryEntitiesStore = create((set, get) => ({
|
|
2518
|
+
// The UninitializedEntityStore is a placeholder instance and is here to highlight the
|
|
2519
|
+
// // fact that it's not used by anything until during loading lifecycle it'sreplaced by real entity store:
|
|
2520
|
+
// - in Preview+Delivery mode: right after we fetch Expereince and it entities
|
|
2521
|
+
// - in EDITOR (VisualEditor) mode: right after the VisualEditor is async imported and initialize event happens
|
|
2522
|
+
entityStore: new UninitializedEntityStore$1(),
|
|
2523
|
+
areEntitiesFetched: false,
|
|
2524
|
+
setEntitiesFetched(fetched) {
|
|
2525
|
+
set({ areEntitiesFetched: fetched });
|
|
2526
|
+
},
|
|
2527
|
+
resolveAssetById(assetId) {
|
|
2528
|
+
if (!assetId)
|
|
2529
|
+
return undefined;
|
|
2530
|
+
const { entityStore } = get();
|
|
2531
|
+
return entityStore.getAssetById(assetId);
|
|
2532
|
+
},
|
|
2533
|
+
resolveEntryById(entryId) {
|
|
2534
|
+
if (!entryId)
|
|
2535
|
+
return undefined;
|
|
2536
|
+
const { entityStore } = get();
|
|
2537
|
+
return entityStore.getEntryById(entryId);
|
|
2538
|
+
},
|
|
2539
|
+
resolveEntity(link) {
|
|
2540
|
+
if (!link)
|
|
2541
|
+
return undefined;
|
|
2542
|
+
const { entityStore } = get();
|
|
2543
|
+
return entityStore.getEntityFromLink(link);
|
|
2544
|
+
},
|
|
2545
|
+
resetEntityStore(entityStore) {
|
|
2546
|
+
set({
|
|
2547
|
+
entityStore,
|
|
2548
|
+
areEntitiesFetched: false,
|
|
2549
|
+
});
|
|
2550
|
+
},
|
|
2551
|
+
}));
|
|
2552
|
+
|
|
2553
|
+
function maybeResolveLink(maybeLink) {
|
|
2554
|
+
if (!isLink$1(maybeLink)) {
|
|
2555
|
+
console.warn('maybeResolveLink function must receive Link shape. Provided argument does not match the Link shape: ', maybeLink);
|
|
2556
|
+
return undefined;
|
|
2557
|
+
}
|
|
2558
|
+
return inMemoryEntitiesStore.getState().resolveEntity(maybeLink);
|
|
2559
|
+
}
|
|
2560
|
+
function maybeResolveByAssetId(assetId) {
|
|
2561
|
+
return inMemoryEntitiesStore.getState().resolveAssetById(assetId);
|
|
2562
|
+
}
|
|
2563
|
+
function maybeResolveByEntryId(entryId) {
|
|
2564
|
+
return inMemoryEntitiesStore.getState().resolveEntryById(entryId);
|
|
2565
|
+
}
|
|
2566
|
+
function hasEntry(entryId) {
|
|
2567
|
+
return Boolean(maybeResolveByEntryId(entryId));
|
|
2568
|
+
}
|
|
2569
|
+
function hasAsset(assetId) {
|
|
2570
|
+
return Boolean(maybeResolveByAssetId(assetId));
|
|
2571
|
+
}
|
|
2572
|
+
function addEntities(entities) {
|
|
2573
|
+
if (!Array.isArray(entities) || entities.length === 0) {
|
|
2574
|
+
return;
|
|
2575
|
+
}
|
|
2576
|
+
const { entityStore } = inMemoryEntitiesStore.getState();
|
|
2577
|
+
const definedEntities = entities.filter(Boolean);
|
|
2578
|
+
for (const entity of definedEntities) {
|
|
2579
|
+
entityStore.updateEntity(entity);
|
|
2580
|
+
}
|
|
2581
|
+
}
|
|
2582
|
+
const inMemoryEntities = {
|
|
2583
|
+
maybeResolveLink,
|
|
2584
|
+
maybeResolveByAssetId,
|
|
2585
|
+
maybeResolveByEntryId,
|
|
2586
|
+
hasEntry,
|
|
2587
|
+
hasAsset,
|
|
2588
|
+
addEntities,
|
|
2589
|
+
};
|
|
2590
|
+
|
|
2503
2591
|
var VisualEditorMode$1;
|
|
2504
2592
|
(function (VisualEditorMode) {
|
|
2505
2593
|
VisualEditorMode["LazyLoad"] = "lazyLoad";
|
|
@@ -2529,7 +2617,7 @@ class DeepReference {
|
|
|
2529
2617
|
// field references nothing (or even field doesn't exist)
|
|
2530
2618
|
return undefined;
|
|
2531
2619
|
}
|
|
2532
|
-
if (!isLink(maybeReferentLink)) {
|
|
2620
|
+
if (!isLink$1(maybeReferentLink)) {
|
|
2533
2621
|
// Scenario of "impostor referent", where one of the deepPath's segments is not a Link but some other type
|
|
2534
2622
|
// Under normal circumstance we expect field to be a Link, but it could be an "impostor"
|
|
2535
2623
|
// eg. `Text` or `Number` or anything like that; could be due to CT changes or manual path creation via CMA
|
|
@@ -2549,7 +2637,7 @@ function gatherDeepReferencesFromTree(startingNode, dataSource) {
|
|
|
2549
2637
|
for (const [, variableMapping] of Object.entries(node.data.props)) {
|
|
2550
2638
|
if (variableMapping.type !== 'BoundValue')
|
|
2551
2639
|
continue;
|
|
2552
|
-
if (!isDeepPath(variableMapping.path))
|
|
2640
|
+
if (!isDeepPath$1(variableMapping.path))
|
|
2553
2641
|
continue;
|
|
2554
2642
|
deepReferences.push(DeepReference.from({
|
|
2555
2643
|
path: variableMapping.path,
|
|
@@ -3158,6 +3246,26 @@ const useTreeStore = create((set, get) => ({
|
|
|
3158
3246
|
reparentChildNode(sourceIndex, destinationIndex, sourceParentId, destinationParentId, state.tree.root);
|
|
3159
3247
|
}));
|
|
3160
3248
|
},
|
|
3249
|
+
// breadth first search
|
|
3250
|
+
findNodeById(nodeId) {
|
|
3251
|
+
if (!nodeId) {
|
|
3252
|
+
return null;
|
|
3253
|
+
}
|
|
3254
|
+
const rootNode = get().tree.root;
|
|
3255
|
+
const visitedNodeIds = [];
|
|
3256
|
+
const queue = [];
|
|
3257
|
+
let currentNode = rootNode;
|
|
3258
|
+
queue.push(currentNode);
|
|
3259
|
+
while (queue.length) {
|
|
3260
|
+
currentNode = queue.shift();
|
|
3261
|
+
visitedNodeIds.push(currentNode.data.id);
|
|
3262
|
+
if (currentNode.data.id === nodeId) {
|
|
3263
|
+
return currentNode;
|
|
3264
|
+
}
|
|
3265
|
+
queue.push(...currentNode.children);
|
|
3266
|
+
}
|
|
3267
|
+
return null;
|
|
3268
|
+
},
|
|
3161
3269
|
}));
|
|
3162
3270
|
const hasBreakpointDiffs = (currentTree, newTree) => {
|
|
3163
3271
|
const currentBreakpoints = currentTree?.root?.data?.breakpoints ?? [];
|
|
@@ -3932,6 +4040,419 @@ class DebugLogger {
|
|
|
3932
4040
|
DebugLogger.instance = null;
|
|
3933
4041
|
DebugLogger.getInstance();
|
|
3934
4042
|
|
|
4043
|
+
const isLink = (maybeLink) => {
|
|
4044
|
+
if (maybeLink === null)
|
|
4045
|
+
return false;
|
|
4046
|
+
if (typeof maybeLink !== 'object')
|
|
4047
|
+
return false;
|
|
4048
|
+
const link = maybeLink;
|
|
4049
|
+
return Boolean(link.sys?.id) && link.sys?.type === 'Link' && Boolean(link.sys?.linkType);
|
|
4050
|
+
};
|
|
4051
|
+
|
|
4052
|
+
/**
|
|
4053
|
+
* This module encapsulates format of the path to a deep reference.
|
|
4054
|
+
*/
|
|
4055
|
+
const parseDataSourcePathIntoFieldset = (path) => {
|
|
4056
|
+
const parsedPath = parseDeepPath(path);
|
|
4057
|
+
if (null === parsedPath) {
|
|
4058
|
+
throw new Error(`Cannot parse path '${path}' as deep path`);
|
|
4059
|
+
}
|
|
4060
|
+
return parsedPath.fields.map((field) => [null, field, '~locale']);
|
|
4061
|
+
};
|
|
4062
|
+
/**
|
|
4063
|
+
* Detects if paths is valid deep-path, like:
|
|
4064
|
+
* - /gV6yKXp61hfYrR7rEyKxY/fields/mainStory/~locale/fields/cover/~locale/fields/title/~locale
|
|
4065
|
+
* or regular, like:
|
|
4066
|
+
* - /6J8eA60yXwdm5eyUh9fX6/fields/mainStory/~locale
|
|
4067
|
+
* @returns
|
|
4068
|
+
*/
|
|
4069
|
+
const isDeepPath = (deepPathCandidate) => {
|
|
4070
|
+
const deepPathParsed = parseDeepPath(deepPathCandidate);
|
|
4071
|
+
if (!deepPathParsed) {
|
|
4072
|
+
return false;
|
|
4073
|
+
}
|
|
4074
|
+
return deepPathParsed.fields.length > 1;
|
|
4075
|
+
};
|
|
4076
|
+
const parseDeepPath = (deepPathCandidate) => {
|
|
4077
|
+
// ALGORITHM:
|
|
4078
|
+
// We start with deep path in form:
|
|
4079
|
+
// /uuid123/fields/mainStory/~locale/fields/cover/~locale/fields/title/~locale
|
|
4080
|
+
// First turn string into array of segments
|
|
4081
|
+
// ['', 'uuid123', 'fields', 'mainStory', '~locale', 'fields', 'cover', '~locale', 'fields', 'title', '~locale']
|
|
4082
|
+
// Then group segments into intermediate represenatation - chunks, where each non-initial chunk starts with 'fields'
|
|
4083
|
+
// [
|
|
4084
|
+
// [ "", "uuid123" ],
|
|
4085
|
+
// [ "fields", "mainStory", "~locale" ],
|
|
4086
|
+
// [ "fields", "cover", "~locale" ],
|
|
4087
|
+
// [ "fields", "title", "~locale" ]
|
|
4088
|
+
// ]
|
|
4089
|
+
// Then check "initial" chunk for corretness
|
|
4090
|
+
// Then check all "field-leading" chunks for correctness
|
|
4091
|
+
const isValidInitialChunk = (initialChunk) => {
|
|
4092
|
+
// must have start with '' and have at least 2 segments, second non-empty
|
|
4093
|
+
// eg. /-_432uuid123123
|
|
4094
|
+
return /^\/([^/^~]+)$/.test(initialChunk.join('/'));
|
|
4095
|
+
};
|
|
4096
|
+
const isValidFieldChunk = (fieldChunk) => {
|
|
4097
|
+
// must start with 'fields' and have at least 3 segments, second non-empty and last segment must be '~locale'
|
|
4098
|
+
// eg. fields/-32234mainStory/~locale
|
|
4099
|
+
return /^fields\/[^/^~]+\/~locale$/.test(fieldChunk.join('/'));
|
|
4100
|
+
};
|
|
4101
|
+
const deepPathSegments = deepPathCandidate.split('/');
|
|
4102
|
+
const chunks = chunkSegments(deepPathSegments, { startNextChunkOnElementEqualTo: 'fields' });
|
|
4103
|
+
if (chunks.length <= 1) {
|
|
4104
|
+
return null; // malformed path, even regular paths have at least 2 chunks
|
|
4105
|
+
}
|
|
4106
|
+
else if (chunks.length === 2) {
|
|
4107
|
+
return null; // deep paths have at least 3 chunks
|
|
4108
|
+
}
|
|
4109
|
+
// With 3+ chunks we can now check for deep path correctness
|
|
4110
|
+
const [initialChunk, ...fieldChunks] = chunks;
|
|
4111
|
+
if (!isValidInitialChunk(initialChunk)) {
|
|
4112
|
+
return null;
|
|
4113
|
+
}
|
|
4114
|
+
if (!fieldChunks.every(isValidFieldChunk)) {
|
|
4115
|
+
return null;
|
|
4116
|
+
}
|
|
4117
|
+
return {
|
|
4118
|
+
key: initialChunk[1], // pick uuid from initial chunk ['','uuid123'],
|
|
4119
|
+
fields: fieldChunks.map((fieldChunk) => fieldChunk[1]), // pick only fieldName eg. from ['fields','mainStory', '~locale'] we pick `mainStory`
|
|
4120
|
+
};
|
|
4121
|
+
};
|
|
4122
|
+
const chunkSegments = (segments, { startNextChunkOnElementEqualTo }) => {
|
|
4123
|
+
const chunks = [];
|
|
4124
|
+
let currentChunk = [];
|
|
4125
|
+
const isSegmentBeginningOfChunk = (segment) => segment === startNextChunkOnElementEqualTo;
|
|
4126
|
+
const excludeEmptyChunks = (chunk) => chunk.length > 0;
|
|
4127
|
+
for (let i = 0; i < segments.length; i++) {
|
|
4128
|
+
const isInitialElement = i === 0;
|
|
4129
|
+
const segment = segments[i];
|
|
4130
|
+
if (isInitialElement) {
|
|
4131
|
+
currentChunk = [segment];
|
|
4132
|
+
}
|
|
4133
|
+
else if (isSegmentBeginningOfChunk(segment)) {
|
|
4134
|
+
chunks.push(currentChunk);
|
|
4135
|
+
currentChunk = [segment];
|
|
4136
|
+
}
|
|
4137
|
+
else {
|
|
4138
|
+
currentChunk.push(segment);
|
|
4139
|
+
}
|
|
4140
|
+
}
|
|
4141
|
+
chunks.push(currentChunk);
|
|
4142
|
+
return chunks.filter(excludeEmptyChunks);
|
|
4143
|
+
};
|
|
4144
|
+
|
|
4145
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4146
|
+
function get(obj, path) {
|
|
4147
|
+
if (!path.length) {
|
|
4148
|
+
return obj;
|
|
4149
|
+
}
|
|
4150
|
+
try {
|
|
4151
|
+
const [currentPath, ...nextPath] = path;
|
|
4152
|
+
return get(obj[currentPath], nextPath);
|
|
4153
|
+
}
|
|
4154
|
+
catch (err) {
|
|
4155
|
+
return undefined;
|
|
4156
|
+
}
|
|
4157
|
+
}
|
|
4158
|
+
const isEntry = (value) => {
|
|
4159
|
+
return (null !== value &&
|
|
4160
|
+
typeof value === 'object' &&
|
|
4161
|
+
'sys' in value &&
|
|
4162
|
+
value.sys?.type === 'Entry');
|
|
4163
|
+
};
|
|
4164
|
+
const isAsset = (value) => {
|
|
4165
|
+
return (null !== value &&
|
|
4166
|
+
typeof value === 'object' &&
|
|
4167
|
+
'sys' in value &&
|
|
4168
|
+
value.sys?.type === 'Asset');
|
|
4169
|
+
};
|
|
4170
|
+
|
|
4171
|
+
function deepFreeze(obj) {
|
|
4172
|
+
const propNames = Object.getOwnPropertyNames(obj);
|
|
4173
|
+
for (const name of propNames) {
|
|
4174
|
+
const value = obj[name];
|
|
4175
|
+
if (value && typeof value === 'object') {
|
|
4176
|
+
deepFreeze(value);
|
|
4177
|
+
}
|
|
4178
|
+
}
|
|
4179
|
+
return Object.freeze(obj);
|
|
4180
|
+
}
|
|
4181
|
+
|
|
4182
|
+
/**
|
|
4183
|
+
* Base Store for entities
|
|
4184
|
+
* Can be extended for the different loading behaviours (editor, production, ..)
|
|
4185
|
+
*/
|
|
4186
|
+
class EntityStoreBase {
|
|
4187
|
+
constructor({ entities, locale }) {
|
|
4188
|
+
/* serialized */ this.entryMap = new Map();
|
|
4189
|
+
/* serialized */ this.assetMap = new Map();
|
|
4190
|
+
this.locale = locale;
|
|
4191
|
+
for (const entity of entities) {
|
|
4192
|
+
this.addEntity(entity);
|
|
4193
|
+
}
|
|
4194
|
+
}
|
|
4195
|
+
get entities() {
|
|
4196
|
+
return [...this.entryMap.values(), ...this.assetMap.values()];
|
|
4197
|
+
}
|
|
4198
|
+
updateEntity(entity) {
|
|
4199
|
+
this.addEntity(entity);
|
|
4200
|
+
}
|
|
4201
|
+
getEntryOrAsset(linkOrEntryOrAsset, path) {
|
|
4202
|
+
if (isDeepPath(path)) {
|
|
4203
|
+
return this.getDeepEntry(linkOrEntryOrAsset, path);
|
|
4204
|
+
}
|
|
4205
|
+
let entity;
|
|
4206
|
+
if (isLink(linkOrEntryOrAsset)) {
|
|
4207
|
+
const resolvedEntity = linkOrEntryOrAsset.sys.linkType === 'Entry'
|
|
4208
|
+
? this.entryMap.get(linkOrEntryOrAsset.sys.id)
|
|
4209
|
+
: this.assetMap.get(linkOrEntryOrAsset.sys.id);
|
|
4210
|
+
if (!resolvedEntity || resolvedEntity.sys.type !== linkOrEntryOrAsset.sys.linkType) {
|
|
4211
|
+
console.warn(`Experience references unresolved entity: ${JSON.stringify(linkOrEntryOrAsset)}`);
|
|
4212
|
+
return;
|
|
4213
|
+
}
|
|
4214
|
+
entity = resolvedEntity;
|
|
4215
|
+
}
|
|
4216
|
+
else if (isAsset(linkOrEntryOrAsset) || isEntry(linkOrEntryOrAsset)) {
|
|
4217
|
+
// We already have the complete entity in preview & delivery (resolved by the CMA client)
|
|
4218
|
+
entity = linkOrEntryOrAsset;
|
|
4219
|
+
}
|
|
4220
|
+
else {
|
|
4221
|
+
throw new Error(`Unexpected object when resolving entity: ${JSON.stringify(linkOrEntryOrAsset)}`);
|
|
4222
|
+
}
|
|
4223
|
+
return entity;
|
|
4224
|
+
}
|
|
4225
|
+
/**
|
|
4226
|
+
* @deprecated in the base class this should be simply an abstract method
|
|
4227
|
+
* @param entityLink
|
|
4228
|
+
* @param path
|
|
4229
|
+
* @returns
|
|
4230
|
+
*/
|
|
4231
|
+
getValue(entityLink, path) {
|
|
4232
|
+
const entity = this.getEntity(entityLink.sys.linkType, entityLink.sys.id);
|
|
4233
|
+
if (!entity) {
|
|
4234
|
+
// TODO: move to `debug` utils once it is extracted
|
|
4235
|
+
console.warn(`Unresolved entity reference: ${entityLink.sys.linkType} with ID ${entityLink.sys.id}`);
|
|
4236
|
+
return;
|
|
4237
|
+
}
|
|
4238
|
+
return get(entity, path);
|
|
4239
|
+
}
|
|
4240
|
+
getEntityFromLink(link) {
|
|
4241
|
+
const resolvedEntity = link.sys.linkType === 'Entry'
|
|
4242
|
+
? this.entryMap.get(link.sys.id)
|
|
4243
|
+
: this.assetMap.get(link.sys.id);
|
|
4244
|
+
if (!resolvedEntity || resolvedEntity.sys.type !== link.sys.linkType) {
|
|
4245
|
+
console.warn(`Experience references unresolved entity: ${JSON.stringify(link)}`);
|
|
4246
|
+
return;
|
|
4247
|
+
}
|
|
4248
|
+
return resolvedEntity;
|
|
4249
|
+
}
|
|
4250
|
+
getAssetById(assetId) {
|
|
4251
|
+
const asset = this.assetMap.get(assetId);
|
|
4252
|
+
if (!asset) {
|
|
4253
|
+
console.warn(`Asset with ID "${assetId}" is not found in the store`);
|
|
4254
|
+
return;
|
|
4255
|
+
}
|
|
4256
|
+
return asset;
|
|
4257
|
+
}
|
|
4258
|
+
getEntryById(entryId) {
|
|
4259
|
+
const entry = this.entryMap.get(entryId);
|
|
4260
|
+
if (!entry) {
|
|
4261
|
+
console.warn(`Entry with ID "${entryId}" is not found in the store`);
|
|
4262
|
+
return;
|
|
4263
|
+
}
|
|
4264
|
+
return entry;
|
|
4265
|
+
}
|
|
4266
|
+
getEntitiesFromMap(type, ids) {
|
|
4267
|
+
const resolved = [];
|
|
4268
|
+
const missing = [];
|
|
4269
|
+
for (const id of ids) {
|
|
4270
|
+
const entity = this.getEntity(type, id);
|
|
4271
|
+
if (entity) {
|
|
4272
|
+
resolved.push(entity);
|
|
4273
|
+
}
|
|
4274
|
+
else {
|
|
4275
|
+
missing.push(id);
|
|
4276
|
+
}
|
|
4277
|
+
}
|
|
4278
|
+
return {
|
|
4279
|
+
resolved,
|
|
4280
|
+
missing,
|
|
4281
|
+
};
|
|
4282
|
+
}
|
|
4283
|
+
addEntity(entity) {
|
|
4284
|
+
if (isAsset(entity)) {
|
|
4285
|
+
// cloned and frozen
|
|
4286
|
+
this.assetMap.set(entity.sys.id, deepFreeze(structuredClone(entity)));
|
|
4287
|
+
}
|
|
4288
|
+
else if (isEntry(entity)) {
|
|
4289
|
+
// cloned and frozen
|
|
4290
|
+
this.entryMap.set(entity.sys.id, deepFreeze(structuredClone(entity)));
|
|
4291
|
+
}
|
|
4292
|
+
else {
|
|
4293
|
+
throw new Error(`Attempted to add an entity to the store that is neither Asset nor Entry: '${JSON.stringify(entity)}'`);
|
|
4294
|
+
}
|
|
4295
|
+
}
|
|
4296
|
+
async fetchAsset(id) {
|
|
4297
|
+
const { resolved, missing } = this.getEntitiesFromMap('Asset', [id]);
|
|
4298
|
+
if (missing.length) {
|
|
4299
|
+
// TODO: move to `debug` utils once it is extracted
|
|
4300
|
+
console.warn(`Asset "${id}" is not in the store`);
|
|
4301
|
+
return;
|
|
4302
|
+
}
|
|
4303
|
+
return resolved[0];
|
|
4304
|
+
}
|
|
4305
|
+
async fetchAssets(ids) {
|
|
4306
|
+
const { resolved, missing } = this.getEntitiesFromMap('Asset', ids);
|
|
4307
|
+
if (missing.length) {
|
|
4308
|
+
throw new Error(`Missing assets in the store (${missing.join(',')})`);
|
|
4309
|
+
}
|
|
4310
|
+
return resolved;
|
|
4311
|
+
}
|
|
4312
|
+
async fetchEntry(id) {
|
|
4313
|
+
const { resolved, missing } = this.getEntitiesFromMap('Entry', [id]);
|
|
4314
|
+
if (missing.length) {
|
|
4315
|
+
// TODO: move to `debug` utils once it is extracted
|
|
4316
|
+
console.warn(`Entry "${id}" is not in the store`);
|
|
4317
|
+
return;
|
|
4318
|
+
}
|
|
4319
|
+
return resolved[0];
|
|
4320
|
+
}
|
|
4321
|
+
async fetchEntries(ids) {
|
|
4322
|
+
const { resolved, missing } = this.getEntitiesFromMap('Entry', ids);
|
|
4323
|
+
if (missing.length) {
|
|
4324
|
+
throw new Error(`Missing assets in the store (${missing.join(',')})`);
|
|
4325
|
+
}
|
|
4326
|
+
return resolved;
|
|
4327
|
+
}
|
|
4328
|
+
getDeepEntry(linkOrEntryOrAsset, path) {
|
|
4329
|
+
const resolveFieldset = (unresolvedFieldset, headEntry) => {
|
|
4330
|
+
const resolvedFieldset = [];
|
|
4331
|
+
let entityToResolveFieldsFrom = headEntry;
|
|
4332
|
+
for (let i = 0; i < unresolvedFieldset.length; i++) {
|
|
4333
|
+
const isLeaf = i === unresolvedFieldset.length - 1; // with last row, we are not expecting a link, but a value
|
|
4334
|
+
const row = unresolvedFieldset[i];
|
|
4335
|
+
const [, field, _localeQualifier] = row;
|
|
4336
|
+
if (!entityToResolveFieldsFrom) {
|
|
4337
|
+
throw new Error(`Logic Error: Cannot resolve field ${field} of a fieldset as there is no entity to resolve it from.`);
|
|
4338
|
+
}
|
|
4339
|
+
if (isLeaf) {
|
|
4340
|
+
resolvedFieldset.push([entityToResolveFieldsFrom, field, _localeQualifier]);
|
|
4341
|
+
break;
|
|
4342
|
+
}
|
|
4343
|
+
const fieldValue = get(entityToResolveFieldsFrom, ['fields', field]);
|
|
4344
|
+
if (undefined === fieldValue) {
|
|
4345
|
+
return {
|
|
4346
|
+
resolvedFieldset,
|
|
4347
|
+
isFullyResolved: false,
|
|
4348
|
+
reason: `Cannot resolve field Link<${entityToResolveFieldsFrom.sys.type}>(sys.id=${entityToResolveFieldsFrom.sys.id}).fields[${field}] as field value is not defined`,
|
|
4349
|
+
};
|
|
4350
|
+
}
|
|
4351
|
+
else if (isLink(fieldValue)) {
|
|
4352
|
+
const entity = this.getEntityFromLink(fieldValue);
|
|
4353
|
+
if (entity === undefined) {
|
|
4354
|
+
return {
|
|
4355
|
+
resolvedFieldset,
|
|
4356
|
+
isFullyResolved: false,
|
|
4357
|
+
reason: `Field reference Link (sys.id=${fieldValue.sys.id}) not found in the EntityStore, waiting...`,
|
|
4358
|
+
};
|
|
4359
|
+
}
|
|
4360
|
+
resolvedFieldset.push([entityToResolveFieldsFrom, field, _localeQualifier]);
|
|
4361
|
+
entityToResolveFieldsFrom = entity; // we move up
|
|
4362
|
+
}
|
|
4363
|
+
else if (isAsset(fieldValue) || isEntry(fieldValue)) {
|
|
4364
|
+
resolvedFieldset.push([entityToResolveFieldsFrom, field, _localeQualifier]);
|
|
4365
|
+
entityToResolveFieldsFrom = fieldValue; // we move up
|
|
4366
|
+
}
|
|
4367
|
+
else {
|
|
4368
|
+
return {
|
|
4369
|
+
resolvedFieldset,
|
|
4370
|
+
isFullyResolved: false,
|
|
4371
|
+
reason: `Deep path points to an invalid field value of type '${typeof fieldValue}' (value=${fieldValue})`,
|
|
4372
|
+
};
|
|
4373
|
+
}
|
|
4374
|
+
}
|
|
4375
|
+
return {
|
|
4376
|
+
resolvedFieldset,
|
|
4377
|
+
isFullyResolved: true,
|
|
4378
|
+
};
|
|
4379
|
+
};
|
|
4380
|
+
const headEntity = isLink(linkOrEntryOrAsset)
|
|
4381
|
+
? this.getEntityFromLink(linkOrEntryOrAsset)
|
|
4382
|
+
: linkOrEntryOrAsset;
|
|
4383
|
+
if (undefined === headEntity) {
|
|
4384
|
+
return;
|
|
4385
|
+
}
|
|
4386
|
+
const unresolvedFieldset = parseDataSourcePathIntoFieldset(path);
|
|
4387
|
+
// The purpose here is to take this intermediate representation of the deep-path
|
|
4388
|
+
// and to follow the links to the leaf-entity and field
|
|
4389
|
+
// in case we can't follow till the end, we should signal that there was null-reference in the path
|
|
4390
|
+
const { resolvedFieldset, isFullyResolved, reason } = resolveFieldset(unresolvedFieldset, headEntity);
|
|
4391
|
+
if (!isFullyResolved) {
|
|
4392
|
+
reason &&
|
|
4393
|
+
console.debug(`[exp-builder.sdk::EntityStoreBased::getValueDeep()] Deep path wasn't resolved till leaf node, falling back to undefined, because: ${reason}`);
|
|
4394
|
+
return;
|
|
4395
|
+
}
|
|
4396
|
+
const [leafEntity] = resolvedFieldset[resolvedFieldset.length - 1];
|
|
4397
|
+
return leafEntity;
|
|
4398
|
+
}
|
|
4399
|
+
getEntity(type, id) {
|
|
4400
|
+
if (type === 'Asset') {
|
|
4401
|
+
return this.assetMap.get(id);
|
|
4402
|
+
}
|
|
4403
|
+
return this.entryMap.get(id);
|
|
4404
|
+
}
|
|
4405
|
+
toJSON() {
|
|
4406
|
+
return {
|
|
4407
|
+
entryMap: Object.fromEntries(this.entryMap),
|
|
4408
|
+
assetMap: Object.fromEntries(this.assetMap),
|
|
4409
|
+
locale: this.locale,
|
|
4410
|
+
};
|
|
4411
|
+
}
|
|
4412
|
+
}
|
|
4413
|
+
|
|
4414
|
+
class UninitializedEntityStore extends EntityStoreBase {
|
|
4415
|
+
constructor() {
|
|
4416
|
+
super({ entities: [], locale: 'uninitialized-locale-in-uninitialized-entity-store' });
|
|
4417
|
+
}
|
|
4418
|
+
}
|
|
4419
|
+
|
|
4420
|
+
create((set, get) => ({
|
|
4421
|
+
// The UninitializedEntityStore is a placeholder instance and is here to highlight the
|
|
4422
|
+
// // fact that it's not used by anything until during loading lifecycle it'sreplaced by real entity store:
|
|
4423
|
+
// - in Preview+Delivery mode: right after we fetch Expereince and it entities
|
|
4424
|
+
// - in EDITOR (VisualEditor) mode: right after the VisualEditor is async imported and initialize event happens
|
|
4425
|
+
entityStore: new UninitializedEntityStore(),
|
|
4426
|
+
areEntitiesFetched: false,
|
|
4427
|
+
setEntitiesFetched(fetched) {
|
|
4428
|
+
set({ areEntitiesFetched: fetched });
|
|
4429
|
+
},
|
|
4430
|
+
resolveAssetById(assetId) {
|
|
4431
|
+
if (!assetId)
|
|
4432
|
+
return undefined;
|
|
4433
|
+
const { entityStore } = get();
|
|
4434
|
+
return entityStore.getAssetById(assetId);
|
|
4435
|
+
},
|
|
4436
|
+
resolveEntryById(entryId) {
|
|
4437
|
+
if (!entryId)
|
|
4438
|
+
return undefined;
|
|
4439
|
+
const { entityStore } = get();
|
|
4440
|
+
return entityStore.getEntryById(entryId);
|
|
4441
|
+
},
|
|
4442
|
+
resolveEntity(link) {
|
|
4443
|
+
if (!link)
|
|
4444
|
+
return undefined;
|
|
4445
|
+
const { entityStore } = get();
|
|
4446
|
+
return entityStore.getEntityFromLink(link);
|
|
4447
|
+
},
|
|
4448
|
+
resetEntityStore(entityStore) {
|
|
4449
|
+
set({
|
|
4450
|
+
entityStore,
|
|
4451
|
+
areEntitiesFetched: false,
|
|
4452
|
+
});
|
|
4453
|
+
},
|
|
4454
|
+
}));
|
|
4455
|
+
|
|
3935
4456
|
var VisualEditorMode;
|
|
3936
4457
|
(function (VisualEditorMode) {
|
|
3937
4458
|
VisualEditorMode["LazyLoad"] = "lazyLoad";
|
|
@@ -3996,23 +4517,6 @@ const Assembly = (props) => {
|
|
|
3996
4517
|
return React.createElement("div", { "data-test-id": "assembly", ...props, style: assemblyStyle });
|
|
3997
4518
|
};
|
|
3998
4519
|
|
|
3999
|
-
const useEntityStore = create((set) => ({
|
|
4000
|
-
entityStore: new EditorModeEntityStore({ locale: 'en-US', entities: [] }),
|
|
4001
|
-
areEntitiesFetched: false,
|
|
4002
|
-
setEntitiesFetched(fetched) {
|
|
4003
|
-
set({ areEntitiesFetched: fetched });
|
|
4004
|
-
},
|
|
4005
|
-
resetEntityStore(locale, entities = []) {
|
|
4006
|
-
console.debug(`[experiences-sdk-react] Resetting entity store because the locale changed to '${locale}'.`);
|
|
4007
|
-
const newEntityStore = new EditorModeEntityStore({ locale, entities });
|
|
4008
|
-
set({
|
|
4009
|
-
entityStore: newEntityStore,
|
|
4010
|
-
areEntitiesFetched: false,
|
|
4011
|
-
});
|
|
4012
|
-
return newEntityStore;
|
|
4013
|
-
},
|
|
4014
|
-
}));
|
|
4015
|
-
|
|
4016
4520
|
class DragState {
|
|
4017
4521
|
constructor() {
|
|
4018
4522
|
this.isDragStartedOnParent = false;
|
|
@@ -4082,10 +4586,11 @@ class SimulateDnD extends DragState {
|
|
|
4082
4586
|
}
|
|
4083
4587
|
var SimulateDnD$1 = new SimulateDnD();
|
|
4084
4588
|
|
|
4085
|
-
function useEditorSubscriber() {
|
|
4086
|
-
const entityStore =
|
|
4087
|
-
const areEntitiesFetched =
|
|
4088
|
-
const setEntitiesFetched =
|
|
4589
|
+
function useEditorSubscriber(entityCache) {
|
|
4590
|
+
const entityStore = entityCache((state) => state.entityStore);
|
|
4591
|
+
const areEntitiesFetched = entityCache((state) => state.areEntitiesFetched);
|
|
4592
|
+
const setEntitiesFetched = entityCache((state) => state.setEntitiesFetched);
|
|
4593
|
+
const resetEntityStore = entityCache((state) => state.resetEntityStore);
|
|
4089
4594
|
const { updateTree, updateNodesByUpdatedEntity } = useTreeStore((state) => ({
|
|
4090
4595
|
updateTree: state.updateTree,
|
|
4091
4596
|
updateNodesByUpdatedEntity: state.updateNodesByUpdatedEntity,
|
|
@@ -4097,7 +4602,6 @@ function useEditorSubscriber() {
|
|
|
4097
4602
|
const setDataSource = useEditorStore((state) => state.setDataSource);
|
|
4098
4603
|
const setSelectedNodeId = useEditorStore((state) => state.setSelectedNodeId);
|
|
4099
4604
|
const selectedNodeId = useEditorStore((state) => state.selectedNodeId);
|
|
4100
|
-
const resetEntityStore = useEntityStore((state) => state.resetEntityStore);
|
|
4101
4605
|
const setComponentId = useDraggedItemStore((state) => state.setComponentId);
|
|
4102
4606
|
const setHoveredComponentId = useDraggedItemStore((state) => state.setHoveredComponentId);
|
|
4103
4607
|
const setDraggingOnCanvas = useDraggedItemStore((state) => state.setDraggingOnCanvas);
|
|
@@ -4148,7 +4652,7 @@ function useEditorSubscriber() {
|
|
|
4148
4652
|
const isMissingL2Entities = (deepReferences) => {
|
|
4149
4653
|
const referentLinks = deepReferences
|
|
4150
4654
|
.map((deepReference) => deepReference.extractReferent(entityStore))
|
|
4151
|
-
.filter(isLink);
|
|
4655
|
+
.filter(isLink$1);
|
|
4152
4656
|
const { missingAssetIds, missingEntryIds } = entityStore.getMissingEntityIds(referentLinks);
|
|
4153
4657
|
return Boolean(missingAssetIds.length) || Boolean(missingEntryIds.length);
|
|
4154
4658
|
};
|
|
@@ -4165,7 +4669,7 @@ function useEditorSubscriber() {
|
|
|
4165
4669
|
const fillupL2 = async ({ deepReferences }) => {
|
|
4166
4670
|
const referentLinks = deepReferences
|
|
4167
4671
|
.map((deepReference) => deepReference.extractReferent(entityStore))
|
|
4168
|
-
.filter(isLink);
|
|
4672
|
+
.filter(isLink$1);
|
|
4169
4673
|
const { missingAssetIds, missingEntryIds } = entityStore.getMissingEntityIds(referentLinks);
|
|
4170
4674
|
await entityStore.fetchEntities({ missingAssetIds, missingEntryIds });
|
|
4171
4675
|
};
|
|
@@ -4218,8 +4722,9 @@ function useEditorSubscriber() {
|
|
|
4218
4722
|
}
|
|
4219
4723
|
let newEntityStore = entityStore;
|
|
4220
4724
|
if (entityStore.locale !== locale) {
|
|
4221
|
-
newEntityStore =
|
|
4725
|
+
newEntityStore = new EditorModeEntityStore({ locale, entities: [] });
|
|
4222
4726
|
setLocale(locale);
|
|
4727
|
+
resetEntityStore(newEntityStore);
|
|
4223
4728
|
}
|
|
4224
4729
|
// Below are mutually exclusive cases
|
|
4225
4730
|
if (changedNode) {
|
|
@@ -4749,17 +5254,49 @@ const addStylesTag = (className, styleRules) => {
|
|
|
4749
5254
|
|
|
4750
5255
|
const getUnboundValues = ({ key, fallback, unboundValues, }) => {
|
|
4751
5256
|
const lodashPath = `${key}.value`;
|
|
4752
|
-
return get$
|
|
5257
|
+
return get$2(unboundValues, lodashPath, fallback);
|
|
5258
|
+
};
|
|
5259
|
+
|
|
5260
|
+
/**
|
|
5261
|
+
* When node is a pattern block, we need to look up for default values of the pattern variables
|
|
5262
|
+
* and merge them with the updated node props.
|
|
5263
|
+
* While loop is making sure that we look up for the updated default values in the parent pattern
|
|
5264
|
+
* component settings as well.
|
|
5265
|
+
*/
|
|
5266
|
+
const maybeMergePatternDefaultDesignValues = ({ variableName, variableMapping, node, findNodeById, }) => {
|
|
5267
|
+
if (node.type === ASSEMBLY_BLOCK_NODE_TYPE) {
|
|
5268
|
+
const patternId = node.data.pattern?.id;
|
|
5269
|
+
const exposedPropertyName = node['exposedPropertyNameToKeyMap'][variableName];
|
|
5270
|
+
if (!exposedPropertyName || !patternId) {
|
|
5271
|
+
return variableMapping.valuesByBreakpoint;
|
|
5272
|
+
}
|
|
5273
|
+
const exposedVariableDefinition = componentRegistry.get(patternId)?.definition.variables[exposedPropertyName];
|
|
5274
|
+
let exposedDefaultValue = exposedVariableDefinition?.defaultValue;
|
|
5275
|
+
let parentPatternNode = findNodeById(node.data.pattern?.nodeId);
|
|
5276
|
+
while (parentPatternNode) {
|
|
5277
|
+
const parentPatternId = parentPatternNode.data.pattern?.id;
|
|
5278
|
+
const nextKey = parentPatternNode['exposedPropertyNameToKeyMap'][exposedPropertyName];
|
|
5279
|
+
if (!parentPatternId || !nextKey) {
|
|
5280
|
+
break;
|
|
5281
|
+
}
|
|
5282
|
+
const parentPatternVariableDefinition = componentRegistry.get(parentPatternId)?.definition.variables[nextKey];
|
|
5283
|
+
exposedDefaultValue = mergeDesignValuesByBreakpoint(parentPatternVariableDefinition?.defaultValue, exposedDefaultValue);
|
|
5284
|
+
parentPatternNode = findNodeById(parentPatternNode.data.pattern?.nodeId);
|
|
5285
|
+
}
|
|
5286
|
+
const mergedDesignValue = mergeDesignValuesByBreakpoint(exposedDefaultValue, variableMapping);
|
|
5287
|
+
return mergedDesignValue?.valuesByBreakpoint;
|
|
5288
|
+
}
|
|
5289
|
+
return variableMapping.valuesByBreakpoint;
|
|
4753
5290
|
};
|
|
4754
5291
|
|
|
4755
|
-
const useComponentProps = ({ node, areEntitiesFetched, resolveDesignValue, renderDropzone, definition, options, userIsDragging, requiresDragWrapper, }) => {
|
|
5292
|
+
const useComponentProps = ({ node, entityStore, areEntitiesFetched, resolveDesignValue, renderDropzone, definition, options, userIsDragging, requiresDragWrapper, }) => {
|
|
4756
5293
|
const unboundValues = useEditorStore((state) => state.unboundValues);
|
|
4757
5294
|
const hyperlinkPattern = useEditorStore((state) => state.hyperLinkPattern);
|
|
4758
5295
|
const locale = useEditorStore((state) => state.locale);
|
|
4759
5296
|
const dataSource = useEditorStore((state) => state.dataSource);
|
|
4760
|
-
const entityStore = useEntityStore((state) => state.entityStore);
|
|
4761
5297
|
const draggingId = useDraggedItemStore((state) => state.onBeforeCaptureId);
|
|
4762
5298
|
const nodeRect = useDraggedItemStore((state) => state.domRect);
|
|
5299
|
+
const findNodeById = useTreeStore((state) => state.findNodeById);
|
|
4763
5300
|
const isEmptyZone = !node.children.length;
|
|
4764
5301
|
const props = useMemo(() => {
|
|
4765
5302
|
const propsBase = {
|
|
@@ -4783,7 +5320,13 @@ const useComponentProps = ({ node, areEntitiesFetched, resolveDesignValue, rende
|
|
|
4783
5320
|
};
|
|
4784
5321
|
}
|
|
4785
5322
|
if (variableMapping.type === 'DesignValue') {
|
|
4786
|
-
const
|
|
5323
|
+
const value = maybeMergePatternDefaultDesignValues({
|
|
5324
|
+
variableName,
|
|
5325
|
+
variableMapping,
|
|
5326
|
+
node,
|
|
5327
|
+
findNodeById,
|
|
5328
|
+
});
|
|
5329
|
+
const valuesByBreakpoint = resolveDesignValue(value, variableName);
|
|
4787
5330
|
const designValue = variableName === 'cfHeight'
|
|
4788
5331
|
? calculateNodeDefaultHeight({
|
|
4789
5332
|
blockId: node.data.blockId,
|
|
@@ -4874,6 +5417,7 @@ const useComponentProps = ({ node, areEntitiesFetched, resolveDesignValue, rende
|
|
|
4874
5417
|
unboundValues,
|
|
4875
5418
|
entityStore,
|
|
4876
5419
|
renderDropzone,
|
|
5420
|
+
findNodeById,
|
|
4877
5421
|
]);
|
|
4878
5422
|
const cfStyles = useMemo(() => ({
|
|
4879
5423
|
...buildCfStyles(props),
|
|
@@ -5046,7 +5590,6 @@ const MissingComponentPlaceholder = ({ blockId }) => {
|
|
|
5046
5590
|
};
|
|
5047
5591
|
|
|
5048
5592
|
const CircularDependencyErrorPlaceholder = forwardRef(({ wrappingPatternIds, ...props }, ref) => {
|
|
5049
|
-
const entityStore = useEntityStore((state) => state.entityStore);
|
|
5050
5593
|
return (React.createElement("div", { ...props,
|
|
5051
5594
|
// Pass through ref to avoid DND errors being logged
|
|
5052
5595
|
ref: ref, "data-cf-node-error": "circular-pattern-dependency", style: {
|
|
@@ -5059,7 +5602,7 @@ const CircularDependencyErrorPlaceholder = forwardRef(({ wrappingPatternIds, ...
|
|
|
5059
5602
|
"Circular usage of patterns detected:",
|
|
5060
5603
|
React.createElement("ul", null, Array.from(wrappingPatternIds).map((patternId) => {
|
|
5061
5604
|
const entryLink = { sys: { type: 'Link', linkType: 'Entry', id: patternId } };
|
|
5062
|
-
const entry =
|
|
5605
|
+
const entry = inMemoryEntities.maybeResolveLink(entryLink);
|
|
5063
5606
|
const entryTitle = entry?.fields?.title;
|
|
5064
5607
|
const text = entryTitle ? `${entryTitle} (${patternId})` : patternId;
|
|
5065
5608
|
return React.createElement("li", { key: patternId }, text);
|
|
@@ -5067,8 +5610,7 @@ const CircularDependencyErrorPlaceholder = forwardRef(({ wrappingPatternIds, ...
|
|
|
5067
5610
|
});
|
|
5068
5611
|
CircularDependencyErrorPlaceholder.displayName = 'CircularDependencyErrorPlaceholder';
|
|
5069
5612
|
|
|
5070
|
-
const useComponent = ({ node, resolveDesignValue, renderDropzone, userIsDragging, wrappingPatternIds, }) => {
|
|
5071
|
-
const areEntitiesFetched = useEntityStore((state) => state.areEntitiesFetched);
|
|
5613
|
+
const useComponent = ({ node, entityStore, areEntitiesFetched, resolveDesignValue, renderDropzone, userIsDragging, wrappingPatternIds, }) => {
|
|
5072
5614
|
const tree = useTreeStore((state) => state.tree);
|
|
5073
5615
|
const componentRegistration = useMemo(() => {
|
|
5074
5616
|
let registration = componentRegistry.get(node.data.blockId);
|
|
@@ -5094,6 +5636,7 @@ const useComponent = ({ node, resolveDesignValue, renderDropzone, userIsDragging
|
|
|
5094
5636
|
const requiresDragWrapper = !isPatternNode && !isStructureComponent && !componentRegistration?.options?.wrapComponent;
|
|
5095
5637
|
const { componentProps, wrapperStyles } = useComponentProps({
|
|
5096
5638
|
node,
|
|
5639
|
+
entityStore,
|
|
5097
5640
|
areEntitiesFetched,
|
|
5098
5641
|
resolveDesignValue,
|
|
5099
5642
|
renderDropzone,
|
|
@@ -5568,13 +6111,15 @@ function getStyle$1(style, snapshot) {
|
|
|
5568
6111
|
transitionDuration: `0.001s`,
|
|
5569
6112
|
};
|
|
5570
6113
|
}
|
|
5571
|
-
const EditorBlock = ({ node: rawNode, resolveDesignValue, renderDropzone, index, zoneId, userIsDragging, placeholder, wrappingPatternIds, }) => {
|
|
6114
|
+
const EditorBlock = ({ node: rawNode, entityStore, areEntitiesFetched, resolveDesignValue, renderDropzone, index, zoneId, userIsDragging, placeholder, wrappingPatternIds, }) => {
|
|
5572
6115
|
const { slotId } = parseZoneId(zoneId);
|
|
5573
6116
|
const ref = useRef(null);
|
|
5574
6117
|
const setSelectedNodeId = useEditorStore((state) => state.setSelectedNodeId);
|
|
5575
6118
|
const selectedNodeId = useEditorStore((state) => state.selectedNodeId);
|
|
5576
6119
|
const { node, componentId, elementToRender, definition, isPatternNode, isPatternComponent, isNestedPattern, } = useComponent({
|
|
5577
6120
|
node: rawNode,
|
|
6121
|
+
entityStore,
|
|
6122
|
+
areEntitiesFetched,
|
|
5578
6123
|
resolveDesignValue,
|
|
5579
6124
|
renderDropzone,
|
|
5580
6125
|
userIsDragging,
|
|
@@ -5715,10 +6260,12 @@ function getStyle(style = {}, snapshot) {
|
|
|
5715
6260
|
transitionDuration: `0.001s`,
|
|
5716
6261
|
};
|
|
5717
6262
|
}
|
|
5718
|
-
const EditorBlockClone = ({ node: rawNode, resolveDesignValue, snapshot, provided, renderDropzone, wrappingPatternIds, }) => {
|
|
6263
|
+
const EditorBlockClone = ({ node: rawNode, entityStore, areEntitiesFetched, resolveDesignValue, snapshot, provided, renderDropzone, wrappingPatternIds, }) => {
|
|
5719
6264
|
const userIsDragging = useDraggedItemStore((state) => state.isDraggingOnCanvas);
|
|
5720
6265
|
const { node, elementToRender } = useComponent({
|
|
5721
6266
|
node: rawNode,
|
|
6267
|
+
entityStore,
|
|
6268
|
+
areEntitiesFetched,
|
|
5722
6269
|
resolveDesignValue,
|
|
5723
6270
|
renderDropzone,
|
|
5724
6271
|
userIsDragging,
|
|
@@ -5755,7 +6302,7 @@ const getHtmlComponentProps = (props) => {
|
|
|
5755
6302
|
return {};
|
|
5756
6303
|
};
|
|
5757
6304
|
|
|
5758
|
-
function DropzoneClone({ node, zoneId, resolveDesignValue, WrapperComponent = 'div', renderDropzone, dragProps, wrappingPatternIds, ...rest }) {
|
|
6305
|
+
function DropzoneClone({ node, entityStore, zoneId, resolveDesignValue, WrapperComponent = 'div', renderDropzone, dragProps, wrappingPatternIds, areEntitiesFetched, ...rest }) {
|
|
5759
6306
|
const tree = useTreeStore((state) => state.tree);
|
|
5760
6307
|
const content = node?.children || tree.root?.children || [];
|
|
5761
6308
|
const { slotId } = parseZoneId(zoneId);
|
|
@@ -5776,11 +6323,11 @@ function DropzoneClone({ node, zoneId, resolveDesignValue, WrapperComponent = 'd
|
|
|
5776
6323
|
.filter((node) => node.data.slotId === slotId)
|
|
5777
6324
|
.map((item) => {
|
|
5778
6325
|
const componentId = item.data.id;
|
|
5779
|
-
return (React.createElement(EditorBlockClone, { key: componentId, node: item, resolveDesignValue: resolveDesignValue, renderDropzone: renderDropzone, wrappingPatternIds: wrappingPatternIds }));
|
|
6326
|
+
return (React.createElement(EditorBlockClone, { entityStore: entityStore, areEntitiesFetched: areEntitiesFetched, key: componentId, node: item, resolveDesignValue: resolveDesignValue, renderDropzone: renderDropzone, wrappingPatternIds: wrappingPatternIds }));
|
|
5780
6327
|
})));
|
|
5781
6328
|
}
|
|
5782
6329
|
|
|
5783
|
-
function Dropzone({ node, zoneId, resolveDesignValue, className, WrapperComponent = 'div', dragProps, wrappingPatternIds: parentWrappingPatternIds = new Set(), ...rest }) {
|
|
6330
|
+
function Dropzone({ node, zoneId, resolveDesignValue, className, WrapperComponent = 'div', dragProps, entityStore, areEntitiesFetched, wrappingPatternIds: parentWrappingPatternIds = new Set(), ...rest }) {
|
|
5784
6331
|
const userIsDragging = useDraggedItemStore((state) => state.isDraggingOnCanvas);
|
|
5785
6332
|
const draggedItem = useDraggedItemStore((state) => state.draggedItem);
|
|
5786
6333
|
const isDraggingNewComponent = useDraggedItemStore((state) => Boolean(state.componentId));
|
|
@@ -5815,11 +6362,11 @@ function Dropzone({ node, zoneId, resolveDesignValue, className, WrapperComponen
|
|
|
5815
6362
|
}, [isRootAssembly, node, parentWrappingPatternIds, tree.root.data.blockId]);
|
|
5816
6363
|
// To avoid a circular dependency, we create the recursive rendering function here and trickle it down
|
|
5817
6364
|
const renderDropzone = useCallback((node, props) => {
|
|
5818
|
-
return (React.createElement(Dropzone, { zoneId: node.data.id, node: node, resolveDesignValue: resolveDesignValue, wrappingPatternIds: wrappingPatternIds, ...props }));
|
|
5819
|
-
}, [wrappingPatternIds, resolveDesignValue]);
|
|
6365
|
+
return (React.createElement(Dropzone, { zoneId: node.data.id, entityStore: entityStore, node: node, resolveDesignValue: resolveDesignValue, wrappingPatternIds: wrappingPatternIds, areEntitiesFetched: areEntitiesFetched, ...props }));
|
|
6366
|
+
}, [wrappingPatternIds, resolveDesignValue, entityStore, areEntitiesFetched]);
|
|
5820
6367
|
const renderClonedDropzone = useCallback((node, props) => {
|
|
5821
|
-
return (React.createElement(DropzoneClone, { zoneId: node.data.id, node: node, resolveDesignValue: resolveDesignValue, renderDropzone: renderClonedDropzone, wrappingPatternIds: wrappingPatternIds, ...props }));
|
|
5822
|
-
}, [resolveDesignValue, wrappingPatternIds]);
|
|
6368
|
+
return (React.createElement(DropzoneClone, { entityStore: entityStore, areEntitiesFetched: areEntitiesFetched, zoneId: node.data.id, node: node, resolveDesignValue: resolveDesignValue, renderDropzone: renderClonedDropzone, wrappingPatternIds: wrappingPatternIds, ...props }));
|
|
6369
|
+
}, [resolveDesignValue, wrappingPatternIds, entityStore, areEntitiesFetched]);
|
|
5823
6370
|
const isDropzoneEnabled = useMemo(() => {
|
|
5824
6371
|
const isColumns = node?.data.blockId === CONTENTFUL_COMPONENTS$1.columns.id;
|
|
5825
6372
|
const isDraggingSingleColumn = draggedNode?.data.blockId === CONTENTFUL_COMPONENTS$1.singleColumn.id;
|
|
@@ -5861,7 +6408,7 @@ function Dropzone({ node, zoneId, resolveDesignValue, className, WrapperComponen
|
|
|
5861
6408
|
? node.children.length === 1 &&
|
|
5862
6409
|
resolveDesignValue(node?.children[0]?.data.props.cfWidth?.valuesByBreakpoint ?? {}, 'cfWidth') === '100%'
|
|
5863
6410
|
: false;
|
|
5864
|
-
return (React.createElement(Droppable, { droppableId: zoneId, direction: direction, isDropDisabled: !isDropzoneEnabled, renderClone: (provided, snapshot, rubic) => (React.createElement(EditorBlockClone, { node: content[rubic.source.index], resolveDesignValue: resolveDesignValue, provided: provided, snapshot: snapshot, renderDropzone: renderClonedDropzone, wrappingPatternIds: wrappingPatternIds })) }, (provided, snapshot) => {
|
|
6411
|
+
return (React.createElement(Droppable, { droppableId: zoneId, direction: direction, isDropDisabled: !isDropzoneEnabled, renderClone: (provided, snapshot, rubic) => (React.createElement(EditorBlockClone, { entityStore: entityStore, areEntitiesFetched: areEntitiesFetched, node: content[rubic.source.index], resolveDesignValue: resolveDesignValue, provided: provided, snapshot: snapshot, renderDropzone: renderClonedDropzone, wrappingPatternIds: wrappingPatternIds })) }, (provided, snapshot) => {
|
|
5865
6412
|
return (React.createElement(WrapperComponent, { ...(provided || { droppableProps: {} }).droppableProps, ...htmlDraggableProps, ...htmlProps, ref: (refNode) => {
|
|
5866
6413
|
if (dragProps?.innerRef) {
|
|
5867
6414
|
dragProps.innerRef(refNode);
|
|
@@ -5879,7 +6426,7 @@ function Dropzone({ node, zoneId, resolveDesignValue, className, WrapperComponen
|
|
|
5879
6426
|
}) },
|
|
5880
6427
|
isEmptyCanvas ? (React.createElement(EmptyContainer, { isDragging: isRootZone && userIsDragging })) : (content
|
|
5881
6428
|
.filter((node) => node.data.slotId === slotId)
|
|
5882
|
-
.map((item, i) => (React.createElement(EditorBlock, { placeholder: {
|
|
6429
|
+
.map((item, i) => (React.createElement(EditorBlock, { entityStore: entityStore, areEntitiesFetched: areEntitiesFetched, placeholder: {
|
|
5883
6430
|
isDraggingOver: snapshot?.isDraggingOver,
|
|
5884
6431
|
totalIndexes: content.length,
|
|
5885
6432
|
elementIndex: i,
|
|
@@ -5891,8 +6438,8 @@ function Dropzone({ node, zoneId, resolveDesignValue, className, WrapperComponen
|
|
|
5891
6438
|
}));
|
|
5892
6439
|
}
|
|
5893
6440
|
|
|
5894
|
-
const RootRenderer = ({ onChange }) => {
|
|
5895
|
-
useEditorSubscriber();
|
|
6441
|
+
const RootRenderer = ({ onChange, inMemoryEntitiesStore, }) => {
|
|
6442
|
+
useEditorSubscriber(inMemoryEntitiesStore);
|
|
5896
6443
|
const dragItem = useDraggedItemStore((state) => state.componentId);
|
|
5897
6444
|
const userIsDragging = useDraggedItemStore((state) => state.isDraggingOnCanvas);
|
|
5898
6445
|
const setHoveredComponentId = useDraggedItemStore((state) => state.setHoveredComponentId);
|
|
@@ -5972,28 +6519,28 @@ const RootRenderer = ({ onChange }) => {
|
|
|
5972
6519
|
handleResizeCanvas();
|
|
5973
6520
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
5974
6521
|
}, [containerRef.current]);
|
|
6522
|
+
const entityStore = inMemoryEntitiesStore((state) => state.entityStore);
|
|
6523
|
+
const areEntitiesFetched = inMemoryEntitiesStore((state) => state.areEntitiesFetched);
|
|
5975
6524
|
return (React.createElement(DNDProvider, null,
|
|
5976
6525
|
dragItem && React.createElement(DraggableContainer, { id: dragItem }),
|
|
5977
6526
|
React.createElement("div", { "data-ctfl-root": true, className: styles$3.container, ref: containerRef, style: containerStyles },
|
|
5978
6527
|
userIsDragging && React.createElement("div", { "data-ctfl-zone-id": ROOT_ID, className: styles$3.hitbox }),
|
|
5979
|
-
React.createElement(Dropzone, { zoneId: ROOT_ID, resolveDesignValue: resolveDesignValue }),
|
|
6528
|
+
React.createElement(Dropzone, { zoneId: ROOT_ID, resolveDesignValue: resolveDesignValue, entityStore: entityStore, areEntitiesFetched: areEntitiesFetched }),
|
|
5980
6529
|
userIsDragging && (React.createElement(React.Fragment, null,
|
|
5981
6530
|
React.createElement("div", { "data-ctfl-zone-id": ROOT_ID, className: styles$3.hitboxLower }),
|
|
5982
6531
|
React.createElement("div", { "data-ctfl-zone-id": ROOT_ID, className: styles$3.canvasBottomSpacer })))),
|
|
5983
6532
|
React.createElement("div", { "data-ctfl-hitboxes": true })));
|
|
5984
6533
|
};
|
|
5985
6534
|
|
|
5986
|
-
const useInitializeEditor = () => {
|
|
6535
|
+
const useInitializeEditor = (inMemoryEntitiesStore) => {
|
|
5987
6536
|
const initializeEditor = useEditorStore((state) => state.initializeEditor);
|
|
5988
6537
|
const [initialized, setInitialized] = useState(false);
|
|
5989
|
-
const resetEntityStore =
|
|
6538
|
+
const resetEntityStore = useStore(inMemoryEntitiesStore, (state) => state.resetEntityStore);
|
|
5990
6539
|
useEffect(() => {
|
|
5991
6540
|
const onVisualEditorInitialize = (event) => {
|
|
5992
6541
|
if (!event.detail)
|
|
5993
6542
|
return;
|
|
5994
|
-
const { componentRegistry, designTokens, locale: initialLocale,
|
|
5995
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
5996
|
-
entities, } = event.detail;
|
|
6543
|
+
const { componentRegistry, designTokens, locale: initialLocale, entities } = event.detail;
|
|
5997
6544
|
initializeEditor({
|
|
5998
6545
|
initialLocale,
|
|
5999
6546
|
componentRegistry,
|
|
@@ -6001,7 +6548,7 @@ const useInitializeEditor = () => {
|
|
|
6001
6548
|
});
|
|
6002
6549
|
// if entities is set to [], then everything will still work as EntityStore will
|
|
6003
6550
|
// request entities on demand via ▲REQUEST_ENTITY
|
|
6004
|
-
resetEntityStore(initialLocale, entities);
|
|
6551
|
+
resetEntityStore(new EditorModeEntityStore({ locale: initialLocale, entities }));
|
|
6005
6552
|
setInitialized(true);
|
|
6006
6553
|
};
|
|
6007
6554
|
// Listen for VisualEditorComponents internal event
|
|
@@ -6021,8 +6568,8 @@ const useInitializeEditor = () => {
|
|
|
6021
6568
|
return initialized;
|
|
6022
6569
|
};
|
|
6023
6570
|
|
|
6024
|
-
const VisualEditorRoot = ({ experience }) => {
|
|
6025
|
-
const initialized = useInitializeEditor();
|
|
6571
|
+
const VisualEditorRoot = ({ experience, inMemoryEntitiesStore: inMemoryEntitiesStore$1 = inMemoryEntitiesStore, }) => {
|
|
6572
|
+
const initialized = useInitializeEditor(inMemoryEntitiesStore$1);
|
|
6026
6573
|
const setHyperLinkPattern = useEditorStore((state) => state.setHyperLinkPattern);
|
|
6027
6574
|
const setMousePosition = useDraggedItemStore((state) => state.setMousePosition);
|
|
6028
6575
|
const setHoveringZone = useZoneStore((state) => state.setHoveringZone);
|
|
@@ -6058,7 +6605,7 @@ const VisualEditorRoot = ({ experience }) => {
|
|
|
6058
6605
|
}, [setHoveringZone, setMousePosition]);
|
|
6059
6606
|
if (!initialized)
|
|
6060
6607
|
return null;
|
|
6061
|
-
return React.createElement(RootRenderer,
|
|
6608
|
+
return React.createElement(RootRenderer, { inMemoryEntitiesStore: inMemoryEntitiesStore$1 });
|
|
6062
6609
|
};
|
|
6063
6610
|
|
|
6064
6611
|
export { VisualEditorRoot as default };
|