diff --git a/app/soapbox/components/autosuggest_input.js b/app/soapbox/components/autosuggest_input.js index 8f750ab3f..8bf5e86fa 100644 --- a/app/soapbox/components/autosuggest_input.js +++ b/app/soapbox/components/autosuggest_input.js @@ -47,6 +47,7 @@ export default class AutosuggestInput extends ImmutablePureComponent { onKeyUp: PropTypes.func, onKeyDown: PropTypes.func, autoFocus: PropTypes.bool, + autoSelect: PropTypes.bool, className: PropTypes.string, id: PropTypes.string, searchTokens: PropTypes.arrayOf(PropTypes.string), @@ -55,13 +56,18 @@ export default class AutosuggestInput extends ImmutablePureComponent { static defaultProps = { autoFocus: false, + autoSelect: true, searchTokens: ImmutableList(['@', ':', '#']), }; + getFirstIndex = () => { + return this.props.autoSelect ? 0 : -1; + } + state = { suggestionsHidden: true, focused: false, - selectedSuggestion: 0, + selectedSuggestion: this.getFirstIndex(), lastToken: null, tokenStart: 0, }; @@ -83,6 +89,7 @@ export default class AutosuggestInput extends ImmutablePureComponent { onKeyDown = (e) => { const { suggestions, disabled } = this.props; const { selectedSuggestion, suggestionsHidden } = this.state; + const firstIndex = this.getFirstIndex(); if (disabled) { e.preventDefault(); @@ -115,16 +122,17 @@ export default class AutosuggestInput extends ImmutablePureComponent { case 'ArrowUp': if (suggestions.size > 0 && !suggestionsHidden) { e.preventDefault(); - this.setState({ selectedSuggestion: Math.max(selectedSuggestion - 1, 0) }); + this.setState({ selectedSuggestion: Math.max(selectedSuggestion - 1, firstIndex) }); } break; case 'Enter': case 'Tab': // Select suggestion - if (suggestions.size > 0 && !suggestionsHidden) { + if (suggestions.size > 0 && !suggestionsHidden && selectedSuggestion > -1) { e.preventDefault(); e.stopPropagation(); + this.setState({ selectedSuggestion: firstIndex }); this.props.onSuggestionSelected(this.state.tokenStart, this.state.lastToken, suggestions.get(selectedSuggestion)); } diff --git a/app/soapbox/features/compose/components/search.js b/app/soapbox/features/compose/components/search.js index 6489b4e32..73a7c035f 100644 --- a/app/soapbox/features/compose/components/search.js +++ b/app/soapbox/features/compose/components/search.js @@ -2,6 +2,7 @@ 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({ @@ -22,13 +23,16 @@ class Search extends React.PureComponent { onSubmit: PropTypes.func.isRequired, onClear: PropTypes.func.isRequired, onShow: PropTypes.func.isRequired, + onSelected: PropTypes.func, openInRoute: PropTypes.bool, autoFocus: PropTypes.bool, + autosuggest: PropTypes.bool, intl: PropTypes.object.isRequired, }; static defaultProps = { autoFocus: false, + ausosuggest: false, } state = { @@ -47,7 +51,7 @@ class Search extends React.PureComponent { } } - handleKeyUp = (e) => { + handleKeyDown = (e) => { if (e.key === 'Enter') { e.preventDefault(); @@ -70,24 +74,36 @@ class Search extends React.PureComponent { this.setState({ expanded: false }); } + handleSelected = accountId => { + const { onSelected } = this.props; + + if (onSelected) { + onSelected(accountId, this.context.router.history); + } + } + render() { - const { intl, value, autoFocus, submitted } = this.props; + const { intl, value, autoFocus, autosuggest, submitted } = this.props; const hasValue = value.length > 0 || submitted; + const Component = autosuggest ? AutosuggestAccountInput : 'input'; + return (
diff --git a/app/soapbox/features/compose/containers/search_container.js b/app/soapbox/features/compose/containers/search_container.js index e6484216c..f11a6af05 100644 --- a/app/soapbox/features/compose/containers/search_container.js +++ b/app/soapbox/features/compose/containers/search_container.js @@ -13,6 +13,16 @@ const mapStateToProps = state => ({ submitted: state.getIn(['search', 'submitted']), }); +function redirectToAccount(accountId, routerHistory) { + return (dispatch, getState) => { + const acct = getState().getIn(['accounts', accountId, 'acct']); + + if (acct && routerHistory) { + routerHistory.push(`/@${acct}`); + } + }; +} + const mapDispatchToProps = (dispatch, { autoSubmit }) => { const debouncedSubmit = debounce(() => { @@ -40,6 +50,11 @@ const mapDispatchToProps = (dispatch, { autoSubmit }) => { dispatch(showSearch()); }, + onSelected(accountId, routerHistory) { + dispatch(clearSearch()); + dispatch(redirectToAccount(accountId, routerHistory)); + }, + }; }; diff --git a/app/soapbox/features/ui/components/tabs_bar.js b/app/soapbox/features/ui/components/tabs_bar.js index a4b1d5bb5..959ce245c 100644 --- a/app/soapbox/features/ui/components/tabs_bar.js +++ b/app/soapbox/features/ui/components/tabs_bar.js @@ -88,7 +88,7 @@ class TabsBar extends React.PureComponent { )}
- +
diff --git a/app/styles/components/search.scss b/app/styles/components/search.scss index 39c56a308..b3e56eaac 100644 --- a/app/styles/components/search.scss +++ b/app/styles/components/search.scss @@ -2,7 +2,7 @@ position: relative; } -.search__input { +input.search__input { @include search-input; display: block; padding: 7px 30px 6px 10px; @@ -177,7 +177,7 @@ border-bottom: 1px solid hsla(var(--primary-text-color_hsl), 0.2); } - .search__input { + input.search__input { background-color: var(--background-color); border-radius: 8px; padding: 12px 36px 12px 16px; @@ -202,3 +202,7 @@ } } } + +.search .autosuggest-textarea__suggestions { + border-radius: 4px; +} diff --git a/app/styles/components/tabs-bar.scss b/app/styles/components/tabs-bar.scss index 037f70251..2827206d5 100644 --- a/app/styles/components/tabs-bar.scss +++ b/app/styles/components/tabs-bar.scss @@ -3,7 +3,6 @@ box-sizing: border-box; background: var(--brand-color); flex: 0 0 auto; - overflow-y: auto; height: 50px; width: 100%; position: sticky;