/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at . */ // @flow import React, { Component } from "react"; import { CloseButton } from "./Button"; import AccessibleImage from "./AccessibleImage"; import classnames from "classnames"; import "./SearchInput.css"; const arrowBtn = (onClick, type, className, tooltip) => { const props = { className, key: type, onClick, title: tooltip, type }; return ( ); }; type Props = { count: number, expanded: boolean, handleClose?: (e: SyntheticMouseEvent) => void, handleNext?: (e: SyntheticMouseEvent) => void, handlePrev?: (e: SyntheticMouseEvent) => void, hasPrefix?: boolean, onChange: (e: SyntheticInputEvent) => void, onKeyDown: (e: SyntheticKeyboardEvent) => void, onKeyUp?: (e: SyntheticKeyboardEvent) => void, onHistoryScroll?: (historyValue: string) => void, placeholder: string, query: string, selectedItemId?: string, showErrorEmoji: boolean, size: string, summaryMsg: string, showClose: boolean, isLoading: boolean }; type State = { history: Array }; class SearchInput extends Component { displayName: "SearchInput"; $input: ?HTMLInputElement; static defaultProps = { expanded: false, hasPrefix: false, selectedItemId: "", size: "", showClose: true }; constructor(props: Props) { super(props); this.state = { history: [] }; } componentDidMount() { this.setFocus(); } setFocus() { if (this.$input) { const input = this.$input; input.focus(); if (!input.value) { return; } // omit prefix @:# from being selected const selectStartPos = this.props.hasPrefix ? 1 : 0; input.setSelectionRange(selectStartPos, input.value.length + 1); } } renderSvg() { return ; } renderArrowButtons() { const { handleNext, handlePrev } = this.props; return [ arrowBtn( handlePrev, "arrow-up", classnames("nav-btn", "prev"), L10N.getFormatStr("editor.searchResults.prevResult") ), arrowBtn( handleNext, "arrow-down", classnames("nav-btn", "next"), L10N.getFormatStr("editor.searchResults.nextResult") ) ]; } onKeyDown = (e: any) => { const { onHistoryScroll, onKeyDown } = this.props; if (!onHistoryScroll) { return onKeyDown(e); } const inputValue = e.target.value; const { history } = this.state; const currentHistoryIndex = history.indexOf(inputValue); if (e.key === "Enter") { this.saveEnteredTerm(inputValue); return onKeyDown(e); } if (e.key === "ArrowUp") { const previous = currentHistoryIndex > -1 ? currentHistoryIndex - 1 : history.length - 1; const previousInHistory = history[previous]; if (previousInHistory) { e.preventDefault(); onHistoryScroll(previousInHistory); } return; } if (e.key === "ArrowDown") { const next = currentHistoryIndex + 1; const nextInHistory = history[next]; if (nextInHistory) { onHistoryScroll(nextInHistory); } } }; saveEnteredTerm(query: string) { const { history } = this.state; const previousIndex = history.indexOf(query); if (previousIndex !== -1) { history.splice(previousIndex, 1); } history.push(query); this.setState({ history }); } renderSummaryMsg() { const { summaryMsg } = this.props; if (!summaryMsg) { return null; } return
{summaryMsg}
; } renderSpinner() { const { isLoading } = this.props; if (isLoading) { return ; } } renderNav() { const { count, handleNext, handlePrev } = this.props; if ((!handleNext && !handlePrev) || (!count || count == 1)) { return; } return (
{this.renderArrowButtons()}
); } render() { const { expanded, handleClose, onChange, onKeyUp, placeholder, query, selectedItemId, showErrorEmoji, size, showClose } = this.props; const inputProps = { className: classnames({ empty: showErrorEmoji }), onChange, onKeyDown: e => this.onKeyDown(e), onKeyUp, "aria-autocomplete": "list", "aria-controls": "result-list", "aria-activedescendant": expanded && selectedItemId ? `${selectedItemId}-title` : "", placeholder, value: query, spellCheck: false, ref: c => (this.$input = c) }; return (
{this.renderSvg()} {this.renderSpinner()} {this.renderSummaryMsg()} {this.renderNav()} {showClose && ( )}
); } } export default SearchInput;