@bzync/rui 0.0.5 → 0.0.9

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 (240) hide show
  1. package/README.md +476 -57
  2. package/dist/autocomplete-D6z5B-WU.cjs +1 -0
  3. package/dist/{autocomplete-BgKbj6M4.js → autocomplete-bgySuP8X.js} +149 -142
  4. package/dist/calendar-CQumLNgS.cjs +1 -0
  5. package/dist/{calendar-j2_zvum1.js → calendar-nkYCMEy3.js} +9 -9
  6. package/dist/charts-Cot5lCgC.cjs +1 -0
  7. package/dist/{charts-CxEy2c3M.js → charts-Dscl6UC3.js} +122 -145
  8. package/dist/cn-B6R3HKzx.cjs +1 -0
  9. package/dist/{cn-DpgY2leY.js → cn-BJyZJP-y.js} +389 -389
  10. package/dist/{component-styles-Bgy44fc8.js → component-styles-C2CbHEEA.js} +2 -2
  11. package/dist/component-styles-DY4wigiq.cjs +1 -0
  12. package/dist/components/accordion.cjs +1 -1
  13. package/dist/components/accordion.js +2 -2
  14. package/dist/components/alert.cjs +1 -1
  15. package/dist/components/alert.js +3 -3
  16. package/dist/components/aspect-ratio.cjs +1 -1
  17. package/dist/components/aspect-ratio.js +1 -1
  18. package/dist/components/auth-backdrop.cjs +1 -1
  19. package/dist/components/auth-backdrop.d.ts +4 -1
  20. package/dist/components/auth-backdrop.js +12 -8
  21. package/dist/components/autocomplete/dropdown.d.ts +4 -1
  22. package/dist/components/autocomplete/multi-trigger.d.ts +3 -1
  23. package/dist/components/autocomplete/single-trigger.d.ts +3 -1
  24. package/dist/components/autocomplete/types.d.ts +15 -0
  25. package/dist/components/autocomplete.cjs +1 -1
  26. package/dist/components/autocomplete.js +1 -1
  27. package/dist/components/avatar-group.cjs +1 -1
  28. package/dist/components/avatar-group.js +1 -1
  29. package/dist/components/avatar.cjs +1 -1
  30. package/dist/components/avatar.js +2 -2
  31. package/dist/components/badge.cjs +1 -1
  32. package/dist/components/badge.js +1 -1
  33. package/dist/components/billing-interval-toggle.cjs +1 -1
  34. package/dist/components/billing-interval-toggle.d.ts +4 -6
  35. package/dist/components/billing-interval-toggle.js +26 -19
  36. package/dist/components/blockquote.cjs +1 -1
  37. package/dist/components/blockquote.js +3 -3
  38. package/dist/components/breadcrumb.cjs +1 -1
  39. package/dist/components/breadcrumb.js +2 -2
  40. package/dist/components/button-group.cjs +1 -1
  41. package/dist/components/button-group.js +1 -1
  42. package/dist/components/button.cjs +1 -1
  43. package/dist/components/button.d.ts +2 -0
  44. package/dist/components/button.js +79 -36
  45. package/dist/components/calendar.cjs +1 -1
  46. package/dist/components/calendar.js +1 -1
  47. package/dist/components/callout.cjs +1 -1
  48. package/dist/components/callout.js +14 -14
  49. package/dist/components/card.cjs +1 -1
  50. package/dist/components/card.js +1 -1
  51. package/dist/components/charts/shared.d.ts +15 -0
  52. package/dist/components/charts.cjs +1 -1
  53. package/dist/components/charts.js +1 -1
  54. package/dist/components/checkbox.cjs +1 -1
  55. package/dist/components/checkbox.js +3 -3
  56. package/dist/components/code.cjs +3 -3
  57. package/dist/components/code.js +4 -4
  58. package/dist/components/command.cjs +1 -1
  59. package/dist/components/command.d.ts +8 -1
  60. package/dist/components/command.js +84 -83
  61. package/dist/components/confirm-dialog.cjs +1 -1
  62. package/dist/components/confirm-dialog.d.ts +8 -1
  63. package/dist/components/confirm-dialog.js +37 -31
  64. package/dist/components/copy-button.cjs +1 -1
  65. package/dist/components/copy-button.js +3 -2
  66. package/dist/components/currency.cjs +1 -1
  67. package/dist/components/currency.js +1 -1
  68. package/dist/components/datatable/types.d.ts +4 -0
  69. package/dist/components/datatable.cjs +1 -1
  70. package/dist/components/datatable.d.ts +1 -5
  71. package/dist/components/datatable.js +1 -1
  72. package/dist/components/datepicker.cjs +1 -1
  73. package/dist/components/datepicker.d.ts +3 -3
  74. package/dist/components/datepicker.js +234 -105
  75. package/dist/components/description-list.cjs +1 -1
  76. package/dist/components/description-list.js +1 -1
  77. package/dist/components/divider.cjs +1 -1
  78. package/dist/components/divider.js +1 -1
  79. package/dist/components/drawer.cjs +1 -1
  80. package/dist/components/drawer.d.ts +6 -1
  81. package/dist/components/drawer.js +128 -2
  82. package/dist/components/dropdown-menu-panel.cjs +1 -0
  83. package/dist/components/dropdown-menu-panel.d.ts +24 -0
  84. package/dist/components/dropdown-menu-panel.js +84 -0
  85. package/dist/components/dropdown-menu.cjs +1 -1
  86. package/dist/components/dropdown-menu.d.ts +5 -1
  87. package/dist/components/dropdown-menu.js +38 -93
  88. package/dist/components/empty-state.cjs +1 -1
  89. package/dist/components/empty-state.d.ts +5 -1
  90. package/dist/components/empty-state.js +9 -9
  91. package/dist/components/error-state.cjs +1 -1
  92. package/dist/components/error-state.js +2 -2
  93. package/dist/components/file-upload.cjs +1 -1
  94. package/dist/components/file-upload.js +4 -4
  95. package/dist/components/form-field.cjs +1 -1
  96. package/dist/components/form-field.d.ts +9 -0
  97. package/dist/components/form-field.js +49 -14
  98. package/dist/components/info-button.cjs +1 -1
  99. package/dist/components/info-button.d.ts +5 -3
  100. package/dist/components/info-button.js +33 -29
  101. package/dist/components/input.cjs +1 -1
  102. package/dist/components/input.js +3 -3
  103. package/dist/components/kbd.cjs +1 -1
  104. package/dist/components/kbd.js +1 -1
  105. package/dist/components/label.cjs +1 -1
  106. package/dist/components/label.js +2 -2
  107. package/dist/components/layout.cjs +1 -1
  108. package/dist/components/layout.js +1 -1
  109. package/dist/components/link.cjs +1 -1
  110. package/dist/components/link.js +1 -1
  111. package/dist/components/list.cjs +1 -1
  112. package/dist/components/list.js +1 -1
  113. package/dist/components/modal.cjs +1 -1
  114. package/dist/components/modal.d.ts +8 -1
  115. package/dist/components/modal.js +74 -120
  116. package/dist/components/navigation.cjs +1 -1
  117. package/dist/components/navigation.js +2 -2
  118. package/dist/components/number-input.cjs +1 -1
  119. package/dist/components/number-input.js +3 -3
  120. package/dist/components/otp-input.cjs +1 -1
  121. package/dist/components/otp-input.js +2 -2
  122. package/dist/components/overlay.cjs +1 -0
  123. package/dist/components/overlay.d.ts +52 -0
  124. package/dist/components/overlay.js +87 -0
  125. package/dist/components/pagination.cjs +1 -1
  126. package/dist/components/pagination.js +2 -2
  127. package/dist/components/popover.cjs +1 -1
  128. package/dist/components/popover.d.ts +2 -1
  129. package/dist/components/popover.js +41 -40
  130. package/dist/components/progressbar.cjs +1 -1
  131. package/dist/components/progressbar.js +1 -1
  132. package/dist/components/radio.cjs +1 -1
  133. package/dist/components/radio.js +3 -3
  134. package/dist/components/rating.cjs +1 -1
  135. package/dist/components/rating.js +3 -3
  136. package/dist/components/richtext.cjs +1 -1
  137. package/dist/components/richtext.js +45 -18
  138. package/dist/components/scroll-area.cjs +1 -1
  139. package/dist/components/scroll-area.js +3 -3
  140. package/dist/components/select/option-list.d.ts +3 -1
  141. package/dist/components/select/types.d.ts +4 -0
  142. package/dist/components/select.cjs +1 -1
  143. package/dist/components/select.js +1 -1
  144. package/dist/components/seo.cjs +1 -1
  145. package/dist/components/seo.js +1 -1
  146. package/dist/components/separator.cjs +1 -1
  147. package/dist/components/separator.js +1 -1
  148. package/dist/components/skeleton.cjs +1 -1
  149. package/dist/components/skeleton.d.ts +14 -1
  150. package/dist/components/skeleton.js +56 -4
  151. package/dist/components/slider.cjs +1 -1
  152. package/dist/components/slider.js +2 -2
  153. package/dist/components/slot.cjs +1 -0
  154. package/dist/components/slot.d.ts +12 -0
  155. package/dist/components/slot.js +16 -0
  156. package/dist/components/snackbar-viewport.cjs +1 -0
  157. package/dist/components/snackbar-viewport.d.ts +27 -0
  158. package/dist/components/snackbar-viewport.js +181 -0
  159. package/dist/components/snackbar.cjs +1 -1
  160. package/dist/components/snackbar.d.ts +5 -1
  161. package/dist/components/snackbar.js +36 -200
  162. package/dist/components/spinner.cjs +1 -1
  163. package/dist/components/spinner.js +1 -1
  164. package/dist/components/stat.cjs +1 -1
  165. package/dist/components/stat.js +1 -1
  166. package/dist/components/status-dot.cjs +1 -1
  167. package/dist/components/status-dot.js +1 -1
  168. package/dist/components/stepper.cjs +1 -1
  169. package/dist/components/stepper.js +5 -5
  170. package/dist/components/switch.cjs +1 -1
  171. package/dist/components/switch.js +37 -43
  172. package/dist/components/table.cjs +1 -1
  173. package/dist/components/table.js +1 -1
  174. package/dist/components/tabs.cjs +1 -1
  175. package/dist/components/tabs.d.ts +6 -4
  176. package/dist/components/tabs.js +51 -81
  177. package/dist/components/tag.cjs +1 -1
  178. package/dist/components/tag.js +1 -1
  179. package/dist/components/terminal.cjs +1 -1
  180. package/dist/components/terminal.js +1 -1
  181. package/dist/components/textarea.cjs +1 -1
  182. package/dist/components/textarea.js +3 -3
  183. package/dist/components/theme-provider.cjs +1 -1
  184. package/dist/components/theme-provider.js +1 -1
  185. package/dist/components/theme-toggle.cjs +1 -1
  186. package/dist/components/theme-toggle.js +27 -3
  187. package/dist/components/time-picker.cjs +1 -1
  188. package/dist/components/time-picker.d.ts +2 -0
  189. package/dist/components/time-picker.js +206 -148
  190. package/dist/components/timeline.cjs +1 -1
  191. package/dist/components/timeline.js +1 -1
  192. package/dist/components/toggle.cjs +1 -1
  193. package/dist/components/toggle.js +2 -2
  194. package/dist/components/tooltip.cjs +1 -1
  195. package/dist/components/tooltip.d.ts +2 -1
  196. package/dist/components/tooltip.js +37 -36
  197. package/dist/components/tree.cjs +1 -1
  198. package/dist/components/tree.js +1 -1
  199. package/dist/components/typography.cjs +1 -1
  200. package/dist/components/typography.d.ts +2 -3
  201. package/dist/components/typography.js +37 -24
  202. package/dist/components/visually-hidden.cjs +1 -0
  203. package/dist/components/visually-hidden.d.ts +16 -0
  204. package/dist/components/visually-hidden.js +13 -0
  205. package/dist/{datatable-yBN4M3UV.js → datatable-BJoZMrKI.js} +6 -6
  206. package/dist/datatable-t0U7t_xh.cjs +1 -0
  207. package/dist/icons-Dfetr1L2.cjs +1 -0
  208. package/dist/icons-Dk7VZ4Ph.js +51 -0
  209. package/dist/index.cjs +1 -1
  210. package/dist/index.d.ts +4 -0
  211. package/dist/index.js +126 -99
  212. package/dist/lib/cn.d.ts +13 -1
  213. package/dist/lib/component-styles.d.ts +14 -2
  214. package/dist/lib/icons.d.ts +12 -0
  215. package/dist/lib/motion.d.ts +58 -0
  216. package/dist/motion-B2shivEB.cjs +1 -0
  217. package/dist/motion-gnRzFS5f.js +62 -0
  218. package/dist/select-ByjnuEcE.cjs +1 -0
  219. package/dist/{select-ClWrcj3R.js → select-CiMzLhUK.js} +128 -122
  220. package/dist/styles.css +1 -1
  221. package/dist/{terminal-CpraMs50.cjs → terminal-1U0ftG3i.cjs} +2 -2
  222. package/dist/{terminal-BOR2cFi1.js → terminal-VXdxVoAv.js} +4 -4
  223. package/dist/use-focus-trap-CPLT49gN.cjs +1 -0
  224. package/dist/use-focus-trap-CS6BXJAB.js +77 -0
  225. package/dist/{utils-CQ8pvCtk.js → utils-DEw5mQrH.js} +1 -1
  226. package/dist/{utils-DOFJTw8o.cjs → utils-MnnCTelh.cjs} +1 -1
  227. package/package.json +56 -9
  228. package/dist/autocomplete-Bk4pRQ2R.cjs +0 -1
  229. package/dist/calendar-CUXpVrVE.cjs +0 -1
  230. package/dist/charts-UDqS1BH1.cjs +0 -1
  231. package/dist/cn-BdjraxxU.cjs +0 -1
  232. package/dist/component-styles-DOUctc8_.cjs +0 -1
  233. package/dist/createLucideIcon-DDY8HuQR.js +0 -42
  234. package/dist/createLucideIcon-b_X_3fj-.cjs +0 -1
  235. package/dist/datatable-rzDgQ3r6.cjs +0 -1
  236. package/dist/drawer-CTeBsYrO.cjs +0 -1
  237. package/dist/drawer-ixuzyLVS.js +0 -189
  238. package/dist/select-BFwx--uK.cjs +0 -1
  239. package/dist/theme-toggle-Bb0BYo51.js +0 -71
  240. package/dist/theme-toggle-Cld8tktJ.cjs +0 -1
package/README.md CHANGED
@@ -1,6 +1,74 @@
1
- # rui
1
+ # @bzync/rui
2
2
 
3
- Composable React UI components with scoped, customizable light and dark themes.
3
+ Composable React UI components with scoped, fully customizable light and dark themes.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@bzync/rui.svg)](https://www.npmjs.com/package/@bzync/rui)
6
+ [![npm downloads](https://img.shields.io/npm/dm/@bzync/rui.svg)](https://www.npmjs.com/package/@bzync/rui)
7
+ [![gzip size](https://img.shields.io/bundlephobia/minzip/@bzync/rui.svg)](https://bundlephobia.com/package/@bzync/rui)
8
+ [![types included](https://img.shields.io/npm/types/@bzync/rui.svg)](https://www.npmjs.com/package/@bzync/rui)
9
+ [![license](https://img.shields.io/npm/l/@bzync/rui.svg)](./LICENSE)
10
+
11
+ `@bzync/rui` (**r**eact **ui**) is the component library behind [Bzync](https://www.bzync.com).
12
+ It ships 79 components plus a small SVG chart set, a token-driven theming system, and
13
+ production-grade lifecycle primitives — with **zero runtime dependencies**.
14
+
15
+ - **Zero runtime dependencies.** `dependencies` is empty. `react`, `react-dom`, and
16
+ `framer-motion` are peer dependencies you already control.
17
+ - **Scoped theming.** `ThemeProvider` renders a `.rui-theme` scope, so you can run
18
+ multiple themes on one page or theme a subtree without touching `<html>`.
19
+ - **Token-driven.** Override accent and neutral scales, radii, fonts, spacing, shadows,
20
+ or any CSS variable through a single `palette` prop — per theme.
21
+ - **Light and dark, controlled or uncontrolled.** System-preference tracking and
22
+ persistent selection are built in.
23
+ - **Accessible by default.** Native semantics, keyboard behavior, focus management,
24
+ focus trapping, scroll-lock restoration, and `prefers-reduced-motion` support.
25
+ - **ESM and CJS.** Dual builds, per-component subpath exports, `sideEffects` metadata
26
+ for tree-shaking, and readable (unminified) published output.
27
+ - **Typed.** Written in TypeScript; declaration files ship with the package.
28
+ - **RSC-friendly.** Client components are marked `"use client"`; server components can
29
+ import and render them directly.
30
+ - **React 18.2 and React 19.**
31
+
32
+ ## Table of contents
33
+
34
+ - [Installation](#installation)
35
+ - [Quick start](#quick-start)
36
+ - [The stylesheet](#the-stylesheet)
37
+ - [Theming](#theming)
38
+ - [Importing components](#importing-components)
39
+ - [Server components and SSR](#server-components-and-ssr)
40
+ - [Accessibility and motion](#accessibility-and-motion)
41
+ - [Component catalog](#component-catalog)
42
+ - [Common recipes](#common-recipes)
43
+ - [Charts](#charts)
44
+ - [Hooks and utilities](#hooks-and-utilities)
45
+ - [TypeScript](#typescript)
46
+ - [Browser and React support](#browser-and-react-support)
47
+ - [Versioning](#versioning)
48
+ - [Documentation](#documentation)
49
+ - [Contributing](#contributing)
50
+ - [Security](#security)
51
+ - [License](#license)
52
+
53
+ ## Installation
54
+
55
+ ```sh
56
+ npm install @bzync/rui framer-motion
57
+ ```
58
+
59
+ ```sh
60
+ pnpm add @bzync/rui framer-motion
61
+ ```
62
+
63
+ ```sh
64
+ yarn add @bzync/rui framer-motion
65
+ ```
66
+
67
+ `react` and `react-dom` (`^18.2.0 || ^19.0.0`) and `framer-motion` (`^13.1.0`) are peer
68
+ dependencies. `framer-motion` powers the animated overlays (Modal, Drawer, Popover,
69
+ Snackbar); it is kept off the critical path and loaded only by the components that use it.
70
+
71
+ ## Quick start
4
72
 
5
73
  ```tsx
6
74
  import { Button, ThemeProvider, ThemeToggle } from "@bzync/rui"
@@ -27,94 +95,445 @@ export function App() {
27
95
  }
28
96
  ```
29
97
 
30
- Every component accepts `className` (and native element props where applicable), so one-off
31
- changes compose with the defaults. `ThemeProvider` supports controlled or uncontrolled themes,
32
- system preference, persistent selection, scoped themes, custom accent/neutral scales, and any
33
- CSS variable through `tokens`. `ThemeToggle` accepts custom icons, labels, and classes.
98
+ Every component accepts `className` (and native element props where applicable), so
99
+ one-off changes compose with the defaults instead of fighting them.
34
100
 
35
- ## Installation
101
+ ## The stylesheet
36
102
 
37
- ```sh
38
- npm install @bzync/rui framer-motion
103
+ Import the core stylesheet once, near the application root:
104
+
105
+ ```tsx
106
+ import "@bzync/rui/styles.css"
39
107
  ```
40
108
 
41
- Import the core stylesheet once near the application root:
109
+ It defines the semantic design tokens, the `.rui-theme` scope, the dark-mode variant,
110
+ and component styles. It does **not** download or bundle webfonts — `@bzync/rui` uses
111
+ system fallbacks by default to keep the stylesheet small and avoid unexpected network
112
+ requests. Load any font in your application and override `--font-sans`, `--font-display`,
113
+ and `--font-mono` on `.rui-theme` (or via `ThemeProvider`'s `fonts` option).
114
+
115
+ ## Theming
116
+
117
+ ### ThemeProvider
118
+
119
+ `ThemeProvider` establishes a theme scope. Place one near the root, or wrap any subtree
120
+ to give it its own theme.
42
121
 
43
122
  ```tsx
44
- import "@bzync/rui/styles.css"
123
+ import { ThemeProvider } from "@bzync/rui"
124
+
125
+ <ThemeProvider
126
+ defaultTheme="system" // "light" | "dark" | "system"
127
+ storageKey="app-theme" // localStorage key, or false to disable persistence
128
+ applyToRoot // also toggle the `dark` class on <html>
129
+ palette={{ accent, neutral, radius, fonts, spacing, shadows, colors, tokens }}
130
+ lightPalette={{ /* overrides applied only in light mode */ }}
131
+ darkPalette={{ /* overrides applied only in dark mode */ }}
132
+ >
133
+ {children}
134
+ </ThemeProvider>
135
+ ```
136
+
137
+ Controlled usage is supported by passing `theme` and `onThemeChange` instead of
138
+ `defaultTheme`.
139
+
140
+ **Palette shape** (`ThemePalette`, all fields optional):
141
+
142
+ | Field | Type | Purpose |
143
+ |---|---|---|
144
+ | `accent` | `Partial<Record<50‥950, string>>` | Primary/action color scale |
145
+ | `neutral` | `Partial<Record<50‥950, string>>` | Grayscale / surfaces / borders |
146
+ | `colors` | `ThemeColors` | Named semantic colors (bg, surface, foreground, border, status colors, focus ring…) |
147
+ | `radius` | `Partial<Record<"sm"‥"2xl" \| "full", string>>` | Corner radii |
148
+ | `fonts` | `ThemeFonts` | `sans`, `display`, `mono` families |
149
+ | `spacing` | `Record<string, string>` | Spacing scale entries |
150
+ | `shadows` | `Partial<Record<"xs"‥"2xl", string>>` | Elevation shadows |
151
+ | `tokens` | `Partial<Record<\`--${string}\`, string \| number>>` | Any CSS custom property, escape hatch |
152
+
153
+ ### useTheme
154
+
155
+ ```tsx
156
+ import { useTheme } from "@bzync/rui"
157
+
158
+ function Example() {
159
+ const { theme, resolvedTheme, setTheme, toggleTheme } = useTheme()
160
+ // theme: "light" | "dark" | "system" (the user's selection)
161
+ // resolvedTheme: "light" | "dark" (after resolving "system")
162
+ return <button onClick={toggleTheme}>Now: {resolvedTheme}</button>
163
+ }
45
164
  ```
46
165
 
47
- rui does not download or bundle webfonts. It uses system fallbacks by default, keeping the
48
- core stylesheet small and avoiding unexpected network requests. Applications can load any font
49
- and override `--font-sans`, `--font-display`, and `--font-mono` on `.rui-theme`.
166
+ `useTheme` must be called inside a `ThemeProvider`.
167
+
168
+ ### ThemeToggle
169
+
170
+ ```tsx
171
+ import { ThemeToggle } from "@bzync/rui"
172
+
173
+ <ThemeToggle
174
+ showLabel
175
+ lightLabel="Light"
176
+ darkLabel="Dark"
177
+ lightIcon={<SunIcon />}
178
+ darkIcon={<MoonIcon />}
179
+ />
180
+ ```
181
+
182
+ Renders a button with `aria-pressed` and an `aria-label` that reflects the current state.
183
+
184
+ ### Semantic tokens
185
+
186
+ Author custom components against the semantic tokens rather than raw palette values:
187
+ `bg`, `surface`, `surface-raised`, `surface-muted`, `foreground`, `muted-foreground`,
188
+ `border`, `border-strong`, `primary`, `primary-foreground`, `destructive`, the status
189
+ colors, and `focus-ring`. They adapt to light/dark and to any palette override
190
+ automatically.
191
+
192
+ ## Importing components
193
+
194
+ The root entry re-exports everything for convenience:
195
+
196
+ ```tsx
197
+ import { Button, Modal, DataTable } from "@bzync/rui"
198
+ ```
199
+
200
+ Per-component subpath entries let a bundler pull in only what an application uses:
201
+
202
+ ```tsx
203
+ import { Button } from "@bzync/rui/button"
204
+ import { Modal } from "@bzync/rui/modal"
205
+ import { BarChart } from "@bzync/rui/charts"
206
+ ```
207
+
208
+ Both forms are tree-shakeable — the package sets `"sideEffects": ["**/*.css"]` and ships
209
+ ESM — but subpath imports keep dependency graphs smallest and are the recommended default
210
+ for libraries and performance-sensitive apps.
211
+
212
+ ## Server components and SSR
213
+
214
+ Client components are marked with the `"use client"` directive, so React Server
215
+ Components and frameworks like Next.js App Router can import and render them directly.
216
+ `ThemeProvider` reads `localStorage` only on the client and resolves `"system"` with
217
+ `matchMedia`; render it in a client boundary and pass a `defaultTheme` so the server and
218
+ first client paint agree.
50
219
 
51
220
  ## Accessibility and motion
52
221
 
53
- Interactive components expose native semantics and keyboard behavior. Modal dialogs label their
54
- content, trap keyboard focus, close with Escape, restore the previously focused element, and
55
- preserve the page's prior scroll-lock state. rui also disables nonessential animation within its
56
- theme scope when the user requests reduced motion.
222
+ - Interactive components expose native element semantics and keyboard behavior.
223
+ - Modal dialogs label their content, trap keyboard focus, close on <kbd>Escape</kbd>,
224
+ restore focus to the previously focused element on close, and preserve the page's
225
+ prior scroll-lock state.
226
+ - Menus, listboxes, tabs, and toggles implement roving focus and arrow-key navigation.
227
+ - Non-essential animation inside the `.rui-theme` scope is disabled when the user has
228
+ `prefers-reduced-motion: reduce` set.
229
+ - Icon-only controls (`IconButton`, `InfoButton`, `CopyButton`) require an accessible
230
+ `label`.
231
+
232
+ ## Component catalog
233
+
234
+ Import any of these from the root or from `@bzync/rui/<kebab-name>`.
235
+
236
+ ### Providers and theming
237
+
238
+ | Component / export | Notes |
239
+ |---|---|
240
+ | `ThemeProvider` | Token-driven theme scope; light/dark, controlled or uncontrolled, persistence, `applyToRoot` |
241
+ | `useTheme()` | `{ theme, resolvedTheme, setTheme, toggleTheme }` |
242
+ | `ThemeToggle` | Accessible light/dark switch with custom icons and labels |
243
+ | `SnackbarProvider` / `useSnackbar()` | Programmatic toast notifications |
244
+ | `CommandProvider` / `CommandPalette` | App-wide searchable command palette |
245
+ | `cn()` | `clsx` + `tailwind-merge` class combiner |
246
+
247
+ ### Actions
248
+
249
+ | Component | Key props |
250
+ |---|---|
251
+ | `Button` | `variant: primary \| secondary \| ghost \| outline \| destructive \| link`, `size: sm \| md \| lg \| icon`, `loading`, `icon`, `iconPosition` |
252
+ | `ButtonGroup` | `orientation`, `aria-label`; wraps `Button` children with `role="group"` |
253
+ | `IconButton` / `InfoButton` | `label` (required for a11y), icon |
254
+ | `CopyButton` | `value` (text to copy), `label`, `timeout` |
255
+ | `Toggle` / `ToggleGroup` / `ToggleGroupItem` | `pressed` / `defaultPressed`, `onPressedChange`, `type: single \| multiple`, `variant`, `size`, `orientation`, `loop` |
256
+ | `BillingIntervalToggle` | `value: monthly \| yearly`, `onChange` |
57
257
 
58
- ## Component imports
258
+ ### Forms
59
259
 
60
- Use subpath imports when an application only needs a small part of the library:
260
+ | Component | Key props |
261
+ |---|---|
262
+ | `Input` | `label`, `hint`, `error`, `prefix` / `suffix`, `size` |
263
+ | `Textarea` | `label`, `hint`, `error`, `rows` |
264
+ | `NumberInput` | `value` / `defaultValue`, `min`, `max`, `step`, `onChange` |
265
+ | `OtpInput` | `length`, `value`, `onChange`, `label` |
266
+ | `Select` | `options`, `label`, `multiple`, groups, searchable, `onChange` |
267
+ | `Autocomplete` | `options`, `multiple`, custom filter, single/multi triggers |
268
+ | `Checkbox` | `label`, `checked` / `defaultChecked`, `onCheckedChange` |
269
+ | `Radio` / `RadioGroup` | `value`, `onChange`, `options` |
270
+ | `Switch` | `label`, `checked`, `onCheckedChange` |
271
+ | `Slider` | `value` / `defaultValue`, `min`, `max`, `step`, `label` |
272
+ | `Rating` | `value` / `defaultValue`, `max`, `size`, `readOnly`, `onValueChange` |
273
+ | `DatePicker` | `label`, `value`, `onChange` |
274
+ | `Calendar` | `value: Date`, `onChange`, month/week views |
275
+ | `TimePicker` | `value` / `defaultValue`, `format: 12 \| 24`, `minuteStep`, `showSeconds`, `min` / `max`, `clearable` |
276
+ | `FileUpload` | `label`, `accept`, `multiple`, `onFilesChange` |
277
+ | `Label` | `htmlFor`, `required`, `hint` |
278
+ | `FormField` | `label`, `htmlFor`, `required`, `hint`, `error` — wraps a control |
279
+ | `Stepper` | `steps`, `activeStep` |
280
+ | `Kbd` | keyboard-key children |
281
+
282
+ ### Display
283
+
284
+ | Component | Key props |
285
+ |---|---|
286
+ | `Badge` / `Tag` | `variant`, `dot`; `Tag` adds `onRemove` |
287
+ | `Avatar` / `AvatarGroup` / `AvatarGroupOverflow` | `name`, `src`, `size`, initials fallback; group `spacing`, `count` |
288
+ | `Card` (`CardHeader` / `CardTitle` / `CardDescription` / `CardBody` / `CardFooter`) | composition |
289
+ | `Callout` / `Alert` | `title`, `variant`; `Alert` adds `dismissable`, `onDismiss` |
290
+ | `Stat` / `StatusDot` | `Stat`: `label`, `value`, `trend`, `trendValue`; `StatusDot`: `status`, `label` |
291
+ | `Tooltip` | `content`, trigger child |
292
+ | `Link` | `href`, `variant` |
293
+ | `Typography`: `Heading` / `Text` / `Prose` / `Time` | `Heading`: `as h1‥h6`, `size`, `tone`, `weight`, `balance`; `Text`: `variant`, `size`, number/date/currency formatting; `Time`: renders `<time datetime>` |
294
+ | `Code` / `InlineCode` / `CodeBlock` / `CodeEditor` | `code`, `filename`, `showLineNumbers`, `value` / `onChange` |
295
+ | `Blockquote` | `variant`, `size`, `cite`, `source` / `sourceHref` |
296
+ | `Currency` | `value: number \| bigint`, `currency`, `locale`, `accounting`, `tone`, `size` |
297
+ | `DescriptionList` (`DescriptionItem` / `DescriptionTerm` / `DescriptionDetails`) | `columns: 1 \| 2 \| 3`, `density`, `orientation` |
298
+ | `List` / `ListItem`, `Timeline`, `Tree` | item collections; `Tree` is expandable |
299
+ | `Table` (`TableHeader` / `TableHead` / `TableBody` / `TableRow` / `TableCell`) | styled primitive table |
300
+ | `Divider` / `Separator` | `orientation`, `variant`, `spacing`, optional `label` |
301
+ | `ScrollArea` | `orientation: vertical \| horizontal \| both`, `hideScrollbar`, `keyboardNavigable` |
302
+ | `AspectRatio` | `ratio: number` |
303
+ | `Skeleton` (+ `SkeletonAvatar` / `SkeletonCard` / `SkeletonTable` / `SkeletonText` / `SkeletonTopbar`) | loading placeholders |
304
+ | `Spinner` / `Progressbar` | `size`; `value`, `max` |
305
+ | `EmptyState` / `ErrorState` | `title`, `description`, `error`, action slot |
306
+ | `RichText` / `RichTextEditor` | rendered content and editor |
307
+ | `AuthBackdrop` | decorative auth-screen background |
308
+
309
+ ### Overlays and feedback
310
+
311
+ | Component | Key props |
312
+ |---|---|
313
+ | `Modal` (`ModalHeader` / `ModalTitle` / `ModalDescription` / `ModalBody` / `ModalFooter`) | `open`, `onClose`, `title`, `size: sm‥7xl \| full`, `ModalBody` `scrollable` |
314
+ | `Drawer` | `open`, `onClose`, `title`, `size`, focus trap |
315
+ | `ConfirmDialog` | `open`, `onConfirm`, `onCancel`, `title` |
316
+ | `Popover` / `PopoverContent` | trigger, `open` / `onOpenChange` |
317
+ | `DropdownMenu` | `trigger`, `items: { label, onClick }[]` |
318
+ | `Command` / `CommandPalette` / `CommandProvider` | searchable command palette |
319
+ | `SnackbarProvider` / `useSnackbar()` | queue and dismiss toasts programmatically |
320
+ | `Tabs` (`TabsList` / `TabsTrigger` / `TabsContent`) | `value`, `onValueChange` |
321
+ | `Accordion` | `items: { id, trigger, content }[]` |
322
+ | `Pagination` | `page`, `totalPages`, `onPageChange` |
323
+ | `Terminal` / `TerminalBlock` / `TerminalEmulator` | virtual filesystem, runnable shell commands |
324
+
325
+ ### Navigation and layout
326
+
327
+ | Component | Key props |
328
+ |---|---|
329
+ | `AppShell` (`AppShellHeader` / `AppShellBody` / `AppShellMain` / `Footer`) | app frame; `sticky`, `scrollable`, `fixed` |
330
+ | `Container` | `size: sm‥xl \| full`, `gutter` |
331
+ | `Stack` / `Inline` / `PageHeader` | spacing and header primitives |
332
+ | `Navbar` / `Sidebar` / `Topbar` / `BottomBar` | `items: NavigationItem[]`, `activeId`, `onSelect` |
333
+ | `NavigationLink` | `id`, `label`, `href`, `icon`, `badge`, `active`, `compact` |
334
+ | `Breadcrumb` | `items` |
335
+ | `SEO` | document head tags |
336
+
337
+ ### Data
338
+
339
+ | Component | Key props |
340
+ |---|---|
341
+ | `DataTable<T>` | `columns: ColumnDef<T>[]` (`{ key, header, cell, sortable?, searchable?, align?, width? }`), `data: T[]`, `searchable`, `searchPlaceholder`, `pageSizeOptions`, `density`, `loading`, `emptyMessage`, `onRowClick`, `unstyled` — built-in sort, search, and pagination. `T` must have an `id`. |
342
+
343
+ ## Common recipes
344
+
345
+ ### Button
61
346
 
62
347
  ```tsx
63
348
  import { Button } from "@bzync/rui/button"
349
+
350
+ <Button variant="primary" size="lg" loading={isSaving} onClick={save}>
351
+ Save changes
352
+ </Button>
353
+
354
+ <Button variant="outline" icon={<PlusIcon />} iconPosition="left">
355
+ New item
356
+ </Button>
64
357
  ```
65
358
 
66
- The root export remains available for convenience. React 18.2 and React 19 are supported.
359
+ ### A labelled, validated field
67
360
 
68
- ## Documentation
361
+ ```tsx
362
+ import { FormField } from "@bzync/rui/form-field"
363
+ import { Input } from "@bzync/rui/input"
69
364
 
70
- The component documentation and live demos are published to
71
- [bzync.github.io/rui](https://bzync.github.io/rui/). A push to `main` deploys
72
- the latest documentation through GitHub Pages; maintainers can also run the
73
- **Deploy documentation** workflow manually from the Actions tab.
365
+ <FormField label="Email" htmlFor="email" required error={errors.email}>
366
+ <Input id="email" type="email" value={email} onChange={(e) => setEmail(e.target.value)} />
367
+ </FormField>
368
+ ```
74
369
 
75
- ## Support
370
+ ### Select
76
371
 
77
- If `@bzync/rui` is useful to you, you can support its continued development on
78
- [Buy Me a Coffee](https://buymeacoffee.com/adminjw).
372
+ ```tsx
373
+ import { Select } from "@bzync/rui/select"
374
+
375
+ <Select
376
+ label="Environment"
377
+ options={[
378
+ { label: "Production", value: "prod" },
379
+ { label: "Staging", value: "staging" },
380
+ { label: "Development", value: "dev" },
381
+ ]}
382
+ value={env}
383
+ onChange={setEnv}
384
+ />
385
+ ```
79
386
 
80
- ## Releasing to npm
387
+ ### Modal
81
388
 
82
- Add an npm publishing token to the GitHub repository as an Actions secret named
83
- `NPM_TOKEN`. The release workflow runs when a `v*` tag is pushed and requires the
84
- tag to match the version in `package.json` exactly.
389
+ ```tsx
390
+ import { Modal, ModalBody, ModalFooter } from "@bzync/rui/modal"
391
+ import { Button } from "@bzync/rui/button"
85
392
 
86
- To publish the version currently declared in `package.json`:
393
+ const [open, setOpen] = useState(false)
87
394
 
88
- ```sh
89
- VERSION="$(node --print "require('./package.json').version")"
90
- git tag -a "v${VERSION}" -m "Release v${VERSION}"
91
- git push origin "v${VERSION}"
395
+ <Modal open={open} onClose={() => setOpen(false)} title="Delete project" size="sm">
396
+ <ModalBody>This action cannot be undone.</ModalBody>
397
+ <ModalFooter>
398
+ <Button variant="ghost" onClick={() => setOpen(false)}>Cancel</Button>
399
+ <Button variant="destructive" onClick={confirmDelete}>Delete</Button>
400
+ </ModalFooter>
401
+ </Modal>
92
402
  ```
93
403
 
94
- For later patch releases, commit all pending changes and run:
404
+ ### Toasts
95
405
 
96
- ```sh
97
- npm version patch
98
- git push origin HEAD --follow-tags
406
+ ```tsx
407
+ import { SnackbarProvider, useSnackbar } from "@bzync/rui/snackbar"
408
+
409
+ function Root() {
410
+ return (
411
+ <SnackbarProvider>
412
+ <App />
413
+ </SnackbarProvider>
414
+ )
415
+ }
416
+
417
+ function SaveButton() {
418
+ const { show } = useSnackbar()
419
+ return <Button onClick={() => show({ title: "Saved", variant: "success" })}>Save</Button>
420
+ }
99
421
  ```
100
422
 
101
- `npm version patch` updates `package.json` and `package-lock.json`, creates a
102
- release commit, and creates the matching version tag. Use `minor` or `major`
103
- instead of `patch` when appropriate. Before publishing, GitHub Actions runs the
104
- complete release check. It also generates npm provenance when the source
105
- repository is public; npm does not support provenance from private GitHub
106
- repositories.
423
+ `useSnackbar()` returns `{ show, dismiss, dismissAll }`. `show(opts)` returns the toast id;
424
+ pass a stable `id` in `opts` to replace an existing toast in place instead of stacking.
107
425
 
108
- ### Retrying a failed release
426
+ ### DataTable
109
427
 
110
- Do not move or reuse an existing version tag after its workflow fails. Commit
111
- the fixes, create the next patch version, and push its new tag:
428
+ ```tsx
429
+ import { DataTable } from "@bzync/rui/datatable"
112
430
 
113
- ```sh
114
- git add .
115
- git commit -m "Fix npm release workflow"
116
- npm version patch
117
- git push origin HEAD --follow-tags
431
+ type Row = { id: string; name: string; role: string; seats: number }
432
+
433
+ <DataTable<Row>
434
+ data={members}
435
+ columns={[
436
+ { key: "name", header: "Name", cell: (r) => r.name, sortable: true, searchable: true },
437
+ { key: "role", header: "Role", cell: (r) => r.role, sortable: true },
438
+ { key: "seats", header: "Seats", cell: (r) => r.seats, align: "right", sortable: true },
439
+ ]}
440
+ searchable
441
+ pageSizeOptions={[10, 25, 50]}
442
+ onRowClick={(row) => open(row.id)}
443
+ />
118
444
  ```
119
445
 
120
- For example, because `v0.0.2` failed, this creates and publishes `v0.0.3`.
446
+ ## Charts
447
+
448
+ The chart set is a separate subpath entry so it stays out of the main graph unless used.
449
+ Every chart renders plain SVG and takes data arrays — no canvas, no chart engine.
450
+
451
+ ```tsx
452
+ import { BarChart, LineChart, DonutChart } from "@bzync/rui/charts"
453
+
454
+ <BarChart data={[{ label: "Jan", value: 42 }, { label: "Feb", value: 55 }]} />
455
+ ```
456
+
457
+ Available: `BarChart`, `LineChart`, `MultiLineChart`, `DonutChart`, `ScatterChart`,
458
+ `GanttChart`, `HeatmapChart`, `RadarChart`, `FunnelChart`, `WaterfallChart`. See
459
+ [`src/components/charts`](./src/components/charts) for exact per-chart props.
460
+
461
+ ## Hooks and utilities
462
+
463
+ Lifecycle-correct hooks (mount/update/unmount with cleanup), re-exported from the root:
464
+
465
+ | Hook | Purpose |
466
+ |---|---|
467
+ | `useIsMounted()` | Guard async setState after unmount |
468
+ | `useIsomorphicLayoutEffect()` | `useLayoutEffect` on the client, `useEffect` on the server |
469
+ | `usePrevious(value)` | Previous render's value |
470
+ | `useUpdateEffect(fn, deps)` | Effect that skips the first render |
471
+ | `useEventCallback(fn)` | Stable callback identity with fresh closure |
472
+ | `useControllableState(opts)` | Controlled/uncontrolled state pattern |
473
+ | `useMediaQuery(query)` | Subscribe to a media query |
474
+ | `useAbortSignal()` | Abort in-flight work on unmount |
475
+ | `useFocusTrap(ref, active)` | Trap focus within a container |
476
+ | `useOutsideClick(ref, handler)` | Detect clicks outside an element |
477
+
478
+ Utilities: `cn()`, focus helpers, `Portal`, and assertion helpers from `@bzync/rui/utils`;
479
+ `ErrorBoundary` from the root; `createSafeEffect` and mount helpers from `@bzync/rui`'s
480
+ lifecycle exports; `KEY`, `DURATIONS`, and `FOCUSABLE_SELECTOR` constants.
481
+
482
+ ## TypeScript
483
+
484
+ `@bzync/rui` is written in TypeScript and ships `.d.ts` files for the root and every
485
+ subpath entry. Prop types, variant unions (`ButtonVariant`, `ButtonSize`, …), and the
486
+ theming types (`Theme`, `ThemePalette`, `ThemeColors`, `ColorShade`, …) are all exported.
487
+ No `@types/*` package is required.
488
+
489
+ ## Browser and React support
490
+
491
+ - **React** `^18.2.0 || ^19.0.0`
492
+ - **Modern evergreen browsers.** The library relies on CSS custom properties, `matchMedia`,
493
+ and standard DOM APIs; no polyfills are bundled.
494
+ - **SSR / RSC** via the `"use client"` boundary described above.
495
+
496
+ ## Bundle and dependencies
497
+
498
+ - `dependencies`: **none**. `clsx`/`tailwind-merge` logic is inlined; icons are inlined SVG.
499
+ - Published output is **not minified** — readable ESM and CJS ship to the registry so the
500
+ code is auditable; your bundler minifies the final app build.
501
+ - `sideEffects` is limited to `**/*.css`, so unused components are dropped by any
502
+ tree-shaking bundler.
503
+
504
+ ## Versioning
505
+
506
+ `@bzync/rui` follows [semantic versioning](https://semver.org/). While the major version
507
+ is `0`, minor releases may contain breaking changes; pin a version or a tight range and
508
+ review the release notes before upgrading. Releases are published from CI with npm
509
+ [provenance](https://docs.npmjs.com/generating-provenance-statements) attestations.
510
+
511
+ ## Documentation
512
+
513
+ Full component documentation and live, themeable demos are published at
514
+ **[bzync.github.io/rui](https://bzync.github.io/rui/)**. A push to `main` deploys the
515
+ latest docs via GitHub Pages.
516
+
517
+ ## Contributing
518
+
519
+ Bug reports, accessibility fixes, documentation improvements, and focused component
520
+ contributions are welcome. See [CONTRIBUTING.md](./CONTRIBUTING.md) for the development
521
+ setup, the verification gate, and the release process, and
522
+ [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md).
523
+
524
+ ## Security
525
+
526
+ Report vulnerabilities privately using the process in [SECURITY.md](./SECURITY.md).
527
+ Please do not open public issues for security reports.
528
+
529
+ ## License
530
+
531
+ [ISC](./LICENSE) © 2026 Bzync
532
+
533
+ ## Maintainer
534
+
535
+ `@bzync/rui` is maintained by [Rayan Reynaldo](https://www.bzync.com), Founder of Bzync
536
+ ([www.bzync.com](https://www.bzync.com)).
537
+
538
+ If `@bzync/rui` is useful to you, you can support its continued development on
539
+ [Buy Me a Coffee](https://buymeacoffee.com/adminjw).
@@ -0,0 +1 @@
1
+ const e=require("./cn-B6R3HKzx.cjs"),t=require("./component-styles-DY4wigiq.cjs"),n=require("./utils-MnnCTelh.cjs"),r=require("./use-event-callback-Du9_9eAi.cjs");let i=require("framer-motion"),a=require("react"),o=require("react/jsx-runtime"),s=require("react-dom");var c=({size:e=12})=>(0,o.jsx)(`svg`,{width:e,height:e,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2.5`,strokeLinecap:`round`,strokeLinejoin:`round`,children:(0,o.jsx)(`path`,{d:`M18 6 6 18M6 6l12 12`})}),l=()=>(0,o.jsxs)(`svg`,{className:`animate-spin shrink-0 w-3.5 h-3.5 text-slate-500`,viewBox:`0 0 24 24`,fill:`none`,children:[(0,o.jsx)(`circle`,{className:`opacity-20`,cx:`12`,cy:`12`,r:`10`,stroke:`currentColor`,strokeWidth:`3`}),(0,o.jsx)(`path`,{className:`opacity-70`,fill:`currentColor`,d:`M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z`})]});function u({text:e,query:t}){if(!t)return(0,o.jsx)(o.Fragment,{children:e});let n=e.toLowerCase().indexOf(t.toLowerCase());return n===-1?(0,o.jsx)(o.Fragment,{children:e}):(0,o.jsxs)(o.Fragment,{children:[e.slice(0,n),(0,o.jsx)(`mark`,{className:`bg-accent-500/25 text-accent-700 dark:text-accent-200 rounded-sm not-italic`,children:e.slice(n,n+t.length)}),e.slice(n+t.length)]})}function d({inputRef:n,inputId:r,listId:i,open:a,activeIdx:s,inputText:u,prefix:d,placeholder:f,disabled:p,error:m,loading:h,showClear:g,onInputChange:_,onFocus:v,onKeyDown:y,onClear:b,messageId:x,inputProps:S,className:C,inputClassName:w}){return(0,o.jsxs)(`div`,{className:e.t(`flex h-9 items-center gap-2 rounded-[var(--radius-md)] px-3`,t.t,m&&`border-destructive/60 hover:border-destructive/70 focus-within:border-destructive focus-within:ring-destructive/25`,p&&`opacity-50 cursor-not-allowed`,C),children:[d&&(0,o.jsx)(`span`,{className:`text-slate-500 shrink-0 text-sm`,children:d}),(0,o.jsx)(`input`,{...S,ref:n,id:r,role:`combobox`,"aria-autocomplete":`list`,"aria-expanded":a,"aria-controls":i,"aria-activedescendant":s>=0?`${i}-opt-${s}`:void 0,"aria-invalid":m?!0:void 0,"aria-describedby":x,autoComplete:`off`,value:u,onChange:_,onFocus:v,onKeyDown:y,placeholder:f,disabled:p,className:e.t(`flex-1 min-w-0 bg-transparent text-sm text-foreground placeholder:text-muted-foreground outline-none disabled:cursor-not-allowed`,w)}),h&&(0,o.jsx)(l,{}),g&&!h&&(0,o.jsx)(`button`,{type:`button`,onClick:b,className:`shrink-0 text-slate-500 hover:text-slate-600 dark:hover:text-slate-300 cursor-pointer transition-colors`,children:(0,o.jsx)(c,{})})]})}function f({inputRef:n,inputId:r,listId:i,open:a,activeIdx:s,inputText:u,prefix:d,placeholder:f,disabled:p,error:m,loading:h,showClear:g,selected:_,onContainerClick:v,onInputChange:y,onFocus:b,onKeyDown:x,onRemove:S,onClearAll:C,messageId:w,inputProps:T,className:ee,inputClassName:E}){return(0,o.jsxs)(`div`,{onClick:v,className:e.t(`flex min-h-9 w-full flex-wrap items-center gap-1.5 rounded-[var(--radius-md)] px-2.5 py-1.5 cursor-text`,t.t,m&&`border-destructive/60 hover:border-destructive/70 focus-within:border-destructive focus-within:ring-destructive/25`,p&&`opacity-50 cursor-not-allowed`,ee),children:[d&&(0,o.jsx)(`span`,{className:`text-slate-500 shrink-0 text-sm`,children:d}),_.map(e=>(0,o.jsxs)(`span`,{className:`inline-flex max-w-[200px] items-center gap-1 rounded-md border border-border bg-surface-muted px-2 py-0.5 text-xs font-medium text-foreground`,children:[e.icon&&(0,o.jsx)(`span`,{className:`shrink-0 text-slate-500 dark:text-slate-400`,children:e.icon}),(0,o.jsx)(`span`,{className:`truncate`,children:e.label}),(0,o.jsx)(`button`,{type:`button`,tabIndex:-1,onMouseDown:e=>e.preventDefault(),onClick:t=>{t.stopPropagation(),S(e)},disabled:p,className:`shrink-0 text-slate-500 dark:text-slate-400 hover:text-foreground transition-colors cursor-pointer ml-0.5`,"aria-label":`Remove ${e.label}`,children:(0,o.jsx)(c,{size:10})})]},String(e.value))),(0,o.jsx)(`input`,{...T,ref:n,id:r,role:`combobox`,"aria-autocomplete":`list`,"aria-expanded":a,"aria-controls":i,"aria-activedescendant":s>=0?`${i}-opt-${s}`:void 0,"aria-invalid":m?!0:void 0,"aria-describedby":w,autoComplete:`off`,value:u,onChange:y,onFocus:b,onKeyDown:x,placeholder:_.length===0?f:void 0,disabled:p,className:e.t(`flex-1 min-w-[80px] bg-transparent text-sm text-foreground placeholder:text-muted-foreground outline-none disabled:cursor-not-allowed py-0.5`,E)}),(0,o.jsxs)(`span`,{className:`ml-auto flex items-center gap-1.5 shrink-0`,children:[h&&(0,o.jsx)(l,{}),g&&!h&&(0,o.jsx)(`button`,{type:`button`,onMouseDown:e=>e.preventDefault(),onClick:e=>{e.stopPropagation(),C()},className:`text-slate-500 hover:text-slate-600 dark:hover:text-slate-300 transition-colors`,"aria-label":`Clear all`,children:(0,o.jsx)(c,{})}),_.length>0&&(0,o.jsx)(`span`,{className:`text-[10px] font-medium text-slate-500 tabular-nums`,children:_.length})]})]})}function p({listRef:t,listId:n,open:r,pos:a,multiple:c,loading:d,filtered:f,emptyMessage:p,activeIdx:m,setActiveIdx:h,inputText:g,selectedValues:_,singleValue:v,onSelectSingle:y,onToggleMulti:b,className:x,optionClassName:S,loadingClassName:C,emptyClassName:w}){return typeof document>`u`?null:(0,s.createPortal)((0,o.jsx)(i.AnimatePresence,{children:r&&a&&(0,o.jsx)(i.motion.ul,{ref:t,id:n,role:`listbox`,"aria-multiselectable":c,initial:{opacity:0,y:a.placement===`bottom`?-4:4},animate:{opacity:1,y:0},exit:{opacity:0,y:a.placement===`bottom`?-4:4},transition:{duration:.13},style:{position:`fixed`,top:a.top,left:a.left,width:a.width,maxHeight:a.maxHeight},className:e.t(`z-[110] overflow-y-auto rounded-[var(--radius-lg)] border border-border bg-surface-raised py-1 shadow-floating`,x),children:d?(0,o.jsxs)(`li`,{className:e.t(`px-4 py-3 text-sm text-slate-600 flex items-center gap-2`,C),children:[(0,o.jsx)(l,{}),`Loading…`]}):f.length===0?(0,o.jsx)(`li`,{className:e.t(`px-4 py-3 text-sm text-slate-600`,w),children:p}):f.map((t,r)=>{let i=r===m,a=c?_.includes(t.value):t.value===v;return(0,o.jsxs)(`li`,{id:`${n}-opt-${r}`,role:`option`,"aria-selected":a,onMouseDown:e=>e.preventDefault(),onClick:()=>c?b(t):y(t),onMouseEnter:()=>h(r),className:e.t(`flex min-h-9 items-center gap-3 px-3 py-2 cursor-pointer transition-colors`,i&&`bg-surface-muted`,a&&!i&&`bg-accent-50 dark:bg-accent-500/10`,S),children:[t.icon&&(0,o.jsx)(`span`,{className:`shrink-0 text-slate-500 dark:text-slate-400`,children:t.icon}),(0,o.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,o.jsx)(`p`,{className:e.t(`text-sm`,a?`text-accent-700 dark:text-accent-300 font-medium`:`text-foreground`),children:(0,o.jsx)(u,{text:t.label,query:g})}),t.description&&(0,o.jsx)(`p`,{className:`text-xs text-slate-500 mt-0.5 truncate`,children:t.description})]}),a&&(0,o.jsx)(`svg`,{"aria-hidden":`true`,width:`14`,height:`14`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2.5`,strokeLinecap:`round`,strokeLinejoin:`round`,className:`text-accent-600 shrink-0`,children:(0,o.jsx)(`path`,{d:`m20 6-11 11-5-5`})})]},String(t.value))})})}),document.body)}function m(i,s){let{options:c,inputValue:l,onInputChange:u,label:m,hint:h,error:g,prefix:_,clearable:v=!0,loading:y=!1,emptyMessage:b=`No results`,maxVisible:x=8,className:S,wrapperClassName:C,triggerClassName:w,inputClassName:T,labelClassName:ee,messageClassName:E,listClassName:te,optionClassName:ne,loadingClassName:re,emptyClassName:ie,placeholder:D,disabled:O,id:ae,multiple:k,unstyled:oe=!1,...se}=i,{value:ce,onSelect:le,onDeselect:ue,...A}=se,de=(0,a.useId)(),j=ae??de,M=`${j}-list`,N=`${j}-message`,[fe,pe]=(0,a.useState)(``),P=l===void 0?fe:l,me=r.t(e=>u?.(e)),F=(0,a.useCallback)(e=>{l===void 0?pe(e):me(e)},[l,me]),[he,I]=(0,a.useState)([]),L=(0,a.useMemo)(()=>{if(!k)return[];let e=i;return e.value===void 0?he:c.filter(t=>e.value.includes(t.value))},[k,c,i,he]),R=(0,a.useMemo)(()=>L.map(e=>e.value),[L]),[z,B]=(0,a.useState)(!1),[V,H]=(0,a.useState)(-1),U=(0,a.useRef)(null),W=(0,a.useRef)(null),G=(0,a.useRef)(null),[K,q]=(0,a.useState)(``),J=(0,a.useMemo)(()=>{let e=K.trim().toLowerCase();return c.filter(t=>!t.disabled&&t.label.toLowerCase().includes(e)).slice(0,x)},[c,K,x]),Y=(0,a.useCallback)(e=>{i.onSelect?.(e),F(e.label),B(!1),H(-1)},[i,F]),ge=(0,a.useCallback)(e=>{let t=i,n=[...L,e];t.value===void 0&&I(n),t.onSelect?.(e,n),F(``),H(-1),W.current?.focus()},[L,i,F]),X=(0,a.useCallback)(e=>{let t=i,n=L.filter(t=>t.value!==e.value);t.value===void 0&&I(n),t.onDeselect?.(e,n)},[L,i]),Z=(0,a.useCallback)(e=>{R.includes(e.value)?X(e):ge(e)},[R,X,ge]),_e=(0,a.useCallback)(()=>{F(``),i.onSelect?.({value:``,label:``}),B(!1)},[i,F]),ve=(0,a.useCallback)(()=>{i.value===void 0&&I([]),F(``)},[i,F]),ye=(0,a.useCallback)(e=>{if(k&&e.key===`Backspace`&&P===``&&L.length>0){X(L[L.length-1]);return}if(!z){(e.key===`ArrowDown`||e.key===`ArrowUp`)&&(B(!0),q(``));return}if(e.key===`ArrowDown`)e.preventDefault(),H(e=>Math.min(e+1,J.length-1));else if(e.key===`ArrowUp`)e.preventDefault(),H(e=>Math.max(e-1,0));else if(e.key===`Enter`){e.preventDefault();let t=J[V];if(!t)return;k?Z(t):Y(t)}else e.key===`Escape`&&(B(!1),H(-1))},[k,P,L,z,J,V,Z,Y,X]);(0,a.useEffect)(()=>{V<0||!G.current||G.current.children[V]?.scrollIntoView({block:`nearest`})},[V]),(0,a.useEffect)(()=>{function e(e){let t=e.target;!U.current?.contains(t)&&!G.current?.contains(t)&&B(!1)}return document.addEventListener(`mousedown`,e),()=>document.removeEventListener(`mousedown`,e)},[]);let be=k?void 0:i.value,xe=!!(!k&&v&&P.length>0&&!O),Se=!!(k&&v&&(L.length>0||P.length>0)&&!O),Ce=n.o(z,U),Q=(0,a.useCallback)(e=>{F(e.target.value),q(e.target.value),B(!0),H(-1)},[F]),$=(0,a.useCallback)(()=>{B(!0),q(``)},[]);return oe?(0,o.jsxs)(`div`,{ref:U,className:e.t(S,C),children:[(0,o.jsx)(`input`,{ref:s,id:j,value:P,onChange:Q,placeholder:D,disabled:O}),z&&(0,o.jsx)(`ul`,{ref:G,id:M,className:te,children:J.map(e=>(0,o.jsx)(`li`,{onClick:()=>k?Z(e):Y(e),children:e.label},String(e.value)))})]}):(0,o.jsxs)(`div`,{ref:U,className:e.t(`relative`,t.o,C,S),children:[m&&(0,o.jsxs)(`label`,{htmlFor:j,className:e.t(`text-xs font-semibold leading-5 text-foreground`,ee),children:[m,se.required&&(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(`span`,{"aria-hidden":`true`,className:`ml-1 text-destructive`,children:`*`}),(0,o.jsx)(`span`,{className:`sr-only`,children:` (required)`})]})]}),!k&&(0,o.jsx)(d,{inputRef:s,inputId:j,listId:M,open:z,activeIdx:V,inputText:P,prefix:_,placeholder:D,disabled:O,error:g,loading:y,showClear:xe,onInputChange:Q,onFocus:$,onKeyDown:ye,onClear:_e,messageId:g||h?N:void 0,inputProps:A,className:w,inputClassName:T}),k&&(0,o.jsx)(f,{inputRef:e=>{W.current=e,typeof s==`function`?s(e):s&&(s.current=e)},inputId:j,listId:M,open:z,activeIdx:V,inputText:P,prefix:_,placeholder:D,disabled:O,error:g,loading:y,showClear:Se,selected:L,onContainerClick:()=>{O||(W.current?.focus(),B(!0),q(``))},onInputChange:Q,onFocus:$,onKeyDown:ye,onRemove:X,onClearAll:ve,messageId:g||h?N:void 0,inputProps:A,className:w,inputClassName:T}),(0,o.jsx)(p,{listRef:G,listId:M,open:z,pos:Ce,multiple:k,loading:y,filtered:J,emptyMessage:b,activeIdx:V,setActiveIdx:H,inputText:K,selectedValues:R,singleValue:be,onSelectSingle:Y,onToggleMulti:Z,className:te,optionClassName:ne,loadingClassName:re,emptyClassName:ie}),g&&(0,o.jsx)(`p`,{id:N,"aria-live":`polite`,className:e.t(`text-xs leading-5 text-destructive`,E),children:g}),h&&!g&&(0,o.jsx)(`p`,{id:N,className:e.t(`text-xs leading-5 text-muted-foreground`,E),children:h})]})}var h=(0,a.forwardRef)(m);Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return h}});