Skip to content

Commit

Permalink
Moved some things around and added functionality for mouse hovering t…
Browse files Browse the repository at this point in the history
…o change the selected hit. Reworked a bit of the global CSS so mouse hovers don't cause multiple highlights in the dropdown
  • Loading branch information
scissorsneedfoodtoo committed Sep 13, 2019
1 parent b7c0454 commit 0dcfc35
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 49 deletions.
12 changes: 9 additions & 3 deletions client/src/components/layouts/global.css
Expand Up @@ -92,7 +92,7 @@ th {
color: var(--secondary-color);
}

a:hover {
a:not(.fcc_suggestion_item):hover {
color: var(--tertiary-color);
background-color: var(--tertiary-background);
}
Expand Down Expand Up @@ -163,6 +163,7 @@ a:focus {
}

.btn:active:hover,
.btn-primary:hover,
.btn-primary:active:hover,
.btn-primary.active:hover,
.open > .dropdown-toggle.btn-primary:hover,
Expand All @@ -172,10 +173,15 @@ a:focus {
.btn-primary:active.focus,
.btn-primary.active.focus,
.open > .dropdown-toggle.btn-primary.focus {
background-color: var(--secondary-color);
color: var(--secondary-background);
background-color: var(--secondary-color) !important;
color: var(--secondary-background) !important;
}

/* .btn-invert:hover {
background-color: var(--secondary-color) !important;
color: var(--secondary-background) !important;
} */

.btn.disabled,
.btn[disabled],
fieldset[disabled] .btn,
Expand Down
87 changes: 52 additions & 35 deletions client/src/components/search/searchBar/SearchBar.js
Expand Up @@ -49,10 +49,12 @@ class SearchBar extends Component {

this.searchBarRef = React.createRef();
this.handleChange = this.handleChange.bind(this);
this.handlePageClick = this.handlePageClick.bind(this);
this.handleSearch = this.handleSearch.bind(this);
this.handleHits = this.handleHits.bind(this);
this.handleKeyDown = this.handleKeyDown.bind(this);
this.handleMouseEnter = this.handleMouseEnter.bind(this);
this.handleMouseLeave = this.handleMouseLeave.bind(this);
this.handleFocus = this.handleFocus.bind(this);
this.state = {
hitsLength: 0,
index: -1,
Expand All @@ -64,7 +66,7 @@ class SearchBar extends Component {
const searchInput = document.querySelector('.ais-SearchBox-input');
searchInput.id = 'fcc_instantsearch';

document.addEventListener('click', this.handlePageClick);
document.addEventListener('click', this.handleFocus);
}

componentDidUpdate() {
Expand All @@ -79,7 +81,7 @@ class SearchBar extends Component {
}

componentWillUnmount() {
document.removeEventListener('click', this.handlePageClick);
document.addEventListener('click', this.handleFocus);
}

handleChange() {
Expand All @@ -91,15 +93,15 @@ class SearchBar extends Component {
this.setState({ index: -1 });
}

handlePageClick(e) {
handleFocus(e) {
const { toggleSearchFocused } = this.props;
const isSearchFocusedClick = this.searchBarRef.current.contains(e.target);
if (!isSearchFocusedClick) {
const isSearchFocused = this.searchBarRef.current.contains(e.target);
if (!isSearchFocused) {
// Reset if user clicks outside of
// search bar / closes dropdown
this.setState({ index: -1 });
}
return toggleSearchFocused(isSearchFocusedClick);
return toggleSearchFocused(isSearchFocused);
}

handleSearch(e, query) {
Expand All @@ -108,6 +110,7 @@ class SearchBar extends Component {
const { hitsNode, index } = this.state;
// Disable the search dropdown
toggleSearchDropdown(false);

const selectedHit = hitsNode[index];
if (selectedHit) {
// Redirect to hit selected by arrow keys
Expand All @@ -127,32 +130,47 @@ class SearchBar extends Component {
);
}

handleHits(length) {
const { toggleSearchDropdown } = this.props;
if (length !== this.state.hitsLength) {
// Toggle dropdown and reset if the length of hits
handleHits() {
const { isDropdownEnabled, isSearchFocused } = this.props;
if (isDropdownEnabled && isSearchFocused) {
const searchBar = ReactDOM.findDOMNode(this);
const currentHitsNode = searchBar.querySelectorAll(
'.fcc_suggestion_item'
);

// Reset index if the length of hits
// suddenly changes because the dropdown is open
// while the window height moves above / below 768 px
toggleSearchDropdown(false);
this.setState({
index: -1,
hitsLength: length
});
} else {
this.setState({ hitsLength: length });
this.setState(prevState => ({
index:
prevState.hitsLength !== currentHitsNode.length
? -1
: prevState.index,
hitsLength: currentHitsNode.length,
hitsNode: currentHitsNode
}));
}
}

handleMouseEnter(e) {
const { hitsNode } = this.state;
const hoveredIndex = Array.from(hitsNode).indexOf(e.currentTarget);

this.setState({
index: hoveredIndex
});
}

handleMouseLeave() {
this.setState({
index: -1
});
}

handleKeyDown(e) {
const { isDropdownEnabled, isSearchFocused } = this.props;
const { index } = this.state;
const { index, hitsLength } = this.state;
const upKey = e.keyCode === 38;
const downKey = e.keyCode === 40;
const searchBar = ReactDOM.findDOMNode(this);
let currentHitsNode;
if (isDropdownEnabled && isSearchFocused) {
currentHitsNode = searchBar.querySelectorAll('.fcc_suggestion_item');
}

if (upKey || downKey) {
// Prevent cursor from jumping to
Expand All @@ -163,25 +181,21 @@ class SearchBar extends Component {
if (upKey) {
if (index === -1) {
this.setState({
index: currentHitsNode.length - 1,
hitsNode: currentHitsNode
index: hitsLength - 1
});
} else {
this.setState(prevState => ({
index: prevState.index - 1,
hitsNode: currentHitsNode
index: prevState.index - 1
}));
}
} else if (downKey) {
if (index === currentHitsNode.length - 1) {
if (index === hitsLength - 1) {
this.setState({
index: -1,
hitsNode: currentHitsNode
index: -1
});
} else {
this.setState(prevState => ({
index: prevState.index + 1,
hitsNode: currentHitsNode
index: prevState.index + 1
}));
}
}
Expand All @@ -202,14 +216,17 @@ class SearchBar extends Component {
<SearchBox
focusShortcuts={[83, 191]}
onChange={this.handleChange}
onFocus={this.handleFocus}
onKeyDown={this.handleKeyDown}
onSubmit={this.handleSearch}
showLoadingIndicator={true}
translations={{ placeholder }}
/>
{isDropdownEnabled && isSearchFocused && (
<SearchHits
getHitsLength={this.handleHits}
handleHits={this.handleHits}
handleMouseEnter={this.handleMouseEnter}
handleMouseLeave={this.handleMouseLeave}
handleSubmit={this.handleSearch}
/>
)}
Expand Down
32 changes: 26 additions & 6 deletions client/src/components/search/searchBar/SearchHits.js
Expand Up @@ -4,7 +4,14 @@ import isEmpty from 'lodash/isEmpty';
import Suggestion from './SearchSuggestion';

const CustomHits = connectHits(
({ hits, currentRefinement, handleSubmit, getHitsLength }) => {
({
hits,
currentRefinement,
handleSubmit,
handleHits,
handleMouseEnter,
handleMouseLeave
}) => {
const footer = [
{
objectID: `default-hit-${currentRefinement}`,
Expand All @@ -21,8 +28,8 @@ const CustomHits = connectHits(
}
}
];
const allHits = hits.concat(footer);
getHitsLength(allHits.length);
const allHits = hits.filter((_, i) => i < 8).concat(footer);
handleHits();

return (
<div className='ais-Hits'>
Expand All @@ -33,7 +40,12 @@ const CustomHits = connectHits(
data-fccobjectid={hit.objectID}
key={hit.objectID}
>
<Suggestion handleSubmit={handleSubmit} hit={hit} />
<Suggestion
handleMouseEnter={handleMouseEnter}
handleMouseLeave={handleMouseLeave}
handleSubmit={handleSubmit}
hit={hit}
/>
</li>
))}
</ul>
Expand All @@ -43,11 +55,19 @@ const CustomHits = connectHits(
);

const SearchHits = connectStateResults(
({ handleSubmit, getHitsLength, searchState }) => {
({
handleSubmit,
handleHits,
searchState,
handleMouseEnter,
handleMouseLeave
}) => {
return isEmpty(searchState) || !searchState.query ? null : (
<CustomHits
currentRefinement={searchState.query}
getHitsLength={getHitsLength}
handleHits={handleHits}
handleMouseEnter={handleMouseEnter}
handleMouseLeave={handleMouseLeave}
handleSubmit={handleSubmit}
/>
);
Expand Down
11 changes: 10 additions & 1 deletion client/src/components/search/searchBar/SearchSuggestion.js
Expand Up @@ -3,7 +3,12 @@ import PropTypes from 'prop-types';
import { Highlight } from 'react-instantsearch-dom';
import { isEmpty } from 'lodash';

const Suggestion = ({ handleSubmit, hit }) => {
const Suggestion = ({
handleSubmit,
hit,
handleMouseEnter,
handleMouseLeave
}) => {
const dropdownFooter = hit.objectID.includes('default-hit-');
return isEmpty(hit) || isEmpty(hit.objectID) ? null : (
<a
Expand All @@ -18,6 +23,8 @@ const Suggestion = ({ handleSubmit, hit }) => {
: hit.url
}
onClick={e => (dropdownFooter ? handleSubmit(e, hit.query) : '')}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
<span className='hit-name'>
{dropdownFooter ? (
Expand All @@ -31,6 +38,8 @@ const Suggestion = ({ handleSubmit, hit }) => {
};

Suggestion.propTypes = {
handleMouseEnter: PropTypes.func.isRequired,
handleMouseLeave: PropTypes.func.isRequired,
handleSubmit: PropTypes.func.isRequired,
hit: PropTypes.object
};
Expand Down
6 changes: 2 additions & 4 deletions client/src/components/search/searchBar/searchbar.css
Expand Up @@ -10,13 +10,12 @@
color: var(--gray-00);
}

.ais-SearchBox-submit,
.ais-SearchBox-reset {
display: none;
}

.ais-SearchBox-input {
padding: 1px 10px;
padding: 1px 10px 1px 30px;
font-size: 18px;
}

Expand Down Expand Up @@ -78,7 +77,7 @@
.fcc_suggestion_item {
display: block;
padding: 8px;
color: var(--gray-00);
color: var(--gray-00) !important;
text-decoration: none;
}

Expand All @@ -87,7 +86,6 @@
}

.fcc_suggestion_item:hover {
background-color: var(--blue-dark);
cursor: pointer;
}

Expand Down

0 comments on commit 0dcfc35

Please sign in to comment.