diff --git a/packages/select/src/components/query-list/queryList.tsx b/packages/select/src/components/query-list/queryList.tsx index c76432f2f4..1b6bdf8126 100644 --- a/packages/select/src/components/query-list/queryList.tsx +++ b/packages/select/src/components/query-list/queryList.tsx @@ -109,7 +109,14 @@ export class QueryList extends React.Component, IQueryList super(props, context); const { query = "" } = this.props; const filteredItems = getFilteredItems(query, this.props); - this.state = { activeItem: getFirstEnabledItem(filteredItems, this.props.itemDisabled), filteredItems, query }; + this.state = { + activeItem: + this.props.activeItem !== undefined + ? this.props.activeItem + : getFirstEnabledItem(filteredItems, this.props.itemDisabled), + filteredItems, + query, + }; } public render() { diff --git a/packages/select/test/queryListTests.tsx b/packages/select/test/queryListTests.tsx index 3a2b26855c..bff202fe01 100644 --- a/packages/select/test/queryListTests.tsx +++ b/packages/select/test/queryListTests.tsx @@ -13,6 +13,8 @@ import { IQueryListProps } from "@blueprintjs/select"; import { IFilm, renderFilm, TOP_100_FILMS } from "../../docs-app/src/examples/select-examples/films"; import { IQueryListRendererProps, IQueryListState, ItemListPredicate, ItemListRenderer, QueryList } from "../src/index"; +type FilmQueryListWrapper = ReactWrapper, IQueryListState>; + describe("", () => { const FilmQueryList = QueryList.ofType(); const testProps = { @@ -99,7 +101,7 @@ describe("", () => { items: [myItem], query: "", }; - const filmQueryList: ReactWrapper> = mount(); + const filmQueryList: FilmQueryListWrapper = mount(); filmQueryList.setProps(props); assert.equal(testProps.onActiveItemChange.callCount, 0); }); @@ -110,9 +112,7 @@ describe("", () => { items: [TOP_100_FILMS[0]], query: "abc", }; - const filmQueryList: ReactWrapper, IQueryListState> = mount( - , - ); + const filmQueryList: FilmQueryListWrapper = mount(); assert.deepEqual(filmQueryList.state().activeItem, TOP_100_FILMS[0]); filmQueryList.setProps({ items: [TOP_100_FILMS[1]], @@ -122,6 +122,39 @@ describe("", () => { }); }); + describe("activeItem state initialization", () => { + it("initializes to first filtered item when uncontrolled", () => { + const props: IQueryListProps = { + ...testProps, + // Filter down to only item at index 11, so item at index 11 should be + // chosen as default activeItem + itemPredicate: (_query, item) => item === TOP_100_FILMS[11], + query: "123", + }; + const filmQueryList: FilmQueryListWrapper = mount(); + assert(filmQueryList.state().activeItem === TOP_100_FILMS[11]); + }); + + it("initializes to controlled activeItem prop (non-null)", () => { + const props: IQueryListProps = { + ...testProps, + // List is not filtered, and item at index 11 is explicitly chosen as activeItem + activeItem: TOP_100_FILMS[11], + }; + const filmQueryList: FilmQueryListWrapper = mount(); + assert(filmQueryList.state().activeItem === TOP_100_FILMS[11]); + }); + + it("initializes to controlled activeItem prop (null)", () => { + const props: IQueryListProps = { + ...testProps, + activeItem: null, + }; + const filmQueryList: FilmQueryListWrapper = mount(); + assert(filmQueryList.state().activeItem === null); + }); + }); + describe("scrolling", () => { it("brings active item into view"); });