Skip to content

Instantly share code, notes, and snippets.

@ryanflorence
Created November 7, 2018 17:55
Show Gist options
  • Select an option

  • Save ryanflorence/669e04f4ee833555a16aae649cb8d2ae to your computer and use it in GitHub Desktop.

Select an option

Save ryanflorence/669e04f4ee833555a16aae649cb8d2ae to your computer and use it in GitHub Desktop.

Revisions

  1. ryanflorence renamed this gist Nov 7, 2018. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. ryanflorence created this gist Nov 7, 2018.
    118 changes: 118 additions & 0 deletions App.Combobox.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,118 @@
    import React, { Suspense, useState } from "react";
    import { unstable_createResource as createResource } from "react-cache";
    import {
    Autocomplete as Combobox,
    Input as ComboboxInput,
    List as ComboboxList,
    Option as ComboboxOption
    } from "./Combobox";

    function App({ tabIndex, navigate }) {
    let [searchTerm, setSearchTerm] = useState(null);

    function handleSelect(value) {
    console.log("SELECTED!", value);
    }

    return (
    <div>
    <h1 style={{ textAlign: "center" }}>Combobox</h1>
    <p>
    <b>Features / Keyboard events</b>
    </p>
    <ul style={{ lineHeight: 1.5 }}>
    <li>Autocompletes first suggestion</li>
    <li>ArrowDown/Up navigate the list</li>
    <li>
    When navigating with arrow keys
    <ul>
    <li>The input's value changes to the item</li>
    <li>
    Enter
    <ul>
    <li>Selects an item (calls onSelect prop)</li>
    <li>List closes</li>
    <li>Text is selected</li>
    </ul>
    </li>
    <li>
    Escape
    <ul>
    <li>Puts the value back to what it was before</li>
    <li>Including autocompleted portion</li>
    </ul>
    </li>
    </ul>
    </li>
    <li>
    Escape while typing (not navigating)
    <ul>
    <li>Closes the list</li>
    <li>Selects the text</li>
    </ul>
    </li>
    </ul>
    <Combobox onSelect={handleSelect}>
    <ComboboxInput
    onChange={async event => {
    let value = event.target.value;
    await Promise.resolve();
    setSearchTerm(value);
    }}
    />
    <Suspense maxDuration={2000} fallback={<div>Loading...</div>}>
    <AsyncList searchTerm={searchTerm} />
    </Suspense>
    </Combobox>
    <div style={{ height: 400 }} />
    </div>
    );
    }

    function AsyncList({ searchTerm }) {
    let options = SearchResource.read(searchTerm);

    return options ? (
    <ComboboxList>
    {options.map(option => (
    <ComboboxOption key={option} value={option}>
    {option}
    </ComboboxOption>
    ))}
    </ComboboxList>
    ) : null;
    }

    let rando = () =>
    Math.random()
    .toString(16)
    .substr(2, 8);

    let SearchResource = createResource(value => {
    return new Promise(resolve => {
    setTimeout(() => {
    resolve(
    value
    ? [
    `${value}${rando()}`,
    `${value}${rando()}`,
    `${value}${rando()}`,
    `${value}${rando()}`,
    `${value}${rando()}`,
    `${value}${rando()}`,
    `${value}${rando()}`,
    `${value}${rando()}`,
    `${value}${rando()}`,
    `${value}${rando()}`
    ]
    : null
    );
    }, Math.random() * 1000);
    });
    });

    export default () => (
    <Suspense maxDuration={5000} fallback={<div>Loading...</div>}>
    <App />
    </Suspense>
    );