@blaze-cms/react-page-builder 0.146.0-node18-core-styles-tooltips.20 → 0.146.0-node18-tooltips.19
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/CHANGELOG.md +25 -63
- package/lib/components/ContentGroup/ContentGroup.js +41 -10
- package/lib/components/ContentGroup/ContentGroup.js.map +1 -1
- package/lib/components/ContentGroup/ContentGroupAccordion.js +175 -0
- package/lib/components/ContentGroup/ContentGroupAccordion.js.map +1 -0
- package/lib/components/ContentGroup/constants.js +13 -1
- package/lib/components/ContentGroup/constants.js.map +1 -1
- package/lib/components/ContentGroup/helpers/get-structured-data-properties.js +40 -0
- package/lib/components/ContentGroup/helpers/get-structured-data-properties.js.map +1 -0
- package/lib/components/Menu/Menu.js +1 -4
- package/lib/components/Menu/Menu.js.map +1 -1
- package/lib/components/Menu/MenuContext.js +1 -2
- package/lib/components/Menu/MenuContext.js.map +1 -1
- package/lib/components/MenuItem/MenuItemRender.js +12 -27
- package/lib/components/MenuItem/MenuItemRender.js.map +1 -1
- package/lib/components/MenuItem/helpers/index.js +0 -14
- package/lib/components/MenuItem/helpers/index.js.map +1 -1
- package/lib/components/SearchContent/SearchContent.js +4 -3
- package/lib/components/SearchContent/SearchContent.js.map +1 -1
- package/lib/system-components/EditorMode/helpers/add-editor-mode-event-listeners.js +0 -1
- package/lib/system-components/EditorMode/helpers/add-editor-mode-event-listeners.js.map +1 -1
- package/lib-es/components/ContentGroup/ContentGroup.js +25 -10
- package/lib-es/components/ContentGroup/ContentGroup.js.map +1 -1
- package/lib-es/components/ContentGroup/ContentGroupAccordion.js +138 -0
- package/lib-es/components/ContentGroup/ContentGroupAccordion.js.map +1 -0
- package/lib-es/components/ContentGroup/constants.js +12 -1
- package/lib-es/components/ContentGroup/constants.js.map +1 -1
- package/lib-es/components/ContentGroup/helpers/get-structured-data-properties.js +33 -0
- package/lib-es/components/ContentGroup/helpers/get-structured-data-properties.js.map +1 -0
- package/lib-es/components/Menu/Menu.js +1 -4
- package/lib-es/components/Menu/Menu.js.map +1 -1
- package/lib-es/components/Menu/MenuContext.js +1 -2
- package/lib-es/components/Menu/MenuContext.js.map +1 -1
- package/lib-es/components/MenuItem/MenuItemRender.js +11 -25
- package/lib-es/components/MenuItem/MenuItemRender.js.map +1 -1
- package/lib-es/components/MenuItem/helpers/index.js +1 -3
- package/lib-es/components/MenuItem/helpers/index.js.map +1 -1
- package/lib-es/components/SearchContent/SearchContent.js +4 -3
- package/lib-es/components/SearchContent/SearchContent.js.map +1 -1
- package/lib-es/system-components/EditorMode/helpers/add-editor-mode-event-listeners.js +0 -1
- package/lib-es/system-components/EditorMode/helpers/add-editor-mode-event-listeners.js.map +1 -1
- package/package.json +10 -10
- package/src/components/ContentGroup/ContentGroup.js +37 -13
- package/src/components/ContentGroup/ContentGroupAccordion.js +163 -0
- package/src/components/ContentGroup/constants.js +14 -1
- package/src/components/ContentGroup/helpers/get-structured-data-properties.js +36 -0
- package/src/components/Menu/Menu.js +1 -3
- package/src/components/Menu/MenuContext.js +1 -1
- package/src/components/MenuItem/MenuItemRender.js +12 -40
- package/src/components/MenuItem/helpers/index.js +1 -3
- package/src/components/SearchContent/SearchContent.js +6 -5
- package/src/system-components/EditorMode/helpers/add-editor-mode-event-listeners.js +3 -1
- package/tests/unit/src/components/ContentGroup/ContentGroup.test.js +32 -2
- package/tests/unit/src/components/ContentGroup/ContentGroupAccordion.test.js +283 -0
- package/tests/unit/src/components/ContentGroup/__snapshots__/ContentGroup.test.js.snap +2 -2
- package/tests/unit/src/components/ContentGroup/__snapshots__/ContentGroupAccordion.test.js.snap +243 -0
- package/tests/unit/src/components/ContentGroup/helpers/get-structured-data-properties.test.js +105 -0
- package/tests/unit/src/components/MenuItem/MenuItem.test.js +0 -5
- package/tests/unit/src/components/MenuItem/MenuItemRender.test.js +3 -11
- package/lib/components/MenuItem/helpers/has-active-child.js +0 -19
- package/lib/components/MenuItem/helpers/has-active-child.js.map +0 -1
- package/lib/components/MenuItem/helpers/isUrlPathMatch.js +0 -18
- package/lib/components/MenuItem/helpers/isUrlPathMatch.js.map +0 -1
- package/lib-es/components/MenuItem/helpers/has-active-child.js +0 -5
- package/lib-es/components/MenuItem/helpers/has-active-child.js.map +0 -1
- package/lib-es/components/MenuItem/helpers/isUrlPathMatch.js +0 -8
- package/lib-es/components/MenuItem/helpers/isUrlPathMatch.js.map +0 -1
- package/src/components/MenuItem/helpers/has-active-child.js +0 -10
- package/src/components/MenuItem/helpers/isUrlPathMatch.js +0 -10
- package/tests/unit/src/components/MenuItem/helpers/constants.js +0 -73
- package/tests/unit/src/components/MenuItem/helpers/has-active-child.test.js +0 -35
- package/tests/unit/src/components/MenuItem/helpers/is-url-path-match.test.js +0 -53
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blaze-cms/react-page-builder",
|
|
3
|
-
"version": "0.146.0-node18-
|
|
3
|
+
"version": "0.146.0-node18-tooltips.19",
|
|
4
4
|
"description": "Blaze react page builder",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"module": "lib-es/index.js",
|
|
@@ -27,15 +27,15 @@
|
|
|
27
27
|
},
|
|
28
28
|
"license": "GPL-3.0",
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@blaze-cms/core-auth-ui": "0.146.0-node18-
|
|
31
|
-
"@blaze-cms/core-errors": "0.146.0-node18-
|
|
32
|
-
"@blaze-cms/core-errors-ui": "0.146.0-node18-
|
|
30
|
+
"@blaze-cms/core-auth-ui": "0.146.0-node18-tooltips.4",
|
|
31
|
+
"@blaze-cms/core-errors": "0.146.0-node18-tooltips.0",
|
|
32
|
+
"@blaze-cms/core-errors-ui": "0.146.0-node18-tooltips.0",
|
|
33
33
|
"@blaze-cms/image-cdn-react": "0.3.0-alpha.7",
|
|
34
|
-
"@blaze-cms/nextjs-components": "0.146.0-node18-
|
|
35
|
-
"@blaze-cms/plugin-search-ui": "0.146.0-node18-
|
|
36
|
-
"@blaze-cms/setup-ui": "0.146.0-node18-
|
|
37
|
-
"@blaze-cms/utils": "0.146.0-node18-
|
|
38
|
-
"@blaze-cms/utils-handlebars": "0.146.0-node18-
|
|
34
|
+
"@blaze-cms/nextjs-components": "0.146.0-node18-tooltips.0",
|
|
35
|
+
"@blaze-cms/plugin-search-ui": "0.146.0-node18-tooltips.11",
|
|
36
|
+
"@blaze-cms/setup-ui": "0.146.0-node18-tooltips.0",
|
|
37
|
+
"@blaze-cms/utils": "0.146.0-node18-tooltips.4",
|
|
38
|
+
"@blaze-cms/utils-handlebars": "0.146.0-node18-tooltips.0",
|
|
39
39
|
"@blaze-react/badge": "^0.7.0",
|
|
40
40
|
"@blaze-react/breadcrumb": "0.8.0-alpha.60",
|
|
41
41
|
"@blaze-react/button": "0.8.0-alpha.82",
|
|
@@ -92,5 +92,5 @@
|
|
|
92
92
|
"lib/*",
|
|
93
93
|
"lib-es/*"
|
|
94
94
|
],
|
|
95
|
-
"gitHead": "
|
|
95
|
+
"gitHead": "2aed24333051ddcd4c2bec869a9df5835362d4c9"
|
|
96
96
|
}
|
|
@@ -1,29 +1,53 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { Fragment, useMemo } from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
+
import { CONTENT_GROUP_TYPES } from './constants';
|
|
3
4
|
import ContentGroupTabs from './ContentGroupTabs';
|
|
5
|
+
import ContentGroupAccordion from './ContentGroupAccordion';
|
|
4
6
|
import { getSectionsData } from './helpers';
|
|
7
|
+
import getStructuredDataProperties from './helpers/get-structured-data-properties';
|
|
8
|
+
|
|
9
|
+
const VALID_TYPES = Object.values(CONTENT_GROUP_TYPES);
|
|
10
|
+
|
|
11
|
+
const ContentGroup = ({ contentType, isFaqContent, children, ...props }) => {
|
|
12
|
+
const groupSections = children?.props?.children?.[1];
|
|
13
|
+
|
|
14
|
+
const GroupComponent = useMemo(
|
|
15
|
+
() =>
|
|
16
|
+
contentType === CONTENT_GROUP_TYPES.ACCORDION ? ContentGroupAccordion : ContentGroupTabs,
|
|
17
|
+
[contentType]
|
|
18
|
+
);
|
|
19
|
+
const WrapperComponent = useMemo(() => (!isFaqContent ? Fragment : 'div'), [isFaqContent]);
|
|
20
|
+
|
|
21
|
+
const { topWrapperProps, ...schemaProperties } = useMemo(
|
|
22
|
+
() => getStructuredDataProperties(isFaqContent),
|
|
23
|
+
[isFaqContent]
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
if (!groupSections || !groupSections.length || !VALID_TYPES.includes(contentType)) return '';
|
|
5
27
|
|
|
6
|
-
const ContentGroup = ({ contentType, children, ...props }) => {
|
|
7
|
-
const groupSections = children?.props?.children[1];
|
|
8
|
-
if (!groupSections || !groupSections.length) return '';
|
|
9
|
-
if (contentType !== 'tab' && contentType !== 'sidepanel') return '';
|
|
10
28
|
const sectionsData = getSectionsData(groupSections);
|
|
11
29
|
|
|
12
30
|
return (
|
|
13
|
-
<
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
31
|
+
<WrapperComponent {...topWrapperProps}>
|
|
32
|
+
<GroupComponent
|
|
33
|
+
contentType={contentType}
|
|
34
|
+
groupSections={groupSections}
|
|
35
|
+
sectionsData={sectionsData}
|
|
36
|
+
{...props}
|
|
37
|
+
{...schemaProperties}
|
|
38
|
+
/>
|
|
39
|
+
</WrapperComponent>
|
|
19
40
|
);
|
|
20
41
|
};
|
|
21
42
|
|
|
22
43
|
ContentGroup.propTypes = {
|
|
23
44
|
children: PropTypes.object.isRequired,
|
|
24
|
-
contentType: PropTypes.
|
|
45
|
+
contentType: PropTypes.oneOf(VALID_TYPES).isRequired,
|
|
46
|
+
isFaqContent: PropTypes.bool
|
|
25
47
|
};
|
|
26
48
|
|
|
27
|
-
ContentGroup.defaultProps = {
|
|
49
|
+
ContentGroup.defaultProps = {
|
|
50
|
+
isFaqContent: false
|
|
51
|
+
};
|
|
28
52
|
|
|
29
53
|
export default ContentGroup;
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import React, { useEffect, useMemo, useState } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import classnames from 'classnames';
|
|
4
|
+
import { useRouter } from 'next/router';
|
|
5
|
+
import { VscChevronUp, VscChevronDown } from 'react-icons/vsc';
|
|
6
|
+
import { CONTENT_GROUP, OPEN_STATES } from './constants';
|
|
7
|
+
|
|
8
|
+
const ContentGroupAccordion = ({
|
|
9
|
+
name,
|
|
10
|
+
groupSections,
|
|
11
|
+
sectionsData,
|
|
12
|
+
VariantComponent,
|
|
13
|
+
openState,
|
|
14
|
+
groupSectionProps,
|
|
15
|
+
groupSectionTitleProps,
|
|
16
|
+
groupContentWrapperProps,
|
|
17
|
+
groupContentProps
|
|
18
|
+
}) => {
|
|
19
|
+
const router = useRouter();
|
|
20
|
+
const { asPath } = router;
|
|
21
|
+
|
|
22
|
+
const sectionPairs = useMemo(
|
|
23
|
+
() =>
|
|
24
|
+
sectionsData.map(([sectionName, sectionLabel]) => ({
|
|
25
|
+
sectionName,
|
|
26
|
+
sectionLabel,
|
|
27
|
+
panelId: `${sectionName}-panel`
|
|
28
|
+
})),
|
|
29
|
+
[sectionsData]
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
const sectionNames = useMemo(() => sectionPairs.map(p => p.sectionName), [sectionPairs]);
|
|
33
|
+
|
|
34
|
+
const baseInitialOpen = useMemo(
|
|
35
|
+
() => {
|
|
36
|
+
if (openState === OPEN_STATES.ALL_OPEN) return new Set(sectionNames);
|
|
37
|
+
if (openState === OPEN_STATES.ALL_CLOSED && sectionNames.length) return new Set();
|
|
38
|
+
|
|
39
|
+
return new Set([sectionNames[0]]);
|
|
40
|
+
},
|
|
41
|
+
[openState, sectionNames]
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const [openSet, setOpenSet] = useState(baseInitialOpen);
|
|
45
|
+
|
|
46
|
+
useEffect(
|
|
47
|
+
() => {
|
|
48
|
+
const rawHash = (asPath.split('#')[1] || '').trim();
|
|
49
|
+
if (rawHash && sectionNames.includes(rawHash) && !openSet.has(rawHash)) {
|
|
50
|
+
setOpenSet(prev => {
|
|
51
|
+
const next = new Set(prev);
|
|
52
|
+
next.add(rawHash);
|
|
53
|
+
return next;
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
58
|
+
[asPath, sectionNames]
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
const WrapperComponent = VariantComponent || 'div';
|
|
62
|
+
|
|
63
|
+
const baseClass = `${CONTENT_GROUP}-accordion`;
|
|
64
|
+
const itemsClass = `${baseClass}__items`;
|
|
65
|
+
const itemClass = `${baseClass}__item`;
|
|
66
|
+
const headerBtnClass = `${baseClass}__header-btn`;
|
|
67
|
+
const panelClass = `${baseClass}__panel`;
|
|
68
|
+
const headingClass = `${baseClass}__heading`;
|
|
69
|
+
const titleClass = `${baseClass}__title`;
|
|
70
|
+
const chevronClass = `${baseClass}__chevron`;
|
|
71
|
+
const chevronIconClass = `${baseClass}__chevron-icon`;
|
|
72
|
+
|
|
73
|
+
const onToggle = sectionName => {
|
|
74
|
+
setOpenSet(prev => {
|
|
75
|
+
const next = new Set(prev);
|
|
76
|
+
const willOpen = !next.has(sectionName);
|
|
77
|
+
|
|
78
|
+
if (willOpen) next.add(sectionName);
|
|
79
|
+
else next.delete(sectionName);
|
|
80
|
+
|
|
81
|
+
const baseUrl = asPath.split('#')[0];
|
|
82
|
+
const newUrl = willOpen ? `${baseUrl}#${sectionName}` : baseUrl;
|
|
83
|
+
|
|
84
|
+
router.replace(`/Resolver`, newUrl, { shallow: true, scroll: false });
|
|
85
|
+
|
|
86
|
+
return next;
|
|
87
|
+
});
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
<div className={baseClass}>
|
|
92
|
+
<div className={itemsClass} aria-label={name}>
|
|
93
|
+
{groupSections.map((groupSection, index) => {
|
|
94
|
+
const { sectionName, sectionLabel, panelId } = sectionPairs[index];
|
|
95
|
+
const isOpen = openSet.has(sectionName);
|
|
96
|
+
|
|
97
|
+
return (
|
|
98
|
+
<div
|
|
99
|
+
key={sectionName}
|
|
100
|
+
className={classnames(itemClass, { [`${itemClass}--open`]: isOpen })}
|
|
101
|
+
{...groupSectionProps}>
|
|
102
|
+
<h3 className={headingClass}>
|
|
103
|
+
<button
|
|
104
|
+
id={sectionName}
|
|
105
|
+
type="button"
|
|
106
|
+
className={classnames(headerBtnClass, { [`${headerBtnClass}--open`]: isOpen })}
|
|
107
|
+
aria-expanded={isOpen}
|
|
108
|
+
aria-controls={panelId}
|
|
109
|
+
onClick={() => onToggle(sectionName)}>
|
|
110
|
+
<span className={titleClass} {...groupSectionTitleProps}>
|
|
111
|
+
{sectionLabel}
|
|
112
|
+
</span>
|
|
113
|
+
|
|
114
|
+
<span aria-hidden="true" className={chevronClass}>
|
|
115
|
+
{isOpen ? (
|
|
116
|
+
<VscChevronUp className={chevronIconClass} />
|
|
117
|
+
) : (
|
|
118
|
+
<VscChevronDown className={chevronIconClass} />
|
|
119
|
+
)}
|
|
120
|
+
</span>
|
|
121
|
+
</button>
|
|
122
|
+
</h3>
|
|
123
|
+
|
|
124
|
+
<WrapperComponent
|
|
125
|
+
id={panelId}
|
|
126
|
+
role="region"
|
|
127
|
+
aria-labelledby={sectionName}
|
|
128
|
+
className={panelClass}
|
|
129
|
+
hidden={!isOpen}
|
|
130
|
+
data-section={sectionName}
|
|
131
|
+
{...groupContentWrapperProps}>
|
|
132
|
+
<div {...groupContentProps}>{groupSection}</div>
|
|
133
|
+
</WrapperComponent>
|
|
134
|
+
</div>
|
|
135
|
+
);
|
|
136
|
+
})}
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
);
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
ContentGroupAccordion.propTypes = {
|
|
143
|
+
name: PropTypes.string.isRequired,
|
|
144
|
+
groupSections: PropTypes.array.isRequired,
|
|
145
|
+
sectionsData: PropTypes.array.isRequired,
|
|
146
|
+
VariantComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.elementType]),
|
|
147
|
+
openState: PropTypes.oneOf(Object.values(OPEN_STATES)),
|
|
148
|
+
groupSectionProps: PropTypes.object,
|
|
149
|
+
groupSectionTitleProps: PropTypes.object,
|
|
150
|
+
groupContentWrapperProps: PropTypes.object,
|
|
151
|
+
groupContentProps: PropTypes.object
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
ContentGroupAccordion.defaultProps = {
|
|
155
|
+
VariantComponent: null,
|
|
156
|
+
openState: OPEN_STATES.ALL_CLOSED,
|
|
157
|
+
groupSectionProps: {},
|
|
158
|
+
groupSectionTitleProps: {},
|
|
159
|
+
groupContentWrapperProps: {},
|
|
160
|
+
groupContentProps: {}
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
export default ContentGroupAccordion;
|
|
@@ -3,5 +3,18 @@ const TABS = 'tabs';
|
|
|
3
3
|
const SIDEPANEL = 'sidepanel';
|
|
4
4
|
const CONTENT_GROUP = 'content-group';
|
|
5
5
|
const PANEL = 'panel';
|
|
6
|
+
const FAQ_PAGE = 'https://schema.org/FAQPage';
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
const CONTENT_GROUP_TYPES = Object.freeze({
|
|
9
|
+
TAB: 'tab',
|
|
10
|
+
SIDEPANEL: 'sidepanel',
|
|
11
|
+
ACCORDION: 'accordion'
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const OPEN_STATES = Object.freeze({
|
|
15
|
+
FIRST_OPEN: 'first_open',
|
|
16
|
+
ALL_CLOSED: 'all_closed',
|
|
17
|
+
ALL_OPEN: 'all_open'
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export { TAB, TABS, SIDEPANEL, CONTENT_GROUP, PANEL, CONTENT_GROUP_TYPES, OPEN_STATES, FAQ_PAGE };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const getStructuredDataProperties = isFaqContent => {
|
|
2
|
+
const properties = {
|
|
3
|
+
topWrapperProps: {},
|
|
4
|
+
groupSectionProps: {},
|
|
5
|
+
groupSectionTitleProps: {},
|
|
6
|
+
groupContentWrapperProps: {},
|
|
7
|
+
groupContentProps: {}
|
|
8
|
+
};
|
|
9
|
+
if (!isFaqContent) return properties;
|
|
10
|
+
|
|
11
|
+
properties.topWrapperProps = {
|
|
12
|
+
itemScope: true,
|
|
13
|
+
itemType: 'https://schema.org/FAQPage'
|
|
14
|
+
};
|
|
15
|
+
properties.groupSectionProps = {
|
|
16
|
+
itemScope: true,
|
|
17
|
+
itemProp: 'mainEntity',
|
|
18
|
+
itemType: 'https://schema.org/Question'
|
|
19
|
+
};
|
|
20
|
+
properties.groupSectionTitleProps = {
|
|
21
|
+
itemProp: 'name'
|
|
22
|
+
};
|
|
23
|
+
properties.groupContentWrapperProps = {
|
|
24
|
+
itemScope: true,
|
|
25
|
+
itemProp: 'acceptedAnswer',
|
|
26
|
+
itemType: 'https://schema.org/Answer'
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
properties.groupContentProps = {
|
|
30
|
+
itemProp: 'text'
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
return properties;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export default getStructuredDataProperties;
|
|
@@ -11,7 +11,6 @@ import BlazeLink from '../BlazeLink';
|
|
|
11
11
|
const Menu = ({
|
|
12
12
|
children,
|
|
13
13
|
collapse,
|
|
14
|
-
openActiveSubmenus,
|
|
15
14
|
modifier,
|
|
16
15
|
mobileMenuModifier,
|
|
17
16
|
mobileMenuChildrenModifier,
|
|
@@ -52,7 +51,7 @@ const Menu = ({
|
|
|
52
51
|
});
|
|
53
52
|
|
|
54
53
|
return (
|
|
55
|
-
<MenuContext.Provider value={{ showMobileMenu
|
|
54
|
+
<MenuContext.Provider value={{ showMobileMenu }}>
|
|
56
55
|
<div className={menuWrapperClasses}>
|
|
57
56
|
{collapse && (
|
|
58
57
|
<div className="menu--mobile-wrapper">
|
|
@@ -100,7 +99,6 @@ const Menu = ({
|
|
|
100
99
|
|
|
101
100
|
Menu.propTypes = {
|
|
102
101
|
collapse: PropTypes.bool.isRequired,
|
|
103
|
-
openActiveSubmenus: PropTypes.bool.isRequired,
|
|
104
102
|
logoOnMobile: PropTypes.bool.isRequired,
|
|
105
103
|
logoOnDesktop: PropTypes.bool,
|
|
106
104
|
logoOnMobileUrl: PropTypes.string,
|
|
@@ -1,23 +1,17 @@
|
|
|
1
|
-
/* eslint-disable jsx-a11y/no-static-element-interactions */
|
|
2
1
|
import React, { useState, useContext, useEffect } from 'react';
|
|
3
2
|
import PropTypes from 'prop-types';
|
|
4
3
|
import { FaChevronDown, FaChevronUp } from 'react-icons/fa';
|
|
5
|
-
import classnames from 'classnames';
|
|
6
4
|
import { useRouter } from 'next/router';
|
|
7
5
|
import { useStringTemplate } from '@blaze-cms/utils-handlebars';
|
|
8
|
-
import { HOVER, MOUSE_ENTER, MOUSE_LEAVE, HIDDEN
|
|
6
|
+
import { HOVER, MOUSE_ENTER, MOUSE_LEAVE, HIDDEN } from '../../constants';
|
|
9
7
|
import { hasChildren } from '../../helpers';
|
|
10
8
|
import BlazeLink from '../BlazeLink';
|
|
11
9
|
import MenuContext from '../Menu/MenuContext';
|
|
12
|
-
import { injectHelperIntoTemplate
|
|
10
|
+
import { injectHelperIntoTemplate } from './helpers';
|
|
13
11
|
|
|
14
12
|
const MenuItemRender = ({ children, eventType, text, modifier, url, parent }) => {
|
|
15
|
-
const
|
|
16
|
-
const { showMobileMenu
|
|
17
|
-
|
|
18
|
-
const isHoverEvent = eventType === HOVER;
|
|
19
|
-
const isClickEvent = eventType === CLICK;
|
|
20
|
-
|
|
13
|
+
const [displayChildren, setDisplayChildren] = useState(false);
|
|
14
|
+
const { showMobileMenu } = useContext(MenuContext);
|
|
21
15
|
const {
|
|
22
16
|
loading: loadingText,
|
|
23
17
|
data: [textToUse]
|
|
@@ -27,24 +21,14 @@ const MenuItemRender = ({ children, eventType, text, modifier, url, parent }) =>
|
|
|
27
21
|
data: [urlToUse]
|
|
28
22
|
} = useStringTemplate(parent, [injectHelperIntoTemplate(url, 'url_encode')]);
|
|
29
23
|
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
const
|
|
24
|
+
const router = useRouter();
|
|
25
|
+
const isHoverEvent = eventType === HOVER;
|
|
26
|
+
const childrenDisplayClass = displayChildren ? '' : HIDDEN;
|
|
33
27
|
const hasValidChildren = hasChildren(children);
|
|
34
28
|
|
|
35
|
-
const [displayChildren, setDisplayChildren] = useState(shouldPreOpen);
|
|
36
|
-
|
|
37
29
|
useEffect(() => {
|
|
38
|
-
if (!showMobileMenu
|
|
39
|
-
}, [
|
|
40
|
-
children,
|
|
41
|
-
isClickEvent,
|
|
42
|
-
loadingUrl,
|
|
43
|
-
openActiveSubmenus,
|
|
44
|
-
router,
|
|
45
|
-
shouldPreOpen,
|
|
46
|
-
showMobileMenu
|
|
47
|
-
]);
|
|
30
|
+
if (!showMobileMenu) setDisplayChildren(false);
|
|
31
|
+
}, [showMobileMenu]);
|
|
48
32
|
|
|
49
33
|
useEffect(() => {
|
|
50
34
|
if (isHoverEvent) {
|
|
@@ -54,8 +38,6 @@ const MenuItemRender = ({ children, eventType, text, modifier, url, parent }) =>
|
|
|
54
38
|
|
|
55
39
|
if (loadingUrl || loadingText) return '';
|
|
56
40
|
|
|
57
|
-
const childrenDisplayClass = displayChildren ? '' : HIDDEN;
|
|
58
|
-
|
|
59
41
|
const handleItemEvent = ({ type }) => {
|
|
60
42
|
if (isHoverEvent) {
|
|
61
43
|
if (type === MOUSE_ENTER) {
|
|
@@ -73,25 +55,15 @@ const MenuItemRender = ({ children, eventType, text, modifier, url, parent }) =>
|
|
|
73
55
|
}
|
|
74
56
|
};
|
|
75
57
|
|
|
76
|
-
const menuItemLinkClassname = classnames('menu--item--link', {
|
|
77
|
-
'menu--item--link--active': isActive,
|
|
78
|
-
'menu--item--link--active-parent': isActiveParent
|
|
79
|
-
});
|
|
80
|
-
|
|
81
58
|
return (
|
|
82
59
|
<li className={modifier} onMouseEnter={handleItemEvent} onMouseLeave={handleItemEvent}>
|
|
83
60
|
<div
|
|
84
|
-
className=
|
|
61
|
+
className="menu--item--link"
|
|
85
62
|
onClick={handleMobileClick}
|
|
86
63
|
role={!urlToUse && hasValidChildren ? 'button' : undefined}
|
|
87
64
|
tabIndex={!urlToUse && hasValidChildren ? 0 : undefined}>
|
|
88
|
-
{urlToUse ?
|
|
89
|
-
|
|
90
|
-
) : (
|
|
91
|
-
<span role="button" onClick={handleItemEvent}>
|
|
92
|
-
{textToUse}
|
|
93
|
-
</span>
|
|
94
|
-
)}
|
|
65
|
+
{urlToUse ? <BlazeLink href={urlToUse}>{textToUse}</BlazeLink> : <span>{textToUse}</span>}
|
|
66
|
+
|
|
95
67
|
{hasValidChildren && (
|
|
96
68
|
<i
|
|
97
69
|
role="button"
|
|
@@ -1,5 +1,3 @@
|
|
|
1
1
|
import injectHelperIntoTemplate from './inject-helper-into-template';
|
|
2
|
-
import isUrlPathMatch from './isUrlPathMatch';
|
|
3
|
-
import hasActiveChild from './has-active-child';
|
|
4
2
|
|
|
5
|
-
export { injectHelperIntoTemplate
|
|
3
|
+
export { injectHelperIntoTemplate };
|
|
@@ -18,6 +18,7 @@ const SearchContent = props => {
|
|
|
18
18
|
searchUrl,
|
|
19
19
|
navigateToSingleSearchResult
|
|
20
20
|
} = props;
|
|
21
|
+
|
|
21
22
|
const searchContentRef = useRef(null);
|
|
22
23
|
const [collapsed, setCollapsed] = useState(collapsedSearch);
|
|
23
24
|
const [showResults, setShowResults] = useState(false);
|
|
@@ -43,7 +44,6 @@ const SearchContent = props => {
|
|
|
43
44
|
if (collapsedSearch) setCollapsed(true);
|
|
44
45
|
};
|
|
45
46
|
router.events.on('routeChangeStart', handleRouteChange);
|
|
46
|
-
|
|
47
47
|
return () => {
|
|
48
48
|
router.events.off('routeChangeStart', handleRouteChange);
|
|
49
49
|
};
|
|
@@ -53,15 +53,16 @@ const SearchContent = props => {
|
|
|
53
53
|
const handleClickOutside = event => {
|
|
54
54
|
if (searchContentRef.current && !searchContentRef.current.contains(event.target)) {
|
|
55
55
|
setShowResults(false);
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
setSearchTerm('');
|
|
57
|
+
if (collapsedSearch) setCollapsed(true);
|
|
58
|
+
|
|
59
|
+
if (document.activeElement && document.activeElement instanceof HTMLElement) {
|
|
60
|
+
document.activeElement.blur();
|
|
59
61
|
}
|
|
60
62
|
}
|
|
61
63
|
};
|
|
62
64
|
|
|
63
65
|
document.addEventListener('click', handleClickOutside);
|
|
64
|
-
|
|
65
66
|
return () => {
|
|
66
67
|
document.removeEventListener('click', handleClickOutside);
|
|
67
68
|
};
|
|
@@ -38,8 +38,10 @@ const addEditorModeEventListeners = ({ ref, name, adminHref, type, setLogoProps
|
|
|
38
38
|
e.preventDefault();
|
|
39
39
|
window.open(`${adminHref}#${componentId}`, adminHref);
|
|
40
40
|
};
|
|
41
|
+
|
|
41
42
|
const mouseenter = e => {
|
|
42
43
|
e.stopPropagation();
|
|
44
|
+
|
|
43
45
|
document.querySelectorAll(`.${EDITOR_MODE_HIGHLIGHT_CLASS}`).forEach(node => {
|
|
44
46
|
node.classList.remove(EDITOR_MODE_HIGHLIGHT_CLASS);
|
|
45
47
|
});
|
|
@@ -52,6 +54,7 @@ const addEditorModeEventListeners = ({ ref, name, adminHref, type, setLogoProps
|
|
|
52
54
|
onClick: click
|
|
53
55
|
});
|
|
54
56
|
};
|
|
57
|
+
|
|
55
58
|
const mouseleave = e => {
|
|
56
59
|
e.stopPropagation();
|
|
57
60
|
if (e.toElement) {
|
|
@@ -61,7 +64,6 @@ const addEditorModeEventListeners = ({ ref, name, adminHref, type, setLogoProps
|
|
|
61
64
|
return;
|
|
62
65
|
}
|
|
63
66
|
}
|
|
64
|
-
childNode.classList.remove(EDITOR_MODE_HIGHLIGHT_CLASS);
|
|
65
67
|
setLogoProps(null);
|
|
66
68
|
};
|
|
67
69
|
|
|
@@ -1,16 +1,46 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @jest-environment jsdom
|
|
3
3
|
*/
|
|
4
|
+
import React from 'react';
|
|
4
5
|
import { render } from '@blaze-cms/tools/test-helpers/test-functions';
|
|
5
6
|
import ContentGroup from '../../../../../src/components/ContentGroup/ContentGroup';
|
|
6
7
|
|
|
8
|
+
jest.mock('../../../../../src/components/ContentGroup/ContentGroupTabs', () => ({
|
|
9
|
+
__esModule: true,
|
|
10
|
+
default: ({ contentType }) => <div data-testid="content-group-tabs">Inner: {contentType}</div>
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
const TestChild = ({ children }) => <div>{children}</div>;
|
|
14
|
+
const buildChildren = (sectionsCount = 2) => (
|
|
15
|
+
<div>
|
|
16
|
+
<div>Header</div>
|
|
17
|
+
{Array.from({ length: sectionsCount }).map((_, i) => (
|
|
18
|
+
<TestChild key={`s${i + 1}`}>Section {i + 1}</TestChild>
|
|
19
|
+
))}
|
|
20
|
+
</div>
|
|
21
|
+
);
|
|
22
|
+
|
|
7
23
|
describe('ContentGroup component', () => {
|
|
8
|
-
it('
|
|
9
|
-
const { asFragment: tabContentGroup } = render(ContentGroup, {
|
|
24
|
+
it('matches snapshots for tab and sidepanel', () => {
|
|
25
|
+
const { asFragment: tabContentGroup } = render(ContentGroup, {
|
|
26
|
+
contentType: 'tab'
|
|
27
|
+
});
|
|
10
28
|
const { asFragment: sidepanelContentGroup } = render(ContentGroup, {
|
|
11
29
|
contentType: 'sidepanel'
|
|
12
30
|
});
|
|
31
|
+
|
|
13
32
|
expect(tabContentGroup()).toMatchSnapshot();
|
|
14
33
|
expect(sidepanelContentGroup()).toMatchSnapshot();
|
|
15
34
|
});
|
|
35
|
+
|
|
36
|
+
it('wraps output in FAQPage schema when isFaqContent is true', () => {
|
|
37
|
+
const { container } = render(ContentGroup, {
|
|
38
|
+
contentType: 'tab',
|
|
39
|
+
isFaqContent: true,
|
|
40
|
+
children: buildChildren()
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const faqWrapper = container.querySelector('div[itemtype="https://schema.org/FAQPage"]');
|
|
44
|
+
expect(faqWrapper).toBeTruthy();
|
|
45
|
+
});
|
|
16
46
|
});
|