@contentful/experiences-visual-editor-react 0.0.1-alpha.9 → 0.0.1-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.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
  };
@@ -424,6 +424,9 @@ const transformRichText = (entryOrAsset, path) => {
424
424
  };
425
425
 
426
426
  function getOptimizedImageUrl(url, width, quality, format) {
427
+ if (url.startsWith('//')) {
428
+ url = 'https:' + url;
429
+ }
427
430
  const params = new URLSearchParams();
428
431
  if (width) {
429
432
  params.append('w', width.toString());
@@ -438,63 +441,67 @@ function getOptimizedImageUrl(url, width, quality, format) {
438
441
  return `${url}${queryString ? '?' + queryString : ''}`;
439
442
  }
440
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
+
441
457
  const MAX_WIDTH_ALLOWED$1 = 2000;
442
- const getOptimizedBackgroundImageAsset = (file, widthStyle, quality = 100, format) => {
443
- 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)) ;
444
462
  const url = file.url;
445
463
  const { width1x, width2x } = getWidths(widthStyle, file);
446
- const imageUrl1x = getOptimizedImageUrl(url, width1x, quality, format);
447
- const imageUrl2x = getOptimizedImageUrl(url, width2x, quality, format);
464
+ const imageUrl1x = getOptimizedImageUrl(url, width1x, qualityNumber, format);
465
+ const imageUrl2x = getOptimizedImageUrl(url, width2x, qualityNumber, format);
448
466
  const srcSet = [`url(${imageUrl1x}) 1x`, `url(${imageUrl2x}) 2x`];
449
- const returnedUrlImageUrl = getOptimizedImageUrl(url, width2x, quality, format);
467
+ const returnedUrl = getOptimizedImageUrl(url, width2x, qualityNumber, format);
450
468
  const optimizedBackgroundImageAsset = {
451
- url: returnedUrlImageUrl,
469
+ url: returnedUrl,
452
470
  srcSet,
453
471
  file,
454
472
  };
455
473
  return optimizedBackgroundImageAsset;
456
- function validateParams(file, quality, format) {
457
- if (!file.details.image) {
458
- throw Error('No image in file asset to transform');
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);
459
480
  }
460
- if (quality < 0 || quality > 100) {
461
- throw Error('Quality must be between 0 and 100');
462
- }
463
- if (format && !SUPPORTED_IMAGE_FORMATS.includes(format)) {
464
- throw Error(`Format must be one of ${SUPPORTED_IMAGE_FORMATS.join(', ')}`);
481
+ else {
482
+ width1x = Math.min(MAX_WIDTH_ALLOWED$1, intrinsicImageWidth);
465
483
  }
466
- return true;
484
+ width2x = Math.min(width1x * 2, intrinsicImageWidth);
485
+ return { width1x, width2x };
467
486
  }
468
487
  };
469
- function getWidths(widthStyle, file) {
470
- let width1x = 0;
471
- let width2x = 0;
472
- const intrinsicImageWidth = file.details.image.width;
473
- if (widthStyle.endsWith('px')) {
474
- width1x = Math.min(Number(widthStyle.replace('px', '')), intrinsicImageWidth);
475
- }
476
- else {
477
- width1x = Math.min(MAX_WIDTH_ALLOWED$1, intrinsicImageWidth);
478
- }
479
- width2x = Math.min(width1x * 2, intrinsicImageWidth);
480
- return { width1x, width2x };
481
- }
482
488
 
483
489
  const MAX_WIDTH_ALLOWED = 4000;
484
- const getOptimizedImageAsset = (file, sizes, quality = 100, format) => {
485
- 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)) ;
486
493
  const url = file.url;
487
494
  const maxWidth = Math.min(file.details.image.width, MAX_WIDTH_ALLOWED);
488
495
  const numOfParts = Math.max(2, Math.ceil(maxWidth / 500));
489
496
  const widthParts = Array.from({ length: numOfParts }, (_, index) => Math.ceil((index + 1) * (maxWidth / numOfParts)));
490
497
  const srcSet = sizes
491
- ? widthParts.map((width) => `${getOptimizedImageUrl(url, width, quality, format)} ${width}w`)
498
+ ? widthParts.map((width) => `${getOptimizedImageUrl(url, width, qualityNumber, format)} ${width}w`)
492
499
  : [];
493
500
  const intrinsicImageWidth = file.details.image.width;
494
501
  if (intrinsicImageWidth > MAX_WIDTH_ALLOWED) {
495
- srcSet.push(`${getOptimizedImageUrl(url, undefined, quality, format)} ${intrinsicImageWidth}w`);
502
+ srcSet.push(`${getOptimizedImageUrl(url, undefined, qualityNumber, format)} ${intrinsicImageWidth}w`);
496
503
  }
497
- 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);
498
505
  const optimizedImageAsset = {
499
506
  url: returnedUrl,
500
507
  srcSet,
@@ -502,18 +509,6 @@ const getOptimizedImageAsset = (file, sizes, quality = 100, format) => {
502
509
  file,
503
510
  };
504
511
  return optimizedImageAsset;
505
- function validateParams(file, quality, format) {
506
- if (!file.details.image) {
507
- throw Error('No image in file asset to transform');
508
- }
509
- if (quality < 0 || quality > 100) {
510
- throw Error('Quality must be between 0 and 100');
511
- }
512
- if (format && !SUPPORTED_IMAGE_FORMATS.includes(format)) {
513
- throw Error(`Format must be one of ${SUPPORTED_IMAGE_FORMATS.join(', ')}`);
514
- }
515
- return true;
516
- }
517
512
  };
518
513
 
519
514
  const transformMedia = (asset, variables, resolveDesignValue, variableName, path) => {
@@ -529,7 +524,7 @@ const transformMedia = (asset, variables, resolveDesignValue, variableName, path
529
524
  return;
530
525
  }
531
526
  try {
532
- value = getOptimizedImageAsset(asset.fields.file, options.targetSize, Number(options.quality), options.format);
527
+ value = getOptimizedImageAsset(asset.fields.file, options.targetSize, options.quality, options.format);
533
528
  return value;
534
529
  }
535
530
  catch (error) {
@@ -548,7 +543,7 @@ const transformMedia = (asset, variables, resolveDesignValue, variableName, path
548
543
  return;
549
544
  }
550
545
  try {
551
- value = getOptimizedBackgroundImageAsset(asset.fields.file, width, Number(options.quality), options.format);
546
+ value = getOptimizedBackgroundImageAsset(asset.fields.file, width, options.quality, options.format);
552
547
  return value;
553
548
  }
554
549
  catch (error) {
@@ -595,6 +590,7 @@ const getDataFromTree = (tree) => {
595
590
  };
596
591
  };
597
592
 
593
+ // These styles get added to every component, user custom or contentful provided
598
594
  const builtInStyles = {
599
595
  cfVerticalAlignment: {
600
596
  validations: {
@@ -705,13 +701,6 @@ const builtInStyles = {
705
701
  description: 'The border of the section',
706
702
  defaultValue: '0px solid rgba(0, 0, 0, 0)',
707
703
  },
708
- cfBorderRadius: {
709
- displayName: 'Border Radius',
710
- type: 'Text',
711
- group: 'style',
712
- description: 'The border radius of the section',
713
- defaultValue: '0px',
714
- },
715
704
  cfGap: {
716
705
  displayName: 'Gap',
717
706
  type: 'Text',
@@ -778,9 +767,6 @@ const optionalBuiltInStyles = {
778
767
  defaultValue: {
779
768
  width: DEFAULT_IMAGE_WIDTH,
780
769
  height: '100%',
781
- objectFit: 'none',
782
- objectPosition: 'center center',
783
- quality: '100',
784
770
  targetSize: DEFAULT_IMAGE_WIDTH,
785
771
  },
786
772
  },
@@ -796,10 +782,16 @@ const optionalBuiltInStyles = {
796
782
  defaultValue: {
797
783
  scaling: 'fill',
798
784
  alignment: 'left top',
799
- quality: '100',
800
785
  targetSize: '2000px',
801
786
  },
802
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
+ },
803
795
  cfLineHeight: {
804
796
  displayName: 'Line Height',
805
797
  type: 'Text',
@@ -1710,23 +1702,23 @@ const CONTENTFUL_COMPONENTS = {
1710
1702
  name: 'Column',
1711
1703
  },
1712
1704
  button: {
1713
- id: 'button',
1705
+ id: 'contentful-button',
1714
1706
  name: 'Button',
1715
1707
  },
1716
1708
  heading: {
1717
- id: 'heading',
1709
+ id: 'contentful-heading',
1718
1710
  name: 'Heading',
1719
1711
  },
1720
1712
  image: {
1721
- id: 'image',
1713
+ id: 'contentful-image',
1722
1714
  name: 'Image',
1723
1715
  },
1724
1716
  richText: {
1725
- id: 'richText',
1717
+ id: 'contentful-richText',
1726
1718
  name: 'Rich Text',
1727
1719
  },
1728
1720
  text: {
1729
- id: 'text',
1721
+ id: 'contentful-text',
1730
1722
  name: 'Text',
1731
1723
  },
1732
1724
  };
@@ -2491,7 +2483,7 @@ styleInject(css_248z$4);
2491
2483
  var css_248z$3 = ".cf-text {\n white-space: pre-line;\n}\n";
2492
2484
  styleInject(css_248z$3);
2493
2485
 
2494
- var css_248z$2$1 = ".cf-no-image {\n position: relative;\n}\n\n.cf-no-image img {\n background-color: var(--cf-color-gray100);\n outline-offset: -2px;\n outline: 2px solid rgba(var(--cf-color-gray400-rgb), 0.5);\n}\n\n[data-ctfl-draggable-id] .cf-no-image {\n width: 100%;\n height: 100%;\n}\n\n[data-ctfl-draggable-id] .cf-no-image img {\n width: 100%;\n}\n\n.cf-no-image svg {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n height: var(--cf-text-3xl);\n width: var(--cf-text-3xl);\n max-height: 100%;\n max-width: 100%;\n}\n\n.cf-no-image svg path {\n fill: var(--cf-color-gray400);\n}\n";
2486
+ var css_248z$2$1 = "@import url(https://fonts.googleapis.com/css2?family=Archivo:ital,wght@0,400;0,500;0,600;1,400;1,600&display=swap);\n\n:root {\n /* All sizing comments based of 16px base body font size */\n\n /* color */\n --cf-color-white: #fff;\n --cf-color-black: #000;\n --cf-color-gray100: #f7f9fa;\n --cf-color-gray400: #aec1cc;\n --cf-color-gray400-rgb: 174, 193, 204;\n\n /* spacing */\n --cf-spacing-0: 0rem; /* 0px */\n --cf-spacing-1: 0.125rem; /* 2px */\n --cf-spacing-2: 0.25rem; /* 4px */\n --cf-spacing-3: 0.375rem; /* 6px */\n --cf-spacing-4: 0.5rem; /* 8px */\n --cf-spacing-5: 0.625rem; /* 10px */\n --cf-spacing-6: 0.75rem; /* 12px */\n --cf-spacing-7: 0.875rem; /* 14px */\n --cf-spacing-8: 1rem; /* 16px */\n --cf-spacing-9: 1.25rem; /* 20px */\n --cf-spacing-10: 1.5rem; /* 24px */\n --cf-spacing-11: 1.75rem; /* 28px */\n --cf-spacing-12: 2rem; /* 32px */\n --cf-spacing-13: 2.25rem; /* 36px */\n\n /* font-size */\n --cf-text-xs: 0.75rem; /* 12px */\n --cf-text-sm: 0.875rem; /* 14px */\n --cf-text-base: 1rem; /* 16px */\n --cf-text-lg: 1.125rem; /* 18px */\n --cf-text-xl: 1.25rem; /* 20px */\n --cf-text-2xl: 1.5rem; /* 24px */\n --cf-text-3xl: 2rem; /* 32px */\n --cf-text-4xl: 2.75rem; /* 44px */\n\n /* font-weight */\n --cf-font-light: 300;\n --cf-font-normal: 400;\n --cf-font-medium: 500;\n --cf-font-semibold: 600;\n --cf-font-bold: 700;\n --cf-font-extra-bold: 800;\n --cf-font-black: 900;\n\n /* border-radius */\n --cf-border-radius-none: 0px; /* none */\n --cf-border-radius-sm: 0.125rem; /* 2px */\n --cf-border-radius: 0.25rem; /* 4px */\n --cf-border-radius-md: 0.375rem; /* 6px */\n --cf-border-radius-lg: 0.5rem; /* 8px */\n --cf-border-radius-xl: 0.75rem; /* 12px */\n --cf-border-radius-2xl: 1rem; /* 16px */\n --cf-border-radius-3xl: 1.5rem; /* 24px */\n --cf-border-radius-full: 9999px; /* full */\n\n /* font-family */\n --cf-font-family-sans: Archivo, Helvetica, Arial, sans-serif;\n --cf-font-family-serif: Georgia, Cambria, Times New Roman, Times, serif;\n\n /* max widths */\n --cf-max-width-full: 100%;\n\n /* component specific colors */\n --cf-button-bg: var(--cf-color-black);\n --cf-button-color: var(--cf-color-white);\n --cf-text-color: var(--cf-color-black);\n}\n\n.cf-no-image {\n position: relative;\n}\n\n.cf-no-image img {\n background-color: var(--cf-color-gray100);\n outline-offset: -2px;\n outline: 2px solid rgba(var(--cf-color-gray400-rgb), 0.5);\n}\n\n[data-ctfl-draggable-id] .cf-no-image {\n width: 100%;\n height: 100%;\n}\n\n[data-ctfl-draggable-id] .cf-no-image img {\n width: 100%;\n}\n\n.cf-no-image svg {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n height: var(--cf-text-3xl);\n width: var(--cf-text-3xl);\n max-height: 100%;\n max-width: 100%;\n}\n\n.cf-no-image svg path {\n fill: var(--cf-color-gray400);\n}\n";
2495
2487
  styleInject(css_248z$2$1);
2496
2488
 
2497
2489
  var css_248z$1$1 = ".contentful-container {\n position: relative;\n display: flex;\n box-sizing: border-box;\n pointer-events: all;\n}\n\n.contentful-container::-webkit-scrollbar {\n display: none; /* Safari and Chrome */\n}\n\n.cf-single-column-wrapper {\n position: relative;\n}\n\n.cf-container-wrapper {\n position: relative;\n width: 100%;\n}\n\n.cf-container-label {\n position: absolute;\n pointer-events: none;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n justify-content: center;\n align-items: center;\n overflow-x: clip;\n font-family: var(--exp-builder-font-stack-primary);\n font-size: 12px;\n color: var(--exp-builder-gray400);\n z-index: 10;\n}\n\n/* used by ContentfulSectionAsHyperlink.tsx */\n\n.contentful-container-link,\n.contentful-container-link:active,\n.contentful-container-link:visited,\n.contentful-container-link:hover,\n.contentful-container-link:read-write,\n.contentful-container-link:focus-visible {\n color: inherit;\n text-decoration: unset;\n outline: unset;\n}\n";
@@ -2672,15 +2664,15 @@ const useComponent = ({ node: rawNode, resolveDesignValue, renderDropzone, userI
2672
2664
  return rawNode;
2673
2665
  }, [areEntitiesFetched, rawNode, entityStore]);
2674
2666
  const componentRegistration = useMemo(() => {
2675
- const registration = componentRegistry.get(node.data.blockId);
2667
+ let registration = componentRegistry.get(node.data.blockId);
2676
2668
  if (node.type === ASSEMBLY_NODE_TYPE && !registration) {
2677
- return createAssemblyRegistration({
2669
+ registration = createAssemblyRegistration({
2678
2670
  definitionId: node.data.blockId,
2679
2671
  component: Assembly,
2680
2672
  });
2681
2673
  }
2682
- else if (!registration) {
2683
- 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.`);
2684
2676
  }
2685
2677
  return registration;
2686
2678
  }, [node]);