Skip to content

Commit d2c01b3

Browse files
committed
fix(#1999): refactor DocSearch component into separate file
1 parent a53f849 commit d2c01b3

File tree

2 files changed

+123
-118
lines changed

2 files changed

+123
-118
lines changed

packages/dev/docs/src/DocSearch.js

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import algoliasearch from 'algoliasearch/lite';
2+
import docsStyle from './docs.css';
3+
import DOMPurify from 'dompurify';
4+
import {Item, SearchAutocomplete, Section} from '@react-spectrum/autocomplete';
5+
import React, {useState} from 'react';
6+
import {Text} from '@adobe/react-spectrum';
7+
import {ThemeProvider} from './ThemeSwitcher';
8+
9+
export default function DocSearch() {
10+
const client = algoliasearch('1V1Q59JVTR', '44a7e2e7508ff185f25ac64c0a675f98');
11+
const searchIndex = client.initIndex('react-spectrum');
12+
const searchOptions = {
13+
distinct: 1,
14+
highlightPreTag: `<mark class="${docsStyle.docSearchBoxMark}">`,
15+
highlightPostTag: '</mark>'
16+
};
17+
18+
const sectionTitles = {
19+
'react-aria': 'React Aria',
20+
'react-spectrum': 'React Spectrum',
21+
'react-stately': 'React Stately',
22+
'internationalized': 'Internationalized',
23+
'blog': 'Blog',
24+
'architecture': 'Architecture',
25+
'contribute': 'Contribute',
26+
'releases': 'Releases',
27+
'support': 'Support'
28+
};
29+
30+
const [searchValue, setSearchValue] = useState('');
31+
const [predictions, setPredictions] = useState(null);
32+
const [suggestions, setSuggestions] = useState(null);
33+
34+
let updatePredictions = ({hits}) => {
35+
setPredictions(hits);
36+
let sections = [];
37+
hits.forEach(prediction => {
38+
let hierarchy = prediction.hierarchy;
39+
let objectID = prediction.objectID;
40+
let url = prediction.url;
41+
let sectionTitle;
42+
for (const [path, title] of Object.entries(sectionTitles)) {
43+
let regexp = new RegExp('^.+//.+/' + path + '[/.].+$', 'i');
44+
if (url.match(regexp)) {
45+
sectionTitle = title;
46+
break;
47+
}
48+
}
49+
if (!sectionTitle) {
50+
sectionTitle = 'Documentation';
51+
}
52+
let section = sections.find(section => section.title === sectionTitle);
53+
if (!section) {
54+
section = {title: sectionTitle, items: []};
55+
sections.push(section);
56+
}
57+
let text = [];
58+
let textValue = [];
59+
for (let i = 1; i < 6; i++) {
60+
if (hierarchy[`lvl${i}`]) {
61+
text.push(prediction._highlightResult.hierarchy[`lvl${i}`].value);
62+
textValue.push(hierarchy[`lvl${i}`]);
63+
}
64+
}
65+
section.items.push(
66+
<Item key={objectID} textValue={textValue.join(' | ')}>
67+
<Text><span dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(text.join(' | '))}} /></Text>
68+
{
69+
prediction.content &&
70+
<Text slot="description">
71+
<span dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(prediction._snippetResult.content.value)}} />
72+
</Text>
73+
}
74+
</Item>
75+
);
76+
});
77+
let titles = Object.values(sectionTitles);
78+
sections = sections.sort((a, b) => titles.indexOf(a.title) < titles.indexOf(b.title) ? -1 : 1);
79+
let suggestions = sections.map((section, index) => <Section key={`${index}-${section.title}`} title={section.title}>{section.items}</Section>);
80+
setSuggestions(suggestions);
81+
};
82+
83+
let onInputChange = (query) => {
84+
if (!query && predictions) {
85+
setPredictions(null);
86+
setSuggestions(null);
87+
}
88+
setSearchValue(query);
89+
searchIndex
90+
.search(
91+
query,
92+
searchOptions
93+
)
94+
.then(updatePredictions);
95+
};
96+
97+
let onSubmit = (value, key) => {
98+
if (key) {
99+
let prediction = predictions.find(prediction => key === prediction.objectID);
100+
let url = prediction.url;
101+
window.location.href = `${window.location.hostname === 'reactspectrum.blob.core.windows.net' ? window.location.href.replace(/(.+\/docs\/)(.+)/, '$1') : '/'}${url.replace('https://react-spectrum.adobe.com/', '')}`;
102+
}
103+
};
104+
105+
return (
106+
<ThemeProvider UNSAFE_className={docsStyle.docSearchBoxThemeProvider}>
107+
<span role="search">
108+
<SearchAutocomplete
109+
aria-label="Search"
110+
UNSAFE_className={docsStyle.docSearchBox}
111+
id="algolia-doc-search"
112+
value={searchValue}
113+
onInputChange={onInputChange}
114+
onSubmit={onSubmit}>
115+
{suggestions}
116+
</SearchAutocomplete>
117+
</span>
118+
</ThemeProvider>
119+
);
120+
}

packages/dev/docs/src/client.js

Lines changed: 3 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,14 @@
1010
* governing permissions and limitations under the License.
1111
*/
1212

13-
import {ActionButton, Text} from '@adobe/react-spectrum';
14-
import algoliasearch from 'algoliasearch/lite';
13+
import {ActionButton} from '@adobe/react-spectrum';
14+
import DocSearch from './DocSearch';
1515
import docsStyle from './docs.css';
16-
import DOMPurify from 'dompurify';
17-
import {Item, SearchAutocomplete, Section} from '@react-spectrum/autocomplete';
1816
import {listen} from 'quicklink';
1917
import React, {useEffect, useRef, useState} from 'react';
2018
import ReactDOM from 'react-dom';
2119
import ShowMenu from '@spectrum-icons/workflow/ShowMenu';
22-
import {ThemeProvider, ThemeSwitcher} from './ThemeSwitcher';
20+
import {ThemeSwitcher} from './ThemeSwitcher';
2321
import {watchModals} from '@react-aria/aria-modal-polyfill';
2422

2523
if (process.env.NODE_ENV === 'production') {
@@ -186,119 +184,6 @@ function Hamburger() {
186184
);
187185
}
188186

189-
function DocSearch() {
190-
const client = algoliasearch('1V1Q59JVTR', '44a7e2e7508ff185f25ac64c0a675f98');
191-
const searchIndex = client.initIndex('react-spectrum');
192-
const searchOptions = {
193-
distinct: 1,
194-
highlightPreTag: `<mark class="${docsStyle.docSearchBoxMark}">`,
195-
highlightPostTag: '</mark>'
196-
};
197-
198-
const sectionTitles = {
199-
'react-aria': 'React Aria',
200-
'react-spectrum': 'React Spectrum',
201-
'react-stately': 'React Stately',
202-
'internationalized': 'Internationalized',
203-
'blog': 'Blog',
204-
'architecture': 'Architecture',
205-
'contribute': 'Contribute',
206-
'releases': 'Releases',
207-
'support': 'Support'
208-
};
209-
210-
const [searchValue, setSearchValue] = useState('');
211-
const [predictions, setPredictions] = useState(null);
212-
const [suggestions, setSuggestions] = useState(null);
213-
214-
let updatePredictions = ({hits}) => {
215-
setPredictions(hits);
216-
let sections = [];
217-
hits.forEach(prediction => {
218-
let hierarchy = prediction.hierarchy;
219-
let objectID = prediction.objectID;
220-
let url = prediction.url;
221-
let sectionTitle;
222-
for (const [path, title] of Object.entries(sectionTitles)) {
223-
let regexp = new RegExp('^.+//.+/' + path + '[/.].+$', 'i');
224-
if (url.match(regexp)) {
225-
sectionTitle = title;
226-
break;
227-
}
228-
}
229-
if (!sectionTitle) {
230-
sectionTitle = 'Documentation';
231-
}
232-
let section = sections.find(section => section.title === sectionTitle);
233-
if (!section) {
234-
section = {title: sectionTitle, items: []};
235-
sections.push(section);
236-
}
237-
let text = [];
238-
let textValue = [];
239-
for (let i = 1; i < 6; i++) {
240-
if (hierarchy[`lvl${i}`]) {
241-
text.push(prediction._highlightResult.hierarchy[`lvl${i}`].value);
242-
textValue.push(hierarchy[`lvl${i}`]);
243-
}
244-
}
245-
section.items.push(
246-
<Item key={objectID} textValue={textValue.join(' | ')}>
247-
<Text><span dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(text.join(' | '))}} /></Text>
248-
{
249-
prediction.content &&
250-
<Text slot="description">
251-
<span dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(prediction._snippetResult.content.value)}} />
252-
</Text>
253-
}
254-
</Item>
255-
);
256-
});
257-
let titles = Object.values(sectionTitles);
258-
sections = sections.sort((a, b) => titles.indexOf(a.title) < titles.indexOf(b.title) ? -1 : 1);
259-
let suggestions = sections.map((section, index) => <Section key={`${index}-${section.title}`} title={section.title}>{section.items}</Section>);
260-
setSuggestions(suggestions);
261-
};
262-
263-
let onInputChange = (query) => {
264-
if (!query && predictions) {
265-
setPredictions(null);
266-
setSuggestions(null);
267-
}
268-
setSearchValue(query);
269-
searchIndex
270-
.search(
271-
query,
272-
searchOptions
273-
)
274-
.then(updatePredictions);
275-
};
276-
277-
let onSubmit = (value, key) => {
278-
if (key) {
279-
let prediction = predictions.find(prediction => key === prediction.objectID);
280-
let url = prediction.url;
281-
window.location.href = `${window.location.hostname === 'reactspectrum.blob.core.windows.net' ? window.location.href.replace(/(.+\/docs\/)(.+)/, '$1') : '/'}${url.replace('https://react-spectrum.adobe.com/', '')}`;
282-
}
283-
};
284-
285-
return (
286-
<ThemeProvider UNSAFE_className={docsStyle.docSearchBoxThemeProvider}>
287-
<span role="search">
288-
<SearchAutocomplete
289-
aria-label="Search"
290-
UNSAFE_className={docsStyle.docSearchBox}
291-
id="algolia-doc-search"
292-
value={searchValue}
293-
onInputChange={onInputChange}
294-
onSubmit={onSubmit}>
295-
{suggestions}
296-
</SearchAutocomplete>
297-
</span>
298-
</ThemeProvider>
299-
);
300-
}
301-
302187
ReactDOM.render(<>
303188
<Hamburger />
304189
<DocSearch />

0 commit comments

Comments
 (0)