import React, { useMemo, useState, useEffect } from "react"; import { screen, userEvent } from "@storybook/testing-library"; import { expect, jest } from "@storybook/jest"; import { Box } from "../box"; import { matchSorter } from "match-sorter"; import { InputSearch } from "./"; import { cities } from "./cities"; import type { StoryFn } from "@storybook/react"; export default { title: "InputSearch", component: InputSearch.Root, subcomponents: { Input: InputSearch.Input, Popover: InputSearch.Popover, List: InputSearch.List, ListItem: InputSearch.ListItem, ListHeading: InputSearch.ListHeading, EmptyState: InputSearch.EmptyState, LoadingState: InputSearch.LoadingState, }, }; const useCityMatch = (term: string) => { return useMemo( () => term.trim() === "" ? null : matchSorter(cities, term, { keys: [(item) => `${item.city}, ${item.state}`], }), [term] ); }; const Template: StoryFn = (args) => { const [term, setTerm] = useState(""); const results: { city: string; state: string }[] | null = useCityMatch(term); return ( { setTerm(event.target.value); }} /> {results && ( {results.length > 0 ? ( {results.slice(0, 20).map((result) => ( ))} ) : ( )} )} ); }; export const Play = { render: Template, args: {}, name: "InputSearch", parameters: { chromatic: { disableSnapshot: true }, }, }; const fetchCities = (value) => { if (value == "") { return []; } return new Promise((resolve) => setTimeout( resolve, 3000, matchSorter(cities, value, { keys: [(item) => `${item.city}, ${item.state}`], }) ) ); }; const AsyncTemplate: StoryFn = (args) => { const [searchTerm, setSearchTerm] = useState(""); const [results, setResults] = useState< { city: string; state: string }[] | undefined >(); useEffect(() => { if (searchTerm === "") { setResults(undefined); } else { setResults([]); const fetch = async () => { const response = await fetchCities(searchTerm); setResults(response as { city: string; state: string }[]); }; fetch(); } }, [searchTerm, setResults]); return ( { setSearchTerm(event.target.value); }} /> {results && ( {results.length > 0 ? ( {results.slice(0, 20).map((result) => ( ))} ) : ( )} )} ); }; export const Async = { render: AsyncTemplate, args: {}, parameters: { chromatic: { disableSnapshot: true }, }, }; const GroupingTemplate: StoryFn = (args) => { return ( Fruits ); }; export const Grouping = { render: GroupingTemplate, args: {}, parameters: { chromatic: { disableSnapshot: true }, }, }; const DisabledTemplate: StoryFn = (args) => { return ( ); }; export const Disabled = { render: DisabledTemplate, args: {}, parameters: { chromatic: { disableSnapshot: true }, }, }; const ScrollTemplate: StoryFn = (args) => { return ( ); }; export const Scroll = { render: ScrollTemplate, args: {}, parameters: { chromatic: { disableSnapshot: true }, }, }; const ControlledTemplate: StoryFn = (args) => { const [term, setTerm] = useState(""); return ( <>
{ setTerm(value); console.log("onSelect", value); args.onSelect && args.onSelect(value); }} > { setTerm(event.target.value); }} /> ); }; export const Controlled = { render: ControlledTemplate, args: { onSelect: jest.fn(), }, parameters: { chromatic: { disableSnapshot: true }, }, }; const InteractionsTemplate: StoryFn = (args) => ( ); export const Interactions = { render: InteractionsTemplate, args: { onSelect: jest.fn(), }, play: async ({ args }) => { const input = await screen.findByLabelText("Search"); await userEvent.type(input, "app", { delay: 100, }); await userEvent.keyboard("[ArrowDown]"); await expect(input).toHaveDisplayValue("Apple"); await userEvent.keyboard("[Enter]"); await expect(args.onSelect).toHaveBeenCalledWith("Apple"); const clearButton = await screen.findByRole("button", { name: "Clear" }); await userEvent.click(clearButton); await expect(args.onSelect).toHaveBeenCalledWith(""); }, }; export const ControlledKeyboardInteractions = { render: ControlledTemplate, play: async ({ args }) => { const input = await screen.findByLabelText("Search"); await userEvent.type(input, "test", { delay: 100, }); await userEvent.keyboard("[ArrowDown]"); await userEvent.keyboard("[ArrowDown]"); await userEvent.keyboard("[ArrowDown]"); await expect(input).toHaveDisplayValue("Orange"); await userEvent.keyboard("[Backspace]"); await expect(input).toHaveDisplayValue("Orang"); await userEvent.keyboard("[ArrowUp]"); await userEvent.keyboard("[Enter]"); await expect(args.onSelect).toHaveBeenCalledWith("Pineapple"); const clearButton = await screen.findByText("Clear"); await userEvent.click(clearButton); await expect(input).toHaveDisplayValue(""); await userEvent.type(input, "test", { delay: 100, }); await userEvent.keyboard("[ArrowDown]"); await expect(input).toHaveDisplayValue("Apple"); const externalClearButton = await screen.findByText("External Clear"); await userEvent.click(externalClearButton); await expect(input).toHaveDisplayValue(""); await userEvent.click(input); await expect(input).toHaveFocus(); const appleOption = await screen.findByRole("option", { name: "Apple" }); await userEvent.click(appleOption); await expect(input).toHaveDisplayValue("Apple"); await expect(args.onSelect).toHaveBeenCalledWith("Apple"); // }, };