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

[Select] Flag to optionally scroll to active item for select components #3096

Merged
merged 5 commits into from
Nov 15, 2018
Merged
Show file tree
Hide file tree
Changes from 4 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
9 changes: 9 additions & 0 deletions packages/select/src/common/listItemsProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,15 @@ export interface IListItemsProps<T> extends IProps {
*/
resetOnSelect?: boolean;

/**
* When `activeItem` is controlled, whether the active item should _always_
* be scrolled into view when the prop changes. If `false`, only changes
* that result from built-in interactions (clicking, querying, or using
* arrow keys) will scroll the active item into view.
* @default true
*/
scrollToActiveItem?: boolean;

/**
* Query string passed to `itemListPredicate` or `itemPredicate` to filter items.
* This value is controlled: its state must be managed externally by attaching an `onChange`
Expand Down
16 changes: 16 additions & 0 deletions packages/select/src/components/query-list/queryList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ export class QueryList<T> extends React.Component<IQueryListProps<T>, IQueryList
*/
private shouldCheckActiveItemInViewport = false;

/**
* The item that we expect to be the next selected active item (based on click
* or key interactions). When scrollToActiveItem = false, used to detect if
* an unexpected external change to the active item has been made.
*/
private expectedNextActiveItem: T | null = null;

public constructor(props: IQueryListProps<T>, context?: any) {
super(props, context);
const { query = "" } = this.props;
Expand Down Expand Up @@ -152,6 +159,14 @@ export class QueryList<T> extends React.Component<IQueryListProps<T>, IQueryList
}

public scrollActiveItemIntoView() {
const scrollToActiveItem = this.props.scrollToActiveItem !== false;
const externalChangeToActiveItem = this.expectedNextActiveItem !== this.props.activeItem;
this.expectedNextActiveItem = null;

if (!scrollToActiveItem && externalChangeToActiveItem) {
return;
}

const activeElement = this.getActiveElement();
if (this.itemsParentRef != null && activeElement != null) {
const { offsetTop: activeTop, offsetHeight: activeHeight } = activeElement;
Expand Down Expand Up @@ -294,6 +309,7 @@ export class QueryList<T> extends React.Component<IQueryListProps<T>, IQueryList
}

private setActiveItem(activeItem: T | null) {
this.expectedNextActiveItem = activeItem;
if (this.props.activeItem === undefined) {
// indicate that the active item may need to be scrolled into view after update.
this.shouldCheckActiveItemInViewport = true;
Expand Down