@uselets/ui 1.20.3 → 2.0.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 (295) hide show
  1. package/README.md +322 -425
  2. package/dist/as-child-Dxg3Xo1G.d.ts +41 -0
  3. package/dist/cli/uselets.mjs +5 -4
  4. package/dist/cli/uselets.mjs.map +1 -1
  5. package/dist/components/accordion.d.ts +12 -8
  6. package/dist/components/accordion.js +1 -1
  7. package/dist/components/accordion.js.map +1 -1
  8. package/dist/components/alert-dialog.d.ts +20 -15
  9. package/dist/components/alert-dialog.js +1 -1
  10. package/dist/components/alert-dialog.js.map +1 -1
  11. package/dist/components/alert.d.ts +1 -1
  12. package/dist/components/alert.js +1 -1
  13. package/dist/components/alert.js.map +1 -1
  14. package/dist/components/anchor.d.ts +3 -5
  15. package/dist/components/anchor.js +1 -1
  16. package/dist/components/anchor.js.map +1 -1
  17. package/dist/components/area-chart.d.ts +54 -0
  18. package/dist/components/area-chart.js +1 -1
  19. package/dist/components/area-chart.js.map +1 -1
  20. package/dist/components/avatar.d.ts +12 -7
  21. package/dist/components/avatar.js +1 -1
  22. package/dist/components/avatar.js.map +1 -1
  23. package/dist/components/badge.d.ts +3 -5
  24. package/dist/components/badge.js +1 -1
  25. package/dist/components/badge.js.map +1 -1
  26. package/dist/components/bar-chart.d.ts +48 -0
  27. package/dist/components/bar-chart.js +1 -1
  28. package/dist/components/bar-chart.js.map +1 -1
  29. package/dist/components/bottom-nav.d.ts +7 -3
  30. package/dist/components/bottom-nav.js +1 -1
  31. package/dist/components/bottom-nav.js.map +1 -1
  32. package/dist/components/breadcrumb.d.ts +3 -4
  33. package/dist/components/breadcrumb.js +1 -1
  34. package/dist/components/breadcrumb.js.map +1 -1
  35. package/dist/components/button-group.d.ts +3 -4
  36. package/dist/components/button-group.js +1 -1
  37. package/dist/components/button-group.js.map +1 -1
  38. package/dist/components/button.d.ts +8 -4
  39. package/dist/components/button.js +1 -1
  40. package/dist/components/button.js.map +1 -1
  41. package/dist/components/calendar.d.ts +4 -0
  42. package/dist/components/calendar.js +1 -1
  43. package/dist/components/calendar.js.map +1 -1
  44. package/dist/components/card.d.ts +4 -0
  45. package/dist/components/card.js +1 -1
  46. package/dist/components/card.js.map +1 -1
  47. package/dist/components/carousel.d.ts +11 -3
  48. package/dist/components/carousel.js +1 -1
  49. package/dist/components/carousel.js.map +1 -1
  50. package/dist/components/center.d.ts +1 -1
  51. package/dist/components/center.js +1 -1
  52. package/dist/components/center.js.map +1 -1
  53. package/dist/components/chart.js +4 -4
  54. package/dist/components/chart.js.map +1 -1
  55. package/dist/components/checkbox.d.ts +14 -4
  56. package/dist/components/checkbox.js +1 -1
  57. package/dist/components/checkbox.js.map +1 -1
  58. package/dist/components/code.js +1 -1
  59. package/dist/components/code.js.map +1 -1
  60. package/dist/components/collapsible.d.ts +8 -7
  61. package/dist/components/collapsible.js +1 -1
  62. package/dist/components/collapsible.js.map +1 -1
  63. package/dist/components/combobox.d.ts +48 -26
  64. package/dist/components/combobox.js +1 -1
  65. package/dist/components/combobox.js.map +1 -1
  66. package/dist/components/command.d.ts +16 -2
  67. package/dist/components/command.js +1 -1
  68. package/dist/components/command.js.map +1 -1
  69. package/dist/components/container.d.ts +1 -1
  70. package/dist/components/container.js +1 -1
  71. package/dist/components/container.js.map +1 -1
  72. package/dist/components/data-table.d.ts +177 -2
  73. package/dist/components/data-table.js +1 -1
  74. package/dist/components/data-table.js.map +1 -1
  75. package/dist/components/date-range-picker.d.ts +24 -2
  76. package/dist/components/date-range-picker.js +1 -1
  77. package/dist/components/date-range-picker.js.map +1 -1
  78. package/dist/components/dialog.d.ts +33 -15
  79. package/dist/components/dialog.js +1 -1
  80. package/dist/components/dialog.js.map +1 -1
  81. package/dist/components/direction.d.ts +7 -0
  82. package/dist/components/direction.js +1 -0
  83. package/dist/components/donut-chart.d.ts +12 -0
  84. package/dist/components/donut-chart.js +1 -1
  85. package/dist/components/donut-chart.js.map +1 -1
  86. package/dist/components/drawer.d.ts +33 -15
  87. package/dist/components/drawer.js +1 -1
  88. package/dist/components/drawer.js.map +1 -1
  89. package/dist/components/dropdown-menu.d.ts +36 -26
  90. package/dist/components/dropdown-menu.js +1 -1
  91. package/dist/components/dropdown-menu.js.map +1 -1
  92. package/dist/components/dropzone.d.ts +19 -0
  93. package/dist/components/dropzone.js +1 -1
  94. package/dist/components/dropzone.js.map +1 -1
  95. package/dist/components/empty.js +1 -1
  96. package/dist/components/empty.js.map +1 -1
  97. package/dist/components/field.d.ts +16 -4
  98. package/dist/components/field.js +1 -1
  99. package/dist/components/field.js.map +1 -1
  100. package/dist/components/flex.d.ts +1 -1
  101. package/dist/components/flex.js +1 -1
  102. package/dist/components/flex.js.map +1 -1
  103. package/dist/components/grid.d.ts +13 -0
  104. package/dist/components/grid.js +1 -1
  105. package/dist/components/grid.js.map +1 -1
  106. package/dist/components/group.d.ts +1 -1
  107. package/dist/components/group.js +1 -1
  108. package/dist/components/group.js.map +1 -1
  109. package/dist/components/heading.d.ts +3 -5
  110. package/dist/components/heading.js +1 -1
  111. package/dist/components/heading.js.map +1 -1
  112. package/dist/components/hover-card.d.ts +7 -6
  113. package/dist/components/hover-card.js +1 -1
  114. package/dist/components/hover-card.js.map +1 -1
  115. package/dist/components/input-group.d.ts +2 -2
  116. package/dist/components/input-group.js +1 -1
  117. package/dist/components/input-group.js.map +1 -1
  118. package/dist/components/input-otp.d.ts +4 -2
  119. package/dist/components/input-otp.js +1 -1
  120. package/dist/components/input-otp.js.map +1 -1
  121. package/dist/components/input.d.ts +1 -1
  122. package/dist/components/input.js +1 -1
  123. package/dist/components/input.js.map +1 -1
  124. package/dist/components/kbd.js +1 -1
  125. package/dist/components/kbd.js.map +1 -1
  126. package/dist/components/label.d.ts +3 -4
  127. package/dist/components/label.js +1 -1
  128. package/dist/components/label.js.map +1 -1
  129. package/dist/components/list.d.ts +8 -5
  130. package/dist/components/list.js +1 -1
  131. package/dist/components/list.js.map +1 -1
  132. package/dist/components/logo.d.ts +113 -0
  133. package/dist/components/logo.js +1 -1
  134. package/dist/components/marker.d.ts +4 -5
  135. package/dist/components/marker.js +1 -1
  136. package/dist/components/marker.js.map +1 -1
  137. package/dist/components/mask-input.d.ts +6 -0
  138. package/dist/components/mask-input.js +1 -1
  139. package/dist/components/mask-input.js.map +1 -1
  140. package/dist/components/native-select.d.ts +5 -1
  141. package/dist/components/native-select.js +1 -1
  142. package/dist/components/native-select.js.map +1 -1
  143. package/dist/components/navigation-menu.d.ts +19 -20
  144. package/dist/components/navigation-menu.js +1 -1
  145. package/dist/components/navigation-menu.js.map +1 -1
  146. package/dist/components/number-field.d.ts +18 -13
  147. package/dist/components/number-field.js +1 -1
  148. package/dist/components/number-field.js.map +1 -1
  149. package/dist/components/pagination.d.ts +9 -0
  150. package/dist/components/pagination.js +1 -1
  151. package/dist/components/pagination.js.map +1 -1
  152. package/dist/components/phone-input.d.ts +6 -0
  153. package/dist/components/phone-input.js +1 -1
  154. package/dist/components/phone-input.js.map +1 -1
  155. package/dist/components/pie-chart.d.ts +53 -0
  156. package/dist/components/pie-chart.js +1 -1
  157. package/dist/components/pie-chart.js.map +1 -1
  158. package/dist/components/popover.d.ts +13 -12
  159. package/dist/components/popover.js +1 -1
  160. package/dist/components/popover.js.map +1 -1
  161. package/dist/components/progress.d.ts +9 -3
  162. package/dist/components/progress.js +1 -1
  163. package/dist/components/progress.js.map +1 -1
  164. package/dist/components/radio-group.d.ts +20 -6
  165. package/dist/components/radio-group.js +1 -1
  166. package/dist/components/radio-group.js.map +1 -1
  167. package/dist/components/resizable.d.ts +1 -0
  168. package/dist/components/resizable.js +1 -1
  169. package/dist/components/resizable.js.map +1 -1
  170. package/dist/components/ring-progress.d.ts +9 -1
  171. package/dist/components/ring-progress.js +1 -1
  172. package/dist/components/ring-progress.js.map +1 -1
  173. package/dist/components/scroll-area.d.ts +3 -3
  174. package/dist/components/scroll-area.js +1 -1
  175. package/dist/components/scroll-area.js.map +1 -1
  176. package/dist/components/select.d.ts +25 -20
  177. package/dist/components/select.js +1 -1
  178. package/dist/components/select.js.map +1 -1
  179. package/dist/components/separator.d.ts +9 -4
  180. package/dist/components/separator.js +1 -1
  181. package/dist/components/separator.js.map +1 -1
  182. package/dist/components/sidebar.d.ts +63 -18
  183. package/dist/components/sidebar.js +1 -1
  184. package/dist/components/sidebar.js.map +1 -1
  185. package/dist/components/simple-grid.d.ts +7 -0
  186. package/dist/components/simple-grid.js +1 -1
  187. package/dist/components/simple-grid.js.map +1 -1
  188. package/dist/components/skeleton.d.ts +4 -0
  189. package/dist/components/skeleton.js +1 -1
  190. package/dist/components/skeleton.js.map +1 -1
  191. package/dist/components/slider.d.ts +2 -2
  192. package/dist/components/slider.js +1 -1
  193. package/dist/components/slider.js.map +1 -1
  194. package/dist/components/sonner.js +1 -1
  195. package/dist/components/sonner.js.map +1 -1
  196. package/dist/components/spinner.d.ts +1 -1
  197. package/dist/components/spinner.js +1 -1
  198. package/dist/components/spinner.js.map +1 -1
  199. package/dist/components/stack.d.ts +1 -1
  200. package/dist/components/stack.js +1 -1
  201. package/dist/components/stack.js.map +1 -1
  202. package/dist/components/stepper.d.ts +46 -25
  203. package/dist/components/stepper.js +1 -1
  204. package/dist/components/stepper.js.map +1 -1
  205. package/dist/components/switch.d.ts +17 -3
  206. package/dist/components/switch.js +1 -1
  207. package/dist/components/switch.js.map +1 -1
  208. package/dist/components/table.d.ts +10 -1
  209. package/dist/components/table.js +1 -1
  210. package/dist/components/table.js.map +1 -1
  211. package/dist/components/tabs.d.ts +14 -10
  212. package/dist/components/tabs.js +1 -1
  213. package/dist/components/tabs.js.map +1 -1
  214. package/dist/components/text.d.ts +3 -5
  215. package/dist/components/text.js +1 -1
  216. package/dist/components/text.js.map +1 -1
  217. package/dist/components/textarea.d.ts +1 -1
  218. package/dist/components/textarea.js +1 -1
  219. package/dist/components/textarea.js.map +1 -1
  220. package/dist/components/theme.d.ts +12 -0
  221. package/dist/components/theme.js +1 -1
  222. package/dist/components/theme.js.map +1 -1
  223. package/dist/components/timeline.d.ts +25 -1
  224. package/dist/components/timeline.js +1 -1
  225. package/dist/components/timeline.js.map +1 -1
  226. package/dist/components/toggle-group.d.ts +16 -6
  227. package/dist/components/toggle-group.js +1 -1
  228. package/dist/components/toggle-group.js.map +1 -1
  229. package/dist/components/toggle.d.ts +4 -4
  230. package/dist/components/toggle.js +1 -1
  231. package/dist/components/toggle.js.map +1 -1
  232. package/dist/components/tooltip.d.ts +15 -8
  233. package/dist/components/tooltip.js +1 -1
  234. package/dist/components/tooltip.js.map +1 -1
  235. package/dist/components/unstyled-button.d.ts +3 -5
  236. package/dist/components/unstyled-button.js +1 -1
  237. package/dist/components/unstyled-button.js.map +1 -1
  238. package/dist/components/visibility.d.ts +2 -0
  239. package/dist/components/visibility.js +1 -1
  240. package/dist/components/visibility.js.map +1 -1
  241. package/dist/hooks/use-breakpoint-value.d.ts +1 -0
  242. package/dist/hooks/use-breakpoint-value.js.map +1 -1
  243. package/dist/hooks/use-breakpoint.d.ts +1 -0
  244. package/dist/hooks/use-breakpoint.js.map +1 -1
  245. package/dist/hooks/use-disclosure.d.ts +3 -0
  246. package/dist/hooks/use-disclosure.js +1 -1
  247. package/dist/hooks/use-disclosure.js.map +1 -1
  248. package/dist/hooks/use-document-visibility.d.ts +1 -0
  249. package/dist/hooks/use-document-visibility.js.map +1 -1
  250. package/dist/hooks/use-hotkeys.d.ts +1 -1
  251. package/dist/hooks/use-hotkeys.js +1 -1
  252. package/dist/hooks/use-idle.d.ts +9 -0
  253. package/dist/hooks/use-idle.js.map +1 -1
  254. package/dist/hooks/use-interval.d.ts +1 -0
  255. package/dist/hooks/use-interval.js.map +1 -1
  256. package/dist/hooks/use-local-storage.d.ts +6 -0
  257. package/dist/hooks/use-local-storage.js +1 -1
  258. package/dist/hooks/use-local-storage.js.map +1 -1
  259. package/dist/hooks/use-mask.d.ts +1 -0
  260. package/dist/hooks/use-mask.js.map +1 -1
  261. package/dist/hooks/use-mobile.d.ts +1 -0
  262. package/dist/hooks/use-mobile.js.map +1 -1
  263. package/dist/index.d.ts +9 -7
  264. package/dist/index.js +1 -1
  265. package/dist/lib/as-child.d.ts +2 -0
  266. package/dist/lib/as-child.js +2 -0
  267. package/dist/lib/as-child.js.map +1 -0
  268. package/dist/lib/badge.js.map +1 -1
  269. package/dist/lib/button.js.map +1 -1
  270. package/dist/lib/color.js.map +1 -1
  271. package/dist/lib/compose-refs.js +1 -1
  272. package/dist/lib/compose-refs.js.map +1 -1
  273. package/dist/lib/progress.js.map +1 -1
  274. package/dist/lib/utils.d.ts +1 -1
  275. package/dist/lib/utils.js.map +1 -1
  276. package/dist/logo--R3_XDgA.js +2 -0
  277. package/dist/logo--R3_XDgA.js.map +1 -0
  278. package/dist/postcss.config.js.map +1 -1
  279. package/dist/resolve-class-name-BurP8ngI.js +2 -0
  280. package/dist/resolve-class-name-BurP8ngI.js.map +1 -0
  281. package/dist/skills/uselets-ui/SKILL.md +9 -3
  282. package/dist/skills/uselets-ui/references/component-catalog.md +31 -16
  283. package/dist/skills/uselets-ui/references/migration-v1-to-v2.md +599 -0
  284. package/dist/skills/uselets-ui/references/package-guide.md +23 -7
  285. package/dist/styles/base.css +21 -0
  286. package/dist/{use-hotkeys-DOjcX9Tt.d.ts → use-hotkeys-D1_TEIwN.d.ts} +2 -1
  287. package/dist/use-hotkeys-YDJmGWX6.js.map +1 -1
  288. package/package.json +18 -19
  289. package/skills/uselets-ui/SKILL.md +9 -3
  290. package/skills/uselets-ui/references/component-catalog.md +31 -16
  291. package/skills/uselets-ui/references/migration-v1-to-v2.md +599 -0
  292. package/skills/uselets-ui/references/package-guide.md +23 -7
  293. package/dist/data-table-DWWVGWbU.d.ts +0 -4184
  294. package/dist/logo-B0thHtTS.js +0 -2
  295. package/dist/logo-B0thHtTS.js.map +0 -1
package/README.md CHANGED
@@ -4,8 +4,8 @@ React component library for the LET'S design system.
4
4
 
5
5
  ## Requirements
6
6
 
7
- - React `>=19`
8
- - React DOM `>=19`
7
+ - React `^19.2`
8
+ - React DOM `^19.2`
9
9
  - Tailwind CSS 4
10
10
 
11
11
  ## Installation
@@ -26,47 +26,32 @@ yarn add @uselets/ui
26
26
  bun add @uselets/ui
27
27
  ```
28
28
 
29
- ## Agent skill
29
+ ## Setup
30
30
 
31
- The package ships the `uselets-ui` agent skill for projects that want local guidance for setup, public
32
- imports, and the installed package API.
31
+ ### Automatic setup
33
32
 
34
- After installing `@uselets/ui`, run:
33
+ Run the setup command once after installing:
35
34
 
36
35
  ```bash
37
- bun uselets skill
36
+ bun uselets init
38
37
  ```
39
38
 
40
- The command reinstalls the skill for both Codex and Claude Code, replacing any older copy:
41
-
42
- - `.agents/skills/uselets-ui`
43
- - `.claude/skills/uselets-ui`
44
-
45
- To target only one agent, run `bun uselets skill --agent codex` or `bun uselets skill --agent claude`.
46
-
47
- ## Project setup
39
+ It installs the package dependencies, configures PostCSS, and prepares your global CSS file. It also:
48
40
 
49
- To install package dependencies, configure PostCSS, and prepare your global CSS file, run:
41
+ - asks which theme to import and where your global CSS lives (default: `src/styles/globals.css`);
42
+ - adds `import '@fontsource-variable/inter'` to your app entry file (`app/layout.tsx`, `pages/_app.tsx`,
43
+ `src/main.tsx`, `src/index.tsx`, or a `.jsx` variant), or asks for the path when none is found;
44
+ - optionally installs the [agent skill](#agent-skill).
50
45
 
51
- ```bash
52
- bun uselets init
53
- ```
54
-
55
- The command asks which theme to import, asks for your global CSS path with `src/styles/globals.css` as the
56
- default, and optionally installs the agent skill. It also imports the Inter font: it detects a conventional
57
- app entry file (`app/layout.tsx`, `pages/_app.tsx`, `src/main.tsx`, `src/index.tsx`, and `.jsx` variants) and
58
- inserts `import '@fontsource-variable/inter'` there, or asks for the entry file path when none is found. This
59
- avoids `@import '@fontsource-variable/inter'` in the global CSS, which some bundlers (including Next.js) don't
60
- resolve correctly for third-party CSS — import it as a JS module instead. For non-interactive setup, pass
61
- options:
46
+ For non-interactive setup, pass the options directly:
62
47
 
63
48
  ```bash
64
49
  bun uselets init --theme max --css src/styles/globals.css --entry app/layout.tsx --no-install-skill
65
50
  ```
66
51
 
67
- ## Tailwind CSS v4 setup
52
+ ### Manual setup (Tailwind CSS v4)
68
53
 
69
- If your app already uses Tailwind CSS v4, you can skip this section.
54
+ If your app already uses Tailwind CSS v4, start at step 3.
70
55
 
71
56
  1. Install Tailwind v4 and the PostCSS plugin:
72
57
 
@@ -81,42 +66,61 @@ npm install tailwindcss @tailwindcss/postcss
81
66
  export { default } from '@uselets/ui/postcss.config'
82
67
  ```
83
68
 
84
- 3. Import Tailwind and one package theme in your global stylesheet:
69
+ > **Using Vite?** You can use the Tailwind Vite plugin instead of PostCSS: install `tailwindcss @tailwindcss/vite`,
70
+ > skip `postcss.config.mjs`, and register the plugin. Prefer this setup when your project uses isolated installs
71
+ > (pnpm, or Bun workspaces): with PostCSS under Vite, the theme's Tailwind plugins may fail to resolve there.
72
+ >
73
+ > ```ts
74
+ > // vite.config.ts
75
+ > import tailwindcss from '@tailwindcss/vite'
76
+ > import { defineConfig } from 'vite'
77
+ >
78
+ > export default defineConfig({
79
+ > plugins: [tailwindcss()]
80
+ > })
81
+ > ```
82
+
83
+ 3. Import Tailwind, one package theme, and the package sources in your global stylesheet:
85
84
 
86
85
  ```css
87
86
  /* app.css */
88
87
  @import 'tailwindcss';
89
- @import '@uselets/ui/themes/max.css';
90
- ```
91
-
92
- Use `@uselets/ui/themes/gomax.css` instead for GoMax apps. If your app consumes `@uselets/ui` components, add a
93
- source directive so Tailwind can generate classes used by the package:
88
+ @import '@uselets/ui/themes/max.css'; /* or @uselets/ui/themes/gomax.css for GoMax apps */
94
89
 
95
- ```css
96
90
  @source '../node_modules/@uselets/ui/dist';
97
91
  ```
98
92
 
99
- 4. Import the Inter font once from your app's entry file (not from CSS — bundlers such as Next.js don't
100
- resolve third-party CSS `@import`s reliably):
93
+ The `@source` line lets Tailwind generate the classes used by the package components.
94
+
95
+ 4. Import the Inter font once from your app's entry file (not from CSS: bundlers such as Next.js don't resolve
96
+ third-party CSS `@import`s reliably):
101
97
 
102
98
  ```ts
103
99
  // app/layout.tsx (or src/main.tsx, pages/_app.tsx, ...)
104
100
  import '@fontsource-variable/inter'
105
101
  ```
106
102
 
107
- ## Quick start
103
+ ### Agent skill
108
104
 
109
- 1. Import Tailwind and one package theme once in your global stylesheet:
105
+ The package ships the `uselets-ui` agent skill, with local guidance on setup, public imports, and the installed
106
+ package API. Install it with:
110
107
 
111
- ```css
112
- @import 'tailwindcss';
113
- @import '@uselets/ui/themes/max.css';
108
+ ```bash
109
+ bun uselets skill
114
110
  ```
115
111
 
116
- For GoMax apps, import `@uselets/ui/themes/gomax.css` instead. Import the font once from your app's entry
117
- file, as shown above.
112
+ It (re)installs the skill for both Codex and Claude Code, replacing any older copy:
113
+
114
+ - `.agents/skills/uselets-ui`
115
+ - `.claude/skills/uselets-ui`
116
+
117
+ To target only one agent, run `bun uselets skill --agent codex` or `bun uselets skill --agent claude`.
118
118
 
119
- 2. Import components from the package root:
119
+ ## Usage
120
+
121
+ ### Imports
122
+
123
+ Import from the package root:
120
124
 
121
125
  ```tsx
122
126
  import { Alert, Button } from '@uselets/ui'
@@ -130,120 +134,66 @@ export function Example() {
130
134
  }
131
135
  ```
132
136
 
133
- 3. You can also import through subpaths:
137
+ Or through subpaths: components at `@uselets/ui/<component>`, hooks at `@uselets/ui/hooks/<hook>`:
134
138
 
135
139
  ```tsx
136
140
  import { Button } from '@uselets/ui/button'
137
- import { DataTable, DataTableColumnHeader, createDataTableSelectColumn } from '@uselets/ui/data-table'
138
- import { useBreakpointValue } from '@uselets/ui/hooks/use-breakpoint-value'
139
- import { useIsMobile } from '@uselets/ui/hooks/use-mobile'
141
+ import { DataTable } from '@uselets/ui/data-table'
140
142
  import { useDisclosure } from '@uselets/ui/hooks/use-disclosure'
141
- import { useLocalStorage } from '@uselets/ui/hooks/use-local-storage'
142
143
  import { randomId } from '@uselets/ui/utils'
143
144
  ```
144
145
 
145
- ### Data tables
146
-
147
- Use `DataTable` for client-side tables. The default render is intentionally bare — just a header and the empty
148
- state — and every additional feature is opt-in: `filterColumns`, `enableSorting`, `showPagination`,
149
- `showColumnVisibility`, `toolbarActions`, and `enableRowSelection`. When `enableRowSelection` is `true` the selection checkbox column
150
- is prepended automatically (use the exported `createDataTableSelectColumn` only when you need to place it
151
- elsewhere). `filterColumns` accepts a single column id (`"customer"`) or an array (`["customer", "email"]`);
152
- when there are two or more, a select rendered with `InputGroup` appears at the left of the input to pick the
153
- target column. `toolbarActions` always renders at the right of the toolbar, even without a filter. All
154
- user-facing labels default to Portuguese (pt-BR) and can be overridden through the `labels` prop.
155
-
156
- The underlying `Table` component renders only the `<table>` element (no auto wrapper) and is striped by default
157
- (pass `striped={false}` to disable). Use `variant` to control the outer chrome: `"line"` (default) renders only
158
- horizontal separators between rows; `"outline"` adds a rounded outer border. The outline chrome works in two
159
- modes: standalone (no `TableContainer`), the border lives on the `<table>` itself; wrapped in a `TableContainer`,
160
- the container detects the outline variant via `:has()`, applies the chrome on itself, and removes it from the
161
- `<table>` — this keeps the border sticky-safe (sticky headers can no longer paint over it) without changing
162
- the visible result. `DataTable` accepts the same `variant` prop and forwards it to its internal `Table`. Wrap `Table` in `TableContainer` to
163
- control horizontal scroll — use the `minWidth` prop (number in px or any CSS length) on `TableContainer` to
164
- force horizontal scroll when the parent is narrower. Combine `stickyHeader` on `Table` with `max-h` +
165
- `overflow-y-auto` on `TableContainer` (via `className` or `style`) to keep `<thead>` visible while the body
166
- scrolls vertically. `DataTable` already wraps its `Table` in a `TableContainer`.
146
+ Each module exports its composition parts and prop types from the same path.
167
147
 
168
- ```tsx
169
- import { type ColumnDef, DataTable, DataTableColumnHeader } from '@uselets/ui/data-table'
148
+ > Upgrading from v1? See the breaking changes in the [changelog](https://storybook.uselets.com/?path=/docs/intro-changelog-ui--docs).
170
149
 
171
- type Payment = {
172
- id: string
173
- customer: string
174
- amount: number
175
- }
176
-
177
- const columns: ColumnDef<Payment>[] = [
178
- {
179
- accessorKey: 'customer',
180
- header: ({ column }) => <DataTableColumnHeader column={column} title="Customer" />
181
- },
182
- {
183
- accessorKey: 'amount',
184
- header: ({ column }) => <DataTableColumnHeader column={column} title="Amount" />,
185
- cell: ({ row }) => new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(row.original.amount)
186
- }
187
- ]
188
-
189
- export function PaymentsTable({ payments }: { payments: Payment[] }) {
190
- return (
191
- <DataTable
192
- columns={columns}
193
- data={payments}
194
- getRowId={(row) => row.id}
195
- filterColumns={['customer', 'email']}
196
- enableRowSelection
197
- enableSorting
198
- showPagination
199
- variant="outline"
200
- labels={{
201
- filterPlaceholder: 'Buscar cliente…',
202
- pageOf: (current, total) => `${current} / ${total}`
203
- }}
204
- />
205
- )
206
- }
207
- ```
208
-
209
- Override any subset of `DataTableLabels`; remaining keys fall back to the pt-BR defaults exported as
210
- `defaultDataTableLabels`.
150
+ ### App providers
211
151
 
212
- #### Compound API and virtualization
152
+ Add these at the app root when you use the matching feature:
213
153
 
214
- `DataTable` also exposes a compound API for cases that need finer control — chiefly virtualization, but also
215
- custom layout (toolbar inside a card header, pagination in a footer slot) or sharing the `table` instance with
216
- code outside the table subtree. The high-level `DataTable` shown above is itself implemented in terms of these
217
- parts, so behavior never diverges.
154
+ | Provider | From | Needed for |
155
+ | --- | --- | --- |
156
+ | `ThemeProvider` (+ `ModeToggle`, `useTheme`) | `@uselets/ui/theme` | Light/dark/system theme ([docs][themeprovider]) |
157
+ | `TooltipProvider` | `@uselets/ui/tooltip` | Shared tooltip delays ([docs][tooltip]) |
158
+ | `Toaster` | `@uselets/ui/sonner` | Toasts via `toast()`; place it inside the `next-themes` `ThemeProvider` ([docs][toast]) |
159
+ | `DirectionProvider` (+ `useDirection`) | `@uselets/ui/direction` | Right-to-left apps: `<DirectionProvider direction="rtl">` (the `dir` attribute alone isn't enough) |
218
160
 
219
- Exports: `DataTableRoot`, `DataTableToolbar`, `DataTableHeader`, `DataTableBody`, `DataTablePagination`,
220
- `useDataTable`, `useDataTableContext`. `DataTableRoot` accepts either `{ columns, data, ...options }` or
221
- `{ table }` (instance created via `useDataTable`).
161
+ ## Theming
222
162
 
223
- For virtualization, `@uselets/ui` is intentionally **virtualizer-agnostic** — no runtime dependency on
224
- `@tanstack/react-virtual`, `react-window`, `virtua`, or any other library. Bring your own: instantiate it next
225
- to `useDataTable`, then render your virtual `<tbody>` in place of `<DataTableBody />`. Set
226
- `enablePagination: false` on `useDataTable` so `table.getRowModel()` returns the full filtered dataset.
163
+ | Theme | Import |
164
+ | --- | --- |
165
+ | Max | `@uselets/ui/themes/max.css` |
166
+ | GoMax | `@uselets/ui/themes/gomax.css` |
227
167
 
228
- A complete TanStack Virtual example lives in `apps/web/src/stories/data-table-virtualized.stories.tsx` and the
229
- recipe is documented in the `uselets-ui` skill (`packages/ui/skills/uselets-ui/references/package-guide.md`).
168
+ Preview both themes in [Foundations/Themes](https://storybook.uselets.com/?path=/docs/foundations-themes--docs).
230
169
 
231
- ## Theme tokens
170
+ ### Colors
232
171
 
233
- The package ships brand theme entrypoints:
172
+ Each family has a complete `50..950` scale (`bg-primary-500`, `--zinc-900`) and a semantic alias (`bg-green`,
173
+ `--red`) that maps to `500` in light mode and `400` in dark mode. The list is exported as `uiColors` / `UIColor`.
234
174
 
235
- - `@uselets/ui/themes/max.css`
236
- - `@uselets/ui/themes/gomax.css`
175
+ | Family | Reference (`500`) |
176
+ | --- | --- |
177
+ | `primary` | <span style="display:inline-block;width:1.25rem;height:1.25rem;border-radius:0.375rem;border:1px solid #d9d9d9;background:#ff5c35;"></span> |
178
+ | `brand` | <span style="display:inline-block;width:1.25rem;height:1.25rem;border-radius:0.375rem;border:1px solid #d9d9d9;background:#ff5c35;"></span> |
179
+ | `gray` | <span style="display:inline-block;width:1.25rem;height:1.25rem;border-radius:0.375rem;border:1px solid #d9d9d9;background:#99afc4;"></span> |
180
+ | `zinc` | <span style="display:inline-block;width:1.25rem;height:1.25rem;border-radius:0.375rem;border:1px solid #d9d9d9;background:#989898;"></span> |
181
+ | `red` | <span style="display:inline-block;width:1.25rem;height:1.25rem;border-radius:0.375rem;border:1px solid #d9d9d9;background:#e02535;"></span> |
182
+ | `yellow` | <span style="display:inline-block;width:1.25rem;height:1.25rem;border-radius:0.375rem;border:1px solid #d9d9d9;background:#ffa736;"></span> |
183
+ | `blue` | <span style="display:inline-block;width:1.25rem;height:1.25rem;border-radius:0.375rem;border:1px solid #d9d9d9;background:#408ec5;"></span> |
184
+ | `indigo` | <span style="display:inline-block;width:1.25rem;height:1.25rem;border-radius:0.375rem;border:1px solid #d9d9d9;background:#545ad4;"></span> |
185
+ | `pink` | <span style="display:inline-block;width:1.25rem;height:1.25rem;border-radius:0.375rem;border:1px solid #d9d9d9;background:#bd138b;"></span> |
186
+ | `green` | <span style="display:inline-block;width:1.25rem;height:1.25rem;border-radius:0.375rem;border:1px solid #d9d9d9;background:#52af4a;"></span> |
237
187
 
238
- Max and GoMax are maintained from their respective Figma style guides. The Storybook
239
- `Foundations/Themes` story reads the active stylesheet tokens, so it is the theme-backed
240
- palette preview for both theme entrypoints.
188
+ Prefer the semantic tokens over palette steps in application UI: `background`, `foreground`, `card`, `popover`,
189
+ `primary`, `secondary`, `accent`, `destructive`, `border`, `input`, `ring`, `placeholder`, `sidebar-*`, and
190
+ `chart-1..5`.
241
191
 
242
- ### Typography scale
192
+ ### Typography
243
193
 
244
- The Max theme overrides Tailwind CSS text size utilities from `text-xs` through `text-6xl` to match the
245
- Figma typography scale. Inter is the default sans-serif family, and each size uses a line height equal to
246
- `font-size * 1.5`.
194
+ The Max theme overrides `text-xs` through `text-6xl` to match the Figma scale. Inter is the default sans-serif
195
+ family, and every size has a line height of `font-size * 1.5`. See
196
+ [Foundations/Typography](https://storybook.uselets.com/?path=/docs/foundations-typography--docs).
247
197
 
248
198
  | Utility | Font size | Line height |
249
199
  | --- | --- | --- |
@@ -258,293 +208,240 @@ Figma typography scale. Inter is the default sans-serif family, and each size us
258
208
  | `text-5xl` | `3rem` / `48px` | `4.5rem` / `72px` |
259
209
  | `text-6xl` | `3.75rem` / `60px` | `5.625rem` / `90px` |
260
210
 
261
- ### Public palette families
262
-
263
- The palette follows the Tailwind and shadcn convention of complete `50..950` scales.
264
-
265
- - `primary`
266
- - `brand`
267
- - `gray`
268
- - `zinc`
269
- - `red`
270
- - `yellow`
271
- - `blue`
272
- - `indigo`
273
- - `pink`
274
- - `green`
275
-
276
- This same list is exported as `uiColors` and `UIColor` from `@uselets/ui` and `@uselets/ui/lib/color`.
277
- Color-aware components such as `Button`, `Toggle`, `Checkbox`, `RadioGroupItem`, and `Switch` use `UIColor` for their public `color` props.
278
- `ButtonColor` remains available as a compatibility alias for existing button consumers.
279
-
280
- Each family is exposed in four layers:
281
-
282
- - CSS variables such as `--primary-500`, `--brand-500` and `--zinc-900`
283
- - Semantic CSS aliases such as `--green`, `--red` and `--gray`, mapped to `500` in light mode and `400` in dark mode
284
- - Tailwind v4 theme utilities such as `bg-primary-500`, `text-zinc-900`, `border-red-300`
285
- - Tailwind v4 semantic utilities such as `bg-green`, `text-red` and `border-gray`
286
-
287
- Color-aware components use the semantic family aliases for their primary color so `color="green"` resolves to
288
- `--green-500` in light mode and `--green-400` in dark mode. Hover and subtle surfaces continue to use explicit
289
- palette steps.
290
-
291
- ### Palette preview
292
-
293
- | Family | Reference token | Preview |
294
- | --- | --- | --- |
295
- | `primary` | `primary-500` | <span style="display:inline-block;width:1.25rem;height:1.25rem;border-radius:0.375rem;border:1px solid #d9d9d9;background:#ff5c35;"></span> |
296
- | `brand` | `brand-500` | <span style="display:inline-block;width:1.25rem;height:1.25rem;border-radius:0.375rem;border:1px solid #d9d9d9;background:#ff5c35;"></span> |
297
- | `gray` | `gray-500` | <span style="display:inline-block;width:1.25rem;height:1.25rem;border-radius:0.375rem;border:1px solid #d9d9d9;background:#99afc4;"></span> |
298
- | `zinc` | `zinc-500` | <span style="display:inline-block;width:1.25rem;height:1.25rem;border-radius:0.375rem;border:1px solid #d9d9d9;background:#989898;"></span> |
299
- | `red` | `red-500` | <span style="display:inline-block;width:1.25rem;height:1.25rem;border-radius:0.375rem;border:1px solid #d9d9d9;background:#e02535;"></span> |
300
- | `yellow` | `yellow-500` | <span style="display:inline-block;width:1.25rem;height:1.25rem;border-radius:0.375rem;border:1px solid #d9d9d9;background:#ffa736;"></span> |
301
- | `blue` | `blue-500` | <span style="display:inline-block;width:1.25rem;height:1.25rem;border-radius:0.375rem;border:1px solid #d9d9d9;background:#408ec5;"></span> |
302
- | `indigo` | `indigo-500` | <span style="display:inline-block;width:1.25rem;height:1.25rem;border-radius:0.375rem;border:1px solid #d9d9d9;background:#545ad4;"></span> |
303
- | `pink` | `pink-500` | <span style="display:inline-block;width:1.25rem;height:1.25rem;border-radius:0.375rem;border:1px solid #d9d9d9;background:#bd138b;"></span> |
304
- | `green` | `green-500` | <span style="display:inline-block;width:1.25rem;height:1.25rem;border-radius:0.375rem;border:1px solid #d9d9d9;background:#52af4a;"></span> |
305
-
306
- ### Semantic tokens
307
-
308
- Use semantic tokens for application UI instead of hardcoding palette steps in components.
309
-
310
- - Surfaces and text: `background`, `foreground`, `card`, `popover`
311
- - Actions and emphasis: `primary`, `secondary`, `accent`, `destructive`
312
- - Supporting tokens: `border`, `input`, `ring`, `placeholder`
313
- - Sidebar tokens: `sidebar`, `sidebar-primary`, `sidebar-accent`, `sidebar-border`, `sidebar-ring`
314
- - Data viz tokens: `chart-1` to `chart-5`
315
- - Component-scoped tokens: `--logo-foreground` (used by the Intelitrack, Neutra, Kovra, and Fibonash logos' `color` tone so they stay legible in dark mode) and `--rd-logo-foreground` (used by the RD logo's wordmark for the same reason)
316
-
317
- The theme also exposes the shadcn foreground pair for destructive surfaces:
318
-
319
- - `--destructive-foreground`
320
- - `text-destructive-foreground`
321
-
322
- ### Gradient tokens
323
-
324
- The palette includes one named gradient token:
325
-
326
- - `--gradient-primary`
327
-
328
- This gradient is a documentation and styling primitive. It is not exposed as a Tailwind color family.
329
-
330
- ### Global scrollbar style
211
+ ### Scrollbar
331
212
 
332
- Importing either theme entrypoint applies a default page scrollbar style via the bundled
333
- [`tailwind-scrollbar`](https://github.com/adoxography/tailwind-scrollbar) plugin: thin width,
334
- transparent track, `muted` thumb with a `muted-foreground` hover state. The plugin's utilities
335
- (`scrollbar-thin`, `scrollbar-thumb-*`, `scrollbar-track-*`, `scrollbar-hover:*`) are available
336
- to override these defaults or to style internal scrollable regions. Firefox uses the standard
337
- `scrollbar-color` property and does not honor the pseudo-element hover variant — the thumb
338
- stays at the base color there.
213
+ Both themes style the page scrollbar; override it with the bundled
214
+ [`tailwind-scrollbar`](https://github.com/adoxography/tailwind-scrollbar) utilities.
339
215
 
340
216
  ## Components
341
217
 
342
- You can import from the package root (`@uselets/ui`) or by subpath (`@uselets/ui/<component>`).
343
-
344
- | Component | Exports | Key props / notes |
218
+ Every component has a [Storybook](https://storybook.uselets.com) page with live examples, variants, and props.
219
+
220
+ ### Conventions
221
+
222
+ - **`asChild`** renders the component as your own element. If that element isn't a `<button>`, also pass
223
+ `nativeButton={false}` on triggers and button-like parts:
224
+
225
+ ```tsx
226
+ <Button asChild>
227
+ <a href="/settings">Settings</a>
228
+ </Button>
229
+ ```
230
+
231
+ - **`color: UIColor`** accepts any palette family on `Button`, `Badge`, `Toggle`, `Checkbox`, `RadioGroup`,
232
+ `Switch`, `Progress`, `RingProgress`, and `Pagination`.
233
+ - **Sizes and spacing:** `size` usually goes from `sm` to `lg` (or `xs` to `xl`). Layout `gap` uses `xs`–`xl`
234
+ (`4/8/16/24/32px`).
235
+ - **Popups** unmount when closed (pass `keepMounted` to keep them), accept `side`/`align`/`sideOffset`/`alignOffset`,
236
+ and accept `sticky` to stay visible after the trigger scrolls away.
237
+ - **Forms:** wrap each control in a `Field` to wire its label, description, error, and invalid state.
238
+
239
+ ### Catalog
240
+
241
+ **Layout**
242
+
243
+ | Component | Description |
244
+ | --- | --- |
245
+ | [Flex][flex], [Stack][stack], [Group][group] | Flexbox layouts with `gap`, `align`, and `justify` |
246
+ | [Grid][grid], [SimpleGrid][simplegrid] | 12-column grid with `GridItem`; equal-column grid with `cols` |
247
+ | [Center][center], [Container][container] | Centering box; max-width page container |
248
+ | [Visibility][visibility] | `HiddenFrom` / `VisibleFrom` a breakpoint |
249
+ | [Card][card] | Content container with header, content, and footer parts |
250
+ | [Accordion][accordion], [Collapsible][collapsible] | Expandable sections (`multiple` to open several) |
251
+ | [Separator][separator], [Marker][marker] | Divider line; labeled divider or marker |
252
+ | [ScrollArea][scrollarea], [Resizable][resizable], [Carousel][carousel] | Custom scrollbars, resizable panels, slides |
253
+ | [Sidebar][sidebar] | App sidebar with `SidebarProvider`; collapsible to icons, optional `expandOnHover` |
254
+
255
+ **Typography**
256
+
257
+ | Component | Description |
258
+ | --- | --- |
259
+ | [Text][text], [Heading][heading] | Text and headings with `size` `xs`–`xl` |
260
+ | [Anchor][anchor] | Styled link with `underline` modes |
261
+ | [List][list] | Ordered/unordered list; `ListIcon` replaces the marker |
262
+ | [Code][code], [Kbd][kbd], [Label][label] | Inline code, keyboard keys, form label |
263
+
264
+ **Actions**
265
+
266
+ | Component | Description |
267
+ | --- | --- |
268
+ | [Button][button] | `variant`, `color`, `size` (including `icon-*` sizes), `loading` |
269
+ | [UnstyledButton][unstyledbutton] | Button with reset styles and a focus ring |
270
+ | [ButtonGroup][buttongroup] | Groups buttons together |
271
+ | [Toggle][toggle], [ToggleGroup][togglegroup] | Pressable toggles (`multiple` for several pressed) |
272
+
273
+ **Forms**
274
+
275
+ | Component | Description |
276
+ | --- | --- |
277
+ | [Field][field] | Label, description, error, and invalid state around a control |
278
+ | [Input][input], [Textarea][textarea], [InputGroup][inputgroup] | Text inputs; input with addons |
279
+ | [MaskInput][maskinput] | Formatted input (`_` digit, `#` letter, `*` any) |
280
+ | [PhoneInput][phoneinput] | International phone number (E.164), default country `BR` |
281
+ | [NumberField][numberfield] | Numeric stepper |
282
+ | [InputOTP][inputotp] | One-time code input |
283
+ | [Select][select], [NativeSelect][nativeselect] | Custom select (`items` maps values to labels); native `<select>` |
284
+ | [Combobox][combobox] | Searchable select, with chips for multiple values |
285
+ | [Checkbox][checkbox], [RadioGroup][radiogroup], [Switch][switch] | Choice controls with built-in `label` and `description` |
286
+ | [Slider][slider] | Single value or range |
287
+ | [Calendar][calendar], [DateRangePicker][daterangepicker] | Date calendar; range picker with presets and apply/reset |
288
+ | [Dropzone][dropzone] | File upload with validation and retries (`useDropzone`) |
289
+
290
+ **Overlays**
291
+
292
+ | Component | Description |
293
+ | --- | --- |
294
+ | [Dialog][dialog], [Drawer][drawer] | Modal and side panel with `size` and `dismissible`; `DialogBody`/`DrawerBody` scroll |
295
+ | [AlertDialog][alertdialog] | Confirmation dialog |
296
+ | [Popover][popover] | Floating panel; `PopoverClose` closes it |
297
+ | [Tooltip][tooltip] | `Tooltip label="…"` for the common case; needs `TooltipProvider` |
298
+ | [HoverCard][hovercard] | Preview card on hover |
299
+ | [DropdownMenu][dropdownmenu] | Action menu with checkbox, radio, and submenu items |
300
+ | [Command][command] | Command palette / searchable list |
301
+
302
+ **Navigation**
303
+
304
+ | Component | Description |
305
+ | --- | --- |
306
+ | [Tabs][tabs] | `line` or `enclosed` tabs; `grow` for equal widths |
307
+ | [NavigationMenu][navigationmenu] | Site navigation with dropdown panels |
308
+ | [Breadcrumb][breadcrumb], [Pagination][pagination] | Path trail; page links |
309
+ | [Stepper][stepper] | Multi-step progress navigation |
310
+ | [BottomNav][bottomnav] | Fixed mobile tab bar; you control when it shows and which item is active |
311
+
312
+ **Feedback**
313
+
314
+ | Component | Description |
315
+ | --- | --- |
316
+ | [Alert][alert] | Inline message (`default` or `destructive`) |
317
+ | [Toast][toast] | `Toaster` + `toast()` |
318
+ | [Progress][progress], [RingProgress][ringprogress] | Linear and circular progress (`value` 0–100) |
319
+ | [Spinner][spinner], [Skeleton][skeleton] | Loading indicator; loading placeholder |
320
+ | [Empty][empty] | Empty state |
321
+
322
+ **Data display**
323
+
324
+ | Component | Description |
325
+ | --- | --- |
326
+ | [Table][table] | Styled table; `TableContainer` for scroll, `stickyHeader` for a fixed header |
327
+ | [DataTable][datatable] | TanStack Table with opt-in filter, sorting, pagination, selection, and pt-BR labels ([virtualized][datatable-virtualized]) |
328
+ | [Badge][badge], [Avatar][avatar] | Status label; user image with fallback and groups |
329
+ | [Timeline][timeline] | Event list with status |
330
+ | [AreaChart][areachart], [BarChart][barchart], [PieChart][piechart], [DonutChart][donutchart] | Recharts-based charts colored with `colorKey` |
331
+ | [Logo][logo] | LetsDelivery product logos (`variant`, `tone`, `size`) |
332
+
333
+ ## Hooks
334
+
335
+ Exported from the package root and from `@uselets/ui/hooks/<name>`.
336
+
337
+ | Hook | What it does |
338
+ | --- | --- |
339
+ | [`useBreakpoint`][usebreakpoint] | Whether the viewport is at or above a Tailwind breakpoint |
340
+ | [`useBreakpointValue`][usebreakpointvalue] | Picks a value per breakpoint: `useBreakpointValue({ base: 1, md: 2 })` |
341
+ | [`useIsMobile`][useismobile] | Whether the viewport is below `768px` (`hooks/use-mobile`) |
342
+ | [`useDisclosure`][usedisclosure] | Open/close state |
343
+ | [`useLocalStorage`][uselocalstorage] | `useState` persisted in `localStorage`, synced across tabs |
344
+ | [`useHotkeys`][usehotkeys] | Keyboard shortcuts such as `'mod+k'` |
345
+ | [`useInterval`][useinterval] | Interval timer |
346
+ | [`useIdle`][useidle] | Whether the user is idle |
347
+ | [`useDocumentVisibility`][usedocumentvisibility] | The document visibility state |
348
+ | `useMask` | Input masking for custom inputs |
349
+
350
+ ## Utilities
351
+
352
+ | Export | Import | What it does |
345
353
  | --- | --- | --- |
346
- | `alert` | `Alert`, `AlertTitle`, `AlertDescription`, `AlertAction` | `Alert` supports `variant: 'default' \| 'destructive'` (default: `default`). |
347
- | `anchor` | `Anchor`, `anchorVariants` | Link primitive rendered as `<a>` with `size: 'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'`, `underline: 'always' \| 'hover' \| 'never' \| 'not-hover'` (default: `hover`), and `asChild`. |
348
- | `avatar` | `Avatar`, `AvatarImage`, `AvatarFallback`, `AvatarBadge`, `AvatarGroup`, `AvatarGroupCount` | `Avatar` supports `size: 'sm' \| 'md' \| 'lg'` (default: `md`). |
349
- | `badge` | `Badge`, `badgeVariants` | `size: 'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` (default: `md`); `variant: 'solid' \| 'secondary' \| 'outline' \| 'subtle'` (default: `solid`); `color: UIColor` (default: `primary`); `asChild?: boolean`. |
350
- | `button` | `Button`, `buttonVariants` | `variant: 'solid' \| 'secondary' \| 'outline' \| 'subtle' \| 'ghost' \| 'link'` (default: `solid`); `color: UIColor` (default: `primary`); `size: 'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'icon-xs' \| 'icon-sm' \| 'icon' \| 'icon-lg' \| 'icon-xl'`; `loading?: boolean`. |
351
- | `unstyled-button` | `UnstyledButton` | Button primitive with reset styles, pointer cursor, accessible focus ring, default `type="button"`, and `asChild`. |
352
- | `calendar` | `Calendar`, `CalendarDayButton` | Also exports the `DateRange` type. Weekends render with destructive text, week numbers are low-emphasis, and selected single/range endpoints use the `primary` palette with a subtle primary range fill. |
353
- | `date-range-picker` | `DateRangePicker`, `DateRangePickerTrigger`, `DateRangePickerValue`, `DateRangePickerContent`, `DateRangePickerPresets`, `DateRangePickerPreset`, `DateRangePickerCalendar`, `DateRangePickerDateFields`, `DateRangePickerActions`, `DateRangePickerApply`, `DateRangePickerReset` | Compound popover picker backed by `Calendar` range mode. Draft edits from fixed presets, relative-day inputs, date inputs, and calendar stay in sync until `Apply`; reset/clear emits `null` through `onValueChange`. |
354
- | `card` | `Card`, `CardHeader`, `CardTitle`, `CardDescription`, `CardAction`, `CardContent`, `CardFooter` | `Card` supports `size: 'sm' \| 'md' \| 'lg'` (default: `md`). |
355
- | `area-chart` / `bar-chart` / `pie-chart` / `donut-chart` | `AreaChart`, `BarChart`, `PieChart`, `DonutChart` (each with their series/datum types) | Recharts-backed charts with a mantine-shaped API. Each series/datum accepts `color` (raw CSS) or `colorKey: ChartColorKey` (`'primary' \| 'brand' \| 'gray' \| 'zinc' \| 'red' \| 'yellow' \| 'green' \| 'blue' \| 'indigo' \| 'pink'`) which resolves to `var(--{key}-500)`. Series/datum `name` is free-form and may contain spaces or non-ASCII characters. `BarChart` also accepts `color` / `colorKey` on each `data` row (`BarChartDatum`); when set, the row color wins over the series color and applies to every bar in that row. Pass `areaProps` / `barProps` / `pieProps` to forward props (e.g. `onClick`, `cursor`) to the underlying recharts series primitive (`<Area>` / `<Bar>` / `<Pie>`); pass `areaChartProps` / `barChartProps` to forward props (e.g. `margin`, `barCategoryGap`, `onClick`) to the wrapping recharts `<AreaChart>` / `<BarChart>`. `PieChart` / `DonutChart` add `strokeColor` (default: `var(--background)`) alongside `strokeWidth` so the segment gaps are now visible by default. Re-exports `ChartColorKey`, `CHART_COLOR_KEYS`, `DEFAULT_CHART_PALETTE`, and `resolveChartColor` from `@uselets/ui/chart` for custom compositions. |
356
- | `checkbox` | `Checkbox` | `Checkbox` supports `size: 'sm' \| 'md' \| 'lg'` (default: `md`), `color: UIColor` (default: `primary`), `label?: React.ReactNode`, and `labelProps` for the composed `Label`. When `label` is provided without `id`, it generates an id and wires `htmlFor` automatically. Label text follows checkbox size: `sm` 12px, `md` 14px, `lg` 20px. |
357
- | `code` | `Code` | Inline code primitive rendered as `<code>`. |
358
- | `combobox` | `Combobox`, `ComboboxInput`, `ComboboxContent`, `ComboboxList`, `ComboboxItem`, `ComboboxGroup`, `ComboboxLabel`, `ComboboxCollection`, `ComboboxClear`, `ComboboxEmpty`, `ComboboxSeparator`, `ComboboxChips`, `ComboboxChip`, `ComboboxChipsInput`, `ComboboxTrigger`, `ComboboxValue`, `useComboboxAnchor` | `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. |
359
- | `dialog` | `Dialog`, `DialogTrigger`, `DialogPortal`, `DialogClose`, `DialogOverlay`, `DialogContent`, `DialogHeader`, `DialogBody`, `DialogFooter`, `DialogTitle`, `DialogDescription` | `Dialog` supports `size: 'sm' \| 'md' \| 'lg' \| 'xl' \| '2xl' \| '3xl' \| 'full'` (default: `md`); `full` occupies the entire viewport. `DialogContent` caps its height at `calc(100dvh - 2rem)` and arranges children as a flex column; wrap long content in `DialogBody` (`flex-1 overflow-y-auto`) so the body scrolls while `DialogHeader` and `DialogFooter` stay pinned. `DialogContent.showCloseButton` (default: `true`); `DialogFooter.showCloseButton` (default: `false`). `Dialog.dismissible` (default: `true`); when `false`, clicking outside and pressing Esc no longer close the dialog (the close button and `DialogClose` still work). `DialogOverlay` and `DialogContent` stop `click`/`submit` events from bubbling to ancestor elements, since Radix portals move them elsewhere in the DOM but React still propagates their synthetic events through the component tree. |
360
- | `drawer` | `Drawer`, `DrawerTrigger`, `DrawerPortal`, `DrawerClose`, `DrawerOverlay`, `DrawerContent`, `DrawerHeader`, `DrawerBody`, `DrawerFooter`, `DrawerTitle`, `DrawerDescription` | `Drawer` supports `size: 'sm' \| 'md' \| 'lg' \| 'xl' \| '2xl' \| '3xl' \| 'full'` (default: `md`); `DrawerBody` provides padded auto-scroll content; `DrawerFooter` stacks actions on mobile and aligns them to the end on larger breakpoints; `DrawerContent.showCloseButton` (default: `true`). `Drawer.dismissible` (default: `true`); when `false`, clicking outside and pressing Esc no longer close the drawer (the close button and `DrawerClose` still work). `Drawer.direction: 'top' \| 'right' \| 'bottom' \| 'left'` (default: `right`) controls which edge the drawer slides in from. `DrawerOverlay` and `DrawerContent` stop `click`/`submit` events from bubbling to ancestor elements, since Radix portals move them elsewhere in the DOM but React still propagates their synthetic events through the component tree. |
361
- | `dropzone` | `Dropzone`, `DropzoneArea`, `DropzoneDescription`, `DropzoneFileList`, `DropzoneFileListItem`, `DropzoneFileMessage`, `DropzoneMessage`, `DropzoneRemoveFile`, `DropzoneRetryFile`, `DropzoneTrigger`, `InfiniteProgress`, `useDropzone` | `useDropzone` manages upload lifecycle, validation (`accept`, `minSize`, `maxSize`, `maxFiles`), retry handling, and optional `shiftOnMaxFiles` replacement. Compose the returned state with `Dropzone` and its subcomponents. |
362
- | `dropdown-menu` | `DropdownMenu`, `DropdownMenuTrigger`, `DropdownMenuContent`, `DropdownMenuItem`, `DropdownMenuCheckboxItem`, `DropdownMenuRadioGroup`, `DropdownMenuRadioItem`, `DropdownMenuSub`, `DropdownMenuSubTrigger`, `DropdownMenuSubContent`, `DropdownMenuSeparator`, `DropdownMenuShortcut` | `DropdownMenuContent` supports `side`, `sideOffset`, `align`, `alignOffset`; items support `inset`, and `DropdownMenuItem` supports `variant: 'default' \| 'destructive'`. |
363
- | `empty` | `Empty`, `EmptyHeader`, `EmptyMedia`, `EmptyTitle`, `EmptyDescription`, `EmptyContent` | `EmptyMedia` supports `variant: 'default' \| 'icon'` (default: `default`). |
364
- | `field` | `FieldSet`, `FieldLegend`, `FieldGroup`, `Field`, `FieldContent`, `FieldLabel`, `FieldTitle`, `FieldDescription`, `FieldSeparator`, `FieldError`, `useFieldControlId` | `Field.orientation: 'vertical' \| 'horizontal' \| 'responsive'` (default: `vertical`); `FieldLegend.variant: 'legend' \| 'label'`; `FieldError.errors` accepts an array of error objects. When a labelable control is rendered inside `Field` without an explicit `id`, `Field` provides a generated id and `FieldLabel` uses it automatically. |
365
- | `flex` | `Flex`, `flexVariants` | Flexbox layout primitive with `direction: 'row' \| 'row-reverse' \| 'column' \| 'column-reverse'` (default: `row`), `align: 'start' \| 'end' \| 'center' \| 'baseline' \| 'stretch'`, `justify: 'start' \| 'end' \| 'center' \| 'between' \| 'around' \| 'evenly'`, `wrap?: boolean`, and `gap: 'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` (`4/8/16/24/32px`). |
366
- | `grid` | `Grid`, `GridItem` | `Grid` is a 12-column CSS grid by default and supports `gap`, `rowGap`, `columnGap`, `templateRows`, and `templateColumns`; spacing uses the `xs` to `xl` scale (`4/8/16/24/32px`). `GridItem` defaults to `colSpan={12}` and supports numeric `colSpan` and `rowSpan`; use `useBreakpointValue` when spans or templates need responsive values. |
367
- | `heading` | `Heading`, `headingVariants` | Heading primitive with `size: 'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` (default: `md`) and `asChild`. |
368
- | `input` | `Input` | Wrapper for Base UI Input with all native `<input>` props. |
369
- | `input-otp` | `InputOTP`, `InputOTPGroup`, `InputOTPSlot`, `InputOTPSeparator`, `REGEXP_ONLY_CHARS`, `REGEXP_ONLY_DIGITS`, `REGEXP_ONLY_DIGITS_AND_CHARS` | `InputOTP` supports all `input-otp` props plus `containerClassName`; use `maxLength` and `pattern` for validation. |
370
- | `number-field` | `NumberField`, `NumberFieldGroup`, `NumberFieldDecrement`, `NumberFieldIncrement`, `NumberFieldInput`, `NumberFieldScrubArea` | Base UI-backed numeric stepper input. `size: 'sm' \| 'md' \| 'lg'` (default: `md`); supports `min`, `max`, `step`, and other Base UI `NumberField.Root` props. `NumberFieldScrubArea` renders a draggable `label` (required) that scrubs the value on pointer drag. |
371
- | `phone-input` | `PhoneInput` | International phone input built on `react-phone-number-input`, composed from the existing `Input` and `Combobox` (country select), matching `Input`'s styling and single size. `value` / `onChange` use the E.164 `Value` string; `defaultCountry` defaults to `BR`. |
372
- | `mask-input` | `MaskInput` | Formatted input backed by `@react-input/mask`. Accepts `mask` plus optional `replacement`, `showMask`, `separate`, `track`, `modify`. Default replacement tokens: `_` (digit), `#` (letter), `*` (any) — chosen so the token character is never a value the user actually types. When no custom `replacement` is passed, `mask` strings written with the older `9`/`a` tokens are automatically translated to `_`/`#`, so existing masks keep working. Forwards an external `ref` prop to the underlying `<input>`, composed with the mask ref. The `useMask` hook is also exported from `@uselets/ui/hooks/use-mask` for custom inputs. |
373
- | `kbd` | `Kbd`, `KbdGroup` | Keyboard shortcut presentation primitives. |
374
- | `label` | `Label` | Styled `<label>` wrapper. |
375
- | `marker` | `Marker`, `MarkerContent`, `MarkerIcon`, `markerVariants` | `variant: 'default' \| 'separator' \| 'border'` (default: `default`); `asChild?: boolean`. `separator` renders divider lines on both sides of the content (for labeled dividers); `border` renders a bottom border instead. |
376
- | `list` | `List`, `ListItem`, `ListIcon`, `listVariants` | `List.type: 'unordered' \| 'ordered'`; `size` and `spacing` use the `xs` to `xl` scale; `ListIcon` can use `asChild` and replaces the default marker with a primary-colored icon. |
377
- | `logo` | `MaxLogo`, `GomaxLogo`, `BippiLogo`, `IntelitrackLogo`, `KovraLogo`, `NeutraLogo`, `RdLogo`, `FibonashLogo`, `LetsLogo` | One component per LetsDelivery product brand. `variant: 'icon' \| 'full'` (default: `full`; `LetsLogo` has no `variant`, it only renders `full`). `tone: 'color' \| 'mono'` (default: `color`); `GomaxLogo` and `BippiLogo` additionally accept `tone: 'reversed'` (their alternate white lockup with an orange accent, for dark/colored backgrounds). `color?: string` recolors `mono`/`reversed` tones (default: white); `size: 'sm' \| 'md' \| 'lg' \| number` (default: `md`) sets height, width follows each product's own aspect ratio; pass a `number` for an exact pixel height instead of a preset. |
378
- | `native-select` | `NativeSelect`, `NativeSelectOption`, `NativeSelectOptGroup` | Native `<select>` API with `size: 'sm' \| 'md'` (default: `md`). |
379
- | `popover` | `Popover`, `PopoverTrigger`, `PopoverContent`, `PopoverAnchor`, `PopoverHeader`, `PopoverTitle`, `PopoverDescription` | `PopoverContent` supports positioning props (`side`, `sideOffset`, `align`, `alignOffset`) and can be used in controlled mode via root props (`open`, `onOpenChange`). |
380
- | `progress` | `Progress`, `progressVariants` | Linear progress bar driven by a single `value` (0–100). Supports `size: 'sm' \| 'md' \| 'lg'` (default: `md`; bar heights `2/4/6px`) and `color: UIColor` (default: `primary`). |
381
- | `ring-progress` | `RingProgress`, `ringProgressVariants` | Circular progress indicator driven by a single `value` (0–100). Supports `size: 'sm' \| 'md' \| 'lg'` (default: `md`; `32/40/48px`), `thickness: 'thin' \| 'md' \| 'thick'` (default: `md`), and `color: UIColor` (default: `primary`). Uses a normalized `viewBox`, so the rendered size can also be overridden via `className` (e.g. `className="size-5"`). Rounded line caps. |
382
- | `radio-group` | `RadioGroup`, `RadioGroupItem` | `RadioGroup` supports `color: UIColor` (default: `primary`) for the group. `RadioGroupItem` supports `size: 'sm' \| 'md' \| 'lg'` (default: `md`), optional `color: UIColor` item overrides, `label?: React.ReactNode`, and `labelProps` for the composed `Label`. When `label` is provided without `id`, it generates an id and wires `htmlFor` automatically. Label text follows item size: `sm` 12px, `md` 14px, `lg` 20px. |
383
- | `select` | `Select`, `SelectTrigger`, `SelectValue`, `SelectContent`, `SelectGroup`, `SelectItem`, `SelectLabel`, `SelectSeparator`, `SelectScrollUpButton`, `SelectScrollDownButton` | `SelectTrigger.size: 'sm' \| 'md'`; `SelectContent` supports positioning props (`side`, `sideOffset`, `align`, `alignOffset`, `alignItemWithTrigger`). |
384
- | `separator` | `Separator` | `orientation: 'horizontal' \| 'vertical'` (default: `horizontal`). |
385
- | `simple-grid` | `SimpleGrid` | Simple grid with `cols`, `gap`, `rowGap`, and `columnGap`. `cols` accepts a number; spacing uses the `xs` to `xl` scale (`4/8/16/24/32px`). Use `useBreakpointValue` when column count needs responsive values. |
386
- | `skeleton` | `Skeleton` | Generic loading placeholder block. Supports `visible?: boolean` (default: `true`) and can wrap `children` to reserve their size while the placeholder is shown. |
387
- | `spinner` | `Spinner` | Loader icon (`role="status"`), accepts SVG props and supports `size: 'sm' \| 'md' \| 'lg'` (default: `md`). |
388
- | `switch` | `Switch` | `Switch` supports `size: 'sm' \| 'md' \| 'lg'` (default: `md`), `color: UIColor` (default: `green`), `label?: React.ReactNode`, and `labelProps` for the composed `Label`. When `label` is provided without `id`, it generates an id and wires `htmlFor` automatically. Track size is `sm` 34x16px, `md` 42x20px, and `lg` 48x22px; the thumb and internal indicator scale with the switch. Label text follows switch size: `sm` 14px, `md` 16px, `lg` 18px. |
389
- | `stepper` | `Stepper`, `StepperNav`, `StepperItem`, `StepperTrigger`, `StepperIndicator`, `StepperSeparator`, `StepperTitle`, `StepperDescription`, `StepperPanel`, `StepperContent`, `useStepper`, `useStepItem` | Multi-step progress navigation. `Stepper.orientation: 'horizontal' \| 'vertical'` (default: `horizontal`); supports controlled (`value` / `onValueChange`) and uncontrolled (`defaultValue`) active step, plus custom per-state `indicators` (`active`, `completed`, `inactive`, `loading`). `StepperItem` accepts `completed`, `disabled`, and `loading`. Arrow-key and Home/End keyboard navigation between triggers is built in. |
390
- | `tabs` | `Tabs`, `TabsContent`, `TabsList`, `TabsTrigger`, `tabsListVariants` | `TabsList.variant: 'line' \| 'enclosed'` (default: `line`); `TabsList.grow?: boolean` makes horizontal tabs share the available width equally; `line` uses a neutral border line with a `primary` active indicator. |
391
- | `text` | `Text`, `textVariants` | Text primitive with `size: 'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` (default: `md`) and `asChild`. |
392
- | `timeline` | `Timeline`, `TimelineItem`, `TimelineConnector`, `TimelineContent`, `TimelineDescription`, `TimelineEmpty`, `TimelineHeader`, `TimelineIcon`, `TimelineTime`, `TimelineTitle`, `timelineVariants` | `Timeline.size: 'sm' \| 'md' \| 'lg'` (default: `md`); `Timeline.iconSize: 'sm' \| 'md' \| 'lg'`; `TimelineItem.status: 'completed' \| 'in-progress' \| 'pending'`; icon and connector colors use the semantic palette (`primary`, `secondary`, `muted`, `accent`, `destructive`). |
393
- | `tooltip` | `TooltipProvider`, `Tooltip`, `TooltipRoot`, `TooltipTrigger`, `TooltipContent` | `Tooltip` composes a trigger and label for common usage and supports `disabled`; `TooltipRoot` is the low-level root for manual composition; `TooltipContent` supports positioning props like `side`, `align`, and `sideOffset`. |
394
- | `visibility` | `HiddenFrom`, `VisibleFrom` | Breakpoint visibility helpers. `HiddenFrom breakpoint="md"` hides at `md` and above; `VisibleFrom breakpoint="md"` shows at `md` and above. |
395
- | `sonner` | `Toaster`, `toast` | Toaster wrapper around Sonner with theme integration from `next-themes` and custom icons. |
396
-
397
- ### Additional components
398
-
399
- The package also exports the following modules through the root entrypoint and subpaths:
400
-
401
- - Layout and disclosure: `Accordion`, `Carousel`, `Center`, `Collapsible`, `Container`, `Flex`, `Group`, `Resizable`, `ScrollArea`, `Sidebar`, `Stack`, `Tabs`
402
- - Inputs and selection: `Calendar`, `DateRangePicker`, `InputGroup`, `RadioGroup`, `Slider`, `Switch`, `Textarea`, `Toggle`, `ToggleGroup`
403
- - Navigation and feedback: `AlertDialog`, `BottomNav`, `Breadcrumb`, `NavigationMenu`, `Pagination`, `Progress`
404
- - Data display and utilities: `Badge`, `ButtonGroup`, `Chart`, `Command`, `HoverCard`, `Table`, `ThemeProvider`, `useTheme`, `ModeToggle`
405
-
406
- Each module exports its public composition parts and prop types from the same import path, for example `@uselets/ui/accordion` or `@uselets/ui`. `Carousel` includes the composed `CarouselIndicators` subcomponent for opt-in slide indicators.
407
-
408
- Layout primitives follow the same pattern: `Stack`, `Group`, and `Flex` support `gap: 'xs' | 'sm' | 'md' | 'lg' | 'xl'`, mapping to `4/8/16/24/32px`, plus typed `align: 'start' | 'end' | 'center' | 'baseline' | 'stretch'` and `justify: 'start' | 'end' | 'center' | 'between' | 'around' | 'evenly'` props; `Group` also supports `wrap` (and defaults `align` to `center`); `Flex` additionally supports typed `direction` and `wrap`; `Center` supports `size: 'xs' | 'sm' | 'md' | 'lg' | 'xl'` and `direction: 'horizontal' | 'vertical'`; and `Container` supports `size: 'sm' | 'md' | 'lg' | 'full'`. `SimpleGrid`, `Grid`, and `GridItem` accept direct layout values; use `useBreakpointValue` to derive responsive values when needed. `HiddenFrom` and `VisibleFrom` provide breakpoint-based visibility wrappers.
409
-
410
- `Pagination` highlights the current page and keeps the other links neutral. Its `color` prop (`UIColor`, default `primary`) controls only the current page's color. `PaginationLink`/`PaginationPrevious`/`PaginationNext` also accept `color` individually, but the value set on `Pagination` wins whenever it's provided.
411
-
412
- `BottomNav`/`BottomNavItem` render a fixed, safe-area-aware mobile tab bar (`env(safe-area-inset-bottom)` via the `--spacing-safe-bottom` token). The component has no built-in responsive/breakpoint logic — consumers decide when it's shown (e.g. wrapping it in `md:hidden`). `BottomNavItem` accepts `asChild` to render a routing library's link, and its active state is fully external via `isActive` (mirrored onto `data-active`/`aria-current="page"`) — there's no internal state, context, or navigation logic.
413
-
414
- Public hooks are exported from the package root and from the `@uselets/ui/hooks/*` namespace:
415
-
416
- - `useBreakpoint` from `@uselets/ui/hooks/use-breakpoint`
417
- - `useBreakpointValue` from `@uselets/ui/hooks/use-breakpoint-value`
418
- - `useDisclosure` from `@uselets/ui/hooks/use-disclosure`
419
- - `useInterval` from `@uselets/ui/hooks/use-interval`
420
- - `useIdle` from `@uselets/ui/hooks/use-idle`
421
- - `useDocumentVisibility` from `@uselets/ui/hooks/use-document-visibility`
422
- - `useHotkeys` from `@uselets/ui/hooks/use-hotkeys`
423
- - `useLocalStorage` from `@uselets/ui/hooks/use-local-storage`
424
- - `useMask` from `@uselets/ui/hooks/use-mask`
425
- - `useIsMobile` from `@uselets/ui/hooks/use-mobile`
426
-
427
- Legacy hook subpaths such as `@uselets/ui/use-mobile` are not public entrypoints.
428
-
429
- `useBreakpoint` checks Tailwind's default breakpoints (`base`, `sm`, `md`, `lg`, `xl`, `2xl`) and returns whether the current viewport is at or above the requested breakpoint. `useBreakpointValue` accepts a breakpoint map and returns the largest active value:
430
-
431
- ```tsx
432
- const cols = useBreakpointValue({ base: 1, md: 2, lg: 3 }) ?? 1
433
-
434
- return <SimpleGrid cols={cols} gap="md" />
435
- ```
436
-
437
- `useLocalStorage` returns a tuple like `useState`, persists values as JSON, and syncs changes between browser tabs and between other instances using the same key in the same tab by default:
438
-
439
- ```tsx
440
- const [settings, setSettings] = useLocalStorage('settings', {
441
- defaultValue: { compact: false }
442
- })
443
-
444
- const [draft, setDraft] = useLocalStorage('draft', {
445
- defaultValue: '',
446
- sync: false
447
- })
448
- ```
449
-
450
- `useHotkeys` registers global keyboard shortcuts on the document. Each item is a tuple `[hotkey, handler, options?]`, where `hotkey` is a string like `'mod+k'` (`mod` matches `ctrl` on Windows/Linux and `meta` on macOS). Events fired from `INPUT`, `TEXTAREA`, and `SELECT` are ignored by default (configurable via the `tagsToIgnore` and `triggerOnContentEditable` arguments), and `options` accepts `preventDefault` (default `true`) and `usePhysicalKeys`. The `getHotkeyHandler` helper is also exported for binding shortcuts to a single element instead of the document:
451
-
452
- ```tsx
453
- useHotkeys([
454
- ['mod+k', () => openCommandPalette()],
455
- ['escape', () => close(), { preventDefault: false }]
456
- ])
457
-
458
- // or scoped to one element
459
- <input onKeyDown={getHotkeyHandler([['mod+enter', submit]])} />
460
- ```
461
-
462
- Utilities are exported from the package root and `@uselets/ui/utils`, including `cn` and `randomId`. The package also exports `composeRefs` (and `setRef`) from `@uselets/ui/lib/compose-refs` for composing multiple refs into a single callback ref — handy when a component needs to merge a forwarded `ref` with an internal one (for example `MaskInput`).
463
-
464
- `ThemeProvider` stores the active `Theme` (`'dark' | 'light' | 'system'`) in `localStorage` under `storageKey` (default `'vite-ui-theme'`) and toggles the `dark`/`light` class on `document.documentElement`. Pass `defaultTheme` to set the initial theme when none is stored yet, and `disableTransitionOnChange` to suppress CSS transitions for the moment the class swaps, matching `next-themes`'s prop of the same name:
465
-
466
- ```tsx
467
- import { ModeToggle, ThemeProvider } from '@uselets/ui/theme'
468
-
469
- export function AppRoot({ children }: { children: React.ReactNode }) {
470
- return (
471
- <ThemeProvider defaultTheme="system" disableTransitionOnChange>
472
- <ModeToggle />
473
- {children}
474
- </ThemeProvider>
475
- )
476
- }
477
- ```
478
-
479
- ### Sonner example
480
-
481
- ```tsx
482
- import { ThemeProvider } from 'next-themes'
483
- import { Toaster, toast } from '@uselets/ui/sonner'
484
-
485
- export function App() {
486
- return (
487
- <ThemeProvider attribute="class" defaultTheme="system" enableSystem>
488
- <button onClick={() => toast.success('Saved')}>Notify</button>
489
- <Toaster />
490
- </ThemeProvider>
491
- )
492
- }
493
- ```
494
-
495
- ## Tooltip setup
496
-
497
- For consistent tooltip behavior across the app, wrap your application root with `TooltipProvider`.
498
-
499
- ```tsx
500
- import { Tooltip, TooltipProvider } from '@uselets/ui/tooltip'
501
-
502
- export function AppRoot() {
503
- return <TooltipProvider delayDuration={200}>{/* app */}</TooltipProvider>
504
- }
505
-
506
- export function SaveButton() {
507
- return (
508
- <Tooltip label="Salva as alterações" side="bottom">
509
- <button type="button">Salvar</button>
510
- </Tooltip>
511
- )
512
- }
513
- ```
514
-
515
- ## Sidebar setup
516
-
517
- `SidebarProvider` owns the sidebar's open/collapsed state; `Sidebar` renders the structure and
518
- accepts `collapsible: 'offcanvas' | 'icon' | 'none'`. Set `expandOnHover` on `SidebarProvider` to let
519
- a `collapsible="icon"` sidebar reveal a floating preview (an overlay, not a layout push) on pointer
520
- hover or keyboard focus while collapsed. During that preview, clicking `SidebarRail` pins the sidebar
521
- open, while clicking `SidebarTrigger` closes the preview. Once a toggle collapses the sidebar, the
522
- preview stays closed until the pointer leaves the sidebar (or keyboard focus moves into it), so it
523
- doesn't reopen under a cursor that is still over it. `useSidebar()` exposes `isHoverExpanded`
524
- for components that need to react to the preview themselves. The preview's open/close debounce
525
- defaults to 150ms/300ms and can be tuned per app via `hoverExpandOpenDelay`/`hoverExpandCloseDelay`.
526
-
527
- ```tsx
528
- import { Sidebar, SidebarContent, SidebarProvider, SidebarRail, SidebarTrigger } from '@uselets/ui/sidebar'
529
-
530
- export function AppShell({ children }: { children: React.ReactNode }) {
531
- return (
532
- <SidebarProvider expandOnHover>
533
- <Sidebar collapsible="icon">
534
- <SidebarContent>{/* menu */}</SidebarContent>
535
- <SidebarRail />
536
- </Sidebar>
537
- <SidebarTrigger />
538
- {children}
539
- </SidebarProvider>
540
- )
541
- }
542
- ```
543
-
544
- To use your own element as the trigger, pass `asChild` — it still toggles the sidebar, no `onClick` needed:
545
-
546
- ```tsx
547
- <SidebarTrigger asChild>
548
- <Button variant="ghost">Menu</Button>
549
- </SidebarTrigger>
550
- ```
354
+ | `cn` | `@uselets/ui/utils` | Merges class names |
355
+ | `randomId` | `@uselets/ui/utils` | Generates a random id |
356
+ | `composeRefs`, `setRef` | `@uselets/ui/lib/compose-refs` | Combine several refs into one callback ref |
357
+ | `uiColors`, `UIColor` | `@uselets/ui/lib/color` | Palette family names |
358
+
359
+ [accordion]: https://storybook.uselets.com/?path=/docs/components-layout-accordion--docs
360
+ [alert]: https://storybook.uselets.com/?path=/docs/components-feedback-alert--docs
361
+ [alertdialog]: https://storybook.uselets.com/?path=/docs/components-overlay-alertdialog--docs
362
+ [anchor]: https://storybook.uselets.com/?path=/docs/components-typography-anchor--docs
363
+ [areachart]: https://storybook.uselets.com/?path=/docs/components-charts-areachart--docs
364
+ [avatar]: https://storybook.uselets.com/?path=/docs/components-data-display-avatar--docs
365
+ [badge]: https://storybook.uselets.com/?path=/docs/components-data-display-badge--docs
366
+ [barchart]: https://storybook.uselets.com/?path=/docs/components-charts-barchart--docs
367
+ [bottomnav]: https://storybook.uselets.com/?path=/docs/components-navigation-bottomnav--docs
368
+ [breadcrumb]: https://storybook.uselets.com/?path=/docs/components-navigation-breadcrumb--docs
369
+ [button]: https://storybook.uselets.com/?path=/docs/components-button-button--docs
370
+ [buttongroup]: https://storybook.uselets.com/?path=/docs/components-button-buttongroup--docs
371
+ [calendar]: https://storybook.uselets.com/?path=/docs/components-forms-calendar--docs
372
+ [card]: https://storybook.uselets.com/?path=/docs/components-data-display-card--docs
373
+ [carousel]: https://storybook.uselets.com/?path=/docs/components-layout-carousel--docs
374
+ [center]: https://storybook.uselets.com/?path=/docs/components-layout-center--docs
375
+ [checkbox]: https://storybook.uselets.com/?path=/docs/components-forms-checkbox--docs
376
+ [code]: https://storybook.uselets.com/?path=/docs/components-typography-code--docs
377
+ [collapsible]: https://storybook.uselets.com/?path=/docs/components-layout-collapsible--docs
378
+ [combobox]: https://storybook.uselets.com/?path=/docs/components-forms-combobox--docs
379
+ [command]: https://storybook.uselets.com/?path=/docs/components-overlay-command--docs
380
+ [container]: https://storybook.uselets.com/?path=/docs/components-layout-container--docs
381
+ [datatable]: https://storybook.uselets.com/?path=/docs/components-data-display-datatable--docs
382
+ [datatable-virtualized]: https://storybook.uselets.com/?path=/docs/components-data-display-datatable-virtualized--docs
383
+ [daterangepicker]: https://storybook.uselets.com/?path=/docs/components-forms-daterangepicker--docs
384
+ [dialog]: https://storybook.uselets.com/?path=/docs/components-overlay-dialog--docs
385
+ [donutchart]: https://storybook.uselets.com/?path=/docs/components-charts-donutchart--docs
386
+ [drawer]: https://storybook.uselets.com/?path=/docs/components-overlay-drawer--docs
387
+ [dropdownmenu]: https://storybook.uselets.com/?path=/docs/components-overlay-dropdownmenu--docs
388
+ [dropzone]: https://storybook.uselets.com/?path=/docs/components-forms-dropzone--docs
389
+ [empty]: https://storybook.uselets.com/?path=/docs/components-feedback-empty--docs
390
+ [field]: https://storybook.uselets.com/?path=/docs/components-forms-field--docs
391
+ [flex]: https://storybook.uselets.com/?path=/docs/components-layout-flex--docs
392
+ [grid]: https://storybook.uselets.com/?path=/docs/components-layout-grid--docs
393
+ [group]: https://storybook.uselets.com/?path=/docs/components-layout-group--docs
394
+ [heading]: https://storybook.uselets.com/?path=/docs/components-typography-heading--docs
395
+ [hovercard]: https://storybook.uselets.com/?path=/docs/components-overlay-hovercard--docs
396
+ [input]: https://storybook.uselets.com/?path=/docs/components-forms-input--docs
397
+ [inputgroup]: https://storybook.uselets.com/?path=/docs/components-forms-inputgroup--docs
398
+ [inputotp]: https://storybook.uselets.com/?path=/docs/components-forms-input-otp--docs
399
+ [kbd]: https://storybook.uselets.com/?path=/docs/components-data-display-kbd--docs
400
+ [label]: https://storybook.uselets.com/?path=/docs/components-forms-label--docs
401
+ [list]: https://storybook.uselets.com/?path=/docs/components-typography-list--docs
402
+ [logo]: https://storybook.uselets.com/?path=/docs/components-media-logo--docs
403
+ [marker]: https://storybook.uselets.com/?path=/docs/components-layout-marker--docs
404
+ [maskinput]: https://storybook.uselets.com/?path=/docs/components-forms-maskinput--docs
405
+ [nativeselect]: https://storybook.uselets.com/?path=/docs/components-forms-native-select--docs
406
+ [navigationmenu]: https://storybook.uselets.com/?path=/docs/components-navigation-navigationmenu--docs
407
+ [numberfield]: https://storybook.uselets.com/?path=/docs/components-forms-number-field--docs
408
+ [pagination]: https://storybook.uselets.com/?path=/docs/components-navigation-pagination--docs
409
+ [phoneinput]: https://storybook.uselets.com/?path=/docs/components-forms-phone-input--docs
410
+ [piechart]: https://storybook.uselets.com/?path=/docs/components-charts-piechart--docs
411
+ [popover]: https://storybook.uselets.com/?path=/docs/components-overlay-popover--docs
412
+ [progress]: https://storybook.uselets.com/?path=/docs/components-feedback-progress--docs
413
+ [radiogroup]: https://storybook.uselets.com/?path=/docs/components-forms-radiogroup--docs
414
+ [resizable]: https://storybook.uselets.com/?path=/docs/components-layout-resizable--docs
415
+ [ringprogress]: https://storybook.uselets.com/?path=/docs/components-feedback-ring-progress--docs
416
+ [scrollarea]: https://storybook.uselets.com/?path=/docs/components-layout-scrollarea--docs
417
+ [select]: https://storybook.uselets.com/?path=/docs/components-forms-select--docs
418
+ [separator]: https://storybook.uselets.com/?path=/docs/components-layout-separator--docs
419
+ [sidebar]: https://storybook.uselets.com/?path=/docs/components-layout-sidebar--docs
420
+ [simplegrid]: https://storybook.uselets.com/?path=/docs/components-layout-simplegrid--docs
421
+ [skeleton]: https://storybook.uselets.com/?path=/docs/components-feedback-skeleton--docs
422
+ [slider]: https://storybook.uselets.com/?path=/docs/components-forms-slider--docs
423
+ [spinner]: https://storybook.uselets.com/?path=/docs/components-feedback-spinner--docs
424
+ [stack]: https://storybook.uselets.com/?path=/docs/components-layout-stack--docs
425
+ [stepper]: https://storybook.uselets.com/?path=/docs/components-navigation-stepper--docs
426
+ [switch]: https://storybook.uselets.com/?path=/docs/components-forms-switch--docs
427
+ [table]: https://storybook.uselets.com/?path=/docs/components-data-display-table--docs
428
+ [tabs]: https://storybook.uselets.com/?path=/docs/components-navigation-tabs--docs
429
+ [text]: https://storybook.uselets.com/?path=/docs/components-typography-text--docs
430
+ [textarea]: https://storybook.uselets.com/?path=/docs/components-forms-textarea--docs
431
+ [themeprovider]: https://storybook.uselets.com/?path=/docs/components-utilities-themeprovider--docs
432
+ [timeline]: https://storybook.uselets.com/?path=/docs/components-data-display-timeline--docs
433
+ [toast]: https://storybook.uselets.com/?path=/docs/components-feedback-toast--docs
434
+ [toggle]: https://storybook.uselets.com/?path=/docs/components-button-toggle--docs
435
+ [togglegroup]: https://storybook.uselets.com/?path=/docs/components-button-togglegroup--docs
436
+ [tooltip]: https://storybook.uselets.com/?path=/docs/components-overlay-tooltip--docs
437
+ [unstyledbutton]: https://storybook.uselets.com/?path=/docs/components-button-unstyledbutton--docs
438
+ [usebreakpoint]: https://storybook.uselets.com/?path=/docs/hooks-browser-usebreakpoint--docs
439
+ [usebreakpointvalue]: https://storybook.uselets.com/?path=/docs/hooks-browser-usebreakpointvalue--docs
440
+ [usedisclosure]: https://storybook.uselets.com/?path=/docs/hooks-state-usedisclosure--docs
441
+ [usedocumentvisibility]: https://storybook.uselets.com/?path=/docs/hooks-browser-usedocumentvisibility--docs
442
+ [usehotkeys]: https://storybook.uselets.com/?path=/docs/hooks-keyboard-usehotkeys--docs
443
+ [useidle]: https://storybook.uselets.com/?path=/docs/hooks-timing-useidle--docs
444
+ [useinterval]: https://storybook.uselets.com/?path=/docs/hooks-timing-useinterval--docs
445
+ [useismobile]: https://storybook.uselets.com/?path=/docs/hooks-browser-useismobile--docs
446
+ [uselocalstorage]: https://storybook.uselets.com/?path=/docs/hooks-state-uselocalstorage--docs
447
+ [visibility]: https://storybook.uselets.com/?path=/docs/components-layout-visibility--docs