Skip to content

Instantly share code, notes, and snippets.

@justinbhopper
Created March 11, 2022 22:35
Show Gist options
  • Save justinbhopper/920d8450da875a380c8c0fd5286cfe29 to your computer and use it in GitHub Desktop.
Save justinbhopper/920d8450da875a380c8c0fd5286cfe29 to your computer and use it in GitHub Desktop.
Suggest enhancement
import React from "react";
import { Button } from "@blueprintjs/core";
import * as Core from "@blueprintjs/select";
export interface SuggestProps<T> extends Omit<Core.SuggestProps<T>, "onItemSelect"> {
/**
* If true, defaults the `inputProps.rightElement` to a clear button that will clear the selection.
* Ignored if `inputProps.rightElement` is provided.
* @default false
*/
clearable?: boolean;
/**
* Invoked when the selection changes or is cleared.
*/
onItemSelect?: (item: T | null, event?: React.SyntheticEvent<HTMLElement>) => void;
}
interface SuggestState<T> {
selectedItem: T | null;
query: string;
}
export class Suggest<T> extends React.PureComponent<SuggestProps<T>, SuggestState<T>> {
private readonly TypedSuggest = Core.Suggest.ofType<T>();
constructor(props: SuggestProps<T>) {
super(props);
this.state = {
query: "",
selectedItem: props.defaultSelectedItem ?? null,
};
}
public static ofType<T>() {
return Suggest as new (props: SuggestProps<T>) => Suggest<T>;
}
public componentDidUpdate(prevProps: SuggestProps<T>) {
const { selectedItem } = this.props;
// Announce new value if prop changed
if (selectedItem && selectedItem !== prevProps.selectedItem) {
this.setState({ selectedItem });
}
}
public render() {
const {
clearable = false,
onItemSelect,
query = this.state.query,
selectedItem = this.state.selectedItem,
inputProps = {},
...restProps
} = this.props;
const { rightElement: controlledRightElement, ...restInputProps } = inputProps;
let rightElement = controlledRightElement;
if (!rightElement && clearable && query) {
rightElement = (
<Button minimal icon="cross" onClick={this.handleClear} />
);
}
return (
<this.TypedSuggest
{...restProps}
inputProps={{
...restInputProps,
rightElement,
}}
query={query}
selectedItem={selectedItem}
onItemSelect={this.handleItemSelect}
onQueryChange={this.handleQueryChange}
/>
);
}
private handleItemSelect = (item: T, event?: React.SyntheticEvent<HTMLElement>) => {
this.props.onItemSelect?.(item, event);
this.handleSelectedItemChange(item);
};
private handleClear = (): void => {
this.handleSelectedItemChange(null);
// Clear query on clear button too
this.handleQueryChange("");
};
private handleSelectedItemChange = (selectedItem: T | null): void => {
const { onItemSelect } = this.props;
onItemSelect?.(selectedItem);
this.setState({ selectedItem });
};
private handleQueryChange = (query: string, event?: React.ChangeEvent<HTMLInputElement>): void => {
this.props.onQueryChange?.(query, event);
this.setState({ query });
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment