@blaze-cms/react-page-builder 0.147.0-rc-eagle.2 → 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.
- package/lib/components/ContentGroup/ContentGroup.js +40 -8
- package/lib/components/ContentGroup/ContentGroup.js.map +1 -1
- package/lib/components/ContentGroup/ContentGroupDataFetcher.js +96 -0
- package/lib/components/ContentGroup/ContentGroupDataFetcher.js.map +1 -0
- package/lib/components/ContentGroup/helpers/build-data-sections.js +46 -0
- package/lib/components/ContentGroup/helpers/build-data-sections.js.map +1 -0
- package/lib/components/ContentGroup/helpers/index.js +7 -0
- package/lib/components/ContentGroup/helpers/index.js.map +1 -1
- package/lib/components/ContentGroupSection/ContentGroupSection.js +3 -2
- package/lib/components/ContentGroupSection/ContentGroupSection.js.map +1 -1
- package/lib/components/Iframe/Iframe.js +16 -6
- package/lib/components/Iframe/Iframe.js.map +1 -1
- package/lib/components/Layout/Layout.js +14 -3
- package/lib/components/Layout/Layout.js.map +1 -1
- package/lib/components/Menu/Menu.js +4 -1
- package/lib/components/Menu/Menu.js.map +1 -1
- package/lib/components/Menu/MenuContext.js +2 -1
- package/lib/components/Menu/MenuContext.js.map +1 -1
- package/lib/components/MenuItem/MenuItemRender.js +24 -9
- package/lib/components/MenuItem/MenuItemRender.js.map +1 -1
- package/lib/components/MenuItem/helpers/has-active-child.js +12 -0
- package/lib/components/MenuItem/helpers/has-active-child.js.map +1 -0
- package/lib/components/MenuItem/helpers/index.js +14 -0
- package/lib/components/MenuItem/helpers/index.js.map +1 -1
- package/lib/components/MenuItem/helpers/isUrlPathMatch.js +14 -0
- package/lib/components/MenuItem/helpers/isUrlPathMatch.js.map +1 -0
- package/lib/helpers/get-component-id.js +9 -3
- package/lib/helpers/get-component-id.js.map +1 -1
- package/lib-es/components/ContentGroup/ContentGroup.js +41 -9
- package/lib-es/components/ContentGroup/ContentGroup.js.map +1 -1
- package/lib-es/components/ContentGroup/ContentGroupDataFetcher.js +88 -0
- package/lib-es/components/ContentGroup/ContentGroupDataFetcher.js.map +1 -0
- package/lib-es/components/ContentGroup/helpers/build-data-sections.js +38 -0
- package/lib-es/components/ContentGroup/helpers/build-data-sections.js.map +1 -0
- package/lib-es/components/ContentGroup/helpers/index.js +2 -1
- package/lib-es/components/ContentGroup/helpers/index.js.map +1 -1
- package/lib-es/components/ContentGroupSection/ContentGroupSection.js +3 -2
- package/lib-es/components/ContentGroupSection/ContentGroupSection.js.map +1 -1
- package/lib-es/components/Iframe/Iframe.js +16 -6
- package/lib-es/components/Iframe/Iframe.js.map +1 -1
- package/lib-es/components/Layout/Layout.js +14 -3
- package/lib-es/components/Layout/Layout.js.map +1 -1
- package/lib-es/components/Menu/Menu.js +4 -1
- package/lib-es/components/Menu/Menu.js.map +1 -1
- package/lib-es/components/Menu/MenuContext.js +2 -1
- package/lib-es/components/Menu/MenuContext.js.map +1 -1
- package/lib-es/components/MenuItem/MenuItemRender.js +25 -11
- package/lib-es/components/MenuItem/MenuItemRender.js.map +1 -1
- package/lib-es/components/MenuItem/helpers/has-active-child.js +5 -0
- package/lib-es/components/MenuItem/helpers/has-active-child.js.map +1 -0
- package/lib-es/components/MenuItem/helpers/index.js +3 -1
- package/lib-es/components/MenuItem/helpers/index.js.map +1 -1
- package/lib-es/components/MenuItem/helpers/isUrlPathMatch.js +8 -0
- package/lib-es/components/MenuItem/helpers/isUrlPathMatch.js.map +1 -0
- package/lib-es/helpers/get-component-id.js +9 -3
- package/lib-es/helpers/get-component-id.js.map +1 -1
- package/package.json +10 -11
- package/src/components/ContentGroup/ContentGroup.js +54 -8
- package/src/components/ContentGroup/ContentGroupDataFetcher.js +74 -0
- package/src/components/ContentGroup/helpers/build-data-sections.js +35 -0
- package/src/components/ContentGroup/helpers/index.js +2 -1
- package/src/components/ContentGroupSection/ContentGroupSection.js +2 -2
- package/src/components/Iframe/Iframe.js +22 -6
- package/src/components/Layout/Layout.js +13 -2
- package/src/components/Menu/Menu.js +3 -1
- package/src/components/Menu/MenuContext.js +1 -1
- package/src/components/MenuItem/MenuItemRender.js +40 -12
- package/src/components/MenuItem/helpers/has-active-child.js +10 -0
- package/src/components/MenuItem/helpers/index.js +3 -1
- package/src/components/MenuItem/helpers/isUrlPathMatch.js +10 -0
- 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
|
|
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 = ({
|
|
13
|
-
|
|
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 (!
|
|
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
|
-
|
|
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
|
|
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;
|
|
@@ -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
|
|
7
|
-
|
|
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={
|
|
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
|
|
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 = {
|
|
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
|
|
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,
|
|
@@ -11,6 +11,7 @@ import BlazeLink from '../BlazeLink';
|
|
|
11
11
|
const Menu = ({
|
|
12
12
|
children,
|
|
13
13
|
collapse,
|
|
14
|
+
openActiveSubmenus,
|
|
14
15
|
modifier,
|
|
15
16
|
mobileMenuModifier,
|
|
16
17
|
mobileMenuChildrenModifier,
|
|
@@ -51,7 +52,7 @@ const Menu = ({
|
|
|
51
52
|
});
|
|
52
53
|
|
|
53
54
|
return (
|
|
54
|
-
<MenuContext.Provider value={{ showMobileMenu }}>
|
|
55
|
+
<MenuContext.Provider value={{ showMobileMenu, openActiveSubmenus }}>
|
|
55
56
|
<div className={menuWrapperClasses}>
|
|
56
57
|
{collapse && (
|
|
57
58
|
<div className="menu--mobile-wrapper">
|
|
@@ -99,6 +100,7 @@ const Menu = ({
|
|
|
99
100
|
|
|
100
101
|
Menu.propTypes = {
|
|
101
102
|
collapse: PropTypes.bool.isRequired,
|
|
103
|
+
openActiveSubmenus: PropTypes.bool.isRequired,
|
|
102
104
|
logoOnMobile: PropTypes.bool.isRequired,
|
|
103
105
|
logoOnDesktop: PropTypes.bool,
|
|
104
106
|
logoOnMobileUrl: PropTypes.string,
|
|
@@ -1,17 +1,23 @@
|
|
|
1
|
+
/* eslint-disable jsx-a11y/no-static-element-interactions */
|
|
1
2
|
import React, { useState, useContext, useEffect } from 'react';
|
|
2
3
|
import PropTypes from 'prop-types';
|
|
3
4
|
import { FaChevronDown, FaChevronUp } from 'react-icons/fa';
|
|
5
|
+
import classnames from 'classnames';
|
|
4
6
|
import { useRouter } from 'next/router';
|
|
5
7
|
import { useStringTemplate } from '@blaze-cms/utils-handlebars';
|
|
6
|
-
import { HOVER, MOUSE_ENTER, MOUSE_LEAVE, HIDDEN } from '../../constants';
|
|
8
|
+
import { HOVER, MOUSE_ENTER, MOUSE_LEAVE, HIDDEN, CLICK } from '../../constants';
|
|
7
9
|
import { hasChildren } from '../../helpers';
|
|
8
10
|
import BlazeLink from '../BlazeLink';
|
|
9
11
|
import MenuContext from '../Menu/MenuContext';
|
|
10
|
-
import { injectHelperIntoTemplate } from './helpers';
|
|
12
|
+
import { injectHelperIntoTemplate, isUrlPathMatch, hasActiveChild } from './helpers';
|
|
11
13
|
|
|
12
14
|
const MenuItemRender = ({ children, eventType, text, modifier, url, parent }) => {
|
|
13
|
-
const
|
|
14
|
-
const { showMobileMenu } = useContext(MenuContext);
|
|
15
|
+
const router = useRouter();
|
|
16
|
+
const { showMobileMenu, openActiveSubmenus } = useContext(MenuContext);
|
|
17
|
+
|
|
18
|
+
const isHoverEvent = eventType === HOVER;
|
|
19
|
+
const isClickEvent = eventType === CLICK;
|
|
20
|
+
|
|
15
21
|
const {
|
|
16
22
|
loading: loadingText,
|
|
17
23
|
data: [textToUse]
|
|
@@ -21,14 +27,24 @@ const MenuItemRender = ({ children, eventType, text, modifier, url, parent }) =>
|
|
|
21
27
|
data: [urlToUse]
|
|
22
28
|
} = useStringTemplate(parent, [injectHelperIntoTemplate(url, 'url_encode')]);
|
|
23
29
|
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
const
|
|
30
|
+
const isActive = router ? isUrlPathMatch(router.asPath, urlToUse) : false;
|
|
31
|
+
const isActiveParent = router ? hasActiveChild(router.asPath, children) : false;
|
|
32
|
+
const shouldPreOpen = openActiveSubmenus && isActiveParent && isClickEvent;
|
|
27
33
|
const hasValidChildren = hasChildren(children);
|
|
28
34
|
|
|
35
|
+
const [displayChildren, setDisplayChildren] = useState(shouldPreOpen);
|
|
36
|
+
|
|
29
37
|
useEffect(() => {
|
|
30
|
-
if (!showMobileMenu) setDisplayChildren(false);
|
|
31
|
-
}, [
|
|
38
|
+
if (!showMobileMenu && !shouldPreOpen) setDisplayChildren(false);
|
|
39
|
+
}, [
|
|
40
|
+
children,
|
|
41
|
+
isClickEvent,
|
|
42
|
+
loadingUrl,
|
|
43
|
+
openActiveSubmenus,
|
|
44
|
+
router,
|
|
45
|
+
shouldPreOpen,
|
|
46
|
+
showMobileMenu
|
|
47
|
+
]);
|
|
32
48
|
|
|
33
49
|
useEffect(() => {
|
|
34
50
|
if (isHoverEvent) {
|
|
@@ -38,6 +54,8 @@ const MenuItemRender = ({ children, eventType, text, modifier, url, parent }) =>
|
|
|
38
54
|
|
|
39
55
|
if (loadingUrl || loadingText) return '';
|
|
40
56
|
|
|
57
|
+
const childrenDisplayClass = displayChildren ? '' : HIDDEN;
|
|
58
|
+
|
|
41
59
|
const handleItemEvent = ({ type }) => {
|
|
42
60
|
if (isHoverEvent) {
|
|
43
61
|
if (type === MOUSE_ENTER) {
|
|
@@ -55,15 +73,25 @@ const MenuItemRender = ({ children, eventType, text, modifier, url, parent }) =>
|
|
|
55
73
|
}
|
|
56
74
|
};
|
|
57
75
|
|
|
76
|
+
const menuItemLinkClassname = classnames('menu--item--link', {
|
|
77
|
+
'menu--item--link--active': isActive,
|
|
78
|
+
'menu--item--link--active-parent': isActiveParent
|
|
79
|
+
});
|
|
80
|
+
|
|
58
81
|
return (
|
|
59
82
|
<li className={modifier} onMouseEnter={handleItemEvent} onMouseLeave={handleItemEvent}>
|
|
60
83
|
<div
|
|
61
|
-
className=
|
|
84
|
+
className={menuItemLinkClassname}
|
|
62
85
|
onClick={handleMobileClick}
|
|
63
86
|
role={!urlToUse && hasValidChildren ? 'button' : undefined}
|
|
64
87
|
tabIndex={!urlToUse && hasValidChildren ? 0 : undefined}>
|
|
65
|
-
{urlToUse ?
|
|
66
|
-
|
|
88
|
+
{urlToUse ? (
|
|
89
|
+
<BlazeLink href={urlToUse}>{textToUse}</BlazeLink>
|
|
90
|
+
) : (
|
|
91
|
+
<span role="button" onClick={handleItemEvent}>
|
|
92
|
+
{textToUse}
|
|
93
|
+
</span>
|
|
94
|
+
)}
|
|
67
95
|
{hasValidChildren && (
|
|
68
96
|
<i
|
|
69
97
|
role="button"
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import isUrlPathMatch from './isUrlPathMatch';
|
|
2
|
+
import { hasChildren } from '../../../helpers';
|
|
3
|
+
|
|
4
|
+
const hasActiveChild = (path, children) =>
|
|
5
|
+
hasChildren(children) &&
|
|
6
|
+
children.props.children[1][0].props.component.items.find(menuItem =>
|
|
7
|
+
isUrlPathMatch(path, menuItem.settings.url)
|
|
8
|
+
);
|
|
9
|
+
|
|
10
|
+
export default hasActiveChild;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import injectHelperIntoTemplate from './inject-helper-into-template';
|
|
2
|
+
import isUrlPathMatch from './isUrlPathMatch';
|
|
3
|
+
import hasActiveChild from './has-active-child';
|
|
2
4
|
|
|
3
|
-
export { injectHelperIntoTemplate };
|
|
5
|
+
export { injectHelperIntoTemplate, isUrlPathMatch, hasActiveChild };
|
|
@@ -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
|
-
|
|
6
|
-
|
|
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;
|