Create AccountSearch component to do more than AutosuggestAccountInput

profile-avatar-switcher
Alex Gleason 2021-10-14 11:47:10 -05:00
rodzic b0b13e9e59
commit a02112a1c8
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 7211D1F99744FBB7
4 zmienionych plików z 112 dodań i 18 usunięć

Wyświetl plik

@ -0,0 +1,83 @@
import React from 'react';
import PropTypes from 'prop-types';
import { defineMessages, injectIntl } from 'react-intl';
import Icon from 'soapbox/components/icon';
import AutosuggestAccountInput from 'soapbox/components/autosuggest_account_input';
import classNames from 'classnames';
const messages = defineMessages({
placeholder: { id: 'account_search.placeholder', defaultMessage: 'Search for an account' },
});
export default @injectIntl
class AccountSearch extends React.PureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
onSelected: PropTypes.func.isRequired,
};
state = {
value: '',
}
isEmpty = () => {
const { value } = this.state;
return !(value.length > 0);
}
clearState = () => {
this.setState({ value: '' });
}
handleChange = ({ target }) => {
this.setState({ value: target.value });
}
handleSelected = accountId => {
this.clearState();
this.props.onSelected(accountId);
}
handleClear = e => {
e.preventDefault();
if (!this.isEmpty()) {
this.setState({ value: '' });
}
}
handleKeyDown = e => {
if (e.key === 'Escape') {
document.querySelector('.ui').parentElement.focus();
}
}
render() {
const { intl, onSelected, ...rest } = this.props;
const { value } = this.state;
const isEmpty = this.isEmpty();
return (
<div className='search search--account'>
<label>
<span style={{ display: 'none' }}>{intl.formatMessage(messages.placeholder)}</span>
<AutosuggestAccountInput
className='search__input'
placeholder={intl.formatMessage(messages.placeholder)}
value={value}
onChange={this.handleChange}
onSelected={this.handleSelected}
onKeyDown={this.handleKeyDown}
{...rest}
/>
</label>
<div role='button' tabIndex='0' className='search__icon' onClick={this.handleClear}>
<Icon src={require('@tabler/icons/icons/search.svg')} className={classNames('svg-icon--search', { active: isEmpty })} />
<Icon src={require('@tabler/icons/icons/backspace.svg')} className={classNames('svg-icon--backspace', { active: !isEmpty })} aria-label={intl.formatMessage(messages.placeholder)} />
</div>
</div>
);
}
}

Wyświetl plik

@ -4,34 +4,29 @@ import PropTypes from 'prop-types';
import { CancelToken } from 'axios';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import { injectIntl, defineMessages } from 'react-intl';
import { OrderedSet as ImmutableOrderedSet } from 'immutable';
import { accountSearch } from 'soapbox/actions/accounts';
import { throttle } from 'lodash';
const noOp = () => {};
const messages = defineMessages({
placeholder: { id: 'autosuggest_account_input.default_placeholder', defaultMessage: 'Search for an account' },
});
export default @connect()
@injectIntl
class AutosuggestAccountInput extends ImmutablePureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired,
onSelected: PropTypes.func.isRequired,
limit: PropTypes.number,
value: PropTypes.string.isRequired,
limit: PropTypes.number.isRequired,
}
static defaultProps = {
value: '',
limit: 4,
}
state = {
text: '',
accountIds: ImmutableOrderedSet(),
}
@ -43,6 +38,10 @@ class AutosuggestAccountInput extends ImmutablePureComponent {
return this.source;
}
clearResults = () => {
this.setState({ accountIds: ImmutableOrderedSet() });
}
handleAccountSearch = throttle(q => {
const { dispatch, limit } = this.props;
const source = this.refreshCancelToken();
@ -58,23 +57,28 @@ class AutosuggestAccountInput extends ImmutablePureComponent {
}, 900, { leading: true, trailing: true })
handleChange = ({ target }) => {
this.handleAccountSearch(target.value);
this.setState({ text: target.value });
handleChange = e => {
this.handleAccountSearch(e.target.value);
this.props.onChange(e);
}
handleSelected = (tokenStart, lastToken, accountId) => {
this.props.onSelected(accountId);
}
componentDidUpdate(prevProps) {
if (this.props.value === '' && prevProps.value !== '') {
this.clearResults();
}
}
render() {
const { intl, ...rest } = this.props;
const { text, accountIds } = this.state;
const { intl, value, onChange, ...rest } = this.props;
const { accountIds } = this.state;
return (
<AutosuggestInput
placeholder={intl.formatMessage(messages.placeholder)}
value={text}
value={value}
onChange={this.handleChange}
suggestions={accountIds.toList()}
onSuggestionsFetchRequested={noOp}

Wyświetl plik

@ -8,10 +8,11 @@ import { expandDirectTimeline } from '../../actions/timelines';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import { connectDirectStream } from '../../actions/streaming';
import { directComposeById } from 'soapbox/actions/compose';
import AutosuggestAccountInput from 'soapbox/components/autosuggest_account_input';
import AccountSearch from 'soapbox/components/account_search';
const messages = defineMessages({
title: { id: 'column.direct', defaultMessage: 'Direct messages' },
searchPlaceholder: { id: 'direct.search_placeholder', defaultMessage: 'Search for an account to message…' },
});
const mapStateToProps = state => ({
@ -62,7 +63,10 @@ class DirectTimeline extends React.PureComponent {
onPin={this.handlePin}
/>
<AutosuggestAccountInput onSelected={this.handleSuggestion} />
<AccountSearch
placeholder={intl.formatMessage(messages.searchPlaceholder)}
onSelected={this.handleSuggestion}
/>
<StatusListContainer
scrollKey='direct_timeline'

Wyświetl plik

@ -167,9 +167,12 @@
.search-page {
height: 100%;
}
.column {
.search {
padding: 10px 15px;
background-color: var(--foreground-color);
border-bottom: 1px solid hsla(var(--primary-text-color_hsl), 0.2);
}