banhaten 0.1.3 → 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 (258) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/CONTRIBUTING.md +44 -0
  3. package/README.md +65 -13
  4. package/SECURITY.md +15 -0
  5. package/banhaten.config.example.json +0 -2
  6. package/docs/design-system/README.md +9 -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 +6 -1
  10. package/docs/design-system/component-docs-pattern.md +81 -0
  11. package/docs/design-system/component-token-consistency-audit.md +13 -3
  12. package/docs/design-system/components/README.md +3 -2
  13. package/docs/design-system/components/accordion.md +16 -0
  14. package/docs/design-system/components/activity-feed.md +15 -1
  15. package/docs/design-system/components/alert-dialog.md +17 -0
  16. package/docs/design-system/components/alert.md +46 -14
  17. package/docs/design-system/components/aspect-ratio.md +15 -0
  18. package/docs/design-system/components/attribute.md +16 -0
  19. package/docs/design-system/components/autocomplete.md +19 -0
  20. package/docs/design-system/components/avatar.md +18 -0
  21. package/docs/design-system/components/badge.md +19 -0
  22. package/docs/design-system/components/banner.md +15 -1
  23. package/docs/design-system/components/breadcrumbs.md +14 -0
  24. package/docs/design-system/components/button-group.md +34 -0
  25. package/docs/design-system/components/button.md +18 -0
  26. package/docs/design-system/components/card.md +18 -1
  27. package/docs/design-system/components/carousel.md +20 -3
  28. package/docs/design-system/components/catalog-components.md +15 -1
  29. package/docs/design-system/components/chart.md +15 -0
  30. package/docs/design-system/components/checkbox.md +16 -0
  31. package/docs/design-system/components/collapsible.md +15 -0
  32. package/docs/design-system/components/command.md +15 -0
  33. package/docs/design-system/components/context-menu.md +15 -0
  34. package/docs/design-system/components/date-picker.md +21 -1
  35. package/docs/design-system/components/divider.md +16 -0
  36. package/docs/design-system/components/empty-state.md +17 -0
  37. package/docs/design-system/components/field.md +17 -0
  38. package/docs/design-system/components/file-upload.md +14 -0
  39. package/docs/design-system/components/hover-card.md +15 -0
  40. package/docs/design-system/components/input-group.md +17 -0
  41. package/docs/design-system/components/input-otp.md +18 -0
  42. package/docs/design-system/components/input.md +43 -7
  43. package/docs/design-system/components/item.md +72 -0
  44. package/docs/design-system/components/kbd.md +18 -0
  45. package/docs/design-system/components/label.md +16 -0
  46. package/docs/design-system/components/menu.md +17 -0
  47. package/docs/design-system/components/menubar.md +15 -0
  48. package/docs/design-system/components/modal.md +25 -4
  49. package/docs/design-system/components/native-select.md +18 -0
  50. package/docs/design-system/components/navigation-menu.md +15 -0
  51. package/docs/design-system/components/onboarding-step-list-item.md +15 -1
  52. package/docs/design-system/components/page-header.md +15 -1
  53. package/docs/design-system/components/pagination.md +30 -8
  54. package/docs/design-system/components/popover.md +19 -0
  55. package/docs/design-system/components/progress-slider.md +18 -0
  56. package/docs/design-system/components/progress.md +17 -0
  57. package/docs/design-system/components/radio-card.md +16 -0
  58. package/docs/design-system/components/radio-group.md +17 -0
  59. package/docs/design-system/components/resizable.md +15 -0
  60. package/docs/design-system/components/scroll-area.md +15 -0
  61. package/docs/design-system/components/segmented-control.md +71 -0
  62. package/docs/design-system/components/select.md +44 -7
  63. package/docs/design-system/components/sheet.md +17 -0
  64. package/docs/design-system/components/sidebar.md +15 -0
  65. package/docs/design-system/components/skeleton.md +18 -0
  66. package/docs/design-system/components/slideout.md +14 -0
  67. package/docs/design-system/components/slider.md +20 -0
  68. package/docs/design-system/components/social-button.md +21 -3
  69. package/docs/design-system/components/spinner.md +16 -0
  70. package/docs/design-system/components/steps.md +14 -0
  71. package/docs/design-system/components/table.md +15 -1
  72. package/docs/design-system/components/tabs.md +17 -0
  73. package/docs/design-system/components/tag.md +17 -0
  74. package/docs/design-system/components/textarea.md +16 -0
  75. package/docs/design-system/components/timeline.md +14 -0
  76. package/docs/design-system/components/toast.md +17 -0
  77. package/docs/design-system/components/toggle.md +17 -0
  78. package/docs/design-system/components/toolbar.md +21 -1
  79. package/docs/design-system/components/tooltip.md +18 -1
  80. package/docs/design-system/density-and-elevation.md +44 -0
  81. package/docs/design-system/direction-and-localization.md +23 -0
  82. package/docs/design-system/form-recipes.md +73 -0
  83. package/docs/design-system/gap-promotion-policy.md +21 -0
  84. package/docs/design-system/gap-promotion-report.md +166 -0
  85. package/docs/design-system/installation.md +68 -0
  86. package/docs/design-system/launch-comparison-shadcn.md +98 -0
  87. package/docs/design-system/registry-and-cli.md +30 -7
  88. package/docs/design-system/release-policy.md +30 -0
  89. package/docs/design-system/roadmap.md +14 -0
  90. package/docs/design-system/support-matrix.md +23 -0
  91. package/docs/design-system/tabs.md +1 -1
  92. package/docs/design-system/token-governance.md +23 -1
  93. package/package.json +29 -15
  94. package/registry/component-contract.json +40 -0
  95. package/registry/components/alert-dialog.tsx +1 -1
  96. package/registry/components/alert.tsx +86 -65
  97. package/registry/components/autocomplete.tsx +23 -9
  98. package/registry/components/avatar.tsx +7 -7
  99. package/registry/components/badge.tsx +1 -1
  100. package/registry/components/button-group.tsx +321 -4
  101. package/registry/components/button.tsx +38 -17
  102. package/registry/components/card.tsx +68 -59
  103. package/registry/components/carousel.tsx +53 -5
  104. package/registry/components/chart.tsx +36 -3
  105. package/registry/components/checkbox.tsx +3 -3
  106. package/registry/components/collapsible.tsx +1 -1
  107. package/registry/components/command.tsx +1 -1
  108. package/registry/components/context-menu.tsx +1 -1
  109. package/registry/components/date-picker.tsx +245 -104
  110. package/registry/components/expanded/ActivityFeed.tsx +6 -15
  111. package/registry/components/expanded/Banner.tsx +3 -3
  112. package/registry/components/expanded/Breadcrumbs.tsx +5 -5
  113. package/registry/components/expanded/CatalogComponentsShowcase.tsx +13 -13
  114. package/registry/components/expanded/CatalogDivider.tsx +1 -1
  115. package/registry/components/expanded/EmptyState.tsx +1 -1
  116. package/registry/components/expanded/FileUpload.tsx +9 -2
  117. package/registry/components/expanded/OnboardingStepListItem.tsx +2 -4
  118. package/registry/components/expanded/PageHeader.tsx +13 -13
  119. package/registry/components/expanded/Slideout.tsx +15 -415
  120. package/registry/components/expanded/Steps.tsx +4 -4
  121. package/registry/components/expanded/Table.tsx +116 -69
  122. package/registry/components/expanded/Timeline.tsx +3 -3
  123. package/registry/components/expanded/activityFeed.css +1 -1
  124. package/registry/components/expanded/breadcrumbs.css +1 -1
  125. package/registry/components/expanded/divider.css +1 -1
  126. package/registry/components/expanded/emptyState.css +1 -1
  127. package/registry/components/expanded/fileUpload.css +6 -6
  128. package/registry/components/expanded/slideout.css +9 -685
  129. package/registry/components/expanded/steps.css +3 -3
  130. package/registry/components/expanded/table.css +2 -2
  131. package/registry/components/expanded/timeline.css +2 -2
  132. package/registry/components/input-content.ts +1 -0
  133. package/registry/components/input-otp.tsx +13 -3
  134. package/registry/components/input.tsx +68 -43
  135. package/registry/components/item.tsx +189 -0
  136. package/registry/components/kbd.tsx +111 -4
  137. package/registry/components/menu.tsx +31 -245
  138. package/registry/components/menubar.tsx +1 -1
  139. package/registry/components/modal.tsx +142 -102
  140. package/registry/components/native-select.tsx +2 -2
  141. package/registry/components/pagination.tsx +80 -58
  142. package/registry/components/popover.tsx +162 -664
  143. package/registry/components/radio-card.tsx +116 -87
  144. package/registry/components/segmented-control.tsx +87 -0
  145. package/registry/components/select-content.tsx +2 -2
  146. package/registry/components/select.tsx +52 -16
  147. package/registry/components/sheet.tsx +1 -1
  148. package/registry/components/sidebar.tsx +1 -1
  149. package/registry/components/skeleton.css +0 -3
  150. package/registry/components/social-button.tsx +47 -25
  151. package/registry/components/spinner.tsx +18 -55
  152. package/registry/components/tabs.css +1 -1
  153. package/registry/components/tabs.tsx +8 -4
  154. package/registry/components/tag.tsx +2 -2
  155. package/registry/components/textarea.tsx +3 -3
  156. package/registry/components/toast.tsx +16 -11
  157. package/registry/components/toggle.tsx +2 -2
  158. package/registry/components/toolbar.tsx +89 -17
  159. package/registry/components/tooltip.tsx +1 -1
  160. package/registry/examples/alert-demo.tsx +25 -5
  161. package/registry/examples/attribute-demo.tsx +1 -1
  162. package/registry/examples/autocomplete-demo.tsx +3 -3
  163. package/registry/examples/avatar-demo.tsx +7 -7
  164. package/registry/examples/badge-demo.tsx +1 -1
  165. package/registry/examples/button-demo.tsx +6 -6
  166. package/registry/examples/button-group-demo.tsx +23 -2
  167. package/registry/examples/card-demo.tsx +46 -8
  168. package/registry/examples/carousel-demo.tsx +20 -2
  169. package/registry/examples/chart-demo.tsx +1 -1
  170. package/registry/examples/checkbox-demo.tsx +5 -5
  171. package/registry/examples/collection-filter-bar-demo.tsx +135 -0
  172. package/registry/examples/command-demo.tsx +3 -3
  173. package/registry/examples/{expanded/command-bar-demo.tsx → command-palette-demo.tsx} +5 -15
  174. package/registry/examples/context-menu-demo.tsx +1 -1
  175. package/registry/examples/control-density-contract-demo.tsx +61 -0
  176. package/registry/examples/date-picker-demo.tsx +12 -12
  177. package/registry/examples/divider-demo.tsx +3 -3
  178. package/registry/examples/expanded/banner-demo.tsx +1 -1
  179. package/registry/examples/expanded/breadcrumbs-demo.tsx +1 -1
  180. package/registry/examples/expanded/empty-state-demo.tsx +1 -1
  181. package/registry/examples/expanded/file-upload-demo.tsx +1 -1
  182. package/registry/examples/expanded/onboarding-step-demo.tsx +1 -1
  183. package/registry/examples/expanded/slideout-demo.tsx +2 -2
  184. package/registry/examples/expanded/steps-demo.tsx +1 -1
  185. package/registry/examples/expanded/tabs-demo.tsx +1 -1
  186. package/registry/examples/expanded/timeline-demo.tsx +1 -1
  187. package/registry/examples/hover-card-demo.tsx +2 -2
  188. package/registry/examples/input-demo.tsx +6 -6
  189. package/registry/examples/input-otp-demo.tsx +4 -4
  190. package/registry/examples/item-demo.tsx +46 -0
  191. package/registry/examples/kbd-demo.tsx +1 -1
  192. package/registry/examples/label-demo.tsx +1 -1
  193. package/registry/examples/menu-demo.tsx +1 -1
  194. package/registry/examples/modal-demo.tsx +67 -9
  195. package/registry/examples/navigation-menu-demo.tsx +1 -1
  196. package/registry/examples/pagination-demo.tsx +6 -3
  197. package/registry/examples/popover-demo.tsx +19 -19
  198. package/registry/examples/progress-demo.tsx +1 -1
  199. package/registry/examples/progress-slider-demo.tsx +1 -1
  200. package/registry/examples/radio-card-demo.tsx +4 -4
  201. package/registry/examples/radio-group-demo.tsx +2 -2
  202. package/registry/examples/resizable-demo.tsx +1 -1
  203. package/registry/examples/results-toolbar-demo.tsx +44 -0
  204. package/registry/examples/scroll-area-demo.tsx +3 -3
  205. package/registry/examples/segmented-control-demo.tsx +39 -0
  206. package/registry/examples/select-demo.tsx +1 -1
  207. package/registry/examples/sidebar-demo.tsx +1 -1
  208. package/registry/examples/slider-demo.tsx +3 -3
  209. package/registry/examples/social-button-demo.tsx +18 -8
  210. package/registry/examples/spinner-demo.tsx +13 -13
  211. package/registry/examples/tabs-demo.tsx +1 -1
  212. package/registry/examples/tag-demo.tsx +1 -1
  213. package/registry/examples/textarea-demo.tsx +4 -4
  214. package/registry/examples/toast-demo.tsx +1 -1
  215. package/registry/examples/toggle-demo.tsx +6 -6
  216. package/registry/examples/tooltip-demo.tsx +4 -4
  217. package/registry/guidance/USAGE.md +27 -0
  218. package/registry/hooks/use-direction.ts +193 -13
  219. package/registry/index.json +5311 -377
  220. package/registry/styles/globals.css +2440 -4061
  221. package/registry.json +119 -149
  222. package/schema/config.schema.json +11 -8
  223. package/schema/registry.schema.json +150 -45
  224. package/schema/tokens.schema.json +134 -34
  225. package/src/cli/command-line.js +194 -0
  226. package/src/cli/config-editors.js +9 -0
  227. package/src/cli/doctor.js +399 -0
  228. package/src/cli/file-transaction.js +295 -0
  229. package/src/cli/global-css.js +153 -0
  230. package/src/cli/index.js +567 -1613
  231. package/src/cli/install-plan.js +592 -0
  232. package/src/cli/install-receipt.js +171 -0
  233. package/src/cli/jsonc.js +203 -0
  234. package/src/cli/package-install-state.js +254 -0
  235. package/src/cli/package-manager.js +238 -0
  236. package/src/cli/package-plan.js +185 -0
  237. package/src/cli/package-version.js +97 -0
  238. package/src/cli/registry-query.js +207 -0
  239. package/src/cli/reporting.js +55 -0
  240. package/src/cli/schema-validation.js +19 -0
  241. package/src/cli/source-scanner.js +686 -0
  242. package/src/cli/vite-config.js +478 -0
  243. package/tokens/banhaten.tokens.json +4312 -309
  244. package/docs/design-system/components/command-bar.md +0 -57
  245. package/registry/components/expanded/BannerBoard.tsx +0 -225
  246. package/registry/components/expanded/CatalogTag.tsx +0 -85
  247. package/registry/components/expanded/CommandBar.tsx +0 -386
  248. package/registry/components/expanded/IconExplorer.tsx +0 -612
  249. package/registry/components/expanded/TimelineShowcase.tsx +0 -158
  250. package/registry/components/expanded/commandBar.css +0 -470
  251. package/registry/components/expanded/iconExplorer.css +0 -764
  252. package/registry/components/expanded/iconPacks.ts +0 -866
  253. package/registry/components/expanded/tag.css +0 -148
  254. package/registry/examples/expanded/icons-demo.tsx +0 -5
  255. package/tokens/Color mode.zip +0 -0
  256. package/tokens/Numbers.zip +0 -0
  257. package/tokens/Radius.zip +0 -0
  258. package/tokens/Theme.zip +0 -0
@@ -7,6 +7,7 @@ import {
7
7
  } from "lucide-react"
8
8
 
9
9
  import { cn } from "@/lib/utils"
10
+ import { useResolvedDirection } from "@/hooks/use-direction"
10
11
 
11
12
  type SocialPlatform =
12
13
  | "apple"
@@ -18,15 +19,15 @@ type SocialPlatform =
18
19
 
19
20
  type SocialButtonVariant = "solid" | "outline"
20
21
  type SocialButtonSize = "default" | "icon"
22
+ type SocialButtonMessages = Record<SocialPlatform, string>
21
23
  type SocialButtonIconComponent = React.ComponentType<
22
24
  React.SVGProps<SVGSVGElement> & {
23
- strokeWidth?: number
25
+ strokeWidth?: number | string
24
26
  }
25
27
  >
26
28
 
27
29
  type SocialPlatformConfig = {
28
30
  label: string
29
- labelAr: string
30
31
  solidBg: string
31
32
  solidHover: string
32
33
  solidBorder: string
@@ -43,7 +44,6 @@ type SocialPlatformConfig = {
43
44
  const socialPlatformConfig: Record<SocialPlatform, SocialPlatformConfig> = {
44
45
  apple: {
45
46
  label: "Sign in with Apple",
46
- labelAr: "تسجيل الدخول بأبل",
47
47
  solidBg: "var(--bh-social-apple-bg)",
48
48
  solidHover: "var(--bh-social-apple-hover)",
49
49
  solidBorder: "var(--bh-social-apple-border)",
@@ -55,7 +55,6 @@ const socialPlatformConfig: Record<SocialPlatform, SocialPlatformConfig> = {
55
55
  },
56
56
  facebook: {
57
57
  label: "Sign in with Facebook",
58
- labelAr: "تسجيل الدخول بفيسبوك",
59
58
  solidBg: "var(--bh-social-facebook-bg)",
60
59
  solidHover: "var(--bh-social-facebook-hover)",
61
60
  solidBorder: "transparent",
@@ -66,7 +65,6 @@ const socialPlatformConfig: Record<SocialPlatform, SocialPlatformConfig> = {
66
65
  },
67
66
  google: {
68
67
  label: "Sign in with Google",
69
- labelAr: "تسجيل الدخول بجوجل",
70
68
  solidBg: "var(--bh-social-google-bg)",
71
69
  solidHover: "var(--bh-social-google-hover)",
72
70
  solidBorder: "var(--bh-social-google-border)",
@@ -77,7 +75,6 @@ const socialPlatformConfig: Record<SocialPlatform, SocialPlatformConfig> = {
77
75
  },
78
76
  linkedin: {
79
77
  label: "Sign in with LinkedIn",
80
- labelAr: "تسجيل الدخول باستخدام لينكد إن",
81
78
  solidBg: "var(--bh-social-linkedin-bg)",
82
79
  solidHover: "var(--bh-social-linkedin-hover)",
83
80
  solidBorder: "transparent",
@@ -88,7 +85,6 @@ const socialPlatformConfig: Record<SocialPlatform, SocialPlatformConfig> = {
88
85
  },
89
86
  twitter: {
90
87
  label: "Sign in with Twitter",
91
- labelAr: "تسجيل الدخول باستخدام تويتر",
92
88
  solidBg: "var(--bh-social-twitter-bg)",
93
89
  solidHover: "var(--bh-social-twitter-hover)",
94
90
  solidBorder: "var(--bh-social-twitter-border)",
@@ -100,7 +96,6 @@ const socialPlatformConfig: Record<SocialPlatform, SocialPlatformConfig> = {
100
96
  },
101
97
  whatsapp: {
102
98
  label: "Sign in with WhatsApp",
103
- labelAr: "تسجيل الدخول باستخدام واتساب",
104
99
  solidBg: "var(--bh-social-whatsapp-bg)",
105
100
  solidHover: "var(--bh-social-whatsapp-hover)",
106
101
  solidBorder: "transparent",
@@ -111,6 +106,15 @@ const socialPlatformConfig: Record<SocialPlatform, SocialPlatformConfig> = {
111
106
  },
112
107
  }
113
108
 
109
+ const arabicSocialButtonMessages: SocialButtonMessages = {
110
+ apple: "تسجيل الدخول بأبل",
111
+ facebook: "تسجيل الدخول بفيسبوك",
112
+ google: "تسجيل الدخول بجوجل",
113
+ linkedin: "تسجيل الدخول باستخدام لينكد إن",
114
+ twitter: "تسجيل الدخول باستخدام تويتر",
115
+ whatsapp: "تسجيل الدخول باستخدام واتساب",
116
+ }
117
+
114
118
  const socialButtonVariants = cva(
115
119
  "group/social-button relative inline-flex items-center justify-center whitespace-nowrap rounded-[var(--bh-social-button-radius)] bg-[var(--bh-social-button-bg)] text-[var(--bh-social-button-fg)] shadow-[var(--shadow-social-button)] outline-none transition-[background-color,box-shadow,color] [--bh-social-button-current-border:var(--bh-social-button-border)] [--shadow-social-button:inset_0px_0px_0px_var(--bh-border-width-default)_var(--bh-social-button-current-border,var(--bh-social-button-border,transparent)),var(--shadow-component-default)] rtl:[--bh-social-button-width:var(--bh-social-button-width-rtl)] hover:bg-[var(--bh-social-button-bg-hover)] focus-visible:[--bh-social-button-current-border:var(--bh-social-button-focus-border)] focus-visible:shadow-[var(--shadow-social-button-focus)] disabled:pointer-events-none disabled:opacity-[var(--bh-opacity-50)] [&_svg]:pointer-events-none [&_svg]:shrink-0",
116
120
  {
@@ -138,6 +142,7 @@ type SocialButtonProps = Omit<React.ComponentProps<"button">, "children"> &
138
142
  asChild?: boolean
139
143
  children?: React.ReactNode
140
144
  label?: string
145
+ messages?: Partial<SocialButtonMessages>
141
146
  }
142
147
 
143
148
  const SocialButton = React.forwardRef<HTMLButtonElement, SocialButtonProps>(function SocialButton({
@@ -146,6 +151,7 @@ const SocialButton = React.forwardRef<HTMLButtonElement, SocialButtonProps>(func
146
151
  variant = "solid",
147
152
  size = "default",
148
153
  label,
154
+ messages,
149
155
  asChild = false,
150
156
  children,
151
157
  dir,
@@ -154,12 +160,25 @@ const SocialButton = React.forwardRef<HTMLButtonElement, SocialButtonProps>(func
154
160
  "aria-label": ariaLabel,
155
161
  ...props
156
162
  }, ref) {
163
+ const rootRef = React.useRef<HTMLButtonElement | null>(null)
164
+ const resolvedDirection = useResolvedDirection(
165
+ dir === "ltr" || dir === "rtl" ? dir : undefined,
166
+ rootRef
167
+ )
168
+ const setRootRef = React.useCallback(
169
+ (node: HTMLButtonElement | null) => {
170
+ rootRef.current = node
171
+ if (typeof ref === "function") ref(node)
172
+ else if (ref) ref.current = node
173
+ },
174
+ [ref]
175
+ )
157
176
  const config = socialPlatformConfig[platform]
158
177
  const selectedVariant = variant || "solid"
159
178
  const selectedSize = size || "default"
160
179
  const isIcon = selectedSize === "icon"
161
- const defaultLabel = getDefaultLabel(config, dir)
162
- const visibleLabel = label || (isSimpleLabel(children) ? children : defaultLabel)
180
+ const defaultLabel = messages?.[platform] ?? config.label
181
+ const visibleLabel = label ?? (isSimpleLabel(children) ? children : defaultLabel)
163
182
  const accessibleLabel =
164
183
  typeof visibleLabel === "string" || typeof visibleLabel === "number"
165
184
  ? String(visibleLabel)
@@ -192,8 +211,8 @@ const SocialButton = React.forwardRef<HTMLButtonElement, SocialButtonProps>(func
192
211
  data-size={selectedSize}
193
212
  data-slot="social-button"
194
213
  data-variant={selectedVariant}
195
- dir={dir}
196
- ref={ref}
214
+ dir={resolvedDirection}
215
+ ref={setRootRef}
197
216
  className={cn(
198
217
  socialButtonVariants({
199
218
  variant: selectedVariant,
@@ -216,13 +235,6 @@ function isSimpleLabel(
216
235
  return typeof value === "string" || typeof value === "number"
217
236
  }
218
237
 
219
- function getDefaultLabel(
220
- config: SocialPlatformConfig,
221
- dir: React.HTMLAttributes<HTMLElement>["dir"]
222
- ) {
223
- return dir === "rtl" ? config.labelAr : config.label
224
- }
225
-
226
238
  function getSocialButtonVars(
227
239
  config: SocialPlatformConfig,
228
240
  variant: SocialButtonVariant,
@@ -270,7 +282,11 @@ function SocialButtonIcon({
270
282
  className="size-[var(--bh-social-button-icon-size)]"
271
283
  data-slot="social-button-icon"
272
284
  focusable="false"
273
- strokeWidth={platform === "apple" ? 2 : 2.25}
285
+ strokeWidth={
286
+ platform === "apple"
287
+ ? "var(--bh-icon-stroke-200)"
288
+ : "var(--bh-icon-stroke-225)"
289
+ }
274
290
  style={{ color: "var(--bh-social-button-icon)" }}
275
291
  />
276
292
  )
@@ -280,7 +296,7 @@ function FacebookBrandIcon({
280
296
  strokeWidth: _strokeWidth,
281
297
  ...props
282
298
  }: React.SVGProps<SVGSVGElement> & {
283
- strokeWidth?: number
299
+ strokeWidth?: number | string
284
300
  }) {
285
301
  return (
286
302
  <svg viewBox="0 0 24 24" fill="none" {...props}>
@@ -296,7 +312,7 @@ function GoogleBrandIcon({
296
312
  strokeWidth: _strokeWidth,
297
313
  ...props
298
314
  }: React.SVGProps<SVGSVGElement> & {
299
- strokeWidth?: number
315
+ strokeWidth?: number | string
300
316
  }) {
301
317
  return (
302
318
  <svg viewBox="0 0 24 24" fill="none" {...props}>
@@ -312,7 +328,7 @@ function LinkedinBrandIcon({
312
328
  strokeWidth: _strokeWidth,
313
329
  ...props
314
330
  }: React.SVGProps<SVGSVGElement> & {
315
- strokeWidth?: number
331
+ strokeWidth?: number | string
316
332
  }) {
317
333
  return (
318
334
  <svg viewBox="0 0 24 24" fill="none" {...props}>
@@ -328,7 +344,7 @@ function TwitterBrandIcon({
328
344
  strokeWidth: _strokeWidth,
329
345
  ...props
330
346
  }: React.SVGProps<SVGSVGElement> & {
331
- strokeWidth?: number
347
+ strokeWidth?: number | string
332
348
  }) {
333
349
  return (
334
350
  <svg viewBox="0 0 24 24" fill="none" {...props}>
@@ -349,8 +365,14 @@ const socialButtonIcons: Record<SocialPlatform, SocialButtonIconComponent> = {
349
365
  whatsapp: MessageCircleIcon,
350
366
  }
351
367
 
352
- export { SocialButton, socialButtonVariants, socialPlatformConfig }
368
+ export {
369
+ arabicSocialButtonMessages,
370
+ SocialButton,
371
+ socialButtonVariants,
372
+ socialPlatformConfig,
373
+ }
353
374
  export type {
375
+ SocialButtonMessages,
354
376
  SocialButtonProps,
355
377
  SocialButtonSize,
356
378
  SocialButtonVariant,
@@ -40,7 +40,7 @@ function SpinnerBase({ className, motion, ...props }: SpinnerBaseProps) {
40
40
  r="10"
41
41
  fill="none"
42
42
  stroke="currentColor"
43
- strokeWidth="4"
43
+ strokeWidth="var(--bh-spinner-stroke-width)"
44
44
  opacity="var(--bh-opacity-25)"
45
45
  />
46
46
  <circle
@@ -50,64 +50,27 @@ function SpinnerBase({ className, motion, ...props }: SpinnerBaseProps) {
50
50
  r="10"
51
51
  fill="none"
52
52
  stroke="currentColor"
53
- strokeWidth="4"
53
+ strokeWidth="var(--bh-spinner-stroke-width)"
54
54
  strokeLinecap="round"
55
55
  pathLength="100"
56
56
  strokeDasharray="30 70"
57
- >
58
- {motion === "dynamic" ? (
59
- <DynamicSpinnerMotion />
60
- ) : (
61
- <SteadySpinnerMotion />
62
- )}
63
- </circle>
64
- </svg>
65
- )
66
- }
67
-
68
- function DynamicSpinnerMotion() {
69
- return (
70
- <>
71
- <animate
72
- attributeName="stroke-dasharray"
73
- calcMode="spline"
74
- dur="6s"
75
- keySplines="0.45 0 0.55 1; 0.45 0 0.55 1; 0.45 0 0.55 1; 0.45 0 0.55 1"
76
- keyTimes="0; 0.25; 0.5; 0.75; 1"
77
- repeatCount="indefinite"
78
- values="22 78; 38 62; 30 70; 42 58; 22 78"
79
- />
80
- <animate
81
- attributeName="stroke-dashoffset"
82
- calcMode="spline"
83
- dur="6s"
84
- keySplines="0.45 0 0.55 1; 0.45 0 0.55 1; 0.45 0 0.55 1; 0.45 0 0.55 1"
85
- keyTimes="0; 0.25; 0.5; 0.75; 1"
86
- repeatCount="indefinite"
87
- values="0; -16; -44; -72; -100"
57
+ style={{
58
+ animationDuration:
59
+ motion === "dynamic"
60
+ ? "var(--bh-spinner-duration-dynamic)"
61
+ : "var(--bh-spinner-duration-steady)",
62
+ animationIterationCount: "infinite",
63
+ animationName:
64
+ motion === "dynamic"
65
+ ? "bh-spinner-dynamic"
66
+ : "bh-spinner-steady",
67
+ animationTimingFunction:
68
+ motion === "dynamic" ? "var(--bh-spinner-easing)" : "linear",
69
+ transformBox: "fill-box",
70
+ transformOrigin: "center",
71
+ }}
88
72
  />
89
- <animateTransform
90
- attributeName="transform"
91
- dur="6s"
92
- from="0 12 12"
93
- repeatCount="indefinite"
94
- to="1080 12 12"
95
- type="rotate"
96
- />
97
- </>
98
- )
99
- }
100
-
101
- function SteadySpinnerMotion() {
102
- return (
103
- <animateTransform
104
- attributeName="transform"
105
- dur="1.5s"
106
- from="0 12 12"
107
- repeatCount="indefinite"
108
- to="360 12 12"
109
- type="rotate"
110
- />
73
+ </svg>
111
74
  )
112
75
  }
113
76
 
@@ -93,7 +93,7 @@
93
93
  .ds-tabs__tab:disabled,
94
94
  .ds-tabs__tab[data-disabled] {
95
95
  cursor: not-allowed;
96
- opacity: var(--bh-opacity-disabled);
96
+ opacity: var(--bh-opacity-60);
97
97
  }
98
98
 
99
99
  .ds-tabs__tab:focus-visible {
@@ -4,6 +4,7 @@ import * as React from "react"
4
4
  import * as TabsPrimitive from "@radix-ui/react-tabs"
5
5
 
6
6
  import { cn } from "@/lib/utils"
7
+ import { useResolvedDirection } from "@/hooks/use-direction"
7
8
 
8
9
  import "./tabs.css"
9
10
 
@@ -84,7 +85,7 @@ const TabsList = React.forwardRef<
84
85
  `ds-tabs--${variant}`,
85
86
  `ds-tabs--${size}`,
86
87
  fullWidth ? "ds-tabs--full" : "ds-tabs--hug",
87
- isRtl ? "ds-tabs--rtl" : "ds-tabs--ltr",
88
+ isRtl ? "ds-tabs--rtl" : dir === "ltr" ? "ds-tabs--ltr" : undefined,
88
89
  className
89
90
  )}
90
91
  {...props}
@@ -133,7 +134,7 @@ function Tabs({
133
134
  className = "",
134
135
  defaultActiveIndex = 0,
135
136
  defaultValue,
136
- dir = "ltr",
137
+ dir,
137
138
  fullWidth = false,
138
139
  items = [],
139
140
  onActiveIndexChange,
@@ -144,6 +145,8 @@ function Tabs({
144
145
  variant = "underline",
145
146
  ...props
146
147
  }: TabsProps) {
148
+ const rootRef = React.useRef<React.ElementRef<typeof TabsPrimitive.Root>>(null)
149
+ const resolvedDirection = useResolvedDirection(dir, rootRef)
147
150
  const normalizedItems = items.map(normalizeTabsItem)
148
151
  const activeValue =
149
152
  value ?? (activeIndex === undefined ? undefined : normalizedItems[activeIndex]?.value)
@@ -166,7 +169,8 @@ function Tabs({
166
169
  <TabsRoot
167
170
  data-slot="tabs-root"
168
171
  defaultValue={activeValue === undefined ? uncontrolledDefaultValue : undefined}
169
- dir={dir}
172
+ dir={resolvedDirection}
173
+ ref={rootRef}
170
174
  value={activeValue}
171
175
  onValueChange={handleValueChange}
172
176
  className={rootClassName}
@@ -175,7 +179,7 @@ function Tabs({
175
179
  <TabsList
176
180
  aria-label={ariaLabel}
177
181
  className={className}
178
- dir={dir}
182
+ dir={resolvedDirection}
179
183
  fullWidth={fullWidth}
180
184
  size={size}
181
185
  variant={variant}
@@ -372,7 +372,7 @@ function TagIcon({
372
372
  )}
373
373
  {...props}
374
374
  >
375
- {children ?? <PlusIcon aria-hidden="true" strokeWidth={2.25} />}
375
+ {children ?? <PlusIcon aria-hidden="true" strokeWidth="var(--bh-icon-stroke-225)" />}
376
376
  </span>
377
377
  )
378
378
  }
@@ -405,7 +405,7 @@ function TagCloseButton({
405
405
  <XIcon
406
406
  aria-hidden="true"
407
407
  className="size-[var(--bh-space-xl-12)]"
408
- strokeWidth={2}
408
+ strokeWidth="var(--bh-icon-stroke-200)"
409
409
  />
410
410
  </button>
411
411
  )
@@ -539,14 +539,14 @@ function TextareaIcon({
539
539
  aria-hidden="true"
540
540
  className="size-[var(--bh-textarea-helper-icon-size)]"
541
541
  focusable="false"
542
- strokeWidth={2.25}
542
+ strokeWidth="var(--bh-icon-stroke-225)"
543
543
  />
544
544
  ) : (
545
545
  <InfoIcon
546
546
  aria-hidden="true"
547
547
  className="size-[var(--bh-textarea-helper-icon-size)]"
548
548
  focusable="false"
549
- strokeWidth={2.25}
549
+ strokeWidth="var(--bh-icon-stroke-225)"
550
550
  />
551
551
  )}
552
552
  </span>
@@ -563,7 +563,7 @@ function CloseIcon() {
563
563
  aria-hidden="true"
564
564
  className="size-[var(--bh-textarea-close-icon-size)]"
565
565
  focusable="false"
566
- strokeWidth={2.5}
566
+ strokeWidth="var(--bh-icon-stroke-250)"
567
567
  />
568
568
  </span>
569
569
  )
@@ -9,6 +9,7 @@ import {
9
9
  } from "sonner"
10
10
 
11
11
  import { cn } from "@/lib/utils"
12
+ import { useResolvedDirection } from "@/hooks/use-direction"
12
13
 
13
14
  type ToastIntent = "default" | "success" | "danger" | "warning" | "info"
14
15
  type ToastSide = "start" | "end"
@@ -54,7 +55,9 @@ function Toaster({
54
55
  toastOptions,
55
56
  ...props
56
57
  }: ToasterProps) {
57
- const resolvedPosition = position ?? getToastPosition(dir, side)
58
+ const directionBoundaryRef = React.useRef<HTMLSpanElement | null>(null)
59
+ const resolvedDirection = useResolvedDirection(dir, directionBoundaryRef)
60
+ const resolvedPosition = position ?? getToastPosition(resolvedDirection, side)
58
61
  const mergedToastOptions: ToasterProps["toastOptions"] = {
59
62
  ...toastOptions,
60
63
  classNames: {
@@ -69,7 +72,7 @@ function Toaster({
69
72
  toastOptions?.classNames?.description
70
73
  ),
71
74
  actionButton: cn(
72
- "rounded-[var(--bh-control-default)] bg-[var(--bh-interactive-primary-default)] px-[var(--bh-space-lg-10)] py-[var(--bh-space-xs-4)] text-[var(--bh-content-on-color)]",
75
+ "rounded-[var(--bh-control-default)] bg-[var(--bh-interactive-brand-default)] px-[var(--bh-space-lg-10)] py-[var(--bh-space-xs-4)] text-[var(--bh-content-on-brand)]",
73
76
  toastOptions?.classNames?.actionButton
74
77
  ),
75
78
  cancelButton: cn(
@@ -80,15 +83,17 @@ function Toaster({
80
83
  }
81
84
 
82
85
  return (
83
- <SonnerToaster
84
- className={cn("toaster group", className)}
85
- closeButton={closeButton}
86
- dir={dir}
87
- position={resolvedPosition}
88
- richColors={richColors}
89
- toastOptions={mergedToastOptions}
90
- {...props}
91
- />
86
+ <span className="contents" data-slot="toaster-direction-boundary" ref={directionBoundaryRef}>
87
+ <SonnerToaster
88
+ className={cn("toaster group", className)}
89
+ closeButton={closeButton}
90
+ dir={resolvedDirection}
91
+ position={resolvedPosition}
92
+ richColors={richColors}
93
+ toastOptions={mergedToastOptions}
94
+ {...props}
95
+ />
96
+ </span>
92
97
  )
93
98
  }
94
99
 
@@ -231,7 +231,7 @@ function ToggleCheckIcon({ className }: { className?: string }) {
231
231
  aria-hidden="true"
232
232
  className={className}
233
233
  focusable="false"
234
- strokeWidth={2.5}
234
+ strokeWidth="var(--bh-icon-stroke-250)"
235
235
  />
236
236
  )
237
237
  }
@@ -242,7 +242,7 @@ function ToggleCloseIcon({ className }: { className?: string }) {
242
242
  aria-hidden="true"
243
243
  className={className}
244
244
  focusable="false"
245
- strokeWidth={2.5}
245
+ strokeWidth="var(--bh-icon-stroke-250)"
246
246
  />
247
247
  )
248
248
  }