Move search out of RoomList and LeftPanel, into RoomSearch
This prevents the entire left panel from having to re-mount whenever the search query changes.pull/21833/head
parent
42498d32cc
commit
c6033b9410
|
@ -44,7 +44,6 @@ interface IProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
searchFilter: string;
|
|
||||||
showBreadcrumbs: boolean;
|
showBreadcrumbs: boolean;
|
||||||
showTagPanel: boolean;
|
showTagPanel: boolean;
|
||||||
}
|
}
|
||||||
|
@ -69,7 +68,6 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
searchFilter: "",
|
|
||||||
showBreadcrumbs: BreadcrumbsStore.instance.visible,
|
showBreadcrumbs: BreadcrumbsStore.instance.visible,
|
||||||
showTagPanel: SettingsStore.getValue('TagPanel.enableTagPanel'),
|
showTagPanel: SettingsStore.getValue('TagPanel.enableTagPanel'),
|
||||||
};
|
};
|
||||||
|
@ -97,10 +95,6 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
this.props.resizeNotifier.off("middlePanelResizedNoisy", this.onResize);
|
this.props.resizeNotifier.off("middlePanelResizedNoisy", this.onResize);
|
||||||
}
|
}
|
||||||
|
|
||||||
private onSearch = (term: string): void => {
|
|
||||||
this.setState({searchFilter: term});
|
|
||||||
};
|
|
||||||
|
|
||||||
private onExplore = () => {
|
private onExplore = () => {
|
||||||
dis.fire(Action.ViewRoomDirectory);
|
dis.fire(Action.ViewRoomDirectory);
|
||||||
};
|
};
|
||||||
|
@ -366,7 +360,6 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
onKeyDown={this.onKeyDown}
|
onKeyDown={this.onKeyDown}
|
||||||
>
|
>
|
||||||
<RoomSearch
|
<RoomSearch
|
||||||
onQueryUpdate={this.onSearch}
|
|
||||||
isMinimized={this.props.isMinimized}
|
isMinimized={this.props.isMinimized}
|
||||||
onVerticalArrow={this.onKeyDown}
|
onVerticalArrow={this.onKeyDown}
|
||||||
onEnter={this.onEnter}
|
onEnter={this.onEnter}
|
||||||
|
@ -392,7 +385,6 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
onKeyDown={this.onKeyDown}
|
onKeyDown={this.onKeyDown}
|
||||||
resizeNotifier={null}
|
resizeNotifier={null}
|
||||||
collapsed={false}
|
collapsed={false}
|
||||||
searchFilter={this.state.searchFilter}
|
|
||||||
onFocus={this.onFocus}
|
onFocus={this.onFocus}
|
||||||
onBlur={this.onBlur}
|
onBlur={this.onBlur}
|
||||||
isMinimized={this.props.isMinimized}
|
isMinimized={this.props.isMinimized}
|
||||||
|
|
|
@ -24,9 +24,10 @@ import { throttle } from 'lodash';
|
||||||
import { Key } from "../../Keyboard";
|
import { Key } from "../../Keyboard";
|
||||||
import AccessibleButton from "../views/elements/AccessibleButton";
|
import AccessibleButton from "../views/elements/AccessibleButton";
|
||||||
import { Action } from "../../dispatcher/actions";
|
import { Action } from "../../dispatcher/actions";
|
||||||
|
import RoomListStore from "../../stores/room-list/RoomListStore";
|
||||||
|
import { NameFilterCondition } from "../../stores/room-list/filters/NameFilterCondition";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
onQueryUpdate: (newQuery: string) => void;
|
|
||||||
isMinimized: boolean;
|
isMinimized: boolean;
|
||||||
onVerticalArrow(ev: React.KeyboardEvent): void;
|
onVerticalArrow(ev: React.KeyboardEvent): void;
|
||||||
onEnter(ev: React.KeyboardEvent): boolean;
|
onEnter(ev: React.KeyboardEvent): boolean;
|
||||||
|
@ -40,6 +41,7 @@ interface IState {
|
||||||
export default class RoomSearch extends React.PureComponent<IProps, IState> {
|
export default class RoomSearch extends React.PureComponent<IProps, IState> {
|
||||||
private dispatcherRef: string;
|
private dispatcherRef: string;
|
||||||
private inputRef: React.RefObject<HTMLInputElement> = createRef();
|
private inputRef: React.RefObject<HTMLInputElement> = createRef();
|
||||||
|
private searchFilter: NameFilterCondition = new NameFilterCondition();
|
||||||
|
|
||||||
constructor(props: IProps) {
|
constructor(props: IProps) {
|
||||||
super(props);
|
super(props);
|
||||||
|
@ -52,6 +54,21 @@ export default class RoomSearch extends React.PureComponent<IProps, IState> {
|
||||||
this.dispatcherRef = defaultDispatcher.register(this.onAction);
|
this.dispatcherRef = defaultDispatcher.register(this.onAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public componentDidUpdate(prevProps: Readonly<IProps>, prevState: Readonly<IState>): void {
|
||||||
|
if (prevState.query !== this.state.query) {
|
||||||
|
const hadSearch = !!this.searchFilter.search.trim();
|
||||||
|
const haveSearch = !!this.state.query.trim();
|
||||||
|
this.searchFilter.search = this.state.query;
|
||||||
|
if (!hadSearch && haveSearch) {
|
||||||
|
// started a new filter - add the condition
|
||||||
|
RoomListStore.instance.addFilter(this.searchFilter);
|
||||||
|
} else if (hadSearch && !haveSearch) {
|
||||||
|
// cleared a filter - remove the condition
|
||||||
|
RoomListStore.instance.removeFilter(this.searchFilter);
|
||||||
|
} // else the filter hasn't changed enough for us to care here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public componentWillUnmount() {
|
public componentWillUnmount() {
|
||||||
defaultDispatcher.unregister(this.dispatcherRef);
|
defaultDispatcher.unregister(this.dispatcherRef);
|
||||||
}
|
}
|
||||||
|
@ -78,19 +95,8 @@ export default class RoomSearch extends React.PureComponent<IProps, IState> {
|
||||||
private onChange = () => {
|
private onChange = () => {
|
||||||
if (!this.inputRef.current) return;
|
if (!this.inputRef.current) return;
|
||||||
this.setState({query: this.inputRef.current.value});
|
this.setState({query: this.inputRef.current.value});
|
||||||
this.onSearchUpdated();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// it wants this at the top of the file, but we know better
|
|
||||||
// tslint:disable-next-line
|
|
||||||
private onSearchUpdated = throttle(
|
|
||||||
() => {
|
|
||||||
// We can't use the state variable because it can lag behind the input.
|
|
||||||
// The lag is most obvious when deleting/clearing text with the keyboard.
|
|
||||||
this.props.onQueryUpdate(this.inputRef.current.value);
|
|
||||||
}, 200, {trailing: true, leading: true},
|
|
||||||
);
|
|
||||||
|
|
||||||
private onFocus = (ev: React.FocusEvent<HTMLInputElement>) => {
|
private onFocus = (ev: React.FocusEvent<HTMLInputElement>) => {
|
||||||
this.setState({focused: true});
|
this.setState({focused: true});
|
||||||
ev.target.select();
|
ev.target.select();
|
||||||
|
|
|
@ -31,7 +31,6 @@ import dis from "../../../dispatcher/dispatcher";
|
||||||
import defaultDispatcher from "../../../dispatcher/dispatcher";
|
import defaultDispatcher from "../../../dispatcher/dispatcher";
|
||||||
import RoomSublist from "./RoomSublist";
|
import RoomSublist from "./RoomSublist";
|
||||||
import { ActionPayload } from "../../../dispatcher/payloads";
|
import { ActionPayload } from "../../../dispatcher/payloads";
|
||||||
import { NameFilterCondition } from "../../../stores/room-list/filters/NameFilterCondition";
|
|
||||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||||
import GroupAvatar from "../avatars/GroupAvatar";
|
import GroupAvatar from "../avatars/GroupAvatar";
|
||||||
import TemporaryTile from "./TemporaryTile";
|
import TemporaryTile from "./TemporaryTile";
|
||||||
|
@ -52,7 +51,6 @@ interface IProps {
|
||||||
onResize: () => void;
|
onResize: () => void;
|
||||||
resizeNotifier: ResizeNotifier;
|
resizeNotifier: ResizeNotifier;
|
||||||
collapsed: boolean;
|
collapsed: boolean;
|
||||||
searchFilter: string;
|
|
||||||
isMinimized: boolean;
|
isMinimized: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,8 +148,7 @@ function customTagAesthetics(tagId: TagID): ITagAesthetics {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class RoomList extends React.Component<IProps, IState> {
|
export default class RoomList extends React.PureComponent<IProps, IState> {
|
||||||
private searchFilter: NameFilterCondition = new NameFilterCondition();
|
|
||||||
private dispatcherRef;
|
private dispatcherRef;
|
||||||
private customTagStoreRef;
|
private customTagStoreRef;
|
||||||
|
|
||||||
|
@ -165,21 +162,6 @@ export default class RoomList extends React.Component<IProps, IState> {
|
||||||
this.dispatcherRef = defaultDispatcher.register(this.onAction);
|
this.dispatcherRef = defaultDispatcher.register(this.onAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentDidUpdate(prevProps: Readonly<IProps>): void {
|
|
||||||
if (prevProps.searchFilter !== this.props.searchFilter) {
|
|
||||||
const hadSearch = !!this.searchFilter.search.trim();
|
|
||||||
const haveSearch = !!this.props.searchFilter.trim();
|
|
||||||
this.searchFilter.search = this.props.searchFilter;
|
|
||||||
if (!hadSearch && haveSearch) {
|
|
||||||
// started a new filter - add the condition
|
|
||||||
RoomListStore.instance.addFilter(this.searchFilter);
|
|
||||||
} else if (hadSearch && !haveSearch) {
|
|
||||||
// cleared a filter - remove the condition
|
|
||||||
RoomListStore.instance.removeFilter(this.searchFilter);
|
|
||||||
} // else the filter hasn't changed enough for us to care here
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public componentDidMount(): void {
|
public componentDidMount(): void {
|
||||||
RoomListStore.instance.on(LISTS_UPDATE_EVENT, this.updateLists);
|
RoomListStore.instance.on(LISTS_UPDATE_EVENT, this.updateLists);
|
||||||
this.customTagStoreRef = CustomRoomTagStore.addListener(this.updateLists);
|
this.customTagStoreRef = CustomRoomTagStore.addListener(this.updateLists);
|
||||||
|
@ -339,7 +321,7 @@ export default class RoomList extends React.Component<IProps, IState> {
|
||||||
isMinimized={this.props.isMinimized}
|
isMinimized={this.props.isMinimized}
|
||||||
onResize={this.props.onResize}
|
onResize={this.props.onResize}
|
||||||
extraBadTilesThatShouldntExist={extraTiles}
|
extraBadTilesThatShouldntExist={extraTiles}
|
||||||
isFiltered={!!this.searchFilter.search}
|
isFiltered={!!RoomListStore.instance.getFirstNameFilterCondition()}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue