@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
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@financial-times/dotcom-ui-header",
3
+ "version": "2.6.0",
4
+ "description": "",
5
+ "browser": "browser.js",
6
+ "main": "component.js",
7
+ "types": "src/index.tsx",
8
+ "styles": "styles.scss",
9
+ "scripts": {
10
+ "test": "echo \"Error: no test specified\" && exit 1",
11
+ "tsc": "../../node_modules/.bin/tsc --incremental",
12
+ "clean": "npm run clean:dist && npm run clean:node_modules",
13
+ "clean:dist": "rm -rf dist",
14
+ "clean:node_modules": "rm -rf node_modules",
15
+ "clean:install": "npm run clean && npm i",
16
+ "build": "npm run build:node",
17
+ "build:node": "npm run tsc -- --module commonjs --outDir ./dist/node",
18
+ "build:svg-to-react": "node scripts/convertSvgsToReactComponents.js",
19
+ "dev": "npm run build:node -- --watch"
20
+ },
21
+ "keywords": [],
22
+ "author": "",
23
+ "license": "MIT",
24
+ "dependencies": {
25
+ "@financial-times/dotcom-types-navigation": "^2.6.0"
26
+ },
27
+ "devDependencies": {
28
+ "@financial-times/logo-images": "^1.10.1",
29
+ "@svgr/core": "^5.0.0",
30
+ "camelcase": "^6.0.0"
31
+ },
32
+ "peerDependencies": {
33
+ "react": "^16.8.6"
34
+ },
35
+ "engines": {
36
+ "node": ">= 12.0.0"
37
+ },
38
+ "repository": {
39
+ "type": "git",
40
+ "repository": "https://github.com/Financial-Times/dotcom-page-kit.git",
41
+ "directory": "packages/dotcom-ui-header"
42
+ },
43
+ "homepage": "https://github.com/Financial-Times/dotcom-page-kit/tree/HEAD/packages/dotcom-ui-header"
44
+ }
@@ -0,0 +1,23 @@
1
+ const fs = require('fs')
2
+
3
+ const camelCase = require('camelcase')
4
+ const svgr = require('@svgr/core').default
5
+
6
+ const logoNames = ['brand-ft-masthead']
7
+
8
+ logoNames.forEach((logoName) => {
9
+ const pathToSvg = require.resolve(`@financial-times/logo-images/src/${logoName}.svg`)
10
+
11
+ const svgString = fs.readFileSync(pathToSvg).toString()
12
+
13
+ const componentName = camelCase(logoName, { pascalCase: true })
14
+
15
+ svgr(svgString, { titleProp: true }, { componentName }).then((jsCode) => {
16
+ const comment =
17
+ '// **THIS IS AN AUTO-GENERATED FILE (`npm run build:svg-to-react`) - DO NOT EDIT MANUALLY.**\n\n'
18
+
19
+ const fileExtension = 'tsx'
20
+
21
+ fs.writeFileSync(`src/components/svg-components/${componentName}.${fileExtension}`, comment + jsCode)
22
+ })
23
+ })
@@ -0,0 +1,97 @@
1
+ import React from 'react'
2
+ import { ariaSelected } from '../../utils'
3
+ import { TNavMenuItem, TNavEditions } from '@financial-times/dotcom-types-navigation'
4
+
5
+ export type TDrawerParentItemProps = {
6
+ item: TNavMenuItem
7
+ idSuffix: string
8
+ }
9
+
10
+ export const DrawerParentItem = ({ item, idSuffix }: TDrawerParentItemProps) => {
11
+ const selected = item.selected ? 'selected' : 'unselected'
12
+ return (
13
+ <React.Fragment>
14
+ <div key={item.url} className="o-header__drawer-menu-toggle-wrapper">
15
+ <a
16
+ className={`o-header__drawer-menu-link o-header__drawer-menu-link--${selected} o-header__drawer-menu-link--parent`}
17
+ href={item.url}
18
+ {...ariaSelected(item)}
19
+ data-trackable={item.label}
20
+ >
21
+ {item.label}
22
+ </a>
23
+ <button
24
+ className={`o-header__drawer-menu-toggle o-header__drawer-menu-toggle--${selected}`}
25
+ aria-controls={`o-header-drawer-child-${idSuffix}`}
26
+ data-trackable={`sub-level-toggle | ${item.label}`}
27
+ >
28
+ {`Show more ${item.label}`}
29
+ </button>
30
+ </div>
31
+ <ul
32
+ className="o-header__drawer-menu-list o-header__drawer-menu-list--child"
33
+ id={`o-header-drawer-child-${idSuffix}`}
34
+ data-trackable="sub-level"
35
+ >
36
+ {(item.submenu.items as TNavMenuItem[]).map((item) => {
37
+ const selected = item.selected ? 'selected' : 'unselected'
38
+ return (
39
+ <li key={item.url} className="o-header__drawer-menu-item">
40
+ <a
41
+ className={`o-header__drawer-menu-link o-header__drawer-menu-link--${selected} o-header__drawer-menu-link--child`}
42
+ href={item.url}
43
+ data-trackable={item.label}
44
+ {...ariaSelected(item)}
45
+ >
46
+ {item.label}
47
+ </a>
48
+ </li>
49
+ )
50
+ })}
51
+ </ul>
52
+ </React.Fragment>
53
+ )
54
+ }
55
+
56
+ export const DrawerSingleItem = (item: TNavMenuItem) => {
57
+ const selected = item.selected ? 'selected' : 'unselected'
58
+ return (
59
+ <a
60
+ className={`o-header__drawer-menu-link o-header__drawer-menu-link--${selected}`}
61
+ href={item.url}
62
+ data-trackable={item.label}
63
+ {...ariaSelected(item)}
64
+ >
65
+ {item.label}
66
+ </a>
67
+ )
68
+ }
69
+
70
+ export const DrawerSpecialItem = (item: TNavMenuItem) => {
71
+ const selected = item.selected ? 'selected' : 'unselected'
72
+ return (
73
+ <a
74
+ className={`o-header__drawer-menu-link o-header__drawer-menu-link--${selected} o-header__drawer-menu-link--secondary`}
75
+ href={item.url}
76
+ data-trackable={item.label}
77
+ {...ariaSelected(item)}
78
+ >
79
+ {item.label}
80
+ </a>
81
+ )
82
+ }
83
+
84
+ export const EditionsSwitcher = (editions: TNavEditions) => (
85
+ <ul className="o-header__drawer-menu-list">
86
+ {editions.others.map(({ id, name, url }) => {
87
+ const href = `${url}?edition=${id}`
88
+ return (
89
+ <li key={id} className="o-header__drawer-menu-item" data-trackable="edition-switcher">
90
+ <a className="o-header__drawer-menu-link" href={href} data-trackable={id}>
91
+ Switch to {name} Edition
92
+ </a>
93
+ </li>
94
+ )
95
+ })}
96
+ </ul>
97
+ )
@@ -0,0 +1,153 @@
1
+ import React from 'react'
2
+ import { DrawerParentItem, DrawerSingleItem, DrawerSpecialItem, EditionsSwitcher } from './additionalPartials'
3
+ import { THeaderProps } from '../../interfaces'
4
+ import { TNavMenuItem, TNavMenu, TNavEditions } from '@financial-times/dotcom-types-navigation'
5
+
6
+ const IncludeDrawer = (props) => <Drawer {...props} />
7
+
8
+ const Drawer = (props: THeaderProps) => {
9
+ const editions = props.data.editions
10
+ const [primary, secondary, tertiary] = props.data.drawer.items
11
+ const user = props.userIsLoggedIn ? props.data.user : props.data.anon
12
+
13
+ return (
14
+ <div
15
+ className="o-header__drawer"
16
+ id="o-header-drawer"
17
+ role="navigation"
18
+ aria-label="Drawer menu"
19
+ data-o-header-drawer
20
+ data-o-header-drawer--no-js
21
+ data-trackable="drawer"
22
+ data-trackable-terminate
23
+ >
24
+ <div className="o-header__drawer-inner">
25
+ <DrawerTools {...editions} />
26
+ <Search />
27
+ <nav className="o-header__drawer-menu o-header__drawer-menu--primary o-header__drawer-menu--border">
28
+ {editions && <EditionsSwitcher {...editions} />}
29
+ <ul className="o-header__drawer-menu-list">
30
+ {primary ? <SectionPrimary {...primary} /> : null}
31
+ {secondary ? <SectionSecondary {...secondary} /> : null}
32
+ {tertiary ? <SectionTertiary {...tertiary} /> : null}
33
+ </ul>
34
+ </nav>
35
+ <UserMenu {...user} />
36
+ </div>
37
+ </div>
38
+ )
39
+ }
40
+
41
+ const DrawerTools = (props: TNavEditions) => (
42
+ <div className="o-header__drawer-tools">
43
+ <button
44
+ type="button"
45
+ className="o-header__drawer-tools-close"
46
+ title="Close drawer menu"
47
+ aria-controls="o-header-drawer"
48
+ data-trackable="close"
49
+ >
50
+ <span className="o-header__visually-hidden">Close drawer menu</span>
51
+ </button>
52
+ <a className="o-header__drawer-tools-logo" href="/" data-trackable="logo">
53
+ <span className="o-header__visually-hidden">Financial Times</span>
54
+ </a>
55
+ {props.current && <p className="o-header__drawer-current-edition">{`${props.current.name} Edition`}</p>}
56
+ </div>
57
+ )
58
+
59
+ const Search = () => (
60
+ <div className="o-header__drawer-search">
61
+ <form
62
+ className="o-header__drawer-search-form"
63
+ action="/search"
64
+ role="search"
65
+ aria-label="Site search"
66
+ data-n-topic-search
67
+ data-n-topic-search-categories="concepts,equities"
68
+ data-n-topic-search-view-all
69
+ >
70
+ <label className="o-header__visually-hidden" htmlFor="o-header-drawer-search-term">
71
+ Search the <abbr title="Financial Times">FT</abbr>
72
+ </label>
73
+ <input
74
+ className="o-header__drawer-search-term"
75
+ id="o-header-drawer-search-term"
76
+ name="q"
77
+ type="text"
78
+ autoComplete="off"
79
+ autoCorrect="off"
80
+ autoCapitalize="off"
81
+ spellCheck={false}
82
+ placeholder="Search the FT"
83
+ data-trackable="search-term"
84
+ data-n-topic-search-input
85
+ />
86
+ <button className="o-header__drawer-search-submit" type="submit" data-trackable="search-submit">
87
+ <span className="o-header__visually-hidden">Search</span>
88
+ </button>
89
+ </form>
90
+ </div>
91
+ )
92
+
93
+ const SectionPrimary = (props: TNavMenuItem) => {
94
+ return (
95
+ <React.Fragment>
96
+ <li className="o-header__drawer-menu-item o-header__drawer-menu-item--heading">{props.label}</li>
97
+ {(props.submenu.items as TNavMenuItem[]).map((item, index) => (
98
+ <li key={item.url} className="o-header__drawer-menu-item">
99
+ {item.submenu ? (
100
+ <DrawerParentItem item={item} idSuffix={`${index}`} />
101
+ ) : (
102
+ <DrawerSingleItem {...item} />
103
+ )}
104
+ </li>
105
+ ))}
106
+ </React.Fragment>
107
+ )
108
+ }
109
+
110
+ const SectionSecondary = (props: TNavMenuItem) => (
111
+ <React.Fragment>
112
+ <li className="o-header__drawer-menu-item o-header__drawer-menu-item--heading">{props.label}</li>
113
+ {(props.submenu.items as TNavMenuItem[]).map((item, index) => (
114
+ <li key={item.url} className="o-header__drawer-menu-item">
115
+ {item.submenu ? (
116
+ <DrawerParentItem item={item} idSuffix={'inner' + index} />
117
+ ) : (
118
+ <DrawerSingleItem {...item} />
119
+ )}
120
+ </li>
121
+ ))}
122
+ </React.Fragment>
123
+ )
124
+
125
+ const SectionTertiary = (props: TNavMenuItem) => (
126
+ <React.Fragment>
127
+ {(props.submenu.items as TNavMenuItem[]).map((item, index) => {
128
+ const divideItem = index === 0 ? 'o-header__drawer-menu-item--divide' : ''
129
+
130
+ return (
131
+ <li key={item.url} className={`o-header__drawer-menu-item ${divideItem}`}>
132
+ <DrawerSpecialItem {...item} />
133
+ </li>
134
+ )
135
+ })}
136
+ </React.Fragment>
137
+ )
138
+
139
+ const UserMenu = (props: TNavMenu) => (
140
+ <nav className="o-header__drawer-menu o-header__drawer-menu--user" data-trackable="user-nav">
141
+ <ul className="o-header__drawer-menu-list">
142
+ {props.items.map((item) => (
143
+ <li key={item.url} className="o-header__drawer-menu-item">
144
+ <a className="o-header__drawer-menu-link" href={item.url} data-trackable={item.label}>
145
+ {item.label}
146
+ </a>
147
+ </li>
148
+ ))}
149
+ </ul>
150
+ </nav>
151
+ )
152
+
153
+ export { IncludeDrawer }
@@ -0,0 +1,212 @@
1
+ import React from 'react'
2
+ import { THeaderProps } from '../../interfaces'
3
+ import { ariaSelected } from '../../utils'
4
+ import {
5
+ TNavMenuItem,
6
+ TNavMeganav,
7
+ INavMeganavSections,
8
+ INavMeganavArticles
9
+ } from '@financial-times/dotcom-types-navigation'
10
+
11
+ const MobileNav = (props: THeaderProps) => {
12
+ // Only display navigation on pages which are included in this menu
13
+ const targetUrls = props.data['navbar-simple'].items.map((item) => item.url)
14
+
15
+ return targetUrls.includes(props.data.currentPath) ? (
16
+ <NavMobile items={props.data['navbar-simple'].items} />
17
+ ) : null
18
+ }
19
+
20
+ const NavMobile = ({ items }: { items: TNavMenuItem[] }) => {
21
+ return (
22
+ <nav
23
+ id="o-header-nav-mobile"
24
+ className="o-header__row o-header__nav o-header__nav--mobile"
25
+ aria-hidden="true"
26
+ data-trackable="header-nav:mobile">
27
+ <ul className="o-header__nav-list">
28
+ {items.map((item, index) => (
29
+ <li className="o-header__nav-item" key={`link-${index}`}>
30
+ <a
31
+ className="o-header__nav-link o-header__nav-link--primary"
32
+ href={item.url}
33
+ {...ariaSelected(item)}
34
+ data-trackable={item.label}>
35
+ {item.label}
36
+ </a>
37
+ </li>
38
+ ))}
39
+ </ul>
40
+ </nav>
41
+ )
42
+ }
43
+
44
+ const NavDesktop = (props) => (
45
+ <nav
46
+ id="o-header-nav-desktop"
47
+ className="o-header__row o-header__nav o-header__nav--desktop"
48
+ role="navigation"
49
+ aria-label="Primary navigation"
50
+ data-trackable="header-nav:desktop">
51
+ <div className="o-header__container">{props.children}</div>
52
+ </nav>
53
+ )
54
+
55
+ const NavListLeft = (props: THeaderProps) => (
56
+ <ul className="o-header__nav-list o-header__nav-list--left" data-trackable="primary-nav">
57
+ {props.data.navbar.items.map((item, index) => (
58
+ <li className="o-header__nav-item" key={`link-${index}`}>
59
+ <a
60
+ className="o-header__nav-link o-header__nav-link--primary"
61
+ href={item.url}
62
+ id={`o-header-link-${index}`}
63
+ {...ariaSelected(item)}
64
+ data-trackable={item.label}>
65
+ {item.label}
66
+ </a>
67
+ {props.showMegaNav && Array.isArray(item.meganav) ? (
68
+ <MegaNav meganav={item.meganav} label={item.label} index={index} />
69
+ ) : null}
70
+ </li>
71
+ ))}
72
+ </ul>
73
+ )
74
+
75
+ const NavListRight = (props: THeaderProps) => {
76
+ if (props.userIsLoggedIn) {
77
+ return <NavListRightLoggedIn items={props.data['navbar-right'].items} />
78
+ } else {
79
+ return <NavListRightAnon items={props.data['navbar-right-anon'].items} />
80
+ }
81
+ }
82
+
83
+ const NavListRightLoggedIn = ({ items }: { items: TNavMenuItem[] }) => {
84
+ return (
85
+ <ul className="o-header__nav-list o-header__nav-list--right" data-trackable="user-nav">
86
+ {items.map((item, index) => (
87
+ <li className="o-header__nav-item" key={`link-${index}`}>
88
+ <a className="o-header__nav-link" href={item.url} data-trackable={item.label}>
89
+ {item.label}
90
+ </a>
91
+ </li>
92
+ ))}
93
+ </ul>
94
+ )
95
+ }
96
+
97
+ const NavListRightAnon = ({ items, variant }: { items: TNavMenuItem[]; variant?: string }) => {
98
+ // If user is anonymous the second list item is styled as a button
99
+ const [first, second] = items
100
+ const setTabIndex = variant === 'sticky' ? { tabIndex: -1 } : null
101
+ return (
102
+ <ul className="o-header__nav-list o-header__nav-list--right" data-trackable="user-nav">
103
+ <li className="o-header__nav-item">
104
+ <a className="o-header__nav-link" href={first.url} data-trackable={first.label} {...setTabIndex}>
105
+ {first.label}
106
+ </a>
107
+ </li>
108
+ <li className="o-header__nav-item o-header__nav-item--hide-s">
109
+ <a
110
+ className="o-header__nav-button"
111
+ // Added as the result of a DAC audit. This will be confusing for users of voice activation software
112
+ // as it looks like a button but behaves like a link without this role.
113
+ role="button"
114
+ href={second.url}
115
+ data-trackable={second.label}
116
+ {...setTabIndex}>
117
+ {second.label}
118
+ </a>
119
+ </li>
120
+ </ul>
121
+ )
122
+ }
123
+
124
+ const MegaNav = ({ label, meganav, index }: { label: string; meganav: TNavMeganav[]; index: number }) => {
125
+ const sections = meganav.find(({ component }) => component === 'sectionlist')
126
+ const articles = meganav.find(({ component }) => component === 'articlelist')
127
+
128
+ return (
129
+ <div
130
+ className="o-header__mega"
131
+ id={`o-header-mega-${index}`}
132
+ role="group"
133
+ aria-labelledby={`o-header-link-${index}`}
134
+ data-o-header-mega
135
+ data-trackable={`meganav | ${label}`}>
136
+ <div className="o-header__container">
137
+ <div className="o-header__mega-wrapper">
138
+ {sections ? <SectionList {...(sections as INavMeganavSections)} /> : null}
139
+ {articles ? <ArticleList {...(articles as INavMeganavArticles)} /> : null}
140
+ </div>
141
+ </div>
142
+ </div>
143
+ )
144
+ }
145
+
146
+ const SectionList = ({ title, data }: INavMeganavSections) => {
147
+ return (
148
+ <div className="o-header__mega-column o-header__mega-column--subsections" data-trackable="sections">
149
+ <div className="o-header__mega-heading">{title}</div>
150
+ <div className="o-header__mega-content">
151
+ <ul className="o-header__mega-list">
152
+ {data.map((column) =>
153
+ column.map((item, index) => (
154
+ <li className="o-header__mega-item" key={`link-${index}`}>
155
+ <a
156
+ className="o-header__mega-link"
157
+ href={item.url}
158
+ {...ariaSelected(item)}
159
+ data-trackable="link">
160
+ {item.label}
161
+ </a>
162
+ </li>
163
+ ))
164
+ )}
165
+ </ul>
166
+ </div>
167
+ </div>
168
+ )
169
+ }
170
+
171
+ const ArticleList = ({ title, data }: INavMeganavArticles) => {
172
+ return (
173
+ <div className="o-header__mega-column o-header__mega-column--articles" data-trackable="popular">
174
+ <div className="o-header__mega-heading">{title}</div>
175
+ <div className="o-header__mega-content">
176
+ <ul className="o-header__mega-list">
177
+ {data.map((item, index) => (
178
+ <li className="o-header__mega-item" key={`link-${index}`}>
179
+ <a
180
+ className="o-header__mega-link"
181
+ href={item.url}
182
+ {...ariaSelected(item)}
183
+ data-trackable="link">
184
+ {item.label}
185
+ </a>
186
+ </li>
187
+ ))}
188
+ </ul>
189
+ </div>
190
+ </div>
191
+ )
192
+ }
193
+
194
+ const UserActionsNav = (props: THeaderProps) => {
195
+ const userNavItems = props.data['navbar-right-anon'].items
196
+
197
+ return (
198
+ <div className="o-header__row o-header__anon" data-trackable="header-anon">
199
+ <ul className="o-header__anon-list">
200
+ {userNavItems.map((item, index) => (
201
+ <li className="o-header__anon-item" key={`link-${index}`}>
202
+ <a className="o-header__anon-link" href={item.url} data-trackable={item.label}>
203
+ {item.label}
204
+ </a>
205
+ </li>
206
+ ))}
207
+ </ul>
208
+ </div>
209
+ )
210
+ }
211
+
212
+ export { NavDesktop, NavListLeft, NavListRight, NavListRightAnon, UserActionsNav, MobileNav }
@@ -0,0 +1,52 @@
1
+ import React from 'react'
2
+
3
+ const Search = ({ instance }) => {
4
+ return (
5
+ <div
6
+ id={`o-header-search-${instance}`}
7
+ className={`o-header__row o-header__search o-header__search--${instance}`}
8
+ data-trackable="header-search"
9
+ data-o-header-search>
10
+ <div className="o-header__container">
11
+ <form
12
+ className="o-header__search-form"
13
+ action="/search"
14
+ role="search"
15
+ aria-label="Site search"
16
+ data-n-topic-search
17
+ data-n-topic-search-categories="concepts,equities"
18
+ data-n-topic-search-view-all>
19
+ <label className="o-header__visually-hidden" htmlFor={`o-header-search-term-${instance}`}>
20
+ Search the <abbr title="Financial Times">FT</abbr>
21
+ </label>
22
+ <input
23
+ className="o-header__search-term"
24
+ id={`o-header-search-term-${instance}`}
25
+ name="q"
26
+ type="text"
27
+ autoComplete="off"
28
+ autoCorrect="off"
29
+ autoCapitalize="off"
30
+ spellCheck={false}
31
+ data-trackable="search-term"
32
+ placeholder="Search the FT"
33
+ data-n-topic-search-input
34
+ />
35
+ <button className="o-header__search-submit" type="submit" data-trackable="search-submit">
36
+ Search
37
+ </button>
38
+ <button
39
+ className="o-header__search-close o--if-js"
40
+ type="button"
41
+ aria-controls={`o-header-search-${instance}`}
42
+ title="Close search bar"
43
+ data-trackable="close">
44
+ <span className="o-header__visually-hidden">Close search bar</span>
45
+ </button>
46
+ </form>
47
+ </div>
48
+ </div>
49
+ )
50
+ }
51
+
52
+ export { Search }