Skip to content

Commit 5de0a28

Browse files
committed
Revert "Use generics for Select arrays (#7036)"
This reverts commit 4d1297a.
1 parent 265df1a commit 5de0a28

File tree

19 files changed

+116
-143
lines changed

19 files changed

+116
-143
lines changed

packages/docs-app/src/examples/select-examples/multiSelectExample.tsx

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,13 @@ const INTENTS = [Intent.NONE, Intent.PRIMARY, Intent.SUCCESS, Intent.DANGER, Int
4040

4141
export interface MultiSelectExampleState {
4242
allowCreate: boolean;
43-
createdItems: readonly Film[];
43+
createdItems: Film[];
4444
disabled: boolean;
4545
fill: boolean;
46-
films: readonly Film[];
46+
films: Film[];
4747
hasInitialContent: boolean;
4848
intent: boolean;
49-
items: readonly Film[];
49+
items: Film[];
5050
matchTargetWidth: boolean;
5151
openOnKeyDown: boolean;
5252
popoverMinimal: boolean;
@@ -124,7 +124,7 @@ export class MultiSelectExample extends React.PureComponent<ExampleProps, MultiS
124124

125125
return (
126126
<Example options={this.renderOptions()} {...this.props}>
127-
<MultiSelect
127+
<MultiSelect<Film>
128128
{...flags}
129129
createNewItemFromQuery={allowCreate ? createFilms : undefined}
130130
createNewItemRenderer={allowCreate ? renderCreateFilmsMenuItem : null}
@@ -251,9 +251,7 @@ export class MultiSelectExample extends React.PureComponent<ExampleProps, MultiS
251251
);
252252
}
253253

254-
private renderCustomTarget = (selectedItems: readonly Film[]) => (
255-
<MultiSelectCustomTarget count={selectedItems.length} />
256-
);
254+
private renderCustomTarget = (selectedItems: Film[]) => <MultiSelectCustomTarget count={selectedItems.length} />;
257255

258256
private renderTag = (film: Film) => film.title;
259257

@@ -289,11 +287,11 @@ export class MultiSelectExample extends React.PureComponent<ExampleProps, MultiS
289287
this.selectFilms([film]);
290288
}
291289

292-
private selectFilms(filmsToSelect: readonly Film[]) {
290+
private selectFilms(filmsToSelect: Film[]) {
293291
this.setState(({ createdItems, films, items }) => {
294-
let nextCreatedItems = createdItems;
295-
let nextFilms = films;
296-
let nextItems = items;
292+
let nextCreatedItems = createdItems.slice();
293+
let nextFilms = films.slice();
294+
let nextItems = items.slice();
297295

298296
filmsToSelect.forEach(film => {
299297
const results = maybeAddCreatedFilmToArrays(nextItems, nextCreatedItems, film);
@@ -338,7 +336,7 @@ export class MultiSelectExample extends React.PureComponent<ExampleProps, MultiS
338336
}
339337
};
340338

341-
private handleFilmsPaste = (films: readonly Film[]) => {
339+
private handleFilmsPaste = (films: Film[]) => {
342340
// On paste, don't bother with deselecting already selected values, just
343341
// add the new ones.
344342
this.selectFilms(films);

packages/docs-app/src/examples/select-examples/omnibarExample.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ export class OmnibarExample extends React.PureComponent<ExampleProps, OmnibarExa
9292
<KeyComboTag combo="shift + o" />
9393
</span>
9494

95-
<Omnibar
95+
<Omnibar<Film>
9696
{...this.state}
9797
createNewItemFromQuery={maybeCreateNewItemFromQuery}
9898
createNewItemRenderer={maybeCreateNewItemRenderer}

packages/docs-app/src/examples/select-examples/selectExample.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import { type Film, FilmSelect, filterFilm, TOP_100_FILMS } from "@blueprintjs/s
2424
export interface SelectExampleState {
2525
allowCreate: boolean;
2626
createFirst: boolean;
27-
createdItems: readonly Film[];
27+
createdItems: Film[];
2828
disableItems: boolean;
2929
disabled: boolean;
3030
fill: boolean;
@@ -169,7 +169,7 @@ export class SelectExample extends React.PureComponent<ExampleProps, SelectExamp
169169
return /[0-9]/.test(firstLetter) ? "0-9" : firstLetter;
170170
}
171171

172-
private getGroupedItems = (filteredItems: readonly Film[]) => {
172+
private getGroupedItems = (filteredItems: Film[]) => {
173173
return filteredItems.reduce<Array<{ group: string; index: number; items: Film[]; key: number }>>(
174174
(acc, item, index) => {
175175
const group = this.getGroup(item);
@@ -193,7 +193,7 @@ export class SelectExample extends React.PureComponent<ExampleProps, SelectExamp
193193
) : undefined;
194194
};
195195

196-
private groupedItemListPredicate = (query: string, items: readonly Film[]) => {
196+
private groupedItemListPredicate = (query: string, items: Film[]) => {
197197
return items
198198
.filter((item, index) => filterFilm(query, item, index))
199199
.sort((a, b) => this.getGroup(a).localeCompare(this.getGroup(b)));
@@ -208,7 +208,7 @@ export class SelectExample extends React.PureComponent<ExampleProps, SelectExamp
208208

209209
private isItemDisabled = (film: Film) => this.state.disableItems && film.year < 2000;
210210

211-
private renderGroupedItemList = (listProps: ItemListRendererProps<Film, readonly Film[]>) => {
211+
private renderGroupedItemList = (listProps: ItemListRendererProps<Film>) => {
212212
const initialContent = this.getInitialContent();
213213
const noResults = <MenuItem disabled={true} text="No results." roleStructure="listoption" />;
214214

@@ -231,7 +231,7 @@ export class SelectExample extends React.PureComponent<ExampleProps, SelectExamp
231231
};
232232

233233
private renderGroupedMenuContent = (
234-
listProps: ItemListRendererProps<Film, readonly Film[]>,
234+
listProps: ItemListRendererProps<Film>,
235235
noResults?: React.ReactNode,
236236
initialContent?: React.ReactNode | null,
237237
) => {

packages/docs-app/src/examples/select-examples/suggestExample.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ import {
3434
export interface SuggestExampleState {
3535
allowCreate: boolean;
3636
closeOnSelect: boolean;
37-
createdItems: readonly Film[];
37+
createdItems: Film[];
3838
disabled: boolean;
3939
fill: boolean;
40-
items: readonly Film[];
40+
items: Film[];
4141
matchTargetWidth: boolean;
4242
minimal: boolean;
4343
openOnKeyDown: boolean;
@@ -92,7 +92,7 @@ export class SuggestExample extends React.PureComponent<ExampleProps, SuggestExa
9292

9393
return (
9494
<Example options={this.renderOptions()} {...this.props}>
95-
<Suggest
95+
<Suggest<Film>
9696
{...flags}
9797
createNewItemFromQuery={maybeCreateNewItemFromQuery}
9898
createNewItemRenderer={maybeCreateNewItemRenderer}

packages/select/src/__examples__/filmSelect.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import {
3535
} from "./films";
3636

3737
type FilmSelectProps = Omit<
38-
SelectProps<Film, readonly Film[]>,
38+
SelectProps<Film>,
3939
| "createNewItemFromQuery"
4040
| "createNewItemRenderer"
4141
| "itemPredicate"
@@ -49,8 +49,8 @@ type FilmSelectProps = Omit<
4949
};
5050

5151
export function FilmSelect({ allowCreate = false, fill, ...restProps }: FilmSelectProps) {
52-
const [items, setItems] = React.useState<readonly Film[]>([...TOP_100_FILMS]);
53-
const [createdItems, setCreatedItems] = React.useState<readonly Film[]>([]);
52+
const [items, setItems] = React.useState([...TOP_100_FILMS]);
53+
const [createdItems, setCreatedItems] = React.useState<Film[]>([]);
5454
const [selectedFilm, setSelectedFilm] = React.useState<Film | undefined>(undefined);
5555
const handleItemSelect = React.useCallback(
5656
(newFilm: Film) => {
@@ -82,7 +82,7 @@ export function FilmSelect({ allowCreate = false, fill, ...restProps }: FilmSele
8282
);
8383

8484
return (
85-
<Select
85+
<Select<Film>
8686
createNewItemFromQuery={allowCreate ? createFilm : undefined}
8787
createNewItemRenderer={allowCreate ? renderCreateFilmMenuItem : undefined}
8888
fill={fill}

packages/select/src/__examples__/films.tsx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export interface Film {
3030
}
3131

3232
/** Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top */
33-
export const TOP_100_FILMS: readonly Film[] = [
33+
export const TOP_100_FILMS: Film[] = [
3434
{ title: "The Shawshank Redemption", year: 1994 },
3535
{ title: "The Godfather", year: 1972 },
3636
{ title: "The Godfather: Part II", year: 1974 },
@@ -270,7 +270,7 @@ export function createFilm(title: string): Film {
270270
};
271271
}
272272

273-
export function createFilms(query: string): readonly Film[] {
273+
export function createFilms(query: string): Film[] {
274274
const titles = query.split(", ");
275275
return titles.map((title, index) => ({
276276
rank: 100 + Math.floor(Math.random() * 100 + index),
@@ -288,23 +288,23 @@ export function doesFilmEqualQuery(film: Film, query: string) {
288288
return film.title.toLowerCase() === query.toLowerCase();
289289
}
290290

291-
export function arrayContainsFilm(films: readonly Film[], filmToFind: Film): boolean {
291+
export function arrayContainsFilm(films: Film[], filmToFind: Film): boolean {
292292
return films.some((film: Film) => film.title === filmToFind.title);
293293
}
294294

295-
export function addFilmToArray(films: readonly Film[], filmToAdd: Film): readonly Film[] {
295+
export function addFilmToArray(films: Film[], filmToAdd: Film) {
296296
return [...films, filmToAdd];
297297
}
298298

299-
export function deleteFilmFromArray(films: readonly Film[], filmToDelete: Film): readonly Film[] {
299+
export function deleteFilmFromArray(films: Film[], filmToDelete: Film) {
300300
return films.filter(film => film !== filmToDelete);
301301
}
302302

303303
export function maybeAddCreatedFilmToArrays(
304-
items: readonly Film[],
305-
createdItems: readonly Film[],
304+
items: Film[],
305+
createdItems: Film[],
306306
film: Film,
307-
): { createdItems: readonly Film[]; items: readonly Film[] } {
307+
): { createdItems: Film[]; items: Film[] } {
308308
const isNewlyCreatedItem = !arrayContainsFilm(items, film);
309309
return {
310310
createdItems: isNewlyCreatedItem ? addFilmToArray(createdItems, film) : createdItems,
@@ -314,10 +314,10 @@ export function maybeAddCreatedFilmToArrays(
314314
}
315315

316316
export function maybeDeleteCreatedFilmFromArrays(
317-
items: readonly Film[],
318-
createdItems: readonly Film[],
317+
items: Film[],
318+
createdItems: Film[],
319319
film: Film | undefined,
320-
): { createdItems: readonly Film[]; items: readonly Film[] } {
320+
): { createdItems: Film[]; items: Film[] } {
321321
if (film === undefined) {
322322
return {
323323
createdItems,

packages/select/src/common/itemListRenderer.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import type { CreateNewItem } from "./listItemsUtils";
2020
* An object describing how to render the list of items.
2121
* An `itemListRenderer` receives this object as its sole argument.
2222
*/
23-
export interface ItemListRendererProps<T, A extends readonly T[] = T[]> {
23+
export interface ItemListRendererProps<T> {
2424
/**
2525
* The currently focused item (for keyboard interactions), or `null` to
2626
* indicate that no item is active.
@@ -35,13 +35,13 @@ export interface ItemListRendererProps<T, A extends readonly T[] = T[]> {
3535
* map each item in this array through `renderItem`, with support for
3636
* optional `noResults` and `initialContent` states.
3737
*/
38-
filteredItems: A;
38+
filteredItems: T[];
3939

4040
/**
4141
* Array of all items in the list.
4242
* See `filteredItems` for a filtered array based on `query` and predicate props.
4343
*/
44-
items: A;
44+
items: T[];
4545

4646
/**
4747
* The current query string.
@@ -75,17 +75,15 @@ export interface ItemListRendererProps<T, A extends readonly T[] = T[]> {
7575
}
7676

7777
/** Type alias for a function that renders the list of items. */
78-
export type ItemListRenderer<T, A extends readonly T[] = T[]> = (
79-
itemListProps: ItemListRendererProps<T, A>,
80-
) => React.JSX.Element | null;
78+
export type ItemListRenderer<T> = (itemListProps: ItemListRendererProps<T>) => React.JSX.Element | null;
8179

8280
/**
8381
* `ItemListRenderer` helper method for rendering each item in `filteredItems`,
8482
* with optional support for `noResults` (when filtered items is empty)
8583
* and `initialContent` (when query is empty).
8684
*/
87-
export function renderFilteredItems<T, A extends readonly T[] = T[]>(
88-
props: ItemListRendererProps<T, A>,
85+
export function renderFilteredItems(
86+
props: ItemListRendererProps<any>,
8987
noResults?: React.ReactNode,
9088
initialContent?: React.ReactNode | null,
9189
): React.ReactNode {

packages/select/src/common/listItemsProps.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export type ItemsEqualComparator<T> = (itemA: T, itemB: T) => boolean;
3434
export type ItemsEqualProp<T> = ItemsEqualComparator<T> | keyof T;
3535

3636
/** Reusable generic props for a component that operates on a filterable, selectable list of `items`. */
37-
export interface ListItemsProps<T, A extends readonly T[] = T[]> extends Props {
37+
export interface ListItemsProps<T> extends Props {
3838
/**
3939
* The currently focused item for keyboard interactions, or `null` to
4040
* indicate that no item is active. If omitted or `undefined`, this prop will be
@@ -44,7 +44,7 @@ export interface ListItemsProps<T, A extends readonly T[] = T[]> extends Props {
4444
activeItem?: T | CreateNewItem | null;
4545

4646
/** Array of items in the list. */
47-
items: A;
47+
items: T[];
4848

4949
/**
5050
* Specifies how to test if two items are equal. By default, simple strict
@@ -75,7 +75,7 @@ export interface ListItemsProps<T, A extends readonly T[] = T[]> extends Props {
7575
*
7676
* If `itemPredicate` is also defined, this prop takes priority and the other will be ignored.
7777
*/
78-
itemListPredicate?: ItemListPredicate<T, A>;
78+
itemListPredicate?: ItemListPredicate<T>;
7979

8080
/**
8181
* Customize querying of individual items.
@@ -110,7 +110,7 @@ export interface ListItemsProps<T, A extends readonly T[] = T[]> extends Props {
110110
* and wraps them all in a `Menu` element. If the query is empty then `initialContent` is returned,
111111
* and if there are no items that match the predicate then `noResults` is returned.
112112
*/
113-
itemListRenderer?: ItemListRenderer<T, A>;
113+
itemListRenderer?: ItemListRenderer<T>;
114114

115115
/**
116116
* React content to render when query is empty.
@@ -157,7 +157,7 @@ export interface ListItemsProps<T, A extends readonly T[] = T[]> extends Props {
157157
/**
158158
* Callback invoked when multiple items are selected at once via pasting.
159159
*/
160-
onItemsPaste?: (items: A) => void;
160+
onItemsPaste?: (items: T[]) => void;
161161

162162
/**
163163
* Callback invoked when the query string changes.
@@ -170,7 +170,7 @@ export interface ListItemsProps<T, A extends readonly T[] = T[]> extends Props {
170170
* created, either by pressing the `Enter` key or by clicking on the "Create
171171
* Item" option. It transforms a query string into one or many items type.
172172
*/
173-
createNewItemFromQuery?: (query: string) => T | A;
173+
createNewItemFromQuery?: (query: string) => T | T[];
174174

175175
/**
176176
* Custom renderer to transform the current query string into a selectable

packages/select/src/common/predicate.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
* A custom predicate for returning an entirely new `items` array based on the provided query.
1919
* See usage sites in `ListItemsProps`.
2020
*/
21-
export type ItemListPredicate<T, A extends readonly T[] = T[]> = (query: string, items: A) => A;
21+
export type ItemListPredicate<T> = (query: string, items: T[]) => T[];
2222

2323
/**
2424
* A custom predicate for filtering items based on the provided query.

0 commit comments

Comments
 (0)