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

Commit a8cb77a

Browse files
author
george
committed
Merge branch 'develop'
2 parents e37113e + 5089d7f commit a8cb77a

File tree

40 files changed

+542
-739
lines changed

40 files changed

+542
-739
lines changed

app/components/Article/Article.js

Lines changed: 27 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,40 @@
1-
import React from "react"
1+
import React, { useState, useEffect } from "react"
22
import Markdown from "react-markdown"
33
import Prism from "prismjs"
4-
import Undernet from "undernet"
54
import classNames from "classnames"
65
import PropTypes from "prop-types"
76

7+
import { COMPONENTS } from "./constants"
88
import ScrollUpOnMount from "app/components/ScrollUpOnMount"
99

10-
export default class Article extends React.Component {
11-
constructor() {
12-
super()
10+
export default function Article(props) {
11+
const [domIsLoaded, setDomIsLoaded] = useState(false)
1312

14-
this.state = {
15-
domIsLoaded: false,
16-
}
13+
const componentUnmountFunction = () => {
14+
COMPONENTS.forEach(Component => Component.stop())
1715
}
1816

19-
COMPONENTS = ["Tooltips", "Accordions", "Modals", "Dropdowns"]
20-
21-
static propTypes = {
22-
children: PropTypes.any,
23-
}
24-
25-
componentDidMount() {
17+
const onMountOnly = []
18+
useEffect(() => {
2619
Prism.highlightAll()
20+
COMPONENTS.forEach(Component => Component.start())
21+
setDomIsLoaded(true)
22+
23+
return componentUnmountFunction
24+
}, onMountOnly)
25+
26+
return (
27+
<article
28+
className={classNames("article-wrapper has-no-padding column", {
29+
fadeIn: domIsLoaded,
30+
})}
31+
>
32+
<ScrollUpOnMount />
33+
<Markdown source={props.children} escapeHtml={false} />
34+
</article>
35+
)
36+
}
2737

28-
// initialize all Undernet components
29-
// DO NOT init focus outline - it is set up in layouts/Main
30-
this.COMPONENTS.forEach(component => Undernet[component].start())
31-
32-
this.setState({ domIsLoaded: true })
33-
}
34-
35-
componentWillUnmount() {
36-
this.COMPONENTS.forEach(component => Undernet[component].stop())
37-
}
38-
39-
render() {
40-
return (
41-
<article
42-
className={classNames("article-wrapper has-no-padding column", {
43-
fadeIn: this.state.domIsLoaded,
44-
})}
45-
>
46-
<ScrollUpOnMount />
47-
<Markdown source={this.props.children} escapeHtml={false} />
48-
</article>
49-
)
50-
}
38+
Article.propTypes = {
39+
children: PropTypes.string.isRequired,
5140
}

app/components/Article/__tests__/Article.spec.js

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
import React from "react"
22
import Article from "../Article"
3-
import Undernet from "undernet"
43
import Prism from "prismjs"
4+
import { COMPONENTS } from "../constants"
55

66
jest.mock("app/components/ScrollUpOnMount", () => global.simpleMock("ScrollUpOnMount"))
77

88
global.scrollTo = jest.fn()
99

10-
const components = ["Tooltips", "Accordions", "Modals", "Dropdowns"]
11-
12-
components.forEach(component => {
13-
Undernet[component].start = jest.fn()
14-
Undernet[component].stop = jest.fn()
10+
COMPONENTS.forEach(Component => {
11+
Component.start = jest.fn()
12+
Component.stop = jest.fn()
1513
})
1614

1715
jest.mock("prismjs", () => ({
@@ -52,25 +50,25 @@ describe("<Article />", () => {
5250
expect(Prism.highlightAll).toHaveBeenCalled()
5351
})
5452

55-
components.forEach(component => {
56-
it(`calls Undernet.${component}.start`, () => {
53+
COMPONENTS.forEach(Component => {
54+
it(`calls ${Component}.start`, () => {
5755
// Given
5856
mountComponent()
5957
// Then
60-
expect(Undernet[component].start).toHaveBeenCalled()
58+
expect(Component.start).toHaveBeenCalled()
6159
})
6260
})
6361
})
6462

6563
describe("#componentWillUnmount", () => {
66-
components.forEach(component => {
67-
it(`calls Undernet.${component}.stop`, () => {
64+
COMPONENTS.forEach(Component => {
65+
it(`calls ${Component}.stop`, () => {
6866
// Given
6967
const wrapper = mountComponent()
7068
// When
7169
wrapper.unmount()
7270
// Then
73-
expect(Undernet[component].stop).toHaveBeenCalled()
71+
expect(Component.stop).toHaveBeenCalled()
7472
})
7573
})
7674
})
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { Tooltips, Accordions, Modals, Dropdowns } from "undernet"
2+
3+
export const COMPONENTS = [Tooltips, Accordions, Modals, Dropdowns]

app/components/Footer/Footer.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ import PropTypes from "prop-types"
66
import "./styles.scss"
77

88
export default function Footer(props) {
9+
const handleClick = event => {
10+
event.preventDefault()
11+
props.handleRefocusClick(props.headerRef)
12+
}
13+
914
return (
1015
<div className="footer-wrapper small-section fluid grid">
1116
<div className="row">
@@ -50,8 +55,9 @@ export default function Footer(props) {
5055
<li role="none">
5156
<button
5257
className="is-visually-hidden-focusable"
53-
onClick={props.handleHeaderFocusClick}
58+
onClick={handleClick}
5459
role="listitem"
60+
type="button"
5561
>
5662
Return to top of page
5763
</button>
@@ -64,5 +70,8 @@ export default function Footer(props) {
6470
}
6571

6672
Footer.propTypes = {
67-
handleHeaderFocusClick: PropTypes.func.isRequired,
73+
handleRefocusClick: PropTypes.func.isRequired,
74+
headerRef: PropTypes.shape({
75+
current: PropTypes.instanceOf(Element),
76+
}),
6877
}

app/components/Footer/__tests__/Footer.spec.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ jest.mock("react-feather/dist/icons/github", () => global.simpleMock("Github"))
66

77
describe("<Footer />", () => {
88
const baseProps = {
9-
handleHeaderFocusClick: jest.fn(),
9+
handleRefocusClick: jest.fn(),
10+
headerRef: {
11+
current: document.createElement("header"),
12+
},
1013
}
1114

1215
const mountComponent = () => {
@@ -20,12 +23,12 @@ describe("<Footer />", () => {
2023
expect(wrapper).toMatchSnapshot()
2124
})
2225

23-
it("calls handleHeaderFocusClick prop when hidden button is clicked", () => {
26+
it("calls handleRefocusClick prop when hidden button is clicked", () => {
2427
// Given
2528
const wrapper = mountComponent()
2629
// When
2730
wrapper.find(".is-visually-hidden-focusable").simulate("click")
2831
// Then
29-
expect(baseProps.handleHeaderFocusClick).toHaveBeenCalled()
32+
expect(baseProps.handleRefocusClick).toHaveBeenCalledWith(baseProps.headerRef)
3033
})
3134
})

app/components/Footer/__tests__/__snapshots__/Footer.spec.js.snap

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@
22

33
exports[`<Footer /> renders 1`] = `
44
<Footer
5-
handleHeaderFocusClick={[MockFunction]}
5+
handleRefocusClick={[MockFunction]}
6+
headerRef={
7+
Object {
8+
"current": <header />,
9+
}
10+
}
611
>
712
<div
813
className="footer-wrapper small-section fluid grid"
@@ -85,8 +90,9 @@ exports[`<Footer /> renders 1`] = `
8590
>
8691
<button
8792
className="is-visually-hidden-focusable"
88-
onClick={[MockFunction]}
93+
onClick={[Function]}
8994
role="listitem"
95+
type="button"
9096
>
9197
Return to top of page
9298
</button>

app/components/GlobalNav/GlobalNav.js

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,27 @@ import Logo from "app/assets/images/un-logo.png"
99
import "./styles.scss"
1010

1111
export default function GlobalNav(props) {
12+
const handleClick = event => {
13+
event.preventDefault()
14+
props.handleRefocusClick(props.mainRef)
15+
}
16+
1217
return (
1318
<nav id="global-nav" className="fluid grid">
1419
<ul className="nav-list row has-no-padding">
1520
<li className="small-5 xsmall-12 columns" role="none">
16-
<Link to="/" className="logo">
21+
<Link to="/" className="logo" role="listitem">
1722
<img src={Logo} alt="Undernet" />
1823
</Link>
1924
</li>
20-
<li className="small-7 xsmall-12 columns" role="none">
25+
<li className="small-7 xsmall-12 columns">
2126
<ul className="row">
2227
<li role="none">
2328
<button
2429
role="listitem"
2530
className="is-visually-hidden-focusable"
26-
onClick={props.handleMainFocusClick}
31+
onClick={handleClick}
32+
type="button"
2733
>
2834
Skip to main content
2935
</button>
@@ -47,9 +53,9 @@ export default function GlobalNav(props) {
4753
</a>
4854
</li>
4955
<li role="none">
50-
<Link to={introductionPath} role="listitem">
56+
<a href={introductionPath} role="listitem">
5157
Documentation
52-
</Link>
58+
</a>
5359
</li>
5460
</ul>
5561
</li>
@@ -59,5 +65,8 @@ export default function GlobalNav(props) {
5965
}
6066

6167
GlobalNav.propTypes = {
62-
handleMainFocusClick: PropTypes.func.isRequired,
68+
handleRefocusClick: PropTypes.func.isRequired,
69+
mainRef: PropTypes.shape({
70+
current: PropTypes.instanceOf(Element),
71+
}),
6372
}

app/components/GlobalNav/__tests__/GlobalNav.spec.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ import { BrowserRouter as Router } from "react-router-dom"
44

55
describe("<Nav />", () => {
66
const baseProps = {
7-
handleMainFocusClick: jest.fn(),
7+
handleRefocusClick: jest.fn(),
8+
mainRef: {
9+
current: document.createElement("main"),
10+
},
811
}
912

1013
const mountComponent = () => {
@@ -22,12 +25,12 @@ describe("<Nav />", () => {
2225
expect(wrapper).toMatchSnapshot()
2326
})
2427

25-
it("calls handleMainFocusClick prop when hidden button is clicked", () => {
28+
it("calls handleRefocusClick prop when hidden button is clicked", () => {
2629
// Given
2730
const wrapper = mountComponent()
2831
// When
2932
wrapper.find(".is-visually-hidden-focusable").simulate("click")
3033
// Then
31-
expect(baseProps.handleMainFocusClick).toHaveBeenCalled()
34+
expect(baseProps.handleRefocusClick).toHaveBeenCalledWith(baseProps.mainRef)
3235
})
3336
})

app/components/GlobalNav/__tests__/__snapshots__/GlobalNav.spec.js.snap

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,12 @@ exports[`<Nav /> renders 1`] = `
2525
}
2626
>
2727
<GlobalNav
28-
handleMainFocusClick={[MockFunction]}
28+
handleRefocusClick={[MockFunction]}
29+
mainRef={
30+
Object {
31+
"current": <main />,
32+
}
33+
}
2934
>
3035
<nav
3136
className="fluid grid"
@@ -40,12 +45,14 @@ exports[`<Nav /> renders 1`] = `
4045
>
4146
<Link
4247
className="logo"
48+
role="listitem"
4349
to="/"
4450
>
4551
<a
4652
className="logo"
4753
href="/"
4854
onClick={[Function]}
55+
role="listitem"
4956
>
5057
<img
5158
alt="Undernet"
@@ -56,7 +63,6 @@ exports[`<Nav /> renders 1`] = `
5663
</li>
5764
<li
5865
className="small-7 xsmall-12 columns"
59-
role="none"
6066
>
6167
<ul
6268
className="row"
@@ -66,8 +72,9 @@ exports[`<Nav /> renders 1`] = `
6672
>
6773
<button
6874
className="is-visually-hidden-focusable"
69-
onClick={[MockFunction]}
75+
onClick={[Function]}
7076
role="listitem"
77+
type="button"
7178
>
7279
Skip to main content
7380
</button>
@@ -153,18 +160,12 @@ exports[`<Nav /> renders 1`] = `
153160
<li
154161
role="none"
155162
>
156-
<Link
163+
<a
164+
href="/docs/overview/introduction"
157165
role="listitem"
158-
to="/docs/overview/introduction"
159166
>
160-
<a
161-
href="/docs/overview/introduction"
162-
onClick={[Function]}
163-
role="listitem"
164-
>
165-
Documentation
166-
</a>
167-
</Link>
167+
Documentation
168+
</a>
168169
</li>
169170
</ul>
170171
</li>

0 commit comments

Comments
 (0)