banhaten 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (365) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/CONTRIBUTING.md +44 -0
  3. package/README.md +145 -328
  4. package/SECURITY.md +15 -0
  5. package/banhaten.config.example.json +1 -3
  6. package/docs/design-system/README.md +20 -0
  7. package/docs/design-system/adoption-quality-remediation.md +87 -0
  8. package/docs/design-system/agent-usage.md +13 -0
  9. package/docs/design-system/appearance-presets.md +189 -0
  10. package/docs/design-system/appearances/default.md +94 -0
  11. package/docs/design-system/appearances/rounded.md +95 -0
  12. package/docs/design-system/appearances/sharp.md +95 -0
  13. package/docs/design-system/component-docs-pattern.md +81 -0
  14. package/docs/design-system/component-showcase-consistency-report.md +217 -0
  15. package/docs/design-system/component-token-consistency-audit.md +173 -0
  16. package/docs/design-system/components/README.md +75 -0
  17. package/docs/design-system/components/accordion.md +67 -0
  18. package/docs/design-system/components/activity-feed.md +106 -0
  19. package/docs/design-system/components/alert-dialog.md +87 -0
  20. package/docs/design-system/components/alert.md +111 -0
  21. package/docs/design-system/components/aspect-ratio.md +59 -0
  22. package/docs/design-system/components/attribute.md +103 -0
  23. package/docs/design-system/components/autocomplete.md +93 -0
  24. package/docs/design-system/components/avatar.md +70 -0
  25. package/docs/design-system/components/badge.md +72 -0
  26. package/docs/design-system/components/banner.md +99 -0
  27. package/docs/design-system/components/breadcrumbs.md +188 -0
  28. package/docs/design-system/components/button-group.md +117 -0
  29. package/docs/design-system/components/button.md +95 -0
  30. package/docs/design-system/components/card.md +95 -0
  31. package/docs/design-system/components/carousel.md +61 -0
  32. package/docs/design-system/components/catalog-components.md +59 -0
  33. package/docs/design-system/components/chart.md +58 -0
  34. package/docs/design-system/components/checkbox.md +68 -0
  35. package/docs/design-system/components/collapsible.md +63 -0
  36. package/docs/design-system/components/command.md +75 -0
  37. package/docs/design-system/components/context-menu.md +59 -0
  38. package/docs/design-system/components/date-picker.md +97 -0
  39. package/docs/design-system/components/divider.md +117 -0
  40. package/docs/design-system/components/empty-state.md +72 -0
  41. package/docs/design-system/components/field.md +86 -0
  42. package/docs/design-system/components/file-upload.md +199 -0
  43. package/docs/design-system/components/hover-card.md +61 -0
  44. package/docs/design-system/components/icons.md +48 -0
  45. package/docs/design-system/components/input-group.md +73 -0
  46. package/docs/design-system/components/input-otp.md +73 -0
  47. package/docs/design-system/components/input.md +84 -0
  48. package/docs/design-system/components/item.md +72 -0
  49. package/docs/design-system/components/kbd.md +62 -0
  50. package/docs/design-system/components/label.md +64 -0
  51. package/docs/design-system/components/menu.md +76 -0
  52. package/docs/design-system/components/menubar.md +60 -0
  53. package/docs/design-system/components/modal.md +119 -0
  54. package/docs/design-system/components/native-select.md +70 -0
  55. package/docs/design-system/components/navigation-menu.md +63 -0
  56. package/docs/design-system/components/onboarding-step-list-item.md +94 -0
  57. package/docs/design-system/components/page-header.md +98 -0
  58. package/docs/design-system/components/pagination.md +71 -0
  59. package/docs/design-system/components/popover.md +77 -0
  60. package/docs/design-system/components/progress-slider.md +66 -0
  61. package/docs/design-system/components/progress.md +92 -0
  62. package/docs/design-system/components/radio-card.md +65 -0
  63. package/docs/design-system/components/radio-group.md +72 -0
  64. package/docs/design-system/components/resizable.md +57 -0
  65. package/docs/design-system/components/scroll-area.md +60 -0
  66. package/docs/design-system/components/segmented-control.md +71 -0
  67. package/docs/design-system/components/select.md +87 -0
  68. package/docs/design-system/components/sheet.md +82 -0
  69. package/docs/design-system/components/sidebar.md +83 -0
  70. package/docs/design-system/components/skeleton.md +91 -0
  71. package/docs/design-system/components/slideout.md +77 -0
  72. package/docs/design-system/components/slider.md +81 -0
  73. package/docs/design-system/components/social-button.md +65 -0
  74. package/docs/design-system/components/spinner.md +77 -0
  75. package/docs/design-system/components/steps.md +77 -0
  76. package/docs/design-system/components/table.md +411 -0
  77. package/docs/design-system/components/tabs.md +69 -0
  78. package/docs/design-system/components/tag.md +95 -0
  79. package/docs/design-system/components/textarea.md +64 -0
  80. package/docs/design-system/components/timeline.md +95 -0
  81. package/docs/design-system/components/toast.md +73 -0
  82. package/docs/design-system/components/toggle.md +96 -0
  83. package/docs/design-system/components/toolbar.md +105 -0
  84. package/docs/design-system/components/tooltip.md +107 -0
  85. package/docs/design-system/components/typography.md +18 -0
  86. package/docs/design-system/density-and-elevation.md +44 -0
  87. package/docs/design-system/design-system-test-missing-items.md +368 -0
  88. package/docs/design-system/direction-and-localization.md +23 -0
  89. package/docs/design-system/form-recipes.md +73 -0
  90. package/docs/design-system/gap-promotion-policy.md +21 -0
  91. package/docs/design-system/gap-promotion-report.md +166 -0
  92. package/docs/design-system/icons.md +69 -0
  93. package/docs/design-system/installation.md +68 -0
  94. package/docs/design-system/launch-comparison-shadcn.md +98 -0
  95. package/docs/design-system/registry-and-cli.md +64 -0
  96. package/docs/design-system/release-policy.md +30 -0
  97. package/docs/design-system/roadmap.md +14 -0
  98. package/docs/design-system/support-matrix.md +23 -0
  99. package/docs/design-system/tabs.md +53 -0
  100. package/docs/design-system/token-governance.md +60 -0
  101. package/package.json +97 -65
  102. package/registry/component-contract.json +40 -0
  103. package/registry/components/alert-dialog.tsx +297 -0
  104. package/registry/components/alert.tsx +86 -65
  105. package/registry/components/aspect-ratio.tsx +30 -0
  106. package/registry/components/autocomplete.tsx +23 -9
  107. package/registry/components/avatar.tsx +7 -7
  108. package/registry/components/badge.tsx +1 -1
  109. package/registry/components/button-group.tsx +321 -4
  110. package/registry/components/button.tsx +38 -17
  111. package/registry/components/card.tsx +68 -59
  112. package/registry/components/carousel.tsx +282 -0
  113. package/registry/components/chart.tsx +203 -0
  114. package/registry/components/checkbox.tsx +3 -3
  115. package/registry/components/collapsible.tsx +69 -0
  116. package/registry/components/command.tsx +174 -0
  117. package/registry/components/context-menu.tsx +236 -0
  118. package/registry/components/date-picker.tsx +246 -105
  119. package/registry/components/expanded/ActivityFeed.tsx +6 -15
  120. package/registry/components/expanded/Banner.tsx +3 -3
  121. package/registry/components/expanded/Breadcrumbs.tsx +5 -5
  122. package/registry/components/expanded/CatalogComponentsShowcase.tsx +13 -13
  123. package/registry/components/expanded/CatalogDivider.tsx +1 -1
  124. package/registry/components/expanded/EmptyState.tsx +1 -1
  125. package/registry/components/expanded/FileUpload.tsx +9 -2
  126. package/registry/components/expanded/OnboardingStepListItem.tsx +2 -4
  127. package/registry/components/expanded/PageHeader.tsx +14 -14
  128. package/registry/components/expanded/Slideout.tsx +15 -415
  129. package/registry/components/expanded/Steps.tsx +4 -4
  130. package/registry/components/expanded/Table.tsx +116 -69
  131. package/registry/components/expanded/Timeline.tsx +3 -3
  132. package/registry/components/expanded/activityFeed.css +1 -1
  133. package/registry/components/expanded/breadcrumbs.css +139 -139
  134. package/registry/components/expanded/catalogComponentsShowcase.css +83 -83
  135. package/registry/components/expanded/divider.css +1 -1
  136. package/registry/components/expanded/emptyState.css +1 -1
  137. package/registry/components/expanded/fileUpload.css +6 -6
  138. package/registry/components/expanded/slideout.css +9 -685
  139. package/registry/components/expanded/steps.css +274 -274
  140. package/registry/components/expanded/table.css +2 -2
  141. package/registry/components/expanded/timeline.css +264 -264
  142. package/registry/components/field.tsx +230 -0
  143. package/registry/components/hover-card.tsx +48 -0
  144. package/registry/components/input-content.ts +1 -0
  145. package/registry/components/input-group.tsx +130 -0
  146. package/registry/components/input-otp.tsx +13 -3
  147. package/registry/components/input.tsx +70 -45
  148. package/registry/components/item.tsx +189 -0
  149. package/registry/components/kbd.tsx +151 -0
  150. package/registry/components/label.tsx +78 -0
  151. package/registry/components/menu.tsx +34 -246
  152. package/registry/components/menubar.tsx +226 -0
  153. package/registry/components/modal.tsx +216 -143
  154. package/registry/components/native-select.tsx +205 -0
  155. package/registry/components/navigation-menu.tsx +171 -0
  156. package/registry/components/pagination.tsx +80 -58
  157. package/registry/components/popover.tsx +162 -664
  158. package/registry/components/radio-card.tsx +116 -87
  159. package/registry/components/radio-group.tsx +1 -1
  160. package/registry/components/resizable.tsx +74 -0
  161. package/registry/components/scroll-area.tsx +67 -0
  162. package/registry/components/segmented-control.tsx +87 -0
  163. package/registry/components/select-content.tsx +2 -2
  164. package/registry/components/select.tsx +54 -20
  165. package/registry/components/sheet.tsx +305 -0
  166. package/registry/components/sidebar.tsx +352 -0
  167. package/registry/components/skeleton.css +0 -3
  168. package/registry/components/social-button.tsx +116 -30
  169. package/registry/components/spinner.tsx +18 -55
  170. package/registry/components/{expanded/tabs.css → tabs.css} +127 -106
  171. package/registry/components/tabs.tsx +246 -0
  172. package/registry/components/tag.tsx +2 -2
  173. package/registry/components/textarea.tsx +4 -4
  174. package/registry/components/toast.tsx +136 -0
  175. package/registry/components/toggle.tsx +2 -2
  176. package/registry/components/toolbar.tsx +89 -17
  177. package/registry/components/tooltip.tsx +1 -1
  178. package/registry/examples/alert-demo.tsx +25 -5
  179. package/registry/examples/alert-dialog-demo.tsx +42 -0
  180. package/registry/examples/aspect-ratio-demo.tsx +11 -0
  181. package/registry/examples/attribute-demo.tsx +1 -1
  182. package/registry/examples/autocomplete-demo.tsx +3 -3
  183. package/registry/examples/avatar-demo.tsx +7 -7
  184. package/registry/examples/badge-demo.tsx +1 -1
  185. package/registry/examples/button-demo.tsx +6 -6
  186. package/registry/examples/button-group-demo.tsx +23 -2
  187. package/registry/examples/card-demo.tsx +46 -8
  188. package/registry/examples/carousel-demo.tsx +43 -0
  189. package/registry/examples/chart-demo.tsx +33 -0
  190. package/registry/examples/checkbox-demo.tsx +5 -5
  191. package/registry/examples/collapsible-demo.tsx +16 -0
  192. package/registry/examples/collection-filter-bar-demo.tsx +135 -0
  193. package/registry/examples/command-demo.tsx +42 -0
  194. package/registry/examples/{expanded/command-bar-demo.tsx → command-palette-demo.tsx} +5 -15
  195. package/registry/examples/context-menu-demo.tsx +29 -0
  196. package/registry/examples/control-density-contract-demo.tsx +61 -0
  197. package/registry/examples/date-picker-demo.tsx +12 -12
  198. package/registry/examples/divider-demo.tsx +3 -3
  199. package/registry/examples/expanded/banner-demo.tsx +1 -1
  200. package/registry/examples/expanded/breadcrumbs-demo.tsx +1 -1
  201. package/registry/examples/expanded/empty-state-demo.tsx +1 -1
  202. package/registry/examples/expanded/file-upload-demo.tsx +1 -1
  203. package/registry/examples/expanded/onboarding-step-demo.tsx +1 -1
  204. package/registry/examples/expanded/slideout-demo.tsx +2 -2
  205. package/registry/examples/expanded/steps-demo.tsx +1 -1
  206. package/registry/examples/expanded/tabs-demo.tsx +2 -2
  207. package/registry/examples/expanded/timeline-demo.tsx +1 -1
  208. package/registry/examples/field-demo.tsx +51 -0
  209. package/registry/examples/hover-card-demo.tsx +23 -0
  210. package/registry/examples/input-demo.tsx +6 -6
  211. package/registry/examples/input-group-demo.tsx +16 -0
  212. package/registry/examples/input-otp-demo.tsx +4 -4
  213. package/registry/examples/item-demo.tsx +46 -0
  214. package/registry/examples/kbd-demo.tsx +11 -0
  215. package/registry/examples/label-demo.tsx +20 -0
  216. package/registry/examples/menu-demo.tsx +1 -1
  217. package/registry/examples/menubar-demo.tsx +34 -0
  218. package/registry/examples/modal-demo.tsx +67 -9
  219. package/registry/examples/native-select-demo.tsx +16 -0
  220. package/registry/examples/navigation-menu-demo.tsx +29 -0
  221. package/registry/examples/pagination-demo.tsx +6 -3
  222. package/registry/examples/popover-demo.tsx +19 -19
  223. package/registry/examples/progress-demo.tsx +1 -1
  224. package/registry/examples/progress-slider-demo.tsx +1 -1
  225. package/registry/examples/radio-card-demo.tsx +4 -4
  226. package/registry/examples/radio-group-demo.tsx +2 -2
  227. package/registry/examples/resizable-demo.tsx +22 -0
  228. package/registry/examples/results-toolbar-demo.tsx +44 -0
  229. package/registry/examples/scroll-area-demo.tsx +15 -0
  230. package/registry/examples/segmented-control-demo.tsx +39 -0
  231. package/registry/examples/select-demo.tsx +1 -1
  232. package/registry/examples/sheet-demo.tsx +47 -0
  233. package/registry/examples/sidebar-demo.tsx +55 -0
  234. package/registry/examples/slider-demo.tsx +3 -3
  235. package/registry/examples/social-button-demo.tsx +18 -8
  236. package/registry/examples/spinner-demo.tsx +13 -13
  237. package/registry/examples/tabs-demo.tsx +13 -0
  238. package/registry/examples/tag-demo.tsx +1 -1
  239. package/registry/examples/textarea-demo.tsx +4 -4
  240. package/registry/examples/toast-demo.tsx +35 -0
  241. package/registry/examples/toggle-demo.tsx +6 -6
  242. package/registry/examples/tooltip-demo.tsx +4 -4
  243. package/registry/guidance/USAGE.md +27 -0
  244. package/registry/hooks/use-direction.ts +193 -13
  245. package/registry/index.json +6010 -432
  246. package/registry/styles/globals.css +3112 -4690
  247. package/registry.json +1582 -0
  248. package/schema/config.schema.json +51 -0
  249. package/schema/registry.schema.json +190 -0
  250. package/schema/tokens.schema.json +163 -0
  251. package/src/cli/command-line.js +194 -0
  252. package/src/cli/config-editors.js +9 -0
  253. package/src/cli/doctor.js +399 -0
  254. package/src/cli/file-transaction.js +295 -0
  255. package/src/cli/global-css.js +153 -0
  256. package/src/cli/index.js +639 -1391
  257. package/src/cli/install-plan.js +592 -0
  258. package/src/cli/install-receipt.js +171 -0
  259. package/src/cli/jsonc.js +203 -0
  260. package/src/cli/package-install-state.js +254 -0
  261. package/src/cli/package-manager.js +238 -0
  262. package/src/cli/package-plan.js +185 -0
  263. package/src/cli/package-version.js +97 -0
  264. package/src/cli/registry-query.js +207 -0
  265. package/src/cli/reporting.js +55 -0
  266. package/src/cli/schema-validation.js +19 -0
  267. package/src/cli/source-scanner.js +686 -0
  268. package/src/cli/vite-config.js +478 -0
  269. package/tokens/banhaten.tokens.json +4313 -310
  270. package/registry/assets/avatars/avatar-02.jpg +0 -0
  271. package/registry/assets/avatars/avatar-03.jpg +0 -0
  272. package/registry/assets/avatars/avatar-04.jpg +0 -0
  273. package/registry/assets/avatars/avatar-05.jpg +0 -0
  274. package/registry/assets/avatars/avatar-06.jpg +0 -0
  275. package/registry/assets/avatars/avatar-07.jpg +0 -0
  276. package/registry/assets/avatars/avatar-08.jpg +0 -0
  277. package/registry/assets/avatars/avatar-09.jpg +0 -0
  278. package/registry/assets/avatars/avatar-10.jpg +0 -0
  279. package/registry/assets/avatars/avatar-11.jpg +0 -0
  280. package/registry/assets/avatars/avatar-12.jpg +0 -0
  281. package/registry/assets/avatars/avatar-13.jpg +0 -0
  282. package/registry/assets/avatars/avatar-14.jpg +0 -0
  283. package/registry/assets/avatars/avatar-15.jpg +0 -0
  284. package/registry/assets/avatars/avatar-16.jpg +0 -0
  285. package/registry/assets/avatars/avatar-17.jpg +0 -0
  286. package/registry/assets/avatars/avatar-18.jpg +0 -0
  287. package/registry/assets/avatars/avatar-19.jpg +0 -0
  288. package/registry/assets/avatars/avatar-20.jpg +0 -0
  289. package/registry/assets/avatars/avatar-21.jpg +0 -0
  290. package/registry/assets/avatars/avatar-22.jpg +0 -0
  291. package/registry/assets/avatars/avatar-23.jpg +0 -0
  292. package/registry/assets/avatars/avatar-24.jpg +0 -0
  293. package/registry/assets/avatars/avatar-25.jpg +0 -0
  294. package/registry/assets/avatars/avatar-26.jpg +0 -0
  295. package/registry/assets/avatars/avatar-27.jpg +0 -0
  296. package/registry/assets/avatars/avatar-28.jpg +0 -0
  297. package/registry/assets/avatars/avatar-29.jpg +0 -0
  298. package/registry/assets/avatars/avatar-30.jpg +0 -0
  299. package/registry/assets/avatars/avatar-31.jpg +0 -0
  300. package/registry/assets/avatars/avatar-32.jpg +0 -0
  301. package/registry/assets/avatars/avatar-33.jpg +0 -0
  302. package/registry/assets/avatars/avatar-34.jpg +0 -0
  303. package/registry/assets/avatars/avatar-35.jpg +0 -0
  304. package/registry/assets/image-assets.json +0 -744
  305. package/registry/assets/images/art-02.jpg +0 -0
  306. package/registry/assets/images/art-03.jpg +0 -0
  307. package/registry/assets/images/art-04.jpg +0 -0
  308. package/registry/assets/images/art-05.jpg +0 -0
  309. package/registry/assets/images/art-06.jpg +0 -0
  310. package/registry/assets/images/art-07.jpg +0 -0
  311. package/registry/assets/images/art-08.jpg +0 -0
  312. package/registry/assets/images/art-09.jpg +0 -0
  313. package/registry/assets/images/art-10.jpg +0 -0
  314. package/registry/assets/images/art-11.jpg +0 -0
  315. package/registry/assets/images/art-12.jpg +0 -0
  316. package/registry/assets/images/art-13.jpg +0 -0
  317. package/registry/assets/images/art-14.jpg +0 -0
  318. package/registry/assets/images/art-15.jpg +0 -0
  319. package/registry/assets/images/art-16.jpg +0 -0
  320. package/registry/assets/images/art-17.jpg +0 -0
  321. package/registry/assets/images/art-18.jpg +0 -0
  322. package/registry/assets/images/art-19.jpg +0 -0
  323. package/registry/assets/images/art-20.jpg +0 -0
  324. package/registry/assets/images/art-21.jpg +0 -0
  325. package/registry/assets/images/art-22.jpg +0 -0
  326. package/registry/assets/images/art-23.jpg +0 -0
  327. package/registry/assets/images/art-24.jpg +0 -0
  328. package/registry/assets/images/art-25.jpg +0 -0
  329. package/registry/assets/images/art-26.jpg +0 -0
  330. package/registry/assets/images/art-27.jpg +0 -0
  331. package/registry/assets/images/nature-01.jpg +0 -0
  332. package/registry/assets/images/nature-02.jpg +0 -0
  333. package/registry/assets/images/nature-03.jpg +0 -0
  334. package/registry/assets/images/nature-04.jpg +0 -0
  335. package/registry/assets/images/nature-05.jpg +0 -0
  336. package/registry/assets/images/nature-06.jpg +0 -0
  337. package/registry/assets/images/nature-07.jpg +0 -0
  338. package/registry/assets/images/nature-08.jpg +0 -0
  339. package/registry/assets/images/nature-09.jpg +0 -0
  340. package/registry/assets/images/nature-10.jpg +0 -0
  341. package/registry/assets/images/nature-11.jpg +0 -0
  342. package/registry/assets/images/nature-12.jpg +0 -0
  343. package/registry/assets/images/nature-13.jpg +0 -0
  344. package/registry/assets/images/nature-14.jpg +0 -0
  345. package/registry/assets/images/nature-15.jpg +0 -0
  346. package/registry/assets/images/nature-16.jpg +0 -0
  347. package/registry/assets/images/nature-17.jpg +0 -0
  348. package/registry/assets/images/nature-18.jpg +0 -0
  349. package/registry/assets/images/nature-19.jpg +0 -0
  350. package/registry/assets/images/nature-20.jpg +0 -0
  351. package/registry/components/expanded/BannerBoard.tsx +0 -225
  352. package/registry/components/expanded/CatalogTag.tsx +0 -85
  353. package/registry/components/expanded/CommandBar.tsx +0 -386
  354. package/registry/components/expanded/IconExplorer.tsx +0 -612
  355. package/registry/components/expanded/Tabs.tsx +0 -86
  356. package/registry/components/expanded/TimelineShowcase.tsx +0 -158
  357. package/registry/components/expanded/commandBar.css +0 -470
  358. package/registry/components/expanded/iconExplorer.css +0 -764
  359. package/registry/components/expanded/iconPacks.ts +0 -866
  360. package/registry/components/expanded/tag.css +0 -148
  361. package/registry/examples/expanded/icons-demo.tsx +0 -5
  362. package/tokens/Color mode.zip +0 -0
  363. package/tokens/Numbers.zip +0 -0
  364. package/tokens/Radius.zip +0 -0
  365. package/tokens/Theme.zip +0 -0
@@ -0,0 +1,205 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { cva, type VariantProps } from "class-variance-authority"
5
+ import { ChevronDownIcon, InfoIcon } from "lucide-react"
6
+
7
+ import { Label } from "@/components/ui/label"
8
+ import { cn } from "@/lib/utils"
9
+
10
+ type NativeSelectSize = "md" | "lg"
11
+ type NativeSelectState = "default" | "filled" | "error" | "disabled"
12
+ type NativeSelectVariant = "default" | "soft"
13
+
14
+ type NativeSelectOption = {
15
+ disabled?: boolean
16
+ label: React.ReactNode
17
+ value: string
18
+ }
19
+
20
+ type NativeSelectProps = Omit<
21
+ React.ComponentProps<"select">,
22
+ "children" | "className" | "dir" | "size"
23
+ > &
24
+ VariantProps<typeof nativeSelectControlVariants> & {
25
+ children?: React.ReactNode
26
+ className?: string
27
+ errorMessage?: React.ReactNode
28
+ hasHelperText?: boolean
29
+ helperText?: React.ReactNode
30
+ isOptional?: boolean
31
+ isRequired?: boolean
32
+ label?: React.ReactNode
33
+ options?: NativeSelectOption[]
34
+ optionalText?: React.ReactNode
35
+ rootClassName?: string
36
+ selectClassName?: string
37
+ state?: NativeSelectState
38
+ triggerId?: string
39
+ dir?: "ltr" | "rtl" | "auto"
40
+ }
41
+
42
+ const nativeSelectRootVariants = cva(
43
+ "grid w-[var(--bh-select-width)] max-w-full gap-[var(--bh-select-field-gap)]"
44
+ )
45
+
46
+ const nativeSelectControlVariants = cva(
47
+ [
48
+ "relative grid w-full rounded-[var(--bh-select-trigger-radius)]",
49
+ "[--bh-select-trigger-border-current:var(--bh-select-trigger-border)] [--shadow-select-trigger:inset_0px_0px_0px_var(--bh-border-width-default)_var(--bh-select-trigger-border-current,var(--bh-select-trigger-border)),var(--shadow-component-default)]",
50
+ "bg-[var(--bh-select-trigger-bg)] shadow-[var(--shadow-select-trigger)] transition-[background-color,box-shadow]",
51
+ "focus-within:[--bh-select-trigger-border-current:var(--bh-select-trigger-border-focus)] focus-within:shadow-[var(--shadow-select-focus-ring)]",
52
+ ],
53
+ {
54
+ variants: {
55
+ size: {
56
+ lg: "min-h-[var(--bh-input-lg-height)]",
57
+ md: "min-h-[var(--bh-input-md-height)]",
58
+ },
59
+ state: {
60
+ default: "",
61
+ filled: "",
62
+ error:
63
+ "[--bh-select-trigger-border-current:var(--bh-select-trigger-border-error)] shadow-[var(--shadow-select-trigger)] focus-within:shadow-[var(--shadow-select-danger-focus-ring)]",
64
+ disabled:
65
+ "pointer-events-none bg-[var(--bh-select-trigger-bg-disabled)] shadow-[inset_0px_0px_0px_var(--bh-border-width-default)_var(--bh-select-trigger-border-disabled)]",
66
+ },
67
+ variant: {
68
+ default: "",
69
+ soft: "bg-[var(--bh-select-trigger-bg-soft)] shadow-none",
70
+ },
71
+ },
72
+ defaultVariants: {
73
+ size: "lg",
74
+ state: "default",
75
+ variant: "default",
76
+ },
77
+ }
78
+ )
79
+
80
+ const NativeSelect = React.forwardRef<HTMLSelectElement, NativeSelectProps>(
81
+ function NativeSelect(
82
+ {
83
+ children,
84
+ className,
85
+ disabled,
86
+ errorMessage,
87
+ hasHelperText,
88
+ helperText,
89
+ isOptional = false,
90
+ isRequired = false,
91
+ label,
92
+ options,
93
+ optionalText,
94
+ rootClassName,
95
+ selectClassName,
96
+ size = "lg",
97
+ state = "default",
98
+ triggerId,
99
+ variant = "default",
100
+ dir,
101
+ ...props
102
+ },
103
+ ref
104
+ ) {
105
+ const generatedId = React.useId()
106
+ const selectId = triggerId ?? generatedId
107
+ const helperId = `${selectId}-helper`
108
+ const visualState = disabled ? "disabled" : state
109
+ const helper = visualState === "error" ? errorMessage : helperText
110
+ const shouldRenderHelper = hasHelperText ?? Boolean(helper)
111
+
112
+ return (
113
+ <div
114
+ data-slot="native-select-root"
115
+ dir={dir}
116
+ className={cn(nativeSelectRootVariants({ className: rootClassName }))}
117
+ >
118
+ {label ? (
119
+ <Label
120
+ htmlFor={selectId}
121
+ optionalText={optionalText}
122
+ required={isRequired}
123
+ data-optional={isOptional ? "true" : undefined}
124
+ >
125
+ {label}
126
+ </Label>
127
+ ) : null}
128
+ <div
129
+ data-slot="native-select-control"
130
+ className={cn(
131
+ nativeSelectControlVariants({
132
+ size,
133
+ state: visualState,
134
+ variant,
135
+ className,
136
+ })
137
+ )}
138
+ >
139
+ <select
140
+ aria-describedby={shouldRenderHelper ? helperId : undefined}
141
+ aria-invalid={visualState === "error" || undefined}
142
+ data-slot="native-select"
143
+ disabled={disabled}
144
+ id={selectId}
145
+ ref={ref}
146
+ className={cn(
147
+ "min-h-[inherit] w-full appearance-none border-0 bg-transparent py-[var(--bh-space-sm-6)] ps-[var(--bh-select-trigger-padding-x)] pe-[var(--bh-space-8xl-48)] text-start text-[length:var(--bh-text-body-md-regular-font-size)] font-[var(--bh-text-body-md-regular-font-weight)] leading-[var(--bh-text-body-md-regular-line-height)] tracking-[var(--bh-text-body-md-regular-letter-spacing)] text-[var(--bh-content-default)] outline-none disabled:cursor-not-allowed disabled:text-[var(--bh-content-disabled)]",
148
+ selectClassName
149
+ )}
150
+ {...props}
151
+ >
152
+ {options?.map((option) => (
153
+ <option
154
+ disabled={option.disabled}
155
+ key={option.value}
156
+ value={option.value}
157
+ >
158
+ {option.label}
159
+ </option>
160
+ ))}
161
+ {children}
162
+ </select>
163
+ <ChevronDownIcon
164
+ aria-hidden="true"
165
+ className="pointer-events-none absolute end-[var(--bh-select-trigger-padding-x)] top-1/2 size-[var(--bh-space-3xl-16)] -translate-y-1/2 text-[var(--bh-select-trigger-icon-color)]"
166
+ strokeWidth="var(--bh-icon-stroke-200)"
167
+ />
168
+ </div>
169
+ {shouldRenderHelper ? (
170
+ <p
171
+ data-slot="native-select-helper"
172
+ dir="auto"
173
+ id={helperId}
174
+ className={cn(
175
+ "m-0 inline-flex items-center gap-[var(--bh-space-xs-4)] text-[length:var(--bh-text-body-xs-regular-font-size)] font-[var(--bh-text-body-xs-regular-font-weight)] leading-[var(--bh-text-body-xs-regular-line-height)] tracking-[var(--bh-text-body-xs-regular-letter-spacing)]",
176
+ visualState === "error"
177
+ ? "text-[var(--bh-content-danger-default)]"
178
+ : "text-[var(--bh-content-subtle)]"
179
+ )}
180
+ >
181
+ <InfoIcon
182
+ aria-hidden="true"
183
+ className="size-[var(--bh-space-3xl-16)] shrink-0"
184
+ strokeWidth="var(--bh-icon-stroke-200)"
185
+ />
186
+ {helper}
187
+ </p>
188
+ ) : null}
189
+ </div>
190
+ )
191
+ }
192
+ )
193
+
194
+ export {
195
+ NativeSelect,
196
+ nativeSelectControlVariants,
197
+ nativeSelectRootVariants,
198
+ }
199
+ export type {
200
+ NativeSelectOption,
201
+ NativeSelectProps,
202
+ NativeSelectSize,
203
+ NativeSelectState,
204
+ NativeSelectVariant,
205
+ }
@@ -0,0 +1,171 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu"
5
+ import { ChevronDownIcon } from "lucide-react"
6
+
7
+ import { cn } from "@/lib/utils"
8
+
9
+ type NavigationMenuProps = React.ComponentProps<
10
+ typeof NavigationMenuPrimitive.Root
11
+ >
12
+ type NavigationMenuListProps = React.ComponentPropsWithoutRef<
13
+ typeof NavigationMenuPrimitive.List
14
+ >
15
+ type NavigationMenuTriggerProps = React.ComponentPropsWithoutRef<
16
+ typeof NavigationMenuPrimitive.Trigger
17
+ >
18
+ type NavigationMenuContentProps = React.ComponentPropsWithoutRef<
19
+ typeof NavigationMenuPrimitive.Content
20
+ >
21
+ type NavigationMenuLinkProps = React.ComponentPropsWithoutRef<
22
+ typeof NavigationMenuPrimitive.Link
23
+ >
24
+ type NavigationMenuViewportProps = React.ComponentPropsWithoutRef<
25
+ typeof NavigationMenuPrimitive.Viewport
26
+ >
27
+ type NavigationMenuIndicatorProps = React.ComponentPropsWithoutRef<
28
+ typeof NavigationMenuPrimitive.Indicator
29
+ >
30
+
31
+ const NavigationMenu = React.forwardRef<
32
+ React.ElementRef<typeof NavigationMenuPrimitive.Root>,
33
+ NavigationMenuProps
34
+ >(function NavigationMenu({ className, ...props }, ref) {
35
+ return (
36
+ <NavigationMenuPrimitive.Root
37
+ data-slot="navigation-menu"
38
+ ref={ref}
39
+ className={cn("relative z-[var(--bh-z-raised)] flex max-w-max flex-1 items-center justify-center", className)}
40
+ {...props}
41
+ />
42
+ )
43
+ })
44
+
45
+ const NavigationMenuList = React.forwardRef<
46
+ React.ElementRef<typeof NavigationMenuPrimitive.List>,
47
+ NavigationMenuListProps
48
+ >(function NavigationMenuList({ className, ...props }, ref) {
49
+ return (
50
+ <NavigationMenuPrimitive.List
51
+ data-slot="navigation-menu-list"
52
+ ref={ref}
53
+ className={cn("group flex flex-1 list-none items-center justify-center gap-[var(--bh-space-xs-4)]", className)}
54
+ {...props}
55
+ />
56
+ )
57
+ })
58
+
59
+ const NavigationMenuItem = NavigationMenuPrimitive.Item
60
+
61
+ const NavigationMenuTrigger = React.forwardRef<
62
+ React.ElementRef<typeof NavigationMenuPrimitive.Trigger>,
63
+ NavigationMenuTriggerProps
64
+ >(function NavigationMenuTrigger({ children, className, ...props }, ref) {
65
+ return (
66
+ <NavigationMenuPrimitive.Trigger
67
+ data-slot="navigation-menu-trigger"
68
+ ref={ref}
69
+ className={cn(
70
+ "group inline-flex h-[var(--bh-space-7xl-40)] items-center justify-center gap-[var(--bh-space-xs-4)] rounded-[var(--bh-radius-lg-8)] bg-transparent px-[var(--bh-space-xl-12)] text-[length:var(--bh-text-body-sm-medium-font-size)] font-[var(--bh-text-body-sm-medium-font-weight)] leading-[var(--bh-text-body-sm-medium-line-height)] tracking-[var(--bh-text-body-sm-medium-letter-spacing)] text-[var(--bh-content-default)] outline-none transition-colors hover:bg-[var(--bh-interactive-ghost-hover)] focus:bg-[var(--bh-interactive-ghost-hover)] disabled:pointer-events-none disabled:text-[var(--bh-content-disabled)] data-[state=open]:bg-[var(--bh-interactive-soft-default)]",
71
+ className
72
+ )}
73
+ {...props}
74
+ >
75
+ {children}
76
+ <ChevronDownIcon
77
+ aria-hidden="true"
78
+ className="size-[var(--bh-space-3xl-16)] transition-transform group-data-[state=open]:rotate-180"
79
+ />
80
+ </NavigationMenuPrimitive.Trigger>
81
+ )
82
+ })
83
+
84
+ const NavigationMenuContent = React.forwardRef<
85
+ React.ElementRef<typeof NavigationMenuPrimitive.Content>,
86
+ NavigationMenuContentProps
87
+ >(function NavigationMenuContent({ className, ...props }, ref) {
88
+ return (
89
+ <NavigationMenuPrimitive.Content
90
+ data-slot="navigation-menu-content"
91
+ ref={ref}
92
+ className={cn(
93
+ "start-0 top-0 w-full rounded-[var(--bh-radius-2xl-12)] bg-[var(--bh-bg-raised)] p-[var(--bh-space-3xl-16)] text-[var(--bh-content-default)] shadow-[var(--shadow-popover)] md:absolute md:w-[var(--bh-space-19xl-384)]",
94
+ className
95
+ )}
96
+ {...props}
97
+ />
98
+ )
99
+ })
100
+
101
+ const NavigationMenuLink = React.forwardRef<
102
+ React.ElementRef<typeof NavigationMenuPrimitive.Link>,
103
+ NavigationMenuLinkProps
104
+ >(function NavigationMenuLink({ className, ...props }, ref) {
105
+ return (
106
+ <NavigationMenuPrimitive.Link
107
+ data-slot="navigation-menu-link"
108
+ ref={ref}
109
+ className={cn(
110
+ "block rounded-[var(--bh-radius-lg-8)] p-[var(--bh-space-xl-12)] text-start text-[length:var(--bh-text-body-sm-regular-font-size)] font-[var(--bh-text-body-sm-regular-font-weight)] leading-[var(--bh-text-body-sm-regular-line-height)] tracking-[var(--bh-text-body-sm-regular-letter-spacing)] text-[var(--bh-content-default)] outline-none transition-colors hover:bg-[var(--bh-interactive-ghost-hover)] focus:bg-[var(--bh-interactive-ghost-hover)]",
111
+ className
112
+ )}
113
+ {...props}
114
+ />
115
+ )
116
+ })
117
+
118
+ const NavigationMenuViewport = React.forwardRef<
119
+ React.ElementRef<typeof NavigationMenuPrimitive.Viewport>,
120
+ NavigationMenuViewportProps
121
+ >(function NavigationMenuViewport({ className, ...props }, ref) {
122
+ return (
123
+ <div className="absolute start-0 top-full flex justify-center">
124
+ <NavigationMenuPrimitive.Viewport
125
+ data-slot="navigation-menu-viewport"
126
+ ref={ref}
127
+ className={cn(
128
+ "origin-top-center relative mt-[var(--bh-space-xs-4)] h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-[var(--bh-radius-2xl-12)] bg-[var(--bh-bg-raised)] shadow-[var(--shadow-popover)] md:w-[var(--radix-navigation-menu-viewport-width)]",
129
+ className
130
+ )}
131
+ {...props}
132
+ />
133
+ </div>
134
+ )
135
+ })
136
+
137
+ const NavigationMenuIndicator = React.forwardRef<
138
+ React.ElementRef<typeof NavigationMenuPrimitive.Indicator>,
139
+ NavigationMenuIndicatorProps
140
+ >(function NavigationMenuIndicator({ className, ...props }, ref) {
141
+ return (
142
+ <NavigationMenuPrimitive.Indicator
143
+ data-slot="navigation-menu-indicator"
144
+ ref={ref}
145
+ className={cn("top-full z-[var(--bh-z-popover)] flex h-[var(--bh-space-lg-10)] items-end justify-center overflow-hidden", className)}
146
+ {...props}
147
+ >
148
+ <div className="relative top-[var(--bh-space-xs-4)] size-[var(--bh-space-lg-10)] rotate-45 rounded-tl-[var(--bh-radius-sm-4)] bg-[var(--bh-bg-raised)] shadow-[var(--shadow-popover)]" />
149
+ </NavigationMenuPrimitive.Indicator>
150
+ )
151
+ })
152
+
153
+ export {
154
+ NavigationMenu,
155
+ NavigationMenuContent,
156
+ NavigationMenuIndicator,
157
+ NavigationMenuItem,
158
+ NavigationMenuLink,
159
+ NavigationMenuList,
160
+ NavigationMenuTrigger,
161
+ NavigationMenuViewport,
162
+ }
163
+ export type {
164
+ NavigationMenuContentProps,
165
+ NavigationMenuIndicatorProps,
166
+ NavigationMenuLinkProps,
167
+ NavigationMenuListProps,
168
+ NavigationMenuProps,
169
+ NavigationMenuTriggerProps,
170
+ NavigationMenuViewportProps,
171
+ }
@@ -3,6 +3,7 @@ import { cva, type VariantProps } from "class-variance-authority"
3
3
  import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react"
4
4
 
5
5
  import { cn } from "@/lib/utils"
6
+ import { useResolvedDirection } from "@/hooks/use-direction"
6
7
 
7
8
  type PaginationType = "numeric" | "simple" | "summary"
8
9
  type PaginationVariant = "soft" | "ghost"
@@ -21,10 +22,47 @@ type PaginationPage =
21
22
  ariaLabel?: string
22
23
  }
23
24
 
24
- type PaginationDirection = "ltr" | "rtl"
25
+ type PaginationMessages = {
26
+ caption: React.ReactNode
27
+ morePagesAriaLabel: string
28
+ navigation: string
29
+ next: React.ReactNode
30
+ nextAriaLabel: string
31
+ pageAriaLabel: (page: number) => string
32
+ previous: React.ReactNode
33
+ previousAriaLabel: string
34
+ summary: React.ReactNode
35
+ }
25
36
 
26
37
  const defaultPaginationPages: PaginationPage[] = [1, 2, 3, 4, "ellipsis", 10]
27
38
 
39
+ const defaultPaginationMessages: PaginationMessages = {
40
+ caption: "Showing 1 to 10 of 20 results",
41
+ morePagesAriaLabel: "More pages",
42
+ navigation: "Pagination",
43
+ next: "Next",
44
+ nextAriaLabel: "Next page",
45
+ pageAriaLabel: (page) => `Page ${page}`,
46
+ previous: "Previous",
47
+ previousAriaLabel: "Previous page",
48
+ summary: "Page 1 of 10",
49
+ }
50
+
51
+ const arabicPaginationMessages: PaginationMessages = {
52
+ caption:
53
+ "\u0639\u0631\u0636 1 \u0625\u0644\u0649 10 \u0645\u0646 20 \u0646\u062a\u064a\u062c\u0629",
54
+ morePagesAriaLabel: "\u0635\u0641\u062d\u0627\u062a \u0625\u0636\u0627\u0641\u064a\u0629",
55
+ navigation: "\u0627\u0644\u062a\u0631\u0642\u064a\u0645",
56
+ next: "\u0627\u0644\u062a\u0627\u0644\u064a",
57
+ nextAriaLabel:
58
+ "\u0627\u0644\u0635\u0641\u062d\u0629 \u0627\u0644\u062a\u0627\u0644\u064a\u0629",
59
+ pageAriaLabel: (page) => `\u0627\u0644\u0635\u0641\u062d\u0629 ${page}`,
60
+ previous: "\u0627\u0644\u0633\u0627\u0628\u0642",
61
+ previousAriaLabel:
62
+ "\u0627\u0644\u0635\u0641\u062d\u0629 \u0627\u0644\u0633\u0627\u0628\u0642\u0629",
63
+ summary: "\u0627\u0644\u0635\u0641\u062d\u0629 1 \u0645\u0646 10",
64
+ }
65
+
28
66
  const paginationVariants = cva(
29
67
  [
30
68
  "flex max-w-full items-center",
@@ -141,6 +179,7 @@ type PaginationProps = Omit<React.ComponentProps<"nav">, "children"> &
141
179
  variant?: PaginationVariant
142
180
  page?: number
143
181
  pages?: PaginationPage[]
182
+ messages?: Partial<PaginationMessages>
144
183
  showCaption?: boolean
145
184
  caption?: React.ReactNode
146
185
  summary?: React.ReactNode
@@ -159,6 +198,7 @@ const Pagination = React.forwardRef<HTMLElement, PaginationProps>(function Pagin
159
198
  variant = "soft",
160
199
  page = 2,
161
200
  pages = defaultPaginationPages,
201
+ messages: messageOverrides,
162
202
  showCaption = true,
163
203
  caption,
164
204
  summary,
@@ -173,24 +213,36 @@ const Pagination = React.forwardRef<HTMLElement, PaginationProps>(function Pagin
173
213
  dir,
174
214
  ...props
175
215
  }, ref) {
216
+ const rootRef = React.useRef<HTMLElement | null>(null)
217
+ const selectedDirection = useResolvedDirection(
218
+ dir === "ltr" || dir === "rtl" ? dir : undefined,
219
+ rootRef
220
+ )
221
+ const setRootRef = React.useCallback(
222
+ (node: HTMLElement | null) => {
223
+ rootRef.current = node
224
+ if (typeof ref === "function") ref(node)
225
+ else if (ref) ref.current = node
226
+ },
227
+ [ref]
228
+ )
176
229
  const selectedType = type || "numeric"
177
230
  const selectedVariant = variant || "soft"
178
- const selectedDirection = getPaginationDirection(dir)
179
- const labels = getDefaultPaginationLabels(selectedDirection)
180
- const captionContent = caption ?? labels.caption
181
- const summaryContent = summary ?? labels.summary
182
- const previousContent = previousLabel ?? labels.previous
183
- const nextContent = nextLabel ?? labels.next
231
+ const messages = { ...defaultPaginationMessages, ...messageOverrides }
232
+ const captionContent = caption ?? messages.caption
233
+ const summaryContent = summary ?? messages.summary
234
+ const previousContent = previousLabel ?? messages.previous
235
+ const nextContent = nextLabel ?? messages.next
184
236
 
185
237
  return (
186
238
  <nav
187
- aria-label={ariaLabel || labels.navigation}
239
+ aria-label={ariaLabel ?? messages.navigation}
188
240
  data-show-caption={showCaption ? "true" : "false"}
189
241
  data-slot="pagination"
190
242
  data-type={selectedType}
191
243
  data-variant={selectedVariant}
192
- dir={dir}
193
- ref={ref}
244
+ dir={selectedDirection}
245
+ ref={setRootRef}
194
246
  className={cn(
195
247
  paginationVariants({
196
248
  type: selectedType,
@@ -207,7 +259,7 @@ const Pagination = React.forwardRef<HTMLElement, PaginationProps>(function Pagin
207
259
  ) : null}
208
260
  <PaginationControls type="actions">
209
261
  <PaginationTextButton
210
- ariaLabel={previousAriaLabel || labels.previousAriaLabel}
262
+ ariaLabel={previousAriaLabel ?? messages.previousAriaLabel}
211
263
  disabled={previousDisabled}
212
264
  label={previousContent}
213
265
  onClick={() => onPageChange?.(Math.max(1, page - 1))}
@@ -215,7 +267,7 @@ const Pagination = React.forwardRef<HTMLElement, PaginationProps>(function Pagin
215
267
  variant={selectedVariant}
216
268
  />
217
269
  <PaginationTextButton
218
- ariaLabel={nextAriaLabel || labels.nextAriaLabel}
270
+ ariaLabel={nextAriaLabel ?? messages.nextAriaLabel}
219
271
  disabled={nextDisabled}
220
272
  label={nextContent}
221
273
  onClick={() => onPageChange?.(page + 1)}
@@ -229,7 +281,7 @@ const Pagination = React.forwardRef<HTMLElement, PaginationProps>(function Pagin
229
281
  {selectedType === "summary" ? (
230
282
  <>
231
283
  <PaginationTextButton
232
- ariaLabel={previousAriaLabel || labels.previousAriaLabel}
284
+ ariaLabel={previousAriaLabel ?? messages.previousAriaLabel}
233
285
  disabled={previousDisabled}
234
286
  label={previousContent}
235
287
  onClick={() => onPageChange?.(Math.max(1, page - 1))}
@@ -244,7 +296,7 @@ const Pagination = React.forwardRef<HTMLElement, PaginationProps>(function Pagin
244
296
  {summaryContent}
245
297
  </span>
246
298
  <PaginationTextButton
247
- ariaLabel={nextAriaLabel || labels.nextAriaLabel}
299
+ ariaLabel={nextAriaLabel ?? messages.nextAriaLabel}
248
300
  disabled={nextDisabled}
249
301
  label={nextContent}
250
302
  onClick={() => onPageChange?.(page + 1)}
@@ -261,7 +313,7 @@ const Pagination = React.forwardRef<HTMLElement, PaginationProps>(function Pagin
261
313
  ) : null}
262
314
  <PaginationControls type="numeric">
263
315
  <PaginationIconButton
264
- ariaLabel={previousAriaLabel || labels.previousAriaLabel}
316
+ ariaLabel={previousAriaLabel ?? messages.previousAriaLabel}
265
317
  disabled={previousDisabled}
266
318
  onClick={() => onPageChange?.(Math.max(1, page - 1))}
267
319
  type="previous"
@@ -275,13 +327,14 @@ const Pagination = React.forwardRef<HTMLElement, PaginationProps>(function Pagin
275
327
  <PaginationPageItem
276
328
  key={getPaginationPageKey(item, index)}
277
329
  item={item}
330
+ messages={messages}
278
331
  page={page}
279
332
  onPageChange={onPageChange}
280
333
  />
281
334
  ))}
282
335
  </div>
283
336
  <PaginationIconButton
284
- ariaLabel={nextAriaLabel || labels.nextAriaLabel}
337
+ ariaLabel={nextAriaLabel ?? messages.nextAriaLabel}
285
338
  disabled={nextDisabled}
286
339
  onClick={() => onPageChange?.(page + 1)}
287
340
  type="next"
@@ -405,10 +458,12 @@ function PaginationTextButton({
405
458
 
406
459
  function PaginationPageItem({
407
460
  item,
461
+ messages,
408
462
  page,
409
463
  onPageChange,
410
464
  }: {
411
465
  item: PaginationPage
466
+ messages: PaginationMessages
412
467
  page: number
413
468
  onPageChange?: (page: number) => void
414
469
  }) {
@@ -417,12 +472,12 @@ function PaginationPageItem({
417
472
  if (normalizedItem.type === "ellipsis") {
418
473
  return (
419
474
  <span
420
- aria-label={normalizedItem.ariaLabel || "More pages"}
475
+ aria-label={normalizedItem.ariaLabel ?? messages.morePagesAriaLabel}
421
476
  data-slot="pagination-ellipsis"
422
477
  role="separator"
423
478
  className={cn(paginationItemVariants({ active: false }))}
424
479
  >
425
- {normalizedItem.label || "..."}
480
+ {normalizedItem.label ?? "..."}
426
481
  </span>
427
482
  )
428
483
  }
@@ -432,14 +487,16 @@ function PaginationPageItem({
432
487
  return (
433
488
  <button
434
489
  aria-current={isActive ? "page" : undefined}
435
- aria-label={normalizedItem.ariaLabel || `Page ${normalizedItem.value}`}
490
+ aria-label={
491
+ normalizedItem.ariaLabel ?? messages.pageAriaLabel(normalizedItem.value)
492
+ }
436
493
  data-page={normalizedItem.value}
437
494
  data-slot="pagination-page"
438
495
  type="button"
439
496
  className={cn(paginationItemVariants({ active: isActive }))}
440
497
  onClick={() => onPageChange?.(normalizedItem.value)}
441
498
  >
442
- {normalizedItem.label || normalizedItem.value}
499
+ {normalizedItem.label ?? normalizedItem.value}
443
500
  </button>
444
501
  )
445
502
  }
@@ -453,7 +510,7 @@ function PaginationArrowIcon({ type }: { type: "previous" | "next" }) {
453
510
  data-rtl-flip="true"
454
511
  data-slot="pagination-icon"
455
512
  focusable="false"
456
- strokeWidth={2.25}
513
+ strokeWidth="var(--bh-icon-stroke-225)"
457
514
  />
458
515
  )
459
516
  }
@@ -480,44 +537,8 @@ function getPaginationPageKey(item: PaginationPage, index: number) {
480
537
  return `ellipsis-${index}`
481
538
  }
482
539
 
483
- function getPaginationDirection(
484
- dir: React.HTMLAttributes<HTMLElement>["dir"]
485
- ): PaginationDirection {
486
- if (dir === "rtl" || dir === "ltr") {
487
- return dir
488
- }
489
-
490
- return "ltr"
491
- }
492
-
493
- function getDefaultPaginationLabels(direction: PaginationDirection) {
494
- if (direction === "rtl") {
495
- return {
496
- navigation: "\u0627\u0644\u062a\u0631\u0642\u064a\u0645",
497
- caption:
498
- "\u0639\u0631\u0636 1 \u0625\u0644\u0649 10 \u0645\u0646 20 \u0646\u062a\u064a\u062c\u0629",
499
- summary: "\u0627\u0644\u0635\u0641\u062d\u0629 1 \u0645\u0646 10",
500
- previous: "\u0645\u0639\u0627\u064a\u0646\u0629",
501
- next: "\u0627\u0644\u062a\u0627\u0644\u064a",
502
- previousAriaLabel:
503
- "\u0627\u0644\u0635\u0641\u062d\u0629 \u0627\u0644\u0633\u0627\u0628\u0642\u0629",
504
- nextAriaLabel:
505
- "\u0627\u0644\u0635\u0641\u062d\u0629 \u0627\u0644\u062a\u0627\u0644\u064a\u0629",
506
- }
507
- }
508
-
509
- return {
510
- navigation: "Pagination",
511
- caption: "Showing 1 to 10 of 20 results",
512
- summary: "Page 1 of 10",
513
- previous: "Previous",
514
- next: "Next",
515
- previousAriaLabel: "Previous page",
516
- nextAriaLabel: "Next page",
517
- }
518
- }
519
-
520
540
  export {
541
+ arabicPaginationMessages,
521
542
  Pagination,
522
543
  paginationControlVariants,
523
544
  paginationItemVariants,
@@ -525,6 +546,7 @@ export {
525
546
  }
526
547
  export type {
527
548
  PaginationPage,
549
+ PaginationMessages,
528
550
  PaginationProps,
529
551
  PaginationType,
530
552
  PaginationVariant,