@financial-times/dotcom-ui-header 8.1.0 → 9.0.0-beta.2
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.
- package/browser.js +5 -2
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/enhanced-search/customList.js +135 -0
- package/src/enhanced-search/enhancedSearch.js +31 -0
- package/src/enhanced-search/styles.scss +117 -0
- package/src/index.tsx +2 -0
- package/styles.scss +8 -4
package/browser.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import Header from '@financial-times/o-header'
|
|
2
2
|
import TopicSearch from 'n-topic-search'
|
|
3
|
-
|
|
3
|
+
import EnhancedSearch from './src/enhanced-search/enhancedSearch'
|
|
4
4
|
/**
|
|
5
5
|
* @typedef HeaderOptions
|
|
6
6
|
* @property { HTMLElement } [rootElement] - the root element passed to o-header
|
|
7
7
|
* @property { string } [hostName]
|
|
8
|
+
* @property { string } [enhancedSearchUrl]
|
|
8
9
|
*/
|
|
9
10
|
|
|
10
11
|
/**
|
|
@@ -16,7 +17,9 @@ export const init = (headerOptions = {}) => {
|
|
|
16
17
|
'.o-header [data-n-topic-search], .o-header__drawer [data-n-topic-search]'
|
|
17
18
|
)
|
|
18
19
|
topicSearchElements.forEach((element) => {
|
|
19
|
-
|
|
20
|
+
headerOptions.enhancedSearchUrl
|
|
21
|
+
? new EnhancedSearch(element, headerOptions)
|
|
22
|
+
: new TopicSearch(element, headerOptions)
|
|
20
23
|
})
|
|
21
24
|
|
|
22
25
|
Header.init(headerOptions.rootElement)
|
|
@@ -222,7 +222,7 @@
|
|
|
222
222
|
"affectsGlobalScope": false
|
|
223
223
|
},
|
|
224
224
|
"../src/index.tsx": {
|
|
225
|
-
"version": "
|
|
225
|
+
"version": "a8079d2415c7f843d4b61f63b855b5b7f2bada6d6952ff1af818e4e22cc9aa4d",
|
|
226
226
|
"signature": "193a1c1b82fe624c251dd16b488b6b90a155e072da0ace6b843ec85f99df0c6e",
|
|
227
227
|
"affectsGlobalScope": false
|
|
228
228
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@financial-times/dotcom-ui-header",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "9.0.0-beta.2",
|
|
4
4
|
"description": "",
|
|
5
5
|
"browser": "browser.js",
|
|
6
6
|
"main": "component.js",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"author": "",
|
|
23
23
|
"license": "MIT",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@financial-times/dotcom-types-navigation": "^
|
|
25
|
+
"@financial-times/dotcom-types-navigation": "^9.0.0-beta.2",
|
|
26
26
|
"n-topic-search": "^4.0.0",
|
|
27
27
|
"n-ui-foundations": "^9.0.0"
|
|
28
28
|
},
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import BaseRenderer from 'n-topic-search/src/renderers/base-renderer'
|
|
2
|
+
|
|
3
|
+
const DISPLAY_ITEMS = 5
|
|
4
|
+
|
|
5
|
+
class CustomSuggestionList extends BaseRenderer {
|
|
6
|
+
constructor(container, options, enhancedSearchUrl) {
|
|
7
|
+
super(container, options)
|
|
8
|
+
this.renderSuggestionGroup = this.renderSuggestionGroup.bind(this)
|
|
9
|
+
this.enhancedSearchUrl = enhancedSearchUrl
|
|
10
|
+
this.createHtml()
|
|
11
|
+
this.render()
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
renderSuggestionChip = (term) => {
|
|
15
|
+
return `<a
|
|
16
|
+
data-trackable="link"
|
|
17
|
+
data-suggestion-id="${term}"
|
|
18
|
+
href="${this.enhancedSearchUrl}${term}"
|
|
19
|
+
class="n-topic-search__target enhanced-search__chip">
|
|
20
|
+
<span class="enhanced-search__chip-text">${term}</span>
|
|
21
|
+
</a>`
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
renderDefaultSuggestionsChips() {
|
|
25
|
+
return `
|
|
26
|
+
<div class="enhanced-search__default-results">
|
|
27
|
+
${['US China trade dispute', 'When is UK inflation likely to fall?', 'Greenwashing']
|
|
28
|
+
.map(this.renderSuggestionChip)
|
|
29
|
+
.join('')}
|
|
30
|
+
</div>`
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
renderSuggestionLink(suggestion, group) {
|
|
34
|
+
return `<li class="n-topic-search__item">
|
|
35
|
+
<a class="n-topic-search__target enhanced-search__target ${group.linkClassName}"
|
|
36
|
+
href="${suggestion.url}"
|
|
37
|
+
tabindex="0"
|
|
38
|
+
data-trackable="link"
|
|
39
|
+
data-suggestion-id="${suggestion.id}"
|
|
40
|
+
data-suggestion-type="${suggestion.type}"
|
|
41
|
+
>${suggestion.html}</a>
|
|
42
|
+
</li>`
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
renderSuggestionGroup(group) {
|
|
46
|
+
let html = `<div class="enhanced-search__group ${group.linkClassName}" data-trackable="${group.trackable}">`
|
|
47
|
+
|
|
48
|
+
if (group.suggestions.length || group.emptyHtml) {
|
|
49
|
+
html += `<ul class="n-topic-search__item-list">
|
|
50
|
+
${group.suggestions.map((suggestion) => this.renderSuggestionLink(suggestion, group)).join('')}
|
|
51
|
+
</ul>`
|
|
52
|
+
}
|
|
53
|
+
html += '</div>'
|
|
54
|
+
return html
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
createHtml() {
|
|
58
|
+
const term = this.state.searchTerm
|
|
59
|
+
const hasConcepts = this.state.suggestions.concepts && this.state.suggestions.concepts.length
|
|
60
|
+
const hasEquities = this.state.suggestions.equities && this.state.suggestions.equities.length
|
|
61
|
+
const hasSuggestions = hasConcepts || hasEquities
|
|
62
|
+
const suggestions = []
|
|
63
|
+
this.items = []
|
|
64
|
+
if (this.options.categories.includes('concepts')) {
|
|
65
|
+
suggestions.push({
|
|
66
|
+
linkClassName: 'enhanced-search__target--news',
|
|
67
|
+
trackable: 'enhanced-search-news',
|
|
68
|
+
suggestions: this.state.suggestions.concepts.slice(0, DISPLAY_ITEMS).map((suggestion) => ({
|
|
69
|
+
html: this.highlight(suggestion.prefLabel),
|
|
70
|
+
url: suggestion.url,
|
|
71
|
+
id: suggestion.id,
|
|
72
|
+
type: 'enhanced-search-tag'
|
|
73
|
+
}))
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (this.options.categories.includes('equities')) {
|
|
78
|
+
suggestions.push({
|
|
79
|
+
trackable: 'enhanced-search-equities',
|
|
80
|
+
linkClassName: 'enhanced-search__target--equities',
|
|
81
|
+
emptyHtml: '<div className="enhanced-search__no-results-message">No equities found</div>',
|
|
82
|
+
suggestions: this.state.suggestions.equities.slice(0, DISPLAY_ITEMS).map((suggestion) => ({
|
|
83
|
+
html: `<span class="enhanced-search__target__equity-name">${this.highlight(
|
|
84
|
+
suggestion.name
|
|
85
|
+
)}</span><abbr>${this.highlight(suggestion.symbol)}</abbr>`,
|
|
86
|
+
url: suggestion.url,
|
|
87
|
+
id: suggestion.symbol,
|
|
88
|
+
type: 'enhanced-search-equity'
|
|
89
|
+
}))
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
this.newHtml = `
|
|
94
|
+
<div aria-live="assertive">
|
|
95
|
+
${
|
|
96
|
+
hasSuggestions
|
|
97
|
+
? `
|
|
98
|
+
<div
|
|
99
|
+
class="o-normalise-visually-hidden n-topic-search__suggestions_explanation"
|
|
100
|
+
>
|
|
101
|
+
Search results have been displayed. To jump to the list of suggestions press
|
|
102
|
+
the down arrow key.
|
|
103
|
+
</div>
|
|
104
|
+
`
|
|
105
|
+
: ''
|
|
106
|
+
}
|
|
107
|
+
<div
|
|
108
|
+
class="n-topic-search n-topic-search__suggestions"
|
|
109
|
+
data-trackable="typeahead"
|
|
110
|
+
>
|
|
111
|
+
<div class="enhanced-search__wrapper">
|
|
112
|
+
<h3 class="enhanced-search__title">Enhanced search results for...</h3>
|
|
113
|
+
${term ? this.renderSuggestionChip(term) : this.renderDefaultSuggestionsChips()}
|
|
114
|
+
<div class="o-normalise-visually-hidden">Suggestions include</div>
|
|
115
|
+
${
|
|
116
|
+
hasSuggestions
|
|
117
|
+
? `<div class="enhanced-search__suggestions">
|
|
118
|
+
${suggestions.map(this.renderSuggestionGroup).join('')}
|
|
119
|
+
</div>
|
|
120
|
+
`
|
|
121
|
+
: ''
|
|
122
|
+
}
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
</div>`
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
handleSelection(el, ev) {
|
|
129
|
+
ev.stopPropagation()
|
|
130
|
+
// we don't prevent default as the link's url is a link to the relevant stream page
|
|
131
|
+
return
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export default CustomSuggestionList
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import TopicSearch from 'n-topic-search'
|
|
2
|
+
import CustomSuggestionList from './customList'
|
|
3
|
+
|
|
4
|
+
class EnhancedSearch extends TopicSearch {
|
|
5
|
+
constructor(containerEl, options) {
|
|
6
|
+
super(containerEl, {
|
|
7
|
+
...options,
|
|
8
|
+
listComponent: (...args) => new CustomSuggestionList(...args.concat(options?.enhancedSearchUrl))
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
const inputs = [
|
|
12
|
+
document.querySelector('#o-header-search-term-primary'),
|
|
13
|
+
document.querySelector('#o-header-search-term-sticky'),
|
|
14
|
+
document.querySelector('#o-header-drawer-search-term')
|
|
15
|
+
]
|
|
16
|
+
inputs[0].parentElement.setAttribute('data-attribute-enhanced-search', 'true')
|
|
17
|
+
inputs.forEach((input) =>
|
|
18
|
+
input.setAttribute('placeholder', 'Search the FT using questions, topics or article titles')
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
onFocus(ev) {
|
|
23
|
+
super.onFocus(ev)
|
|
24
|
+
this.show()
|
|
25
|
+
this.suggestionTargets = Array.from(
|
|
26
|
+
this.suggestionListContainer.querySelectorAll('.n-topic-search__target')
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default EnhancedSearch
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
@use '@financial-times/o-colors/main' as colors;
|
|
2
|
+
@use '@financial-times/o-spacing/main' as spacing;
|
|
3
|
+
@use '@financial-times/o-typography/main' as typography;
|
|
4
|
+
|
|
5
|
+
@mixin enhancedSearch {
|
|
6
|
+
.enhanced-search {
|
|
7
|
+
&__wrapper {
|
|
8
|
+
display: flex;
|
|
9
|
+
flex-direction: column;
|
|
10
|
+
width: 100%;
|
|
11
|
+
padding: spacing.oSpacingByName('s6');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
&__title {
|
|
15
|
+
color: colors.oColorsByName('black');
|
|
16
|
+
@include typography.oTypographySans($scale: 0, $style: 'normal', $weight: 'semibold');
|
|
17
|
+
margin: 0 0 spacing.oSpacingByName('s3') 0;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
&__suggestions {
|
|
21
|
+
display: flex;
|
|
22
|
+
gap: spacing.oSpacingByName('m16');
|
|
23
|
+
padding-top: spacing.oSpacingByName('s6');
|
|
24
|
+
flex-direction: column;
|
|
25
|
+
|
|
26
|
+
@include oGridRespondTo('L') {
|
|
27
|
+
flex-direction: row;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
&__target {
|
|
32
|
+
padding: 0;
|
|
33
|
+
padding-block: spacing.oSpacingByName('s2');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
&__target::before,
|
|
37
|
+
&__chip::before {
|
|
38
|
+
border-bottom: unset !important;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
&__target:hover,
|
|
42
|
+
&__target:focus {
|
|
43
|
+
background-color: transparent;
|
|
44
|
+
color: oColorsByName('teal');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
&__target:hover:before,
|
|
48
|
+
&__target:focus:before {
|
|
49
|
+
opacity: 0;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
&__target--news {
|
|
53
|
+
color: colors.oColorsByName('claret-70');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
&__target--news:hover,
|
|
57
|
+
&__target--news:focus {
|
|
58
|
+
color: colors.oColorsByName('claret-30');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
&__target--equities {
|
|
62
|
+
display: flex;
|
|
63
|
+
align-items: flex-start;
|
|
64
|
+
gap: spacing.oSpacingByName('s3');
|
|
65
|
+
color: colors.oColorsByName('black');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
&__target--equities:hover,
|
|
69
|
+
&__target--equities:focus {
|
|
70
|
+
color: colors.oColorsByName('slate');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
&__chip {
|
|
74
|
+
border-radius: spacing.oSpacingByName('s1');
|
|
75
|
+
background: colors.oColorsMix('ft-grey', 'white', 10);
|
|
76
|
+
padding: spacing.oSpacingByName('s2') spacing.oSpacingByName('s3');
|
|
77
|
+
width: fit-content;
|
|
78
|
+
cursor: pointer;
|
|
79
|
+
text-decoration: none;
|
|
80
|
+
display: block;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
&__chip:hover,
|
|
84
|
+
&__chip:focus {
|
|
85
|
+
background: colors.oColorsMix('ft-grey', 'white', 20);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
&__chip:focus-visible {
|
|
89
|
+
box-shadow: 0 0 0 spacing.oSpacingByIncrement(0.5) colors.oColorsByName('white'),
|
|
90
|
+
0 0 0 spacing.oSpacingByName('s1') colors.oColorsByName('black-70');
|
|
91
|
+
color: colors.oColorsByName('white');
|
|
92
|
+
border-color: transparent;
|
|
93
|
+
border-radius: 0;
|
|
94
|
+
outline: none;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
&__chip-text {
|
|
98
|
+
margin: 0;
|
|
99
|
+
color: colors.oColorsByName('black');
|
|
100
|
+
@include typography.oTypographySans($scale: -1, $style: 'normal', $weight: 'regular');
|
|
101
|
+
outline: none;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
&__default-results {
|
|
105
|
+
display: flex;
|
|
106
|
+
justify-content: flex-start;
|
|
107
|
+
align-items: flex-start;
|
|
108
|
+
gap: spacing.oSpacingByName('s2');
|
|
109
|
+
flex-direction: column;
|
|
110
|
+
|
|
111
|
+
@include oGridRespondTo('L') {
|
|
112
|
+
flex-direction: row;
|
|
113
|
+
align-items: center;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
package/src/index.tsx
CHANGED
|
@@ -48,7 +48,9 @@ function MainHeader(props: THeaderProps) {
|
|
|
48
48
|
{props.showLogoLink ? <TopColumnCenter /> : <TopColumnCenterNoLink />}
|
|
49
49
|
<TopColumnRight {...props} />
|
|
50
50
|
</TopWrapper>
|
|
51
|
+
|
|
51
52
|
<Search instance="primary" />
|
|
53
|
+
|
|
52
54
|
<MobileNav {...props} />
|
|
53
55
|
<NavDesktop>
|
|
54
56
|
<NavListLeft {...props} />
|
package/styles.scss
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
// This will be overridden by dotcom-ui-layout, it's necessary here for storybook builds
|
|
2
2
|
$system-code: 'page-kit-header' !default;
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
|
|
5
|
+
@import 'n-ui-foundations/mixins';
|
|
5
6
|
|
|
6
7
|
// We don't need the sub-brand or transparent header styles so disable them.
|
|
7
8
|
// TODO: move drawer styles into a separate stylesheet which can be lazy loaded?
|
|
8
|
-
@import
|
|
9
|
+
@import '@financial-times/o-header/main';
|
|
9
10
|
@include oHeader(('top', 'nav', 'subnav', 'search', 'megamenu', 'drawer', 'anon', 'sticky', 'simple'));
|
|
10
11
|
|
|
11
|
-
@import
|
|
12
|
+
@import 'src/header';
|
|
12
13
|
|
|
13
|
-
@import
|
|
14
|
+
@import 'n-topic-search/main';
|
|
14
15
|
@include nTopicSearch;
|
|
16
|
+
|
|
17
|
+
@import './src/enhanced-search/styles';
|
|
18
|
+
@include enhancedSearch;
|