@blaze-cms/react-page-builder 0.147.0-rc-eagle.4 → 0.147.0-rc-eagle.6

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.
Files changed (41) hide show
  1. package/lib/components/ContentGroup/ContentGroup.js +40 -8
  2. package/lib/components/ContentGroup/ContentGroup.js.map +1 -1
  3. package/lib/components/ContentGroup/ContentGroupDataFetcher.js +96 -0
  4. package/lib/components/ContentGroup/ContentGroupDataFetcher.js.map +1 -0
  5. package/lib/components/ContentGroup/helpers/build-data-sections.js +46 -0
  6. package/lib/components/ContentGroup/helpers/build-data-sections.js.map +1 -0
  7. package/lib/components/ContentGroup/helpers/index.js +7 -0
  8. package/lib/components/ContentGroup/helpers/index.js.map +1 -1
  9. package/lib/components/ContentGroupSection/ContentGroupSection.js +3 -2
  10. package/lib/components/ContentGroupSection/ContentGroupSection.js.map +1 -1
  11. package/lib/components/Iframe/Iframe.js +16 -6
  12. package/lib/components/Iframe/Iframe.js.map +1 -1
  13. package/lib/components/Layout/Layout.js +14 -3
  14. package/lib/components/Layout/Layout.js.map +1 -1
  15. package/lib/helpers/get-component-id.js +9 -3
  16. package/lib/helpers/get-component-id.js.map +1 -1
  17. package/lib-es/components/ContentGroup/ContentGroup.js +41 -9
  18. package/lib-es/components/ContentGroup/ContentGroup.js.map +1 -1
  19. package/lib-es/components/ContentGroup/ContentGroupDataFetcher.js +88 -0
  20. package/lib-es/components/ContentGroup/ContentGroupDataFetcher.js.map +1 -0
  21. package/lib-es/components/ContentGroup/helpers/build-data-sections.js +38 -0
  22. package/lib-es/components/ContentGroup/helpers/build-data-sections.js.map +1 -0
  23. package/lib-es/components/ContentGroup/helpers/index.js +2 -1
  24. package/lib-es/components/ContentGroup/helpers/index.js.map +1 -1
  25. package/lib-es/components/ContentGroupSection/ContentGroupSection.js +3 -2
  26. package/lib-es/components/ContentGroupSection/ContentGroupSection.js.map +1 -1
  27. package/lib-es/components/Iframe/Iframe.js +16 -6
  28. package/lib-es/components/Iframe/Iframe.js.map +1 -1
  29. package/lib-es/components/Layout/Layout.js +14 -3
  30. package/lib-es/components/Layout/Layout.js.map +1 -1
  31. package/lib-es/helpers/get-component-id.js +9 -3
  32. package/lib-es/helpers/get-component-id.js.map +1 -1
  33. package/package.json +6 -6
  34. package/src/components/ContentGroup/ContentGroup.js +54 -8
  35. package/src/components/ContentGroup/ContentGroupDataFetcher.js +74 -0
  36. package/src/components/ContentGroup/helpers/build-data-sections.js +35 -0
  37. package/src/components/ContentGroup/helpers/index.js +2 -1
  38. package/src/components/ContentGroupSection/ContentGroupSection.js +2 -2
  39. package/src/components/Iframe/Iframe.js +22 -6
  40. package/src/components/Layout/Layout.js +13 -2
  41. package/src/helpers/get-component-id.js +7 -4
@@ -3,14 +3,27 @@ import PropTypes from 'prop-types';
3
3
  import { CONTENT_GROUP_TYPES } from './constants';
4
4
  import ContentGroupTabs from './ContentGroupTabs';
5
5
  import ContentGroupAccordion from './ContentGroupAccordion';
6
- import { getSectionsData } from './helpers';
6
+ import ContentGroupDataFetcher from './ContentGroupDataFetcher';
7
+ import { getSectionsData, buildDataSections } from './helpers';
7
8
  import getStructuredDataProperties from './helpers/get-structured-data-properties';
8
9
  import { getCustomHtmlProperties } from '../../helpers';
9
10
 
10
11
  const VALID_TYPES = Object.values(CONTENT_GROUP_TYPES);
11
12
 
12
- const ContentGroup = ({ contentType, isFaqContent, children, customHtmlProps, ...props }) => {
13
- const groupSections = children?.props?.children?.[1];
13
+ const ContentGroup = ({
14
+ contentType,
15
+ isFaqContent,
16
+ children,
17
+ customHtmlProps,
18
+ simpleData,
19
+ dataProperty,
20
+ ...props
21
+ }) => {
22
+ const hasSimpleData = Array.isArray(simpleData) && simpleData.length > 0;
23
+ const dataPropertyName = Array.isArray(dataProperty) ? dataProperty[0] : dataProperty;
24
+ const hasDataProperty = !!dataPropertyName;
25
+
26
+ const childGroupSections = children?.props?.children?.[1];
14
27
 
15
28
  const GroupComponent = useMemo(
16
29
  () =>
@@ -30,9 +43,32 @@ const ContentGroup = ({ contentType, isFaqContent, children, customHtmlProps, ..
30
43
  };
31
44
  }, [isFaqContent, customHtmlProps]);
32
45
 
33
- if (!groupSections || !groupSections.length || !VALID_TYPES.includes(contentType)) return '';
46
+ if (!VALID_TYPES.includes(contentType)) return '';
47
+
48
+ if (!hasSimpleData && hasDataProperty) {
49
+ return (
50
+ <WrapperComponent {...topWrapperProps}>
51
+ <ContentGroupDataFetcher
52
+ dataProperty={dataPropertyName}
53
+ contentType={contentType}
54
+ {...props}
55
+ {...schemaProperties}
56
+ />
57
+ </WrapperComponent>
58
+ );
59
+ }
60
+
61
+ let groupSections;
62
+ let sectionsData;
34
63
 
35
- const sectionsData = getSectionsData(groupSections);
64
+ if (hasSimpleData) {
65
+ ({ groupSections, sectionsData } = buildDataSections(simpleData));
66
+ } else {
67
+ groupSections = childGroupSections;
68
+ if (!groupSections || !groupSections.length) return '';
69
+ sectionsData = getSectionsData(groupSections);
70
+ }
71
+ if (!groupSections || !groupSections.length) return '';
36
72
 
37
73
  return (
38
74
  <WrapperComponent {...topWrapperProps}>
@@ -48,7 +84,7 @@ const ContentGroup = ({ contentType, isFaqContent, children, customHtmlProps, ..
48
84
  };
49
85
 
50
86
  ContentGroup.propTypes = {
51
- children: PropTypes.object.isRequired,
87
+ children: PropTypes.object,
52
88
  contentType: PropTypes.oneOf(VALID_TYPES).isRequired,
53
89
  isFaqContent: PropTypes.bool,
54
90
  customHtmlProps: PropTypes.arrayOf(
@@ -56,12 +92,22 @@ ContentGroup.propTypes = {
56
92
  name: PropTypes.string,
57
93
  value: PropTypes.string
58
94
  })
59
- )
95
+ ),
96
+ simpleData: PropTypes.arrayOf(
97
+ PropTypes.shape({
98
+ label: PropTypes.string,
99
+ text: PropTypes.string
100
+ })
101
+ ),
102
+ dataProperty: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)])
60
103
  };
61
104
 
62
105
  ContentGroup.defaultProps = {
106
+ children: null,
63
107
  isFaqContent: false,
64
- customHtmlProps: []
108
+ customHtmlProps: [],
109
+ simpleData: null,
110
+ dataProperty: null
65
111
  };
66
112
 
67
113
  export default ContentGroup;
@@ -0,0 +1,74 @@
1
+ import React, { useContext, useMemo } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { useQuery, gql } from '@apollo/client';
4
+ import { MainContext } from '@blaze-cms/nextjs-components';
5
+ import { getSingleEntitySchema, generateSingleItemQuery } from '../../application/query';
6
+ import ContentGroupTabs from './ContentGroupTabs';
7
+ import ContentGroupAccordion from './ContentGroupAccordion';
8
+ import { buildDataSections } from './helpers';
9
+ import { CONTENT_GROUP_TYPES } from './constants';
10
+
11
+ const PLACEHOLDER_QUERY = gql`
12
+ query {
13
+ __typename
14
+ }
15
+ `;
16
+
17
+ const ContentGroupDataFetcher = ({ dataProperty, parent, contentType, ...props }) => {
18
+ const { isPreview } = useContext(MainContext);
19
+ const dataPropertyName = Array.isArray(dataProperty) ? dataProperty[0] : dataProperty;
20
+
21
+ const { data: schemaData, loading: schemaLoading } = useQuery(getSingleEntitySchema, {
22
+ variables: { id: parent?.itemEntity },
23
+ skip: !parent?.itemEntity || !dataPropertyName
24
+ });
25
+
26
+ const dataQuery = useMemo(() => {
27
+ if (!schemaData) return null;
28
+ const { getEntitySchema } = schemaData;
29
+ const { actions: { getPublished, get } = {} } = getEntitySchema;
30
+ const actionKey = isPreview ? get : getPublished || get;
31
+ if (!actionKey) return null;
32
+ return generateSingleItemQuery(actionKey, `${dataPropertyName} { label text }`);
33
+ }, [schemaData, isPreview, dataPropertyName]);
34
+
35
+ const { data: recordData, loading: recordLoading } = useQuery(dataQuery || PLACEHOLDER_QUERY, {
36
+ variables: { id: parent?.itemId },
37
+ skip: !dataQuery || !parent?.itemId
38
+ });
39
+
40
+ if (schemaLoading || recordLoading) return '';
41
+ if (!recordData?.entityData) return null;
42
+
43
+ const propertyData = recordData.entityData[dataPropertyName];
44
+ if (!propertyData || !propertyData.length) return null;
45
+
46
+ const { groupSections, sectionsData } = buildDataSections(propertyData);
47
+
48
+ if (!groupSections.length) return null;
49
+
50
+ const GroupComponent =
51
+ contentType === CONTENT_GROUP_TYPES.ACCORDION ? ContentGroupAccordion : ContentGroupTabs;
52
+
53
+ return (
54
+ <GroupComponent
55
+ contentType={contentType}
56
+ groupSections={groupSections}
57
+ sectionsData={sectionsData}
58
+ {...props}
59
+ />
60
+ );
61
+ };
62
+
63
+ ContentGroupDataFetcher.propTypes = {
64
+ dataProperty: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
65
+ parent: PropTypes.object,
66
+ contentType: PropTypes.string.isRequired
67
+ };
68
+
69
+ ContentGroupDataFetcher.defaultProps = {
70
+ dataProperty: null,
71
+ parent: null
72
+ };
73
+
74
+ export default ContentGroupDataFetcher;
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+ import dynamic from 'next/dynamic';
3
+ import getComponentId from '../../../helpers/get-component-id';
4
+
5
+ const TextBlock = dynamic(() => import('../../TextBlock'));
6
+ const ContentGroupSection = dynamic(() => import('../../ContentGroupSection'));
7
+
8
+ const buildDataSections = (items = []) => {
9
+ const itemData = items.map((item, i) => {
10
+ if (!item || !item.text || !item.label) return null;
11
+
12
+ const sectionName = getComponentId(item.label || `section-${i}`, true, true);
13
+ return {
14
+ sectionName,
15
+ label: item.label,
16
+ sectionContent: (
17
+ <ContentGroupSection key={sectionName} name={sectionName} disableChildCheck>
18
+ <TextBlock html={item.text} name={`${sectionName}-text`} />
19
+ </ContentGroupSection>
20
+ )
21
+ };
22
+ });
23
+
24
+ return itemData.filter(Boolean).reduce(
25
+ (acc, { sectionName, label, sectionContent }) => {
26
+ if (!sectionName || !sectionContent) return acc;
27
+ acc.groupSections.push(sectionContent);
28
+ acc.sectionsData.push([sectionName, label]);
29
+ return acc;
30
+ },
31
+ { groupSections: [], sectionsData: [] }
32
+ );
33
+ };
34
+
35
+ export default buildDataSections;
@@ -1,4 +1,5 @@
1
1
  import getSectionsData from './get-sections-data';
2
2
  import getActiveTab from './get-active-tab';
3
+ import buildDataSections from './build-data-sections';
3
4
 
4
- export { getSectionsData, getActiveTab };
5
+ export { getSectionsData, getActiveTab, buildDataSections };
@@ -2,8 +2,8 @@ import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import { hasChildren } from '../../helpers';
4
4
 
5
- const ContentGroupSection = ({ children, name }) => {
6
- if (!hasChildren(children)) return null;
5
+ const ContentGroupSection = ({ children, name, disableChildCheck }) => {
6
+ if (!disableChildCheck && !hasChildren(children)) return null;
7
7
 
8
8
  return (
9
9
  <div key={name} className="content-group-section">
@@ -1,10 +1,18 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import IframeResizer from 'iframe-resizer-react';
4
+ import { useStringTemplate } from '@blaze-cms/utils-handlebars';
4
5
  import { IFRAME_CLASS, DEFAULT_WIDTH } from './constants';
5
6
 
6
- const Iframe = ({ src, modifier, width, height, enableScrolling }) => {
7
- if (!src) return null;
7
+ const UNSAFE_URL_PATTERN = /^(javascript|data):/i;
8
+
9
+ const isSafeUrl = url => !UNSAFE_URL_PATTERN.test(url.trim());
10
+
11
+ const Iframe = ({ src, modifier, width, height, enableScrolling, parent }) => {
12
+ const {
13
+ data: [resolvedSrc]
14
+ } = useStringTemplate(parent, [src || '']);
15
+ if (!resolvedSrc || !isSafeUrl(resolvedSrc)) return null;
8
16
  const modifierString = modifier ? ` ${modifier}` : '';
9
17
  const iframeClassName = `${IFRAME_CLASS}${modifierString}`;
10
18
  const defaultWidth = !width ? DEFAULT_WIDTH : {};
@@ -13,7 +21,7 @@ const Iframe = ({ src, modifier, width, height, enableScrolling }) => {
13
21
  <IframeResizer
14
22
  scrolling={enableScrolling}
15
23
  autoResize
16
- src={src}
24
+ src={resolvedSrc}
17
25
  sizeHeight={!height}
18
26
  height={height}
19
27
  width={width}
@@ -24,13 +32,21 @@ const Iframe = ({ src, modifier, width, height, enableScrolling }) => {
24
32
  };
25
33
 
26
34
  Iframe.propTypes = {
27
- src: PropTypes.string.isRequired,
35
+ src: PropTypes.string,
28
36
  enableScrolling: PropTypes.bool,
29
37
  modifier: PropTypes.string,
30
38
  width: PropTypes.string,
31
- height: PropTypes.string
39
+ height: PropTypes.string,
40
+ parent: PropTypes.object
32
41
  };
33
42
 
34
- Iframe.defaultProps = { enableScrolling: false, modifier: '', width: '', height: '' };
43
+ Iframe.defaultProps = {
44
+ src: '',
45
+ enableScrolling: false,
46
+ modifier: '',
47
+ width: '',
48
+ height: '',
49
+ parent: {}
50
+ };
35
51
 
36
52
  export default Iframe;
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
+ import { useStringTemplate } from '@blaze-cms/utils-handlebars';
3
4
  import Wrapper from '../Wrapper';
4
5
  import { getClassModifiers } from '../../utils';
5
6
  import { useGetImages } from '../../hooks';
@@ -15,6 +16,8 @@ const Layout = React.forwardRef(
15
16
  settings,
16
17
  modifier,
17
18
  backgroundImage,
19
+ backgroundImageUrl,
20
+ parent,
18
21
  tagType,
19
22
  dataNoSnippet,
20
23
  sticky,
@@ -24,10 +27,14 @@ const Layout = React.forwardRef(
24
27
  },
25
28
  ref
26
29
  ) => {
30
+ const {
31
+ data: [resolvedBackgroundImageUrl]
32
+ } = useStringTemplate(parent, [backgroundImageUrl || '']);
27
33
  const {
28
34
  data: { getFile: { url = null } = {} }
29
- } = useGetImages(backgroundImage);
30
- const style = getStylesToUpdate({ backgroundImage: url });
35
+ } = useGetImages(backgroundImage, false, !!resolvedBackgroundImageUrl);
36
+ const backgroundUrl = resolvedBackgroundImageUrl || url;
37
+ const style = getStylesToUpdate({ backgroundImage: backgroundUrl });
31
38
  const { title } = settings;
32
39
  const classModifiers = getClassModifiers(type, { modifier, sticky, ...otherProps });
33
40
  const additionalRowModifier = checkIfRowHasColumns(type, children) ? ' display-row' : '';
@@ -65,6 +72,8 @@ Layout.propTypes = {
65
72
  }),
66
73
  modifier: PropTypes.string,
67
74
  backgroundImage: PropTypes.string,
75
+ backgroundImageUrl: PropTypes.string,
76
+ parent: PropTypes.object,
68
77
  tagType: PropTypes.string,
69
78
  dataNoSnippet: PropTypes.bool,
70
79
  VariantComponent: PropTypes.func,
@@ -82,6 +91,8 @@ Layout.defaultProps = {
82
91
  title: ''
83
92
  },
84
93
  backgroundImage: '',
94
+ backgroundImageUrl: '',
95
+ parent: {},
85
96
  modifier: '',
86
97
  tagType: '',
87
98
  dataNoSnippet: false,
@@ -1,9 +1,12 @@
1
1
  import cssesc from 'cssesc';
2
2
  import { COMPONENT_ID_PREFIX } from '../constants';
3
3
 
4
- const getComponentId = componentName =>
5
- cssesc(`${COMPONENT_ID_PREFIX}${componentName.replace(/\s+/g, '-')}`, {
6
- isIdentifier: true
7
- });
4
+ const getComponentId = (componentName, noPrefix = false, toLowerCase = false) => {
5
+ let id = `${noPrefix ? '' : COMPONENT_ID_PREFIX}${componentName.replace(/\s+/g, '-')}`;
6
+ if (toLowerCase) {
7
+ id = id.toLowerCase();
8
+ }
9
+ return cssesc(id, { isIdentifier: true });
10
+ };
8
11
 
9
12
  export default getComponentId;