1 | import * as React from "react";
|
2 | import { AbstractComponent, type Props } from "@blueprintjs/core";
|
3 | import { type CreateNewItem, type ListItemsProps } from "../../common";
|
4 | export interface QueryListProps<T> extends ListItemsProps<T> {
|
5 | /**
|
6 | * Initial active item, useful if the parent component is controlling its selectedItem but
|
7 | * not activeItem.
|
8 | */
|
9 | initialActiveItem?: T;
|
10 | /**
|
11 | * Additional props to apply to the `Menu` that is created within the `QueryList`
|
12 | */
|
13 | menuProps?: React.HTMLAttributes<HTMLUListElement>;
|
14 | /**
|
15 | * Callback invoked when user presses a key, after processing `QueryList`'s own key events
|
16 | * (up/down to navigate active item). This callback is passed to `renderer` and (along with
|
17 | * `onKeyUp`) can be attached to arbitrary content elements to support keyboard selection.
|
18 | */
|
19 | onKeyDown?: React.KeyboardEventHandler<HTMLElement>;
|
20 | /**
|
21 | * Callback invoked when user releases a key, after processing `QueryList`'s own key events
|
22 | * (enter to select active item). This callback is passed to `renderer` and (along with
|
23 | * `onKeyDown`) can be attached to arbitrary content elements to support keyboard selection.
|
24 | */
|
25 | onKeyUp?: React.KeyboardEventHandler<HTMLElement>;
|
26 | /**
|
27 | * Customize rendering of the component.
|
28 | * Receives an object with props that should be applied to elements as necessary.
|
29 | */
|
30 | renderer: (listProps: QueryListRendererProps<T>) => React.JSX.Element;
|
31 | /**
|
32 | * Whether the list is disabled.
|
33 | *
|
34 | * @default false
|
35 | */
|
36 | disabled?: boolean;
|
37 | }
|
38 | /**
|
39 | * An object describing how to render a `QueryList`.
|
40 | * A `QueryList` `renderer` receives this object as its sole argument.
|
41 | */
|
42 | export interface QueryListRendererProps<T>// Omit `createNewItem`, because it's used strictly for internal tracking.
|
43 | extends Pick<QueryListState<T>, "activeItem" | "filteredItems" | "query">, Props {
|
44 | /**
|
45 | * Selection handler that should be invoked when a new item has been chosen,
|
46 | * perhaps because the user clicked it.
|
47 | */
|
48 | handleItemSelect: (item: T, event?: React.SyntheticEvent<HTMLElement>) => void;
|
49 | /**
|
50 | * Handler that should be invoked when the user pastes one or more values.
|
51 | *
|
52 | * This callback will use `itemPredicate` with `exactMatch=true` to find a
|
53 | * subset of `items` exactly matching the pasted `values` provided, then it
|
54 | * will invoke `onItemsPaste` with those found items. Each pasted value that
|
55 | * does not exactly match an item will be ignored.
|
56 | *
|
57 | * If creating items is enabled (by providing both `createNewItemFromQuery`
|
58 | * and `createNewItemRenderer`), then pasted values that do not exactly
|
59 | * match an existing item will emit a new item as created via
|
60 | * `createNewItemFromQuery`.
|
61 | *
|
62 | * If `itemPredicate` returns multiple matching items for a particular query
|
63 | * in `queries`, then only the first matching item will be emitted.
|
64 | */
|
65 | handlePaste: (queries: string[]) => void;
|
66 | /**
|
67 | * Keyboard handler for up/down arrow keys to shift the active item.
|
68 | * Attach this handler to any element that should support this interaction.
|
69 | */
|
70 | handleKeyDown: React.KeyboardEventHandler<HTMLElement>;
|
71 | /**
|
72 | * Keyboard handler for enter key to select the active item.
|
73 | * Attach this handler to any element that should support this interaction.
|
74 | */
|
75 | handleKeyUp: React.KeyboardEventHandler<HTMLElement>;
|
76 | /**
|
77 | * Change handler for query string. Attach this to an input element to allow
|
78 | * `QueryList` to control the query.
|
79 | */
|
80 | handleQueryChange: React.ChangeEventHandler<HTMLInputElement>;
|
81 | /** Rendered elements returned from `itemListRenderer` prop. */
|
82 | itemList: React.ReactNode;
|
83 | }
|
84 | /** Exported for testing, not part of public API */
|
85 | export interface QueryListState<T> {
|
86 | /** The currently focused item (for keyboard interactions). */
|
87 | activeItem: T | CreateNewItem | null;
|
88 | /**
|
89 | * The item returned from `createNewItemFromQuery(this.state.query)`, cached
|
90 | * to avoid continuous reinstantions within `isCreateItemRendered`, where
|
91 | * this element will be used to hide the "Create Item" option if its value
|
92 | * matches the current `query`.
|
93 | */
|
94 | createNewItem: T | T[] | undefined;
|
95 | /** The original `items` array filtered by `itemListPredicate` or `itemPredicate`. */
|
96 | filteredItems: T[];
|
97 | /** The current query string. */
|
98 | query: string;
|
99 | }
|
100 | /**
|
101 | * Query list component.
|
102 | *
|
103 | * @see https://blueprintjs.com/docs/#select/query-list
|
104 | */
|
105 | export declare class QueryList<T> extends AbstractComponent<QueryListProps<T>, QueryListState<T>> {
|
106 | static displayName: string;
|
107 | static defaultProps: {
|
108 | disabled: boolean;
|
109 | resetOnQuery: boolean;
|
110 | };
|
111 | /** @deprecated no longer necessary now that the TypeScript parser supports type arguments on JSX element tags */
|
112 | static ofType<U>(): new (props: QueryListProps<U>) => QueryList<U>;
|
113 | private itemsParentRef?;
|
114 | private itemRefs;
|
115 | private refHandlers;
|
116 | /**
|
117 | * Flag indicating that we should check whether selected item is in viewport
|
118 | * after rendering, typically because of keyboard change. Set to `true` when
|
119 | * manipulating state in a way that may cause active item to scroll away.
|
120 | */
|
121 | private shouldCheckActiveItemInViewport;
|
122 | /**
|
123 | * The item that we expect to be the next selected active item (based on click
|
124 | * or key interactions). When scrollToActiveItem = false, used to detect if
|
125 | * an unexpected external change to the active item has been made.
|
126 | */
|
127 | private expectedNextActiveItem;
|
128 | /**
|
129 | * Flag which is set to true while in between an ENTER "keydown" event and its
|
130 | * corresponding "keyup" event.
|
131 | *
|
132 | * When entering text via an IME (https://en.wikipedia.org/wiki/Input_method),
|
133 | * the ENTER key is pressed to confirm the character(s) to be input from a list
|
134 | * of options. The operating system intercepts the ENTER "keydown" event and
|
135 | * prevents it from propagating to the application, but "keyup" is still
|
136 | * fired, triggering a spurious event which this component does not expect.
|
137 | *
|
138 | * To work around this quirk, we keep track of "real" key presses by setting
|
139 | * this flag in handleKeyDown.
|
140 | */
|
141 | private isEnterKeyPressed;
|
142 | constructor(props: QueryListProps<T>);
|
143 | render(): React.JSX.Element;
|
144 | componentDidUpdate(prevProps: QueryListProps<T>): void;
|
145 | scrollActiveItemIntoView(): void;
|
146 | setQuery(query: string, resetActiveItem?: boolean | undefined, props?: Readonly<QueryListProps<T>> & Readonly<{
|
147 | children?: React.ReactNode;
|
148 | }>): void;
|
149 | setActiveItem(activeItem: T | CreateNewItem | null): void;
|
150 | /** default `itemListRenderer` implementation */
|
151 | private renderItemList;
|
152 | /** wrapper around `itemRenderer` to inject props */
|
153 | private renderItem;
|
154 | private renderCreateItemMenuItem;
|
155 | private getActiveElement;
|
156 | private getActiveIndex;
|
157 | private getItemsParentPadding;
|
158 | private handleItemCreate;
|
159 | private handleItemSelect;
|
160 | private handlePaste;
|
161 | private handleKeyDown;
|
162 | private handleKeyUp;
|
163 | private handleInputQueryChange;
|
164 | /**
|
165 | * Get the next enabled item, moving in the given direction from the start
|
166 | * index. A `null` return value means no suitable item was found.
|
167 | *
|
168 | * @param direction amount to move in each iteration, typically +/-1
|
169 | * @param startIndex item to start iteration
|
170 | */
|
171 | private getNextActiveItem;
|
172 | /**
|
173 | * @param createNewItem Checks if this item would match the current query. Cannot check this.state.createNewItem
|
174 | * every time since state may not have been updated yet.
|
175 | */
|
176 | private isCreateItemRendered;
|
177 | private isCreateItemFirst;
|
178 | private canCreateItems;
|
179 | private wouldCreatedItemMatchSomeExistingItem;
|
180 | private maybeResetQuery;
|
181 | }
|
182 | /**
|
183 | * Get the next enabled item, moving in the given direction from the start
|
184 | * index. A `null` return value means no suitable item was found.
|
185 | *
|
186 | * @param items the list of items
|
187 | * @param itemDisabled callback to determine if a given item is disabled
|
188 | * @param direction amount to move in each iteration, typically +/-1
|
189 | * @param startIndex which index to begin moving from
|
190 | */
|
191 | export declare function getFirstEnabledItem<T>(items: T[], itemDisabled?: keyof T | ((item: T, index: number) => boolean), direction?: number, startIndex?: number): T | CreateNewItem | null;
|