This repository has been archived by the owner on May 24, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 13
/
MainContainer.jsx
105 lines (92 loc) · 3.13 KB
/
MainContainer.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import classNamesBind from 'classnames/bind';
import { ApplicationIntlContext } from '../application-intl';
import SkipToLink from '../application-container/private/skip-to-links/SkipToLink';
import NavigationItemContext from '../navigation-item/NavigationItemContext';
import ActiveMainRegistrationContext from './private/ActiveMainRegistrationContext';
import styles from './MainContainer.module.scss';
const cx = classNamesBind.bind(styles);
const propTypes = {
/**
* The elements to render within the main element.
*/
children: PropTypes.node,
/**
* A string label describing the content within the main element. This value
* will be applied to the element as a user-facing aria-label and should be
* translated, if necessary. It will also be provided to consumers of the
* ActiveMainContext when this element is active.
*/
label: PropTypes.string.isRequired,
/**
* An object containing meta data related to the main element. This data is
* provided to consumers of the ActiveMainContext to provide additional
* information regarding the active main content.
*/
metaData: PropTypes.object,
/**
* A function to be called when a ref has been assigned for the created
* `<main>` element.
*/
refCallback: PropTypes.func,
};
/**
* The MainContainer can be used to create a semantic `<main>` element for the
* application, within which the application's most important and dynamic
* content will reside. A SkipToLink will be registered automatically to ensure
* this content can be accessed quickly.
*/
const MainContainer = ({
children, refCallback, label, metaData, ...otherProps
}) => {
const applicationIntl = React.useContext(ApplicationIntlContext);
const activeMainRegistration = React.useContext(ActiveMainRegistrationContext);
const navigationItem = React.useContext(NavigationItemContext);
const mainElementRef = React.useRef();
const unregisterActiveMainRef = React.useRef();
React.useEffect(() => {
unregisterActiveMainRef.current = activeMainRegistration.register({
label,
metaData,
});
}, [
activeMainRegistration,
label,
metaData,
navigationItem.isActive,
navigationItem.navigationKeys,
]);
React.useEffect(() => () => {
// A separate effect is used to unregister the active main when it is
// unmounted to limit registration thrash on updates to props.
unregisterActiveMainRef.current();
}, []);
return (
<main
aria-label={label}
className={classNames(cx('main-container'), otherProps.className)}
tabIndex="-1"
ref={(mainRef) => {
mainElementRef.current = mainRef;
if (refCallback) {
refCallback(mainRef);
}
}}
{...otherProps}
>
<SkipToLink
description={applicationIntl.formatMessage({
id: 'terraApplication.mainContainer.skipToLabel',
})}
onSelect={() => {
mainElementRef.current.focus();
}}
/>
{children}
</main>
);
};
MainContainer.propTypes = propTypes;
export default MainContainer;