@contentful/experiences-visual-editor-react 0.0.1-alpha.8 → 0.0.1-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2,10 +2,10 @@ import styleInject from 'style-inject';
2
2
  import React, { useRef, useMemo, useEffect, useState, forwardRef, useCallback } from 'react';
3
3
  import md5 from 'md5';
4
4
  import { BLOCKS } from '@contentful/rich-text-types';
5
+ import { isEqual, get as get$1, omit } from 'lodash-es';
5
6
  import { Draggable, Droppable, DragDropContext } from '@hello-pangea/dnd';
6
7
  import classNames from 'classnames';
7
8
  import { create } from 'zustand';
8
- import { isEqual, get as get$1, omit } from 'lodash-es';
9
9
  import '@contentful/rich-text-react-renderer';
10
10
  import { produce } from 'immer';
11
11
  import { createPortal } from 'react-dom';
@@ -49,23 +49,23 @@ const CONTENTFUL_COMPONENTS$1 = {
49
49
  name: 'Column',
50
50
  },
51
51
  button: {
52
- id: 'button',
52
+ id: 'contentful-button',
53
53
  name: 'Button',
54
54
  },
55
55
  heading: {
56
- id: 'heading',
56
+ id: 'contentful-heading',
57
57
  name: 'Heading',
58
58
  },
59
59
  image: {
60
- id: 'image',
60
+ id: 'contentful-image',
61
61
  name: 'Image',
62
62
  },
63
63
  richText: {
64
- id: 'richText',
64
+ id: 'contentful-richText',
65
65
  name: 'Rich Text',
66
66
  },
67
67
  text: {
68
- id: 'text',
68
+ id: 'contentful-text',
69
69
  name: 'Text',
70
70
  },
71
71
  };
@@ -329,7 +329,7 @@ const buildStyleTag = ({ styles, nodeId }) => {
329
329
  const styleRule = `.${className}{ ${stylesStr} }`;
330
330
  return [className, styleRule];
331
331
  };
332
- const buildCfStyles = ({ cfHorizontalAlignment, cfVerticalAlignment, cfFlexDirection, cfFlexWrap, cfMargin, cfPadding, cfBackgroundColor, cfWidth, cfHeight, cfMaxWidth, cfBorder, cfGap, cfBackgroundImageUrl, cfBackgroundImageOptions, cfFontSize, cfFontWeight, cfImageOptions, cfLineHeight, cfLetterSpacing, cfTextColor, cfTextAlign, cfTextTransform, cfTextBold, cfTextItalic, cfTextUnderline, cfColumnSpan, }) => {
332
+ const buildCfStyles = ({ cfHorizontalAlignment, cfVerticalAlignment, cfFlexDirection, cfFlexWrap, cfMargin, cfPadding, cfBackgroundColor, cfWidth, cfHeight, cfMaxWidth, cfBorder, cfBorderRadius, cfGap, cfBackgroundImageUrl, cfBackgroundImageOptions, cfFontSize, cfFontWeight, cfImageOptions, cfLineHeight, cfLetterSpacing, cfTextColor, cfTextAlign, cfTextTransform, cfTextBold, cfTextItalic, cfTextUnderline, cfColumnSpan, }) => {
333
333
  return {
334
334
  margin: cfMargin,
335
335
  padding: cfPadding,
@@ -339,6 +339,7 @@ const buildCfStyles = ({ cfHorizontalAlignment, cfVerticalAlignment, cfFlexDirec
339
339
  maxWidth: cfMaxWidth,
340
340
  ...transformGridColumn(cfColumnSpan),
341
341
  ...transformBorderStyle(cfBorder),
342
+ borderRadius: cfBorderRadius,
342
343
  gap: cfGap,
343
344
  ...transformAlignment(cfHorizontalAlignment, cfVerticalAlignment, cfFlexDirection),
344
345
  flexDirection: cfFlexDirection,
@@ -423,6 +424,9 @@ const transformRichText = (entryOrAsset, path) => {
423
424
  };
424
425
 
425
426
  function getOptimizedImageUrl(url, width, quality, format) {
427
+ if (url.startsWith('//')) {
428
+ url = 'https:' + url;
429
+ }
426
430
  const params = new URLSearchParams();
427
431
  if (width) {
428
432
  params.append('w', width.toString());
@@ -437,63 +441,67 @@ function getOptimizedImageUrl(url, width, quality, format) {
437
441
  return `${url}${queryString ? '?' + queryString : ''}`;
438
442
  }
439
443
 
444
+ function validateParams(file, quality, format) {
445
+ if (!file.details.image) {
446
+ throw Error('No image in file asset to transform');
447
+ }
448
+ if (quality < 0 || quality > 100) {
449
+ throw Error('Quality must be between 0 and 100');
450
+ }
451
+ if (format && !SUPPORTED_IMAGE_FORMATS.includes(format)) {
452
+ throw Error(`Format must be one of ${SUPPORTED_IMAGE_FORMATS.join(', ')}`);
453
+ }
454
+ return true;
455
+ }
456
+
440
457
  const MAX_WIDTH_ALLOWED$1 = 2000;
441
- const getOptimizedBackgroundImageAsset = (file, widthStyle, quality = 100, format) => {
442
- if (!validateParams(file, quality, format)) ;
458
+ const getOptimizedBackgroundImageAsset = (file, widthStyle, quality = '100%', format) => {
459
+ const qualityNumber = Number(quality.replace('%', ''));
460
+ if (!validateParams(file, qualityNumber, format)) ;
461
+ if (!validateParams(file, qualityNumber, format)) ;
443
462
  const url = file.url;
444
463
  const { width1x, width2x } = getWidths(widthStyle, file);
445
- const imageUrl1x = getOptimizedImageUrl(url, width1x, quality, format);
446
- const imageUrl2x = getOptimizedImageUrl(url, width2x, quality, format);
464
+ const imageUrl1x = getOptimizedImageUrl(url, width1x, qualityNumber, format);
465
+ const imageUrl2x = getOptimizedImageUrl(url, width2x, qualityNumber, format);
447
466
  const srcSet = [`url(${imageUrl1x}) 1x`, `url(${imageUrl2x}) 2x`];
448
- const returnedUrlImageUrl = getOptimizedImageUrl(url, width2x, quality, format);
467
+ const returnedUrl = getOptimizedImageUrl(url, width2x, qualityNumber, format);
449
468
  const optimizedBackgroundImageAsset = {
450
- url: returnedUrlImageUrl,
469
+ url: returnedUrl,
451
470
  srcSet,
452
471
  file,
453
472
  };
454
473
  return optimizedBackgroundImageAsset;
455
- function validateParams(file, quality, format) {
456
- if (!file.details.image) {
457
- throw Error('No image in file asset to transform');
458
- }
459
- if (quality < 0 || quality > 100) {
460
- throw Error('Quality must be between 0 and 100');
474
+ function getWidths(widthStyle, file) {
475
+ let width1x = 0;
476
+ let width2x = 0;
477
+ const intrinsicImageWidth = file.details.image.width;
478
+ if (widthStyle.endsWith('px')) {
479
+ width1x = Math.min(Number(widthStyle.replace('px', '')), intrinsicImageWidth);
461
480
  }
462
- if (format && !SUPPORTED_IMAGE_FORMATS.includes(format)) {
463
- throw Error(`Format must be one of ${SUPPORTED_IMAGE_FORMATS.join(', ')}`);
481
+ else {
482
+ width1x = Math.min(MAX_WIDTH_ALLOWED$1, intrinsicImageWidth);
464
483
  }
465
- return true;
484
+ width2x = Math.min(width1x * 2, intrinsicImageWidth);
485
+ return { width1x, width2x };
466
486
  }
467
487
  };
468
- function getWidths(widthStyle, file) {
469
- let width1x = 0;
470
- let width2x = 0;
471
- const intrinsicImageWidth = file.details.image.width;
472
- if (widthStyle.endsWith('px')) {
473
- width1x = Math.min(Number(widthStyle.replace('px', '')), intrinsicImageWidth);
474
- }
475
- else {
476
- width1x = Math.min(MAX_WIDTH_ALLOWED$1, intrinsicImageWidth);
477
- }
478
- width2x = Math.min(width1x * 2, intrinsicImageWidth);
479
- return { width1x, width2x };
480
- }
481
488
 
482
489
  const MAX_WIDTH_ALLOWED = 4000;
483
- const getOptimizedImageAsset = (file, sizes, quality = 100, format) => {
484
- if (!validateParams(file, quality, format)) ;
490
+ const getOptimizedImageAsset = (file, sizes, quality = '100%', format) => {
491
+ const qualityNumber = Number(quality.replace('%', ''));
492
+ if (!validateParams(file, qualityNumber, format)) ;
485
493
  const url = file.url;
486
494
  const maxWidth = Math.min(file.details.image.width, MAX_WIDTH_ALLOWED);
487
495
  const numOfParts = Math.max(2, Math.ceil(maxWidth / 500));
488
496
  const widthParts = Array.from({ length: numOfParts }, (_, index) => Math.ceil((index + 1) * (maxWidth / numOfParts)));
489
497
  const srcSet = sizes
490
- ? widthParts.map((width) => `${getOptimizedImageUrl(url, width, quality, format)} ${width}w`)
498
+ ? widthParts.map((width) => `${getOptimizedImageUrl(url, width, qualityNumber, format)} ${width}w`)
491
499
  : [];
492
500
  const intrinsicImageWidth = file.details.image.width;
493
501
  if (intrinsicImageWidth > MAX_WIDTH_ALLOWED) {
494
- srcSet.push(`${getOptimizedImageUrl(url, undefined, quality, format)} ${intrinsicImageWidth}w`);
502
+ srcSet.push(`${getOptimizedImageUrl(url, undefined, qualityNumber, format)} ${intrinsicImageWidth}w`);
495
503
  }
496
- const returnedUrl = getOptimizedImageUrl(url, file.details.image.width > 2000 ? 2000 : undefined, quality, format);
504
+ const returnedUrl = getOptimizedImageUrl(url, file.details.image.width > 2000 ? 2000 : undefined, qualityNumber, format);
497
505
  const optimizedImageAsset = {
498
506
  url: returnedUrl,
499
507
  srcSet,
@@ -501,18 +509,6 @@ const getOptimizedImageAsset = (file, sizes, quality = 100, format) => {
501
509
  file,
502
510
  };
503
511
  return optimizedImageAsset;
504
- function validateParams(file, quality, format) {
505
- if (!file.details.image) {
506
- throw Error('No image in file asset to transform');
507
- }
508
- if (quality < 0 || quality > 100) {
509
- throw Error('Quality must be between 0 and 100');
510
- }
511
- if (format && !SUPPORTED_IMAGE_FORMATS.includes(format)) {
512
- throw Error(`Format must be one of ${SUPPORTED_IMAGE_FORMATS.join(', ')}`);
513
- }
514
- return true;
515
- }
516
512
  };
517
513
 
518
514
  const transformMedia = (asset, variables, resolveDesignValue, variableName, path) => {
@@ -528,7 +524,7 @@ const transformMedia = (asset, variables, resolveDesignValue, variableName, path
528
524
  return;
529
525
  }
530
526
  try {
531
- value = getOptimizedImageAsset(asset.fields.file, options.targetSize, Number(options.quality), options.format);
527
+ value = getOptimizedImageAsset(asset.fields.file, options.targetSize, options.quality, options.format);
532
528
  return value;
533
529
  }
534
530
  catch (error) {
@@ -547,7 +543,7 @@ const transformMedia = (asset, variables, resolveDesignValue, variableName, path
547
543
  return;
548
544
  }
549
545
  try {
550
- value = getOptimizedBackgroundImageAsset(asset.fields.file, width, Number(options.quality), options.format);
546
+ value = getOptimizedBackgroundImageAsset(asset.fields.file, width, options.quality, options.format);
551
547
  return value;
552
548
  }
553
549
  catch (error) {
@@ -594,6 +590,7 @@ const getDataFromTree = (tree) => {
594
590
  };
595
591
  };
596
592
 
593
+ // These styles get added to every component, user custom or contentful provided
597
594
  const builtInStyles = {
598
595
  cfVerticalAlignment: {
599
596
  validations: {
@@ -770,9 +767,6 @@ const optionalBuiltInStyles = {
770
767
  defaultValue: {
771
768
  width: DEFAULT_IMAGE_WIDTH,
772
769
  height: '100%',
773
- objectFit: 'none',
774
- objectPosition: 'center center',
775
- quality: '100',
776
770
  targetSize: DEFAULT_IMAGE_WIDTH,
777
771
  },
778
772
  },
@@ -788,10 +782,16 @@ const optionalBuiltInStyles = {
788
782
  defaultValue: {
789
783
  scaling: 'fill',
790
784
  alignment: 'left top',
791
- quality: '100',
792
785
  targetSize: '2000px',
793
786
  },
794
787
  },
788
+ cfBorderRadius: {
789
+ displayName: 'Border Radius',
790
+ type: 'Text',
791
+ group: 'style',
792
+ description: 'The border radius of the section',
793
+ defaultValue: '0px',
794
+ },
795
795
  cfLineHeight: {
796
796
  displayName: 'Line Height',
797
797
  type: 'Text',
@@ -993,6 +993,7 @@ const builtInStylesWithDesignTokens = [
993
993
  'cfHeight',
994
994
  'cfBackgroundColor',
995
995
  'cfBorder',
996
+ 'cfBorderRadius',
996
997
  'cfFontSize',
997
998
  'cfLineHeight',
998
999
  'cfLetterSpacing',
@@ -1701,23 +1702,23 @@ const CONTENTFUL_COMPONENTS = {
1701
1702
  name: 'Column',
1702
1703
  },
1703
1704
  button: {
1704
- id: 'button',
1705
+ id: 'contentful-button',
1705
1706
  name: 'Button',
1706
1707
  },
1707
1708
  heading: {
1708
- id: 'heading',
1709
+ id: 'contentful-heading',
1709
1710
  name: 'Heading',
1710
1711
  },
1711
1712
  image: {
1712
- id: 'image',
1713
+ id: 'contentful-image',
1713
1714
  name: 'Image',
1714
1715
  },
1715
1716
  richText: {
1716
- id: 'richText',
1717
+ id: 'contentful-richText',
1717
1718
  name: 'Rich Text',
1718
1719
  },
1719
1720
  text: {
1720
- id: 'text',
1721
+ id: 'contentful-text',
1721
1722
  name: 'Text',
1722
1723
  },
1723
1724
  };
@@ -1741,6 +1742,7 @@ const CF_STYLE_ATTRIBUTES = [
1741
1742
  'cfFlexDirection',
1742
1743
  'cfFlexWrap',
1743
1744
  'cfBorder',
1745
+ 'cfBorderRadius',
1744
1746
  'cfGap',
1745
1747
  'cfFontSize',
1746
1748
  'cfFontWeight',
@@ -2662,15 +2664,15 @@ const useComponent = ({ node: rawNode, resolveDesignValue, renderDropzone, userI
2662
2664
  return rawNode;
2663
2665
  }, [areEntitiesFetched, rawNode, entityStore]);
2664
2666
  const componentRegistration = useMemo(() => {
2665
- const registration = componentRegistry.get(node.data.blockId);
2667
+ let registration = componentRegistry.get(node.data.blockId);
2666
2668
  if (node.type === ASSEMBLY_NODE_TYPE && !registration) {
2667
- return createAssemblyRegistration({
2669
+ registration = createAssemblyRegistration({
2668
2670
  definitionId: node.data.blockId,
2669
2671
  component: Assembly,
2670
2672
  });
2671
2673
  }
2672
- else if (!registration) {
2673
- console.warn(`[experiences-sdk-react] Component registration not found for ${node.data.blockId}`);
2674
+ if (!registration) {
2675
+ throw Error(`Component registration not found for component with id: "${node.data.blockId}". The component might of been removed. To proceed, remove the component manually from the layers tab.`);
2674
2676
  }
2675
2677
  return registration;
2676
2678
  }, [node]);