@financial-times/dotcom-ui-header 2.6.0

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.
Files changed (32) hide show
  1. package/README.md +125 -0
  2. package/bower.json +9 -0
  3. package/browser.js +25 -0
  4. package/component.js +1 -0
  5. package/dist/node/components/drawer/additionalPartials.js +36 -0
  6. package/dist/node/components/drawer/topLevelPartials.js +56 -0
  7. package/dist/node/components/navigation/partials.js +83 -0
  8. package/dist/node/components/search/partials.js +20 -0
  9. package/dist/node/components/sticky/partials.js +59 -0
  10. package/dist/node/components/sub-navigation/partials.js +36 -0
  11. package/dist/node/components/svg-components/BrandFtMasthead.js +11 -0
  12. package/dist/node/components/top/partials.js +35 -0
  13. package/dist/node/index.js +78 -0
  14. package/dist/node/utils.js +6 -0
  15. package/package.json +44 -0
  16. package/screenshots/header-navigation.png +0 -0
  17. package/screenshots/header-sub-navigation.png +0 -0
  18. package/screenshots/header-top-search.png +0 -0
  19. package/scripts/convertSvgsToReactComponents.js +23 -0
  20. package/src/components/drawer/additionalPartials.tsx +97 -0
  21. package/src/components/drawer/topLevelPartials.tsx +153 -0
  22. package/src/components/navigation/partials.tsx +212 -0
  23. package/src/components/search/partials.tsx +52 -0
  24. package/src/components/sticky/partials.tsx +137 -0
  25. package/src/components/sub-navigation/partials.tsx +101 -0
  26. package/src/components/svg-components/BrandFtMasthead.tsx +16 -0
  27. package/src/components/top/partials.tsx +90 -0
  28. package/src/header.scss +29 -0
  29. package/src/index.tsx +123 -0
  30. package/src/interfaces.d.ts +18 -0
  31. package/src/utils.ts +5 -0
  32. package/styles.scss +14 -0
@@ -0,0 +1,137 @@
1
+ /* WARN: This file looks similar to ../top/partials */
2
+ /* This is the sticky header variant */
3
+
4
+ import React from 'react'
5
+ import { NavListRightAnon } from '../navigation/partials'
6
+ import { THeaderProps } from '../../interfaces'
7
+
8
+ const StickyHeaderWrapper = (props: THeaderProps & { children: React.ReactNode }) => (
9
+ <header
10
+ className={`o-header o-header--simple o-header--sticky o--if-js`}
11
+ data-o-component="o-header"
12
+ data-o-header--sticky
13
+ aria-hidden="true">
14
+ {props.children}
15
+ </header>
16
+ )
17
+
18
+ const DrawerIconSticky = () => (
19
+ <a
20
+ href="#"
21
+ className="o-header__top-link o-header__top-link--menu"
22
+ aria-controls="o-header-drawer"
23
+ data-trackable="drawer-toggle"
24
+ tabIndex={-1}>
25
+ <span className="o-header__top-link-label">Menu</span>
26
+ </a>
27
+ )
28
+
29
+ const SearchIconSticky = () => (
30
+ <a
31
+ href="#"
32
+ className="o-header__top-link o-header__top-link--search"
33
+ aria-controls="o-header-search-sticky"
34
+ data-trackable="search-toggle"
35
+ tabIndex={-1}>
36
+ <span className="o-header__top-link-label">Search</span>
37
+ </a>
38
+ )
39
+
40
+ const Navigation = (props: THeaderProps) => (
41
+ <div className="o-header__top-takeover">
42
+ <div className="o-header__nav">
43
+ <ul className="o-header__nav-list o-header__nav-list--left" data-trackable="primary-nav">
44
+ {props.data.navbar.items.map((item, index) => (
45
+ <li className="o-header__nav-item" key={`link-${index}`}>
46
+ <a
47
+ className="o-header__nav-link o-header__nav-link--primary"
48
+ href={item.url}
49
+ data-trackable={item.label}
50
+ tabIndex={-1}>
51
+ {item.label}
52
+ </a>
53
+ </li>
54
+ ))}
55
+ </ul>
56
+ </div>
57
+ </div>
58
+ )
59
+
60
+ const Logo = () => (
61
+ <a
62
+ className="o-header__top-logo o-header__hide--L"
63
+ data-trackable="logo"
64
+ href="/"
65
+ title="Go to Financial Times homepage"
66
+ tabIndex={-1}>
67
+ <span className="o-header__visually-hidden">Financial Times</span>
68
+ </a>
69
+ )
70
+
71
+ const NavListRightAnonSticky = (props: THeaderProps) => {
72
+ const navbarItems = props.data['navbar-right-anon'].items
73
+
74
+ return (
75
+ <div className="o-header__nav">
76
+ <NavListRightAnon items={navbarItems} variant="sticky" />
77
+ </div>
78
+ )
79
+ }
80
+
81
+ const MyFtSticky = () => (
82
+ <a
83
+ className="o-header__top-link o-header__top-link--myft"
84
+ href="/myft"
85
+ data-trackable="my-ft"
86
+ tabIndex={-1}>
87
+ <span className="o-header__visually-hidden">myFT</span>
88
+ </a>
89
+ )
90
+
91
+ const TopWrapperSticky = (props) => (
92
+ <div className="o-header__row o-header__top" data-trackable="header-sticky">
93
+ <div className="o-header__container">
94
+ <div className="o-header__top-wrapper">{props.children}</div>
95
+ </div>
96
+ </div>
97
+ )
98
+
99
+ const TopColumnLeftSticky = () => {
100
+ return (
101
+ <div className="o-header__top-column o-header__top-column--left">
102
+ <DrawerIconSticky />
103
+ <SearchIconSticky />
104
+ </div>
105
+ )
106
+ }
107
+ const TopColumnCenterSticky = (props: THeaderProps) => {
108
+ return (
109
+ <div className="o-header__top-column o-header__top-column--center">
110
+ <Navigation {...props} />
111
+ <Logo />
112
+ </div>
113
+ )
114
+ }
115
+
116
+ // This behaviour is similar to `NavListRight` in '../navigation/partials' but:
117
+ // - The sticky header renders either the `navbar-right-anon` data or the myFT component
118
+ // - The normal header renders either the `navbar-right-anon` or the `navbar-right` data
119
+ const TopColumnRightSticky = (props: THeaderProps) => {
120
+ let children = null
121
+
122
+ if (props.userIsLoggedIn) {
123
+ children = <MyFtSticky />
124
+ } else if (props.showUserNavigation) {
125
+ children = <NavListRightAnonSticky {...props} />
126
+ }
127
+
128
+ return <div className="o-header__top-column o-header__top-column--right">{children}</div>
129
+ }
130
+
131
+ export {
132
+ StickyHeaderWrapper,
133
+ TopWrapperSticky,
134
+ TopColumnLeftSticky,
135
+ TopColumnCenterSticky,
136
+ TopColumnRightSticky
137
+ }
@@ -0,0 +1,101 @@
1
+ import React from 'react'
2
+ import { ariaSelected } from '../../utils'
3
+ import { THeaderProps } from '../../interfaces'
4
+ import { TNavMenuItem } from '@financial-times/dotcom-types-navigation'
5
+
6
+ const SubNavigation = (props: THeaderProps) => (
7
+ <SubNavigationWrapper>
8
+ <BreadCrumb items={props.data.breadcrumb} />
9
+ <SubSections items={props.data.subsections} />
10
+ <SubSections items={props.data['subsections-right']} rightAlignment={true} />
11
+ </SubNavigationWrapper>
12
+ )
13
+
14
+ const SubNavigationWrapper = (props) => (
15
+ <div
16
+ className="o-header__subnav"
17
+ role="navigation"
18
+ aria-label="Sub navigation"
19
+ data-o-header-subnav
20
+ data-trackable="header-subnav">
21
+ <div className="o-header__container">
22
+ <div className="o-header__subnav-wrap-outside">
23
+ <div className="o-header__subnav-wrap-inside" data-o-header-subnav-wrapper>
24
+ <div className="o-header__subnav-content">{props.children}</div>
25
+ </div>
26
+ {/* Implements subNavigation scrolling at smaller viewports */}
27
+ <button
28
+ className="o-header__subnav-button o-header__subnav-button--left"
29
+ title="scroll left"
30
+ aria-label="scroll left"
31
+ aria-hidden="true"
32
+ disabled
33
+ />
34
+ <button
35
+ className="o-header__subnav-button o-header__subnav-button--right"
36
+ title="scroll right"
37
+ aria-label="scroll right"
38
+ aria-hidden="true"
39
+ disabled
40
+ />
41
+ </div>
42
+ </div>
43
+ </div>
44
+ )
45
+
46
+ const BreadCrumb = ({ items }: { items: TNavMenuItem[] }) => (
47
+ <ol
48
+ className="o-header__subnav-list o-header__subnav-list--breadcrumb"
49
+ aria-label="Breadcrumb"
50
+ data-trackable="breadcrumb">
51
+ {items.map((item, index) => {
52
+ const selected = item.selected ? 'o-header__subnav-link--highlight' : ''
53
+
54
+ return (
55
+ <li className="o-header__subnav-item" key={`item-${index}`}>
56
+ <a
57
+ className={`o-header__subnav-link ${selected}`}
58
+ href={item.url}
59
+ {...ariaSelected(item)}
60
+ data-trackable={item.label}>
61
+ {item.label}
62
+ </a>
63
+ </li>
64
+ )
65
+ })}
66
+ </ol>
67
+ )
68
+
69
+ const SubSections = ({ items, rightAlignment }: { items: TNavMenuItem[]; rightAlignment?: boolean }) => {
70
+ if (!items || items.length === 0) {
71
+ return null
72
+ }
73
+
74
+ return (
75
+ <ul
76
+ className={
77
+ 'o-header__subnav-list o-header__subnav-list--children' +
78
+ (rightAlignment ? ' o-header__subnav-list--right' : '')
79
+ }
80
+ aria-label={rightAlignment ? 'Additional Sub Navigation' : 'Subsections'}
81
+ data-trackable="subsections">
82
+ {items.map((item, index) => {
83
+ const selected = item.selected ? 'o-header__subnav-link--highlight' : ''
84
+
85
+ return (
86
+ <li className="o-header__subnav-item" key={`item-${index}`}>
87
+ <a
88
+ className={`o-header__subnav-link ${selected}`}
89
+ href={item.url}
90
+ {...ariaSelected(item)}
91
+ data-trackable={item.label}>
92
+ {item.label}
93
+ </a>
94
+ </li>
95
+ )
96
+ })}
97
+ </ul>
98
+ )
99
+ }
100
+
101
+ export { SubNavigation }
@@ -0,0 +1,16 @@
1
+ // **THIS IS AN AUTO-GENERATED FILE (`npm run build:svg-to-react`) - DO NOT EDIT MANUALLY.**
2
+
3
+ import React from 'react'
4
+
5
+ const BrandFtMasthead = ({ title, ...props }) => (
6
+ <svg viewBox="0 0 1054 86" {...props}>
7
+ {title === undefined ? <title>{'brand-ft-masthead'}</title> : title ? <title>{title}</title> : null}
8
+ <path
9
+ d="M26.177 72.609c0 5.938 1.697 7.295 12.554 7.295v3.732H.9v-3.732c7.464 0 10.01-.679 10.01-7.125V12.215c0-6.447-2.546-7.126-10.01-7.126V1.357h63.448l.34 22.563h-3.054C59.937 6.956 55.696 5.43 39.919 5.43H26.008v33.59h11.196c10.688 0 11.367-1.697 12.215-10.179h3.054v24.599h-3.054c-.848-8.482-1.527-10.01-12.215-10.01H26.008v29.18h.17zm46.314 11.027v-3.732c7.465 0 10.01-.679 10.01-7.125V12.215c0-6.447-2.545-7.126-10.01-7.126V1.357h35.287V5.09c-7.465 0-10.01.679-10.01 7.126v60.564c0 6.446 2.545 7.125 10.01 7.125v3.732H72.49zm115.36 1.357l-56.323-69.725V72.44c0 6.617 4.58 7.634 12.385 7.634v3.733h-29.858v-3.733c7.803 0 12.045-1.017 12.045-7.634V8.991c-3.563-3.732-6.108-3.902-12.045-3.902V1.357h26.465l43.09 55.475V12.554c0-6.616-4.58-7.634-12.384-7.634V1.357h30.027V5.09c-7.803 0-12.045 1.018-12.045 7.635v72.27h-1.357zm40.207-1.357h-29.689v-3.732c7.804 0 11.367-1.018 13.911-7.804L239.085.509h7.464l28.84 72.1c2.545 6.447 3.732 7.125 9.67 7.125v3.732h-34.438v-3.732c10.518 0 11.536-.848 8.99-7.125l-8.481-21.884h-25.787L217.71 71.93c-2.375 6.447 1.357 7.804 10.518 7.804v3.902h-.17zm-1.188-37.153h22.393l-11.705-29.518-10.688 29.518zm135.548 38.51l-56.153-69.725V72.44c0 6.617 4.58 7.634 12.384 7.634v3.733h-29.18v-3.733c7.126 0 11.367-1.017 11.367-7.634V9.161c-4.071-3.732-7.125-4.072-13.91-4.072V1.357h28.16l43.09 55.475V12.554c0-6.616-4.58-7.634-12.383-7.634V1.357h29.858V5.09c-7.804 0-12.045 1.018-12.045 7.635v72.27h-1.188zm83.297-83.805h2.036l1.187 24.598-3.053.17c-2.036-14.08-9.5-21.545-23.242-21.545-15.268 0-26.804 13.063-26.804 33.081 0 25.617 16.116 40.206 33.08 40.206 7.296 0 13.912-2.035 20.358-8.99l2.376 2.374c-5.26 7.465-15.608 13.742-29.52 13.742-20.696 0-41.732-15.608-41.732-41.734C380.4 17.813 399.57 0 422.813 0c11.027 0 16.795 4.75 19.848 4.75 1.357 0 2.375-1.187 3.054-3.562zm12.723 82.448v-3.732c7.465 0 10.01-.679 10.01-7.125V12.215c0-6.447-2.545-7.126-10.01-7.126V1.357h35.287V5.09c-7.464 0-10.01.679-10.01 7.126v60.564c0 6.446 2.546 7.125 10.01 7.125v3.732h-35.287zm68.538 0h-27.653v-3.732c6.108 0 9.331-1.018 11.876-7.804L538.003.509h7.464l28.84 72.1c2.545 6.447 3.733 7.125 9.67 7.125v3.732H549.54v-3.732c10.518 0 11.536-.848 8.991-7.125l-8.482-21.884h-25.786l-7.635 21.205c-2.375 6.447 1.358 7.804 10.519 7.804v3.902h-.17zm-1.188-37.153h22.394l-11.536-29.518-10.858 29.518zm63.957 37.153v-3.732c7.465 0 10.01-.679 10.01-7.125V12.215c0-6.447-2.545-7.126-10.01-7.126V1.357h35.117V5.09c-7.464 0-9.84.679-9.84 7.126v61.073c0 5.428 2.715 6.107 7.126 6.107h4.241c15.947 0 21.036-2.375 25.447-20.527l3.054.339-2.545 24.26h-62.6v.17zM760.75 1.357l.339 23.92h-3.054C756.34 7.634 752.098 5.43 736.32 5.43h-5.089v67.18c0 6.447 2.375 7.295 12.554 7.295v3.732h-40.376v-3.732c10.179 0 12.723-1.018 12.723-7.295V5.429h-5.089c-15.777 0-20.018 2.205-21.715 19.848h-3.053l.339-23.92h74.136zm7.973 82.28v-3.733c7.465 0 10.01-.679 10.01-7.125V12.215c0-6.447-2.545-7.126-10.01-7.126V1.357h35.287V5.09c-7.465 0-10.01.679-10.01 7.126v60.564c0 6.446 2.545 7.125 10.01 7.125v3.732h-35.287zM910.21 1.356V5.09c-7.465 0-10.688.34-10.01 6.956l6.447 61.073c.679 6.277 3.054 6.955 10.518 6.955v3.733h-35.117v-3.733c7.295 0 9.84-.678 9.331-6.955L884.762 8.99l-25.956 76.172h-1.018L832.34 8.822l-6.108 64.126c-.678 6.447 3.733 7.125 11.197 7.125v3.733h-27.483v-3.733c7.465 0 10.01-1.187 10.518-7.125l6.447-61.073c.679-6.446-2.545-6.955-10.01-6.955V1.357h28.84l17.305 56.153 18.661-56.153h28.5zm65.653 52.082h-3.053c-.849-8.482-1.527-10.01-12.215-10.01H948.04v29.859c0 5.428 2.715 6.107 7.125 6.107h6.786c15.947 0 21.036-2.375 25.447-20.527l3.054.339-2.884 24.26h-64.805v-3.733c7.464 0 10.009-.678 10.009-7.125V12.215c0-6.447-2.545-7.126-10.01-7.126V1.357h62.261l.34 20.527h-3.054c-1.866-14.59-5.598-16.286-21.885-16.286H948.21v33.42h12.554c10.687 0 11.366-1.696 12.214-10.178h3.054v24.599h-.17zm65.484 13.232c0-7.464-4.75-11.196-12.893-15.777l-13.063-6.786c-9.84-5.259-15.607-11.027-15.607-21.375C999.783 9.84 1010.81 0 1025.23 0c9.84 0 14.929 4.75 17.813 4.75 1.866 0 2.714-1.187 3.562-3.562h2.375l1.188 23.072-3.054.17c-1.696-11.198-9.67-19.85-20.866-19.85-8.483 0-14.081 5.09-14.081 12.215 0 7.804 5.937 11.027 12.554 14.59l11.196 5.937c10.519 5.768 17.983 11.536 17.983 22.563 0 14.59-12.554 24.939-28.161 24.939-11.028 0-16.456-5.26-19.34-5.26-1.866 0-2.884 1.697-3.732 4.242h-2.376l-1.696-24.43 3.054-.339c2.375 15.268 12.893 21.545 23.411 21.545 8.822-.17 16.286-4.071 16.286-13.91z"
10
+ fill="#231F20"
11
+ fillRule="evenodd"
12
+ />
13
+ </svg>
14
+ )
15
+
16
+ export default BrandFtMasthead
@@ -0,0 +1,90 @@
1
+ import React from 'react'
2
+ import BrandFtMastheadSvg from '../svg-components/BrandFtMasthead'
3
+
4
+ const HeaderWrapper = (props) => (
5
+ <header
6
+ id="site-navigation"
7
+ className={`o-header o-header--${props.variant || 'simple'}`}
8
+ data-o-component="o-header"
9
+ data-o-header--no-js={true}
10
+ tabIndex={-1}>
11
+ {props.children}
12
+ </header>
13
+ )
14
+
15
+ const DrawerIcon = () => (
16
+ <a
17
+ href="#o-header-drawer"
18
+ className="o-header__top-link o-header__top-link--menu"
19
+ aria-controls="o-header-drawer"
20
+ title="Open side navigation menu"
21
+ data-trackable="drawer-toggle">
22
+ <span className="o-header__top-link-label">Open side navigation menu</span>
23
+ </a>
24
+ )
25
+
26
+ const SearchIcon = () => (
27
+ <a
28
+ href={`#o-header-search-primary`}
29
+ className="o-header__top-link o-header__top-link--search"
30
+ aria-controls={`o-header-search-primary`}
31
+ title="Open search bar"
32
+ data-trackable="search-toggle">
33
+ <span className="o-header__top-link-label">Open search bar</span>
34
+ </a>
35
+ )
36
+
37
+ const MyFt = () => (
38
+ <a
39
+ className="o-header__top-link o-header__top-link--myft"
40
+ href="/myft"
41
+ data-trackable="my-ft"
42
+ data-tour-stage="myFt"
43
+ aria-label="My F T">
44
+ <span className="o-header__visually-hidden">myFT</span>
45
+ </a>
46
+ )
47
+
48
+ const TopWrapper = (props) => (
49
+ <div className="o-header__row o-header__top" data-trackable="header-top">
50
+ <div className="o-header__container">
51
+ <div className="o-header__top-wrapper">{props.children}</div>
52
+ </div>
53
+ </div>
54
+ )
55
+
56
+ const TopColumnLeft = () => (
57
+ <div className="o-header__top-column o-header__top-column--left">
58
+ <DrawerIcon />
59
+ <SearchIcon />
60
+ </div>
61
+ )
62
+
63
+ const TopColumnCenter = () => (
64
+ <div className="o-header__top-column o-header__top-column--center">
65
+ <a
66
+ className="o-header__top-logo"
67
+ style={{ backgroundImage: 'none' }}
68
+ data-trackable="logo"
69
+ href="/"
70
+ title="Go to Financial Times homepage">
71
+ <BrandFtMastheadSvg title="Financial Times" />
72
+ </a>
73
+ </div>
74
+ )
75
+
76
+ const TopColumnCenterNoLink = () => (
77
+ <div className="o-header__top-column o-header__top-column--center">
78
+ <div className="o-header__top-logo" style={{ backgroundImage: 'none' }}>
79
+ <BrandFtMastheadSvg title="Financial Times" />
80
+ </div>
81
+ </div>
82
+ )
83
+
84
+ const TopColumnRight = () => (
85
+ <div className="o-header__top-column o-header__top-column--right">
86
+ <MyFt />
87
+ </div>
88
+ )
89
+
90
+ export { HeaderWrapper, TopWrapper, TopColumnLeft, TopColumnCenter, TopColumnCenterNoLink, TopColumnRight }
@@ -0,0 +1,29 @@
1
+ // Search
2
+ // At the time of writing o-header duplicates search markup.
3
+ // Once for a core experience, once for an enhanced experience.
4
+ // The enhanced version is hidden until toggled with JavaScript.
5
+ // Instead since we can rely on the `core` class we can use the
6
+ // one enhanced experience search block and reveal for the core
7
+ // experience if needed.
8
+ .core [data-o-header-search] {
9
+ display: block;
10
+ }
11
+
12
+ // z-indexes
13
+ .o-header__mega {
14
+ @include nUiZIndexFor('meganav');
15
+ }
16
+
17
+ .o-header__drawer {
18
+ @include nUiZIndexFor('drawer');
19
+ display: block;
20
+ }
21
+
22
+ .o-header--sticky {
23
+ @include nUiZIndexFor('sticky-header');
24
+ }
25
+
26
+ // Search typeahead
27
+ .n-typeahead {
28
+ display: none;
29
+ }
package/src/index.tsx ADDED
@@ -0,0 +1,123 @@
1
+ import React from 'react'
2
+ import {
3
+ HeaderWrapper,
4
+ TopWrapper,
5
+ TopColumnLeft,
6
+ TopColumnCenter,
7
+ TopColumnCenterNoLink,
8
+ TopColumnRight
9
+ } from './components/top/partials'
10
+ import {
11
+ NavListLeft,
12
+ NavListRight,
13
+ NavDesktop,
14
+ UserActionsNav,
15
+ MobileNav
16
+ } from './components/navigation/partials'
17
+ import {
18
+ StickyHeaderWrapper,
19
+ TopWrapperSticky,
20
+ TopColumnCenterSticky,
21
+ TopColumnLeftSticky,
22
+ TopColumnRightSticky
23
+ } from './components/sticky/partials'
24
+ import { SubNavigation } from './components/sub-navigation/partials'
25
+ import { IncludeDrawer } from './components/drawer/topLevelPartials'
26
+ import { Search } from './components/search/partials'
27
+
28
+ import { THeaderProps, THeaderOptions } from './interfaces'
29
+
30
+ const defaultProps: Partial<THeaderOptions> = {
31
+ showSubNavigation: true,
32
+ showUserNavigation: true,
33
+ userIsAnonymous: true,
34
+ userIsLoggedIn: false,
35
+ showStickyHeader: true,
36
+ showMegaNav: true
37
+ }
38
+
39
+ function MainHeader(props: THeaderProps) {
40
+ const includeUserActionsNav = props.showUserNavigation && !props.userIsLoggedIn
41
+ const includeSubNavigation = props.showSubNavigation && (props.data.breadcrumb || props.data.subsections)
42
+
43
+ return (
44
+ <HeaderWrapper {...props}>
45
+ {includeUserActionsNav ? <UserActionsNav {...props} /> : null}
46
+ <TopWrapper>
47
+ <TopColumnLeft />
48
+ {props.showLogoLink ? <TopColumnCenter /> : <TopColumnCenterNoLink />}
49
+ <TopColumnRight />
50
+ </TopWrapper>
51
+ <Search instance="primary" />
52
+ <MobileNav {...props} />
53
+ <NavDesktop>
54
+ <NavListLeft {...props} />
55
+ {props.showUserNavigation ? <NavListRight {...props} /> : null}
56
+ </NavDesktop>
57
+ {includeSubNavigation ? <SubNavigation {...props} /> : null}
58
+ </HeaderWrapper>
59
+ )
60
+ }
61
+
62
+ MainHeader.defaultProps = { ...defaultProps, showLogoLink: true }
63
+
64
+ function StickyHeader(props: THeaderProps) {
65
+ return props.showStickyHeader ? (
66
+ <StickyHeaderWrapper {...props}>
67
+ <TopWrapperSticky>
68
+ <TopColumnLeftSticky />
69
+ <TopColumnCenterSticky {...props} />
70
+ <TopColumnRightSticky {...props} />
71
+ </TopWrapperSticky>
72
+ <Search instance="sticky" />
73
+ </StickyHeaderWrapper>
74
+ ) : null
75
+ }
76
+
77
+ StickyHeader.defaultProps = defaultProps
78
+
79
+ function Header(props: THeaderProps) {
80
+ return (
81
+ <React.Fragment>
82
+ <MainHeader {...props} />
83
+ <StickyHeader {...props} />
84
+ </React.Fragment>
85
+ )
86
+ }
87
+
88
+ Header.defaultProps = defaultProps
89
+
90
+ function LogoOnly(props: Pick<THeaderProps, 'variant' | 'showLogoLink'>) {
91
+ return (
92
+ <HeaderWrapper {...props}>
93
+ <TopWrapper>{props.showLogoLink ? <TopColumnCenter /> : <TopColumnCenterNoLink />}</TopWrapper>
94
+ </HeaderWrapper>
95
+ )
96
+ }
97
+
98
+ LogoOnly.defaultProps = defaultProps
99
+
100
+ function Drawer(props: THeaderProps) {
101
+ return <IncludeDrawer {...props} />
102
+ }
103
+
104
+ Drawer.defaultProps = defaultProps
105
+
106
+ function NoOutboundLinksHeader(props: THeaderProps) {
107
+ const includeUserActionsNav = props.showUserNavigation && !props.userIsLoggedIn
108
+ const includeSubNavigation = props.showSubNavigation && (props.data.breadcrumb || props.data.subsections)
109
+
110
+ return (
111
+ <HeaderWrapper {...props}>
112
+ {includeUserActionsNav ? <UserActionsNav {...props} /> : null}
113
+ <TopWrapper>{props.showLogoLink ? <TopColumnCenter /> : <TopColumnCenterNoLink />}</TopWrapper>
114
+ <NavDesktop>{props.showUserNavigation ? <NavListRight {...props} /> : null}</NavDesktop>
115
+ {includeSubNavigation ? <SubNavigation {...props} /> : null}
116
+ </HeaderWrapper>
117
+ )
118
+ }
119
+
120
+ NoOutboundLinksHeader.defaultProps = defaultProps
121
+
122
+ export { Header, MainHeader, StickyHeader, LogoOnly, NoOutboundLinksHeader, Drawer }
123
+ export type { THeaderProps }
@@ -0,0 +1,18 @@
1
+ import { TNavigationData } from '@financial-times/dotcom-types-navigation'
2
+
3
+ export type THeaderOptions = {
4
+ variant?: THeaderVariant
5
+ userIsAnonymous?: boolean
6
+ userIsLoggedIn?: boolean
7
+ showSubNavigation?: boolean
8
+ showUserNavigation?: boolean
9
+ showStickyHeader?: boolean
10
+ showMegaNav?: boolean
11
+ showLogoLink?: boolean
12
+ }
13
+
14
+ export type THeaderProps = THeaderOptions & {
15
+ data: TNavigationData
16
+ }
17
+
18
+ export type THeaderVariant = 'simple' | 'large-logo'
package/src/utils.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { HTMLAttributes } from 'react'
2
+
3
+ export const ariaSelected = (item): HTMLAttributes<HTMLElement> | null => {
4
+ return item.selected ? { 'aria-label': `${item.label}, current page`, 'aria-current': 'page' } : null
5
+ }
package/styles.scss ADDED
@@ -0,0 +1,14 @@
1
+ // This will be overridden by dotcom-ui-layout, it's necessary here for storybook builds
2
+ $system-code: 'page-kit-header' !default;
3
+
4
+ @import "n-ui-foundations/mixins";
5
+
6
+ // We don't need the sub-brand or transparent header styles so disable them.
7
+ // TODO: move drawer styles into a separate stylesheet which can be lazy loaded?
8
+ @import "o-header/main";
9
+ @include oHeader(('top', 'nav', 'subnav', 'search', 'megamenu', 'drawer', 'anon', 'sticky', 'simple'));
10
+
11
+ @import "src/header";
12
+
13
+ @import "n-topic-search/main";
14
+ @include nTopicSearch;