@codapet/design-system 0.8.5 → 0.8.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md CHANGED
@@ -15,6 +15,45 @@ This is a **shadcn/ui-style** library (Radix primitives + cva variants + Tailwin
15
15
  - ESM-only. If a consumer uses Jest, add the package to `transformIgnorePatterns` (or use Vitest, which handles it).
16
16
  - Single entry: `from '@codapet/design-system'`. There are **no subpath component imports** — only `'@codapet/design-system'` and `'@codapet/design-system/styles'` exist.
17
17
 
18
+ ## Finding exact props: read the shipped types
19
+
20
+ `dist/index.d.mts` is the authoritative API reference, and it ships inside the
21
+ package with every JSDoc comment intact. When you need a component's exact
22
+ props, defaults, or union values, **read it instead of guessing**:
23
+
24
+ ```
25
+ node_modules/@codapet/design-system/dist/index.d.mts
26
+ ```
27
+
28
+ Grep it for the type you want — `interface SearchInputProps`,
29
+ `interface AsyncAutocompleteProps` — and you get every prop with its
30
+ documentation. It is regenerated from source on every release, so it cannot go
31
+ stale.
32
+
33
+ **One trap when reading the types.** Many components take props that never
34
+ appear in their interface body, because they come from a cva:
35
+
36
+ ```ts
37
+ interface BadgeNumberProps
38
+ extends React.ComponentProps<'span'>,
39
+ VariantProps<typeof badgeNumberVariants> { value: number }
40
+ ```
41
+
42
+ Grepping `interface BadgeNumberProps` suggests `value` is the only prop, but
43
+ `state` (`'active' | 'disabled' | 'resting'`, default `'active'`) is real — it
44
+ lives in `badgeNumberVariants`. Whenever an interface extends
45
+ `VariantProps<typeof xVariants>`, read the `declare const xVariants` entry just
46
+ above it for the remaining props. `variant`, `size`, `state` and `colorScheme`
47
+ almost always arrive this way.
48
+
49
+ Division of labour: **this guide covers what is surprising** (defaults that
50
+ differ from shadcn, which component to reach for, gotchas). **The `.d.mts`
51
+ covers what is exhaustive.** Read this file first to pick the right component,
52
+ then the types to get its props right.
53
+
54
+ The docs app in this repo also has a live example page per component, and the
55
+ richer ones (`SmartDialog*`, `AsyncAutocomplete`) carry a full props table.
56
+
18
57
  ## Required setup in a consumer (Tailwind v4)
19
58
 
20
59
  In the app's global CSS:
@@ -107,6 +146,7 @@ These don't exist in shadcn — reach for them instead of building your own:
107
146
  | `SearchableSelect` | Combobox-style select with search; supports `mode="single"` or `"multiple"` + `maxCount` for tag overflow. |
108
147
  | `MultiSelectFreeText` | Tag input where users can type free text **and** pick from suggestions. |
109
148
  | `SearchInput` | Search field with `variant="icon"` or `"button"`, suggestions dropdown, and clear button. Don't compose this from `Input` + a Search icon. |
149
+ | `AsyncAutocomplete` | Type-ahead over an **async** source — a Places lookup, a REST search. You own fetching and debouncing; it renders `options` verbatim, never filtering. Full ARIA combobox with keyboard nav, portaled panel, and it dismisses the moment the user scrolls. `mobileVariant="sheet"` makes it a full-screen takeover under 768px. Restyle any part through the `classNames` slot object. For a **static** list reach for `SearchableSelect` instead. |
110
150
  | `DateInput` / `DateRangeInput` | Text input + Calendar popover. Controlled via `date`/`setDate` (or `dateRange`/`setDateRange`). Configurable `dateFormat` (15 options including `'MMM D, YYYY'`, `'DD/MM/YYYY'`, etc.). Prefer over a bare `Calendar`. |
111
151
  | `TimeInput` | Time picker with `timeFormat` = `'12h' \| '24h' \| 'h:mm a' \| 'h:mm A'`. Value is `{ hours, minutes }`, not a `Date`. |
112
152
  | `AutoResizeTextarea` | Textarea that grows with content; `maxHeight` enables scroll. Handles RHF `setValue`/`reset` correctly. |
@@ -115,6 +155,138 @@ These don't exist in shadcn — reach for them instead of building your own:
115
155
  | `Typography`: `DisplayHeading`, `HeadingXL` … `HeadingXXS` (+ `*Medium` variants), `Body` | Use these instead of raw `<h1>`/`<p>` to inherit the right tokens (`font-serif italic` for display, `text-vibrant-text-heading` for headings, `text-vibrant-text-body` for body). Sizes are responsive (md: breakpoint baked in). |
116
156
  | `ThemeToggle` | Drop-in light/dark toggle. |
117
157
 
158
+ ## Choosing the right component
159
+
160
+ The most common agent mistake here is not a wrong prop, it is reaching for the
161
+ wrong component. Work from the task:
162
+
163
+ | The task | Use | Not |
164
+ |---|---|---|
165
+ | Type-ahead whose results come from an API | `AsyncAutocomplete` | `SearchInput`, whose suggestions are a static prop and whose dropdown pushes page content down |
166
+ | Pick one/many from a **static** list, with search | `SearchableSelect` | `AsyncAutocomplete`, which never filters — it renders `options` verbatim |
167
+ | Pick one from a short static list, no search | `DropdownSelect` | `Select` (heavier; still fine when you need native-select semantics) |
168
+ | Free-text entry **plus** suggestions, many values | `MultiSelectFreeText` | a hand-rolled `Input` + chips |
169
+ | A search field with a visible Search button | `SearchInput` | `Input` + a magnifier icon |
170
+ | Command palette / fuzzy launcher | `Command*` | `SearchableSelect` |
171
+ | Modal that should bottom-sheet on phones | `SmartDialog*` | `Dialog*` |
172
+ | Modal that is a dialog at every size | `Dialog*` | `SmartDialog*` |
173
+ | Panel sliding from a screen edge | `Sheet*` | `Drawer*` |
174
+ | Bottom sheet with drag-to-dismiss at every size | `Drawer*` | `Sheet*` |
175
+ | Destructive confirm | `AlertDialog*` | `Dialog*` |
176
+ | Inline, page-level notice | `AlertBanner` | `Alert` (the shadcn-equivalent, quieter) |
177
+ | Transient notification | `toast` + `Toaster` | `AlertBanner` |
178
+ | Date, or date range | `DateInput` / `DateRangeInput` | a bare `Calendar` |
179
+ | Time of day | `TimeInput` (value is `{ hours, minutes }`, not a `Date`) | `Input type="time"` |
180
+ | Any heading or body copy | `DisplayHeading` / `Heading*` / `Body` | raw `<h1>`/`<p>`, which miss the tokens |
181
+ | Textarea that grows with content | `AutoResizeTextarea` | `Textarea` + manual resize |
182
+ | Selectable card with a radio/checkbox | `OptionCard` | `Card` + a `Checkbox` |
183
+ | Step or count pill | `BadgeNumber` | `Badge` |
184
+ | Clickable filter chip | `BadgeActionable` | `Button variant="outline"` |
185
+ | Read-only metadata pill | `BadgeInformative` | `Badge` |
186
+
187
+ ## Dialogs, drawers and sheets — read this before writing one
188
+
189
+ Four families, and they are the most common source of broken code here. Each
190
+ has its own React context, so **parts are never interchangeable**: a
191
+ `DialogContent` inside a `SmartDialog` throws on mobile, because the root
192
+ rendered a vaul `Drawer` and the child asked for a Radix Dialog context that
193
+ does not exist. Pick a family and use only its parts.
194
+
195
+ | Family | Parts | Renders as |
196
+ |---|---|---|
197
+ | `Dialog*` | Root, Trigger, Content, Header, Footer, Title, Description, Close, Overlay, Portal | Centred modal at every size |
198
+ | `SmartDialog*` | Root, Trigger, Content, Header, Footer, Title, Description, Close — **8 parts, no Overlay/Portal/Body** | `Dialog` above 600px, `Drawer` at/below |
199
+ | `Drawer*` | Root, Trigger, Content, Header, Footer, Title, Description, Close, Overlay, Portal | vaul sheet, draggable, `max-h-[80vh]` |
200
+ | `Sheet*` | Root, Trigger, Content, Header, Footer, Title, Description, Close | Edge panel, `w-3/4 sm:max-w-sm` |
201
+
202
+ ### Never wrap `*Content` in a Portal or Overlay
203
+
204
+ `DialogContent`, `DrawerContent` and `SheetContent` **already render their own
205
+ Portal and Overlay internally.** Stock shadcn composes them by hand, so a copied
206
+ example produces two stacked backdrops (visibly double-dimmed) and two portals:
207
+
208
+ ```tsx
209
+ // ❌ copied from shadcn — double overlay
210
+ <Dialog>
211
+ <DialogPortal>
212
+ <DialogOverlay />
213
+ <DialogContent>…</DialogContent>
214
+ </DialogPortal>
215
+ </Dialog>
216
+
217
+ // ✅ here
218
+ <Dialog>
219
+ <DialogTrigger asChild><Button>Open</Button></DialogTrigger>
220
+ <DialogContent>
221
+ <DialogHeader>
222
+ <DialogTitle>Confirm</DialogTitle>
223
+ <DialogDescription>This cannot be undone.</DialogDescription>
224
+ </DialogHeader>
225
+ <DialogFooter>
226
+ <DialogClose asChild><Button variant="ghost">Cancel</Button></DialogClose>
227
+ <Button variant="destructive">Delete</Button>
228
+ </DialogFooter>
229
+ </DialogContent>
230
+ </Dialog>
231
+ ```
232
+
233
+ `DialogPortal` / `DialogOverlay` / `DrawerPortal` / `DrawerOverlay` are exported
234
+ only because shadcn exports them. **You almost never need them.** To restyle the
235
+ backdrop, pass `overlayClassName` to `DialogContent` / `DrawerContent` /
236
+ `SmartDialogContent` — `SheetContent` and `AlertDialogContent` do not accept it.
237
+
238
+ ### `withCloseButton` is the drag handle, not the close button
239
+
240
+ On `DrawerContent` and `SmartDialogContent`:
241
+
242
+ - `showCloseButton` (default `true`) — the round **X** in the top-right.
243
+ - `withCloseButton` (default `true`) — the small grey **drag pill**, and only for
244
+ `direction="bottom"`. The name is misleading; it has nothing to do with the X.
245
+
246
+ So `withCloseButton={false}` still leaves the X. To remove the X, pass
247
+ `showCloseButton={false}`. `SmartDialogContent` forwards `showCloseButton` to
248
+ both variants, so the X stays consistent across the breakpoint.
249
+
250
+ ### `direction` goes on both the root and the content
251
+
252
+ vaul needs it on the root for gesture handling; the content needs it for its own
253
+ edge/rounding classes. Setting only one gives a drawer that animates from one
254
+ edge and is styled for another:
255
+
256
+ ```tsx
257
+ <Drawer direction="right">
258
+ <DrawerContent direction="right">…</DrawerContent>
259
+ </Drawer>
260
+ ```
261
+
262
+ `Sheet` uses `side` instead (`'top' | 'right' | 'bottom' | 'left'`, default
263
+ `'right'`), on `SheetContent` only.
264
+
265
+ ### `SmartDialog` specifics
266
+
267
+ - The breakpoint is **600px**, not the 768px `useIsMobile` uses. That is
268
+ deliberate — see the note further down.
269
+ - **The first client render is always the Dialog variant**, then it settles to
270
+ the real one. The server has no viewport, so `useMediaQuery` returns the server
271
+ snapshot during hydration; rendering the true value there would be a hydration
272
+ mismatch. Do not measure the DOM or branch on the variant during first paint.
273
+ - Props are a union of Dialog's and Drawer's, so drawer-only props
274
+ (`direction`, `dismissible`) are accepted and silently ignored above 600px.
275
+ - `Drawer` hardcodes `repositionInputs={false}`, which `SmartDialog` inherits —
276
+ relevant if you put a focused input inside on iOS.
277
+
278
+ ### Always give it a title
279
+
280
+ All four families are Radix-Dialog-based and warn without a `Title`. If the
281
+ design has no visible heading, keep the element and hide it:
282
+
283
+ ```tsx
284
+ <DialogTitle className="sr-only">Edit profile</DialogTitle>
285
+ ```
286
+
287
+ Pass `aria-describedby={undefined}` on the content when there is genuinely no
288
+ `Description`, rather than leaving the warning in the console.
289
+
118
290
  ## Color tokens (don't reach for raw Tailwind colors)
119
291
 
120
292
  The brand palette lives in CSS variables exposed as Tailwind colors. Use these, not `bg-blue-600`, `text-gray-500`, `border-red-300`, etc. — raw colors won't dark-mode correctly.
@@ -141,12 +313,65 @@ Source of truth: `src/styles.css` in this package. If a token is missing, propos
141
313
  - `useTheme()` — re-exported from `next-themes`.
142
314
  - `buttonVariants`, `badgeVariants`, etc. — exported `cva` instances. Use them when you need the same look on a non-button element (e.g. an `<a>` styled like a button) instead of reimplementing the styles.
143
315
 
316
+ ## Complete export index
317
+
318
+ Everything below is imported from the single entry `'@codapet/design-system'`.
319
+ A `Foo*` glob means the whole compound family — `Dialog*` is `Dialog`,
320
+ `DialogTrigger`, `DialogContent`, `DialogHeader`, `DialogFooter`, `DialogTitle`,
321
+ `DialogDescription`, `DialogClose`, `DialogOverlay`, `DialogPortal`. Families
322
+ follow the standard shadcn part names; when unsure, grep the `.d.mts`.
323
+
324
+ **If a name is not in this list, it does not exist — do not import it.**
325
+
326
+ | Area | Exports |
327
+ |---|---|
328
+ | Layout & structure | `AspectRatio`, `Card*`, `Separator`, `ScrollArea`, `ScrollBar`, `Resizable*`, `Sidebar*`, `useSidebar`, `Table*`, `Skeleton` |
329
+ | Typography | `DisplayHeading`, `HeadingXL`, `HeadingL`, `HeadingM`, `HeadingS`, `HeadingXS`, `HeadingXXS` (each with a `*Medium` twin, e.g. `HeadingLMedium`), `Body` |
330
+ | Buttons & badges | `Button`, `Badge`, `BadgeActionable`, `BadgeInformative`, `BadgeInformativeGroup`, `BadgeInformativeItem`, `BadgeNumber`, `Toggle`, `ToggleGroup`, `ToggleGroupItem` |
331
+ | Form fields | `Input`, `Textarea`, `AutoResizeTextarea`, `Label`, `Checkbox`, `RadioGroup`, `RadioGroupItem`, `Switch`, `Slider`, `InputOTP*`, `Form*`, `useFormField`, `OptionCard` |
332
+ | Selection & search | `AsyncAutocomplete*`, `SearchableSelect*`, `SearchInput`, `MultiSelectFreeText`, `DropdownSelect*`, `Select*`, `Command*` |
333
+ | Date & time | `Calendar`, `CalendarDayButton`, `DateInput`, `DateRangeInput`, `TimeInput` |
334
+ | Overlays & menus | `Dialog*`, `AlertDialog*`, `Drawer*`, `Sheet*`, `SmartDialog*`, `Popover*`, `HoverCard*`, `Tooltip*`, `RichTooltip*`, `DropdownMenu*`, `ContextMenu*`, `Menubar*` |
335
+ | Feedback | `Alert`, `AlertTitle`, `AlertDescription`, `AlertBanner`, `Toaster`, `toast`, `Progress`, `ProgressBar` |
336
+ | Navigation | `Tabs*`, `Breadcrumb*`, `Pagination*`, `NavigationMenu*` |
337
+ | Content & data | `Accordion*`, `Collapsible*`, `Avatar*`, `Carousel*`, `Chart*` |
338
+ | Theming & utilities | `ThemeProvider*`, `ThemeToggle`, `cn`, `useIsMobile` |
339
+
340
+ **cva style objects** — use these to give a non-button element a button's look
341
+ rather than reimplementing the classes: `buttonVariants`, `badgeVariants`,
342
+ `badgeActionableVariants`, `badgeInformativeVariants`, `badgeNumberVariants`,
343
+ `alertBannerVariants`, `inputVariants`, `labelTextVariants`, `optionCardVariants`,
344
+ `progressBarVariants`, `tabsTriggerVariants`, `toggleVariants`,
345
+ `bodyTextVariants`, `displayTextVariants`, `navigationMenuTriggerStyle`.
346
+
347
+ **Exported types** — import with `import type`: `InputProps`, `TextareaProps`,
348
+ `SearchInputProps`, `SearchSuggestion`, `AlertBannerProps`,
349
+ `BadgeActionableProps`, `BadgeInformativeProps`, `BadgeNumberProps`,
350
+ `OptionCardProps`, `ProgressBarProps`, `TabsTriggerProps`, `TooltipContentProps`,
351
+ `RichTooltipContentProps`, `RichTooltipVariant`, `DateFormat`, `DateInputProps`,
352
+ `DateRangeInputProps`, `DateRange` (re-exported from `react-day-picker`:
353
+ `{ from?: Date; to?: Date }` — the value type for `DateRangeInput`),
354
+ `TimeFormat`, `TimeValue`, `TimeInputProps`,
355
+ `SearchableSelectOption`, `SearchableSelectProps`, `MultiSelectFreeTextOption`,
356
+ `MultiSelectFreeTextProps`, `DropdownSelectProps`, `DropdownSelectLabelProps`,
357
+ `DropdownSelectTriggerProps`, `DropdownSelectContentProps`,
358
+ `DropdownSelectOptionProps`, `AsyncAutocompleteProps`,
359
+ `AsyncAutocompleteOption`, `AsyncAutocompleteOptionState`,
360
+ `AsyncAutocompleteClassNames`, `AsyncAutocompleteInputProps`, `CarouselApi`,
361
+ `ChartConfig`, `ThemeProviderProps`.
362
+
363
+ There are no other public exports, and no subpath imports: only
364
+ `'@codapet/design-system'` and `'@codapet/design-system/styles'` resolve.
365
+
144
366
  ## Common gotchas
145
367
 
146
368
  - **Unstyled components** → missing `@source` glob for `node_modules/@codapet/design-system/dist/**` in the consumer's CSS.
147
369
  - **Wrong default Button look** → you forgot `variant="primary"`/`size="md"` are not the same as shadcn's defaults; passing nothing gives you `primary` + `lg`.
148
370
  - **Toast looks generic** → you imported `toast` from `'sonner'` instead of from `@codapet/design-system`.
149
371
  - **Modal doesn't bottom-sheet on mobile** → you used `Dialog` instead of `SmartDialog`.
372
+ - **`AsyncAutocomplete` fires a request per keystroke** → it deliberately does not debounce. Debounce in your fetch layer (`usePlacesService({ debounce: 300 })`, your own hook) so cancellation and out-of-order responses stay with the code that owns them.
373
+ - **`AsyncAutocomplete` shows results that don't match what you typed** → it renders `options` verbatim by design, because the server already filtered. If your list is static, use `SearchableSelect`/`DropdownSelect`, which filter client-side.
374
+ - **Styling `AsyncAutocomplete`** → it does **not** follow the flat `*ClassName` convention that `DateInput`/`TimeInput` use, because it has twenty-odd stylable slots. `className` is the root wrapper; everything else lives in one `classNames` object: `field`, `input`, `leftIcon`, `clearButton`, `content`, `listbox`, `option`, `optionHighlighted`, `optionDisabled`, `optionIcon`, `optionLabel`, `optionDescription`, `loading`, `loadingSpinner`, `empty`, plus `sheetOverlay`, `sheetContent`, `sheetHeader`, `sheetCloseButton`, `sheetInput`, `sheetList`. All merge through `cn`, so `{ content: 'max-h-[420px]' }` replaces the built-in max-height rather than stacking with it. A single row can also carry its own `className` via the option object, and rows expose `data-highlighted` / `data-disabled` for parent-level selectors. Use `renderOption` to change row *structure*, `classNames` to change its *look*.
150
375
  - **Headings look wrong** → you used a raw `<h1>` instead of `HeadingXL` / `DisplayHeading`. The serif-italic display style only comes from `DisplayHeading`.
151
376
  - **Dark mode broken** → you used raw Tailwind colors (`bg-gray-100`, `text-zinc-700`) instead of brand tokens; or you forgot to wrap in `ThemeProvider`.
152
377
  - **"Module not found" in tests** → Jest can't parse ESM; add `'@codapet/design-system'` to `transformIgnorePatterns` or switch the test file to Vitest.
package/dist/index.d.mts CHANGED
@@ -87,6 +87,201 @@ declare function AlertDialogCancel({ className, ...props }: React$1.ComponentPro
87
87
 
88
88
  declare function AspectRatio({ ...props }: React.ComponentProps<typeof AspectRatioPrimitive.Root>): react_jsx_runtime.JSX.Element;
89
89
 
90
+ interface AsyncAutocompleteOption<TData = unknown> {
91
+ /** Stable unique key. Doubles as the DOM id suffix — a `place_id`, slug, … */
92
+ id: string;
93
+ /** Primary line. */
94
+ label: string;
95
+ /** Secondary line, rendered dimmed after the label. */
96
+ description?: string;
97
+ /** Leading icon/avatar for this row. Falls back to `optionIcon`. */
98
+ icon?: React$1.ReactNode;
99
+ /** Rendered dimmed, and skipped by keyboard navigation and clicks. */
100
+ disabled?: boolean;
101
+ /**
102
+ * Merged onto this row only, after `classNames.option` — so a single row can
103
+ * be styled differently from its siblings (a "use my location" entry, a
104
+ * promoted result).
105
+ */
106
+ className?: string;
107
+ /**
108
+ * Arbitrary consumer payload handed straight back by `onSelect` — a raw
109
+ * Google `AutocompletePrediction`, a REST row, a whole domain object. The
110
+ * design system never inspects it.
111
+ */
112
+ data?: TData;
113
+ }
114
+ /** Row state passed to `renderOption`. */
115
+ interface AsyncAutocompleteOptionState {
116
+ /** Position in `options`. Matches the `-suggestion-N` DOM id. */
117
+ index: number;
118
+ /** True when keyboard- or hover-highlighted (`aria-activedescendant`). */
119
+ highlighted: boolean;
120
+ /** Current input text, for match highlighting. */
121
+ query: string;
122
+ }
123
+ /**
124
+ * Long-tail `<input>` props forwarded to the text field. The props
125
+ * `AsyncAutocomplete` owns are excluded; `onFocus`, `onKeyDown` and
126
+ * `onPointerDown` are chained after the component's own handlers rather than
127
+ * replacing them.
128
+ */
129
+ type AsyncAutocompleteInputProps = Omit<React$1.ComponentPropsWithoutRef<'input'>, 'value' | 'defaultValue' | 'onChange' | 'size' | 'disabled' | 'placeholder' | 'id' | 'type' | 'role' | 'readOnly'>;
130
+ /**
131
+ * Per-slot class overrides. Every entry is merged with `cn`, so
132
+ * tailwind-merge lets a caller class replace a conflicting default rather than
133
+ * fight it — `{ content: 'max-h-[420px]' }` really does replace the built-in
134
+ * max-height.
135
+ *
136
+ * `DateInput`/`TimeInput` expose two or three flat `*ClassName` props;
137
+ * `AsyncAutocomplete` has twenty-odd stylable slots, so they live in one
138
+ * object here instead of twenty top-level props burying `onSearch`/`onSelect`.
139
+ */
140
+ interface AsyncAutocompleteClassNames {
141
+ /** Wrapper around the input — also the popover's anchor. */
142
+ field?: string;
143
+ /** The text input itself. */
144
+ input?: string;
145
+ /** Left icon wrapper inside the input. */
146
+ leftIcon?: string;
147
+ /** The clear ("X") button. */
148
+ clearButton?: string;
149
+ /** The popover surface holding the results. */
150
+ content?: string;
151
+ /** The `role="listbox"` container, in both popover and sheet. */
152
+ listbox?: string;
153
+ /** Every option row. */
154
+ option?: string;
155
+ /** Added to the highlighted row, on top of `option`. */
156
+ optionHighlighted?: string;
157
+ /** Added to a disabled row, on top of `option`. */
158
+ optionDisabled?: string;
159
+ /** Icon wrapper inside a default row. Not applied when `renderOption` is used. */
160
+ optionIcon?: string;
161
+ /** Primary text span in a default row. Not applied when `renderOption` is used. */
162
+ optionLabel?: string;
163
+ /** Secondary text span in a default row. Not applied when `renderOption` is used. */
164
+ optionDescription?: string;
165
+ /** The loading row. */
166
+ loading?: string;
167
+ /** The spinner inside the loading row. */
168
+ loadingSpinner?: string;
169
+ /** The empty ("no results") row. Not applied when `emptyState` is used. */
170
+ empty?: string;
171
+ /** The sheet's backdrop. */
172
+ sheetOverlay?: string;
173
+ /** The sheet panel. */
174
+ sheetContent?: string;
175
+ /** The sheet's pinned header row. */
176
+ sheetHeader?: string;
177
+ /** The sheet's close/back button. */
178
+ sheetCloseButton?: string;
179
+ /** The sheet's own text input. */
180
+ sheetInput?: string;
181
+ /** The sheet's scrollable results area. */
182
+ sheetList?: string;
183
+ }
184
+ interface AsyncAutocompleteProps<TData = unknown> {
185
+ /**
186
+ * Current result set, rendered **verbatim**. `AsyncAutocomplete` never
187
+ * filters, sorts or caches — map your API response to options yourself.
188
+ */
189
+ options: AsyncAutocompleteOption<TData>[];
190
+ /**
191
+ * Fired on every keystroke with the raw input text, plus `''` when the
192
+ * clear button is pressed. **Not debounced** — debounce in your fetch layer
193
+ * (`usePlacesService({ debounce: 300 })`, a `setTimeout` hook, …) so
194
+ * request cancellation and out-of-order responses stay with the code that
195
+ * owns them.
196
+ */
197
+ onSearch: (query: string) => void;
198
+ /**
199
+ * Fired when an option is committed by click, tap or Enter. Closes the
200
+ * panel. Deliberately does **not** write the label into the input: call
201
+ * sites resolve their own display text (a `getDetails` lookup, a
202
+ * `formatted_address`) or clear the field. Drive `value` yourself.
203
+ */
204
+ onSelect: (option: AsyncAutocompleteOption<TData>) => void;
205
+ /** In-flight request. Replaces the rows with a spinner. */
206
+ loading?: boolean;
207
+ /** Controlled input text. */
208
+ value?: string;
209
+ /** Initial input text when uncontrolled. */
210
+ defaultValue?: string;
211
+ /** Fired on every input change and on clear. */
212
+ onValueChange?: (value: string) => void;
213
+ /**
214
+ * Fired only when the clear (X) button is pressed, after
215
+ * `onValueChange('')` and `onSearch('')`. Use it to drop the selected
216
+ * entity. Focus is returned to the input automatically.
217
+ */
218
+ onClear?: () => void;
219
+ placeholder?: string;
220
+ /** Decorative leading icon — `<MapPin />`, `<Stethoscope />`, … */
221
+ leftIcon?: React$1.ReactNode;
222
+ /** Fixed height: `sm` 40px · `md` 48px (default) · `lg` 56px. */
223
+ size?: 'sm' | 'md' | 'lg';
224
+ /** Error color scheme on the input. Also sets `aria-invalid`. */
225
+ error?: boolean;
226
+ disabled?: boolean;
227
+ /** Forwarded to the underlying `<input>` for imperative focus. */
228
+ inputRef?: React$1.Ref<HTMLInputElement>;
229
+ /** Escape hatch for `name`, `enterKeyHint`, `inputMode`, `autoFocus`, … */
230
+ inputProps?: AsyncAutocompleteInputProps;
231
+ /**
232
+ * `'popover'` (default) always anchors a portaled popover under the field
233
+ * and dismisses it as soon as the user scrolls. `'sheet'` keeps that
234
+ * behavior above 768px but turns the search into a full-screen takeover on
235
+ * phones, where the page behind is scroll-locked.
236
+ */
237
+ mobileVariant?: 'popover' | 'sheet';
238
+ /**
239
+ * Replace a whole row. The default renders `label` plus a dimmed
240
+ * `, description` on one truncated line with a leading icon. Reach for this
241
+ * for stacked two-line rows, avatars, or bold match highlighting — the
242
+ * wrapper, `role="option"`, ids, highlight background and click/keyboard
243
+ * wiring stay with the component.
244
+ */
245
+ renderOption?: (option: AsyncAutocompleteOption<TData>, state: AsyncAutocompleteOptionState) => React$1.ReactNode;
246
+ /** Default leading icon for rows without their own `option.icon`. */
247
+ optionIcon?: React$1.ReactNode;
248
+ /** "No results" copy. Ignored when `emptyState` is provided. */
249
+ emptyMessage?: string;
250
+ /** Full replacement for the empty row — an illustration, a CTA, … */
251
+ emptyState?: React$1.ReactNode;
252
+ /** Copy beside the loading spinner. */
253
+ loadingMessage?: string;
254
+ /** Replaces the clear button's `X` glyph. */
255
+ clearIcon?: React$1.ReactNode;
256
+ /** Accessible name for the clear button. */
257
+ clearLabel?: string;
258
+ /** Accessible name for the `mobileVariant="sheet"` takeover. */
259
+ sheetTitle?: string;
260
+ /** Replaces the sheet's back-arrow glyph. */
261
+ sheetCloseIcon?: React$1.ReactNode;
262
+ /** Accessible name for the sheet's close button. */
263
+ sheetCloseLabel?: string;
264
+ /** Controlled open state. Prefer `defaultOpen` unless you truly need this. */
265
+ open?: boolean;
266
+ /** Start open — for fields mounted lazily on focus. */
267
+ defaultOpen?: boolean;
268
+ onOpenChange?: (open: boolean) => void;
269
+ /**
270
+ * Prefix for stable DOM ids, so analytics autocapture keeps working:
271
+ * `{idPrefix}-input`, `{idPrefix}-clear`, `{idPrefix}-listbox`,
272
+ * `{idPrefix}-suggestion-{index}`, and in sheet mode also
273
+ * `{idPrefix}-sheet-input` and `{idPrefix}-sheet-clear`. Falls back to a
274
+ * `useId()` value, which is fine for ARIA wiring but not usable as a CSS
275
+ * selector.
276
+ */
277
+ idPrefix?: string;
278
+ /** Merged onto the root wrapper. */
279
+ className?: string;
280
+ /** Per-slot class overrides. See `AsyncAutocompleteClassNames`. */
281
+ classNames?: AsyncAutocompleteClassNames;
282
+ }
283
+ declare function AsyncAutocomplete<TData = unknown>({ options, onSearch, onSelect, loading, value: valueProp, defaultValue, onValueChange, onClear, placeholder, leftIcon, size, error, disabled, inputRef, inputProps, mobileVariant, renderOption, optionIcon, emptyMessage, emptyState, loadingMessage, clearIcon, clearLabel, sheetTitle, sheetCloseIcon, sheetCloseLabel, open: openProp, defaultOpen, onOpenChange, idPrefix, className, classNames }: AsyncAutocompleteProps<TData>): react_jsx_runtime.JSX.Element;
284
+
90
285
  interface TextareaProps extends Omit<React$1.ComponentProps<'textarea'>, 'size'> {
91
286
  error?: boolean;
92
287
  }
@@ -959,4 +1154,4 @@ declare function cn(...inputs: ClassValue[]): string;
959
1154
 
960
1155
  declare function useIsMobile(): boolean;
961
1156
 
962
- export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertBanner, type AlertBannerProps, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AspectRatio, AutoResizeTextarea, Avatar, AvatarFallback, AvatarImage, Badge, BadgeActionable, type BadgeActionableProps, BadgeInformative, BadgeInformativeGroup, BadgeInformativeItem, type BadgeInformativeProps, BadgeNumber, type BadgeNumberProps, Body, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, Calendar, CalendarDayButton, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, type CarouselApi, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, type ChartConfig, ChartContainer, ChartLegend, ChartLegendContent, ChartStyle, ChartTooltip, ChartTooltipContent, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, type DateFormat, DateInput, type DateInputProps, DateRangeInput, type DateRangeInputProps, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DisplayHeading, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, DropdownSelect, DropdownSelectContent, type DropdownSelectContentProps, DropdownSelectLabel, type DropdownSelectLabelProps, DropdownSelectOption, type DropdownSelectOptionProps, type DropdownSelectProps, DropdownSelectTrigger, type DropdownSelectTriggerProps, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, HeadingL, HeadingLMedium, HeadingM, HeadingMMedium, HeadingS, HeadingSMedium, HeadingXL, HeadingXLMedium, HeadingXS, HeadingXSMedium, HeadingXXS, HeadingXXSMedium, HoverCard, HoverCardContent, HoverCardTrigger, Input, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, Label, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, MultiSelectFreeText, type MultiSelectFreeTextOption, type MultiSelectFreeTextProps, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, OptionCard, type OptionCardProps, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, Progress, ProgressBar, type ProgressBarProps, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, RichTooltipContent, type RichTooltipContentProps, type RichTooltipVariant, ScrollArea, ScrollBar, SearchInput, type SearchInputProps, type SearchSuggestion, SearchableSelect, SearchableSelectContent, SearchableSelectEmpty, SearchableSelectGroup, SearchableSelectItem, type SearchableSelectOption, type SearchableSelectProps, SearchableSelectTrigger, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, Slider, SmartDialog, SmartDialogClose, SmartDialogContent, SmartDialogDescription, SmartDialogFooter, SmartDialogHeader, SmartDialogTitle, SmartDialogTrigger, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, type TabsTriggerProps, Textarea, type TextareaProps, ThemeProvider, ThemeToggle, type TimeFormat, TimeInput, type TimeInputProps, type TimeValue, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, type TooltipContentProps, TooltipProvider, TooltipTrigger, alertBannerVariants, badgeActionableVariants, badgeInformativeVariants, badgeNumberVariants, badgeVariants, bodyTextVariants, buttonVariants, cn, displayTextVariants, inputVariants, labelTextVariants, navigationMenuTriggerStyle, optionCardVariants, progressBarVariants, tabsTriggerVariants, toggleVariants, useFormField, useIsMobile, useSidebar };
1157
+ export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertBanner, type AlertBannerProps, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AspectRatio, AsyncAutocomplete, type AsyncAutocompleteClassNames, type AsyncAutocompleteInputProps, type AsyncAutocompleteOption, type AsyncAutocompleteOptionState, type AsyncAutocompleteProps, AutoResizeTextarea, Avatar, AvatarFallback, AvatarImage, Badge, BadgeActionable, type BadgeActionableProps, BadgeInformative, BadgeInformativeGroup, BadgeInformativeItem, type BadgeInformativeProps, BadgeNumber, type BadgeNumberProps, Body, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, Calendar, CalendarDayButton, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, type CarouselApi, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, type ChartConfig, ChartContainer, ChartLegend, ChartLegendContent, ChartStyle, ChartTooltip, ChartTooltipContent, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, type DateFormat, DateInput, type DateInputProps, DateRangeInput, type DateRangeInputProps, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DisplayHeading, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, DropdownSelect, DropdownSelectContent, type DropdownSelectContentProps, DropdownSelectLabel, type DropdownSelectLabelProps, DropdownSelectOption, type DropdownSelectOptionProps, type DropdownSelectProps, DropdownSelectTrigger, type DropdownSelectTriggerProps, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, HeadingL, HeadingLMedium, HeadingM, HeadingMMedium, HeadingS, HeadingSMedium, HeadingXL, HeadingXLMedium, HeadingXS, HeadingXSMedium, HeadingXXS, HeadingXXSMedium, HoverCard, HoverCardContent, HoverCardTrigger, Input, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, type InputProps, Label, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, MultiSelectFreeText, type MultiSelectFreeTextOption, type MultiSelectFreeTextProps, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, OptionCard, type OptionCardProps, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, Progress, ProgressBar, type ProgressBarProps, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, RichTooltipContent, type RichTooltipContentProps, type RichTooltipVariant, ScrollArea, ScrollBar, SearchInput, type SearchInputProps, type SearchSuggestion, SearchableSelect, SearchableSelectContent, SearchableSelectEmpty, SearchableSelectGroup, SearchableSelectItem, type SearchableSelectOption, type SearchableSelectProps, SearchableSelectTrigger, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, Slider, SmartDialog, SmartDialogClose, SmartDialogContent, SmartDialogDescription, SmartDialogFooter, SmartDialogHeader, SmartDialogTitle, SmartDialogTrigger, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, type TabsTriggerProps, Textarea, type TextareaProps, ThemeProvider, ThemeToggle, type TimeFormat, TimeInput, type TimeInputProps, type TimeValue, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, type TooltipContentProps, TooltipProvider, TooltipTrigger, alertBannerVariants, badgeActionableVariants, badgeInformativeVariants, badgeNumberVariants, badgeVariants, bodyTextVariants, buttonVariants, cn, displayTextVariants, inputVariants, labelTextVariants, navigationMenuTriggerStyle, optionCardVariants, progressBarVariants, tabsTriggerVariants, toggleVariants, useFormField, useIsMobile, useSidebar };