|
|
@@ -1,262 +1,340 @@
|
|
|
-import React from 'react';
|
|
|
-import PropTypes from 'prop-types';
|
|
|
+import React, { FC, useReducer, useState } from 'react';
|
|
|
|
|
|
import { AsyncTypeahead } from 'react-bootstrap-typeahead';
|
|
|
|
|
|
import { UserPicture, PageListMeta, PagePathLabel } from '@growi/ui';
|
|
|
|
|
|
import { apiGet } from '~/client/util/apiv1-client';
|
|
|
+import { IPage } from '~/interfaces/page';
|
|
|
|
|
|
-class SearchTypeahead extends React.Component {
|
|
|
-
|
|
|
- constructor(props) {
|
|
|
-
|
|
|
- super(props);
|
|
|
-
|
|
|
- this.state = {
|
|
|
- input: this.props.keywordOnInit,
|
|
|
- pages: [],
|
|
|
- isLoading: false,
|
|
|
- searchError: null,
|
|
|
- };
|
|
|
-
|
|
|
- this.restoreInitialData = this.restoreInitialData.bind(this);
|
|
|
- this.clearKeyword = this.clearKeyword.bind(this);
|
|
|
- this.changeKeyword = this.changeKeyword.bind(this);
|
|
|
- this.search = this.search.bind(this);
|
|
|
- this.onInputChange = this.onInputChange.bind(this);
|
|
|
- this.onKeyDown = this.onKeyDown.bind(this);
|
|
|
- this.dispatchSubmit = this.dispatchSubmit.bind(this);
|
|
|
- this.getEmptyLabel = this.getEmptyLabel.bind(this);
|
|
|
- this.getResetFormButton = this.getResetFormButton.bind(this);
|
|
|
- this.renderMenuItemChildren = this.renderMenuItemChildren.bind(this);
|
|
|
- this.getTypeahead = this.getTypeahead.bind(this);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Get instance of AsyncTypeahead
|
|
|
- */
|
|
|
- getTypeahead() {
|
|
|
- return this.typeahead ? this.typeahead.getInstance() : null;
|
|
|
- }
|
|
|
-
|
|
|
- componentDidMount() {
|
|
|
- }
|
|
|
-
|
|
|
- componentWillUnmount() {
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Initialize keywordyword
|
|
|
- */
|
|
|
- restoreInitialData() {
|
|
|
- this.changeKeyword(this.props.keywordOnInit);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * clear keyword
|
|
|
- */
|
|
|
- clearKeyword(text) {
|
|
|
- this.changeKeyword('');
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * change keyword
|
|
|
- */
|
|
|
- changeKeyword(text) {
|
|
|
- // see https://github.com/ericgio/react-bootstrap-typeahead/issues/266#issuecomment-414987723
|
|
|
- const instance = this.typeahead.getInstance();
|
|
|
- instance.clear();
|
|
|
- instance.setState({ text });
|
|
|
- }
|
|
|
-
|
|
|
- search(keyword) {
|
|
|
-
|
|
|
- if (keyword === '') {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- this.setState({ isLoading: true });
|
|
|
-
|
|
|
- apiGet('/search', { q: keyword })
|
|
|
- .then((res) => { this.onSearchSuccess(res) })
|
|
|
- .catch((err) => { this.onSearchError(err) });
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Callback function which is occured when search is exit successfully
|
|
|
- * @param {*} pages
|
|
|
- */
|
|
|
- onSearchSuccess(res) {
|
|
|
- this.setState({
|
|
|
- isLoading: false,
|
|
|
- pages: res.data,
|
|
|
- });
|
|
|
- if (this.props.onSearchSuccess != null) {
|
|
|
- this.props.onSearchSuccess(res);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Callback function which is occured when search is exit abnormaly
|
|
|
- * @param {*} err
|
|
|
- */
|
|
|
- onSearchError(err) {
|
|
|
- this.setState({
|
|
|
- isLoading: false,
|
|
|
- searchError: err,
|
|
|
- });
|
|
|
- if (this.props.onSearchError != null) {
|
|
|
- this.props.onSearchError(err);
|
|
|
- }
|
|
|
- }
|
|
|
|
|
|
- onInputChange(text) {
|
|
|
- this.setState({ input: text });
|
|
|
- this.props.onInputChange(text);
|
|
|
- if (text === '') {
|
|
|
- this.setState({ pages: [] });
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- onKeyDown(event) {
|
|
|
- if (event.keyCode === 13) {
|
|
|
- this.dispatchSubmit();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- dispatchSubmit() {
|
|
|
- if (this.props.onSubmit != null) {
|
|
|
- this.props.onSubmit(this.state.input);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- getEmptyLabel() {
|
|
|
- const { emptyLabel, helpElement } = this.props;
|
|
|
- const { input } = this.state;
|
|
|
-
|
|
|
- // show help element if empty
|
|
|
- if (input.length === 0) {
|
|
|
- return helpElement;
|
|
|
- }
|
|
|
-
|
|
|
- // use props.emptyLabel as is if defined
|
|
|
- if (emptyLabel !== undefined) {
|
|
|
- return this.props.emptyLabel;
|
|
|
- }
|
|
|
-
|
|
|
- let emptyLabelExceptError = 'No matches found on title...';
|
|
|
- if (this.props.emptyLabelExceptError !== undefined) {
|
|
|
- emptyLabelExceptError = this.props.emptyLabelExceptError;
|
|
|
- }
|
|
|
+type ResetFormButtonProps = {
|
|
|
+ keywordOnInit: string,
|
|
|
+ behaviorOfResetBtn: 'restore' | 'clear',
|
|
|
+ input: string,
|
|
|
+ onReset: () => void,
|
|
|
+}
|
|
|
|
|
|
- return (this.state.searchError !== null)
|
|
|
- ? 'Error on searching.'
|
|
|
- : emptyLabelExceptError;
|
|
|
- }
|
|
|
+const ResetFormButton: FC<ResetFormButtonProps> = (props: ResetFormButtonProps) => {
|
|
|
+ const isClearBtn = props.behaviorOfResetBtn === 'clear';
|
|
|
+ const initialKeyword = isClearBtn ? '' : props.keywordOnInit;
|
|
|
+ const isHidden = props.input === initialKeyword;
|
|
|
+
|
|
|
+ return isHidden ? (
|
|
|
+ <span />
|
|
|
+ ) : (
|
|
|
+ <button type="button" className="btn btn-link search-clear" onMouseDown={props.onReset}>
|
|
|
+ <i className="icon-close" />
|
|
|
+ </button>
|
|
|
+ );
|
|
|
+};
|
|
|
|
|
|
- /**
|
|
|
- * Get restore form button to initialize button
|
|
|
- */
|
|
|
- getResetFormButton() {
|
|
|
- const isClearBtn = this.props.behaviorOfResetBtn === 'clear';
|
|
|
- const initialKeyword = isClearBtn ? '' : this.props.keywordOnInit;
|
|
|
- const isHidden = this.state.input === initialKeyword;
|
|
|
- const resetForm = isClearBtn ? this.clearKeyword : this.restoreInitialData;
|
|
|
-
|
|
|
- return isHidden ? (
|
|
|
- <span />
|
|
|
- ) : (
|
|
|
- <button type="button" className="btn btn-link search-clear" onMouseDown={resetForm}>
|
|
|
- <i className="icon-close" />
|
|
|
- </button>
|
|
|
- );
|
|
|
- }
|
|
|
|
|
|
- renderMenuItemChildren(option, props, index) {
|
|
|
- const page = option;
|
|
|
- return (
|
|
|
- <span>
|
|
|
- <UserPicture user={page.lastUpdateUser} size="sm" noLink />
|
|
|
- <span className="ml-1 text-break text-wrap"><PagePathLabel page={page} /></span>
|
|
|
- <PageListMeta page={page} />
|
|
|
- </span>
|
|
|
- );
|
|
|
- }
|
|
|
+type Props = {
|
|
|
+ onSearchSuccess?: () => void,
|
|
|
+ onSearchError?: () => void,
|
|
|
+ onChange?: () => void,
|
|
|
+ onBlur?: () => void,
|
|
|
+ onFocus?: () => void,
|
|
|
+ onSubmit?: () => void,
|
|
|
+ onInputChange?: () => void,
|
|
|
+ inputName?: string,
|
|
|
+ emptyLabel?: string,
|
|
|
+ emptyLabelExceptError?: string,
|
|
|
+ placeholder?: string,
|
|
|
+ keywordOnInit?: string,
|
|
|
+ helpElement?: any,
|
|
|
+ autoFocus?: boolean,
|
|
|
+ behaviorOfResetBtn?: 'restore' | 'clear',
|
|
|
+};
|
|
|
|
|
|
- render() {
|
|
|
- const defaultSelected = (this.props.keywordOnInit !== '')
|
|
|
- ? [{ path: this.props.keywordOnInit }]
|
|
|
- : [];
|
|
|
- const inputProps = { autoComplete: 'off' };
|
|
|
- if (this.props.inputName != null) {
|
|
|
- inputProps.name = this.props.inputName;
|
|
|
- }
|
|
|
-
|
|
|
- const resetFormButton = this.getResetFormButton();
|
|
|
-
|
|
|
- return (
|
|
|
- <div className="search-typeahead">
|
|
|
- <AsyncTypeahead
|
|
|
- {...this.props}
|
|
|
- id="search-typeahead-asynctypeahead"
|
|
|
- ref={(c) => { this.typeahead = c }}
|
|
|
- inputProps={inputProps}
|
|
|
- isLoading={this.state.isLoading}
|
|
|
- labelKey="path"
|
|
|
- minLength={0}
|
|
|
- options={this.state.pages} // Search result (Some page names)
|
|
|
- promptText={this.props.helpElement}
|
|
|
- emptyLabel={this.getEmptyLabel()}
|
|
|
- align="left"
|
|
|
- submitFormOnEnter
|
|
|
- onSearch={this.search}
|
|
|
- onInputChange={this.onInputChange}
|
|
|
- onKeyDown={this.onKeyDown}
|
|
|
- renderMenuItemChildren={this.renderMenuItemChildren}
|
|
|
- caseSensitive={false}
|
|
|
- defaultSelected={defaultSelected}
|
|
|
- autoFocus={this.props.autoFocus}
|
|
|
- onBlur={this.props.onBlur}
|
|
|
- onFocus={this.props.onFocus}
|
|
|
- />
|
|
|
- {resetFormButton}
|
|
|
- </div>
|
|
|
- );
|
|
|
+export const SearchTypeahead: FC<Props> = (props: Props) => {
|
|
|
+
|
|
|
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
|
+ const [input, setInput] = useState(props.keywordOnInit!);
|
|
|
+ const [pages, setPages] = useState<IPage>();
|
|
|
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
|
+ const [searchError, setSearchError] = useState<any>(null);
|
|
|
+ const [isLoading, setLoaded] = useReducer(() => true, false);
|
|
|
+
|
|
|
+ const defaultSelected = (props.keywordOnInit !== '')
|
|
|
+ ? [{ path: props.keywordOnInit }]
|
|
|
+ : [];
|
|
|
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
|
+ const inputProps: any = { autoComplete: 'off' };
|
|
|
+ if (props.inputName != null) {
|
|
|
+ inputProps.name = props.inputName;
|
|
|
}
|
|
|
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * Properties
|
|
|
- */
|
|
|
-SearchTypeahead.propTypes = {
|
|
|
- onSearchSuccess: PropTypes.func,
|
|
|
- onSearchError: PropTypes.func,
|
|
|
- onChange: PropTypes.func,
|
|
|
- onBlur: PropTypes.func,
|
|
|
- onFocus: PropTypes.func,
|
|
|
- onSubmit: PropTypes.func,
|
|
|
- onInputChange: PropTypes.func,
|
|
|
- inputName: PropTypes.string,
|
|
|
- emptyLabel: PropTypes.string,
|
|
|
- emptyLabelExceptError: PropTypes.string,
|
|
|
- placeholder: PropTypes.string,
|
|
|
- keywordOnInit: PropTypes.string,
|
|
|
- helpElement: PropTypes.object,
|
|
|
- autoFocus: PropTypes.bool,
|
|
|
- behaviorOfResetBtn: PropTypes.oneOf(['restore', 'clear']),
|
|
|
+ const isClearBtn = props.behaviorOfResetBtn === 'clear';
|
|
|
+ // const resetForm = isClearBtn ? this.clearKeyword : this.restoreInitialData;
|
|
|
+ const resetForm = () => {};
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div className="search-typeahead">
|
|
|
+ <AsyncTypeahead
|
|
|
+ {...props}
|
|
|
+ id="search-typeahead-asynctypeahead"
|
|
|
+ // ref={(c) => { this.typeahead = c }}
|
|
|
+ inputProps={inputProps}
|
|
|
+ isLoading={isLoading}
|
|
|
+ labelKey="path"
|
|
|
+ minLength={0}
|
|
|
+ options={pages} // Search result (Some page names)
|
|
|
+ promptText={props.helpElement}
|
|
|
+ // emptyLabel={this.getEmptyLabel()}
|
|
|
+ align="left"
|
|
|
+ submitFormOnEnter
|
|
|
+ // onSearch={this.search}
|
|
|
+ // onInputChange={this.onInputChange}
|
|
|
+ // onKeyDown={this.onKeyDown}
|
|
|
+ // renderMenuItemChildren={this.renderMenuItemChildren}
|
|
|
+ caseSensitive={false}
|
|
|
+ defaultSelected={defaultSelected}
|
|
|
+ autoFocus={props.autoFocus}
|
|
|
+ onBlur={props.onBlur}
|
|
|
+ onFocus={props.onFocus}
|
|
|
+ />
|
|
|
+ <ResetFormButton
|
|
|
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
|
+ keywordOnInit={props.keywordOnInit!}
|
|
|
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
|
+ behaviorOfResetBtn={props.behaviorOfResetBtn!}
|
|
|
+ input={input}
|
|
|
+ onReset={resetForm}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ );
|
|
|
};
|
|
|
|
|
|
+// class SearchTypeahead extends React.Component {
|
|
|
+
|
|
|
+// constructor(props) {
|
|
|
+
|
|
|
+// super(props);
|
|
|
+
|
|
|
+// this.state = {
|
|
|
+// input: this.props.keywordOnInit,
|
|
|
+// pages: [],
|
|
|
+// isLoading: false,
|
|
|
+// searchError: null,
|
|
|
+// };
|
|
|
+
|
|
|
+// this.restoreInitialData = this.restoreInitialData.bind(this);
|
|
|
+// this.clearKeyword = this.clearKeyword.bind(this);
|
|
|
+// this.changeKeyword = this.changeKeyword.bind(this);
|
|
|
+// this.search = this.search.bind(this);
|
|
|
+// this.onInputChange = this.onInputChange.bind(this);
|
|
|
+// this.onKeyDown = this.onKeyDown.bind(this);
|
|
|
+// this.dispatchSubmit = this.dispatchSubmit.bind(this);
|
|
|
+// this.getEmptyLabel = this.getEmptyLabel.bind(this);
|
|
|
+// this.getResetFormButton = this.getResetFormButton.bind(this);
|
|
|
+// this.renderMenuItemChildren = this.renderMenuItemChildren.bind(this);
|
|
|
+// this.getTypeahead = this.getTypeahead.bind(this);
|
|
|
+// }
|
|
|
+
|
|
|
+// /**
|
|
|
+// * Get instance of AsyncTypeahead
|
|
|
+// */
|
|
|
+// getTypeahead() {
|
|
|
+// return this.typeahead ? this.typeahead.getInstance() : null;
|
|
|
+// }
|
|
|
+
|
|
|
+// componentDidMount() {
|
|
|
+// }
|
|
|
+
|
|
|
+// componentWillUnmount() {
|
|
|
+// }
|
|
|
+
|
|
|
+// /**
|
|
|
+// * Initialize keywordyword
|
|
|
+// */
|
|
|
+// restoreInitialData() {
|
|
|
+// this.changeKeyword(this.props.keywordOnInit);
|
|
|
+// }
|
|
|
+
|
|
|
+// /**
|
|
|
+// * clear keyword
|
|
|
+// */
|
|
|
+// clearKeyword(text) {
|
|
|
+// this.changeKeyword('');
|
|
|
+// }
|
|
|
+
|
|
|
+// /**
|
|
|
+// * change keyword
|
|
|
+// */
|
|
|
+// changeKeyword(text) {
|
|
|
+// // see https://github.com/ericgio/react-bootstrap-typeahead/issues/266#issuecomment-414987723
|
|
|
+// const instance = this.typeahead.getInstance();
|
|
|
+// instance.clear();
|
|
|
+// instance.setState({ text });
|
|
|
+// }
|
|
|
+
|
|
|
+// search(keyword) {
|
|
|
+
|
|
|
+// if (keyword === '') {
|
|
|
+// return;
|
|
|
+// }
|
|
|
+
|
|
|
+// this.setState({ isLoading: true });
|
|
|
+
|
|
|
+// apiGet('/search', { q: keyword })
|
|
|
+// .then((res) => { this.onSearchSuccess(res) })
|
|
|
+// .catch((err) => { this.onSearchError(err) });
|
|
|
+// }
|
|
|
+
|
|
|
+// /**
|
|
|
+// * Callback function which is occured when search is exit successfully
|
|
|
+// * @param {*} pages
|
|
|
+// */
|
|
|
+// onSearchSuccess(res) {
|
|
|
+// this.setState({
|
|
|
+// isLoading: false,
|
|
|
+// pages: res.data,
|
|
|
+// });
|
|
|
+// if (this.props.onSearchSuccess != null) {
|
|
|
+// this.props.onSearchSuccess(res);
|
|
|
+// }
|
|
|
+// }
|
|
|
+
|
|
|
+// /**
|
|
|
+// * Callback function which is occured when search is exit abnormaly
|
|
|
+// * @param {*} err
|
|
|
+// */
|
|
|
+// onSearchError(err) {
|
|
|
+// this.setState({
|
|
|
+// isLoading: false,
|
|
|
+// searchError: err,
|
|
|
+// });
|
|
|
+// if (this.props.onSearchError != null) {
|
|
|
+// this.props.onSearchError(err);
|
|
|
+// }
|
|
|
+// }
|
|
|
+
|
|
|
+// onInputChange(text) {
|
|
|
+// this.setState({ input: text });
|
|
|
+// this.props.onInputChange(text);
|
|
|
+// if (text === '') {
|
|
|
+// this.setState({ pages: [] });
|
|
|
+// }
|
|
|
+// }
|
|
|
+
|
|
|
+// onKeyDown(event) {
|
|
|
+// if (event.keyCode === 13) {
|
|
|
+// this.dispatchSubmit();
|
|
|
+// }
|
|
|
+// }
|
|
|
+
|
|
|
+// dispatchSubmit() {
|
|
|
+// if (this.props.onSubmit != null) {
|
|
|
+// this.props.onSubmit(this.state.input);
|
|
|
+// }
|
|
|
+// }
|
|
|
+
|
|
|
+// getEmptyLabel() {
|
|
|
+// const { emptyLabel, helpElement } = this.props;
|
|
|
+// const { input } = this.state;
|
|
|
+
|
|
|
+// // show help element if empty
|
|
|
+// if (input.length === 0) {
|
|
|
+// return helpElement;
|
|
|
+// }
|
|
|
+
|
|
|
+// // use props.emptyLabel as is if defined
|
|
|
+// if (emptyLabel !== undefined) {
|
|
|
+// return this.props.emptyLabel;
|
|
|
+// }
|
|
|
+
|
|
|
+// let emptyLabelExceptError = 'No matches found on title...';
|
|
|
+// if (this.props.emptyLabelExceptError !== undefined) {
|
|
|
+// emptyLabelExceptError = this.props.emptyLabelExceptError;
|
|
|
+// }
|
|
|
+
|
|
|
+// return (this.state.searchError !== null)
|
|
|
+// ? 'Error on searching.'
|
|
|
+// : emptyLabelExceptError;
|
|
|
+// }
|
|
|
+
|
|
|
+// /**
|
|
|
+// * Get restore form button to initialize button
|
|
|
+// */
|
|
|
+// getResetFormButton() {
|
|
|
+// const isClearBtn = this.props.behaviorOfResetBtn === 'clear';
|
|
|
+// const initialKeyword = isClearBtn ? '' : this.props.keywordOnInit;
|
|
|
+// const isHidden = this.state.input === initialKeyword;
|
|
|
+// const resetForm = isClearBtn ? this.clearKeyword : this.restoreInitialData;
|
|
|
+
|
|
|
+// return isHidden ? (
|
|
|
+// <span />
|
|
|
+// ) : (
|
|
|
+// <button type="button" className="btn btn-link search-clear" onMouseDown={resetForm}>
|
|
|
+// <i className="icon-close" />
|
|
|
+// </button>
|
|
|
+// );
|
|
|
+// }
|
|
|
+
|
|
|
+// renderMenuItemChildren(option, props, index) {
|
|
|
+// const page = option;
|
|
|
+// return (
|
|
|
+// <span>
|
|
|
+// <UserPicture user={page.lastUpdateUser} size="sm" noLink />
|
|
|
+// <span className="ml-1 text-break text-wrap"><PagePathLabel page={page} /></span>
|
|
|
+// <PageListMeta page={page} />
|
|
|
+// </span>
|
|
|
+// );
|
|
|
+// }
|
|
|
+
|
|
|
+// render() {
|
|
|
+// const defaultSelected = (this.props.keywordOnInit !== '')
|
|
|
+// ? [{ path: this.props.keywordOnInit }]
|
|
|
+// : [];
|
|
|
+// const inputProps = { autoComplete: 'off' };
|
|
|
+// if (this.props.inputName != null) {
|
|
|
+// inputProps.name = this.props.inputName;
|
|
|
+// }
|
|
|
+
|
|
|
+// const resetFormButton = this.getResetFormButton();
|
|
|
+
|
|
|
+// return (
|
|
|
+// <div className="search-typeahead">
|
|
|
+// <AsyncTypeahead
|
|
|
+// {...this.props}
|
|
|
+// id="search-typeahead-asynctypeahead"
|
|
|
+// ref={(c) => { this.typeahead = c }}
|
|
|
+// inputProps={inputProps}
|
|
|
+// isLoading={this.state.isLoading}
|
|
|
+// labelKey="path"
|
|
|
+// minLength={0}
|
|
|
+// options={this.state.pages} // Search result (Some page names)
|
|
|
+// promptText={this.props.helpElement}
|
|
|
+// emptyLabel={this.getEmptyLabel()}
|
|
|
+// align="left"
|
|
|
+// submitFormOnEnter
|
|
|
+// onSearch={this.search}
|
|
|
+// onInputChange={this.onInputChange}
|
|
|
+// onKeyDown={this.onKeyDown}
|
|
|
+// renderMenuItemChildren={this.renderMenuItemChildren}
|
|
|
+// caseSensitive={false}
|
|
|
+// defaultSelected={defaultSelected}
|
|
|
+// autoFocus={this.props.autoFocus}
|
|
|
+// onBlur={this.props.onBlur}
|
|
|
+// onFocus={this.props.onFocus}
|
|
|
+// />
|
|
|
+// {resetFormButton}
|
|
|
+// </div>
|
|
|
+// );
|
|
|
+// }
|
|
|
+
|
|
|
+// }
|
|
|
+
|
|
|
/**
|
|
|
* Properties
|
|
|
*/
|
|
|
SearchTypeahead.defaultProps = {
|
|
|
- placeholder: '',
|
|
|
- keywordOnInit: '',
|
|
|
+ placeholder: '',
|
|
|
+ keywordOnInit: '',
|
|
|
behaviorOfResetBtn: 'restore',
|
|
|
- autoFocus: false,
|
|
|
- onInputChange: () => {},
|
|
|
+ autoFocus: false,
|
|
|
};
|
|
|
|
|
|
export default SearchTypeahead;
|