@financial-times/dotcom-ui-header 13.8.1-beta.0 → 13.9.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.
@@ -67,6 +67,38 @@ describe('dotcom-ui-header', () => {
67
67
  expect(mobileHeader).not.toBeNull()
68
68
  })
69
69
 
70
+ it('renders one search widget anchor in the primary search row', () => {
71
+ const { container } = render(commonHeader)
72
+ const primarySearch = container.querySelector('#o-header-search-primary')
73
+ const primarySearchMain = primarySearch?.querySelector('.o-header__search-main')
74
+ const primaryForm = primarySearch?.querySelector('.o-header__search-form')
75
+ const primaryAnchor = primarySearch?.querySelector('[data-o-header-search-widget-anchor="primary"]')
76
+ const primaryAnchors = container.querySelectorAll('[data-o-header-search-widget-anchor="primary"]')
77
+ const widgetAnchors = container.querySelectorAll('[data-o-header-search-widget-anchor]')
78
+
79
+ expect(primarySearchMain).not.toBeNull()
80
+ expect(primaryForm?.parentElement).toBe(primarySearchMain)
81
+ expect(primarySearchMain?.nextElementSibling).toBe(primaryAnchor)
82
+ expect(primaryAnchors).toHaveLength(1)
83
+ expect(widgetAnchors).toHaveLength(2)
84
+ })
85
+
86
+ it('renders one search widget anchor in sticky search', () => {
87
+ const { container } = render(commonHeader)
88
+ const searchMainNodes = container.querySelectorAll('.o-header__search-main')
89
+ const stickySearch = container.querySelector('#o-header-search-sticky')
90
+ const stickySearchMain = stickySearch?.querySelector('.o-header__search-main')
91
+ const stickyForm = stickySearch?.querySelector('.o-header__search-form')
92
+ const stickyAnchor = stickySearch?.querySelector('[data-o-header-search-widget-anchor="sticky"]')
93
+ const stickyAnchors = container.querySelectorAll('[data-o-header-search-widget-anchor="sticky"]')
94
+
95
+ expect(searchMainNodes).toHaveLength(2)
96
+ expect(stickySearchMain).not.toBeNull()
97
+ expect(stickyForm?.parentElement).toBe(stickySearchMain)
98
+ expect(stickySearchMain?.nextElementSibling).toBe(stickyAnchor)
99
+ expect(stickyAnchors).toHaveLength(1)
100
+ })
101
+
70
102
  describe('When the user is subscribed', () => {
71
103
  it('renders the expected logged in user header links', () => {
72
104
  const { container } = render(subscribedUserHeader)
@@ -2,6 +2,7 @@ import React from 'react'
2
2
 
3
3
  const Search = ({ instance }) => {
4
4
  const inputId = `o-header-search-term-${instance}`
5
+
5
6
  return (
6
7
  <div
7
8
  id={`o-header-search-${instance}`}
@@ -11,49 +12,52 @@ const Search = ({ instance }) => {
11
12
  data-o-header-search
12
13
  >
13
14
  <div className="o-header__container">
14
- <form
15
- className="o-header__search-form"
16
- action="/search"
17
- role="search"
18
- aria-label="Site search"
19
- data-n-topic-search
20
- >
21
- <label htmlFor={inputId} className="o-header__search-term o-forms-field o-forms-field--optional">
22
- <span className="o-forms-title o-header__visually-hidden">
23
- <span className="o-forms-title__main">
24
- Search the <abbr title="Financial Times">FT</abbr>
15
+ <div className="o-header__search-main">
16
+ <form
17
+ className="o-header__search-form"
18
+ action="/search"
19
+ role="search"
20
+ aria-label="Site search"
21
+ data-n-topic-search
22
+ >
23
+ <label htmlFor={inputId} className="o-header__search-term o-forms-field o-forms-field--optional">
24
+ <span className="o-forms-title o-header__visually-hidden">
25
+ <span className="o-forms-title__main">
26
+ Search the <abbr title="Financial Times">FT</abbr>
27
+ </span>
28
+ </span>
29
+ <span className="o-forms-input o-forms-input--text o-forms-input--suffix">
30
+ <input
31
+ id={inputId}
32
+ name="q"
33
+ type="search"
34
+ autoComplete="off"
35
+ autoCorrect="off"
36
+ autoCapitalize="off"
37
+ spellCheck={false}
38
+ placeholder="Search for stories, topics or securities"
39
+ role="combobox"
40
+ aria-controls={`suggestions-${inputId}`}
41
+ />
42
+ <button className="o-header__search-submit" type="submit">
43
+ <span aria-hidden="true" className="o-header__search-icon"></span>
44
+ <span>Search</span>
45
+ </button>
46
+ <button
47
+ className="o-header__search-close o--if-js"
48
+ type="button"
49
+ aria-controls={`o-header-search-${instance}`}
50
+ title="Close search bar"
51
+ data-trackable="close"
52
+ >
53
+ <span className="o-header__visually-hidden">Close search bar</span>
54
+ <span>Close</span>
55
+ </button>
25
56
  </span>
26
- </span>
27
- <span className="o-forms-input o-forms-input--text o-forms-input--suffix">
28
- <input
29
- id={inputId}
30
- name="q"
31
- type="search"
32
- autoComplete="off"
33
- autoCorrect="off"
34
- autoCapitalize="off"
35
- spellCheck={false}
36
- placeholder="Search for stories, topics or securities"
37
- role="combobox"
38
- aria-controls={`suggestions-${inputId}`}
39
- />
40
- <button className="o-header__search-submit" type="submit">
41
- <span aria-hidden="true" className="o-header__search-icon"></span>
42
- <span>Search</span>
43
- </button>
44
- <button
45
- className="o-header__search-close o--if-js"
46
- type="button"
47
- aria-controls={`o-header-search-${instance}`}
48
- title="Close search bar"
49
- data-trackable="close"
50
- >
51
- <span className="o-header__visually-hidden">Close search bar</span>
52
- <span>Close</span>
53
- </button>
54
- </span>
55
- </label>
56
- </form>
57
+ </label>
58
+ </form>
59
+ </div>
60
+ <div className="o-header__search-widget-anchor" data-o-header-search-widget-anchor={instance} />
57
61
  </div>
58
62
  </div>
59
63
  )
package/src/header.scss CHANGED
@@ -16,6 +16,38 @@
16
16
  display: none;
17
17
  }
18
18
 
19
+ .o-header__search-widget-anchor[data-o-header-search-widget-anchor] {
20
+ display: none;
21
+ }
22
+
23
+ // Grid layout on large sizes to create right hand rail for widget anchor
24
+ @include oGridRespondTo('L') {
25
+ .o-header__search--primary .o-header__container,
26
+ .o-header__search--sticky .o-header__container {
27
+ max-width: none;
28
+ display: grid;
29
+ grid-template-columns: minmax(0, 1fr) minmax(0, 840px) minmax(0, 1fr);
30
+ column-gap: var(--o3-spacing-3xs);
31
+ }
32
+
33
+ .o-header__search--primary .o-header__search-main,
34
+ .o-header__search--sticky .o-header__search-main {
35
+ grid-column: 2;
36
+ grid-row: 1;
37
+ min-width: 0;
38
+ }
39
+
40
+ .o-header__search--primary .o-header__search-widget-anchor[data-o-header-search-widget-anchor='primary'],
41
+ .o-header__search--sticky .o-header__search-widget-anchor[data-o-header-search-widget-anchor='sticky'] {
42
+ grid-column: 3;
43
+ display: block;
44
+ width: 100%;
45
+ min-width: 0;
46
+ overflow-x: hidden;
47
+ overflow-y: visible;
48
+ }
49
+ }
50
+
19
51
  // Import the dropdown navigation styles
20
52
  @import 'components/dropdown-navigation/dropdownNavigation.scss';
21
53