Skip to content

Commit

Permalink
feat: Add typing with auto-complete to select a filter field in the d…
Browse files Browse the repository at this point in the history
…ata browser (parse-community#2463)
  • Loading branch information
patelmilanun authored Jun 19, 2023
1 parent 5f94fb0 commit 257f76b
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 14 deletions.
37 changes: 31 additions & 6 deletions src/components/Autocomplete/Autocomplete.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export default class Autocomplete extends Component {
this.onBlur = this.onBlur.bind(this);

this.onClick = this.onClick.bind(this);
this.onMouseDown = this.onMouseDown.bind(this);
this.onChange = this.onChange.bind(this);
this.onKeyDown = this.onKeyDown.bind(this);
this.onInputClick = this.onInputClick.bind(this);
Expand All @@ -46,10 +47,11 @@ export default class Autocomplete extends Component {
};

this.state = {
valueFromSuggestion: props.strict ? props.value ?? props.suggestions[0] : '',
activeSuggestion: 0,
filteredSuggestions: [],
showSuggestions: false,
userInput: '',
userInput: props.strict ? props.value ?? props.suggestions[0] : '',
label: props.label,
position: null
};
Expand All @@ -60,6 +62,7 @@ export default class Autocomplete extends Component {
this.fieldRef.current.addEventListener('scroll', this.handleScroll);
this.recalculatePosition();
this._ignoreBlur = false;
this._suggestionClicked = false;
}

componentWillUnmount() {
Expand Down Expand Up @@ -120,11 +123,12 @@ export default class Autocomplete extends Component {
error: undefined
});

this.props.onChange && this.props.onChange(userInput);
if (!this.props.strict) this.props.onChange && this.props.onChange(userInput);
}

onClick(e) {
const userInput = e.currentTarget.innerText;
if (this.props.strict) this.props.onChange && this.props.onChange(userInput);
const label = this.props.label || this.props.buildLabel(userInput);

this.inputRef.current.focus();
Expand All @@ -144,15 +148,33 @@ export default class Autocomplete extends Component {
);
}

onMouseDown(e) {
this._suggestionClicked = true;
this.props.onMouseDown && this.props.onMouseDown(e);
}

onFocus(e) {
if (!this._ignoreBlur && !this.state.showSuggestions) {
this._ignoreBlur = true;
}

if(this.props.strict) e.target.select();
this.activate(e);
}

onBlur(e) {
if (this.props.strict) {
if (!this._suggestionClicked) {
if (!this.props.suggestions.includes(this.state.userInput)) {
this.setState({ userInput: this.state.valueFromSuggestion });
this.props.onChange &&
this.props.onChange(this.state.valueFromSuggestion);
} else {
this.setState({ valueFromSuggestion: this.state.userInput });
this.props.onChange && this.props.onChange(this.state.userInput);
}
}
this._suggestionClicked = false;
}
this.props.onBlur && this.props.onBlur(e);
}

Expand Down Expand Up @@ -279,9 +301,10 @@ export default class Autocomplete extends Component {
onChange,
onClick,
onBlur,
onMouseDown,
onFocus,
onKeyDown,
props: { suggestionsStyle, inputStyle, placeholder, error },
props: {suggestionsStyle, suggestionsItemStyle, inputStyle, containerStyle, placeholder, error },
state: {
activeSuggestion,
filteredSuggestions,
Expand Down Expand Up @@ -314,19 +337,21 @@ export default class Autocomplete extends Component {
onExternalClick={onExternalClick}
suggestions={filteredSuggestions}
suggestionsStyle={suggestionsStyle}
suggestionsItemStyle={suggestionsItemStyle}
activeSuggestion={activeSuggestion}
onClick={onClick}
onMouseDown={onMouseDown}
/>
);
}

return (
<React.Fragment>
<div className={fieldClassName} ref={this.fieldRef}>
<div style={containerStyle} className={fieldClassName} ref={this.fieldRef}>
<input
id={1}
role={'combobox'}
autoComplete='off'
autoComplete="new-password"
className={inputClasses}
placeholder={placeholder}
ref={this.inputRef}
Expand Down
46 changes: 41 additions & 5 deletions src/components/BrowserFilter/FilterRow.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* the root directory of this source tree.
*/
import ChromeDropdown from 'components/ChromeDropdown/ChromeDropdown.react';
import Autocomplete from 'components/Autocomplete/Autocomplete.react';
import { Constraints } from 'lib/Filters';
import DateTimeEntry from 'components/DateTimeEntry/DateTimeEntry.react';
import Icon from 'components/Icon/Icon.react';
Expand Down Expand Up @@ -92,15 +93,50 @@ let FilterRow = ({
if (input !== null && editMode) {
input.focus();
}
}, [])
}, [])

const buildSuggestions = (input) => {
const regex = new RegExp(input.split('').join('.*?'), 'i');
return fields.filter(f => regex.test(f));
};

return (
<div className={styles.row}>
<ChromeDropdown
color={active ? 'blue' : 'purple'}
<Autocomplete
inputStyle={{
transition: '0s background-color ease-in-out',
}}
suggestionsStyle={{
width: '140px',
maxHeight: '360px',
overflowY: 'auto',
fontSize: '14px',
background: '#343445',
borderBottomLeftRadius: '5px',
borderBottomRightRadius: '5px',
color: 'white',
cursor: 'pointer',
}}
suggestionsItemStyle={{
background: '#343445',
color: 'white',
height: '30px',
lineHeight: '30px',
borderBottom: '0px',
}}
containerStyle={{
display: 'inline-block',
width: '140px',
verticalAlign: 'top',
height: '30px',
}}
strict={true}
value={currentField}
options={fields}
onChange={onChangeField} />
suggestions={fields}
onChange={onChangeField}
buildSuggestions={buildSuggestions}
buildLabel={() => ''}
/>
<ChromeDropdown
width={compareInfo.type ? '175' : '325'}
color={active ? 'blue' : 'purple'}
Expand Down
8 changes: 8 additions & 0 deletions src/components/Popover/Popover.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ export default class Popover extends React.Component {
this._popoverLayer.dataset.parentContentId = this.props.parentContentId;
}

if (this.props['data-popover-type']) {
this._popoverLayer.setAttribute('data-popover-type', this.props['data-popover-type']);
}

document.body.addEventListener('click', this._checkExternalClick);
}

Expand All @@ -79,8 +83,12 @@ export default class Popover extends React.Component {
? document.getElementById(contentId)
: this._popoverLayer;
const isChromeDropdown = e.target.parentNode.classList.contains('chromeDropdown');
// Find the inner popover element so on clicking inside it
// we can prevent external click function
const innerPopover = e.target.closest('[data-popover-type="inner"]');
if (
!hasAncestor(e.target, popoverWrapper, contentId) &&
!innerPopover &&
this.props.onExternalClick &&
!isChromeDropdown
) {
Expand Down
9 changes: 6 additions & 3 deletions src/components/SuggestionsList/SuggestionsList.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,23 @@ export default class Suggestion extends React.Component {
}

render() {
const {
const {
position,
onExternalClick,
suggestions,
suggestionsStyle,
suggestionsItemStyle,
activeSuggestion,
onClick} = this.props;
onClick,
onMouseDown} = this.props;

return (
<Popover
fixed={false}
position={position}
ref={this.popoverRef}
onExternalClick={onExternalClick}
data-popover-type="inner"
>
<ul style={suggestionsStyle} className={styles.suggestions}>
{suggestions.map((suggestion, index) => {
Expand All @@ -57,7 +60,7 @@ export default class Suggestion extends React.Component {
className = styles.active;
}
return (
<li className={className} key={suggestion} onClick={onClick}>
<li style={suggestionsItemStyle} className={className} key={suggestion} onMouseDown={onMouseDown} onClick={onClick}>
{suggestion}
</li>
);
Expand Down

0 comments on commit 257f76b

Please sign in to comment.