@contentful/experiences-visual-editor-react 3.1.1 → 3.2.0-dev-20250812T1437-66fa8cb.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +128 -53
- package/dist/index.js.map +1 -1
- package/dist/renderApp.js +128 -53
- package/dist/renderApp.js.map +1 -1
- package/package.json +4 -4
package/dist/renderApp.js
CHANGED
|
@@ -44069,35 +44069,69 @@ const breakpointsRefinement$1 = (value, ctx) => {
|
|
|
44069
44069
|
code: z.ZodIssueCode.custom,
|
|
44070
44070
|
message: `The first breakpoint should include the following attributes: { "query": "*" }`,
|
|
44071
44071
|
});
|
|
44072
|
+
return;
|
|
44072
44073
|
}
|
|
44073
|
-
|
|
44074
|
-
|
|
44075
|
-
|
|
44076
|
-
return
|
|
44077
|
-
}
|
|
44074
|
+
// Return early if there's only one generic breakpoint
|
|
44075
|
+
const hasNoBreakpointsStrategy = value.length === 1;
|
|
44076
|
+
if (hasNoBreakpointsStrategy) {
|
|
44077
|
+
return;
|
|
44078
|
+
}
|
|
44079
|
+
// Check if any breakpoint id occurs twice
|
|
44080
|
+
const ids = value.map((breakpoint) => breakpoint.id);
|
|
44081
|
+
const hasDuplicateIds = new Set(ids).size !== ids.length;
|
|
44078
44082
|
if (hasDuplicateIds) {
|
|
44079
44083
|
ctx.addIssue({
|
|
44080
44084
|
code: z.ZodIssueCode.custom,
|
|
44081
44085
|
message: `Breakpoint IDs must be unique`,
|
|
44082
44086
|
});
|
|
44087
|
+
return;
|
|
44083
44088
|
}
|
|
44084
|
-
//
|
|
44085
|
-
const
|
|
44086
|
-
|
|
44087
|
-
const
|
|
44088
|
-
|
|
44089
|
-
|
|
44090
|
-
|
|
44089
|
+
// Skip the first one which is guaranteed to be a wildcard query
|
|
44090
|
+
const nonBaseBreakpoints = value.slice(1);
|
|
44091
|
+
const isMobileFirstStrategy = nonBaseBreakpoints[0].query.startsWith('>');
|
|
44092
|
+
const isDesktopFirstStrategy = nonBaseBreakpoints[0].query.startsWith('<');
|
|
44093
|
+
if (isMobileFirstStrategy) {
|
|
44094
|
+
const areOperatorsEqual = nonBaseBreakpoints.every(({ query }) => query.startsWith('>'));
|
|
44095
|
+
if (!areOperatorsEqual) {
|
|
44096
|
+
ctx.addIssue({
|
|
44097
|
+
code: z.ZodIssueCode.custom,
|
|
44098
|
+
message: `Breakpoint queries must be in the format ">[size]px" for mobile-first strategy`,
|
|
44099
|
+
});
|
|
44091
44100
|
}
|
|
44092
|
-
|
|
44093
|
-
|
|
44101
|
+
// Extract the queries boundary by removing the special characters around it
|
|
44102
|
+
const queries = nonBaseBreakpoints.map((bp) => parseInt(bp.query.replace(/px|<|>/, '')));
|
|
44103
|
+
// Starting with the third breakpoint, check that every query is higher than the one above
|
|
44104
|
+
const isIncreasing = queries.every((value, index, array) => index === 0 || value > array[index - 1]);
|
|
44105
|
+
if (!isIncreasing) {
|
|
44106
|
+
ctx.addIssue({
|
|
44107
|
+
code: z.ZodIssueCode.custom,
|
|
44108
|
+
message: `When using a mobile-first strategy, all breakpoints must have strictly increasing pixel values`,
|
|
44109
|
+
});
|
|
44094
44110
|
}
|
|
44095
|
-
|
|
44096
|
-
|
|
44097
|
-
|
|
44111
|
+
}
|
|
44112
|
+
else if (isDesktopFirstStrategy) {
|
|
44113
|
+
const areOperatorsEqual = nonBaseBreakpoints.every(({ query }) => query.startsWith('<'));
|
|
44114
|
+
if (!areOperatorsEqual) {
|
|
44115
|
+
ctx.addIssue({
|
|
44116
|
+
code: z.ZodIssueCode.custom,
|
|
44117
|
+
message: `Breakpoint queries must be in the format "<[size]px" for desktop-first strategy`,
|
|
44118
|
+
});
|
|
44119
|
+
}
|
|
44120
|
+
// Extract the queries boundary by removing the special characters around it
|
|
44121
|
+
const queries = nonBaseBreakpoints.map((bp) => parseInt(bp.query.replace(/px|<|>/, '')));
|
|
44122
|
+
// Starting with the third breakpoint, check that every query is lower than the one above
|
|
44123
|
+
const isDecreasing = queries.every((value, index, array) => index === 0 || value < array[index - 1]);
|
|
44124
|
+
if (!isDecreasing) {
|
|
44125
|
+
ctx.addIssue({
|
|
44126
|
+
code: z.ZodIssueCode.custom,
|
|
44127
|
+
message: `When using a desktop-first strategy, all breakpoints must have strictly decreasing pixel values`,
|
|
44128
|
+
});
|
|
44129
|
+
}
|
|
44130
|
+
}
|
|
44131
|
+
else if (!isMobileFirstStrategy && !isDesktopFirstStrategy) {
|
|
44098
44132
|
ctx.addIssue({
|
|
44099
44133
|
code: z.ZodIssueCode.custom,
|
|
44100
|
-
message: `
|
|
44134
|
+
message: `You may only use a mobile-first or desktop-first strategy for breakpoints using '<' or '>' queries`,
|
|
44101
44135
|
});
|
|
44102
44136
|
}
|
|
44103
44137
|
};
|
|
@@ -44156,7 +44190,7 @@ const ParametersSchema$1 = z.record(propertyKeySchema$1, ParameterSchema$1);
|
|
|
44156
44190
|
const BreakpointSchema$1 = z
|
|
44157
44191
|
.object({
|
|
44158
44192
|
id: propertyKeySchema$1,
|
|
44159
|
-
query: z.string().regex(
|
|
44193
|
+
query: z.string().regex(/^\*$|^[<>][0-9*]+px$/),
|
|
44160
44194
|
previewSize: z.string(),
|
|
44161
44195
|
displayName: z.string(),
|
|
44162
44196
|
displayIcon: z.enum(['desktop', 'tablet', 'mobile']).optional(),
|
|
@@ -44434,7 +44468,7 @@ const toCSSMediaQuery = ({ query }) => {
|
|
|
44434
44468
|
};
|
|
44435
44469
|
// Remove this helper when upgrading to TypeScript 5.0 - https://github.com/microsoft/TypeScript/issues/48829
|
|
44436
44470
|
const findLast = (array, predicate) => {
|
|
44437
|
-
return array.reverse().find(predicate);
|
|
44471
|
+
return [...array].reverse().find(predicate);
|
|
44438
44472
|
};
|
|
44439
44473
|
// Initialise media query matchers. This won't include the always matching fallback breakpoint.
|
|
44440
44474
|
const mediaQueryMatcher = (breakpoints) => {
|
|
@@ -44454,19 +44488,19 @@ const mediaQueryMatcher = (breakpoints) => {
|
|
|
44454
44488
|
return [mediaQueryMatchers, mediaQueryMatches];
|
|
44455
44489
|
};
|
|
44456
44490
|
const getActiveBreakpointIndex = (breakpoints, mediaQueryMatches, fallbackBreakpointIndex) => {
|
|
44457
|
-
// The breakpoints are ordered (desktop-first: descending by screen width)
|
|
44491
|
+
// The breakpoints are ordered (desktop-first: descending by screen width, mobile-first: ascending by screen width).
|
|
44458
44492
|
const breakpointsWithMatches = breakpoints.map(({ id }, index) => ({
|
|
44459
44493
|
id,
|
|
44460
44494
|
index,
|
|
44461
44495
|
// The fallback breakpoint with wildcard query will always match
|
|
44462
44496
|
isMatch: mediaQueryMatches[id] ?? index === fallbackBreakpointIndex,
|
|
44463
44497
|
}));
|
|
44464
|
-
// Find the last breakpoint in the list that matches (desktop-first: the narrowest one)
|
|
44498
|
+
// Find the last breakpoint in the list that matches (desktop-first: the narrowest one, mobile-first: the widest one)
|
|
44465
44499
|
const mostSpecificIndex = findLast(breakpointsWithMatches, ({ isMatch }) => isMatch)?.index;
|
|
44466
44500
|
return mostSpecificIndex ?? fallbackBreakpointIndex;
|
|
44467
44501
|
};
|
|
44468
44502
|
const getFallbackBreakpointIndex = (breakpoints) => {
|
|
44469
|
-
//
|
|
44503
|
+
// The validation ensures that there will be exactly one breakpoint using the wildcard query.
|
|
44470
44504
|
// If there is none, we just take the first one in the list.
|
|
44471
44505
|
return Math.max(breakpoints.findIndex(({ query }) => query === '*'), 0);
|
|
44472
44506
|
};
|
|
@@ -48684,35 +48718,69 @@ const breakpointsRefinement = (value, ctx) => {
|
|
|
48684
48718
|
code: z.ZodIssueCode.custom,
|
|
48685
48719
|
message: `The first breakpoint should include the following attributes: { "query": "*" }`,
|
|
48686
48720
|
});
|
|
48721
|
+
return;
|
|
48687
48722
|
}
|
|
48688
|
-
|
|
48689
|
-
|
|
48690
|
-
|
|
48691
|
-
return
|
|
48692
|
-
}
|
|
48723
|
+
// Return early if there's only one generic breakpoint
|
|
48724
|
+
const hasNoBreakpointsStrategy = value.length === 1;
|
|
48725
|
+
if (hasNoBreakpointsStrategy) {
|
|
48726
|
+
return;
|
|
48727
|
+
}
|
|
48728
|
+
// Check if any breakpoint id occurs twice
|
|
48729
|
+
const ids = value.map((breakpoint) => breakpoint.id);
|
|
48730
|
+
const hasDuplicateIds = new Set(ids).size !== ids.length;
|
|
48693
48731
|
if (hasDuplicateIds) {
|
|
48694
48732
|
ctx.addIssue({
|
|
48695
48733
|
code: z.ZodIssueCode.custom,
|
|
48696
48734
|
message: `Breakpoint IDs must be unique`,
|
|
48697
48735
|
});
|
|
48736
|
+
return;
|
|
48698
48737
|
}
|
|
48699
|
-
//
|
|
48700
|
-
const
|
|
48701
|
-
|
|
48702
|
-
const
|
|
48703
|
-
|
|
48704
|
-
|
|
48705
|
-
|
|
48738
|
+
// Skip the first one which is guaranteed to be a wildcard query
|
|
48739
|
+
const nonBaseBreakpoints = value.slice(1);
|
|
48740
|
+
const isMobileFirstStrategy = nonBaseBreakpoints[0].query.startsWith('>');
|
|
48741
|
+
const isDesktopFirstStrategy = nonBaseBreakpoints[0].query.startsWith('<');
|
|
48742
|
+
if (isMobileFirstStrategy) {
|
|
48743
|
+
const areOperatorsEqual = nonBaseBreakpoints.every(({ query }) => query.startsWith('>'));
|
|
48744
|
+
if (!areOperatorsEqual) {
|
|
48745
|
+
ctx.addIssue({
|
|
48746
|
+
code: z.ZodIssueCode.custom,
|
|
48747
|
+
message: `Breakpoint queries must be in the format ">[size]px" for mobile-first strategy`,
|
|
48748
|
+
});
|
|
48706
48749
|
}
|
|
48707
|
-
|
|
48708
|
-
|
|
48750
|
+
// Extract the queries boundary by removing the special characters around it
|
|
48751
|
+
const queries = nonBaseBreakpoints.map((bp) => parseInt(bp.query.replace(/px|<|>/, '')));
|
|
48752
|
+
// Starting with the third breakpoint, check that every query is higher than the one above
|
|
48753
|
+
const isIncreasing = queries.every((value, index, array) => index === 0 || value > array[index - 1]);
|
|
48754
|
+
if (!isIncreasing) {
|
|
48755
|
+
ctx.addIssue({
|
|
48756
|
+
code: z.ZodIssueCode.custom,
|
|
48757
|
+
message: `When using a mobile-first strategy, all breakpoints must have strictly increasing pixel values`,
|
|
48758
|
+
});
|
|
48709
48759
|
}
|
|
48710
|
-
|
|
48711
|
-
|
|
48712
|
-
|
|
48760
|
+
}
|
|
48761
|
+
else if (isDesktopFirstStrategy) {
|
|
48762
|
+
const areOperatorsEqual = nonBaseBreakpoints.every(({ query }) => query.startsWith('<'));
|
|
48763
|
+
if (!areOperatorsEqual) {
|
|
48764
|
+
ctx.addIssue({
|
|
48765
|
+
code: z.ZodIssueCode.custom,
|
|
48766
|
+
message: `Breakpoint queries must be in the format "<[size]px" for desktop-first strategy`,
|
|
48767
|
+
});
|
|
48768
|
+
}
|
|
48769
|
+
// Extract the queries boundary by removing the special characters around it
|
|
48770
|
+
const queries = nonBaseBreakpoints.map((bp) => parseInt(bp.query.replace(/px|<|>/, '')));
|
|
48771
|
+
// Starting with the third breakpoint, check that every query is lower than the one above
|
|
48772
|
+
const isDecreasing = queries.every((value, index, array) => index === 0 || value < array[index - 1]);
|
|
48773
|
+
if (!isDecreasing) {
|
|
48774
|
+
ctx.addIssue({
|
|
48775
|
+
code: z.ZodIssueCode.custom,
|
|
48776
|
+
message: `When using a desktop-first strategy, all breakpoints must have strictly decreasing pixel values`,
|
|
48777
|
+
});
|
|
48778
|
+
}
|
|
48779
|
+
}
|
|
48780
|
+
else if (!isMobileFirstStrategy && !isDesktopFirstStrategy) {
|
|
48713
48781
|
ctx.addIssue({
|
|
48714
48782
|
code: z.ZodIssueCode.custom,
|
|
48715
|
-
message: `
|
|
48783
|
+
message: `You may only use a mobile-first or desktop-first strategy for breakpoints using '<' or '>' queries`,
|
|
48716
48784
|
});
|
|
48717
48785
|
}
|
|
48718
48786
|
};
|
|
@@ -48771,7 +48839,7 @@ const ParametersSchema = z.record(propertyKeySchema, ParameterSchema);
|
|
|
48771
48839
|
const BreakpointSchema = z
|
|
48772
48840
|
.object({
|
|
48773
48841
|
id: propertyKeySchema,
|
|
48774
|
-
query: z.string().regex(
|
|
48842
|
+
query: z.string().regex(/^\*$|^[<>][0-9*]+px$/),
|
|
48775
48843
|
previewSize: z.string(),
|
|
48776
48844
|
displayName: z.string(),
|
|
48777
48845
|
displayIcon: z.enum(['desktop', 'tablet', 'mobile']).optional(),
|
|
@@ -50222,7 +50290,7 @@ const collectNodeCoordinates = (node, nodeToCoordinatesMap) => {
|
|
|
50222
50290
|
node.children.forEach((child) => collectNodeCoordinates(child, nodeToCoordinatesMap));
|
|
50223
50291
|
};
|
|
50224
50292
|
function waitForImageToBeLoaded(imageNode) {
|
|
50225
|
-
if (imageNode.complete) {
|
|
50293
|
+
if (imageNode.complete && (imageNode.naturalWidth > 0 || imageNode.naturalHeight > 0)) {
|
|
50226
50294
|
return Promise.resolve();
|
|
50227
50295
|
}
|
|
50228
50296
|
return new Promise((resolve, reject) => {
|
|
@@ -50256,8 +50324,8 @@ const useCanvasGeometryUpdates = ({ tree, canvasMode }) => {
|
|
|
50256
50324
|
trailing: true,
|
|
50257
50325
|
}), []);
|
|
50258
50326
|
const debouncedCollectImages = reactExports.useMemo(() => debounce(() => {
|
|
50259
|
-
|
|
50260
|
-
}, 300, {
|
|
50327
|
+
setImages((prev) => ({ ...prev, allImages: findAllImages() }));
|
|
50328
|
+
}, 300, { trailing: true }), []);
|
|
50261
50329
|
// Store tree in a ref to avoid the need to deactivate & reactivate the mutation observer
|
|
50262
50330
|
// when the tree changes. This is important to avoid missing out on some mutation events.
|
|
50263
50331
|
const treeRef = reactExports.useRef(tree);
|
|
@@ -50266,13 +50334,17 @@ const useCanvasGeometryUpdates = ({ tree, canvasMode }) => {
|
|
|
50266
50334
|
}, [tree]);
|
|
50267
50335
|
// Handling window resize events
|
|
50268
50336
|
reactExports.useEffect(() => {
|
|
50269
|
-
const resizeEventListener = () =>
|
|
50337
|
+
const resizeEventListener = () => {
|
|
50338
|
+
debouncedUpdateGeometry(treeRef.current, 'resize');
|
|
50339
|
+
// find all images on resize
|
|
50340
|
+
debouncedCollectImages();
|
|
50341
|
+
};
|
|
50270
50342
|
window.addEventListener('resize', resizeEventListener);
|
|
50271
50343
|
return () => window.removeEventListener('resize', resizeEventListener);
|
|
50272
|
-
}, [debouncedUpdateGeometry]);
|
|
50344
|
+
}, [debouncedCollectImages, debouncedUpdateGeometry]);
|
|
50273
50345
|
const [{ allImages, loadedImages }, setImages] = reactExports.useState(() => {
|
|
50274
|
-
const allImages =
|
|
50275
|
-
const loadedImages = new
|
|
50346
|
+
const allImages = findAllImages();
|
|
50347
|
+
const loadedImages = new WeakMap();
|
|
50276
50348
|
return { allImages, loadedImages };
|
|
50277
50349
|
});
|
|
50278
50350
|
// Handling DOM mutations
|
|
@@ -50280,8 +50352,7 @@ const useCanvasGeometryUpdates = ({ tree, canvasMode }) => {
|
|
|
50280
50352
|
const observer = new MutationObserver(() => {
|
|
50281
50353
|
debouncedUpdateGeometry(treeRef.current, 'mutation');
|
|
50282
50354
|
// find all images on any DOM change
|
|
50283
|
-
|
|
50284
|
-
setImages((prevState) => ({ ...prevState, allImages }));
|
|
50355
|
+
debouncedCollectImages();
|
|
50285
50356
|
});
|
|
50286
50357
|
// send initial geometry in case the tree is empty
|
|
50287
50358
|
debouncedUpdateGeometry(treeRef.current, 'mutation');
|
|
@@ -50297,13 +50368,14 @@ const useCanvasGeometryUpdates = ({ tree, canvasMode }) => {
|
|
|
50297
50368
|
reactExports.useEffect(() => {
|
|
50298
50369
|
let isCurrent = true;
|
|
50299
50370
|
allImages.forEach(async (imageNode) => {
|
|
50300
|
-
|
|
50371
|
+
const lastSrc = loadedImages.get(imageNode);
|
|
50372
|
+
if (lastSrc === imageNode.currentSrc) {
|
|
50301
50373
|
return;
|
|
50302
50374
|
}
|
|
50303
50375
|
// update the geometry after each image is loaded, as it can shift the layout
|
|
50304
50376
|
await waitForImageToBeLoaded(imageNode);
|
|
50305
50377
|
if (isCurrent) {
|
|
50306
|
-
loadedImages.
|
|
50378
|
+
loadedImages.set(imageNode, imageNode.currentSrc);
|
|
50307
50379
|
debouncedUpdateGeometry(treeRef.current, 'imageLoad');
|
|
50308
50380
|
}
|
|
50309
50381
|
});
|
|
@@ -50330,6 +50402,9 @@ const useCanvasGeometryUpdates = ({ tree, canvasMode }) => {
|
|
|
50330
50402
|
return () => document.removeEventListener('wheel', onWheel);
|
|
50331
50403
|
}, [canvasMode]);
|
|
50332
50404
|
};
|
|
50405
|
+
function findAllImages() {
|
|
50406
|
+
return Array.from(document.querySelectorAll('img'));
|
|
50407
|
+
}
|
|
50333
50408
|
|
|
50334
50409
|
const RootRenderer = ({ inMemoryEntitiesStore, canvasMode }) => {
|
|
50335
50410
|
useEditorSubscriber(inMemoryEntitiesStore);
|