@uselets/ui 2.0.1 → 2.1.0

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.
Files changed (246) hide show
  1. package/README.md +8 -0
  2. package/dist/{as-child-Dxg3Xo1G.d.ts → as-child-T9W73ZYU.d.ts} +1 -3
  3. package/dist/{chart-B_6nC_ih.d.ts → chart-8rgtsk95.d.ts} +1 -3
  4. package/dist/checkbox-group-context-HDVxTNPi.js +2 -0
  5. package/dist/checkbox-group-context-HDVxTNPi.js.map +1 -0
  6. package/dist/cli/uselets.mjs.map +1 -1
  7. package/dist/combobox-styles-CZ0aJayc.js +2 -0
  8. package/dist/combobox-styles-CZ0aJayc.js.map +1 -0
  9. package/dist/components/accordion.d.ts +1 -3
  10. package/dist/components/accordion.js.map +1 -1
  11. package/dist/components/alert-dialog.d.ts +1 -3
  12. package/dist/components/alert-dialog.js.map +1 -1
  13. package/dist/components/alert.d.ts +0 -2
  14. package/dist/components/alert.js.map +1 -1
  15. package/dist/components/anchor.d.ts +1 -3
  16. package/dist/components/anchor.js.map +1 -1
  17. package/dist/components/area-chart.d.ts +1 -3
  18. package/dist/components/area-chart.js.map +1 -1
  19. package/dist/components/autocomplete.d.ts +46 -0
  20. package/dist/components/autocomplete.js +2 -0
  21. package/dist/components/autocomplete.js.map +1 -0
  22. package/dist/components/avatar.d.ts +1 -3
  23. package/dist/components/avatar.js.map +1 -1
  24. package/dist/components/badge.d.ts +1 -3
  25. package/dist/components/badge.js +1 -1
  26. package/dist/components/badge.js.map +1 -1
  27. package/dist/components/bar-chart.d.ts +1 -3
  28. package/dist/components/bar-chart.js.map +1 -1
  29. package/dist/components/bottom-nav.d.ts +1 -3
  30. package/dist/components/bottom-nav.js.map +1 -1
  31. package/dist/components/breadcrumb.d.ts +1 -3
  32. package/dist/components/breadcrumb.js.map +1 -1
  33. package/dist/components/button-group.d.ts +1 -3
  34. package/dist/components/button-group.js.map +1 -1
  35. package/dist/components/button.d.ts +1 -3
  36. package/dist/components/button.js +1 -1
  37. package/dist/components/button.js.map +1 -1
  38. package/dist/components/calendar.d.ts +0 -2
  39. package/dist/components/calendar.js +1 -1
  40. package/dist/components/calendar.js.map +1 -1
  41. package/dist/components/card.d.ts +0 -2
  42. package/dist/components/card.js.map +1 -1
  43. package/dist/components/carousel.d.ts +0 -2
  44. package/dist/components/carousel.js.map +1 -1
  45. package/dist/components/center.d.ts +0 -2
  46. package/dist/components/center.js.map +1 -1
  47. package/dist/components/chart.d.ts +1 -1
  48. package/dist/components/chart.js.map +1 -1
  49. package/dist/components/checkbox-group.d.ts +19 -0
  50. package/dist/components/checkbox-group.js +2 -0
  51. package/dist/components/checkbox-group.js.map +1 -0
  52. package/dist/components/checkbox.d.ts +2 -4
  53. package/dist/components/checkbox.js +1 -1
  54. package/dist/components/checkbox.js.map +1 -1
  55. package/dist/components/code.d.ts +0 -2
  56. package/dist/components/code.js.map +1 -1
  57. package/dist/components/collapsible.d.ts +1 -3
  58. package/dist/components/collapsible.js.map +1 -1
  59. package/dist/components/combobox.d.ts +1 -3
  60. package/dist/components/combobox.js +1 -1
  61. package/dist/components/combobox.js.map +1 -1
  62. package/dist/components/command.d.ts +0 -2
  63. package/dist/components/command.js +1 -1
  64. package/dist/components/command.js.map +1 -1
  65. package/dist/components/container.d.ts +0 -2
  66. package/dist/components/container.js.map +1 -1
  67. package/dist/components/data-table.d.ts +0 -2
  68. package/dist/components/data-table.js +1 -1
  69. package/dist/components/data-table.js.map +1 -1
  70. package/dist/components/date-range-picker.d.ts +0 -2
  71. package/dist/components/date-range-picker.js.map +1 -1
  72. package/dist/components/dialog.d.ts +1 -3
  73. package/dist/components/dialog.js.map +1 -1
  74. package/dist/components/direction.d.ts +0 -2
  75. package/dist/components/donut-chart.d.ts +0 -2
  76. package/dist/components/donut-chart.js.map +1 -1
  77. package/dist/components/drawer.d.ts +1 -3
  78. package/dist/components/drawer.js.map +1 -1
  79. package/dist/components/dropdown-menu.d.ts +1 -3
  80. package/dist/components/dropdown-menu.js.map +1 -1
  81. package/dist/components/dropzone.d.ts +0 -2
  82. package/dist/components/dropzone.js +1 -1
  83. package/dist/components/dropzone.js.map +1 -1
  84. package/dist/components/empty.d.ts +0 -2
  85. package/dist/components/empty.js.map +1 -1
  86. package/dist/components/field.d.ts +0 -2
  87. package/dist/components/field.js +1 -1
  88. package/dist/components/field.js.map +1 -1
  89. package/dist/components/flex.d.ts +0 -2
  90. package/dist/components/flex.js.map +1 -1
  91. package/dist/components/grid.d.ts +0 -2
  92. package/dist/components/grid.js.map +1 -1
  93. package/dist/components/group.d.ts +0 -2
  94. package/dist/components/group.js.map +1 -1
  95. package/dist/components/heading.d.ts +1 -3
  96. package/dist/components/heading.js.map +1 -1
  97. package/dist/components/hover-card.d.ts +1 -3
  98. package/dist/components/hover-card.js.map +1 -1
  99. package/dist/components/input-group.d.ts +0 -2
  100. package/dist/components/input-group.js.map +1 -1
  101. package/dist/components/input-otp.d.ts +0 -2
  102. package/dist/components/input-otp.js.map +1 -1
  103. package/dist/components/input.d.ts +0 -2
  104. package/dist/components/input.js.map +1 -1
  105. package/dist/components/kbd.d.ts +0 -2
  106. package/dist/components/kbd.js.map +1 -1
  107. package/dist/components/label.d.ts +1 -3
  108. package/dist/components/label.js.map +1 -1
  109. package/dist/components/list.d.ts +1 -3
  110. package/dist/components/list.js.map +1 -1
  111. package/dist/components/logo.d.ts +0 -2
  112. package/dist/components/marker.d.ts +1 -3
  113. package/dist/components/marker.js.map +1 -1
  114. package/dist/components/mask-input.d.ts +1 -3
  115. package/dist/components/mask-input.js +1 -1
  116. package/dist/components/mask-input.js.map +1 -1
  117. package/dist/components/meter.d.ts +21 -0
  118. package/dist/components/meter.js +2 -0
  119. package/dist/components/meter.js.map +1 -0
  120. package/dist/components/native-select.d.ts +0 -2
  121. package/dist/components/native-select.js.map +1 -1
  122. package/dist/components/navigation-menu.d.ts +1 -3
  123. package/dist/components/navigation-menu.js.map +1 -1
  124. package/dist/components/number-field.d.ts +1 -3
  125. package/dist/components/number-field.js +1 -1
  126. package/dist/components/number-field.js.map +1 -1
  127. package/dist/components/pagination.d.ts +0 -2
  128. package/dist/components/pagination.js.map +1 -1
  129. package/dist/components/phone-input.d.ts +0 -2
  130. package/dist/components/phone-input.js +1 -1
  131. package/dist/components/phone-input.js.map +1 -1
  132. package/dist/components/pie-chart.d.ts +1 -3
  133. package/dist/components/pie-chart.js.map +1 -1
  134. package/dist/components/popover.d.ts +1 -3
  135. package/dist/components/popover.js.map +1 -1
  136. package/dist/components/progress.d.ts +0 -2
  137. package/dist/components/progress.js +1 -1
  138. package/dist/components/progress.js.map +1 -1
  139. package/dist/components/radio-group.d.ts +0 -2
  140. package/dist/components/radio-group.js +1 -1
  141. package/dist/components/radio-group.js.map +1 -1
  142. package/dist/components/resizable.d.ts +0 -2
  143. package/dist/components/resizable.js.map +1 -1
  144. package/dist/components/ring-progress.d.ts +0 -2
  145. package/dist/components/ring-progress.js +1 -1
  146. package/dist/components/ring-progress.js.map +1 -1
  147. package/dist/components/scroll-area.d.ts +0 -2
  148. package/dist/components/scroll-area.js.map +1 -1
  149. package/dist/components/select.d.ts +1 -3
  150. package/dist/components/select.js.map +1 -1
  151. package/dist/components/separator.d.ts +1 -3
  152. package/dist/components/separator.js.map +1 -1
  153. package/dist/components/sidebar.d.ts +2 -4
  154. package/dist/components/sidebar.js +1 -1
  155. package/dist/components/sidebar.js.map +1 -1
  156. package/dist/components/simple-grid.d.ts +0 -2
  157. package/dist/components/simple-grid.js.map +1 -1
  158. package/dist/components/skeleton.d.ts +0 -2
  159. package/dist/components/skeleton.js.map +1 -1
  160. package/dist/components/slider.d.ts +0 -2
  161. package/dist/components/slider.js.map +1 -1
  162. package/dist/components/sonner.d.ts +0 -2
  163. package/dist/components/sonner.js.map +1 -1
  164. package/dist/components/spinner.d.ts +0 -2
  165. package/dist/components/spinner.js.map +1 -1
  166. package/dist/components/stack.d.ts +0 -2
  167. package/dist/components/stack.js.map +1 -1
  168. package/dist/components/stepper.d.ts +1 -3
  169. package/dist/components/stepper.js +1 -1
  170. package/dist/components/stepper.js.map +1 -1
  171. package/dist/components/switch.d.ts +0 -2
  172. package/dist/components/switch.js +1 -1
  173. package/dist/components/switch.js.map +1 -1
  174. package/dist/components/table.d.ts +0 -2
  175. package/dist/components/table.js.map +1 -1
  176. package/dist/components/tabs.d.ts +1 -3
  177. package/dist/components/tabs.js.map +1 -1
  178. package/dist/components/text.d.ts +1 -3
  179. package/dist/components/text.js.map +1 -1
  180. package/dist/components/textarea.d.ts +0 -2
  181. package/dist/components/textarea.js.map +1 -1
  182. package/dist/components/theme.d.ts +0 -2
  183. package/dist/components/theme.js.map +1 -1
  184. package/dist/components/timeline.d.ts +0 -2
  185. package/dist/components/timeline.js.map +1 -1
  186. package/dist/components/toggle-group.d.ts +1 -3
  187. package/dist/components/toggle-group.js.map +1 -1
  188. package/dist/components/toggle.d.ts +1 -3
  189. package/dist/components/toggle.js +1 -1
  190. package/dist/components/toggle.js.map +1 -1
  191. package/dist/components/toolbar.d.ts +30 -0
  192. package/dist/components/toolbar.js +2 -0
  193. package/dist/components/toolbar.js.map +1 -0
  194. package/dist/components/tooltip.d.ts +1 -3
  195. package/dist/components/tooltip.js.map +1 -1
  196. package/dist/components/unstyled-button.d.ts +1 -3
  197. package/dist/components/unstyled-button.js.map +1 -1
  198. package/dist/components/visibility.d.ts +0 -2
  199. package/dist/components/visibility.js.map +1 -1
  200. package/dist/hooks/use-breakpoint-value.d.ts +0 -2
  201. package/dist/hooks/use-breakpoint-value.js.map +1 -1
  202. package/dist/hooks/use-breakpoint.d.ts +0 -2
  203. package/dist/hooks/use-breakpoint.js.map +1 -1
  204. package/dist/hooks/use-disclosure.d.ts +0 -2
  205. package/dist/hooks/use-disclosure.js.map +1 -1
  206. package/dist/hooks/use-document-visibility.d.ts +0 -2
  207. package/dist/hooks/use-document-visibility.js.map +1 -1
  208. package/dist/hooks/use-hotkeys.d.ts +1 -1
  209. package/dist/hooks/use-idle.d.ts +0 -2
  210. package/dist/hooks/use-idle.js.map +1 -1
  211. package/dist/hooks/use-interval.d.ts +0 -2
  212. package/dist/hooks/use-interval.js.map +1 -1
  213. package/dist/hooks/use-local-storage.d.ts +0 -2
  214. package/dist/hooks/use-local-storage.js.map +1 -1
  215. package/dist/hooks/use-mask.d.ts +0 -2
  216. package/dist/hooks/use-mask.js.map +1 -1
  217. package/dist/hooks/use-mobile.d.ts +0 -2
  218. package/dist/hooks/use-mobile.js.map +1 -1
  219. package/dist/index.d.ts +21 -17
  220. package/dist/index.js +1 -1
  221. package/dist/lib/as-child.d.ts +1 -1
  222. package/dist/lib/as-child.js.map +1 -1
  223. package/dist/lib/badge.d.ts +0 -2
  224. package/dist/lib/badge.js.map +1 -1
  225. package/dist/lib/button.d.ts +0 -2
  226. package/dist/lib/button.js.map +1 -1
  227. package/dist/lib/color.d.ts +0 -2
  228. package/dist/lib/color.js.map +1 -1
  229. package/dist/lib/compose-refs.d.ts +0 -2
  230. package/dist/lib/compose-refs.js.map +1 -1
  231. package/dist/lib/progress.d.ts +0 -2
  232. package/dist/lib/progress.js.map +1 -1
  233. package/dist/lib/utils.d.ts +0 -2
  234. package/dist/lib/utils.js.map +1 -1
  235. package/dist/logo--R3_XDgA.js.map +1 -1
  236. package/dist/postcss.config.js.map +1 -1
  237. package/dist/resolve-class-name-BurP8ngI.js.map +1 -1
  238. package/dist/skills/uselets-ui/SKILL.md +3 -3
  239. package/dist/skills/uselets-ui/references/component-catalog.md +14 -2
  240. package/dist/skills/uselets-ui/references/package-guide.md +3 -3
  241. package/dist/{use-hotkeys-D1_TEIwN.d.ts → use-hotkeys-BVm0IGb8.d.ts} +1 -5
  242. package/dist/use-hotkeys-YDJmGWX6.js.map +1 -1
  243. package/package.json +14 -14
  244. package/skills/uselets-ui/SKILL.md +3 -3
  245. package/skills/uselets-ui/references/component-catalog.md +14 -2
  246. package/skills/uselets-ui/references/package-guide.md +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"postcss.config.js","names":["config"],"sources":["../postcss.config.mjs"],"sourcesContent":["/** @type {import('postcss-load-config').Config} */\nconst config = {\n plugins: { \"@tailwindcss/postcss\": {} },\n};\n\nexport default config;\n"],"mappings":"AACA,MAAMA,EAAS,CACX,QAAS,CAAE,uBAAwB,CAAC,CAAE,CAC1C"}
1
+ {"version":3,"file":"postcss.config.js","names":["config"],"sources":["../postcss.config.mjs"],"sourcesContent":["/** @type {import('postcss-load-config').Config} */\nconst config = {\n plugins: { \"@tailwindcss/postcss\": {} },\n};\n\nexport default config;\n"],"mappings":"AACA,MAAMA,EAAS,CACX,QAAS,CAAE,uBAAwB,CAAC,CAAE,CAC1C,E"}
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-class-name-BurP8ngI.js","names":["className","state"],"sources":["../src/utils/resolve-class-name.ts"],"sourcesContent":["/** Resolves a Base UI `className`, which can also be a function of the component state, for that state. */\nexport function resolveClassName<State>(\n className: string | ((state: State) => string | undefined) | undefined,\n state: State\n) {\n return typeof className === 'function' ? className(state) : className\n}\n"],"mappings":"uCACA,SAAgB,iBACd,EACA,EACA,CACA,OAAO,OAAOA,GAAc,WAAaA,EAAUC,CAAK,EAAID,CAC9D"}
1
+ {"version":3,"file":"resolve-class-name-BurP8ngI.js","names":["className","state"],"sources":["../src/utils/resolve-class-name.ts"],"sourcesContent":["/** Resolves a Base UI `className`, which can also be a function of the component state, for that state. */\nexport function resolveClassName<State>(\n className: string | ((state: State) => string | undefined) | undefined,\n state: State\n) {\n return typeof className === 'function' ? className(state) : className\n}\n"],"mappings":"A,uCACA,SAAgB,iBACd,EACA,EACA,CACA,OAAO,OAAOA,GAAc,WAAaA,EAAUC,CAAK,EAAID,CAC9D,C"}
@@ -54,14 +54,14 @@ To set up a consumer project after installing `@uselets/ui`, run `bun uselets in
54
54
  app's entry file (`import '@fontsource-variable/inter'` in `app/layout.tsx`, `pages/_app.tsx`, or `src/main.tsx`),
55
55
  not via `@import` in CSS — some bundlers, including Next.js, don't resolve third-party CSS `@import`s reliably.
56
56
  - Recommend `@uselets/ui/postcss.config` when the app needs the package PostCSS preset for Tailwind v4.
57
- - Interactive components are built on Base UI (`@base-ui/react`). Use `asChild` (Radix-style, single child element) for polymorphism; the child replaces the part's content. Not supported on `ScrollArea`, `ScrollBar`, `SelectContent`, `SelectItem`, `AccordionContent`, `Checkbox`, `Switch`, `RadioGroupItem`, `Progress`, `Slider`, `NavigationMenu`, `NumberFieldScrubArea`, `ComboboxInput`, `ComboboxClear`, `ComboboxChipsInput`, `NumberField`, `NumberFieldInput` (their internal structure is required). Do not pass Base UI's `render` prop — it is not part of the public API. When `asChild` wraps a button-like part (triggers, closes, `TabsTrigger`, `AccordionTrigger`, `Toggle`, `SelectTrigger`, `AlertDialogAction`/`Cancel`) with a non-`<button>` child, also pass `nativeButton={false}` (not needed for `TooltipTrigger`/`HoverCardTrigger`). Change callbacks of Base UI-backed components (`onOpenChange`, `onValueChange`, `onCheckedChange`, …) receive `(value, eventDetails)`; `DateRangePicker`, `SidebarProvider` and `Stepper` callbacks don't.
58
- - Popups unmount when closed. `keepMounted?: boolean` (default `false`) keeps them mounted while hidden on `DialogContent`, `AlertDialogContent`, `DrawerContent`, `PopoverContent`, `DropdownMenuContent`, `DropdownMenuSubContent`, `TooltipContent`/`Tooltip`, `HoverCardContent`, `ComboboxContent` and `NavigationMenuPositioner`; `SelectContent` does not accept it. `sticky?: boolean` (default `false`) keeps `PopoverContent`, `SelectContent`, `DropdownMenuContent`, `DropdownMenuSubContent`, `TooltipContent`/`Tooltip`, `HoverCardContent` and `ComboboxContent` in the viewport after the anchor scrolls out of view. Other positioner props (`collisionPadding`, `collisionBoundary`, `arrowPadding`, `collisionAvoidance`) are only exposed on `ComboboxContent`.
57
+ - Interactive components are built on Base UI (`@base-ui/react`). Use `asChild` (Radix-style, single child element) for polymorphism; the child replaces the part's content. Not supported on `ScrollArea`, `ScrollBar`, `SelectContent`, `SelectItem`, `AccordionContent`, `Checkbox`, `Switch`, `RadioGroupItem`, `Progress`, `Slider`, `NavigationMenu`, `NumberFieldScrubArea`, `ComboboxInput`, `ComboboxClear`, `ComboboxChipsInput`, `AutocompleteInput`, `Meter`, `ToolbarInput`, `NumberField`, `NumberFieldInput` (their internal structure is required). Do not pass Base UI's `render` prop — it is not part of the public API. When `asChild` wraps a button-like part (triggers, closes, `TabsTrigger`, `AccordionTrigger`, `Toggle`, `SelectTrigger`, `AlertDialogAction`/`Cancel`) with a non-`<button>` child, also pass `nativeButton={false}` (not needed for `TooltipTrigger`/`HoverCardTrigger`). Change callbacks of Base UI-backed components (`onOpenChange`, `onValueChange`, `onCheckedChange`, …) receive `(value, eventDetails)`; `DateRangePicker`, `SidebarProvider` and `Stepper` callbacks don't.
58
+ - Popups unmount when closed. `keepMounted?: boolean` (default `false`) keeps them mounted while hidden on `DialogContent`, `AlertDialogContent`, `DrawerContent`, `PopoverContent`, `DropdownMenuContent`, `DropdownMenuSubContent`, `TooltipContent`/`Tooltip`, `HoverCardContent`, `ComboboxContent`, `AutocompleteContent` and `NavigationMenuPositioner`; `SelectContent` does not accept it. `sticky?: boolean` (default `false`) keeps `PopoverContent`, `SelectContent`, `DropdownMenuContent`, `DropdownMenuSubContent`, `TooltipContent`/`Tooltip`, `HoverCardContent`, `ComboboxContent` and `AutocompleteContent` in the viewport after the anchor scrolls out of view. Other positioner props (`collisionPadding`, `collisionBoundary`, `arrowPadding`, `collisionAvoidance`) are only exposed on `ComboboxContent` and `AutocompleteContent`.
59
59
  - For Vite apps, `@tailwindcss/vite` (registered in `vite.config.ts`, no `postcss.config.mjs`) is a valid alternative to PostCSS; prefer it when the project uses isolated installs (pnpm, Bun workspaces). See `references/package-guide.md`.
60
60
  - For tooltip-heavy apps, wrap the app with `TooltipProvider` (`delay`, not `delayDuration`); use `Tooltip label={...}` for common trigger/content usage (it accepts `delay`/`closeDelay`) and `TooltipRoot` only when manual composition is needed.
61
61
  - Use `UnstyledButton` when button semantics are needed without `Button` variants; it provides reset styles, pointer cursor, focus ring, default `type="button"`, and `asChild`.
62
62
  - For toast usage, mount `Toaster` near the app root before calling `toast(...)`.
63
63
  - For package theme helpers, use `ThemeProvider`, `useTheme`, and `ModeToggle` from `@uselets/ui/theme` or the root barrel.
64
- - For form fields, `Field` automatically shares a generated control id with `FieldLabel` and labelable controls when explicit ids are omitted; pass explicit matching `htmlFor` and `id` only when a stable custom id is required. Use one control per `Field` (a `RadioGroup` counts as one control); for several checkboxes/switches use `FieldSet` + `FieldLegend` with one `Field` each. Mark errors with `<Field invalid>` (not `aria-invalid` on each control): it colors the label and propagates `aria-invalid` to the control; `Checkbox`/`Switch`/`RadioGroup` get the attribute but no red style.
64
+ - For form fields, `Field` automatically shares a generated control id with `FieldLabel` and labelable controls when explicit ids are omitted; pass explicit matching `htmlFor` and `id` only when a stable custom id is required. Use one control per `Field` (a `RadioGroup` or `CheckboxGroup` counts as one control); for several checkboxes use a `CheckboxGroup` (it also provides "select all" via a `parent` checkbox), and for several switches use `FieldSet` + `FieldLegend` with one `Field` each. Mark errors with `<Field invalid>` (not `aria-invalid` on each control): it colors the label and propagates `aria-invalid` to the control; `Checkbox`/`Switch`/`RadioGroup`/`CheckboxGroup` get the attribute but no red style.
65
65
  - For client-side tabular data, use `DataTable` from `@uselets/ui/data-table`. Defaults are bare: `enableRowSelection`, `enableSorting`, and `showPagination` are all `false`. Set `enableRowSelection` to auto-prepend the selection checkbox column (no need to add `createDataTableSelectColumn` manually); set `enableSorting` to make `DataTableColumnHeader` clickable for sort. `filterColumns` accepts a single id or an array; with 2+ ids the toolbar renders an `InputGroup` with a column selector on the left. `toolbarActions` always sits at the right of the toolbar. All labels default to pt-BR; override any subset through `labels` (`Partial<DataTableLabels>`), with full defaults exposed as `defaultDataTableLabels`. Use `variant` on `DataTable` (or directly on the base `Table`) to switch chrome: `"line"` (default) renders only horizontal separators between rows; `"outline"` adds a rounded outer border around the table. The base `Table` from `@uselets/ui/table` renders only the `<table>` element and is striped by default (pass `striped={false}` to disable). Wrap it in `TableContainer` to control scroll; `minWidth` lives on `TableContainer`. Combine `stickyHeader` on `Table` with `max-h` + `overflow-y-auto` on the `TableContainer` to keep the `<thead>` visible during vertical scroll. `DataTable` wraps its `Table` in `TableContainer` automatically.
66
66
 
67
67
  ## Quick Routing
@@ -115,11 +115,17 @@ Unless noted otherwise, each module also exports its public `*Props` types from
115
115
  - Notes: action button with `solid`, `secondary`, `outline`, `subtle`, `ghost`, and `link` variants, `color: UIColor` (`primary` default), sizes from `xs` through `xl` plus icon sizes through `icon-xl`, and `loading`
116
116
  - `button-group`
117
117
  - Exports: `ButtonGroup`, `ButtonGroupSeparator`, `ButtonGroupText`, `buttonGroupVariants`
118
+ - `toolbar`
119
+ - Exports: `Toolbar`, `ToolbarButton`, `ToolbarGroup`, `ToolbarInput`, `ToolbarLink`, `ToolbarSeparator`
120
+ - Notes: action bar (`role="toolbar"`) that is one tab stop; arrow keys move focus between its controls. Always pass `aria-label`. No background/border of its own (wrap in `Card` or a container). `Toolbar` props: `orientation: 'horizontal' | 'vertical'` (default `horizontal`), `loopFocus` (default `true`), `disabled`. `ToolbarButton` renders `Button`: `variant` (default `ghost`), `size` (default `sm`), `color: UIColor`, `loading`; disabled buttons stay focusable (`focusableWhenDisabled`, default `true`). To open a menu/popover: `<DropdownMenuTrigger asChild><ToolbarButton>…</ToolbarButton></DropdownMenuTrigger>`. `ToolbarSeparator` takes the opposite orientation automatically. `ToolbarInput` renders `Input` (no `asChild`). Use for action bars (bulk actions, filters, editors), not navigation (`Tabs`/`NavigationMenu`)
118
121
  - `empty`
119
122
  - Exports: `Empty`, `EmptyContent`, `EmptyDescription`, `EmptyHeader`, `EmptyMedia`, `EmptyTitle`
120
123
  - `progress`
121
124
  - Exports: `Progress`, `progressVariants`
122
125
  - Notes: linear progress bar driven by a single `value` (0–100); `size: 'sm' | 'md' | 'lg'` (default: `md`) controls bar height and `color: UIColor` (default: `primary`) controls the indicator; omitting `value` (or passing `null`) renders the indeterminate state
126
+ - `meter`
127
+ - Exports: `Meter`, `meterVariants`
128
+ - Notes: linear bar for a static measurement within a range (usage, capacity, share of a total) with `role="meter"`; use `Progress` for task completion. `value` required; `min`/`max` (default `0`/`100`); `label?: React.ReactNode` renders above the bar and names it (without it, pass `aria-label`); `showValue?: boolean` (default `false`) prints the formatted value at the end of the label row, formatted with `format?: Intl.NumberFormatOptions` and `locale`. `size: 'sm' | 'md' | 'lg'` (default `md`) and `color: UIColor` (default `primary`) match `Progress`; `className` targets the bar. No `asChild`
123
129
  - `ring-progress`
124
130
  - Exports: `RingProgress`, `ringProgressVariants`
125
131
  - Notes: circular progress indicator driven by a single `value` (0–100); `size: 'sm' | 'md' | 'lg'` (default: `md`, `32/40/48px`), `thickness: 'thin' | 'md' | 'thick'` (default: `md`), and `color: UIColor` (default: `primary`); normalized `viewBox` means the size can also be set via `className` (e.g. `size-5`); rounded line caps
@@ -133,8 +139,8 @@ Unless noted otherwise, each module also exports its public `*Props` types from
133
139
 
134
140
  - `field`
135
141
  - Exports: `Field`, `FieldContent`, `FieldDescription`, `FieldError`, `FieldGroup`, `FieldLabel`, `FieldLegend`, `FieldSeparator`, `FieldSet`, `FieldTitle`, `useFieldControlId`, `useFieldInvalid`, `useFieldLabelId`
136
- - Notes: form layout and validation helpers; `Field` automatically provides a generated control id to `FieldLabel` and labelable descendants when explicit ids are omitted. One control per `Field`: a `RadioGroup` placed directly in a `Field` takes the `FieldLabel` as its group label (`aria-labelledby`) and its items keep their own ids; never put several `Checkbox`/`Switch` controls in one `Field` (they would share the control id) — use `FieldSet` + `FieldLegend` with one `Field` per control. `useFieldLabelId()` returns the current `FieldLabel` id (or `undefined` outside a `Field`) for custom group controls
137
- - Invalid state: `Field.invalid?: boolean` (or legacy `data-invalid="true"`; `invalid` wins when both are set) renders `data-invalid="true"` (label/description turn destructive) and sets `aria-invalid` on the control inside. Styled red: `Input` (incl. `InputGroupInput`, `PhoneInput`), `Textarea`, `NativeSelect`, `SelectTrigger`, `ComboboxInput`, `ComboboxChipsInput`, `InputOTP` (+ slots), `NumberField`. `aria-invalid` only, no red style: `Checkbox`, `Switch`, `RadioGroup` (on the group). Not propagated: `Slider`, `DatePicker`/`DateRangePicker` triggers. A control's own `aria-invalid` (including `false`) overrides the `Field`. Do: `<Field invalid><FieldLabel/><Input/><FieldError/></Field>`. Don't: repeat `aria-invalid` on every control inside an invalid `Field`. Custom controls: `const invalid = useFieldInvalid(props['aria-invalid'])` → `aria-invalid={invalid}` (returns `undefined` outside a `Field`)
142
+ - Notes: form layout and validation helpers; `Field` automatically provides a generated control id to `FieldLabel` and labelable descendants when explicit ids are omitted. One control per `Field`: a `RadioGroup` placed directly in a `Field` takes the `FieldLabel` as its group label (`aria-labelledby`) and its items keep their own ids; a `CheckboxGroup` placed directly in a `Field` behaves the same way; never put several loose `Checkbox`/`Switch` controls in one `Field` (they would share the control id) — wrap checkboxes in a `CheckboxGroup`, or use `FieldSet` + `FieldLegend` with one `Field` per control. `useFieldLabelId()` returns the current `FieldLabel` id (or `undefined` outside a `Field`) for custom group controls
143
+ - Invalid state: `Field.invalid?: boolean` (or legacy `data-invalid="true"`; `invalid` wins when both are set) renders `data-invalid="true"` (label/description turn destructive) and sets `aria-invalid` on the control inside. Styled red: `Input` (incl. `InputGroupInput`, `PhoneInput`), `Textarea`, `NativeSelect`, `SelectTrigger`, `ComboboxInput`, `ComboboxChipsInput`, `AutocompleteInput`, `InputOTP` (+ slots), `NumberField`. `aria-invalid` only, no red style: `Checkbox`, `Switch`, `RadioGroup` and `CheckboxGroup` (on the group). Not propagated: `Slider`, `DatePicker`/`DateRangePicker` triggers. A control's own `aria-invalid` (including `false`) overrides the `Field`. Do: `<Field invalid><FieldLabel/><Input/><FieldError/></Field>`. Don't: repeat `aria-invalid` on every control inside an invalid `Field`. Custom controls: `const invalid = useFieldInvalid(props['aria-invalid'])` → `aria-invalid={invalid}` (returns `undefined` outside a `Field`)
138
144
  - `grid`
139
145
  - Exports: `Grid`, `GridItem`
140
146
  - Notes: 12-column CSS grid by default. `Grid` supports spacing props plus direct `templateRows` and `templateColumns`; spacing values `xs` to `xl` map to `4/8/16/24/32px`; `GridItem` defaults to `colSpan={12}` and supports numeric `colSpan` and `rowSpan`. Use `useBreakpointValue` when these values need to change by breakpoint.
@@ -165,6 +171,9 @@ Unless noted otherwise, each module also exports its public `*Props` types from
165
171
  - `checkbox`
166
172
  - Exports: `Checkbox`
167
173
  - Notes: supports `size: 'sm' | 'md' | 'lg'`, `color: UIColor` (default `primary`), `indeterminate?: boolean` for the mixed state (use it alongside a boolean `checked`; `checked="indeterminate"` is not supported), `label?: React.ReactNode`, `labelProps`, and automatic `id`/`htmlFor` wiring when a label is provided without an explicit `id`; composed label text follows checkbox size (`sm` 12px, `md` 14px, `lg` 18px); `description?: React.ReactNode` + `descriptionProps` render muted helper text (a `<p>`) below the label, linked via `aria-describedby`; description text is `sm` 12px, `md` 12px, `lg` 14px
174
+ - `checkbox-group`
175
+ - Exports: `CheckboxGroup`
176
+ - Notes: shares one `string[]` value between child `Checkbox`es; each child needs `value`. `value`/`defaultValue`/`onValueChange(value: string[], eventDetails)`. Select all: pass every value in `allValues` and add `<Checkbox parent label="…" />` (no `value`); it checks/unchecks all and shows the mixed state automatically (don't compute `indeterminate` yourself). `orientation: 'vertical' | 'horizontal'` (default `vertical`; horizontal wraps in a row). `color: UIColor` (default `primary`) applies to every child; a child's own `color` wins. `disabled` disables all. Inside a `Field`, the group is labelled by `FieldLabel` (`aria-labelledby`), gets `aria-invalid` from an invalid `Field`, and each checkbox keeps its own id. Supports `asChild`
168
177
  - `switch`
169
178
  - Exports: `Switch`
170
179
  - Notes: supports `size: 'sm' | 'md' | 'lg'`, `color: UIColor` (default `green`), `label?: React.ReactNode`, `labelProps`, and automatic `id`/`htmlFor` wiring when a label is provided without an explicit `id`; `color` controls the checked track and indicator color only; track size is `sm` 30x14px, `md` 34x16px, and `lg` 42x20px (control heights match `Checkbox`); the thumb and internal indicator scale with the switch; composed label text follows switch size (`sm` 12px, `md` 14px, `lg` 18px (same as `Checkbox` and `RadioGroupItem`)); `description?: React.ReactNode` + `descriptionProps` render muted helper text (a `<p>`) below the label, linked via `aria-describedby`; description text is `sm` 12px, `md` 12px, `lg` 14px
@@ -179,6 +188,9 @@ Unless noted otherwise, each module also exports its public `*Props` types from
179
188
  - `combobox`
180
189
  - Exports: `Combobox`, `ComboboxInput`, `ComboboxContent`, `ComboboxList`, `ComboboxItem`, `ComboboxGroup`, `ComboboxLabel`, `ComboboxCollection`, `ComboboxClear`, `ComboboxEmpty`, `ComboboxSeparator`, `ComboboxChips`, `ComboboxChip`, `ComboboxChipsInput`, `ComboboxTrigger`, `ComboboxValue`, `useComboboxAnchor`
181
190
  - Notes: `ComboboxInput` supports `icon?: React.ReactNode`, `triggerIcon?: React.ReactNode`, `showTrigger?: boolean`, and `showClear?: boolean`; `ComboboxChips` supports `showClear?: boolean` to render a button that clears all selected chips at once; `ComboboxContent` supports `container` for rendering inside overlays such as dialogs, and forwards the underlying Base UI Positioner's public props (`side`, `align`, `sideOffset`, `alignOffset`, `anchor`, `positionMethod` (default `'absolute'`), `collisionBoundary`, `collisionPadding`, `sticky`, `arrowPadding`, `disableAnchorTracking`, `collisionAvoidance`)
191
+ - `autocomplete`
192
+ - Exports: `Autocomplete`, `AutocompleteInput`, `AutocompleteContent`, `AutocompleteList`, `AutocompleteItem`, `AutocompleteGroup`, `AutocompleteLabel`, `AutocompleteCollection`, `AutocompleteEmpty`, `AutocompleteStatus`, `AutocompleteSeparator`, `useAutocompleteFilter`
193
+ - Notes: free-text input with suggestions; the value is the input text (`value`/`defaultValue`/`onValueChange(value: string, eventDetails)`), so any text is valid. Use `Combobox` when the value must be one of the options. Pass suggestions in `items` and render with `AutocompleteCollection`; for object items set `itemToStringValue` so picking fills the input. Server suggestions: `filter={null}`, update `items` from the request, render loading/count text in `AutocompleteStatus` (live region). `AutocompleteInput` props: `icon`, `showClear` (default `false`), `showTrigger` (default `false`, unlike `ComboboxInput`), `triggerIcon`; no `asChild`. `AutocompleteContent` has the same positioner/portal props and defaults as `ComboboxContent` (`side` `bottom`, `align` `start`, `sideOffset` `6`, `container`, `keepMounted`, `sticky`, …). Root props include `mode` (`list` default, `both`, `inline`, `none`), `autoHighlight`, `openOnInputClick` (default `false`), `limit`, `submitOnItemClick`. `useAutocompleteFilter()` returns locale-aware `contains`/`startsWith`/`endsWith` matchers for a custom `filter`. Inside a `Field` it takes the control id and turns red when invalid
182
194
  - `dropzone`
183
195
  - Exports: `Dropzone`, `DropzoneArea`, `DropzoneDescription`, `DropzoneFileList`, `DropzoneFileListItem`, `DropzoneFileMessage`, `DropzoneMessage`, `DropzoneRemoveFile`, `DropzoneRetryFile`, `DropzoneTrigger`, `InfiniteProgress`, `useDropzone`
184
196
  - Notes: upload composition with validation, retry handling, status list UI, and optional `shiftOnMaxFiles`
@@ -287,7 +287,7 @@ The package stylesheet exposes these palette families:
287
287
  - `pink`
288
288
  - `green`
289
289
 
290
- The same palette family names are exported as `uiColors` and `UIColor`. `Button`, `Toggle`, `Checkbox`, `RadioGroupItem`, and `Switch` use `UIColor` for color props. `ButtonColor` remains available as a compatibility alias, but new public APIs should use `UIColor`.
290
+ The same palette family names are exported as `uiColors` and `UIColor`. `Button`, `Toggle`, `Checkbox`, `CheckboxGroup`, `RadioGroupItem`, `Switch`, `Progress`, and `Meter` use `UIColor` for color props. `ButtonColor` remains available as a compatibility alias, but new public APIs should use `UIColor`.
291
291
 
292
292
  Each palette family is exposed in four layers:
293
293
 
@@ -465,9 +465,9 @@ A full working example lives in `apps/web/src/stories/data-table-virtualized.sto
465
465
  Choose components by intent:
466
466
 
467
467
  - actions and status:
468
- - `Button`, `Badge`, `Alert`, `Progress`, `Skeleton`, `Spinner`, `toast`
468
+ - `Button`, `Badge`, `Alert`, `Progress`, `Meter`, `Skeleton`, `Spinner`, `toast`
469
469
  - forms and inputs:
470
- - `Field`, `Input`, `Textarea`, `Checkbox`, `Switch`, `RadioGroup`, `Select`, `NativeSelect`, `Combobox`, `Dropzone`, `InputGroup`, `InputOTP`, `Slider`, `DateRangePicker`
470
+ - `Field`, `Input`, `Textarea`, `Checkbox`, `CheckboxGroup`, `Switch`, `RadioGroup`, `Select`, `NativeSelect`, `Combobox`, `Autocomplete`, `Dropzone`, `InputGroup`, `InputOTP`, `Slider`, `DateRangePicker`
471
471
  - overlays and floating UI:
472
472
  - `Dialog`, `Drawer`, `Popover`, `Tooltip`, `HoverCard`, `AlertDialog`
473
473
  - navigation:
@@ -1,19 +1,15 @@
1
1
  import { t as __name } from "./rolldown-runtime-BhWHdk3m.js";
2
- //#region src/utils/parse-hotkey.d.ts
3
2
  type HotkeyItemOptions = {
4
3
  preventDefault?: boolean;
5
4
  usePhysicalKeys?: boolean;
6
5
  };
7
6
  type HotkeyItem$1 = [string, (event: unknown) => void, HotkeyItemOptions?];
8
7
  declare function getHotkeyHandler(hotkeys: HotkeyItem$1[]): (event: React.KeyboardEvent<HTMLElement> | KeyboardEvent) => void;
9
- //#endregion
10
- //#region src/hooks/use-hotkeys.d.ts
11
8
  type HotkeyItem = [string, (event: KeyboardEvent) => void, HotkeyItemOptions?];
12
9
  /** Registers keyboard shortcuts on the document. Items are `[hotkey, handler, options?]`; `mod` is `ctrl` or `⌘`. */
13
10
  declare function useHotkeys(hotkeys: HotkeyItem[], tagsToIgnore?: string[], triggerOnContentEditable?: boolean): void;
14
11
  declare namespace useHotkeys {
15
12
  type Hotkey = HotkeyItem;
16
13
  }
17
- //#endregion
18
14
  export { getHotkeyHandler as i, useHotkeys as n, HotkeyItemOptions as r, HotkeyItem as t };
19
- //# sourceMappingURL=use-hotkeys-D1_TEIwN.d.ts.map
15
+ //# sourceMappingURL=use-hotkeys-BVm0IGb8.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-hotkeys-YDJmGWX6.js","names":["keyNameMap","lowerKey","key","keys","hotkey","part","modifiers","reservedKeys","freeKey","pressedKey","pressedCode","event","alt","altKey","mod","ctrlKey","metaKey","ctrl","meta","shift","shiftKey","usePhysicalKeys","_event","hotkeys","handler","options","triggerOnContentEditable","tagsToIgnore","handleKeydown","useEffectEvent","useEffect"],"sources":["../src/utils/parse-hotkey.ts","../src/hooks/use-hotkeys.ts"],"sourcesContent":["export type KeyboardModifiers = {\n alt: boolean\n ctrl: boolean\n meta: boolean\n mod: boolean\n shift: boolean\n}\n\nexport type Hotkey = KeyboardModifiers & {\n key?: string\n}\n\ntype CheckHotkeyMatch = (event: KeyboardEvent) => boolean\n\nconst keyNameMap: Record<string, string> = {\n ' ': 'space',\n ArrowLeft: 'arrowleft',\n ArrowRight: 'arrowright',\n ArrowUp: 'arrowup',\n ArrowDown: 'arrowdown',\n Escape: 'escape',\n Esc: 'escape',\n esc: 'escape',\n Enter: 'enter',\n Tab: 'tab',\n Backspace: 'backspace',\n Delete: 'delete',\n Insert: 'insert',\n Home: 'home',\n End: 'end',\n PageUp: 'pageup',\n PageDown: 'pagedown',\n '+': 'plus',\n '-': 'minus',\n '*': 'asterisk',\n '/': 'slash'\n}\n\nfunction normalizeKey(key: string): string {\n const lowerKey = key.replace('Key', '').toLowerCase()\n return keyNameMap[key] || lowerKey\n}\n\nexport function parseHotkey(hotkey: string): Hotkey {\n const keys = hotkey\n .toLowerCase()\n .split('+')\n .map((part) => part.trim())\n\n const modifiers: KeyboardModifiers = {\n alt: keys.includes('alt'),\n ctrl: keys.includes('ctrl'),\n meta: keys.includes('meta'),\n mod: keys.includes('mod'),\n shift: keys.includes('shift')\n }\n\n const reservedKeys = ['alt', 'ctrl', 'meta', 'shift', 'mod']\n\n const freeKey = keys.find((key) => !reservedKeys.includes(key))\n\n return {\n ...modifiers,\n key: freeKey === '[plus]' ? '+' : freeKey\n }\n}\n\nfunction isExactHotkey(hotkey: Hotkey, event: KeyboardEvent, usePhysicalKeys?: boolean): boolean {\n const { alt, ctrl, meta, mod, shift, key } = hotkey\n const { altKey, ctrlKey, metaKey, shiftKey, key: pressedKey, code: pressedCode } = event\n\n if (alt !== altKey) {\n return false\n }\n\n if (mod) {\n if (!ctrlKey && !metaKey) {\n return false\n }\n } else {\n if (ctrl !== ctrlKey) {\n return false\n }\n if (meta !== metaKey) {\n return false\n }\n }\n if (shift !== shiftKey) {\n return false\n }\n\n if (\n key &&\n (usePhysicalKeys\n ? normalizeKey(pressedCode) === normalizeKey(key)\n : normalizeKey(pressedKey ?? pressedCode) === normalizeKey(key))\n ) {\n return true\n }\n\n return false\n}\n\nexport function getHotkeyMatcher(hotkey: string, usePhysicalKeys?: boolean): CheckHotkeyMatch {\n return (event) => isExactHotkey(parseHotkey(hotkey), event, usePhysicalKeys)\n}\n\nexport type HotkeyItemOptions = {\n preventDefault?: boolean\n usePhysicalKeys?: boolean\n}\n\ntype HotkeyItem = [string, (event: unknown) => void, HotkeyItemOptions?]\n\nexport function getHotkeyHandler(hotkeys: HotkeyItem[]) {\n return (event: React.KeyboardEvent<HTMLElement> | KeyboardEvent) => {\n const _event = 'nativeEvent' in event ? event.nativeEvent : event\n hotkeys.forEach(([hotkey, handler, options = { preventDefault: true, usePhysicalKeys: false }]) => {\n if (getHotkeyMatcher(hotkey, options.usePhysicalKeys)(_event)) {\n if (options.preventDefault) {\n event.preventDefault()\n }\n\n handler(_event)\n }\n })\n }\n}\n","import { useEffect, useEffectEvent } from 'react'\n\nimport { getHotkeyHandler, getHotkeyMatcher, type HotkeyItemOptions } from '../utils/parse-hotkey'\n\nexport type { HotkeyItemOptions }\nexport { getHotkeyHandler }\n\nexport type HotkeyItem = [string, (event: KeyboardEvent) => void, HotkeyItemOptions?]\n\nfunction shouldFireEvent(event: KeyboardEvent, tagsToIgnore: string[], triggerOnContentEditable = false) {\n if (event.target instanceof HTMLElement) {\n if (triggerOnContentEditable) {\n return !tagsToIgnore.includes(event.target.tagName)\n }\n\n return !event.target.isContentEditable && !tagsToIgnore.includes(event.target.tagName)\n }\n\n return true\n}\n\n/** Registers keyboard shortcuts on the document. Items are `[hotkey, handler, options?]`; `mod` is `ctrl` or `⌘`. */\nexport function useHotkeys(\n hotkeys: HotkeyItem[],\n tagsToIgnore: string[] = ['INPUT', 'TEXTAREA', 'SELECT'],\n triggerOnContentEditable = false\n) {\n const handleKeydown = useEffectEvent((event: KeyboardEvent) => {\n hotkeys.forEach(([hotkey, handler, options = { preventDefault: true, usePhysicalKeys: false }]) => {\n if (\n getHotkeyMatcher(hotkey, options.usePhysicalKeys)(event) &&\n shouldFireEvent(event, tagsToIgnore, triggerOnContentEditable)\n ) {\n if (options.preventDefault) {\n event.preventDefault()\n }\n\n handler(event)\n }\n })\n })\n\n useEffect(() => {\n document.documentElement.addEventListener('keydown', handleKeydown)\n return () => document.documentElement.removeEventListener('keydown', handleKeydown)\n }, [])\n}\n\nexport namespace useHotkeys {\n export type Hotkey = HotkeyItem\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"use-hotkeys-YDJmGWX6.js","names":["keyNameMap","lowerKey","key","keys","hotkey","part","modifiers","reservedKeys","freeKey","pressedKey","pressedCode","event","alt","altKey","mod","ctrlKey","metaKey","ctrl","meta","shift","shiftKey","usePhysicalKeys","_event","hotkeys","handler","options","triggerOnContentEditable","tagsToIgnore","handleKeydown","useEffectEvent","useEffect"],"sources":["../src/utils/parse-hotkey.ts","../src/hooks/use-hotkeys.ts"],"sourcesContent":["export type KeyboardModifiers = {\n alt: boolean\n ctrl: boolean\n meta: boolean\n mod: boolean\n shift: boolean\n}\n\nexport type Hotkey = KeyboardModifiers & {\n key?: string\n}\n\ntype CheckHotkeyMatch = (event: KeyboardEvent) => boolean\n\nconst keyNameMap: Record<string, string> = {\n ' ': 'space',\n ArrowLeft: 'arrowleft',\n ArrowRight: 'arrowright',\n ArrowUp: 'arrowup',\n ArrowDown: 'arrowdown',\n Escape: 'escape',\n Esc: 'escape',\n esc: 'escape',\n Enter: 'enter',\n Tab: 'tab',\n Backspace: 'backspace',\n Delete: 'delete',\n Insert: 'insert',\n Home: 'home',\n End: 'end',\n PageUp: 'pageup',\n PageDown: 'pagedown',\n '+': 'plus',\n '-': 'minus',\n '*': 'asterisk',\n '/': 'slash'\n}\n\nfunction normalizeKey(key: string): string {\n const lowerKey = key.replace('Key', '').toLowerCase()\n return keyNameMap[key] || lowerKey\n}\n\nexport function parseHotkey(hotkey: string): Hotkey {\n const keys = hotkey\n .toLowerCase()\n .split('+')\n .map((part) => part.trim())\n\n const modifiers: KeyboardModifiers = {\n alt: keys.includes('alt'),\n ctrl: keys.includes('ctrl'),\n meta: keys.includes('meta'),\n mod: keys.includes('mod'),\n shift: keys.includes('shift')\n }\n\n const reservedKeys = ['alt', 'ctrl', 'meta', 'shift', 'mod']\n\n const freeKey = keys.find((key) => !reservedKeys.includes(key))\n\n return {\n ...modifiers,\n key: freeKey === '[plus]' ? '+' : freeKey\n }\n}\n\nfunction isExactHotkey(hotkey: Hotkey, event: KeyboardEvent, usePhysicalKeys?: boolean): boolean {\n const { alt, ctrl, meta, mod, shift, key } = hotkey\n const { altKey, ctrlKey, metaKey, shiftKey, key: pressedKey, code: pressedCode } = event\n\n if (alt !== altKey) {\n return false\n }\n\n if (mod) {\n if (!ctrlKey && !metaKey) {\n return false\n }\n } else {\n if (ctrl !== ctrlKey) {\n return false\n }\n if (meta !== metaKey) {\n return false\n }\n }\n if (shift !== shiftKey) {\n return false\n }\n\n if (\n key &&\n (usePhysicalKeys\n ? normalizeKey(pressedCode) === normalizeKey(key)\n : normalizeKey(pressedKey ?? pressedCode) === normalizeKey(key))\n ) {\n return true\n }\n\n return false\n}\n\nexport function getHotkeyMatcher(hotkey: string, usePhysicalKeys?: boolean): CheckHotkeyMatch {\n return (event) => isExactHotkey(parseHotkey(hotkey), event, usePhysicalKeys)\n}\n\nexport type HotkeyItemOptions = {\n preventDefault?: boolean\n usePhysicalKeys?: boolean\n}\n\ntype HotkeyItem = [string, (event: unknown) => void, HotkeyItemOptions?]\n\nexport function getHotkeyHandler(hotkeys: HotkeyItem[]) {\n return (event: React.KeyboardEvent<HTMLElement> | KeyboardEvent) => {\n const _event = 'nativeEvent' in event ? event.nativeEvent : event\n hotkeys.forEach(([hotkey, handler, options = { preventDefault: true, usePhysicalKeys: false }]) => {\n if (getHotkeyMatcher(hotkey, options.usePhysicalKeys)(_event)) {\n if (options.preventDefault) {\n event.preventDefault()\n }\n\n handler(_event)\n }\n })\n }\n}\n","import { useEffect, useEffectEvent } from 'react'\n\nimport { getHotkeyHandler, getHotkeyMatcher, type HotkeyItemOptions } from '../utils/parse-hotkey'\n\nexport type { HotkeyItemOptions }\nexport { getHotkeyHandler }\n\nexport type HotkeyItem = [string, (event: KeyboardEvent) => void, HotkeyItemOptions?]\n\nfunction shouldFireEvent(event: KeyboardEvent, tagsToIgnore: string[], triggerOnContentEditable = false) {\n if (event.target instanceof HTMLElement) {\n if (triggerOnContentEditable) {\n return !tagsToIgnore.includes(event.target.tagName)\n }\n\n return !event.target.isContentEditable && !tagsToIgnore.includes(event.target.tagName)\n }\n\n return true\n}\n\n/** Registers keyboard shortcuts on the document. Items are `[hotkey, handler, options?]`; `mod` is `ctrl` or `⌘`. */\nexport function useHotkeys(\n hotkeys: HotkeyItem[],\n tagsToIgnore: string[] = ['INPUT', 'TEXTAREA', 'SELECT'],\n triggerOnContentEditable = false\n) {\n const handleKeydown = useEffectEvent((event: KeyboardEvent) => {\n hotkeys.forEach(([hotkey, handler, options = { preventDefault: true, usePhysicalKeys: false }]) => {\n if (\n getHotkeyMatcher(hotkey, options.usePhysicalKeys)(event) &&\n shouldFireEvent(event, tagsToIgnore, triggerOnContentEditable)\n ) {\n if (options.preventDefault) {\n event.preventDefault()\n }\n\n handler(event)\n }\n })\n })\n\n useEffect(() => {\n document.documentElement.addEventListener('keydown', handleKeydown)\n return () => document.documentElement.removeEventListener('keydown', handleKeydown)\n }, [])\n}\n\nexport namespace useHotkeys {\n export type Hotkey = HotkeyItem\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uselets/ui",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
4
4
  "type": "module",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,
@@ -63,23 +63,23 @@
63
63
  "@base-ui/react": "1.9.0",
64
64
  "@fontsource-variable/inter": "^5.3.0",
65
65
  "@react-input/mask": "2.0.4",
66
- "@tabler/icons-react": "^3.49.0",
66
+ "@tabler/icons-react": "^3.50.0",
67
67
  "@tanstack/react-table": "9.3.1",
68
68
  "@uselets/tokens": "0.2.0",
69
69
  "class-variance-authority": "^0.7.1",
70
70
  "cmdk": "1.1.1",
71
- "cn": "0.5.0",
71
+ "cn": "0.5.2",
72
72
  "commander": "15.0.0",
73
73
  "date-fns": "4.4.0",
74
74
  "embla-carousel-react": "^8.6.0",
75
75
  "input-otp": "1.5.0",
76
76
  "next-themes": "0.4.6",
77
77
  "react-day-picker": "10.0.2",
78
- "react-dropzone": "20.1.3",
78
+ "react-dropzone": "20.1.4",
79
79
  "react-phone-number-input": "^3.4.18",
80
- "react-resizable-panels": "4.14.5",
80
+ "react-resizable-panels": "4.17.0",
81
81
  "recharts": "^3.10.1",
82
- "shadcn": "4.22.0",
82
+ "shadcn": "4.23.0",
83
83
  "sonner": "2.0.8"
84
84
  },
85
85
  "peerDependencies": {
@@ -88,18 +88,18 @@
88
88
  },
89
89
  "devDependencies": {
90
90
  "@bosh-code/tsdown-plugin-tailwindcss": "1.0.1",
91
- "@tailwindcss/postcss": "4.3.3",
91
+ "@tailwindcss/postcss": "4.3.4",
92
92
  "@testing-library/react": "16.3.3",
93
- "@vitest/coverage-v8": "5.0.5",
94
- "@tsdown/css": "0.23.1",
95
- "@turbo/gen": "2.11.9",
96
- "@types/node": "26.6.5",
93
+ "@vitest/coverage-v8": "5.1.0",
94
+ "@tsdown/css": "0.23.5",
95
+ "@turbo/gen": "2.11.10",
96
+ "@types/node": "26.6.6",
97
97
  "@types/react": "19.3.0",
98
98
  "@types/react-dom": "19.3.0",
99
99
  "jsdom": "30.1.3",
100
- "tailwindcss": "4.3.3",
101
- "tsdown": "0.23.1",
100
+ "tailwindcss": "4.3.4",
101
+ "tsdown": "0.23.5",
102
102
  "typescript": "7.0.2",
103
- "vitest": "5.0.5"
103
+ "vitest": "5.1.0"
104
104
  }
105
105
  }
@@ -54,14 +54,14 @@ To set up a consumer project after installing `@uselets/ui`, run `bun uselets in
54
54
  app's entry file (`import '@fontsource-variable/inter'` in `app/layout.tsx`, `pages/_app.tsx`, or `src/main.tsx`),
55
55
  not via `@import` in CSS — some bundlers, including Next.js, don't resolve third-party CSS `@import`s reliably.
56
56
  - Recommend `@uselets/ui/postcss.config` when the app needs the package PostCSS preset for Tailwind v4.
57
- - Interactive components are built on Base UI (`@base-ui/react`). Use `asChild` (Radix-style, single child element) for polymorphism; the child replaces the part's content. Not supported on `ScrollArea`, `ScrollBar`, `SelectContent`, `SelectItem`, `AccordionContent`, `Checkbox`, `Switch`, `RadioGroupItem`, `Progress`, `Slider`, `NavigationMenu`, `NumberFieldScrubArea`, `ComboboxInput`, `ComboboxClear`, `ComboboxChipsInput`, `NumberField`, `NumberFieldInput` (their internal structure is required). Do not pass Base UI's `render` prop — it is not part of the public API. When `asChild` wraps a button-like part (triggers, closes, `TabsTrigger`, `AccordionTrigger`, `Toggle`, `SelectTrigger`, `AlertDialogAction`/`Cancel`) with a non-`<button>` child, also pass `nativeButton={false}` (not needed for `TooltipTrigger`/`HoverCardTrigger`). Change callbacks of Base UI-backed components (`onOpenChange`, `onValueChange`, `onCheckedChange`, …) receive `(value, eventDetails)`; `DateRangePicker`, `SidebarProvider` and `Stepper` callbacks don't.
58
- - Popups unmount when closed. `keepMounted?: boolean` (default `false`) keeps them mounted while hidden on `DialogContent`, `AlertDialogContent`, `DrawerContent`, `PopoverContent`, `DropdownMenuContent`, `DropdownMenuSubContent`, `TooltipContent`/`Tooltip`, `HoverCardContent`, `ComboboxContent` and `NavigationMenuPositioner`; `SelectContent` does not accept it. `sticky?: boolean` (default `false`) keeps `PopoverContent`, `SelectContent`, `DropdownMenuContent`, `DropdownMenuSubContent`, `TooltipContent`/`Tooltip`, `HoverCardContent` and `ComboboxContent` in the viewport after the anchor scrolls out of view. Other positioner props (`collisionPadding`, `collisionBoundary`, `arrowPadding`, `collisionAvoidance`) are only exposed on `ComboboxContent`.
57
+ - Interactive components are built on Base UI (`@base-ui/react`). Use `asChild` (Radix-style, single child element) for polymorphism; the child replaces the part's content. Not supported on `ScrollArea`, `ScrollBar`, `SelectContent`, `SelectItem`, `AccordionContent`, `Checkbox`, `Switch`, `RadioGroupItem`, `Progress`, `Slider`, `NavigationMenu`, `NumberFieldScrubArea`, `ComboboxInput`, `ComboboxClear`, `ComboboxChipsInput`, `AutocompleteInput`, `Meter`, `ToolbarInput`, `NumberField`, `NumberFieldInput` (their internal structure is required). Do not pass Base UI's `render` prop — it is not part of the public API. When `asChild` wraps a button-like part (triggers, closes, `TabsTrigger`, `AccordionTrigger`, `Toggle`, `SelectTrigger`, `AlertDialogAction`/`Cancel`) with a non-`<button>` child, also pass `nativeButton={false}` (not needed for `TooltipTrigger`/`HoverCardTrigger`). Change callbacks of Base UI-backed components (`onOpenChange`, `onValueChange`, `onCheckedChange`, …) receive `(value, eventDetails)`; `DateRangePicker`, `SidebarProvider` and `Stepper` callbacks don't.
58
+ - Popups unmount when closed. `keepMounted?: boolean` (default `false`) keeps them mounted while hidden on `DialogContent`, `AlertDialogContent`, `DrawerContent`, `PopoverContent`, `DropdownMenuContent`, `DropdownMenuSubContent`, `TooltipContent`/`Tooltip`, `HoverCardContent`, `ComboboxContent`, `AutocompleteContent` and `NavigationMenuPositioner`; `SelectContent` does not accept it. `sticky?: boolean` (default `false`) keeps `PopoverContent`, `SelectContent`, `DropdownMenuContent`, `DropdownMenuSubContent`, `TooltipContent`/`Tooltip`, `HoverCardContent`, `ComboboxContent` and `AutocompleteContent` in the viewport after the anchor scrolls out of view. Other positioner props (`collisionPadding`, `collisionBoundary`, `arrowPadding`, `collisionAvoidance`) are only exposed on `ComboboxContent` and `AutocompleteContent`.
59
59
  - For Vite apps, `@tailwindcss/vite` (registered in `vite.config.ts`, no `postcss.config.mjs`) is a valid alternative to PostCSS; prefer it when the project uses isolated installs (pnpm, Bun workspaces). See `references/package-guide.md`.
60
60
  - For tooltip-heavy apps, wrap the app with `TooltipProvider` (`delay`, not `delayDuration`); use `Tooltip label={...}` for common trigger/content usage (it accepts `delay`/`closeDelay`) and `TooltipRoot` only when manual composition is needed.
61
61
  - Use `UnstyledButton` when button semantics are needed without `Button` variants; it provides reset styles, pointer cursor, focus ring, default `type="button"`, and `asChild`.
62
62
  - For toast usage, mount `Toaster` near the app root before calling `toast(...)`.
63
63
  - For package theme helpers, use `ThemeProvider`, `useTheme`, and `ModeToggle` from `@uselets/ui/theme` or the root barrel.
64
- - For form fields, `Field` automatically shares a generated control id with `FieldLabel` and labelable controls when explicit ids are omitted; pass explicit matching `htmlFor` and `id` only when a stable custom id is required. Use one control per `Field` (a `RadioGroup` counts as one control); for several checkboxes/switches use `FieldSet` + `FieldLegend` with one `Field` each. Mark errors with `<Field invalid>` (not `aria-invalid` on each control): it colors the label and propagates `aria-invalid` to the control; `Checkbox`/`Switch`/`RadioGroup` get the attribute but no red style.
64
+ - For form fields, `Field` automatically shares a generated control id with `FieldLabel` and labelable controls when explicit ids are omitted; pass explicit matching `htmlFor` and `id` only when a stable custom id is required. Use one control per `Field` (a `RadioGroup` or `CheckboxGroup` counts as one control); for several checkboxes use a `CheckboxGroup` (it also provides "select all" via a `parent` checkbox), and for several switches use `FieldSet` + `FieldLegend` with one `Field` each. Mark errors with `<Field invalid>` (not `aria-invalid` on each control): it colors the label and propagates `aria-invalid` to the control; `Checkbox`/`Switch`/`RadioGroup`/`CheckboxGroup` get the attribute but no red style.
65
65
  - For client-side tabular data, use `DataTable` from `@uselets/ui/data-table`. Defaults are bare: `enableRowSelection`, `enableSorting`, and `showPagination` are all `false`. Set `enableRowSelection` to auto-prepend the selection checkbox column (no need to add `createDataTableSelectColumn` manually); set `enableSorting` to make `DataTableColumnHeader` clickable for sort. `filterColumns` accepts a single id or an array; with 2+ ids the toolbar renders an `InputGroup` with a column selector on the left. `toolbarActions` always sits at the right of the toolbar. All labels default to pt-BR; override any subset through `labels` (`Partial<DataTableLabels>`), with full defaults exposed as `defaultDataTableLabels`. Use `variant` on `DataTable` (or directly on the base `Table`) to switch chrome: `"line"` (default) renders only horizontal separators between rows; `"outline"` adds a rounded outer border around the table. The base `Table` from `@uselets/ui/table` renders only the `<table>` element and is striped by default (pass `striped={false}` to disable). Wrap it in `TableContainer` to control scroll; `minWidth` lives on `TableContainer`. Combine `stickyHeader` on `Table` with `max-h` + `overflow-y-auto` on the `TableContainer` to keep the `<thead>` visible during vertical scroll. `DataTable` wraps its `Table` in `TableContainer` automatically.
66
66
 
67
67
  ## Quick Routing
@@ -115,11 +115,17 @@ Unless noted otherwise, each module also exports its public `*Props` types from
115
115
  - Notes: action button with `solid`, `secondary`, `outline`, `subtle`, `ghost`, and `link` variants, `color: UIColor` (`primary` default), sizes from `xs` through `xl` plus icon sizes through `icon-xl`, and `loading`
116
116
  - `button-group`
117
117
  - Exports: `ButtonGroup`, `ButtonGroupSeparator`, `ButtonGroupText`, `buttonGroupVariants`
118
+ - `toolbar`
119
+ - Exports: `Toolbar`, `ToolbarButton`, `ToolbarGroup`, `ToolbarInput`, `ToolbarLink`, `ToolbarSeparator`
120
+ - Notes: action bar (`role="toolbar"`) that is one tab stop; arrow keys move focus between its controls. Always pass `aria-label`. No background/border of its own (wrap in `Card` or a container). `Toolbar` props: `orientation: 'horizontal' | 'vertical'` (default `horizontal`), `loopFocus` (default `true`), `disabled`. `ToolbarButton` renders `Button`: `variant` (default `ghost`), `size` (default `sm`), `color: UIColor`, `loading`; disabled buttons stay focusable (`focusableWhenDisabled`, default `true`). To open a menu/popover: `<DropdownMenuTrigger asChild><ToolbarButton>…</ToolbarButton></DropdownMenuTrigger>`. `ToolbarSeparator` takes the opposite orientation automatically. `ToolbarInput` renders `Input` (no `asChild`). Use for action bars (bulk actions, filters, editors), not navigation (`Tabs`/`NavigationMenu`)
118
121
  - `empty`
119
122
  - Exports: `Empty`, `EmptyContent`, `EmptyDescription`, `EmptyHeader`, `EmptyMedia`, `EmptyTitle`
120
123
  - `progress`
121
124
  - Exports: `Progress`, `progressVariants`
122
125
  - Notes: linear progress bar driven by a single `value` (0–100); `size: 'sm' | 'md' | 'lg'` (default: `md`) controls bar height and `color: UIColor` (default: `primary`) controls the indicator; omitting `value` (or passing `null`) renders the indeterminate state
126
+ - `meter`
127
+ - Exports: `Meter`, `meterVariants`
128
+ - Notes: linear bar for a static measurement within a range (usage, capacity, share of a total) with `role="meter"`; use `Progress` for task completion. `value` required; `min`/`max` (default `0`/`100`); `label?: React.ReactNode` renders above the bar and names it (without it, pass `aria-label`); `showValue?: boolean` (default `false`) prints the formatted value at the end of the label row, formatted with `format?: Intl.NumberFormatOptions` and `locale`. `size: 'sm' | 'md' | 'lg'` (default `md`) and `color: UIColor` (default `primary`) match `Progress`; `className` targets the bar. No `asChild`
123
129
  - `ring-progress`
124
130
  - Exports: `RingProgress`, `ringProgressVariants`
125
131
  - Notes: circular progress indicator driven by a single `value` (0–100); `size: 'sm' | 'md' | 'lg'` (default: `md`, `32/40/48px`), `thickness: 'thin' | 'md' | 'thick'` (default: `md`), and `color: UIColor` (default: `primary`); normalized `viewBox` means the size can also be set via `className` (e.g. `size-5`); rounded line caps
@@ -133,8 +139,8 @@ Unless noted otherwise, each module also exports its public `*Props` types from
133
139
 
134
140
  - `field`
135
141
  - Exports: `Field`, `FieldContent`, `FieldDescription`, `FieldError`, `FieldGroup`, `FieldLabel`, `FieldLegend`, `FieldSeparator`, `FieldSet`, `FieldTitle`, `useFieldControlId`, `useFieldInvalid`, `useFieldLabelId`
136
- - Notes: form layout and validation helpers; `Field` automatically provides a generated control id to `FieldLabel` and labelable descendants when explicit ids are omitted. One control per `Field`: a `RadioGroup` placed directly in a `Field` takes the `FieldLabel` as its group label (`aria-labelledby`) and its items keep their own ids; never put several `Checkbox`/`Switch` controls in one `Field` (they would share the control id) — use `FieldSet` + `FieldLegend` with one `Field` per control. `useFieldLabelId()` returns the current `FieldLabel` id (or `undefined` outside a `Field`) for custom group controls
137
- - Invalid state: `Field.invalid?: boolean` (or legacy `data-invalid="true"`; `invalid` wins when both are set) renders `data-invalid="true"` (label/description turn destructive) and sets `aria-invalid` on the control inside. Styled red: `Input` (incl. `InputGroupInput`, `PhoneInput`), `Textarea`, `NativeSelect`, `SelectTrigger`, `ComboboxInput`, `ComboboxChipsInput`, `InputOTP` (+ slots), `NumberField`. `aria-invalid` only, no red style: `Checkbox`, `Switch`, `RadioGroup` (on the group). Not propagated: `Slider`, `DatePicker`/`DateRangePicker` triggers. A control's own `aria-invalid` (including `false`) overrides the `Field`. Do: `<Field invalid><FieldLabel/><Input/><FieldError/></Field>`. Don't: repeat `aria-invalid` on every control inside an invalid `Field`. Custom controls: `const invalid = useFieldInvalid(props['aria-invalid'])` → `aria-invalid={invalid}` (returns `undefined` outside a `Field`)
142
+ - Notes: form layout and validation helpers; `Field` automatically provides a generated control id to `FieldLabel` and labelable descendants when explicit ids are omitted. One control per `Field`: a `RadioGroup` placed directly in a `Field` takes the `FieldLabel` as its group label (`aria-labelledby`) and its items keep their own ids; a `CheckboxGroup` placed directly in a `Field` behaves the same way; never put several loose `Checkbox`/`Switch` controls in one `Field` (they would share the control id) — wrap checkboxes in a `CheckboxGroup`, or use `FieldSet` + `FieldLegend` with one `Field` per control. `useFieldLabelId()` returns the current `FieldLabel` id (or `undefined` outside a `Field`) for custom group controls
143
+ - Invalid state: `Field.invalid?: boolean` (or legacy `data-invalid="true"`; `invalid` wins when both are set) renders `data-invalid="true"` (label/description turn destructive) and sets `aria-invalid` on the control inside. Styled red: `Input` (incl. `InputGroupInput`, `PhoneInput`), `Textarea`, `NativeSelect`, `SelectTrigger`, `ComboboxInput`, `ComboboxChipsInput`, `AutocompleteInput`, `InputOTP` (+ slots), `NumberField`. `aria-invalid` only, no red style: `Checkbox`, `Switch`, `RadioGroup` and `CheckboxGroup` (on the group). Not propagated: `Slider`, `DatePicker`/`DateRangePicker` triggers. A control's own `aria-invalid` (including `false`) overrides the `Field`. Do: `<Field invalid><FieldLabel/><Input/><FieldError/></Field>`. Don't: repeat `aria-invalid` on every control inside an invalid `Field`. Custom controls: `const invalid = useFieldInvalid(props['aria-invalid'])` → `aria-invalid={invalid}` (returns `undefined` outside a `Field`)
138
144
  - `grid`
139
145
  - Exports: `Grid`, `GridItem`
140
146
  - Notes: 12-column CSS grid by default. `Grid` supports spacing props plus direct `templateRows` and `templateColumns`; spacing values `xs` to `xl` map to `4/8/16/24/32px`; `GridItem` defaults to `colSpan={12}` and supports numeric `colSpan` and `rowSpan`. Use `useBreakpointValue` when these values need to change by breakpoint.
@@ -165,6 +171,9 @@ Unless noted otherwise, each module also exports its public `*Props` types from
165
171
  - `checkbox`
166
172
  - Exports: `Checkbox`
167
173
  - Notes: supports `size: 'sm' | 'md' | 'lg'`, `color: UIColor` (default `primary`), `indeterminate?: boolean` for the mixed state (use it alongside a boolean `checked`; `checked="indeterminate"` is not supported), `label?: React.ReactNode`, `labelProps`, and automatic `id`/`htmlFor` wiring when a label is provided without an explicit `id`; composed label text follows checkbox size (`sm` 12px, `md` 14px, `lg` 18px); `description?: React.ReactNode` + `descriptionProps` render muted helper text (a `<p>`) below the label, linked via `aria-describedby`; description text is `sm` 12px, `md` 12px, `lg` 14px
174
+ - `checkbox-group`
175
+ - Exports: `CheckboxGroup`
176
+ - Notes: shares one `string[]` value between child `Checkbox`es; each child needs `value`. `value`/`defaultValue`/`onValueChange(value: string[], eventDetails)`. Select all: pass every value in `allValues` and add `<Checkbox parent label="…" />` (no `value`); it checks/unchecks all and shows the mixed state automatically (don't compute `indeterminate` yourself). `orientation: 'vertical' | 'horizontal'` (default `vertical`; horizontal wraps in a row). `color: UIColor` (default `primary`) applies to every child; a child's own `color` wins. `disabled` disables all. Inside a `Field`, the group is labelled by `FieldLabel` (`aria-labelledby`), gets `aria-invalid` from an invalid `Field`, and each checkbox keeps its own id. Supports `asChild`
168
177
  - `switch`
169
178
  - Exports: `Switch`
170
179
  - Notes: supports `size: 'sm' | 'md' | 'lg'`, `color: UIColor` (default `green`), `label?: React.ReactNode`, `labelProps`, and automatic `id`/`htmlFor` wiring when a label is provided without an explicit `id`; `color` controls the checked track and indicator color only; track size is `sm` 30x14px, `md` 34x16px, and `lg` 42x20px (control heights match `Checkbox`); the thumb and internal indicator scale with the switch; composed label text follows switch size (`sm` 12px, `md` 14px, `lg` 18px (same as `Checkbox` and `RadioGroupItem`)); `description?: React.ReactNode` + `descriptionProps` render muted helper text (a `<p>`) below the label, linked via `aria-describedby`; description text is `sm` 12px, `md` 12px, `lg` 14px
@@ -179,6 +188,9 @@ Unless noted otherwise, each module also exports its public `*Props` types from
179
188
  - `combobox`
180
189
  - Exports: `Combobox`, `ComboboxInput`, `ComboboxContent`, `ComboboxList`, `ComboboxItem`, `ComboboxGroup`, `ComboboxLabel`, `ComboboxCollection`, `ComboboxClear`, `ComboboxEmpty`, `ComboboxSeparator`, `ComboboxChips`, `ComboboxChip`, `ComboboxChipsInput`, `ComboboxTrigger`, `ComboboxValue`, `useComboboxAnchor`
181
190
  - Notes: `ComboboxInput` supports `icon?: React.ReactNode`, `triggerIcon?: React.ReactNode`, `showTrigger?: boolean`, and `showClear?: boolean`; `ComboboxChips` supports `showClear?: boolean` to render a button that clears all selected chips at once; `ComboboxContent` supports `container` for rendering inside overlays such as dialogs, and forwards the underlying Base UI Positioner's public props (`side`, `align`, `sideOffset`, `alignOffset`, `anchor`, `positionMethod` (default `'absolute'`), `collisionBoundary`, `collisionPadding`, `sticky`, `arrowPadding`, `disableAnchorTracking`, `collisionAvoidance`)
191
+ - `autocomplete`
192
+ - Exports: `Autocomplete`, `AutocompleteInput`, `AutocompleteContent`, `AutocompleteList`, `AutocompleteItem`, `AutocompleteGroup`, `AutocompleteLabel`, `AutocompleteCollection`, `AutocompleteEmpty`, `AutocompleteStatus`, `AutocompleteSeparator`, `useAutocompleteFilter`
193
+ - Notes: free-text input with suggestions; the value is the input text (`value`/`defaultValue`/`onValueChange(value: string, eventDetails)`), so any text is valid. Use `Combobox` when the value must be one of the options. Pass suggestions in `items` and render with `AutocompleteCollection`; for object items set `itemToStringValue` so picking fills the input. Server suggestions: `filter={null}`, update `items` from the request, render loading/count text in `AutocompleteStatus` (live region). `AutocompleteInput` props: `icon`, `showClear` (default `false`), `showTrigger` (default `false`, unlike `ComboboxInput`), `triggerIcon`; no `asChild`. `AutocompleteContent` has the same positioner/portal props and defaults as `ComboboxContent` (`side` `bottom`, `align` `start`, `sideOffset` `6`, `container`, `keepMounted`, `sticky`, …). Root props include `mode` (`list` default, `both`, `inline`, `none`), `autoHighlight`, `openOnInputClick` (default `false`), `limit`, `submitOnItemClick`. `useAutocompleteFilter()` returns locale-aware `contains`/`startsWith`/`endsWith` matchers for a custom `filter`. Inside a `Field` it takes the control id and turns red when invalid
182
194
  - `dropzone`
183
195
  - Exports: `Dropzone`, `DropzoneArea`, `DropzoneDescription`, `DropzoneFileList`, `DropzoneFileListItem`, `DropzoneFileMessage`, `DropzoneMessage`, `DropzoneRemoveFile`, `DropzoneRetryFile`, `DropzoneTrigger`, `InfiniteProgress`, `useDropzone`
184
196
  - Notes: upload composition with validation, retry handling, status list UI, and optional `shiftOnMaxFiles`
@@ -287,7 +287,7 @@ The package stylesheet exposes these palette families:
287
287
  - `pink`
288
288
  - `green`
289
289
 
290
- The same palette family names are exported as `uiColors` and `UIColor`. `Button`, `Toggle`, `Checkbox`, `RadioGroupItem`, and `Switch` use `UIColor` for color props. `ButtonColor` remains available as a compatibility alias, but new public APIs should use `UIColor`.
290
+ The same palette family names are exported as `uiColors` and `UIColor`. `Button`, `Toggle`, `Checkbox`, `CheckboxGroup`, `RadioGroupItem`, `Switch`, `Progress`, and `Meter` use `UIColor` for color props. `ButtonColor` remains available as a compatibility alias, but new public APIs should use `UIColor`.
291
291
 
292
292
  Each palette family is exposed in four layers:
293
293
 
@@ -465,9 +465,9 @@ A full working example lives in `apps/web/src/stories/data-table-virtualized.sto
465
465
  Choose components by intent:
466
466
 
467
467
  - actions and status:
468
- - `Button`, `Badge`, `Alert`, `Progress`, `Skeleton`, `Spinner`, `toast`
468
+ - `Button`, `Badge`, `Alert`, `Progress`, `Meter`, `Skeleton`, `Spinner`, `toast`
469
469
  - forms and inputs:
470
- - `Field`, `Input`, `Textarea`, `Checkbox`, `Switch`, `RadioGroup`, `Select`, `NativeSelect`, `Combobox`, `Dropzone`, `InputGroup`, `InputOTP`, `Slider`, `DateRangePicker`
470
+ - `Field`, `Input`, `Textarea`, `Checkbox`, `CheckboxGroup`, `Switch`, `RadioGroup`, `Select`, `NativeSelect`, `Combobox`, `Autocomplete`, `Dropzone`, `InputGroup`, `InputOTP`, `Slider`, `DateRangePicker`
471
471
  - overlays and floating UI:
472
472
  - `Dialog`, `Drawer`, `Popover`, `Tooltip`, `HoverCard`, `AlertDialog`
473
473
  - navigation: