Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Suggest] add disabled and resetOnClose props #3292

Merged
merged 4 commits into from
Jan 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ export interface ISuggestExampleState {
film: IFilm;
minimal: boolean;
openOnKeyDown: boolean;
resetOnSelect: boolean;
resetOnClose: boolean;
resetOnQuery: boolean;
resetOnSelect: boolean;
}

export class SuggestExample extends React.PureComponent<IExampleProps, ISuggestExampleState> {
Expand All @@ -28,13 +29,15 @@ export class SuggestExample extends React.PureComponent<IExampleProps, ISuggestE
film: TOP_100_FILMS[0],
minimal: true,
openOnKeyDown: false,
resetOnClose: false,
resetOnQuery: true,
resetOnSelect: false,
};

private handleCloseOnSelectChange = this.handleSwitchChange("closeOnSelect");
private handleOpenOnKeyDownChange = this.handleSwitchChange("openOnKeyDown");
private handleMinimalChange = this.handleSwitchChange("minimal");
private handleResetOnCloseChange = this.handleSwitchChange("resetOnClose");
private handleResetOnQueryChange = this.handleSwitchChange("resetOnQuery");
private handleResetOnSelectChange = this.handleSwitchChange("resetOnSelect");

Expand Down Expand Up @@ -68,6 +71,11 @@ export class SuggestExample extends React.PureComponent<IExampleProps, ISuggestE
checked={this.state.openOnKeyDown}
onChange={this.handleOpenOnKeyDownChange}
/>
<Switch
label="Reset on close"
checked={this.state.resetOnClose}
onChange={this.handleResetOnCloseChange}
/>
<Switch
label="Reset on query"
checked={this.state.resetOnQuery}
Expand Down
5 changes: 4 additions & 1 deletion packages/select/src/components/select/suggest.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
@# Suggest

`Suggest` behaves similarly to [`Select`](#select/select-component), except it renders a text input as the `Popover` target instead of arbitrary children.
`Suggest` behaves similarly to [`Select`](#select/select-component), except it
renders a text input as the `Popover` target instead of arbitrary children. This
text [`InputGroup`](#core/components/text-inputs.input-group) can be customized
using `inputProps`.

@reactExample SuggestExample

Expand Down
37 changes: 32 additions & 5 deletions packages/select/src/components/select/suggest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ export interface ISuggestProps<T> extends IListItemsProps<T> {
*/
closeOnSelect?: boolean;

/** Whether the input field should be disabled. */
disabled?: boolean;

/**
* Props to spread to the query `InputGroup`. To control this input, use
* `query` and `onQueryChange` instead of `inputProps.value` and
Expand Down Expand Up @@ -59,6 +62,13 @@ export interface ISuggestProps<T> extends IListItemsProps<T> {

/** Props to spread to `Popover`. Note that `content` cannot be changed. */
popoverProps?: Partial<IPopoverProps> & object;

/**
* Whether the active item should be reset to the first matching item _when
* the popover closes_. The query will also be reset to the empty string.
* @default false
*/
resetOnClose?: boolean;
}

export interface ISuggestState<T> {
Expand All @@ -69,10 +79,10 @@ export interface ISuggestState<T> {
export class Suggest<T> extends React.PureComponent<ISuggestProps<T>, ISuggestState<T>> {
public static displayName = `${DISPLAYNAME_PREFIX}.Suggest`;

// Note: can't use <T> in static members, so this remains dynamically typed.
public static defaultProps = {
public static defaultProps: Partial<ISuggestProps<any>> = {
closeOnSelect: true,
openOnKeyDown: false,
resetOnClose: false,
};

public static ofType<T>() {
Expand Down Expand Up @@ -101,7 +111,7 @@ export class Suggest<T> extends React.PureComponent<ISuggestProps<T>, ISuggestSt

public render() {
// omit props specific to this component, spread the rest.
const { inputProps, popoverProps, ...restProps } = this.props;
const { disabled, inputProps, popoverProps, ...restProps } = this.props;

return (
<this.TypedQueryList
Expand Down Expand Up @@ -136,7 +146,10 @@ export class Suggest<T> extends React.PureComponent<ISuggestProps<T>, ISuggestSt
// placeholder shows selected item while open.
const inputPlaceholder = isOpen && selectedItemText ? selectedItemText : placeholder;
// value shows query when open, and query remains when closed if nothing is selected.
const inputValue = isOpen ? listProps.query : selectedItemText || listProps.query;
// if resetOnClose is enabled, then hide query when not open. (see handlePopoverOpening)
const inputValue = isOpen
? listProps.query
: selectedItemText || (this.props.resetOnClose ? "" : listProps.query);

return (
<Popover
Expand All @@ -148,16 +161,18 @@ export class Suggest<T> extends React.PureComponent<ISuggestProps<T>, ISuggestSt
className={classNames(listProps.className, popoverProps.className)}
onInteraction={this.handlePopoverInteraction}
popoverClassName={classNames(Classes.SELECT_POPOVER, popoverProps.popoverClassName)}
onOpening={this.handlePopoverOpening}
onOpened={this.handlePopoverOpened}
>
<InputGroup
disabled={this.props.disabled}
{...inputProps}
placeholder={inputPlaceholder}
inputRef={this.refHandlers.input}
onChange={listProps.handleQueryChange}
onFocus={this.handleInputFocus}
onKeyDown={this.getTargetKeyDownHandler(handleKeyDown)}
onKeyUp={this.getTargetKeyUpHandler(handleKeyUp)}
placeholder={inputPlaceholder}
value={inputValue}
/>
<div onKeyDown={handleKeyDown} onKeyUp={handleKeyUp}>
Expand Down Expand Up @@ -240,6 +255,18 @@ export class Suggest<T> extends React.PureComponent<ISuggestProps<T>, ISuggestSt
Utils.safeInvoke(popoverProps.onInteraction, nextOpenState);
});

private handlePopoverOpening = (node: HTMLElement) => {
const { popoverProps = {}, resetOnClose } = this.props;

// reset query before opening instead of when closing to prevent flash of unfiltered items.
// this is a limitation of the interactions between QueryList state and Popover transitions.
if (resetOnClose && this.queryList) {
this.queryList.setQuery("", true);
}

Utils.safeInvoke(popoverProps.onOpening, node);
};

private handlePopoverOpened = (node: HTMLElement) => {
const { popoverProps = {} } = this.props;

Expand Down