Skip to content
This repository was archived by the owner on May 24, 2024. It is now read-only.

Commit 52332e9

Browse files
authored
Adding MainContainer, ActiveMainContext, and related files (#195)
* Introducing SkipToLinks to the ApplicationContainer. * Adding wdio tests * Adding CHANGELOG entry * Adding newlines * Copying files from integration branch * Updating implementation to be more straightforward. * Final API updates. Adding tests. * Adding node version range * Working around flaky tests * Removing unnecessary default * Adding comment
1 parent 016ec34 commit 52332e9

File tree

87 files changed

+792
-77
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

87 files changed

+792
-77
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
* Adding SessionContext
1111
* ApplicationBase updates
1212
* Adding SkipToLink
13+
* Adding MainContainer
1314

1415
## Unreleased
1516

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"version": "1.35.0",
88
"description": "A framework to support application development with Terra components",
99
"engines": {
10-
"node": ">=10"
10+
"node": ">=10 <13"
1111
},
1212
"repository": {
1313
"type": "git",
@@ -104,7 +104,6 @@
104104
"terra-slide-panel-manager": "^5.19.0",
105105
"terra-status-view": "^4.10.0",
106106
"terra-theme-context": "^1.0.0",
107-
"terra-theme-provider": "^4.0.0",
108107
"terra-toolbar": "^1.20.0",
109108
"terra-visually-hidden-text": "^2.30.0",
110109
"uuid": "^3.0.0",

src/application-container/ApplicationContainer.jsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import classNames from 'classnames/bind';
44

55
import { NavigationPromptCheckpoint } from '../navigation-prompt';
66
import WindowManager from '../utils/window-manager';
7+
import ActiveMainProvider from '../main-container/private/ActiveMainProvider';
78

89
import ApplicationContainerErrorBoundary from './private/ApplicationContainerErrorBoundary';
910
import useSkipToLinks from './private/skip-to-links/useSkipToLinks';
@@ -63,9 +64,11 @@ const ApplicationContainer = ({
6364
<div className={cx('application-container')} data-testid="application-container">
6465
<SkipToLinks />
6566
<SkipToLinksProvider>
66-
<ApplicationContainerErrorBoundary>
67-
{children}
68-
</ApplicationContainerErrorBoundary>
67+
<ActiveMainProvider>
68+
<ApplicationContainerErrorBoundary>
69+
{children}
70+
</ApplicationContainerErrorBoundary>
71+
</ActiveMainProvider>
6972
</SkipToLinksProvider>
7073
</div>
7174
</NavigationPromptCheckpoint>

src/application-container/index.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import ApplicationContainer from './ApplicationContainer';
2-
import useActiveMainPage from './useActiveMainPage';
32
import ApplicationContainerContext, {
43
useApplicationContainer,
54
contextShape as applicationContainerContextShape,
@@ -11,7 +10,6 @@ import ApplicationConceptContext, {
1110

1211
export default ApplicationContainer;
1312
export {
14-
useActiveMainPage,
1513
ApplicationContainerContext,
1614
useApplicationContainer,
1715
applicationContainerContextShape,

src/application-container/private/active-main-page/ActiveMainPageContext.jsx

Lines changed: 0 additions & 14 deletions
This file was deleted.

src/application-container/useActiveMainPage.jsx

Lines changed: 0 additions & 11 deletions
This file was deleted.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
4+
/**
5+
* The ActiveMainContext is used to communicate data related to the current
6+
* active main content to the application.
7+
*/
8+
const ActiveMainContext = React.createContext({});
9+
10+
/**
11+
* Hook to simplify consumption of the ActiveMainContext.
12+
* @returns The ActiveMainContext value found at the consuming render location.
13+
*/
14+
const useActiveMain = () => React.useContext(ActiveMainContext);
15+
16+
const contextShape = {
17+
/**
18+
* The string label describing the active main content to be used for display purposes.
19+
*/
20+
label: PropTypes.string,
21+
/**
22+
* A collection of data related to the active main content.
23+
*/
24+
metaData: PropTypes.object,
25+
};
26+
27+
export default ActiveMainContext;
28+
export { useActiveMain, contextShape };

src/main-container/MainContainer.jsx

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

src/main-container/index.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import MainContainer from './MainContainer';
2+
import ActiveMainContext, {
3+
useActiveMain,
4+
contextShape as activeMainContextShape,
5+
} from './ActiveMainContext';
6+
7+
export default MainContainer;
8+
export { ActiveMainContext, useActiveMain, activeMainContextShape };

0 commit comments

Comments
 (0)