Skip to content

Commit

Permalink
Update examples and tests to use readonly array
Browse files Browse the repository at this point in the history
  • Loading branch information
ggdouglas committed Oct 30, 2024
1 parent 8f5925a commit 19cdbee
Show file tree
Hide file tree
Showing 11 changed files with 52 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ const INTENTS = [Intent.NONE, Intent.PRIMARY, Intent.SUCCESS, Intent.DANGER, Int

export interface MultiSelectExampleState {
allowCreate: boolean;
createdItems: Film[];
createdItems: readonly Film[];
disabled: boolean;
fill: boolean;
films: Film[];
films: readonly Film[];
hasInitialContent: boolean;
intent: boolean;
items: Film[];
items: readonly Film[];
matchTargetWidth: boolean;
openOnKeyDown: boolean;
popoverMinimal: boolean;
Expand Down Expand Up @@ -124,7 +124,7 @@ export class MultiSelectExample extends React.PureComponent<ExampleProps, MultiS

return (
<Example options={this.renderOptions()} {...this.props}>
<MultiSelect<Film>
<MultiSelect
{...flags}
createNewItemFromQuery={allowCreate ? createFilms : undefined}
createNewItemRenderer={allowCreate ? renderCreateFilmsMenuItem : null}
Expand Down Expand Up @@ -251,7 +251,9 @@ export class MultiSelectExample extends React.PureComponent<ExampleProps, MultiS
);
}

private renderCustomTarget = (selectedItems: Film[]) => <MultiSelectCustomTarget count={selectedItems.length} />;
private renderCustomTarget = (selectedItems: readonly Film[]) => (
<MultiSelectCustomTarget count={selectedItems.length} />
);

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

Expand Down Expand Up @@ -287,16 +289,16 @@ export class MultiSelectExample extends React.PureComponent<ExampleProps, MultiS
this.selectFilms([film]);
}

private selectFilms(filmsToSelect: Film[]) {
private selectFilms(filmsToSelect: readonly Film[]) {
this.setState(({ createdItems, films, items }) => {
let nextCreatedItems = createdItems.slice();
let nextFilms = films.slice();
let nextItems = items.slice();

filmsToSelect.forEach(film => {
const results = maybeAddCreatedFilmToArrays(nextItems, nextCreatedItems, film);
nextItems = results.items;
nextCreatedItems = results.createdItems;
nextItems = results.items.slice();
nextCreatedItems = results.createdItems.slice();
// Avoid re-creating an item that is already selected (the "Create
// Item" option will be shown even if it matches an already selected
// item).
Expand Down Expand Up @@ -336,7 +338,7 @@ export class MultiSelectExample extends React.PureComponent<ExampleProps, MultiS
}
};

private handleFilmsPaste = (films: Film[]) => {
private handleFilmsPaste = (films: readonly Film[]) => {
// On paste, don't bother with deselecting already selected values, just
// add the new ones.
this.selectFilms(films);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export class OmnibarExample extends React.PureComponent<ExampleProps, OmnibarExa
<KeyComboTag combo="shift + o" />
</span>

<Omnibar<Film>
<Omnibar
{...this.state}
createNewItemFromQuery={maybeCreateNewItemFromQuery}
createNewItemRenderer={maybeCreateNewItemRenderer}
Expand Down
10 changes: 5 additions & 5 deletions packages/docs-app/src/examples/select-examples/selectExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { type Film, FilmSelect, filterFilm, TOP_100_FILMS } from "@blueprintjs/s
export interface SelectExampleState {
allowCreate: boolean;
createFirst: boolean;
createdItems: Film[];
createdItems: readonly Film[];
disableItems: boolean;
disabled: boolean;
fill: boolean;
Expand Down Expand Up @@ -169,7 +169,7 @@ export class SelectExample extends React.PureComponent<ExampleProps, SelectExamp
return /[0-9]/.test(firstLetter) ? "0-9" : firstLetter;
}

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

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

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

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

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

private renderGroupedMenuContent = (
listProps: ItemListRendererProps<Film>,
listProps: ItemListRendererProps<Film, readonly Film[]>,
noResults?: React.ReactNode,
initialContent?: React.ReactNode | null,
) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ import {
export interface SuggestExampleState {
allowCreate: boolean;
closeOnSelect: boolean;
createdItems: Film[];
createdItems: readonly Film[];
disabled: boolean;
fill: boolean;
items: Film[];
items: readonly Film[];
matchTargetWidth: boolean;
minimal: boolean;
openOnKeyDown: boolean;
Expand Down Expand Up @@ -92,7 +92,7 @@ export class SuggestExample extends React.PureComponent<ExampleProps, SuggestExa

return (
<Example options={this.renderOptions()} {...this.props}>
<Suggest<Film>
<Suggest
{...flags}
createNewItemFromQuery={maybeCreateNewItemFromQuery}
createNewItemRenderer={maybeCreateNewItemRenderer}
Expand Down
8 changes: 4 additions & 4 deletions packages/select/src/__examples__/filmSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import {
} from "./films";

type FilmSelectProps = Omit<
SelectProps<Film>,
SelectProps<Film, readonly Film[]>,
| "createNewItemFromQuery"
| "createNewItemRenderer"
| "itemPredicate"
Expand All @@ -49,8 +49,8 @@ type FilmSelectProps = Omit<
};

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

return (
<Select<Film>
<Select
createNewItemFromQuery={allowCreate ? createFilm : undefined}
createNewItemRenderer={allowCreate ? renderCreateFilmMenuItem : undefined}
fill={fill}
Expand Down
22 changes: 11 additions & 11 deletions packages/select/src/__examples__/films.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export interface Film {
}

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

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

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

export function addFilmToArray(films: Film[], filmToAdd: Film) {
export function addFilmToArray(films: readonly Film[], filmToAdd: Film): readonly Film[] {
return [...films, filmToAdd];
}

export function deleteFilmFromArray(films: Film[], filmToDelete: Film) {
export function deleteFilmFromArray(films: readonly Film[], filmToDelete: Film): readonly Film[] {
return films.filter(film => film !== filmToDelete);
}

export function maybeAddCreatedFilmToArrays(
items: Film[],
createdItems: Film[],
items: readonly Film[],
createdItems: readonly Film[],
film: Film,
): { createdItems: Film[]; items: Film[] } {
): { createdItems: readonly Film[]; items: readonly Film[] } {
const isNewlyCreatedItem = !arrayContainsFilm(items, film);
return {
createdItems: isNewlyCreatedItem ? addFilmToArray(createdItems, film) : createdItems,
Expand All @@ -314,10 +314,10 @@ export function maybeAddCreatedFilmToArrays(
}

export function maybeDeleteCreatedFilmFromArrays(
items: Film[],
createdItems: Film[],
items: readonly Film[],
createdItems: readonly Film[],
film: Film | undefined,
): { createdItems: Film[]; items: Film[] } {
): { createdItems: readonly Film[]; items: readonly Film[] } {
if (film === undefined) {
return {
createdItems,
Expand Down
12 changes: 6 additions & 6 deletions packages/select/test/multiSelectTests.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ describe("<MultiSelect>", () => {
items: TOP_100_FILMS,
popoverProps: { isOpen: true, usePortal: false },
query: "",
selectedItems: [] as Film[],
selectedItems: [] as readonly Film[],
tagRenderer: renderTag,
};
let handlers: {
Expand All @@ -50,9 +50,9 @@ describe("<MultiSelect>", () => {
};
});

selectComponentSuite<MultiSelectProps<Film>, MultiSelectState>(props =>
selectComponentSuite<MultiSelectProps<Film, readonly Film[]>, MultiSelectState>(props =>
mount(
<MultiSelect<Film>
<MultiSelect
selectedItems={[]}
{...props}
popoverProps={{ isOpen: true, usePortal: false }}
Expand Down Expand Up @@ -135,7 +135,7 @@ describe("<MultiSelect>", () => {
popoverProps: { usePortal: false },
};

const wrapper = mount(<MultiSelect<Film> {...defaultProps} {...handlers} {...props} />, {
const wrapper = mount(<MultiSelect {...defaultProps} {...handlers} {...props} />, {
attachTo: containerElement,
});

Expand Down Expand Up @@ -167,9 +167,9 @@ describe("<MultiSelect>", () => {
containerElement?.remove();
});

function multiselect(props: Partial<MultiSelectProps<Film>> = {}, query?: string) {
function multiselect(props: Partial<MultiSelectProps<Film, readonly Film[]>> = {}, query?: string) {
const wrapper = mount(
<MultiSelect<Film> {...defaultProps} {...handlers} {...props}>
<MultiSelect {...defaultProps} {...handlers} {...props}>
<article />
</MultiSelect>,
);
Expand Down
4 changes: 3 additions & 1 deletion packages/select/test/queryListTests.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,9 @@ describe("<QueryList>", () => {
});

it("itemListPredicate filters entire list by query", () => {
const predicate = sinon.spy((query: string, films: Film[]) => films.filter(f => f.year === +query));
const predicate = sinon.spy((query: string, films: readonly Film[]) =>
films.filter(f => f.year === +query),
);
shallow(<QueryList<Film> {...testProps} itemListPredicate={predicate} query="1994" />);

assert.equal(predicate.callCount, 1, "called once for entire list");
Expand Down
4 changes: 2 additions & 2 deletions packages/select/test/selectComponentSuite.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ import {
TOP_100_FILMS,
} from "../src/__examples__";

export function selectComponentSuite<P extends ListItemsProps<Film>, S>(
render: (props: ListItemsProps<Film>) => ReactWrapper<P, S>,
export function selectComponentSuite<P extends ListItemsProps<Film, readonly Film[]>, S>(
render: (props: ListItemsProps<Film, readonly Film[]>) => ReactWrapper<P, S>,
findInput: (wrapper: ReactWrapper<P, S>) => ReactWrapper<HTMLInputProps> = wrapper =>
wrapper.find("input") as ReactWrapper<HTMLInputProps>,
findItems: (wrapper: ReactWrapper<P, S>) => ReactWrapper = wrapper => wrapper.find("a"),
Expand Down
6 changes: 3 additions & 3 deletions packages/select/test/selectTests.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ describe("<Select>", () => {
testsContainerElement?.remove();
});

selectComponentSuite<SelectProps<Film>, SelectState>(props =>
selectComponentSuite<SelectProps<Film, readonly Film[]>, SelectState>(props =>
mount(<Select {...props} popoverProps={{ isOpen: true, usePortal: false }} />),
);

Expand Down Expand Up @@ -179,9 +179,9 @@ describe("<Select>", () => {
assert.isTrue(wrapper.find(Popover).prop("isOpen"));
});

function select(props: Partial<SelectProps<Film>> = {}, query?: string) {
function select(props: Partial<SelectProps<Film, readonly Film[]>> = {}, query?: string) {
const wrapper = mount(
<Select<Film> {...defaultProps} {...handlers} {...props}>
<Select {...defaultProps} {...handlers} {...props}>
<Button data-testid="target-button" text="Target" />
</Select>,
{ attachTo: testsContainerElement },
Expand Down
6 changes: 3 additions & 3 deletions packages/select/test/suggestTests.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ describe("Suggest", () => {
testsContainerElement?.remove();
});

selectComponentSuite<SuggestProps<Film>, SuggestState<Film>>(props =>
selectComponentSuite<SuggestProps<Film, readonly Film[]>, SuggestState<Film>>(props =>
mount(
<Suggest
{...props}
Expand Down Expand Up @@ -338,8 +338,8 @@ describe("Suggest", () => {
});
});

function suggest(props: Partial<SuggestProps<Film>> = {}) {
return mount<Suggest<Film>>(<Suggest<Film> {...defaultProps} {...handlers} {...props} />, {
function suggest(props: Partial<SuggestProps<Film, readonly Film[]>> = {}) {
return mount<SuggestProps<Film, readonly Film[]>>(<Suggest {...defaultProps} {...handlers} {...props} />, {
attachTo: testsContainerElement,
});
}
Expand Down

0 comments on commit 19cdbee

Please sign in to comment.