@uselets/ui 1.20.4 → 2.0.1

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 (252) hide show
  1. package/README.md +309 -426
  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 +22 -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/anchor.d.ts +3 -5
  13. package/dist/components/anchor.js +1 -1
  14. package/dist/components/anchor.js.map +1 -1
  15. package/dist/components/area-chart.d.ts +54 -0
  16. package/dist/components/area-chart.js +1 -1
  17. package/dist/components/area-chart.js.map +1 -1
  18. package/dist/components/avatar.d.ts +12 -7
  19. package/dist/components/avatar.js +1 -1
  20. package/dist/components/avatar.js.map +1 -1
  21. package/dist/components/badge.d.ts +3 -5
  22. package/dist/components/badge.js +1 -1
  23. package/dist/components/badge.js.map +1 -1
  24. package/dist/components/bar-chart.d.ts +48 -0
  25. package/dist/components/bar-chart.js +1 -1
  26. package/dist/components/bar-chart.js.map +1 -1
  27. package/dist/components/bottom-nav.d.ts +7 -3
  28. package/dist/components/bottom-nav.js +1 -1
  29. package/dist/components/bottom-nav.js.map +1 -1
  30. package/dist/components/breadcrumb.d.ts +3 -4
  31. package/dist/components/breadcrumb.js +1 -1
  32. package/dist/components/breadcrumb.js.map +1 -1
  33. package/dist/components/button-group.d.ts +3 -4
  34. package/dist/components/button-group.js +1 -1
  35. package/dist/components/button-group.js.map +1 -1
  36. package/dist/components/button.d.ts +8 -4
  37. package/dist/components/button.js +1 -1
  38. package/dist/components/button.js.map +1 -1
  39. package/dist/components/calendar.d.ts +4 -0
  40. package/dist/components/calendar.js +1 -1
  41. package/dist/components/calendar.js.map +1 -1
  42. package/dist/components/card.d.ts +4 -0
  43. package/dist/components/card.js.map +1 -1
  44. package/dist/components/carousel.d.ts +11 -3
  45. package/dist/components/carousel.js +1 -1
  46. package/dist/components/carousel.js.map +1 -1
  47. package/dist/components/center.d.ts +1 -1
  48. package/dist/components/chart.js +4 -4
  49. package/dist/components/checkbox.d.ts +14 -4
  50. package/dist/components/checkbox.js +1 -1
  51. package/dist/components/checkbox.js.map +1 -1
  52. package/dist/components/collapsible.d.ts +8 -7
  53. package/dist/components/collapsible.js +1 -1
  54. package/dist/components/collapsible.js.map +1 -1
  55. package/dist/components/combobox.d.ts +48 -26
  56. package/dist/components/combobox.js +1 -1
  57. package/dist/components/combobox.js.map +1 -1
  58. package/dist/components/command.d.ts +16 -2
  59. package/dist/components/command.js +1 -1
  60. package/dist/components/command.js.map +1 -1
  61. package/dist/components/container.d.ts +1 -1
  62. package/dist/components/data-table.d.ts +39 -0
  63. package/dist/components/data-table.js +1 -1
  64. package/dist/components/data-table.js.map +1 -1
  65. package/dist/components/date-range-picker.d.ts +24 -2
  66. package/dist/components/date-range-picker.js +1 -1
  67. package/dist/components/date-range-picker.js.map +1 -1
  68. package/dist/components/dialog.d.ts +35 -15
  69. package/dist/components/dialog.js +1 -1
  70. package/dist/components/dialog.js.map +1 -1
  71. package/dist/components/direction.d.ts +7 -0
  72. package/dist/components/direction.js +1 -0
  73. package/dist/components/donut-chart.d.ts +12 -0
  74. package/dist/components/donut-chart.js +1 -1
  75. package/dist/components/donut-chart.js.map +1 -1
  76. package/dist/components/drawer.d.ts +33 -15
  77. package/dist/components/drawer.js +1 -1
  78. package/dist/components/drawer.js.map +1 -1
  79. package/dist/components/dropdown-menu.d.ts +36 -26
  80. package/dist/components/dropdown-menu.js +1 -1
  81. package/dist/components/dropdown-menu.js.map +1 -1
  82. package/dist/components/dropzone.d.ts +19 -0
  83. package/dist/components/dropzone.js +1 -1
  84. package/dist/components/dropzone.js.map +1 -1
  85. package/dist/components/field.d.ts +16 -4
  86. package/dist/components/field.js +1 -1
  87. package/dist/components/field.js.map +1 -1
  88. package/dist/components/flex.d.ts +1 -1
  89. package/dist/components/grid.d.ts +13 -0
  90. package/dist/components/grid.js.map +1 -1
  91. package/dist/components/group.d.ts +1 -1
  92. package/dist/components/heading.d.ts +3 -5
  93. package/dist/components/heading.js +1 -1
  94. package/dist/components/heading.js.map +1 -1
  95. package/dist/components/hover-card.d.ts +7 -6
  96. package/dist/components/hover-card.js +1 -1
  97. package/dist/components/hover-card.js.map +1 -1
  98. package/dist/components/input-group.d.ts +2 -2
  99. package/dist/components/input-group.js +1 -1
  100. package/dist/components/input-group.js.map +1 -1
  101. package/dist/components/input-otp.d.ts +4 -2
  102. package/dist/components/input-otp.js +1 -1
  103. package/dist/components/input-otp.js.map +1 -1
  104. package/dist/components/input.d.ts +1 -1
  105. package/dist/components/input.js +1 -1
  106. package/dist/components/input.js.map +1 -1
  107. package/dist/components/label.d.ts +3 -4
  108. package/dist/components/label.js +1 -1
  109. package/dist/components/label.js.map +1 -1
  110. package/dist/components/list.d.ts +8 -5
  111. package/dist/components/list.js +1 -1
  112. package/dist/components/list.js.map +1 -1
  113. package/dist/components/logo.d.ts +113 -0
  114. package/dist/components/marker.d.ts +4 -5
  115. package/dist/components/marker.js +1 -1
  116. package/dist/components/marker.js.map +1 -1
  117. package/dist/components/mask-input.d.ts +6 -0
  118. package/dist/components/mask-input.js.map +1 -1
  119. package/dist/components/native-select.d.ts +5 -1
  120. package/dist/components/native-select.js +1 -1
  121. package/dist/components/native-select.js.map +1 -1
  122. package/dist/components/navigation-menu.d.ts +19 -20
  123. package/dist/components/navigation-menu.js +1 -1
  124. package/dist/components/navigation-menu.js.map +1 -1
  125. package/dist/components/number-field.d.ts +18 -13
  126. package/dist/components/number-field.js +1 -1
  127. package/dist/components/number-field.js.map +1 -1
  128. package/dist/components/pagination.d.ts +9 -0
  129. package/dist/components/pagination.js +1 -1
  130. package/dist/components/pagination.js.map +1 -1
  131. package/dist/components/phone-input.d.ts +3 -0
  132. package/dist/components/phone-input.js +1 -1
  133. package/dist/components/phone-input.js.map +1 -1
  134. package/dist/components/pie-chart.d.ts +53 -0
  135. package/dist/components/pie-chart.js +1 -1
  136. package/dist/components/pie-chart.js.map +1 -1
  137. package/dist/components/popover.d.ts +13 -12
  138. package/dist/components/popover.js +1 -1
  139. package/dist/components/popover.js.map +1 -1
  140. package/dist/components/progress.d.ts +9 -3
  141. package/dist/components/progress.js +1 -1
  142. package/dist/components/progress.js.map +1 -1
  143. package/dist/components/radio-group.d.ts +20 -6
  144. package/dist/components/radio-group.js +1 -1
  145. package/dist/components/radio-group.js.map +1 -1
  146. package/dist/components/resizable.d.ts +1 -0
  147. package/dist/components/resizable.js.map +1 -1
  148. package/dist/components/ring-progress.d.ts +9 -1
  149. package/dist/components/ring-progress.js.map +1 -1
  150. package/dist/components/scroll-area.d.ts +3 -3
  151. package/dist/components/scroll-area.js +1 -1
  152. package/dist/components/scroll-area.js.map +1 -1
  153. package/dist/components/select.d.ts +25 -20
  154. package/dist/components/select.js +1 -1
  155. package/dist/components/select.js.map +1 -1
  156. package/dist/components/separator.d.ts +9 -4
  157. package/dist/components/separator.js +1 -1
  158. package/dist/components/separator.js.map +1 -1
  159. package/dist/components/sidebar.d.ts +63 -18
  160. package/dist/components/sidebar.js +1 -1
  161. package/dist/components/sidebar.js.map +1 -1
  162. package/dist/components/simple-grid.d.ts +7 -0
  163. package/dist/components/simple-grid.js +1 -1
  164. package/dist/components/simple-grid.js.map +1 -1
  165. package/dist/components/skeleton.d.ts +4 -0
  166. package/dist/components/skeleton.js.map +1 -1
  167. package/dist/components/slider.d.ts +2 -2
  168. package/dist/components/slider.js +1 -1
  169. package/dist/components/slider.js.map +1 -1
  170. package/dist/components/spinner.d.ts +1 -1
  171. package/dist/components/stack.d.ts +1 -1
  172. package/dist/components/stepper.d.ts +46 -25
  173. package/dist/components/stepper.js +1 -1
  174. package/dist/components/stepper.js.map +1 -1
  175. package/dist/components/switch.d.ts +17 -3
  176. package/dist/components/switch.js +1 -1
  177. package/dist/components/switch.js.map +1 -1
  178. package/dist/components/table.d.ts +10 -1
  179. package/dist/components/table.js +1 -1
  180. package/dist/components/table.js.map +1 -1
  181. package/dist/components/tabs.d.ts +14 -10
  182. package/dist/components/tabs.js +1 -1
  183. package/dist/components/tabs.js.map +1 -1
  184. package/dist/components/text.d.ts +3 -5
  185. package/dist/components/text.js +1 -1
  186. package/dist/components/text.js.map +1 -1
  187. package/dist/components/textarea.d.ts +1 -1
  188. package/dist/components/textarea.js +1 -1
  189. package/dist/components/textarea.js.map +1 -1
  190. package/dist/components/theme.d.ts +12 -0
  191. package/dist/components/theme.js +1 -1
  192. package/dist/components/theme.js.map +1 -1
  193. package/dist/components/timeline.d.ts +25 -1
  194. package/dist/components/timeline.js +1 -1
  195. package/dist/components/timeline.js.map +1 -1
  196. package/dist/components/toggle-group.d.ts +16 -6
  197. package/dist/components/toggle-group.js +1 -1
  198. package/dist/components/toggle-group.js.map +1 -1
  199. package/dist/components/toggle.d.ts +4 -4
  200. package/dist/components/toggle.js +1 -1
  201. package/dist/components/toggle.js.map +1 -1
  202. package/dist/components/tooltip.d.ts +15 -8
  203. package/dist/components/tooltip.js +1 -1
  204. package/dist/components/tooltip.js.map +1 -1
  205. package/dist/components/unstyled-button.d.ts +3 -5
  206. package/dist/components/unstyled-button.js +1 -1
  207. package/dist/components/unstyled-button.js.map +1 -1
  208. package/dist/components/visibility.d.ts +2 -0
  209. package/dist/components/visibility.js +1 -1
  210. package/dist/components/visibility.js.map +1 -1
  211. package/dist/hooks/use-breakpoint-value.d.ts +1 -0
  212. package/dist/hooks/use-breakpoint-value.js.map +1 -1
  213. package/dist/hooks/use-breakpoint.d.ts +1 -0
  214. package/dist/hooks/use-breakpoint.js.map +1 -1
  215. package/dist/hooks/use-disclosure.d.ts +3 -0
  216. package/dist/hooks/use-disclosure.js +1 -1
  217. package/dist/hooks/use-disclosure.js.map +1 -1
  218. package/dist/hooks/use-document-visibility.d.ts +1 -0
  219. package/dist/hooks/use-document-visibility.js.map +1 -1
  220. package/dist/hooks/use-hotkeys.d.ts +1 -1
  221. package/dist/hooks/use-idle.d.ts +9 -0
  222. package/dist/hooks/use-idle.js.map +1 -1
  223. package/dist/hooks/use-interval.d.ts +1 -0
  224. package/dist/hooks/use-interval.js.map +1 -1
  225. package/dist/hooks/use-local-storage.d.ts +6 -0
  226. package/dist/hooks/use-local-storage.js +1 -1
  227. package/dist/hooks/use-local-storage.js.map +1 -1
  228. package/dist/hooks/use-mask.d.ts +1 -0
  229. package/dist/hooks/use-mask.js.map +1 -1
  230. package/dist/hooks/use-mobile.d.ts +1 -0
  231. package/dist/hooks/use-mobile.js.map +1 -1
  232. package/dist/index.d.ts +7 -5
  233. package/dist/index.js +1 -1
  234. package/dist/lib/as-child.d.ts +2 -0
  235. package/dist/lib/as-child.js +2 -0
  236. package/dist/lib/as-child.js.map +1 -0
  237. package/dist/lib/utils.d.ts +1 -1
  238. package/dist/logo--R3_XDgA.js.map +1 -1
  239. package/dist/resolve-class-name-BurP8ngI.js +2 -0
  240. package/dist/resolve-class-name-BurP8ngI.js.map +1 -0
  241. package/dist/skills/uselets-ui/SKILL.md +8 -3
  242. package/dist/skills/uselets-ui/references/component-catalog.md +32 -17
  243. package/dist/skills/uselets-ui/references/migration-v1-to-v2.md +599 -0
  244. package/dist/skills/uselets-ui/references/package-guide.md +7 -7
  245. package/dist/styles/base.css +21 -0
  246. package/dist/{use-hotkeys-DOjcX9Tt.d.ts → use-hotkeys-D1_TEIwN.d.ts} +2 -1
  247. package/dist/use-hotkeys-YDJmGWX6.js.map +1 -1
  248. package/package.json +16 -17
  249. package/skills/uselets-ui/SKILL.md +8 -3
  250. package/skills/uselets-ui/references/component-catalog.md +32 -17
  251. package/skills/uselets-ui/references/migration-v1-to-v2.md +599 -0
  252. package/skills/uselets-ui/references/package-guide.md +7 -7
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,7 +66,7 @@ npm install tailwindcss @tailwindcss/postcss
81
66
  export { default } from '@uselets/ui/postcss.config'
82
67
  ```
83
68
 
84
- > **Using Vite?** You can use the Tailwind Vite plugin instead of PostCSS — install `tailwindcss @tailwindcss/vite`,
69
+ > **Using Vite?** You can use the Tailwind Vite plugin instead of PostCSS: install `tailwindcss @tailwindcss/vite`,
85
70
  > skip `postcss.config.mjs`, and register the plugin. Prefer this setup when your project uses isolated installs
86
71
  > (pnpm, or Bun workspaces): with PostCSS under Vite, the theme's Tailwind plugins may fail to resolve there.
87
72
  >
@@ -95,42 +80,47 @@ export { default } from '@uselets/ui/postcss.config'
95
80
  > })
96
81
  > ```
97
82
 
98
- 3. Import Tailwind and one package theme in your global stylesheet:
83
+ 3. Import Tailwind, one package theme, and the package sources in your global stylesheet:
99
84
 
100
85
  ```css
101
86
  /* app.css */
102
87
  @import 'tailwindcss';
103
- @import '@uselets/ui/themes/max.css';
104
- ```
105
-
106
- Use `@uselets/ui/themes/gomax.css` instead for GoMax apps. If your app consumes `@uselets/ui` components, add a
107
- 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 */
108
89
 
109
- ```css
110
90
  @source '../node_modules/@uselets/ui/dist';
111
91
  ```
112
92
 
113
- 4. Import the Inter font once from your app's entry file (not from CSS — bundlers such as Next.js don't
114
- 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):
115
97
 
116
98
  ```ts
117
99
  // app/layout.tsx (or src/main.tsx, pages/_app.tsx, ...)
118
100
  import '@fontsource-variable/inter'
119
101
  ```
120
102
 
121
- ## Quick start
103
+ ### Agent skill
122
104
 
123
- 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:
124
107
 
125
- ```css
126
- @import 'tailwindcss';
127
- @import '@uselets/ui/themes/max.css';
108
+ ```bash
109
+ bun uselets skill
128
110
  ```
129
111
 
130
- For GoMax apps, import `@uselets/ui/themes/gomax.css` instead. Import the font once from your app's entry
131
- 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`.
132
118
 
133
- 2. Import components from the package root:
119
+ ## Usage
120
+
121
+ ### Imports
122
+
123
+ Import from the package root:
134
124
 
135
125
  ```tsx
136
126
  import { Alert, Button } from '@uselets/ui'
@@ -144,120 +134,66 @@ export function Example() {
144
134
  }
145
135
  ```
146
136
 
147
- 3. You can also import through subpaths:
137
+ Or through subpaths: components at `@uselets/ui/<component>`, hooks at `@uselets/ui/hooks/<hook>`:
148
138
 
149
139
  ```tsx
150
140
  import { Button } from '@uselets/ui/button'
151
- import { DataTable, DataTableColumnHeader, createDataTableSelectColumn } from '@uselets/ui/data-table'
152
- import { useBreakpointValue } from '@uselets/ui/hooks/use-breakpoint-value'
153
- import { useIsMobile } from '@uselets/ui/hooks/use-mobile'
141
+ import { DataTable } from '@uselets/ui/data-table'
154
142
  import { useDisclosure } from '@uselets/ui/hooks/use-disclosure'
155
- import { useLocalStorage } from '@uselets/ui/hooks/use-local-storage'
156
143
  import { randomId } from '@uselets/ui/utils'
157
144
  ```
158
145
 
159
- ### Data tables
160
-
161
- Use `DataTable` for client-side tables. The default render is intentionally bare — just a header and the empty
162
- state — and every additional feature is opt-in: `filterColumns`, `enableSorting`, `showPagination`,
163
- `showColumnVisibility`, `toolbarActions`, and `enableRowSelection`. When `enableRowSelection` is `true` the selection checkbox column
164
- is prepended automatically (use the exported `createDataTableSelectColumn` only when you need to place it
165
- elsewhere). `filterColumns` accepts a single column id (`"customer"`) or an array (`["customer", "email"]`);
166
- when there are two or more, a select rendered with `InputGroup` appears at the left of the input to pick the
167
- target column. `toolbarActions` always renders at the right of the toolbar, even without a filter. All
168
- user-facing labels default to Portuguese (pt-BR) and can be overridden through the `labels` prop.
169
-
170
- The underlying `Table` component renders only the `<table>` element (no auto wrapper) and is striped by default
171
- (pass `striped={false}` to disable). Use `variant` to control the outer chrome: `"line"` (default) renders only
172
- horizontal separators between rows; `"outline"` adds a rounded outer border. The outline chrome works in two
173
- modes: standalone (no `TableContainer`), the border lives on the `<table>` itself; wrapped in a `TableContainer`,
174
- the container detects the outline variant via `:has()`, applies the chrome on itself, and removes it from the
175
- `<table>` — this keeps the border sticky-safe (sticky headers can no longer paint over it) without changing
176
- the visible result. `DataTable` accepts the same `variant` prop and forwards it to its internal `Table`. Wrap `Table` in `TableContainer` to
177
- control horizontal scroll — use the `minWidth` prop (number in px or any CSS length) on `TableContainer` to
178
- force horizontal scroll when the parent is narrower. Combine `stickyHeader` on `Table` with `max-h` +
179
- `overflow-y-auto` on `TableContainer` (via `className` or `style`) to keep `<thead>` visible while the body
180
- scrolls vertically. `DataTable` already wraps its `Table` in a `TableContainer`.
146
+ Each module exports its composition parts and prop types from the same path.
181
147
 
182
- ```tsx
183
- 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).
184
149
 
185
- type Payment = {
186
- id: string
187
- customer: string
188
- amount: number
189
- }
190
-
191
- const columns: ColumnDef<Payment>[] = [
192
- {
193
- accessorKey: 'customer',
194
- header: ({ column }) => <DataTableColumnHeader column={column} title="Customer" />
195
- },
196
- {
197
- accessorKey: 'amount',
198
- header: ({ column }) => <DataTableColumnHeader column={column} title="Amount" />,
199
- cell: ({ row }) => new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(row.original.amount)
200
- }
201
- ]
202
-
203
- export function PaymentsTable({ payments }: { payments: Payment[] }) {
204
- return (
205
- <DataTable
206
- columns={columns}
207
- data={payments}
208
- getRowId={(row) => row.id}
209
- filterColumns={['customer', 'email']}
210
- enableRowSelection
211
- enableSorting
212
- showPagination
213
- variant="outline"
214
- labels={{
215
- filterPlaceholder: 'Buscar cliente…',
216
- pageOf: (current, total) => `${current} / ${total}`
217
- }}
218
- />
219
- )
220
- }
221
- ```
222
-
223
- Override any subset of `DataTableLabels`; remaining keys fall back to the pt-BR defaults exported as
224
- `defaultDataTableLabels`.
150
+ ### App providers
225
151
 
226
- #### Compound API and virtualization
152
+ Add these at the app root when you use the matching feature:
227
153
 
228
- `DataTable` also exposes a compound API for cases that need finer control — chiefly virtualization, but also
229
- custom layout (toolbar inside a card header, pagination in a footer slot) or sharing the `table` instance with
230
- code outside the table subtree. The high-level `DataTable` shown above is itself implemented in terms of these
231
- 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) |
232
160
 
233
- Exports: `DataTableRoot`, `DataTableToolbar`, `DataTableHeader`, `DataTableBody`, `DataTablePagination`,
234
- `useDataTable`, `useDataTableContext`. `DataTableRoot` accepts either `{ columns, data, ...options }` or
235
- `{ table }` (instance created via `useDataTable`).
161
+ ## Theming
236
162
 
237
- For virtualization, `@uselets/ui` is intentionally **virtualizer-agnostic** — no runtime dependency on
238
- `@tanstack/react-virtual`, `react-window`, `virtua`, or any other library. Bring your own: instantiate it next
239
- to `useDataTable`, then render your virtual `<tbody>` in place of `<DataTableBody />`. Set
240
- `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` |
241
167
 
242
- A complete TanStack Virtual example lives in `apps/web/src/stories/data-table-virtualized.stories.tsx` and the
243
- 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).
244
169
 
245
- ## Theme tokens
170
+ ### Colors
246
171
 
247
- 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`.
248
174
 
249
- - `@uselets/ui/themes/max.css`
250
- - `@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> |
251
187
 
252
- Max and GoMax are maintained from their respective Figma style guides. The Storybook
253
- `Foundations/Themes` story reads the active stylesheet tokens, so it is the theme-backed
254
- 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`.
255
191
 
256
- ### Typography scale
192
+ ### Typography
257
193
 
258
- The Max theme overrides Tailwind CSS text size utilities from `text-xs` through `text-6xl` to match the
259
- Figma typography scale. Inter is the default sans-serif family, and each size uses a line height equal to
260
- `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).
261
197
 
262
198
  | Utility | Font size | Line height |
263
199
  | --- | --- | --- |
@@ -272,293 +208,240 @@ Figma typography scale. Inter is the default sans-serif family, and each size us
272
208
  | `text-5xl` | `3rem` / `48px` | `4.5rem` / `72px` |
273
209
  | `text-6xl` | `3.75rem` / `60px` | `5.625rem` / `90px` |
274
210
 
275
- ### Public palette families
276
-
277
- The palette follows the Tailwind and shadcn convention of complete `50..950` scales.
278
-
279
- - `primary`
280
- - `brand`
281
- - `gray`
282
- - `zinc`
283
- - `red`
284
- - `yellow`
285
- - `blue`
286
- - `indigo`
287
- - `pink`
288
- - `green`
289
-
290
- This same list is exported as `uiColors` and `UIColor` from `@uselets/ui` and `@uselets/ui/lib/color`.
291
- Color-aware components such as `Button`, `Toggle`, `Checkbox`, `RadioGroupItem`, and `Switch` use `UIColor` for their public `color` props.
292
- `ButtonColor` remains available as a compatibility alias for existing button consumers.
293
-
294
- Each family is exposed in four layers:
295
-
296
- - CSS variables such as `--primary-500`, `--brand-500` and `--zinc-900`
297
- - Semantic CSS aliases such as `--green`, `--red` and `--gray`, mapped to `500` in light mode and `400` in dark mode
298
- - Tailwind v4 theme utilities such as `bg-primary-500`, `text-zinc-900`, `border-red-300`
299
- - Tailwind v4 semantic utilities such as `bg-green`, `text-red` and `border-gray`
300
-
301
- Color-aware components use the semantic family aliases for their primary color so `color="green"` resolves to
302
- `--green-500` in light mode and `--green-400` in dark mode. Hover and subtle surfaces continue to use explicit
303
- palette steps.
304
-
305
- ### Palette preview
306
-
307
- | Family | Reference token | Preview |
308
- | --- | --- | --- |
309
- | `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> |
310
- | `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> |
311
- | `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> |
312
- | `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> |
313
- | `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> |
314
- | `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> |
315
- | `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> |
316
- | `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> |
317
- | `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> |
318
- | `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> |
319
-
320
- ### Semantic tokens
321
-
322
- Use semantic tokens for application UI instead of hardcoding palette steps in components.
323
-
324
- - Surfaces and text: `background`, `foreground`, `card`, `popover`
325
- - Actions and emphasis: `primary`, `secondary`, `accent`, `destructive`
326
- - Supporting tokens: `border`, `input`, `ring`, `placeholder`
327
- - Sidebar tokens: `sidebar`, `sidebar-primary`, `sidebar-accent`, `sidebar-border`, `sidebar-ring`
328
- - Data viz tokens: `chart-1` to `chart-5`
329
- - 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)
330
-
331
- The theme also exposes the shadcn foreground pair for destructive surfaces:
332
-
333
- - `--destructive-foreground`
334
- - `text-destructive-foreground`
335
-
336
- ### Gradient tokens
337
-
338
- The palette includes one named gradient token:
339
-
340
- - `--gradient-primary`
341
-
342
- This gradient is a documentation and styling primitive. It is not exposed as a Tailwind color family.
343
-
344
- ### Global scrollbar style
211
+ ### Scrollbar
345
212
 
346
- Importing either theme entrypoint applies a default page scrollbar style via the bundled
347
- [`tailwind-scrollbar`](https://github.com/adoxography/tailwind-scrollbar) plugin: thin width,
348
- transparent track, `muted` thumb with a `muted-foreground` hover state. The plugin's utilities
349
- (`scrollbar-thin`, `scrollbar-thumb-*`, `scrollbar-track-*`, `scrollbar-hover:*`) are available
350
- to override these defaults or to style internal scrollable regions. Firefox uses the standard
351
- `scrollbar-color` property and does not honor the pseudo-element hover variant — the thumb
352
- 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.
353
215
 
354
216
  ## Components
355
217
 
356
- You can import from the package root (`@uselets/ui`) or by subpath (`@uselets/ui/<component>`).
357
-
358
- | 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 |
359
353
  | --- | --- | --- |
360
- | `alert` | `Alert`, `AlertTitle`, `AlertDescription`, `AlertAction` | `Alert` supports `variant: 'default' \| 'destructive'` (default: `default`). |
361
- | `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`. |
362
- | `avatar` | `Avatar`, `AvatarImage`, `AvatarFallback`, `AvatarBadge`, `AvatarGroup`, `AvatarGroupCount` | `Avatar` supports `size: 'sm' \| 'md' \| 'lg'` (default: `md`). |
363
- | `badge` | `Badge`, `badgeVariants` | `size: 'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` (default: `md`); `variant: 'solid' \| 'secondary' \| 'outline' \| 'subtle'` (default: `solid`); `color: UIColor` (default: `primary`); `asChild?: boolean`. |
364
- | `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`. |
365
- | `unstyled-button` | `UnstyledButton` | Button primitive with reset styles, pointer cursor, accessible focus ring, default `type="button"`, and `asChild`. |
366
- | `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. |
367
- | `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`. |
368
- | `card` | `Card`, `CardHeader`, `CardTitle`, `CardDescription`, `CardAction`, `CardContent`, `CardFooter` | `Card` supports `size: 'sm' \| 'md' \| 'lg'` (default: `md`). |
369
- | `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. |
370
- | `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. |
371
- | `code` | `Code` | Inline code primitive rendered as `<code>`. |
372
- | `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. |
373
- | `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. |
374
- | `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. |
375
- | `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. |
376
- | `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'`. |
377
- | `empty` | `Empty`, `EmptyHeader`, `EmptyMedia`, `EmptyTitle`, `EmptyDescription`, `EmptyContent` | `EmptyMedia` supports `variant: 'default' \| 'icon'` (default: `default`). |
378
- | `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. |
379
- | `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`). |
380
- | `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. |
381
- | `heading` | `Heading`, `headingVariants` | Heading primitive with `size: 'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` (default: `md`) and `asChild`. |
382
- | `input` | `Input` | Wrapper for Base UI Input with all native `<input>` props. |
383
- | `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. |
384
- | `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. |
385
- | `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`. |
386
- | `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. |
387
- | `kbd` | `Kbd`, `KbdGroup` | Keyboard shortcut presentation primitives. |
388
- | `label` | `Label` | Styled `<label>` wrapper. |
389
- | `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. |
390
- | `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. |
391
- | `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. |
392
- | `native-select` | `NativeSelect`, `NativeSelectOption`, `NativeSelectOptGroup` | Native `<select>` API with `size: 'sm' \| 'md'` (default: `md`). |
393
- | `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`). |
394
- | `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`). |
395
- | `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. |
396
- | `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. |
397
- | `select` | `Select`, `SelectTrigger`, `SelectValue`, `SelectContent`, `SelectGroup`, `SelectItem`, `SelectLabel`, `SelectSeparator`, `SelectScrollUpButton`, `SelectScrollDownButton` | `SelectTrigger.size: 'sm' \| 'md'`; `SelectContent` supports positioning props (`side`, `sideOffset`, `align`, `alignOffset`, `alignItemWithTrigger`). |
398
- | `separator` | `Separator` | `orientation: 'horizontal' \| 'vertical'` (default: `horizontal`). |
399
- | `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. |
400
- | `skeleton` | `Skeleton` | Generic loading placeholder block. Supports `visible?: boolean` (default: `true`) and can wrap `children` to reserve their size while the placeholder is shown. |
401
- | `spinner` | `Spinner` | Loader icon (`role="status"`), accepts SVG props and supports `size: 'sm' \| 'md' \| 'lg'` (default: `md`). |
402
- | `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. |
403
- | `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. |
404
- | `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. |
405
- | `text` | `Text`, `textVariants` | Text primitive with `size: 'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` (default: `md`) and `asChild`. |
406
- | `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`). |
407
- | `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`. |
408
- | `visibility` | `HiddenFrom`, `VisibleFrom` | Breakpoint visibility helpers. `HiddenFrom breakpoint="md"` hides at `md` and above; `VisibleFrom breakpoint="md"` shows at `md` and above. |
409
- | `sonner` | `Toaster`, `toast` | Toaster wrapper around Sonner with theme integration from `next-themes` and custom icons. |
410
-
411
- ### Additional components
412
-
413
- The package also exports the following modules through the root entrypoint and subpaths:
414
-
415
- - Layout and disclosure: `Accordion`, `Carousel`, `Center`, `Collapsible`, `Container`, `Flex`, `Group`, `Resizable`, `ScrollArea`, `Sidebar`, `Stack`, `Tabs`
416
- - Inputs and selection: `Calendar`, `DateRangePicker`, `InputGroup`, `RadioGroup`, `Slider`, `Switch`, `Textarea`, `Toggle`, `ToggleGroup`
417
- - Navigation and feedback: `AlertDialog`, `BottomNav`, `Breadcrumb`, `NavigationMenu`, `Pagination`, `Progress`
418
- - Data display and utilities: `Badge`, `ButtonGroup`, `Chart`, `Command`, `HoverCard`, `Table`, `ThemeProvider`, `useTheme`, `ModeToggle`
419
-
420
- 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.
421
-
422
- 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.
423
-
424
- `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.
425
-
426
- `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.
427
-
428
- Public hooks are exported from the package root and from the `@uselets/ui/hooks/*` namespace:
429
-
430
- - `useBreakpoint` from `@uselets/ui/hooks/use-breakpoint`
431
- - `useBreakpointValue` from `@uselets/ui/hooks/use-breakpoint-value`
432
- - `useDisclosure` from `@uselets/ui/hooks/use-disclosure`
433
- - `useInterval` from `@uselets/ui/hooks/use-interval`
434
- - `useIdle` from `@uselets/ui/hooks/use-idle`
435
- - `useDocumentVisibility` from `@uselets/ui/hooks/use-document-visibility`
436
- - `useHotkeys` from `@uselets/ui/hooks/use-hotkeys`
437
- - `useLocalStorage` from `@uselets/ui/hooks/use-local-storage`
438
- - `useMask` from `@uselets/ui/hooks/use-mask`
439
- - `useIsMobile` from `@uselets/ui/hooks/use-mobile`
440
-
441
- Legacy hook subpaths such as `@uselets/ui/use-mobile` are not public entrypoints.
442
-
443
- `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:
444
-
445
- ```tsx
446
- const cols = useBreakpointValue({ base: 1, md: 2, lg: 3 }) ?? 1
447
-
448
- return <SimpleGrid cols={cols} gap="md" />
449
- ```
450
-
451
- `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:
452
-
453
- ```tsx
454
- const [settings, setSettings] = useLocalStorage('settings', {
455
- defaultValue: { compact: false }
456
- })
457
-
458
- const [draft, setDraft] = useLocalStorage('draft', {
459
- defaultValue: '',
460
- sync: false
461
- })
462
- ```
463
-
464
- `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:
465
-
466
- ```tsx
467
- useHotkeys([
468
- ['mod+k', () => openCommandPalette()],
469
- ['escape', () => close(), { preventDefault: false }]
470
- ])
471
-
472
- // or scoped to one element
473
- <input onKeyDown={getHotkeyHandler([['mod+enter', submit]])} />
474
- ```
475
-
476
- 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`).
477
-
478
- `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:
479
-
480
- ```tsx
481
- import { ModeToggle, ThemeProvider } from '@uselets/ui/theme'
482
-
483
- export function AppRoot({ children }: { children: React.ReactNode }) {
484
- return (
485
- <ThemeProvider defaultTheme="system" disableTransitionOnChange>
486
- <ModeToggle />
487
- {children}
488
- </ThemeProvider>
489
- )
490
- }
491
- ```
492
-
493
- ### Sonner example
494
-
495
- ```tsx
496
- import { ThemeProvider } from 'next-themes'
497
- import { Toaster, toast } from '@uselets/ui/sonner'
498
-
499
- export function App() {
500
- return (
501
- <ThemeProvider attribute="class" defaultTheme="system" enableSystem>
502
- <button onClick={() => toast.success('Saved')}>Notify</button>
503
- <Toaster />
504
- </ThemeProvider>
505
- )
506
- }
507
- ```
508
-
509
- ## Tooltip setup
510
-
511
- For consistent tooltip behavior across the app, wrap your application root with `TooltipProvider`.
512
-
513
- ```tsx
514
- import { Tooltip, TooltipProvider } from '@uselets/ui/tooltip'
515
-
516
- export function AppRoot() {
517
- return <TooltipProvider delayDuration={200}>{/* app */}</TooltipProvider>
518
- }
519
-
520
- export function SaveButton() {
521
- return (
522
- <Tooltip label="Salva as alterações" side="bottom">
523
- <button type="button">Salvar</button>
524
- </Tooltip>
525
- )
526
- }
527
- ```
528
-
529
- ## Sidebar setup
530
-
531
- `SidebarProvider` owns the sidebar's open/collapsed state; `Sidebar` renders the structure and
532
- accepts `collapsible: 'offcanvas' | 'icon' | 'none'`. Set `expandOnHover` on `SidebarProvider` to let
533
- a `collapsible="icon"` sidebar reveal a floating preview (an overlay, not a layout push) on pointer
534
- hover or keyboard focus while collapsed. During that preview, clicking `SidebarRail` pins the sidebar
535
- open, while clicking `SidebarTrigger` closes the preview. Once a toggle collapses the sidebar, the
536
- preview stays closed until the pointer leaves the sidebar (or keyboard focus moves into it), so it
537
- doesn't reopen under a cursor that is still over it. `useSidebar()` exposes `isHoverExpanded`
538
- for components that need to react to the preview themselves. The preview's open/close debounce
539
- defaults to 150ms/300ms and can be tuned per app via `hoverExpandOpenDelay`/`hoverExpandCloseDelay`.
540
-
541
- ```tsx
542
- import { Sidebar, SidebarContent, SidebarProvider, SidebarRail, SidebarTrigger } from '@uselets/ui/sidebar'
543
-
544
- export function AppShell({ children }: { children: React.ReactNode }) {
545
- return (
546
- <SidebarProvider expandOnHover>
547
- <Sidebar collapsible="icon">
548
- <SidebarContent>{/* menu */}</SidebarContent>
549
- <SidebarRail />
550
- </Sidebar>
551
- <SidebarTrigger />
552
- {children}
553
- </SidebarProvider>
554
- )
555
- }
556
- ```
557
-
558
- To use your own element as the trigger, pass `asChild` — it still toggles the sidebar, no `onClick` needed:
559
-
560
- ```tsx
561
- <SidebarTrigger asChild>
562
- <Button variant="ghost">Menu</Button>
563
- </SidebarTrigger>
564
- ```
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