Skip to content

Commit ac47455

Browse files
github-actions[bot]GitHub CopilotCopilotIzumiSy
authored
[docs-update] Update docs for Menu, Select, Combobox, and Autocomplete components (#97)
* docs: add Menu, Select, Combobox, and Autocomplete component docs Add documentation for four new components introduced in changeset bright-waves-dance.md: - docs/components/menu.md: compound component API, checkbox/radio items, groups, separators, and nested sub-menus - docs/components/select.md: single/multi-select, grouped items, async loading via Select.Async, and SelectAsyncFetcher type - docs/components/combobox.md: searchable combobox, multi-select chips, creatable items via onCreateItem, async loading via Combobox.Async - docs/components/autocomplete.md: free-text input with suggestions, async loading via Autocomplete.Async Also update the Documentation Index in CLAUDE.md with links to all four new doc files. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix fetcher usage --------- Co-authored-by: GitHub Copilot <copilot@github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: IzumiSy <beetle-noise@gmx.com>
1 parent e7a1177 commit ac47455

File tree

5 files changed

+807
-0
lines changed

5 files changed

+807
-0
lines changed

CLAUDE.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,12 @@ This project has comprehensive documentation organized in the `docs/` directory:
2525
- **[Input](./docs/components/input.md)** - Styled text input
2626
- **[Table](./docs/components/table.md)** - Semantic HTML table sub-components
2727
- **[Dialog](./docs/components/dialog.md)** - Modal dialog with compound component API
28+
- **[Menu](./docs/components/menu.md)** - Dropdown menu with compound component API, checkbox/radio items, groups, and sub-menus
2829
- **[Sheet](./docs/components/sheet.md)** - Slide-in panel with swipe-to-dismiss support
2930
- **[Tooltip](./docs/components/tooltip.md)** - Hover/focus tooltip with placement options
31+
- **[Select](./docs/components/select.md)** - Single or multi-select dropdown with optional async loading
32+
- **[Combobox](./docs/components/combobox.md)** - Searchable combobox with filtering, multi-select, async loading, and creatable items
33+
- **[Autocomplete](./docs/components/autocomplete.md)** - Free-text input with a suggestion list and optional async loading
3034

3135
## Key Architecture Points (LLM Orientation)
3236

docs/components/autocomplete.md

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
---
2+
title: Autocomplete
3+
description: Text input with a suggestion list — value is the raw input string, not a discrete item selection
4+
---
5+
6+
# Autocomplete
7+
8+
The `Autocomplete` component provides a free-text input with a suggestion list. Unlike `Select` and `Combobox`, the component value is the raw input string — not a discrete item selection. For async suggestions use `Autocomplete.Async`. For custom compositions use `Autocomplete.Parts`.
9+
10+
## Import
11+
12+
```tsx
13+
import { Autocomplete } from "@tailor-platform/app-shell";
14+
```
15+
16+
## Basic Usage
17+
18+
```tsx
19+
<Autocomplete
20+
items={["Apple", "Banana", "Cherry"]}
21+
placeholder="Type a fruit..."
22+
onValueChange={(value) => console.log(value)}
23+
/>
24+
```
25+
26+
## Props
27+
28+
### Autocomplete Props
29+
30+
| Prop | Type | Default | Description |
31+
| --------------- | ------------------------- | --------------- | ------------------------------------------------------------------- |
32+
| `items` | `I[]` | - | Suggestion items. May be a flat array or an array of `ItemGroup<T>` |
33+
| `placeholder` | `string` | - | Placeholder text for the input |
34+
| `emptyText` | `string` | `"No results."` | Text shown when no items match |
35+
| `value` | `string` | - | Controlled value (raw input string) |
36+
| `defaultValue` | `string` | - | Initial value (uncontrolled) |
37+
| `onValueChange` | `(value: string) => void` | - | Called when the value changes |
38+
| `mapItem` | `(item: T) => MappedItem` | - | Map each item to its label, key, and optional custom render |
39+
| `className` | `string` | - | Additional CSS classes for the root container |
40+
| `disabled` | `boolean` | `false` | Disables the autocomplete |
41+
42+
### MappedItem
43+
44+
```ts
45+
interface MappedItem {
46+
label: string; // Display text, used for filtering and a11y
47+
key?: string; // React key. Defaults to label
48+
render?: React.ReactNode; // Custom JSX to render in the dropdown
49+
}
50+
```
51+
52+
### ItemGroup
53+
54+
```ts
55+
interface ItemGroup<T> {
56+
label: string;
57+
items: T[];
58+
}
59+
```
60+
61+
## Grouped Suggestions
62+
63+
```tsx
64+
const cities = [
65+
{ label: "Japan", items: ["Tokyo", "Osaka", "Kyoto"] },
66+
{ label: "France", items: ["Paris", "Lyon", "Marseille"] },
67+
];
68+
69+
<Autocomplete items={cities} placeholder="Search cities..." />;
70+
```
71+
72+
## Object Items with mapItem
73+
74+
When items are objects, use `mapItem` to tell the component how to display them. The selected value is the item's `label` string returned by `mapItem`:
75+
76+
```tsx
77+
type City = { code: string; name: string };
78+
79+
const cities: City[] = [
80+
{ code: "TYO", name: "Tokyo" },
81+
{ code: "OSA", name: "Osaka" },
82+
];
83+
84+
<Autocomplete
85+
items={cities}
86+
mapItem={(city) => ({ label: city.name, key: city.code })}
87+
placeholder="Search cities..."
88+
onValueChange={(name) => console.log(name)} // receives "Tokyo", "Osaka", etc.
89+
/>;
90+
```
91+
92+
## Async Suggestions
93+
94+
Use `Autocomplete.Async` to fetch suggestions as the user types. The fetcher is called on each keystroke (debounced).
95+
96+
```tsx
97+
import { type AutocompleteAsyncFetcher } from "@tailor-platform/app-shell";
98+
99+
const fetcher: AutocompleteAsyncFetcher<string> = async (query, { signal }) => {
100+
const res = await fetch(`/api/suggestions?q=${query}`, { signal });
101+
return res.json();
102+
};
103+
104+
<Autocomplete.Async
105+
fetcher={fetcher}
106+
placeholder="Search..."
107+
onValueChange={(value) => console.log(value)}
108+
/>;
109+
```
110+
111+
### Autocomplete.Async Props
112+
113+
Accepts all the same props as `Autocomplete` except `items`, plus:
114+
115+
| Prop | Type | Default | Description |
116+
| ------------- | ----------------------------- | -------------- | ------------------------------------------------------- |
117+
| `fetcher` | `AutocompleteAsyncFetcher<T>` | - | Fetcher called on each keystroke (debounced by default) |
118+
| `loadingText` | `string` | `"Loading..."` | Text shown while loading |
119+
120+
### AutocompleteAsyncFetcher
121+
122+
```ts
123+
type AutocompleteAsyncFetcher<T> =
124+
| ((query: string, options: { signal: AbortSignal }) => Promise<T[]>)
125+
| { fn: (query: string, options: { signal: AbortSignal }) => Promise<T[]>; debounceMs: number };
126+
```
127+
128+
Pass `{ fn, debounceMs }` to customize the debounce delay. Errors thrown by the fetcher are silently caught — handle errors inside the fetcher.
129+
130+
## Low-level Primitives
131+
132+
`Autocomplete.Parts` exposes styled sub-components and hooks for fully custom compositions:
133+
134+
```tsx
135+
const {
136+
Root,
137+
Value,
138+
InputGroup,
139+
Input,
140+
Trigger,
141+
Content,
142+
List,
143+
Item,
144+
Empty,
145+
Clear,
146+
Group,
147+
GroupLabel,
148+
Collection,
149+
Status,
150+
useFilter,
151+
useAsync,
152+
} = Autocomplete.Parts;
153+
```
154+
155+
## Examples
156+
157+
### Controlled Autocomplete
158+
159+
```tsx
160+
const [query, setQuery] = useState("");
161+
162+
<Autocomplete items={suggestions} value={query} onValueChange={setQuery} placeholder="Search..." />;
163+
```
164+
165+
### Address Input with Async Suggestions
166+
167+
```tsx
168+
const fetcher: AutocompleteAsyncFetcher<string> = async (query, { signal }) => {
169+
if (!query) return [];
170+
const res = await fetch(`/api/address-lookup?q=${encodeURIComponent(query)}`, { signal });
171+
return res.json();
172+
};
173+
174+
<Autocomplete.Async
175+
fetcher={fetcher}
176+
placeholder="Start typing an address..."
177+
onValueChange={(address) => form.setValue("address", address)}
178+
/>;
179+
```
180+
181+
## Accessibility
182+
183+
- Input is keyboard accessible with arrow key navigation
184+
- Pressing `Escape` closes the suggestion list
185+
- Selecting a suggestion fills the input with the item's label
186+
187+
## Related Components
188+
189+
- [Select](./select.md) - Non-searchable discrete item selection
190+
- [Combobox](./combobox.md) - Searchable combobox that returns discrete items
191+
- [Input](./input.md) - Plain text input without suggestions

0 commit comments

Comments
 (0)