@eeacms/volto-tabs-block 3.0.1 → 4.0.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/CHANGELOG.md +30 -0
- package/package.json +2 -2
- package/src/components/EditBlockWrapper.jsx +9 -2
- package/src/components/View.jsx +1 -0
- package/src/components/templates/accordion/View.jsx +42 -7
- package/src/components/templates/accordion/schema.js +25 -19
- package/src/components/templates/carousel/HorizontalView.jsx +37 -2
- package/src/components/templates/default/Edit.jsx +5 -1
- package/src/components/templates/default/View.jsx +24 -4
- package/src/components/templates/horizontal-responsive/View.jsx +53 -6
- package/src/less/menu.less +170 -6
- package/src/less/menu.variables +5 -0
- package/src/less/tabs.less +25 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,36 @@ All notable changes to this project will be documented in this file. Dates are d
|
|
|
4
4
|
|
|
5
5
|
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
6
6
|
|
|
7
|
+
### [4.0.1](https://github.com/eea/volto-tabs-block/compare/4.0.0...4.0.1) - 4 April 2023
|
|
8
|
+
|
|
9
|
+
#### :rocket: New Features
|
|
10
|
+
|
|
11
|
+
- feat(EditBlockWrapper.jsx): add buildStyleClassNamesFromData helper function to import [Miu Razvan - [`b3cd3c8`](https://github.com/eea/volto-tabs-block/commit/b3cd3c84aecea5d858a77cdd208dd669ee4bf328)]
|
|
12
|
+
|
|
13
|
+
#### :bug: Bug Fixes
|
|
14
|
+
|
|
15
|
+
- fix(Edit.jsx): add key prop to MenuItem component to avoid warning in console [Miu Razvan - [`55cc784`](https://github.com/eea/volto-tabs-block/commit/55cc784f452637cf686f80a40aef3809784032f6)]
|
|
16
|
+
|
|
17
|
+
#### :hammer_and_wrench: Others
|
|
18
|
+
|
|
19
|
+
- Add Sonarqube tag using eea-website-frontend addons list [EEA Jenkins - [`52bc1b0`](https://github.com/eea/volto-tabs-block/commit/52bc1b0fbd4611173b8ca9dc2cf4033b31474420)]
|
|
20
|
+
## [4.0.0](https://github.com/eea/volto-tabs-block/compare/3.0.1...4.0.0) - 10 March 2023
|
|
21
|
+
|
|
22
|
+
#### :house: Internal changes
|
|
23
|
+
|
|
24
|
+
- chore(accordion): Cleanup menuColor [Alin Voinea - [`de63905`](https://github.com/eea/volto-tabs-block/commit/de639056210d426d64e2e4762aeec2e215563854)]
|
|
25
|
+
- chore(typo): Fix typo accesibilty [Alin Voinea - [`cc7754e`](https://github.com/eea/volto-tabs-block/commit/cc7754eeb2e224966f942b9053638c3db94d834c)]
|
|
26
|
+
|
|
27
|
+
#### :hammer_and_wrench: Others
|
|
28
|
+
|
|
29
|
+
- Release 4.0.0 [Alin Voinea - [`8fc4cc9`](https://github.com/eea/volto-tabs-block/commit/8fc4cc9d8dc71e623e6586b95871cb3b98dc385f)]
|
|
30
|
+
- Add Sonarqube tag using eea-website-frontend addons list [EEA Jenkins - [`22d5bdc`](https://github.com/eea/volto-tabs-block/commit/22d5bdc1b3579cc46c73ce855041ca09154eb502)]
|
|
31
|
+
- Add Sonarqube tag using advisory-board-frontend addons list [EEA Jenkins - [`fde4324`](https://github.com/eea/volto-tabs-block/commit/fde4324f962cde8e8de0d76a44bee4b67d216bf8)]
|
|
32
|
+
- Add Sonarqube tag using advisory-board-frontend addons list [EEA Jenkins - [`9175e47`](https://github.com/eea/volto-tabs-block/commit/9175e470d793edc63b62a99940aed25dd45f3713)]
|
|
33
|
+
- test(Jenkins): Run tests and cypress with latest canary @plone/volto [Alin Voinea - [`3348950`](https://github.com/eea/volto-tabs-block/commit/334895036f8e367281abb35a20879c32dfbfc292)]
|
|
34
|
+
- Add Sonarqube tag using cca-frontend addons list [EEA Jenkins - [`39bfb39`](https://github.com/eea/volto-tabs-block/commit/39bfb39fa6e8483e639491ff998293e758ac6384)]
|
|
35
|
+
- yarn 3 [Alin Voinea - [`7e98df5`](https://github.com/eea/volto-tabs-block/commit/7e98df59669d71945be461e86e282b913538b805)]
|
|
36
|
+
- Add Sonarqube tag using demo-kitkat-frontend addons list [EEA Jenkins - [`079d7a4`](https://github.com/eea/volto-tabs-block/commit/079d7a43480e92fe280a9372399ff2d4d28537ae)]
|
|
7
37
|
### [3.0.1](https://github.com/eea/volto-tabs-block/compare/3.0.0...3.0.1) - 16 November 2022
|
|
8
38
|
|
|
9
39
|
#### :hammer_and_wrench: Others
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eeacms/volto-tabs-block",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.1",
|
|
4
4
|
"description": "volto-tabs-block: Volto add-on",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"author": "European Environment Agency: IDM2 A-Team",
|
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
"slick-carousel": "^1.8.1"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@plone/scripts": "*",
|
|
30
29
|
"@cypress/code-coverage": "^3.10.0",
|
|
30
|
+
"@plone/scripts": "*",
|
|
31
31
|
"babel-plugin-transform-class-properties": "^6.24.1",
|
|
32
32
|
"md5": "^2.3.0"
|
|
33
33
|
},
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Icon, BlockChooser } from '@plone/volto/components';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
blockHasValue,
|
|
5
|
+
buildStyleClassNamesFromData,
|
|
6
|
+
} from '@plone/volto/helpers';
|
|
4
7
|
import config from '@plone/volto/registry';
|
|
5
8
|
import { Button } from 'semantic-ui-react';
|
|
6
9
|
import includes from 'lodash/includes';
|
|
@@ -81,12 +84,16 @@ class EditBlockWrapper extends React.Component {
|
|
|
81
84
|
? data.required
|
|
82
85
|
: includes(config.blocks.requiredBlocks, type);
|
|
83
86
|
|
|
87
|
+
const styles = buildStyleClassNamesFromData(data.styles);
|
|
88
|
+
|
|
84
89
|
return (
|
|
85
90
|
<div ref={this.blockNode} className="block-wrapper">
|
|
86
91
|
<div
|
|
87
92
|
ref={draginfo?.innerRef}
|
|
88
93
|
{...(selected ? draginfo?.draggableProps : null)}
|
|
89
|
-
className={`block-editor-${data['@type']}
|
|
94
|
+
className={cx(`block-editor-${data['@type']}`, styles, {
|
|
95
|
+
[data.align]: data.align,
|
|
96
|
+
})}
|
|
90
97
|
>
|
|
91
98
|
{!selected && (
|
|
92
99
|
<div
|
package/src/components/View.jsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useLayoutEffect } from 'react';
|
|
2
2
|
import cx from 'classnames';
|
|
3
3
|
import { compose } from 'redux';
|
|
4
4
|
import { withRouter } from 'react-router';
|
|
@@ -31,7 +31,12 @@ class Tab extends React.Component {
|
|
|
31
31
|
|
|
32
32
|
render() {
|
|
33
33
|
return (
|
|
34
|
-
<AnimateHeight
|
|
34
|
+
<AnimateHeight
|
|
35
|
+
animateOpacity
|
|
36
|
+
duration={500}
|
|
37
|
+
height={this.state.height}
|
|
38
|
+
aria-hidden={false}
|
|
39
|
+
>
|
|
35
40
|
<RenderBlocks {...this.props} />
|
|
36
41
|
</AnimateHeight>
|
|
37
42
|
);
|
|
@@ -45,7 +50,9 @@ const View = (props) => {
|
|
|
45
50
|
tabs = {},
|
|
46
51
|
activeTabIndex = 0,
|
|
47
52
|
setActiveTab = () => {},
|
|
53
|
+
id,
|
|
48
54
|
} = props;
|
|
55
|
+
|
|
49
56
|
const accordionConfig =
|
|
50
57
|
config.blocks.blocksConfig[TABS_BLOCK].templates?.['accordion'] || {};
|
|
51
58
|
const { icons, semanticIcon, transformWidth = 800 } = accordionConfig;
|
|
@@ -94,7 +101,9 @@ const View = (props) => {
|
|
|
94
101
|
{title || defaultTitle}{' '}
|
|
95
102
|
</>
|
|
96
103
|
),
|
|
97
|
-
getContent: () =>
|
|
104
|
+
getContent: () => (
|
|
105
|
+
<Tab {...props} tab={tab} content={tabs[tab]} aria-hidden={false} />
|
|
106
|
+
),
|
|
98
107
|
key: tab,
|
|
99
108
|
tabClassName: cx('ui button item title', { active }),
|
|
100
109
|
panelClassName: cx('ui bottom attached segment tab', {
|
|
@@ -115,12 +124,36 @@ const View = (props) => {
|
|
|
115
124
|
);
|
|
116
125
|
}, [mounted]);
|
|
117
126
|
|
|
127
|
+
useLayoutEffect(() => {
|
|
128
|
+
if (document.activeElement.role !== 'tab') return;
|
|
129
|
+
if (
|
|
130
|
+
document.getElementById(id)?.getElementsByClassName('tab active').length >
|
|
131
|
+
0
|
|
132
|
+
) {
|
|
133
|
+
let activeTabDiv = document
|
|
134
|
+
.getElementById(id)
|
|
135
|
+
.getElementsByClassName('tab active')[0];
|
|
136
|
+
activeTabDiv.setAttribute('tabindex', '0');
|
|
137
|
+
activeTabDiv.setAttribute('className', 'accessibility-accordion-tab');
|
|
138
|
+
activeTabDiv.focus();
|
|
139
|
+
}
|
|
140
|
+
}, [activeTabIndex, id]);
|
|
141
|
+
|
|
118
142
|
return (
|
|
119
|
-
|
|
143
|
+
<div
|
|
144
|
+
tabIndex="0"
|
|
145
|
+
onKeyDown={(e) => {
|
|
146
|
+
if (e.key === 'Enter') {
|
|
147
|
+
e.preventDefault();
|
|
148
|
+
const focusedElement = document.activeElement;
|
|
149
|
+
if (focusedElement) focusedElement.click();
|
|
150
|
+
}
|
|
151
|
+
}}
|
|
152
|
+
role="tab"
|
|
153
|
+
>
|
|
120
154
|
<Tabs
|
|
121
155
|
ref={tabsContainer}
|
|
122
156
|
transformWidth={initialWidth}
|
|
123
|
-
className="tabs aa"
|
|
124
157
|
selectedTabKey={tabsList[activeTabIndex]}
|
|
125
158
|
items={items}
|
|
126
159
|
onChange={(tab) => {
|
|
@@ -131,15 +164,17 @@ const View = (props) => {
|
|
|
131
164
|
}
|
|
132
165
|
}}
|
|
133
166
|
tabsWrapperClass={cx(
|
|
167
|
+
props?.data?.accordionIconRight ? 'tabs-accordion-icon-right' : '',
|
|
134
168
|
'ui pointing secondary menu',
|
|
135
|
-
|
|
169
|
+
'tabs-accessibility',
|
|
170
|
+
data?.theme ? `theme-${data?.theme}` : '',
|
|
136
171
|
{
|
|
137
172
|
inverted: getDataValue('menuInverted'),
|
|
138
173
|
},
|
|
139
174
|
)}
|
|
140
175
|
showMore={false}
|
|
141
176
|
/>
|
|
142
|
-
|
|
177
|
+
</div>
|
|
143
178
|
);
|
|
144
179
|
};
|
|
145
180
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import config from '@plone/volto/registry';
|
|
2
|
+
|
|
1
3
|
export default () => ({
|
|
2
4
|
title: 'Accordion tabs block',
|
|
3
5
|
fieldsets: [
|
|
@@ -9,36 +11,40 @@ export default () => ({
|
|
|
9
11
|
{
|
|
10
12
|
id: 'menu',
|
|
11
13
|
title: 'Menu',
|
|
12
|
-
fields: ['
|
|
14
|
+
fields: ['menuInverted', 'accordionIconRight'],
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
id: 'style',
|
|
18
|
+
title: 'Style',
|
|
19
|
+
fields: ['theme'],
|
|
13
20
|
},
|
|
14
21
|
],
|
|
15
22
|
properties: {
|
|
16
23
|
description: {
|
|
17
24
|
title: 'Description',
|
|
18
25
|
},
|
|
19
|
-
|
|
20
|
-
title: '
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
['red', 'Red'],
|
|
24
|
-
['orange', 'Orange'],
|
|
25
|
-
['yellow', 'Yellow'],
|
|
26
|
-
['olive', 'Olive'],
|
|
27
|
-
['green', 'Green'],
|
|
28
|
-
['teal', 'Teal'],
|
|
29
|
-
['blue', 'Blue'],
|
|
30
|
-
['violet', 'Violet'],
|
|
31
|
-
['purple', 'Purple'],
|
|
32
|
-
['pink', 'Pink'],
|
|
33
|
-
['brown', 'Brown'],
|
|
34
|
-
['grey', 'Grey'],
|
|
35
|
-
['black', 'Black'],
|
|
36
|
-
],
|
|
26
|
+
accordionIconRight: {
|
|
27
|
+
title: 'Icon position on the right',
|
|
28
|
+
description: 'Position left/right of the icon in the accordion tab',
|
|
29
|
+
type: 'boolean',
|
|
37
30
|
},
|
|
38
31
|
menuInverted: {
|
|
39
32
|
title: 'Inverted',
|
|
40
33
|
type: 'boolean',
|
|
41
34
|
},
|
|
35
|
+
theme: {
|
|
36
|
+
title: 'Theme',
|
|
37
|
+
description: 'Set the theme for the accordion tabs block',
|
|
38
|
+
widget: 'theme_picker',
|
|
39
|
+
colors: [
|
|
40
|
+
...(config.settings && config.settings.themeColors
|
|
41
|
+
? config.settings.themeColors.map(({ value, title }) => ({
|
|
42
|
+
name: value,
|
|
43
|
+
label: title,
|
|
44
|
+
}))
|
|
45
|
+
: []),
|
|
46
|
+
],
|
|
47
|
+
},
|
|
42
48
|
},
|
|
43
49
|
required: [],
|
|
44
50
|
});
|
|
@@ -29,6 +29,7 @@ const Dots = (props) => {
|
|
|
29
29
|
>
|
|
30
30
|
<button
|
|
31
31
|
aria-label={`Select slide ${index + 1}`}
|
|
32
|
+
tabIndex={0}
|
|
32
33
|
onClick={() => {
|
|
33
34
|
if (slider.current) {
|
|
34
35
|
slider.current.slickGoTo(index);
|
|
@@ -65,6 +66,7 @@ const ArrowsGroup = (props) => {
|
|
|
65
66
|
slider.current.slickPrev();
|
|
66
67
|
}
|
|
67
68
|
}}
|
|
69
|
+
tabIndex={0}
|
|
68
70
|
>
|
|
69
71
|
<Icon name={leftArrowSVG} size="50px" />
|
|
70
72
|
</button>
|
|
@@ -80,6 +82,7 @@ const ArrowsGroup = (props) => {
|
|
|
80
82
|
slider.current.slickNext();
|
|
81
83
|
}
|
|
82
84
|
}}
|
|
85
|
+
tabIndex={0}
|
|
83
86
|
>
|
|
84
87
|
<Icon name={rightArrowSVG} size="50px" />
|
|
85
88
|
</button>
|
|
@@ -93,6 +96,7 @@ const ArrowsGroup = (props) => {
|
|
|
93
96
|
const View = (props) => {
|
|
94
97
|
const slider = React.useRef(null);
|
|
95
98
|
const [hashlinkOnMount, setHashlinkOnMount] = React.useState(false);
|
|
99
|
+
const blockId = props.id;
|
|
96
100
|
const {
|
|
97
101
|
activeTab = null,
|
|
98
102
|
data = {},
|
|
@@ -128,10 +132,24 @@ const View = (props) => {
|
|
|
128
132
|
for (let element of slider.current.innerSlider.list.querySelectorAll(
|
|
129
133
|
".slick-slide[aria-hidden='true'] a",
|
|
130
134
|
)) {
|
|
131
|
-
element.setAttribute('aria-
|
|
135
|
+
element.setAttribute('aria-hidden', 'false');
|
|
132
136
|
}
|
|
133
137
|
});
|
|
134
138
|
}, [activeTab]);
|
|
139
|
+
React.useEffect(() => {
|
|
140
|
+
if (!slider.current?.innerSlider?.list) return;
|
|
141
|
+
let unaccesibileElements = slider.current.innerSlider.list.querySelectorAll(
|
|
142
|
+
'.slick-slide',
|
|
143
|
+
);
|
|
144
|
+
for (let element of unaccesibileElements) {
|
|
145
|
+
element.setAttribute('tabindex', '0');
|
|
146
|
+
element.setAttribute('aria-hidden', 'false');
|
|
147
|
+
element.style.removeProperty('outline');
|
|
148
|
+
}
|
|
149
|
+
if (document.getElementsByClassName('slick-slider')?.length > 0)
|
|
150
|
+
for (let carouselDiv of document.getElementsByClassName('slick-slider'))
|
|
151
|
+
carouselDiv.setAttribute('tabindex', '0');
|
|
152
|
+
}, []);
|
|
135
153
|
|
|
136
154
|
React.useEffect(() => {
|
|
137
155
|
const urlHash = props.location.hash.substring(1) || '';
|
|
@@ -183,7 +201,24 @@ const View = (props) => {
|
|
|
183
201
|
|
|
184
202
|
return (
|
|
185
203
|
<>
|
|
186
|
-
<Slider
|
|
204
|
+
<Slider
|
|
205
|
+
{...settings}
|
|
206
|
+
ref={slider}
|
|
207
|
+
className={cx(uiContainer, 'tabs-accessibility')}
|
|
208
|
+
accessibility={true}
|
|
209
|
+
afterChange={() => {
|
|
210
|
+
if (
|
|
211
|
+
document
|
|
212
|
+
.getElementById(blockId)
|
|
213
|
+
?.getElementsByClassName('slick-slider')?.length > 0
|
|
214
|
+
) {
|
|
215
|
+
document
|
|
216
|
+
.getElementById(blockId)
|
|
217
|
+
.getElementsByClassName('slick-current')[0]
|
|
218
|
+
.focus();
|
|
219
|
+
}
|
|
220
|
+
}}
|
|
221
|
+
>
|
|
187
222
|
{panes.length ? panes.map((pane) => pane.renderItem) : ''}
|
|
188
223
|
</Slider>
|
|
189
224
|
<ArrowsGroup activeTab={activeTab} tabsList={tabsList} slider={slider} />
|
|
@@ -193,6 +193,7 @@ const Edit = (props) => {
|
|
|
193
193
|
menuItem: (
|
|
194
194
|
<MenuItem
|
|
195
195
|
{...props}
|
|
196
|
+
key={tab}
|
|
196
197
|
editingTab={editingTab}
|
|
197
198
|
index={index}
|
|
198
199
|
setEditingTab={setEditingTab}
|
|
@@ -274,7 +275,10 @@ const Edit = (props) => {
|
|
|
274
275
|
menu={{
|
|
275
276
|
attached: menuPosition.attached,
|
|
276
277
|
borderless: getDataValue('menuBorderless'),
|
|
277
|
-
color:
|
|
278
|
+
color:
|
|
279
|
+
props?.template === 'accordion' && props?.data?.theme
|
|
280
|
+
? `theme-${props?.data?.theme}`
|
|
281
|
+
: getDataValue('menuColor'),
|
|
278
282
|
compact: getDataValue('menuCompact'),
|
|
279
283
|
fluid: getDataValue('menuFluid'),
|
|
280
284
|
inverted: getDataValue('menuInverted'),
|
|
@@ -22,11 +22,12 @@ const MenuItem = (props) => {
|
|
|
22
22
|
setActiveTab = () => {},
|
|
23
23
|
tabsTitle,
|
|
24
24
|
tabsDescription,
|
|
25
|
+
blockId,
|
|
25
26
|
} = props;
|
|
27
|
+
|
|
26
28
|
const { tab, index } = props;
|
|
27
29
|
const title = tabs[tab].title;
|
|
28
30
|
const tabIndex = index + 1;
|
|
29
|
-
|
|
30
31
|
const defaultTitle = `Tab ${tabIndex}`;
|
|
31
32
|
|
|
32
33
|
return (
|
|
@@ -40,11 +41,30 @@ const MenuItem = (props) => {
|
|
|
40
41
|
<Menu.Item
|
|
41
42
|
name={defaultTitle}
|
|
42
43
|
active={tab === activeTab}
|
|
44
|
+
tabIndex={0}
|
|
43
45
|
onClick={() => {
|
|
44
46
|
if (activeTab !== tab) {
|
|
45
47
|
setActiveTab(tab);
|
|
46
48
|
}
|
|
47
49
|
}}
|
|
50
|
+
onKeyDown={(e) => {
|
|
51
|
+
if (e.key === 'Enter') {
|
|
52
|
+
e.preventDefault();
|
|
53
|
+
if (
|
|
54
|
+
document
|
|
55
|
+
.getElementById(blockId)
|
|
56
|
+
?.getElementsByClassName('active tab').length > 0
|
|
57
|
+
) {
|
|
58
|
+
const tabDiv = document
|
|
59
|
+
.getElementById(blockId)
|
|
60
|
+
.getElementsByClassName('active tab')[0];
|
|
61
|
+
tabDiv.focus();
|
|
62
|
+
}
|
|
63
|
+
if (activeTab !== tab) {
|
|
64
|
+
setActiveTab(tab);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}}
|
|
48
68
|
>
|
|
49
69
|
<span className={'menu-item-count'}>{tabIndex}</span>
|
|
50
70
|
<p className={'menu-item-text'}>{title || defaultTitle}</p>
|
|
@@ -64,7 +84,6 @@ const View = (props) => {
|
|
|
64
84
|
hashlink = {},
|
|
65
85
|
setActiveTab = () => {},
|
|
66
86
|
} = props;
|
|
67
|
-
|
|
68
87
|
const [menuPosition, setMenuPosition] = React.useState({});
|
|
69
88
|
|
|
70
89
|
React.useEffect(() => {
|
|
@@ -134,11 +153,12 @@ const View = (props) => {
|
|
|
134
153
|
index={index}
|
|
135
154
|
tabsTitle={tabsTitle}
|
|
136
155
|
tabsDescription={tabsDescription}
|
|
156
|
+
blockId={props?.id || ''}
|
|
137
157
|
/>
|
|
138
158
|
),
|
|
139
159
|
render: () => {
|
|
140
160
|
return (
|
|
141
|
-
<Tab.Pane as={isContainer ? Container : undefined}>
|
|
161
|
+
<Tab.Pane as={isContainer ? Container : undefined} tabIndex={0}>
|
|
142
162
|
<RenderBlocks {...props} metadata={metadata} content={tabs[tab]} />
|
|
143
163
|
</Tab.Pane>
|
|
144
164
|
);
|
|
@@ -150,7 +170,7 @@ const View = (props) => {
|
|
|
150
170
|
<>
|
|
151
171
|
<Tab
|
|
152
172
|
activeIndex={activeTabIndex}
|
|
153
|
-
className="default tabs"
|
|
173
|
+
className="default tabs tabs-accessibility"
|
|
154
174
|
menu={{
|
|
155
175
|
attached: menuPosition.attached,
|
|
156
176
|
borderless: getDataValue('menuBorderless'),
|
|
@@ -18,30 +18,76 @@ import {
|
|
|
18
18
|
import '@eeacms/volto-tabs-block/less/menu.less';
|
|
19
19
|
|
|
20
20
|
const MenuItem = (props) => {
|
|
21
|
-
const {
|
|
21
|
+
const {
|
|
22
|
+
activeTab = null,
|
|
23
|
+
tabs = {},
|
|
24
|
+
setActiveTab = () => {},
|
|
25
|
+
blockId,
|
|
26
|
+
} = props;
|
|
22
27
|
const { tabsTitle, tabsDescription, tab, index } = props;
|
|
23
28
|
const title = tabs[tab].title;
|
|
24
29
|
const tabIndex = index + 1;
|
|
25
|
-
|
|
26
30
|
const defaultTitle = `Tab ${tabIndex}`;
|
|
27
31
|
|
|
28
32
|
return (
|
|
29
33
|
<React.Fragment>
|
|
30
34
|
{index === 0 && (tabsTitle || tabsDescription) && (
|
|
31
|
-
<Menu.Item
|
|
35
|
+
<Menu.Item
|
|
36
|
+
className="menu-title"
|
|
37
|
+
tabIndex={0}
|
|
38
|
+
onKeyDown={(e) => {
|
|
39
|
+
if (e.key === 'Enter') {
|
|
40
|
+
e.preventDefault();
|
|
41
|
+
if (
|
|
42
|
+
document
|
|
43
|
+
.getElementById(blockId)
|
|
44
|
+
?.getElementsByClassName('active tab')?.length > 0
|
|
45
|
+
) {
|
|
46
|
+
const tabDiv = document
|
|
47
|
+
.getElementById(blockId)
|
|
48
|
+
.getElementsByClassName('active tab')[0];
|
|
49
|
+
tabDiv.focus();
|
|
50
|
+
}
|
|
51
|
+
if (activeTab !== tab) {
|
|
52
|
+
setActiveTab(tab);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}}
|
|
56
|
+
>
|
|
32
57
|
<SimpleMarkdown md={tabsTitle} defaultTag="##" className="title" />
|
|
33
58
|
<SimpleMarkdown md={tabsDescription} className="description" />
|
|
34
59
|
</Menu.Item>
|
|
35
60
|
)}
|
|
36
61
|
<Button
|
|
37
62
|
as="a"
|
|
38
|
-
|
|
63
|
+
tabIndex={0}
|
|
64
|
+
className={cx('item', 'accesibility-button', {
|
|
65
|
+
active: tab === activeTab,
|
|
66
|
+
})}
|
|
39
67
|
item-data={tab}
|
|
40
68
|
onClick={() => {
|
|
41
69
|
if (activeTab !== tab) {
|
|
42
70
|
setActiveTab(tab);
|
|
43
71
|
}
|
|
44
72
|
}}
|
|
73
|
+
onKeyDown={(e) => {
|
|
74
|
+
if (e.key === 'Enter') {
|
|
75
|
+
e.preventDefault();
|
|
76
|
+
if (
|
|
77
|
+
document
|
|
78
|
+
.getElementById(blockId)
|
|
79
|
+
?.getElementsByClassName('active tab').length > 0
|
|
80
|
+
) {
|
|
81
|
+
const tabDiv = document
|
|
82
|
+
.getElementById(blockId)
|
|
83
|
+
.getElementsByClassName('active tab')[0];
|
|
84
|
+
tabDiv.focus();
|
|
85
|
+
}
|
|
86
|
+
if (activeTab !== tab) {
|
|
87
|
+
setActiveTab(tab);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}}
|
|
45
91
|
>
|
|
46
92
|
<span className={'menu-item-count'}>{tabIndex}</span>
|
|
47
93
|
<p className={'menu-item-text'}>{title || defaultTitle}</p>
|
|
@@ -92,7 +138,7 @@ const MenuWrapper = (props) => {
|
|
|
92
138
|
|
|
93
139
|
return (
|
|
94
140
|
<React.Fragment>
|
|
95
|
-
<div className="menu-wrapper">
|
|
141
|
+
<div className="menu-wrapper tabs-accessibility">
|
|
96
142
|
{panes.map((pane, index) => (
|
|
97
143
|
<React.Fragment key={`menu-item-${index}-${pane.id}`}>
|
|
98
144
|
{pane.menuItem}
|
|
@@ -207,6 +253,7 @@ const View = (props) => {
|
|
|
207
253
|
key={tab}
|
|
208
254
|
tab={tab}
|
|
209
255
|
tabsList={tabsList}
|
|
256
|
+
blockId={props.id}
|
|
210
257
|
index={index}
|
|
211
258
|
lastIndex={tabsList.length - 1}
|
|
212
259
|
tabsTitle={tabsTitle}
|
|
@@ -216,7 +263,7 @@ const View = (props) => {
|
|
|
216
263
|
render: () => {
|
|
217
264
|
return (
|
|
218
265
|
<>
|
|
219
|
-
<Tab.Pane as={isContainer ? Container : undefined}>
|
|
266
|
+
<Tab.Pane as={isContainer ? Container : undefined} tabIndex={0}>
|
|
220
267
|
<RenderBlocks
|
|
221
268
|
{...props}
|
|
222
269
|
metadata={metadata}
|
package/src/less/menu.less
CHANGED
|
@@ -55,12 +55,10 @@
|
|
|
55
55
|
flex-direction: column;
|
|
56
56
|
align-items: flex-start;
|
|
57
57
|
justify-content: center;
|
|
58
|
-
background: @menuTitleBackgrounnd;
|
|
59
58
|
font-size: @menuTitleFontSize;
|
|
60
59
|
font-weight: @menuTitleFontWeight;
|
|
61
60
|
|
|
62
61
|
&:hover {
|
|
63
|
-
background: @menuTitleHoverBackground;
|
|
64
62
|
color: @menuTitleHoverColor;
|
|
65
63
|
}
|
|
66
64
|
|
|
@@ -143,6 +141,13 @@
|
|
|
143
141
|
}
|
|
144
142
|
}
|
|
145
143
|
|
|
144
|
+
.ui.menu.RRT__accordion.tabs-accordion-icon-right {
|
|
145
|
+
.ui.item {
|
|
146
|
+
flex-direction: row-reverse;
|
|
147
|
+
justify-content: space-between;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
146
151
|
.ui.menu.RRT__accordion {
|
|
147
152
|
&::before {
|
|
148
153
|
display: none;
|
|
@@ -153,11 +158,9 @@
|
|
|
153
158
|
.ui.item {
|
|
154
159
|
display: flex;
|
|
155
160
|
width: 100%;
|
|
156
|
-
padding: 0
|
|
157
|
-
border-
|
|
158
|
-
border-bottom: none !important;
|
|
161
|
+
padding: 0 1rem !important;
|
|
162
|
+
border-bottom: 0.0625rem solid #e6e7e8;
|
|
159
163
|
margin: 0 !important;
|
|
160
|
-
background-color: @accordionMenuItemBackground;
|
|
161
164
|
|
|
162
165
|
.icon {
|
|
163
166
|
margin: 0 !important;
|
|
@@ -174,7 +177,58 @@
|
|
|
174
177
|
}
|
|
175
178
|
}
|
|
176
179
|
|
|
180
|
+
.RRT__tab:not(.active) .icon {
|
|
181
|
+
color: #808285;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
&.theme-primary {
|
|
185
|
+
.ui.item:not(.active):hover {
|
|
186
|
+
color: @primaryColor !important;
|
|
187
|
+
|
|
188
|
+
.icon {
|
|
189
|
+
color: @primaryColor !important;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.ui.item.active {
|
|
194
|
+
background-color: @primaryColor !important;
|
|
195
|
+
color: #fff !important;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
&.theme-secondary {
|
|
200
|
+
.ui.item:not(.active):hover {
|
|
201
|
+
color: @secondaryColor !important;
|
|
202
|
+
|
|
203
|
+
.icon {
|
|
204
|
+
color: @secondaryColor !important;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.ui.item.active {
|
|
209
|
+
background-color: @secondaryColor !important;
|
|
210
|
+
color: #fff !important;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
&.theme-tertiary {
|
|
215
|
+
.ui.item:not(.active):hover {
|
|
216
|
+
color: @tertiaryColor !important;
|
|
217
|
+
|
|
218
|
+
.icon {
|
|
219
|
+
color: @tertiaryColor !important;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.ui.item.active {
|
|
224
|
+
background-color: @tertiaryColor !important;
|
|
225
|
+
color: #fff !important;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
177
229
|
&.red {
|
|
230
|
+
color: @red !important;
|
|
231
|
+
|
|
178
232
|
.ui.item.active {
|
|
179
233
|
background-color: @red !important;
|
|
180
234
|
color: #fff !important;
|
|
@@ -182,6 +236,10 @@
|
|
|
182
236
|
}
|
|
183
237
|
|
|
184
238
|
&.orange {
|
|
239
|
+
.ui.item:hover {
|
|
240
|
+
color: @orange !important;
|
|
241
|
+
}
|
|
242
|
+
|
|
185
243
|
.ui.item.active {
|
|
186
244
|
background-color: @orange !important;
|
|
187
245
|
color: #fff !important;
|
|
@@ -189,6 +247,10 @@
|
|
|
189
247
|
}
|
|
190
248
|
|
|
191
249
|
&.yellow {
|
|
250
|
+
.ui.item:hover {
|
|
251
|
+
color: @yellow !important;
|
|
252
|
+
}
|
|
253
|
+
|
|
192
254
|
.ui.item.active {
|
|
193
255
|
background-color: @yellow !important;
|
|
194
256
|
color: #fff !important;
|
|
@@ -196,6 +258,10 @@
|
|
|
196
258
|
}
|
|
197
259
|
|
|
198
260
|
&.olive {
|
|
261
|
+
.ui.item:hover {
|
|
262
|
+
color: @olive !important;
|
|
263
|
+
}
|
|
264
|
+
|
|
199
265
|
.ui.item.active {
|
|
200
266
|
background-color: @olive !important;
|
|
201
267
|
color: #fff !important;
|
|
@@ -203,6 +269,10 @@
|
|
|
203
269
|
}
|
|
204
270
|
|
|
205
271
|
&.green {
|
|
272
|
+
.ui.item:hover {
|
|
273
|
+
color: @green !important;
|
|
274
|
+
}
|
|
275
|
+
|
|
206
276
|
.ui.item.active {
|
|
207
277
|
background-color: @green !important;
|
|
208
278
|
color: #fff !important;
|
|
@@ -210,6 +280,10 @@
|
|
|
210
280
|
}
|
|
211
281
|
|
|
212
282
|
&.teal {
|
|
283
|
+
.ui.item:hover {
|
|
284
|
+
color: @teal !important;
|
|
285
|
+
}
|
|
286
|
+
|
|
213
287
|
.ui.item.active {
|
|
214
288
|
background-color: @teal !important;
|
|
215
289
|
color: #fff !important;
|
|
@@ -217,6 +291,10 @@
|
|
|
217
291
|
}
|
|
218
292
|
|
|
219
293
|
&.blue {
|
|
294
|
+
.ui.item:hover {
|
|
295
|
+
color: @blue !important;
|
|
296
|
+
}
|
|
297
|
+
|
|
220
298
|
.ui.item.active {
|
|
221
299
|
background-color: @blue !important;
|
|
222
300
|
color: #fff !important;
|
|
@@ -224,6 +302,10 @@
|
|
|
224
302
|
}
|
|
225
303
|
|
|
226
304
|
&.violet {
|
|
305
|
+
.ui.item:hover {
|
|
306
|
+
color: @violet !important;
|
|
307
|
+
}
|
|
308
|
+
|
|
227
309
|
.ui.item.active {
|
|
228
310
|
background-color: @violet !important;
|
|
229
311
|
color: #fff !important;
|
|
@@ -231,6 +313,10 @@
|
|
|
231
313
|
}
|
|
232
314
|
|
|
233
315
|
&.purple {
|
|
316
|
+
.ui.item:hover {
|
|
317
|
+
color: @purple !important;
|
|
318
|
+
}
|
|
319
|
+
|
|
234
320
|
.ui.item.active {
|
|
235
321
|
background-color: @purple !important;
|
|
236
322
|
color: #fff !important;
|
|
@@ -238,6 +324,10 @@
|
|
|
238
324
|
}
|
|
239
325
|
|
|
240
326
|
&.brown {
|
|
327
|
+
.ui.item:hover {
|
|
328
|
+
color: @brown !important;
|
|
329
|
+
}
|
|
330
|
+
|
|
241
331
|
.ui.item.active {
|
|
242
332
|
background-color: @brown !important;
|
|
243
333
|
color: #fff !important;
|
|
@@ -245,6 +335,10 @@
|
|
|
245
335
|
}
|
|
246
336
|
|
|
247
337
|
&.grey {
|
|
338
|
+
.ui.item:hover {
|
|
339
|
+
color: @grey !important;
|
|
340
|
+
}
|
|
341
|
+
|
|
248
342
|
.ui.item.active {
|
|
249
343
|
background-color: @grey !important;
|
|
250
344
|
color: #fff !important;
|
|
@@ -252,6 +346,10 @@
|
|
|
252
346
|
}
|
|
253
347
|
|
|
254
348
|
&.black {
|
|
349
|
+
.ui.item:hover {
|
|
350
|
+
color: @black !important;
|
|
351
|
+
}
|
|
352
|
+
|
|
255
353
|
.ui.item.active {
|
|
256
354
|
background-color: @black !important;
|
|
257
355
|
color: #fff !important;
|
|
@@ -266,4 +364,70 @@
|
|
|
266
364
|
}
|
|
267
365
|
}
|
|
268
366
|
|
|
367
|
+
.ui.menu.RRT__tabs {
|
|
368
|
+
.item.ui {
|
|
369
|
+
color: #323232;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
&.theme-primary {
|
|
373
|
+
.item.ui:hover {
|
|
374
|
+
color: @primaryColor !important;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
.item.ui.active {
|
|
378
|
+
border-bottom: 0.1875rem solid @primaryColor !important;
|
|
379
|
+
color: @primaryColor !important;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
&.theme-secondary {
|
|
384
|
+
.item.ui:hover {
|
|
385
|
+
color: @secondaryColor !important;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
.item.ui.active {
|
|
389
|
+
border-bottom: 0.1875rem solid @secondaryColor !important;
|
|
390
|
+
color: @secondaryColor !important;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
&.theme-tertiary {
|
|
395
|
+
.item.ui:hover {
|
|
396
|
+
color: @tertiaryColor !important;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
.ui.item.active {
|
|
400
|
+
border-bottom: 0.1875rem solid @tertiaryColor !important;
|
|
401
|
+
color: @tertiaryColor !important;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
.tabs-block {
|
|
407
|
+
.theme-primary {
|
|
408
|
+
.active.item {
|
|
409
|
+
border-bottom: 0.1875rem solid @primaryColor !important;
|
|
410
|
+
color: @primaryColor !important;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
.theme-secondary {
|
|
415
|
+
.active.item {
|
|
416
|
+
border-bottom: 0.1875rem solid @secondaryColor !important;
|
|
417
|
+
color: @secondaryColor !important;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
.theme-tertiary {
|
|
422
|
+
.active.item {
|
|
423
|
+
border-bottom: 0.1875rem solid @tertiaryColor !important;
|
|
424
|
+
color: @tertiaryColor !important;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// .tabs-block .ui.menu.RRT__accordion .ui.item .icon {
|
|
430
|
+
// color: #808285;
|
|
431
|
+
// }
|
|
432
|
+
|
|
269
433
|
.loadAddonOverrides();
|
package/src/less/menu.variables
CHANGED
package/src/less/tabs.less
CHANGED
|
@@ -7,6 +7,31 @@
|
|
|
7
7
|
.loadAddonVariables();
|
|
8
8
|
|
|
9
9
|
.tabs-block {
|
|
10
|
+
.tabs-accessibility {
|
|
11
|
+
.ui.button.item:focus-visible {
|
|
12
|
+
outline: 1px dotted #212121 !important;
|
|
13
|
+
outline: 5px auto -webkit-focus-ring-color !important;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
a:focus-visible {
|
|
17
|
+
outline: 1px dotted #212121 !important;
|
|
18
|
+
outline: 5px auto -webkit-focus-ring-color !important;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.slick-current:focus-visible {
|
|
22
|
+
outline: 1px dotted #212121 !important;
|
|
23
|
+
outline: 5px auto -webkit-focus-ring-color !important;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.accessibility-accordion-tab {
|
|
27
|
+
outline: none;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.accessibility-accordion-tab:focus-visible {
|
|
31
|
+
outline: 1px dotted #212121 !important;
|
|
32
|
+
outline: 5px auto -webkit-focus-ring-color !important;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
10
35
|
color: @tabsBlockColor;
|
|
11
36
|
|
|
12
37
|
> .styled {
|