/* Copyright 2024 New Vector Ltd. Copyright 2019 Michael Telatynski <7t3chguy@gmail.com> Copyright 2015, 2016 OpenMarket Ltd SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only Please see LICENSE files in the repository root for full details. */ import React, { createRef, HTMLProps } from "react"; import { throttle } from "lodash"; import classNames from "classnames"; import AccessibleButton from "../../components/views/elements/AccessibleButton"; import { getKeyBindingsManager } from "../../KeyBindingsManager"; import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts"; interface IProps extends HTMLProps { onSearch: (query: string) => void; onCleared?: (source?: string) => void; onKeyDown?: (ev: React.KeyboardEvent) => void; onFocus?: (ev: React.FocusEvent) => void; onBlur?: (ev: React.FocusEvent) => void; className?: string; placeholder: string; blurredPlaceholder?: string; autoFocus?: boolean; initialValue?: string; collapsed?: boolean; } interface IState { searchTerm: string; blurred: boolean; } export default class SearchBox extends React.Component { private search = createRef(); public constructor(props: IProps) { super(props); this.state = { searchTerm: props.initialValue || "", blurred: true, }; } private onChange = (): void => { if (!this.search.current) return; this.setState({ searchTerm: this.search.current.value }); this.onSearch(); }; private onSearch = throttle( (): void => { this.props.onSearch(this.search.current?.value ?? ""); }, 200, { trailing: true, leading: true }, ); private onKeyDown = (ev: React.KeyboardEvent): void => { const action = getKeyBindingsManager().getAccessibilityAction(ev); switch (action) { case KeyBindingAction.Escape: this.clearSearch("keyboard"); break; } if (this.props.onKeyDown) this.props.onKeyDown(ev); }; private onFocus = (ev: React.FocusEvent): void => { this.setState({ blurred: false }); (ev.target as HTMLInputElement).select(); if (this.props.onFocus) { this.props.onFocus(ev); } }; private onBlur = (ev: React.FocusEvent): void => { this.setState({ blurred: true }); if (this.props.onBlur) { this.props.onBlur(ev); } }; private clearSearch(source?: string): void { if (this.search.current) this.search.current.value = ""; this.onChange(); this.props.onCleared?.(source); } public render(): React.ReactNode { /* eslint @typescript-eslint/no-unused-vars: ["error", { "ignoreRestSiblings": true }] */ const { onSearch, onCleared, onKeyDown, onFocus, onBlur, className = "", placeholder, blurredPlaceholder, autoFocus, initialValue, collapsed, ...props } = this.props; // check for collapsed here and // not at parent so we keep // searchTerm in our state // when collapsing and expanding if (collapsed) { return null; } const clearButton = !this.state.blurred || this.state.searchTerm ? ( { this.clearSearch("button"); }} /> ) : undefined; // show a shorter placeholder when blurred, if requested // this is used for the room filter field that has // the explore button next to it when blurred return (
{clearButton}
); } }