@blaze-cms/plugin-search-ui 0.110.0-alpha.1
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/CHANGELOG.md +345 -0
- package/LICENSE +674 -0
- package/README.md +45 -0
- package/babel.config.js +3 -0
- package/jest.config.js +5 -0
- package/lib/application/query/index.js +32 -0
- package/lib/application/query/index.js.map +1 -0
- package/lib/components/SearchAdmin/RecentSearches/RecentSearches.js +62 -0
- package/lib/components/SearchAdmin/RecentSearches/RecentSearches.js.map +1 -0
- package/lib/components/SearchAdmin/RecentSearches/index.js +16 -0
- package/lib/components/SearchAdmin/RecentSearches/index.js.map +1 -0
- package/lib/components/SearchAdmin/SearchAdmin.js +191 -0
- package/lib/components/SearchAdmin/SearchAdmin.js.map +1 -0
- package/lib/components/SearchAdmin/SearchBar/SearchBar.js +72 -0
- package/lib/components/SearchAdmin/SearchBar/SearchBar.js.map +1 -0
- package/lib/components/SearchAdmin/SearchBar/index.js +16 -0
- package/lib/components/SearchAdmin/SearchBar/index.js.map +1 -0
- package/lib/components/SearchAdmin/SearchResults/SearchResults.js +200 -0
- package/lib/components/SearchAdmin/SearchResults/SearchResults.js.map +1 -0
- package/lib/components/SearchAdmin/SearchResults/index.js +16 -0
- package/lib/components/SearchAdmin/SearchResults/index.js.map +1 -0
- package/lib/components/SearchAdmin/TriggerModal/TriggerModal.js +30 -0
- package/lib/components/SearchAdmin/TriggerModal/TriggerModal.js.map +1 -0
- package/lib/components/SearchAdmin/TriggerModal/index.js +16 -0
- package/lib/components/SearchAdmin/TriggerModal/index.js.map +1 -0
- package/lib/components/SearchAdmin/index.js +16 -0
- package/lib/components/SearchAdmin/index.js.map +1 -0
- package/lib/components/SearchPublishedContent/SearchPublishedContent.js +216 -0
- package/lib/components/SearchPublishedContent/SearchPublishedContent.js.map +1 -0
- package/lib/components/SearchPublishedContent/index.js +16 -0
- package/lib/components/SearchPublishedContent/index.js.map +1 -0
- package/lib/components/useLocalStorage/index.js +16 -0
- package/lib/components/useLocalStorage/index.js.map +1 -0
- package/lib/components/useLocalStorage/useLocalStorage.js +36 -0
- package/lib/components/useLocalStorage/useLocalStorage.js.map +1 -0
- package/lib/components/useSearch/index.js +16 -0
- package/lib/components/useSearch/index.js.map +1 -0
- package/lib/components/useSearch/useSearch.js +154 -0
- package/lib/components/useSearch/useSearch.js.map +1 -0
- package/lib/components/useSearchResults/index.js +16 -0
- package/lib/components/useSearchResults/index.js.map +1 -0
- package/lib/components/useSearchResults/useSearchResults.js +102 -0
- package/lib/components/useSearchResults/useSearchResults.js.map +1 -0
- package/lib/constants.js +25 -0
- package/lib/constants.js.map +1 -0
- package/lib/index.js +34 -0
- package/lib/index.js.map +1 -0
- package/lib-es/application/query/index.js +34 -0
- package/lib-es/application/query/index.js.map +1 -0
- package/lib-es/components/SearchAdmin/RecentSearches/RecentSearches.js +40 -0
- package/lib-es/components/SearchAdmin/RecentSearches/RecentSearches.js.map +1 -0
- package/lib-es/components/SearchAdmin/RecentSearches/index.js +3 -0
- package/lib-es/components/SearchAdmin/RecentSearches/index.js.map +1 -0
- package/lib-es/components/SearchAdmin/SearchAdmin.js +126 -0
- package/lib-es/components/SearchAdmin/SearchAdmin.js.map +1 -0
- package/lib-es/components/SearchAdmin/SearchBar/SearchBar.js +54 -0
- package/lib-es/components/SearchAdmin/SearchBar/SearchBar.js.map +1 -0
- package/lib-es/components/SearchAdmin/SearchBar/index.js +3 -0
- package/lib-es/components/SearchAdmin/SearchBar/index.js.map +1 -0
- package/lib-es/components/SearchAdmin/SearchResults/SearchResults.js +120 -0
- package/lib-es/components/SearchAdmin/SearchResults/SearchResults.js.map +1 -0
- package/lib-es/components/SearchAdmin/SearchResults/index.js +3 -0
- package/lib-es/components/SearchAdmin/SearchResults/index.js.map +1 -0
- package/lib-es/components/SearchAdmin/TriggerModal/TriggerModal.js +16 -0
- package/lib-es/components/SearchAdmin/TriggerModal/TriggerModal.js.map +1 -0
- package/lib-es/components/SearchAdmin/TriggerModal/index.js +3 -0
- package/lib-es/components/SearchAdmin/TriggerModal/index.js.map +1 -0
- package/lib-es/components/SearchAdmin/index.js +3 -0
- package/lib-es/components/SearchAdmin/index.js.map +1 -0
- package/lib-es/components/SearchPublishedContent/SearchPublishedContent.js +157 -0
- package/lib-es/components/SearchPublishedContent/SearchPublishedContent.js.map +1 -0
- package/lib-es/components/SearchPublishedContent/index.js +3 -0
- package/lib-es/components/SearchPublishedContent/index.js.map +1 -0
- package/lib-es/components/useLocalStorage/index.js +3 -0
- package/lib-es/components/useLocalStorage/index.js.map +1 -0
- package/lib-es/components/useLocalStorage/useLocalStorage.js +19 -0
- package/lib-es/components/useLocalStorage/useLocalStorage.js.map +1 -0
- package/lib-es/components/useSearch/index.js +3 -0
- package/lib-es/components/useSearch/index.js.map +1 -0
- package/lib-es/components/useSearch/useSearch.js +100 -0
- package/lib-es/components/useSearch/useSearch.js.map +1 -0
- package/lib-es/components/useSearchResults/index.js +3 -0
- package/lib-es/components/useSearchResults/index.js.map +1 -0
- package/lib-es/components/useSearchResults/useSearchResults.js +57 -0
- package/lib-es/components/useSearchResults/useSearchResults.js.map +1 -0
- package/lib-es/constants.js +10 -0
- package/lib-es/constants.js.map +1 -0
- package/lib-es/index.js +5 -0
- package/lib-es/index.js.map +1 -0
- package/package.json +56 -0
- package/src/application/query/index.js +28 -0
- package/src/components/SearchAdmin/RecentSearches/RecentSearches.js +33 -0
- package/src/components/SearchAdmin/RecentSearches/index.js +3 -0
- package/src/components/SearchAdmin/SearchAdmin.js +129 -0
- package/src/components/SearchAdmin/SearchBar/SearchBar.js +58 -0
- package/src/components/SearchAdmin/SearchBar/index.js +3 -0
- package/src/components/SearchAdmin/SearchResults/SearchResults.js +112 -0
- package/src/components/SearchAdmin/SearchResults/index.js +3 -0
- package/src/components/SearchAdmin/TriggerModal/TriggerModal.js +17 -0
- package/src/components/SearchAdmin/TriggerModal/index.js +3 -0
- package/src/components/SearchAdmin/index.js +3 -0
- package/src/components/SearchPublishedContent/SearchPublishedContent.js +157 -0
- package/src/components/SearchPublishedContent/index.js +3 -0
- package/src/components/useLocalStorage/index.js +3 -0
- package/src/components/useLocalStorage/useLocalStorage.js +18 -0
- package/src/components/useSearch/index.js +3 -0
- package/src/components/useSearch/useSearch.js +85 -0
- package/src/components/useSearchResults/index.js +3 -0
- package/src/components/useSearchResults/useSearchResults.js +38 -0
- package/src/constants.js +19 -0
- package/src/index.js +5 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import classnames from 'classnames';
|
|
3
|
+
import PropTypes from 'prop-types';
|
|
4
|
+
import { useDebounce } from '@blaze-react/utils/lib/customHooks';
|
|
5
|
+
import useSearchResults from '../useSearchResults';
|
|
6
|
+
import { SEARCH_PUBLISHED, DEFAULT_RESULTS_KEYS, SEARCH_BUTTON } from '../../constants';
|
|
7
|
+
|
|
8
|
+
const SearchPublishedContent = ({
|
|
9
|
+
entities,
|
|
10
|
+
children,
|
|
11
|
+
resultKeys,
|
|
12
|
+
getIsOpenSearchBar,
|
|
13
|
+
SearchIcon,
|
|
14
|
+
CloseIcon,
|
|
15
|
+
className,
|
|
16
|
+
onChange,
|
|
17
|
+
placeholder,
|
|
18
|
+
onEnterPress,
|
|
19
|
+
inputRef,
|
|
20
|
+
isSearchBarOpen,
|
|
21
|
+
fields
|
|
22
|
+
}) => {
|
|
23
|
+
const [displaySearchBar, setDisplaySearchBar] = useState(isSearchBarOpen);
|
|
24
|
+
const [searchTerm, setSearchTerm] = useState('');
|
|
25
|
+
const [previousSearchTerm, setPreviousSearchTerm] = useState(null);
|
|
26
|
+
const debouncedSearchTerm = useDebounce(searchTerm, 500);
|
|
27
|
+
const [{ loading, results }, setQueryParams] = useSearchResults({
|
|
28
|
+
queryKey: SEARCH_PUBLISHED,
|
|
29
|
+
resultKeys,
|
|
30
|
+
entities,
|
|
31
|
+
fields
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
useEffect(
|
|
35
|
+
() => {
|
|
36
|
+
if (isSearchBarOpen !== displaySearchBar) {
|
|
37
|
+
setDisplaySearchBar(isSearchBarOpen);
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
41
|
+
[isSearchBarOpen]
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
useEffect(
|
|
45
|
+
() => {
|
|
46
|
+
if (inputRef && inputRef.current && displaySearchBar) {
|
|
47
|
+
inputRef.current.focus();
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
51
|
+
[displaySearchBar]
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
useEffect(
|
|
55
|
+
() => {
|
|
56
|
+
if (debouncedSearchTerm && debouncedSearchTerm !== previousSearchTerm) {
|
|
57
|
+
setQueryParams({ value: debouncedSearchTerm });
|
|
58
|
+
setPreviousSearchTerm(debouncedSearchTerm);
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
[debouncedSearchTerm, previousSearchTerm, setQueryParams]
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
const handleOnChange = ({ target: { value = '' } = {} }) => {
|
|
65
|
+
onChange(value);
|
|
66
|
+
setSearchTerm(value);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const handleKeyPress = event => {
|
|
70
|
+
const onEnter = event.key === 'Enter';
|
|
71
|
+
onEnter && onEnterPress();
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const handleSearchBar = () => {
|
|
75
|
+
const voidSearchTerm = '';
|
|
76
|
+
displaySearchBar && setSearchTerm(voidSearchTerm);
|
|
77
|
+
handleOnChange({ value: voidSearchTerm });
|
|
78
|
+
if (isSearchBarOpen !== null) {
|
|
79
|
+
getIsOpenSearchBar(!displaySearchBar);
|
|
80
|
+
}
|
|
81
|
+
setDisplaySearchBar(!displaySearchBar);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const searchWrapperClassname = classnames('search__wrapper', {
|
|
85
|
+
'search__wrapper--toggle-display': displaySearchBar,
|
|
86
|
+
'search__wrapper--toggle': !displaySearchBar
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const triggerClassname = classnames('search__icon', {
|
|
90
|
+
open: displaySearchBar
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
<div className={`search-wrapper ${className}`}>
|
|
95
|
+
<div className="search search--header search--toggle">
|
|
96
|
+
<div className={searchWrapperClassname}>
|
|
97
|
+
<input
|
|
98
|
+
data-testid="search-input"
|
|
99
|
+
onKeyPress={handleKeyPress}
|
|
100
|
+
placeholder={placeholder}
|
|
101
|
+
type="text"
|
|
102
|
+
onChange={handleOnChange}
|
|
103
|
+
value={searchTerm}
|
|
104
|
+
ref={inputRef}
|
|
105
|
+
/>
|
|
106
|
+
<button type="button" className="icon-button icon-button--search icon-button--toggle">
|
|
107
|
+
<SearchIcon />
|
|
108
|
+
</button>
|
|
109
|
+
</div>
|
|
110
|
+
<div
|
|
111
|
+
role="button"
|
|
112
|
+
className={triggerClassname}
|
|
113
|
+
onClick={handleSearchBar}
|
|
114
|
+
id={SEARCH_BUTTON}
|
|
115
|
+
title={SEARCH_BUTTON}>
|
|
116
|
+
{!displaySearchBar ? <SearchIcon /> : <CloseIcon />}
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
<div className="search-modal">
|
|
120
|
+
{children({ results: results.length && searchTerm ? results : [], loading })}
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
);
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
SearchPublishedContent.propTypes = {
|
|
127
|
+
entities: PropTypes.array,
|
|
128
|
+
children: PropTypes.func.isRequired,
|
|
129
|
+
resultKeys: PropTypes.string,
|
|
130
|
+
getIsOpenSearchBar: PropTypes.func,
|
|
131
|
+
SearchIcon: PropTypes.func,
|
|
132
|
+
CloseIcon: PropTypes.func,
|
|
133
|
+
onChange: PropTypes.func,
|
|
134
|
+
onEnterPress: PropTypes.func,
|
|
135
|
+
className: PropTypes.string,
|
|
136
|
+
placeholder: PropTypes.string,
|
|
137
|
+
inputRef: PropTypes.object,
|
|
138
|
+
isSearchBarOpen: PropTypes.bool,
|
|
139
|
+
fields: PropTypes.array
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
SearchPublishedContent.defaultProps = {
|
|
143
|
+
entities: ['published_page'],
|
|
144
|
+
placeholder: '',
|
|
145
|
+
resultKeys: DEFAULT_RESULTS_KEYS,
|
|
146
|
+
onChange: () => {},
|
|
147
|
+
onEnterPress: () => {},
|
|
148
|
+
getIsOpenSearchBar: state => state,
|
|
149
|
+
SearchIcon: () => <i className="material-icons">search</i>,
|
|
150
|
+
CloseIcon: () => <i className="material-icons">close</i>,
|
|
151
|
+
className: '',
|
|
152
|
+
inputRef: null,
|
|
153
|
+
isSearchBarOpen: null,
|
|
154
|
+
fields: []
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
export default SearchPublishedContent;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
|
|
3
|
+
function useLocalStorage(key, initialValue) {
|
|
4
|
+
const [storedValue, setStoredValue] = useState(() => {
|
|
5
|
+
const item = window.localStorage.getItem(key);
|
|
6
|
+
return item ? JSON.parse(item) : initialValue;
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const setValue = value => {
|
|
10
|
+
const valueToStore = value instanceof Function ? value(storedValue) : value;
|
|
11
|
+
setStoredValue(valueToStore);
|
|
12
|
+
window.localStorage.setItem(key, JSON.stringify(valueToStore));
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
return [storedValue, setValue];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default useLocalStorage;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
|
+
import { useLazyQuery } from 'react-apollo';
|
|
3
|
+
import searchQueries from '../../application/query';
|
|
4
|
+
|
|
5
|
+
function useSearch({ queryKey, resultKeys, entities = [], fields }) {
|
|
6
|
+
const [queryParams, setParams] = useState({ limit: 20, offset: 0, value: '' });
|
|
7
|
+
const [searchedValue, setSearchedValue] = useState(null);
|
|
8
|
+
const [previousOffset, setPreviousOffset] = useState(null);
|
|
9
|
+
const buildSearchQuery = searchQueries[queryKey];
|
|
10
|
+
const [
|
|
11
|
+
getSearchResults,
|
|
12
|
+
{
|
|
13
|
+
loading,
|
|
14
|
+
data: { search: { results, jsonResults, total } } = {
|
|
15
|
+
search: { results: [], total: 0 }
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
] = useLazyQuery(buildSearchQuery({ resultKeys }));
|
|
19
|
+
|
|
20
|
+
const handleQueryParams = newQueryParams => {
|
|
21
|
+
setParams({ ...queryParams, ...newQueryParams });
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
useEffect(
|
|
25
|
+
() => {
|
|
26
|
+
const { limit, offset, value } = queryParams;
|
|
27
|
+
const isNewValueSet = value && value !== searchedValue;
|
|
28
|
+
const isNewOffsetSet = previousOffset !== null && offset !== previousOffset;
|
|
29
|
+
const parsedEntities = entities.length
|
|
30
|
+
? entities.map(entity => ({
|
|
31
|
+
match: { docType: entity }
|
|
32
|
+
}))
|
|
33
|
+
: [];
|
|
34
|
+
|
|
35
|
+
if (isNewValueSet || isNewOffsetSet) {
|
|
36
|
+
getSearchResults({
|
|
37
|
+
variables: {
|
|
38
|
+
limit,
|
|
39
|
+
offset,
|
|
40
|
+
rawQuery: {
|
|
41
|
+
query: {
|
|
42
|
+
bool: {
|
|
43
|
+
must: [
|
|
44
|
+
{
|
|
45
|
+
query_string: {
|
|
46
|
+
query: value,
|
|
47
|
+
fields,
|
|
48
|
+
type: 'most_fields'
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
bool: {
|
|
53
|
+
should: parsedEntities
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
setSearchedValue(value);
|
|
63
|
+
setPreviousOffset(offset);
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
[
|
|
67
|
+
queryParams,
|
|
68
|
+
queryParams.limit,
|
|
69
|
+
queryParams.value,
|
|
70
|
+
queryParams.offset,
|
|
71
|
+
searchedValue,
|
|
72
|
+
previousOffset,
|
|
73
|
+
getSearchResults,
|
|
74
|
+
entities,
|
|
75
|
+
fields
|
|
76
|
+
]
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
return [
|
|
80
|
+
{ searchedValue: queryParams.value, loading, data: { results: results || jsonResults, total } },
|
|
81
|
+
handleQueryParams
|
|
82
|
+
];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export default useSearch;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
|
+
import useSearch from '../useSearch';
|
|
3
|
+
|
|
4
|
+
function useSearchResults({ queryKey, resultKeys, entities, fields }) {
|
|
5
|
+
const [
|
|
6
|
+
{
|
|
7
|
+
searchedValue,
|
|
8
|
+
loading,
|
|
9
|
+
data: { results, total }
|
|
10
|
+
},
|
|
11
|
+
setParams
|
|
12
|
+
] = useSearch({ queryKey, resultKeys, entities, fields });
|
|
13
|
+
const [currentResults, setCurrentResults] = useState([]);
|
|
14
|
+
const [allResults, setAllResults] = useState([]);
|
|
15
|
+
|
|
16
|
+
useEffect(
|
|
17
|
+
() => {
|
|
18
|
+
if (currentResults.length !== results.length) {
|
|
19
|
+
setAllResults([...allResults, ...results]);
|
|
20
|
+
setCurrentResults(results);
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
[allResults, currentResults, currentResults.length, results]
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
const clearList = params => {
|
|
27
|
+
setAllResults([]);
|
|
28
|
+
setParams({ ...params, offset: 0 });
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const setQueryParams = params => {
|
|
32
|
+
params.value !== searchedValue ? clearList(params) : setParams(params);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
return [{ loading, results: allResults, total }, setQueryParams];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default useSearchResults;
|
package/src/constants.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const SEARCH_ADMIN = 'SEARCH_ADMIN';
|
|
2
|
+
const SEARCH_PUBLISHED = 'SEARCH_PUBLISHED';
|
|
3
|
+
const SEARCH_RESULTS_OVER_SCAN_BUFFER = 0;
|
|
4
|
+
const SEARCH_RESULTS_ELEMETS_HEIGHT_ABOVE_LIST = 186;
|
|
5
|
+
const SEARCH_RESULTS_ITEM_SIZE = 105;
|
|
6
|
+
const DEFAULT_RESULTS_KEYS = 'name, url';
|
|
7
|
+
const SEARCH_BUTTON = 'search-button';
|
|
8
|
+
const FILE = 'file';
|
|
9
|
+
|
|
10
|
+
export {
|
|
11
|
+
SEARCH_ADMIN,
|
|
12
|
+
SEARCH_PUBLISHED,
|
|
13
|
+
SEARCH_RESULTS_OVER_SCAN_BUFFER,
|
|
14
|
+
SEARCH_RESULTS_ELEMETS_HEIGHT_ABOVE_LIST,
|
|
15
|
+
SEARCH_RESULTS_ITEM_SIZE,
|
|
16
|
+
DEFAULT_RESULTS_KEYS,
|
|
17
|
+
SEARCH_BUTTON,
|
|
18
|
+
FILE
|
|
19
|
+
};
|
package/src/index.js
ADDED