banhaten 0.1.3 → 0.3.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.
- package/CHANGELOG.md +73 -0
- package/CONTRIBUTING.md +44 -0
- package/README.md +65 -13
- package/SECURITY.md +15 -0
- package/banhaten.config.example.json +0 -2
- package/docs/design-system/README.md +9 -0
- package/docs/design-system/adoption-quality-remediation.md +87 -0
- package/docs/design-system/agent-usage.md +13 -0
- package/docs/design-system/appearance-presets.md +6 -1
- package/docs/design-system/component-docs-pattern.md +81 -0
- package/docs/design-system/component-implementation-ownership-audit.md +244 -0
- package/docs/design-system/component-quality-audit-2026-08-20.md +223 -0
- package/docs/design-system/component-showcase-consistency-report.md +2 -0
- package/docs/design-system/component-token-consistency-audit.md +13 -3
- package/docs/design-system/components/README.md +4 -2
- package/docs/design-system/components/accordion.md +16 -0
- package/docs/design-system/components/activity-feed.md +17 -1
- package/docs/design-system/components/activity-heatmap.md +73 -0
- package/docs/design-system/components/alert-dialog.md +17 -0
- package/docs/design-system/components/alert.md +46 -14
- package/docs/design-system/components/aspect-ratio.md +15 -0
- package/docs/design-system/components/attribute.md +16 -0
- package/docs/design-system/components/autocomplete.md +19 -0
- package/docs/design-system/components/avatar.md +18 -0
- package/docs/design-system/components/badge.md +19 -0
- package/docs/design-system/components/banner.md +19 -1
- package/docs/design-system/components/breadcrumbs.md +17 -0
- package/docs/design-system/components/button-group.md +35 -0
- package/docs/design-system/components/button.md +18 -0
- package/docs/design-system/components/card.md +26 -1
- package/docs/design-system/components/carousel.md +20 -3
- package/docs/design-system/components/catalog-components.md +18 -1
- package/docs/design-system/components/chart.md +15 -0
- package/docs/design-system/components/checkbox.md +16 -0
- package/docs/design-system/components/collapsible.md +15 -0
- package/docs/design-system/components/command.md +15 -0
- package/docs/design-system/components/context-menu.md +15 -0
- package/docs/design-system/components/date-picker.md +21 -1
- package/docs/design-system/components/divider.md +16 -0
- package/docs/design-system/components/empty-state.md +17 -0
- package/docs/design-system/components/field.md +17 -0
- package/docs/design-system/components/file-upload.md +18 -0
- package/docs/design-system/components/hover-card.md +15 -0
- package/docs/design-system/components/input-group.md +17 -0
- package/docs/design-system/components/input-otp.md +18 -0
- package/docs/design-system/components/input.md +43 -7
- package/docs/design-system/components/item.md +72 -0
- package/docs/design-system/components/kbd.md +18 -0
- package/docs/design-system/components/label.md +16 -0
- package/docs/design-system/components/menu.md +17 -0
- package/docs/design-system/components/menubar.md +15 -0
- package/docs/design-system/components/modal.md +25 -4
- package/docs/design-system/components/native-select.md +18 -0
- package/docs/design-system/components/navigation-menu.md +15 -0
- package/docs/design-system/components/onboarding-step-list-item.md +16 -1
- package/docs/design-system/components/page-header.md +17 -1
- package/docs/design-system/components/pagination.md +31 -8
- package/docs/design-system/components/popover.md +19 -0
- package/docs/design-system/components/progress-slider.md +18 -0
- package/docs/design-system/components/progress.md +17 -0
- package/docs/design-system/components/radio-card.md +16 -0
- package/docs/design-system/components/radio-group.md +17 -0
- package/docs/design-system/components/resizable.md +15 -0
- package/docs/design-system/components/scroll-area.md +20 -1
- package/docs/design-system/components/segmented-control.md +71 -0
- package/docs/design-system/components/select.md +44 -7
- package/docs/design-system/components/sheet.md +17 -0
- package/docs/design-system/components/sidebar.md +17 -0
- package/docs/design-system/components/skeleton.md +18 -0
- package/docs/design-system/components/slideout.md +17 -0
- package/docs/design-system/components/slider.md +20 -0
- package/docs/design-system/components/social-button.md +21 -3
- package/docs/design-system/components/spinner.md +16 -0
- package/docs/design-system/components/steps.md +19 -0
- package/docs/design-system/components/table.md +36 -4
- package/docs/design-system/components/tabs.md +17 -0
- package/docs/design-system/components/tag.md +17 -0
- package/docs/design-system/components/textarea.md +16 -0
- package/docs/design-system/components/timeline.md +17 -0
- package/docs/design-system/components/toast.md +17 -0
- package/docs/design-system/components/toggle.md +17 -0
- package/docs/design-system/components/toolbar.md +21 -1
- package/docs/design-system/components/tooltip.md +18 -1
- package/docs/design-system/density-and-elevation.md +61 -0
- package/docs/design-system/direction-and-localization.md +23 -0
- package/docs/design-system/form-recipes.md +73 -0
- package/docs/design-system/gap-promotion-policy.md +21 -0
- package/docs/design-system/gap-promotion-report.md +100 -0
- package/docs/design-system/installation.md +68 -0
- package/docs/design-system/launch-comparison-shadcn.md +98 -0
- package/docs/design-system/registry-and-cli.md +30 -7
- package/docs/design-system/release-policy.md +30 -0
- package/docs/design-system/roadmap.md +14 -0
- package/docs/design-system/support-matrix.md +23 -0
- package/docs/design-system/tabs.md +1 -1
- package/docs/design-system/token-governance.md +23 -1
- package/package.json +30 -15
- package/registry/component-contract.json +40 -0
- package/registry/components/alert-dialog.tsx +2 -2
- package/registry/components/alert.tsx +101 -76
- package/registry/components/autocomplete.tsx +23 -9
- package/registry/components/avatar.tsx +14 -10
- package/registry/components/badge.tsx +18 -18
- package/registry/components/button-group.tsx +324 -5
- package/registry/components/button.tsx +38 -17
- package/registry/components/card.tsx +87 -62
- package/registry/components/carousel.tsx +67 -5
- package/registry/components/chart.tsx +36 -3
- package/registry/components/checkbox.tsx +3 -3
- package/registry/components/collapsible.tsx +1 -1
- package/registry/components/command.tsx +38 -4
- package/registry/components/context-menu.tsx +1 -1
- package/registry/components/date-picker.tsx +312 -135
- package/registry/components/expanded/ActivityFeed.tsx +9 -22
- package/registry/components/expanded/ActivityHeatmap.tsx +64 -0
- package/registry/components/expanded/Banner.tsx +3 -4
- package/registry/components/expanded/Breadcrumbs.tsx +8 -5
- package/registry/components/expanded/CatalogComponentsShowcase.tsx +16 -17
- package/registry/components/expanded/CatalogDivider.tsx +4 -3
- package/registry/components/expanded/EmptyState.tsx +1 -1
- package/registry/components/expanded/FileUpload.tsx +16 -7
- package/registry/components/expanded/OnboardingStepListItem.tsx +2 -6
- package/registry/components/expanded/PageHeader.tsx +47 -56
- package/registry/components/expanded/Slideout.tsx +29 -424
- package/registry/components/expanded/Steps.tsx +151 -13
- package/registry/components/expanded/Table.tsx +161 -82
- package/registry/components/expanded/Timeline.tsx +14 -27
- package/registry/components/expanded/activityFeed.css +9 -9
- package/registry/components/expanded/activityHeatmap.css +66 -0
- package/registry/components/expanded/banner.css +21 -11
- package/registry/components/expanded/breadcrumbs.css +2 -2
- package/registry/components/expanded/divider.css +1 -1
- package/registry/components/expanded/emptyState.css +1 -1
- package/registry/components/expanded/fileUpload.css +7 -7
- package/registry/components/expanded/onboardingStepListItem.css +2 -2
- package/registry/components/expanded/pageHeader.css +14 -11
- package/registry/components/expanded/slideout.css +10 -690
- package/registry/components/expanded/steps.css +78 -15
- package/registry/components/expanded/table.css +60 -69
- package/registry/components/expanded/timeline.css +19 -18
- package/registry/components/field.tsx +61 -8
- package/registry/components/input-content.ts +1 -0
- package/registry/components/input-otp.tsx +13 -3
- package/registry/components/input.tsx +68 -43
- package/registry/components/item.tsx +189 -0
- package/registry/components/kbd.tsx +111 -4
- package/registry/components/menu.tsx +87 -251
- package/registry/components/menubar.tsx +1 -1
- package/registry/components/modal.tsx +143 -103
- package/registry/components/native-select.tsx +2 -2
- package/registry/components/navigation-menu.tsx +1 -1
- package/registry/components/pagination.css +36 -0
- package/registry/components/pagination.tsx +88 -64
- package/registry/components/popover.tsx +162 -664
- package/registry/components/progress-slider.tsx +1 -1
- package/registry/components/radio-card.tsx +116 -87
- package/registry/components/resizable.tsx +36 -2
- package/registry/components/scroll-area.tsx +30 -6
- package/registry/components/segmented-control.tsx +87 -0
- package/registry/components/select-content.tsx +2 -2
- package/registry/components/select.tsx +86 -27
- package/registry/components/sheet.tsx +1 -1
- package/registry/components/sidebar.tsx +12 -6
- package/registry/components/skeleton.css +0 -3
- package/registry/components/social-button.tsx +59 -30
- package/registry/components/spinner.tsx +18 -55
- package/registry/components/table-elements.tsx +128 -0
- package/registry/components/tabs.css +1 -1
- package/registry/components/tabs.tsx +13 -14
- package/registry/components/tag.tsx +3 -3
- package/registry/components/textarea.tsx +3 -3
- package/registry/components/toast.tsx +16 -11
- package/registry/components/toggle.tsx +4 -4
- package/registry/components/toolbar.tsx +94 -22
- package/registry/components/tooltip.tsx +2 -2
- package/registry/examples/alert-demo.tsx +25 -5
- package/registry/examples/attribute-demo.tsx +1 -1
- package/registry/examples/autocomplete-demo.tsx +3 -3
- package/registry/examples/avatar-demo.tsx +14 -11
- package/registry/examples/badge-demo.tsx +1 -1
- package/registry/examples/button-demo.tsx +6 -6
- package/registry/examples/button-group-demo.tsx +23 -2
- package/registry/examples/card-demo.tsx +46 -8
- package/registry/examples/carousel-demo.tsx +20 -2
- package/registry/examples/chart-demo.tsx +1 -1
- package/registry/examples/checkbox-demo.tsx +5 -5
- package/registry/examples/collection-filter-bar-demo.tsx +135 -0
- package/registry/examples/command-demo.tsx +3 -3
- package/registry/examples/{expanded/command-bar-demo.tsx → command-palette-demo.tsx} +5 -15
- package/registry/examples/context-menu-demo.tsx +1 -1
- package/registry/examples/control-density-contract-demo.tsx +61 -0
- package/registry/examples/date-picker-demo.tsx +12 -12
- package/registry/examples/divider-demo.tsx +3 -3
- package/registry/examples/expanded/activity-heatmap-demo.tsx +29 -0
- package/registry/examples/expanded/banner-demo.tsx +1 -1
- package/registry/examples/expanded/breadcrumbs-demo.tsx +4 -4
- package/registry/examples/expanded/empty-state-demo.tsx +1 -1
- package/registry/examples/expanded/file-upload-demo.tsx +1 -1
- package/registry/examples/expanded/onboarding-step-demo.tsx +1 -1
- package/registry/examples/expanded/slideout-demo.tsx +2 -2
- package/registry/examples/expanded/steps-demo.tsx +1 -1
- package/registry/examples/expanded/tabs-demo.tsx +1 -1
- package/registry/examples/expanded/timeline-demo.tsx +1 -1
- package/registry/examples/hover-card-demo.tsx +2 -2
- package/registry/examples/input-demo.tsx +6 -6
- package/registry/examples/input-otp-demo.tsx +4 -4
- package/registry/examples/item-demo.tsx +46 -0
- package/registry/examples/kbd-demo.tsx +1 -1
- package/registry/examples/label-demo.tsx +1 -1
- package/registry/examples/menu-demo.tsx +1 -1
- package/registry/examples/modal-demo.tsx +67 -9
- package/registry/examples/navigation-menu-demo.tsx +1 -1
- package/registry/examples/pagination-demo.tsx +10 -7
- package/registry/examples/popover-demo.tsx +19 -19
- package/registry/examples/progress-demo.tsx +1 -1
- package/registry/examples/progress-slider-demo.tsx +1 -1
- package/registry/examples/radio-card-demo.tsx +4 -4
- package/registry/examples/radio-group-demo.tsx +2 -2
- package/registry/examples/resizable-demo.tsx +1 -1
- package/registry/examples/results-toolbar-demo.tsx +44 -0
- package/registry/examples/scroll-area-demo.tsx +3 -3
- package/registry/examples/segmented-control-demo.tsx +39 -0
- package/registry/examples/select-demo.tsx +1 -1
- package/registry/examples/sidebar-demo.tsx +5 -3
- package/registry/examples/slider-demo.tsx +3 -3
- package/registry/examples/social-button-demo.tsx +18 -8
- package/registry/examples/spinner-demo.tsx +13 -13
- package/registry/examples/tabs-demo.tsx +1 -1
- package/registry/examples/tag-demo.tsx +1 -1
- package/registry/examples/textarea-demo.tsx +4 -4
- package/registry/examples/toast-demo.tsx +1 -1
- package/registry/examples/toggle-demo.tsx +6 -6
- package/registry/examples/tooltip-demo.tsx +4 -4
- package/registry/guidance/USAGE.md +27 -0
- package/registry/hooks/use-direction.ts +193 -13
- package/registry/index.json +5668 -375
- package/registry/styles/globals.css +2404 -3999
- package/registry.json +156 -149
- package/schema/config.schema.json +11 -8
- package/schema/registry.schema.json +150 -45
- package/schema/tokens.schema.json +134 -34
- package/src/cli/command-line.js +194 -0
- package/src/cli/config-editors.js +9 -0
- package/src/cli/doctor.js +399 -0
- package/src/cli/file-transaction.js +295 -0
- package/src/cli/global-css.js +153 -0
- package/src/cli/index.js +567 -1613
- package/src/cli/install-plan.js +592 -0
- package/src/cli/install-receipt.js +171 -0
- package/src/cli/jsonc.js +203 -0
- package/src/cli/package-install-state.js +254 -0
- package/src/cli/package-manager.js +238 -0
- package/src/cli/package-plan.js +185 -0
- package/src/cli/package-version.js +97 -0
- package/src/cli/registry-query.js +207 -0
- package/src/cli/reporting.js +55 -0
- package/src/cli/schema-validation.js +19 -0
- package/src/cli/source-scanner.js +686 -0
- package/src/cli/vite-config.js +478 -0
- package/tokens/banhaten.tokens.json +4444 -331
- package/docs/design-system/components/command-bar.md +0 -57
- package/registry/components/expanded/BannerBoard.tsx +0 -225
- package/registry/components/expanded/CatalogTag.tsx +0 -85
- package/registry/components/expanded/CommandBar.tsx +0 -386
- package/registry/components/expanded/IconExplorer.tsx +0 -612
- package/registry/components/expanded/TimelineShowcase.tsx +0 -158
- package/registry/components/expanded/commandBar.css +0 -470
- package/registry/components/expanded/iconExplorer.css +0 -764
- package/registry/components/expanded/iconPacks.ts +0 -866
- package/registry/components/expanded/tag.css +0 -148
- package/registry/examples/expanded/icons-demo.tsx +0 -5
- package/tokens/Color mode.zip +0 -0
- package/tokens/Numbers.zip +0 -0
- package/tokens/Radius.zip +0 -0
- package/tokens/Theme.zip +0 -0
|
@@ -16,7 +16,8 @@ import {
|
|
|
16
16
|
type SelectStatusTone,
|
|
17
17
|
} from "./select-content"
|
|
18
18
|
|
|
19
|
-
type
|
|
19
|
+
type ControlDensity = "compact" | "default" | "comfortable"
|
|
20
|
+
type SelectSize = "lg" | "md" | "comfortable"
|
|
20
21
|
type SelectVisualState = "default" | "filled" | "error" | "disabled"
|
|
21
22
|
type SelectVariant = "default" | "soft"
|
|
22
23
|
type SelectSelectionType = "default" | "checkbox"
|
|
@@ -39,6 +40,7 @@ const selectTrigger = cva(
|
|
|
39
40
|
{
|
|
40
41
|
variants: {
|
|
41
42
|
size: {
|
|
43
|
+
comfortable: "py-[var(--bh-select-trigger-padding-y-comfortable)]",
|
|
42
44
|
lg: "py-[var(--bh-select-trigger-padding-y-lg)]",
|
|
43
45
|
md: "py-[var(--bh-select-trigger-padding-y-md)]",
|
|
44
46
|
},
|
|
@@ -120,6 +122,7 @@ const SelectRadixItemContext = React.createContext(false)
|
|
|
120
122
|
type SelectProps = Omit<React.ComponentProps<"div">, "children" | "dir"> & {
|
|
121
123
|
children?: React.ReactNode
|
|
122
124
|
defaultSelectValue?: string
|
|
125
|
+
density?: ControlDensity
|
|
123
126
|
dir?: "ltr" | "rtl" | "auto"
|
|
124
127
|
errorMessage?: React.ReactNode
|
|
125
128
|
expandIcon?: React.ReactNode | false
|
|
@@ -133,7 +136,7 @@ type SelectProps = Omit<React.ComponentProps<"div">, "children" | "dir"> & {
|
|
|
133
136
|
isOptional?: boolean
|
|
134
137
|
isRequired?: boolean
|
|
135
138
|
label?: React.ReactNode
|
|
136
|
-
leadingIcon?: React.ReactNode
|
|
139
|
+
leadingIcon?: React.ReactNode | false
|
|
137
140
|
onOpenChange?: (open: boolean) => void
|
|
138
141
|
onTriggerClick?: React.MouseEventHandler<HTMLButtonElement>
|
|
139
142
|
onValueChange?: (value: string) => void
|
|
@@ -158,7 +161,7 @@ type SelectProps = Omit<React.ComponentProps<"div">, "children" | "dir"> & {
|
|
|
158
161
|
| "value"
|
|
159
162
|
| "variant"
|
|
160
163
|
>
|
|
161
|
-
trailingIcon?: React.ReactNode
|
|
164
|
+
trailingIcon?: React.ReactNode | false
|
|
162
165
|
value?: React.ReactNode
|
|
163
166
|
variant?: SelectVariant
|
|
164
167
|
}
|
|
@@ -167,6 +170,7 @@ const Select = React.forwardRef<HTMLDivElement, SelectProps>(function Select({
|
|
|
167
170
|
children,
|
|
168
171
|
className,
|
|
169
172
|
defaultSelectValue,
|
|
173
|
+
density,
|
|
170
174
|
dir,
|
|
171
175
|
errorMessage,
|
|
172
176
|
expandIcon,
|
|
@@ -174,8 +178,8 @@ const Select = React.forwardRef<HTMLDivElement, SelectProps>(function Select({
|
|
|
174
178
|
hasHelperText,
|
|
175
179
|
hasInformationIcon = false,
|
|
176
180
|
hasLabel,
|
|
177
|
-
hasLeadingIcon
|
|
178
|
-
hasTrailingIcon
|
|
181
|
+
hasLeadingIcon,
|
|
182
|
+
hasTrailingIcon,
|
|
179
183
|
helperText,
|
|
180
184
|
isOptional = false,
|
|
181
185
|
isRequired = false,
|
|
@@ -188,7 +192,7 @@ const Select = React.forwardRef<HTMLDivElement, SelectProps>(function Select({
|
|
|
188
192
|
optionalText,
|
|
189
193
|
placeholder,
|
|
190
194
|
selectValue,
|
|
191
|
-
size
|
|
195
|
+
size,
|
|
192
196
|
state = "default",
|
|
193
197
|
triggerClassName,
|
|
194
198
|
triggerId,
|
|
@@ -199,6 +203,7 @@ const Select = React.forwardRef<HTMLDivElement, SelectProps>(function Select({
|
|
|
199
203
|
...props
|
|
200
204
|
}, ref) {
|
|
201
205
|
const generatedId = React.useId()
|
|
206
|
+
const resolvedSize = resolveSelectSize(density, size)
|
|
202
207
|
const resolvedDir = dir
|
|
203
208
|
const triggerVisualState = triggerProps?.disabled ? "disabled" : state
|
|
204
209
|
const isError = triggerVisualState === "error"
|
|
@@ -210,9 +215,18 @@ const Select = React.forwardRef<HTMLDivElement, SelectProps>(function Select({
|
|
|
210
215
|
const shouldRenderLabel = hasLabel ?? hasRenderableContent(selectedLabel)
|
|
211
216
|
const shouldRenderHelperText =
|
|
212
217
|
hasHelperText ?? hasRenderableContent(selectedHelper)
|
|
218
|
+
const shouldShowLeadingIcon =
|
|
219
|
+
leadingIcon !== false &&
|
|
220
|
+
(hasLeadingIcon ?? hasRenderableContent(leadingIcon))
|
|
221
|
+
const shouldShowTrailingIcon =
|
|
222
|
+
trailingIcon !== false &&
|
|
223
|
+
(hasTrailingIcon ?? hasRenderableContent(trailingIcon))
|
|
213
224
|
const shouldRenderMenu = React.Children.count(children) > 0
|
|
214
225
|
const selectId = triggerId || generatedId
|
|
215
226
|
const helperId = `${selectId}-helper`
|
|
227
|
+
const triggerAccessibleLabel = shouldRenderLabel
|
|
228
|
+
? undefined
|
|
229
|
+
: getAccessibleText(selectedValue) ?? getAccessibleText(selectedPlaceholder)
|
|
216
230
|
const rootOpenProps =
|
|
217
231
|
open === undefined ? { onOpenChange } : { open, onOpenChange }
|
|
218
232
|
|
|
@@ -226,6 +240,8 @@ const Select = React.forwardRef<HTMLDivElement, SelectProps>(function Select({
|
|
|
226
240
|
{...rootOpenProps}
|
|
227
241
|
>
|
|
228
242
|
<SelectRoot
|
|
243
|
+
data-density={density}
|
|
244
|
+
data-size={resolvedSize}
|
|
229
245
|
data-state={triggerVisualState}
|
|
230
246
|
data-variant={variant}
|
|
231
247
|
dir={resolvedDir}
|
|
@@ -248,18 +264,26 @@ const Select = React.forwardRef<HTMLDivElement, SelectProps>(function Select({
|
|
|
248
264
|
<div data-slot="select-control" className="relative w-full">
|
|
249
265
|
<SelectPrimitive.Trigger asChild>
|
|
250
266
|
<SelectTrigger
|
|
267
|
+
aria-label={triggerAccessibleLabel}
|
|
251
268
|
aria-describedby={shouldRenderHelperText ? helperId : undefined}
|
|
252
|
-
aria-expanded={open || undefined}
|
|
253
269
|
aria-haspopup="listbox"
|
|
254
270
|
aria-invalid={isError || undefined}
|
|
255
271
|
expandIcon={expandIcon}
|
|
256
272
|
id={selectId}
|
|
257
|
-
leadingIcon={
|
|
273
|
+
leadingIcon={
|
|
274
|
+
shouldShowLeadingIcon
|
|
275
|
+
? (leadingIcon ?? <SelectIcon name="user" />)
|
|
276
|
+
: false
|
|
277
|
+
}
|
|
258
278
|
onClick={onTriggerClick}
|
|
259
279
|
placeholder={selectedPlaceholder}
|
|
260
|
-
size={
|
|
280
|
+
size={resolvedSize}
|
|
261
281
|
state={triggerVisualState}
|
|
262
|
-
trailingIcon={
|
|
282
|
+
trailingIcon={
|
|
283
|
+
shouldShowTrailingIcon
|
|
284
|
+
? (trailingIcon ?? <SelectIcon name="info" />)
|
|
285
|
+
: false
|
|
286
|
+
}
|
|
263
287
|
value={selectedValue}
|
|
264
288
|
variant={variant}
|
|
265
289
|
className={triggerClassName}
|
|
@@ -415,6 +439,12 @@ function hasRenderableContent(content: React.ReactNode) {
|
|
|
415
439
|
)
|
|
416
440
|
}
|
|
417
441
|
|
|
442
|
+
function getAccessibleText(content: React.ReactNode) {
|
|
443
|
+
return typeof content === "string" || typeof content === "number"
|
|
444
|
+
? String(content)
|
|
445
|
+
: undefined
|
|
446
|
+
}
|
|
447
|
+
|
|
418
448
|
type SelectHelperTextProps = React.ComponentProps<"p"> & {
|
|
419
449
|
hasIcon?: boolean
|
|
420
450
|
type?: "default" | "error"
|
|
@@ -464,6 +494,7 @@ type SelectTriggerProps = Omit<
|
|
|
464
494
|
"children" | "value"
|
|
465
495
|
> &
|
|
466
496
|
VariantProps<typeof selectTrigger> & {
|
|
497
|
+
density?: ControlDensity
|
|
467
498
|
expandIcon?: React.ReactNode | false
|
|
468
499
|
leadingIcon?: React.ReactNode | false
|
|
469
500
|
placeholder?: React.ReactNode
|
|
@@ -475,11 +506,12 @@ const SelectTrigger = React.forwardRef<HTMLButtonElement, SelectTriggerProps>(
|
|
|
475
506
|
(
|
|
476
507
|
{
|
|
477
508
|
className,
|
|
509
|
+
density,
|
|
478
510
|
disabled,
|
|
479
511
|
expandIcon,
|
|
480
512
|
leadingIcon,
|
|
481
513
|
placeholder,
|
|
482
|
-
size
|
|
514
|
+
size,
|
|
483
515
|
state,
|
|
484
516
|
trailingIcon,
|
|
485
517
|
type = "button",
|
|
@@ -489,13 +521,15 @@ const SelectTrigger = React.forwardRef<HTMLButtonElement, SelectTriggerProps>(
|
|
|
489
521
|
},
|
|
490
522
|
ref
|
|
491
523
|
) => {
|
|
524
|
+
const resolvedSize = resolveSelectSize(density, size)
|
|
492
525
|
const hasValue = value !== undefined && value !== null && value !== ""
|
|
493
526
|
const visualState = disabled ? "disabled" : state ?? (hasValue ? "filled" : "default")
|
|
494
527
|
const isDisabled = visualState === "disabled"
|
|
495
528
|
|
|
496
529
|
return (
|
|
497
530
|
<button
|
|
498
|
-
data-
|
|
531
|
+
data-density={density}
|
|
532
|
+
data-size={resolvedSize}
|
|
499
533
|
data-slot="select-trigger"
|
|
500
534
|
data-state={visualState}
|
|
501
535
|
data-variant={variant}
|
|
@@ -503,7 +537,7 @@ const SelectTrigger = React.forwardRef<HTMLButtonElement, SelectTriggerProps>(
|
|
|
503
537
|
ref={ref}
|
|
504
538
|
type={type}
|
|
505
539
|
className={cn(
|
|
506
|
-
selectTrigger({ size, state: visualState, variant }),
|
|
540
|
+
selectTrigger({ size: resolvedSize, state: visualState, variant }),
|
|
507
541
|
className
|
|
508
542
|
)}
|
|
509
543
|
{...props}
|
|
@@ -512,12 +546,12 @@ const SelectTrigger = React.forwardRef<HTMLButtonElement, SelectTriggerProps>(
|
|
|
512
546
|
data-slot="select-trigger-main"
|
|
513
547
|
className="flex min-w-0 flex-1 items-center gap-[var(--bh-select-content-gap)]"
|
|
514
548
|
>
|
|
515
|
-
{leadingIcon
|
|
549
|
+
{hasRenderableContent(leadingIcon) ? (
|
|
516
550
|
<span
|
|
517
551
|
data-slot="select-leading-icon"
|
|
518
552
|
className="flex size-[var(--bh-select-icon-slot-size)] shrink-0 items-center justify-center text-[var(--bh-select-trigger-icon-color)] group-data-[state=disabled]/select-trigger:text-[var(--bh-content-disabled)] [&_svg:not([class*='size-'])]:size-[var(--bh-select-icon-size)]"
|
|
519
553
|
>
|
|
520
|
-
{leadingIcon
|
|
554
|
+
{leadingIcon}
|
|
521
555
|
</span>
|
|
522
556
|
) : null}
|
|
523
557
|
|
|
@@ -541,12 +575,12 @@ const SelectTrigger = React.forwardRef<HTMLButtonElement, SelectTriggerProps>(
|
|
|
541
575
|
</span>
|
|
542
576
|
</span>
|
|
543
577
|
|
|
544
|
-
{trailingIcon
|
|
578
|
+
{hasRenderableContent(trailingIcon) ? (
|
|
545
579
|
<span
|
|
546
580
|
data-slot="select-trailing-icon"
|
|
547
581
|
className="flex size-[var(--bh-select-icon-slot-size)] shrink-0 items-center justify-center text-[var(--bh-select-trigger-icon-color)] group-data-[state=disabled]/select-trigger:text-[var(--bh-content-disabled)] [&_svg:not([class*='size-'])]:size-[var(--bh-select-icon-size)]"
|
|
548
582
|
>
|
|
549
|
-
{trailingIcon
|
|
583
|
+
{trailingIcon}
|
|
550
584
|
</span>
|
|
551
585
|
) : null}
|
|
552
586
|
|
|
@@ -567,7 +601,14 @@ SelectTrigger.displayName = "SelectTrigger"
|
|
|
567
601
|
type SelectMenuProps = React.ComponentProps<"div">
|
|
568
602
|
|
|
569
603
|
const SelectMenu = React.forwardRef<HTMLDivElement, SelectMenuProps>(function SelectMenu(
|
|
570
|
-
{
|
|
604
|
+
{
|
|
605
|
+
"aria-label": ariaLabel = "Options",
|
|
606
|
+
children,
|
|
607
|
+
className,
|
|
608
|
+
onKeyDown,
|
|
609
|
+
role,
|
|
610
|
+
...props
|
|
611
|
+
},
|
|
571
612
|
ref
|
|
572
613
|
) {
|
|
573
614
|
const handleKeyDown = React.useCallback(
|
|
@@ -613,6 +654,7 @@ const SelectMenu = React.forwardRef<HTMLDivElement, SelectMenuProps>(function Se
|
|
|
613
654
|
|
|
614
655
|
return (
|
|
615
656
|
<div
|
|
657
|
+
aria-label={ariaLabel}
|
|
616
658
|
data-slot="select-menu"
|
|
617
659
|
onKeyDown={handleKeyDown}
|
|
618
660
|
ref={ref}
|
|
@@ -620,7 +662,11 @@ const SelectMenu = React.forwardRef<HTMLDivElement, SelectMenuProps>(function Se
|
|
|
620
662
|
className={cn(selectMenu(), className)}
|
|
621
663
|
{...props}
|
|
622
664
|
>
|
|
623
|
-
<div
|
|
665
|
+
<div
|
|
666
|
+
data-slot="select-menu-list"
|
|
667
|
+
role="presentation"
|
|
668
|
+
className={selectMenuList()}
|
|
669
|
+
>
|
|
624
670
|
{children}
|
|
625
671
|
</div>
|
|
626
672
|
</div>
|
|
@@ -664,6 +710,8 @@ type SelectMenuItemProps = SelectMenuItemBaseProps &
|
|
|
664
710
|
|
|
665
711
|
const SelectMenuItem = React.forwardRef<HTMLButtonElement, SelectMenuItemProps>(function SelectMenuItem({
|
|
666
712
|
addonText,
|
|
713
|
+
"aria-checked": ariaChecked,
|
|
714
|
+
"aria-selected": ariaSelected,
|
|
667
715
|
children,
|
|
668
716
|
className,
|
|
669
717
|
disabled,
|
|
@@ -681,8 +729,12 @@ const SelectMenuItem = React.forwardRef<HTMLButtonElement, SelectMenuItemProps>(
|
|
|
681
729
|
const generatedValue = React.useId()
|
|
682
730
|
const isDisabled = disabled
|
|
683
731
|
const selectedWithEndCheck = selected && selectionType === "default"
|
|
684
|
-
const resolvedRole =
|
|
685
|
-
|
|
732
|
+
const resolvedRole = role || "option"
|
|
733
|
+
const usesCheckedState =
|
|
734
|
+
resolvedRole === "checkbox" ||
|
|
735
|
+
resolvedRole === "menuitemcheckbox" ||
|
|
736
|
+
resolvedRole === "radio" ||
|
|
737
|
+
resolvedRole === "menuitemradio"
|
|
686
738
|
const selectedMedia =
|
|
687
739
|
media === false ? null : media ?? getDefaultSelectItemMedia(itemType)
|
|
688
740
|
const content = label ?? children
|
|
@@ -698,13 +750,9 @@ const SelectMenuItem = React.forwardRef<HTMLButtonElement, SelectMenuItemProps>(
|
|
|
698
750
|
|
|
699
751
|
const item = (
|
|
700
752
|
<button
|
|
701
|
-
aria-checked={
|
|
702
|
-
selectionType === "checkbox" ? Boolean(selected) : undefined
|
|
703
|
-
}
|
|
753
|
+
aria-checked={usesCheckedState ? (ariaChecked ?? Boolean(selected)) : undefined}
|
|
704
754
|
aria-disabled={isDisabled || undefined}
|
|
705
|
-
aria-selected={
|
|
706
|
-
selectionType === "default" ? Boolean(selected) : undefined
|
|
707
|
-
}
|
|
755
|
+
aria-selected={resolvedRole === "option" ? (ariaSelected ?? Boolean(selected)) : undefined}
|
|
708
756
|
data-disabled={isDisabled ? "true" : undefined}
|
|
709
757
|
data-item-type={itemType}
|
|
710
758
|
data-selected={selected ? "true" : "false"}
|
|
@@ -799,6 +847,16 @@ function getFocusableSelectItems(root: HTMLElement) {
|
|
|
799
847
|
).filter((item) => !item.hasAttribute("disabled"))
|
|
800
848
|
}
|
|
801
849
|
|
|
850
|
+
function resolveSelectSize(
|
|
851
|
+
density: ControlDensity | undefined,
|
|
852
|
+
size: SelectSize | null | undefined
|
|
853
|
+
): SelectSize {
|
|
854
|
+
if (density === "compact") return "md"
|
|
855
|
+
if (density === "default") return "lg"
|
|
856
|
+
if (density === "comfortable") return "comfortable"
|
|
857
|
+
return size ?? "lg"
|
|
858
|
+
}
|
|
859
|
+
|
|
802
860
|
type SelectCheckboxIndicatorProps = {
|
|
803
861
|
checked?: boolean
|
|
804
862
|
className?: string
|
|
@@ -860,6 +918,7 @@ export {
|
|
|
860
918
|
selectTrigger,
|
|
861
919
|
}
|
|
862
920
|
export type {
|
|
921
|
+
ControlDensity,
|
|
863
922
|
SelectItemType,
|
|
864
923
|
SelectMenuItemProps,
|
|
865
924
|
SelectProps,
|
|
@@ -34,7 +34,9 @@ type SidebarMenuButtonProps = React.ComponentProps<"button"> & {
|
|
|
34
34
|
type SidebarToggleProps = React.ComponentProps<"button">
|
|
35
35
|
type SidebarTriggerProps = SidebarToggleProps
|
|
36
36
|
type SidebarRailProps = React.ComponentProps<"button">
|
|
37
|
-
type SidebarInsetProps = React.ComponentProps<"
|
|
37
|
+
type SidebarInsetProps = React.ComponentProps<"div"> & {
|
|
38
|
+
asChild?: boolean
|
|
39
|
+
}
|
|
38
40
|
|
|
39
41
|
const SidebarContext = React.createContext<SidebarContextValue | null>(null)
|
|
40
42
|
|
|
@@ -91,7 +93,9 @@ const Sidebar = React.forwardRef<HTMLElement, SidebarProps>(function Sidebar(
|
|
|
91
93
|
{ className, side = "start", ...props },
|
|
92
94
|
ref
|
|
93
95
|
) {
|
|
94
|
-
const
|
|
96
|
+
const context = React.useContext(SidebarContext)
|
|
97
|
+
const collapsed = context?.collapsed ?? false
|
|
98
|
+
const dir = context?.dir
|
|
95
99
|
|
|
96
100
|
return (
|
|
97
101
|
<aside
|
|
@@ -265,7 +269,7 @@ const SidebarToggle = React.forwardRef<HTMLButtonElement, SidebarToggleProps>(
|
|
|
265
269
|
<PanelLeftIcon
|
|
266
270
|
aria-hidden="true"
|
|
267
271
|
className="size-[var(--bh-space-5xl-24)] rtl:-scale-x-100"
|
|
268
|
-
strokeWidth=
|
|
272
|
+
strokeWidth="var(--bh-icon-stroke-200)"
|
|
269
273
|
/>
|
|
270
274
|
)}
|
|
271
275
|
</button>
|
|
@@ -299,10 +303,12 @@ const SidebarRail = React.forwardRef<HTMLButtonElement, SidebarRailProps>(
|
|
|
299
303
|
}
|
|
300
304
|
)
|
|
301
305
|
|
|
302
|
-
const SidebarInset = React.forwardRef<
|
|
303
|
-
function SidebarInset({ className, ...props }, ref) {
|
|
306
|
+
const SidebarInset = React.forwardRef<HTMLDivElement, SidebarInsetProps>(
|
|
307
|
+
function SidebarInset({ asChild = false, className, ...props }, ref) {
|
|
308
|
+
const Comp = asChild ? Slot : "div"
|
|
309
|
+
|
|
304
310
|
return (
|
|
305
|
-
<
|
|
311
|
+
<Comp
|
|
306
312
|
data-slot="sidebar-inset"
|
|
307
313
|
ref={ref}
|
|
308
314
|
className={cn("min-w-0 flex-1", className)}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
[data-slot="skeleton"] {
|
|
2
2
|
--bh-skeleton-bg: var(--bh-bg-muted);
|
|
3
3
|
--bh-skeleton-highlight: var(--bh-bg-raised-subtle);
|
|
4
|
-
--bh-skeleton-duration: 1.4s;
|
|
5
4
|
--bh-skeleton-radius: var(--bh-radius-md-6);
|
|
6
|
-
--bh-skeleton-shimmer-width: 62%;
|
|
7
|
-
--bh-skeleton-width: 100%;
|
|
8
5
|
--bh-skeleton-height: var(--bh-space-4xl-20);
|
|
9
6
|
}
|
|
10
7
|
|
|
@@ -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,8 +106,17 @@ 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
|
-
"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)]
|
|
119
|
+
"group/social-button relative inline-flex max-w-full min-w-0 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)] 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
|
{
|
|
117
121
|
variants: {
|
|
118
122
|
variant: {
|
|
@@ -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,18 +160,36 @@ 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 =
|
|
162
|
-
const visibleLabel = label
|
|
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)
|
|
166
185
|
: defaultLabel
|
|
167
186
|
const Comp = asChild ? Slot : "button"
|
|
168
|
-
const cssVars = getSocialButtonVars(
|
|
187
|
+
const cssVars = getSocialButtonVars(
|
|
188
|
+
config,
|
|
189
|
+
selectedVariant,
|
|
190
|
+
isIcon,
|
|
191
|
+
resolvedDirection
|
|
192
|
+
)
|
|
169
193
|
const content = (
|
|
170
194
|
<>
|
|
171
195
|
<SocialButtonIcon platform={platform} />
|
|
@@ -173,7 +197,8 @@ const SocialButton = React.forwardRef<HTMLButtonElement, SocialButtonProps>(func
|
|
|
173
197
|
<span
|
|
174
198
|
data-slot="social-button-label"
|
|
175
199
|
dir="auto"
|
|
176
|
-
|
|
200
|
+
title={typeof visibleLabel === "string" ? visibleLabel : undefined}
|
|
201
|
+
className="min-w-0 overflow-hidden text-ellipsis pe-[var(--bh-social-button-label-padding-inline-end)]"
|
|
177
202
|
>
|
|
178
203
|
{visibleLabel}
|
|
179
204
|
</span>
|
|
@@ -192,8 +217,8 @@ const SocialButton = React.forwardRef<HTMLButtonElement, SocialButtonProps>(func
|
|
|
192
217
|
data-size={selectedSize}
|
|
193
218
|
data-slot="social-button"
|
|
194
219
|
data-variant={selectedVariant}
|
|
195
|
-
dir={
|
|
196
|
-
ref={
|
|
220
|
+
dir={resolvedDirection}
|
|
221
|
+
ref={setRootRef}
|
|
197
222
|
className={cn(
|
|
198
223
|
socialButtonVariants({
|
|
199
224
|
variant: selectedVariant,
|
|
@@ -216,17 +241,11 @@ function isSimpleLabel(
|
|
|
216
241
|
return typeof value === "string" || typeof value === "number"
|
|
217
242
|
}
|
|
218
243
|
|
|
219
|
-
function getDefaultLabel(
|
|
220
|
-
config: SocialPlatformConfig,
|
|
221
|
-
dir: React.HTMLAttributes<HTMLElement>["dir"]
|
|
222
|
-
) {
|
|
223
|
-
return dir === "rtl" ? config.labelAr : config.label
|
|
224
|
-
}
|
|
225
|
-
|
|
226
244
|
function getSocialButtonVars(
|
|
227
245
|
config: SocialPlatformConfig,
|
|
228
246
|
variant: SocialButtonVariant,
|
|
229
|
-
isIcon: boolean
|
|
247
|
+
isIcon: boolean,
|
|
248
|
+
direction: "ltr" | "rtl"
|
|
230
249
|
) {
|
|
231
250
|
const isSolid = variant === "solid"
|
|
232
251
|
const border = isSolid
|
|
@@ -250,7 +269,7 @@ function getSocialButtonVars(
|
|
|
250
269
|
"--bh-social-button-icon": isSolid ? config.solidIcon : config.outlineIcon,
|
|
251
270
|
"--bh-social-button-width": isIcon
|
|
252
271
|
? "var(--bh-social-button-height)"
|
|
253
|
-
: config.width
|
|
272
|
+
: config.width[direction],
|
|
254
273
|
"--bh-social-button-width-rtl": isIcon
|
|
255
274
|
? "var(--bh-social-button-height)"
|
|
256
275
|
: config.width.rtl,
|
|
@@ -270,7 +289,11 @@ function SocialButtonIcon({
|
|
|
270
289
|
className="size-[var(--bh-social-button-icon-size)]"
|
|
271
290
|
data-slot="social-button-icon"
|
|
272
291
|
focusable="false"
|
|
273
|
-
strokeWidth={
|
|
292
|
+
strokeWidth={
|
|
293
|
+
platform === "apple"
|
|
294
|
+
? "var(--bh-icon-stroke-200)"
|
|
295
|
+
: "var(--bh-icon-stroke-225)"
|
|
296
|
+
}
|
|
274
297
|
style={{ color: "var(--bh-social-button-icon)" }}
|
|
275
298
|
/>
|
|
276
299
|
)
|
|
@@ -280,7 +303,7 @@ function FacebookBrandIcon({
|
|
|
280
303
|
strokeWidth: _strokeWidth,
|
|
281
304
|
...props
|
|
282
305
|
}: React.SVGProps<SVGSVGElement> & {
|
|
283
|
-
strokeWidth?: number
|
|
306
|
+
strokeWidth?: number | string
|
|
284
307
|
}) {
|
|
285
308
|
return (
|
|
286
309
|
<svg viewBox="0 0 24 24" fill="none" {...props}>
|
|
@@ -296,7 +319,7 @@ function GoogleBrandIcon({
|
|
|
296
319
|
strokeWidth: _strokeWidth,
|
|
297
320
|
...props
|
|
298
321
|
}: React.SVGProps<SVGSVGElement> & {
|
|
299
|
-
strokeWidth?: number
|
|
322
|
+
strokeWidth?: number | string
|
|
300
323
|
}) {
|
|
301
324
|
return (
|
|
302
325
|
<svg viewBox="0 0 24 24" fill="none" {...props}>
|
|
@@ -312,7 +335,7 @@ function LinkedinBrandIcon({
|
|
|
312
335
|
strokeWidth: _strokeWidth,
|
|
313
336
|
...props
|
|
314
337
|
}: React.SVGProps<SVGSVGElement> & {
|
|
315
|
-
strokeWidth?: number
|
|
338
|
+
strokeWidth?: number | string
|
|
316
339
|
}) {
|
|
317
340
|
return (
|
|
318
341
|
<svg viewBox="0 0 24 24" fill="none" {...props}>
|
|
@@ -328,7 +351,7 @@ function TwitterBrandIcon({
|
|
|
328
351
|
strokeWidth: _strokeWidth,
|
|
329
352
|
...props
|
|
330
353
|
}: React.SVGProps<SVGSVGElement> & {
|
|
331
|
-
strokeWidth?: number
|
|
354
|
+
strokeWidth?: number | string
|
|
332
355
|
}) {
|
|
333
356
|
return (
|
|
334
357
|
<svg viewBox="0 0 24 24" fill="none" {...props}>
|
|
@@ -349,8 +372,14 @@ const socialButtonIcons: Record<SocialPlatform, SocialButtonIconComponent> = {
|
|
|
349
372
|
whatsapp: MessageCircleIcon,
|
|
350
373
|
}
|
|
351
374
|
|
|
352
|
-
export {
|
|
375
|
+
export {
|
|
376
|
+
arabicSocialButtonMessages,
|
|
377
|
+
SocialButton,
|
|
378
|
+
socialButtonVariants,
|
|
379
|
+
socialPlatformConfig,
|
|
380
|
+
}
|
|
353
381
|
export type {
|
|
382
|
+
SocialButtonMessages,
|
|
354
383
|
SocialButtonProps,
|
|
355
384
|
SocialButtonSize,
|
|
356
385
|
SocialButtonVariant,
|