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.
- package/CHANGELOG.md +45 -0
- package/CONTRIBUTING.md +44 -0
- package/README.md +145 -328
- package/SECURITY.md +15 -0
- package/banhaten.config.example.json +1 -3
- package/docs/design-system/README.md +20 -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 +189 -0
- package/docs/design-system/appearances/default.md +94 -0
- package/docs/design-system/appearances/rounded.md +95 -0
- package/docs/design-system/appearances/sharp.md +95 -0
- package/docs/design-system/component-docs-pattern.md +81 -0
- package/docs/design-system/component-showcase-consistency-report.md +217 -0
- package/docs/design-system/component-token-consistency-audit.md +173 -0
- package/docs/design-system/components/README.md +75 -0
- package/docs/design-system/components/accordion.md +67 -0
- package/docs/design-system/components/activity-feed.md +106 -0
- package/docs/design-system/components/alert-dialog.md +87 -0
- package/docs/design-system/components/alert.md +111 -0
- package/docs/design-system/components/aspect-ratio.md +59 -0
- package/docs/design-system/components/attribute.md +103 -0
- package/docs/design-system/components/autocomplete.md +93 -0
- package/docs/design-system/components/avatar.md +70 -0
- package/docs/design-system/components/badge.md +72 -0
- package/docs/design-system/components/banner.md +99 -0
- package/docs/design-system/components/breadcrumbs.md +188 -0
- package/docs/design-system/components/button-group.md +117 -0
- package/docs/design-system/components/button.md +95 -0
- package/docs/design-system/components/card.md +95 -0
- package/docs/design-system/components/carousel.md +61 -0
- package/docs/design-system/components/catalog-components.md +59 -0
- package/docs/design-system/components/chart.md +58 -0
- package/docs/design-system/components/checkbox.md +68 -0
- package/docs/design-system/components/collapsible.md +63 -0
- package/docs/design-system/components/command.md +75 -0
- package/docs/design-system/components/context-menu.md +59 -0
- package/docs/design-system/components/date-picker.md +97 -0
- package/docs/design-system/components/divider.md +117 -0
- package/docs/design-system/components/empty-state.md +72 -0
- package/docs/design-system/components/field.md +86 -0
- package/docs/design-system/components/file-upload.md +199 -0
- package/docs/design-system/components/hover-card.md +61 -0
- package/docs/design-system/components/icons.md +48 -0
- package/docs/design-system/components/input-group.md +73 -0
- package/docs/design-system/components/input-otp.md +73 -0
- package/docs/design-system/components/input.md +84 -0
- package/docs/design-system/components/item.md +72 -0
- package/docs/design-system/components/kbd.md +62 -0
- package/docs/design-system/components/label.md +64 -0
- package/docs/design-system/components/menu.md +76 -0
- package/docs/design-system/components/menubar.md +60 -0
- package/docs/design-system/components/modal.md +119 -0
- package/docs/design-system/components/native-select.md +70 -0
- package/docs/design-system/components/navigation-menu.md +63 -0
- package/docs/design-system/components/onboarding-step-list-item.md +94 -0
- package/docs/design-system/components/page-header.md +98 -0
- package/docs/design-system/components/pagination.md +71 -0
- package/docs/design-system/components/popover.md +77 -0
- package/docs/design-system/components/progress-slider.md +66 -0
- package/docs/design-system/components/progress.md +92 -0
- package/docs/design-system/components/radio-card.md +65 -0
- package/docs/design-system/components/radio-group.md +72 -0
- package/docs/design-system/components/resizable.md +57 -0
- package/docs/design-system/components/scroll-area.md +60 -0
- package/docs/design-system/components/segmented-control.md +71 -0
- package/docs/design-system/components/select.md +87 -0
- package/docs/design-system/components/sheet.md +82 -0
- package/docs/design-system/components/sidebar.md +83 -0
- package/docs/design-system/components/skeleton.md +91 -0
- package/docs/design-system/components/slideout.md +77 -0
- package/docs/design-system/components/slider.md +81 -0
- package/docs/design-system/components/social-button.md +65 -0
- package/docs/design-system/components/spinner.md +77 -0
- package/docs/design-system/components/steps.md +77 -0
- package/docs/design-system/components/table.md +411 -0
- package/docs/design-system/components/tabs.md +69 -0
- package/docs/design-system/components/tag.md +95 -0
- package/docs/design-system/components/textarea.md +64 -0
- package/docs/design-system/components/timeline.md +95 -0
- package/docs/design-system/components/toast.md +73 -0
- package/docs/design-system/components/toggle.md +96 -0
- package/docs/design-system/components/toolbar.md +105 -0
- package/docs/design-system/components/tooltip.md +107 -0
- package/docs/design-system/components/typography.md +18 -0
- package/docs/design-system/density-and-elevation.md +44 -0
- package/docs/design-system/design-system-test-missing-items.md +368 -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 +166 -0
- package/docs/design-system/icons.md +69 -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 +64 -0
- 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 +53 -0
- package/docs/design-system/token-governance.md +60 -0
- package/package.json +97 -65
- package/registry/component-contract.json +40 -0
- package/registry/components/alert-dialog.tsx +297 -0
- package/registry/components/alert.tsx +86 -65
- package/registry/components/aspect-ratio.tsx +30 -0
- package/registry/components/autocomplete.tsx +23 -9
- package/registry/components/avatar.tsx +7 -7
- package/registry/components/badge.tsx +1 -1
- package/registry/components/button-group.tsx +321 -4
- package/registry/components/button.tsx +38 -17
- package/registry/components/card.tsx +68 -59
- package/registry/components/carousel.tsx +282 -0
- package/registry/components/chart.tsx +203 -0
- package/registry/components/checkbox.tsx +3 -3
- package/registry/components/collapsible.tsx +69 -0
- package/registry/components/command.tsx +174 -0
- package/registry/components/context-menu.tsx +236 -0
- package/registry/components/date-picker.tsx +246 -105
- package/registry/components/expanded/ActivityFeed.tsx +6 -15
- package/registry/components/expanded/Banner.tsx +3 -3
- package/registry/components/expanded/Breadcrumbs.tsx +5 -5
- package/registry/components/expanded/CatalogComponentsShowcase.tsx +13 -13
- package/registry/components/expanded/CatalogDivider.tsx +1 -1
- package/registry/components/expanded/EmptyState.tsx +1 -1
- package/registry/components/expanded/FileUpload.tsx +9 -2
- package/registry/components/expanded/OnboardingStepListItem.tsx +2 -4
- package/registry/components/expanded/PageHeader.tsx +14 -14
- package/registry/components/expanded/Slideout.tsx +15 -415
- package/registry/components/expanded/Steps.tsx +4 -4
- package/registry/components/expanded/Table.tsx +116 -69
- package/registry/components/expanded/Timeline.tsx +3 -3
- package/registry/components/expanded/activityFeed.css +1 -1
- package/registry/components/expanded/breadcrumbs.css +139 -139
- package/registry/components/expanded/catalogComponentsShowcase.css +83 -83
- package/registry/components/expanded/divider.css +1 -1
- package/registry/components/expanded/emptyState.css +1 -1
- package/registry/components/expanded/fileUpload.css +6 -6
- package/registry/components/expanded/slideout.css +9 -685
- package/registry/components/expanded/steps.css +274 -274
- package/registry/components/expanded/table.css +2 -2
- package/registry/components/expanded/timeline.css +264 -264
- package/registry/components/field.tsx +230 -0
- package/registry/components/hover-card.tsx +48 -0
- package/registry/components/input-content.ts +1 -0
- package/registry/components/input-group.tsx +130 -0
- package/registry/components/input-otp.tsx +13 -3
- package/registry/components/input.tsx +70 -45
- package/registry/components/item.tsx +189 -0
- package/registry/components/kbd.tsx +151 -0
- package/registry/components/label.tsx +78 -0
- package/registry/components/menu.tsx +34 -246
- package/registry/components/menubar.tsx +226 -0
- package/registry/components/modal.tsx +216 -143
- package/registry/components/native-select.tsx +205 -0
- package/registry/components/navigation-menu.tsx +171 -0
- package/registry/components/pagination.tsx +80 -58
- package/registry/components/popover.tsx +162 -664
- package/registry/components/radio-card.tsx +116 -87
- package/registry/components/radio-group.tsx +1 -1
- package/registry/components/resizable.tsx +74 -0
- package/registry/components/scroll-area.tsx +67 -0
- package/registry/components/segmented-control.tsx +87 -0
- package/registry/components/select-content.tsx +2 -2
- package/registry/components/select.tsx +54 -20
- package/registry/components/sheet.tsx +305 -0
- package/registry/components/sidebar.tsx +352 -0
- package/registry/components/skeleton.css +0 -3
- package/registry/components/social-button.tsx +116 -30
- package/registry/components/spinner.tsx +18 -55
- package/registry/components/{expanded/tabs.css → tabs.css} +127 -106
- package/registry/components/tabs.tsx +246 -0
- package/registry/components/tag.tsx +2 -2
- package/registry/components/textarea.tsx +4 -4
- package/registry/components/toast.tsx +136 -0
- package/registry/components/toggle.tsx +2 -2
- package/registry/components/toolbar.tsx +89 -17
- package/registry/components/tooltip.tsx +1 -1
- package/registry/examples/alert-demo.tsx +25 -5
- package/registry/examples/alert-dialog-demo.tsx +42 -0
- package/registry/examples/aspect-ratio-demo.tsx +11 -0
- package/registry/examples/attribute-demo.tsx +1 -1
- package/registry/examples/autocomplete-demo.tsx +3 -3
- package/registry/examples/avatar-demo.tsx +7 -7
- 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 +43 -0
- package/registry/examples/chart-demo.tsx +33 -0
- package/registry/examples/checkbox-demo.tsx +5 -5
- package/registry/examples/collapsible-demo.tsx +16 -0
- package/registry/examples/collection-filter-bar-demo.tsx +135 -0
- package/registry/examples/command-demo.tsx +42 -0
- package/registry/examples/{expanded/command-bar-demo.tsx → command-palette-demo.tsx} +5 -15
- package/registry/examples/context-menu-demo.tsx +29 -0
- 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/banner-demo.tsx +1 -1
- package/registry/examples/expanded/breadcrumbs-demo.tsx +1 -1
- 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 +2 -2
- package/registry/examples/expanded/timeline-demo.tsx +1 -1
- package/registry/examples/field-demo.tsx +51 -0
- package/registry/examples/hover-card-demo.tsx +23 -0
- package/registry/examples/input-demo.tsx +6 -6
- package/registry/examples/input-group-demo.tsx +16 -0
- package/registry/examples/input-otp-demo.tsx +4 -4
- package/registry/examples/item-demo.tsx +46 -0
- package/registry/examples/kbd-demo.tsx +11 -0
- package/registry/examples/label-demo.tsx +20 -0
- package/registry/examples/menu-demo.tsx +1 -1
- package/registry/examples/menubar-demo.tsx +34 -0
- package/registry/examples/modal-demo.tsx +67 -9
- package/registry/examples/native-select-demo.tsx +16 -0
- package/registry/examples/navigation-menu-demo.tsx +29 -0
- package/registry/examples/pagination-demo.tsx +6 -3
- 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 +22 -0
- package/registry/examples/results-toolbar-demo.tsx +44 -0
- package/registry/examples/scroll-area-demo.tsx +15 -0
- package/registry/examples/segmented-control-demo.tsx +39 -0
- package/registry/examples/select-demo.tsx +1 -1
- package/registry/examples/sheet-demo.tsx +47 -0
- package/registry/examples/sidebar-demo.tsx +55 -0
- 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 +13 -0
- package/registry/examples/tag-demo.tsx +1 -1
- package/registry/examples/textarea-demo.tsx +4 -4
- package/registry/examples/toast-demo.tsx +35 -0
- 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 +6010 -432
- package/registry/styles/globals.css +3112 -4690
- package/registry.json +1582 -0
- package/schema/config.schema.json +51 -0
- package/schema/registry.schema.json +190 -0
- package/schema/tokens.schema.json +163 -0
- 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 +639 -1391
- 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 +4313 -310
- package/registry/assets/avatars/avatar-02.jpg +0 -0
- package/registry/assets/avatars/avatar-03.jpg +0 -0
- package/registry/assets/avatars/avatar-04.jpg +0 -0
- package/registry/assets/avatars/avatar-05.jpg +0 -0
- package/registry/assets/avatars/avatar-06.jpg +0 -0
- package/registry/assets/avatars/avatar-07.jpg +0 -0
- package/registry/assets/avatars/avatar-08.jpg +0 -0
- package/registry/assets/avatars/avatar-09.jpg +0 -0
- package/registry/assets/avatars/avatar-10.jpg +0 -0
- package/registry/assets/avatars/avatar-11.jpg +0 -0
- package/registry/assets/avatars/avatar-12.jpg +0 -0
- package/registry/assets/avatars/avatar-13.jpg +0 -0
- package/registry/assets/avatars/avatar-14.jpg +0 -0
- package/registry/assets/avatars/avatar-15.jpg +0 -0
- package/registry/assets/avatars/avatar-16.jpg +0 -0
- package/registry/assets/avatars/avatar-17.jpg +0 -0
- package/registry/assets/avatars/avatar-18.jpg +0 -0
- package/registry/assets/avatars/avatar-19.jpg +0 -0
- package/registry/assets/avatars/avatar-20.jpg +0 -0
- package/registry/assets/avatars/avatar-21.jpg +0 -0
- package/registry/assets/avatars/avatar-22.jpg +0 -0
- package/registry/assets/avatars/avatar-23.jpg +0 -0
- package/registry/assets/avatars/avatar-24.jpg +0 -0
- package/registry/assets/avatars/avatar-25.jpg +0 -0
- package/registry/assets/avatars/avatar-26.jpg +0 -0
- package/registry/assets/avatars/avatar-27.jpg +0 -0
- package/registry/assets/avatars/avatar-28.jpg +0 -0
- package/registry/assets/avatars/avatar-29.jpg +0 -0
- package/registry/assets/avatars/avatar-30.jpg +0 -0
- package/registry/assets/avatars/avatar-31.jpg +0 -0
- package/registry/assets/avatars/avatar-32.jpg +0 -0
- package/registry/assets/avatars/avatar-33.jpg +0 -0
- package/registry/assets/avatars/avatar-34.jpg +0 -0
- package/registry/assets/avatars/avatar-35.jpg +0 -0
- package/registry/assets/image-assets.json +0 -744
- package/registry/assets/images/art-02.jpg +0 -0
- package/registry/assets/images/art-03.jpg +0 -0
- package/registry/assets/images/art-04.jpg +0 -0
- package/registry/assets/images/art-05.jpg +0 -0
- package/registry/assets/images/art-06.jpg +0 -0
- package/registry/assets/images/art-07.jpg +0 -0
- package/registry/assets/images/art-08.jpg +0 -0
- package/registry/assets/images/art-09.jpg +0 -0
- package/registry/assets/images/art-10.jpg +0 -0
- package/registry/assets/images/art-11.jpg +0 -0
- package/registry/assets/images/art-12.jpg +0 -0
- package/registry/assets/images/art-13.jpg +0 -0
- package/registry/assets/images/art-14.jpg +0 -0
- package/registry/assets/images/art-15.jpg +0 -0
- package/registry/assets/images/art-16.jpg +0 -0
- package/registry/assets/images/art-17.jpg +0 -0
- package/registry/assets/images/art-18.jpg +0 -0
- package/registry/assets/images/art-19.jpg +0 -0
- package/registry/assets/images/art-20.jpg +0 -0
- package/registry/assets/images/art-21.jpg +0 -0
- package/registry/assets/images/art-22.jpg +0 -0
- package/registry/assets/images/art-23.jpg +0 -0
- package/registry/assets/images/art-24.jpg +0 -0
- package/registry/assets/images/art-25.jpg +0 -0
- package/registry/assets/images/art-26.jpg +0 -0
- package/registry/assets/images/art-27.jpg +0 -0
- package/registry/assets/images/nature-01.jpg +0 -0
- package/registry/assets/images/nature-02.jpg +0 -0
- package/registry/assets/images/nature-03.jpg +0 -0
- package/registry/assets/images/nature-04.jpg +0 -0
- package/registry/assets/images/nature-05.jpg +0 -0
- package/registry/assets/images/nature-06.jpg +0 -0
- package/registry/assets/images/nature-07.jpg +0 -0
- package/registry/assets/images/nature-08.jpg +0 -0
- package/registry/assets/images/nature-09.jpg +0 -0
- package/registry/assets/images/nature-10.jpg +0 -0
- package/registry/assets/images/nature-11.jpg +0 -0
- package/registry/assets/images/nature-12.jpg +0 -0
- package/registry/assets/images/nature-13.jpg +0 -0
- package/registry/assets/images/nature-14.jpg +0 -0
- package/registry/assets/images/nature-15.jpg +0 -0
- package/registry/assets/images/nature-16.jpg +0 -0
- package/registry/assets/images/nature-17.jpg +0 -0
- package/registry/assets/images/nature-18.jpg +0 -0
- package/registry/assets/images/nature-19.jpg +0 -0
- package/registry/assets/images/nature-20.jpg +0 -0
- 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/Tabs.tsx +0 -86
- 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
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import * as LabelPrimitive from "@radix-ui/react-label"
|
|
5
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
6
|
+
|
|
7
|
+
import { cn } from "@/lib/utils"
|
|
8
|
+
|
|
9
|
+
const labelVariants = cva(
|
|
10
|
+
[
|
|
11
|
+
"inline-flex max-w-full items-center gap-[var(--bh-space-xs-4)] text-start",
|
|
12
|
+
"text-[length:var(--bh-text-body-sm-medium-font-size)] font-[var(--bh-text-body-sm-medium-font-weight)]",
|
|
13
|
+
"leading-[var(--bh-text-body-sm-medium-line-height)] tracking-[var(--bh-text-body-sm-medium-letter-spacing)]",
|
|
14
|
+
"text-[var(--bh-content-default)]",
|
|
15
|
+
"has-[[aria-disabled=true]]:text-[var(--bh-content-disabled)]",
|
|
16
|
+
"peer-disabled:cursor-not-allowed peer-disabled:text-[var(--bh-content-disabled)]",
|
|
17
|
+
],
|
|
18
|
+
{
|
|
19
|
+
variants: {
|
|
20
|
+
tone: {
|
|
21
|
+
default: "",
|
|
22
|
+
subtle: "text-[var(--bh-content-subtle)]",
|
|
23
|
+
danger: "text-[var(--bh-content-danger-default)]",
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
defaultVariants: {
|
|
27
|
+
tone: "default",
|
|
28
|
+
},
|
|
29
|
+
}
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
type LabelProps = React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
|
|
33
|
+
VariantProps<typeof labelVariants> & {
|
|
34
|
+
optionalText?: React.ReactNode
|
|
35
|
+
required?: boolean
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const Label = React.forwardRef<
|
|
39
|
+
React.ElementRef<typeof LabelPrimitive.Root>,
|
|
40
|
+
LabelProps
|
|
41
|
+
>(function Label(
|
|
42
|
+
{ children, className, optionalText, required = false, tone, ...props },
|
|
43
|
+
ref
|
|
44
|
+
) {
|
|
45
|
+
return (
|
|
46
|
+
<LabelPrimitive.Root
|
|
47
|
+
data-slot="label"
|
|
48
|
+
ref={ref}
|
|
49
|
+
className={cn(labelVariants({ tone, className }))}
|
|
50
|
+
{...props}
|
|
51
|
+
>
|
|
52
|
+
<span data-slot="label-text" dir="auto" className="min-w-0">
|
|
53
|
+
{children}
|
|
54
|
+
</span>
|
|
55
|
+
{required ? (
|
|
56
|
+
<span
|
|
57
|
+
aria-hidden="true"
|
|
58
|
+
data-slot="label-required"
|
|
59
|
+
className="shrink-0 text-[var(--bh-content-danger-default)]"
|
|
60
|
+
>
|
|
61
|
+
*
|
|
62
|
+
</span>
|
|
63
|
+
) : null}
|
|
64
|
+
{optionalText ? (
|
|
65
|
+
<span
|
|
66
|
+
data-slot="label-optional"
|
|
67
|
+
dir="auto"
|
|
68
|
+
className="min-w-0 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)] text-[var(--bh-content-subtle)]"
|
|
69
|
+
>
|
|
70
|
+
{optionalText}
|
|
71
|
+
</span>
|
|
72
|
+
) : null}
|
|
73
|
+
</LabelPrimitive.Root>
|
|
74
|
+
)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
export { Label, labelVariants }
|
|
78
|
+
export type { LabelProps }
|
|
@@ -4,37 +4,21 @@ import { Slot } from "@radix-ui/react-slot"
|
|
|
4
4
|
import { cva, type VariantProps } from "class-variance-authority"
|
|
5
5
|
|
|
6
6
|
import { cn } from "@/lib/utils"
|
|
7
|
+
import { useResolvedDirection } from "@/hooks/use-direction"
|
|
7
8
|
|
|
8
9
|
type MenuWidth = "menu" | "default" | "multiline" | "action" | "auto"
|
|
9
10
|
type MenuItemKind = "default" | "multiline" | "action" | "progress" | "button"
|
|
10
11
|
type MenuItemState = "default" | "disabled"
|
|
11
12
|
type MenuItemIconPosition = "leading" | "trailing"
|
|
12
13
|
type MenuItemAvatarSize = "sm" | "lg"
|
|
13
|
-
type MenuCollisionShift = {
|
|
14
|
-
x: number
|
|
15
|
-
y: number
|
|
16
|
-
}
|
|
17
14
|
type MenuCollisionPadding = NonNullable<
|
|
18
15
|
React.ComponentProps<typeof DropdownMenuPrimitive.Content>["collisionPadding"]
|
|
19
16
|
>
|
|
20
|
-
type MenuCollisionPaddingSides = {
|
|
21
|
-
bottom: number
|
|
22
|
-
left: number
|
|
23
|
-
right: number
|
|
24
|
-
top: number
|
|
25
|
-
}
|
|
26
|
-
type MenuResizeObserverConstructor = new (
|
|
27
|
-
callback: () => void
|
|
28
|
-
) => {
|
|
29
|
-
disconnect: () => void
|
|
30
|
-
observe: (target: Element) => void
|
|
31
|
-
}
|
|
32
17
|
|
|
33
18
|
// Default Radix collisionPadding mirrors --bh-space-md-8.
|
|
34
19
|
const MENU_COLLISION_PADDING_PX = 8
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
typeof window === "undefined" ? React.useEffect : React.useLayoutEffect
|
|
20
|
+
// Radix sideOffset is numeric; this mirrors --bh-space-xs-4.
|
|
21
|
+
const MENU_SUBCONTENT_SIDE_OFFSET_PX = 4
|
|
38
22
|
|
|
39
23
|
const menuVariants = cva(
|
|
40
24
|
"flex flex-col items-start gap-[var(--bh-menu-gap)] overflow-hidden rounded-[var(--bh-menu-radius)] bg-[var(--bh-menu-bg)] py-[var(--bh-menu-padding-y)] shadow-[var(--shadow-menu)]",
|
|
@@ -117,14 +101,7 @@ const menuItemIconVariants = cva(
|
|
|
117
101
|
}
|
|
118
102
|
)
|
|
119
103
|
|
|
120
|
-
type MenuProps = React.ComponentProps<
|
|
121
|
-
VariantProps<typeof menuVariants> & {
|
|
122
|
-
asChild?: boolean
|
|
123
|
-
defaultOpen?: boolean
|
|
124
|
-
modal?: boolean
|
|
125
|
-
onOpenChange?: (open: boolean) => void
|
|
126
|
-
open?: boolean
|
|
127
|
-
}
|
|
104
|
+
type MenuProps = React.ComponentProps<typeof DropdownMenuPrimitive.Root>
|
|
128
105
|
|
|
129
106
|
type MenuContentProps = React.ComponentProps<typeof DropdownMenuPrimitive.Content> &
|
|
130
107
|
VariantProps<typeof menuVariants> & {
|
|
@@ -141,147 +118,38 @@ const MenuSub = DropdownMenuPrimitive.Sub
|
|
|
141
118
|
const MenuTrigger = DropdownMenuPrimitive.Trigger
|
|
142
119
|
const MenuStaticContext = React.createContext(false)
|
|
143
120
|
|
|
121
|
+
function Menu({ dir, ...props }: MenuProps) {
|
|
122
|
+
const directionBoundaryRef = React.useRef<HTMLSpanElement | null>(null)
|
|
123
|
+
const resolvedDirection = useResolvedDirection(dir, directionBoundaryRef)
|
|
124
|
+
|
|
125
|
+
return (
|
|
126
|
+
<span className="contents" data-slot="menu-root-boundary" ref={directionBoundaryRef}>
|
|
127
|
+
<MenuRoot dir={resolvedDirection} {...props} />
|
|
128
|
+
</span>
|
|
129
|
+
)
|
|
130
|
+
}
|
|
131
|
+
|
|
144
132
|
type MenuSurfaceProps = React.ComponentProps<"div"> &
|
|
145
133
|
VariantProps<typeof menuVariants> & {
|
|
146
134
|
asChild?: boolean
|
|
147
|
-
avoidViewportNudge?: boolean
|
|
148
|
-
collisionPadding?: MenuCollisionPadding
|
|
149
135
|
}
|
|
150
136
|
|
|
151
137
|
const MenuSurface = React.forwardRef<HTMLDivElement, MenuSurfaceProps>(function MenuSurface({
|
|
152
138
|
asChild = false,
|
|
153
|
-
avoidViewportNudge = true,
|
|
154
139
|
children,
|
|
155
140
|
className,
|
|
156
|
-
collisionPadding = MENU_COLLISION_PADDING_PX,
|
|
157
141
|
role = "menu",
|
|
158
|
-
style,
|
|
159
142
|
width,
|
|
160
143
|
...props
|
|
161
144
|
}, ref) {
|
|
162
145
|
const Comp = asChild ? Slot : "div"
|
|
163
|
-
const surfaceRef = React.useRef<HTMLDivElement | null>(null)
|
|
164
|
-
const collisionShiftRef = React.useRef(zeroMenuCollisionShift)
|
|
165
|
-
const [collisionShift, setCollisionShift] = React.useState(
|
|
166
|
-
zeroMenuCollisionShift
|
|
167
|
-
)
|
|
168
|
-
|
|
169
|
-
function updateCollisionShift(nextShift: MenuCollisionShift) {
|
|
170
|
-
collisionShiftRef.current = nextShift
|
|
171
|
-
setCollisionShift((currentShift) =>
|
|
172
|
-
isSameMenuCollisionShift(currentShift, nextShift)
|
|
173
|
-
? currentShift
|
|
174
|
-
: nextShift
|
|
175
|
-
)
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
function setSurfaceRef(node: HTMLDivElement | null) {
|
|
179
|
-
surfaceRef.current = node
|
|
180
|
-
|
|
181
|
-
if (typeof ref === "function") {
|
|
182
|
-
ref(node)
|
|
183
|
-
} else if (ref) {
|
|
184
|
-
ref.current = node
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
useSafeLayoutEffect(() => {
|
|
189
|
-
if (!avoidViewportNudge) {
|
|
190
|
-
updateCollisionShift(zeroMenuCollisionShift)
|
|
191
|
-
return
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
const node = surfaceRef.current
|
|
195
|
-
if (!node) return
|
|
196
|
-
const surfaceNode: HTMLDivElement = node
|
|
197
|
-
|
|
198
|
-
const ownerWindow = surfaceNode.ownerDocument.defaultView
|
|
199
|
-
if (!ownerWindow) return
|
|
200
|
-
const surfaceWindow: Window = ownerWindow
|
|
201
|
-
|
|
202
|
-
let animationFrame = 0
|
|
203
|
-
const resolvedCollisionPadding = resolveMenuCollisionPadding(collisionPadding)
|
|
204
|
-
const requestFrame =
|
|
205
|
-
typeof surfaceWindow.requestAnimationFrame === "function"
|
|
206
|
-
? surfaceWindow.requestAnimationFrame.bind(surfaceWindow)
|
|
207
|
-
: (callback: FrameRequestCallback) =>
|
|
208
|
-
surfaceWindow.setTimeout(
|
|
209
|
-
() => callback(surfaceWindow.performance.now()),
|
|
210
|
-
0
|
|
211
|
-
)
|
|
212
|
-
const cancelFrame =
|
|
213
|
-
typeof surfaceWindow.cancelAnimationFrame === "function"
|
|
214
|
-
? surfaceWindow.cancelAnimationFrame.bind(surfaceWindow)
|
|
215
|
-
: surfaceWindow.clearTimeout.bind(surfaceWindow)
|
|
216
|
-
|
|
217
|
-
function measureCollisionShift() {
|
|
218
|
-
animationFrame = 0
|
|
219
|
-
|
|
220
|
-
const rect = surfaceNode.getBoundingClientRect()
|
|
221
|
-
const currentShift = collisionShiftRef.current
|
|
222
|
-
const unshiftedRect = {
|
|
223
|
-
bottom: rect.bottom - currentShift.y,
|
|
224
|
-
left: rect.left - currentShift.x,
|
|
225
|
-
right: rect.right - currentShift.x,
|
|
226
|
-
top: rect.top - currentShift.y,
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
updateCollisionShift(
|
|
230
|
-
getMenuCollisionShift({
|
|
231
|
-
collisionPadding: resolvedCollisionPadding,
|
|
232
|
-
rect: unshiftedRect,
|
|
233
|
-
viewportHeight: surfaceWindow.innerHeight,
|
|
234
|
-
viewportWidth: surfaceWindow.innerWidth,
|
|
235
|
-
})
|
|
236
|
-
)
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
function queueCollisionShiftMeasure() {
|
|
240
|
-
if (animationFrame) {
|
|
241
|
-
cancelFrame(animationFrame)
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
animationFrame = requestFrame(measureCollisionShift)
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
queueCollisionShiftMeasure()
|
|
248
|
-
surfaceWindow.addEventListener("resize", queueCollisionShiftMeasure)
|
|
249
|
-
surfaceWindow.addEventListener("scroll", queueCollisionShiftMeasure, true)
|
|
250
|
-
|
|
251
|
-
const ResizeObserver = (
|
|
252
|
-
surfaceWindow as Window & {
|
|
253
|
-
ResizeObserver?: MenuResizeObserverConstructor
|
|
254
|
-
}
|
|
255
|
-
).ResizeObserver
|
|
256
|
-
const resizeObserver = ResizeObserver
|
|
257
|
-
? new ResizeObserver(queueCollisionShiftMeasure)
|
|
258
|
-
: undefined
|
|
259
|
-
resizeObserver?.observe(surfaceNode)
|
|
260
|
-
|
|
261
|
-
return () => {
|
|
262
|
-
if (animationFrame) {
|
|
263
|
-
cancelFrame(animationFrame)
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
surfaceWindow.removeEventListener("resize", queueCollisionShiftMeasure)
|
|
267
|
-
surfaceWindow.removeEventListener("scroll", queueCollisionShiftMeasure, true)
|
|
268
|
-
resizeObserver?.disconnect()
|
|
269
|
-
}
|
|
270
|
-
}, [avoidViewportNudge, collisionPadding, width])
|
|
271
146
|
|
|
272
147
|
return (
|
|
273
148
|
<Comp
|
|
274
149
|
data-slot="menu"
|
|
275
150
|
data-width={width ?? "menu"}
|
|
276
|
-
ref={
|
|
151
|
+
ref={ref}
|
|
277
152
|
role={role}
|
|
278
|
-
style={{
|
|
279
|
-
...style,
|
|
280
|
-
transform: mergeMenuTransforms(
|
|
281
|
-
getMenuCollisionTransform(collisionShift),
|
|
282
|
-
style?.transform
|
|
283
|
-
),
|
|
284
|
-
}}
|
|
285
153
|
className={cn(
|
|
286
154
|
menuVariants({ width }),
|
|
287
155
|
"max-h-[var(--radix-dropdown-menu-content-available-height)] overflow-y-auto",
|
|
@@ -312,7 +180,6 @@ const MenuContent = React.forwardRef<HTMLDivElement, MenuContentProps>(function
|
|
|
312
180
|
<MenuSurface
|
|
313
181
|
asChild={asChild}
|
|
314
182
|
className={className}
|
|
315
|
-
collisionPadding={collisionPadding}
|
|
316
183
|
ref={ref}
|
|
317
184
|
role={role}
|
|
318
185
|
width={width}
|
|
@@ -327,7 +194,7 @@ const MenuSubContent = React.forwardRef<HTMLDivElement, MenuSubContentProps>(fun
|
|
|
327
194
|
children,
|
|
328
195
|
className,
|
|
329
196
|
collisionPadding = MENU_COLLISION_PADDING_PX,
|
|
330
|
-
sideOffset =
|
|
197
|
+
sideOffset = MENU_SUBCONTENT_SIDE_OFFSET_PX,
|
|
331
198
|
width,
|
|
332
199
|
asChild = false,
|
|
333
200
|
role = "menu",
|
|
@@ -343,7 +210,6 @@ const MenuSubContent = React.forwardRef<HTMLDivElement, MenuSubContentProps>(fun
|
|
|
343
210
|
<MenuSurface
|
|
344
211
|
asChild={asChild}
|
|
345
212
|
className={className}
|
|
346
|
-
collisionPadding={collisionPadding}
|
|
347
213
|
ref={ref}
|
|
348
214
|
role={role}
|
|
349
215
|
width={width}
|
|
@@ -354,37 +220,30 @@ const MenuSubContent = React.forwardRef<HTMLDivElement, MenuSubContentProps>(fun
|
|
|
354
220
|
)
|
|
355
221
|
})
|
|
356
222
|
|
|
357
|
-
|
|
223
|
+
type MenuPreviewProps = React.ComponentProps<"div"> &
|
|
224
|
+
VariantProps<typeof menuVariants> & {
|
|
225
|
+
asChild?: boolean
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function MenuPreview({
|
|
358
229
|
children,
|
|
359
230
|
className,
|
|
360
|
-
defaultOpen = true,
|
|
361
|
-
modal = false,
|
|
362
|
-
onOpenChange,
|
|
363
|
-
open,
|
|
364
231
|
role = "menu",
|
|
365
232
|
width,
|
|
366
233
|
asChild = false,
|
|
367
234
|
...props
|
|
368
|
-
}:
|
|
369
|
-
const Comp = asChild ? Slot : "div"
|
|
370
|
-
const isOpen = open ?? defaultOpen
|
|
371
|
-
|
|
372
|
-
void modal
|
|
373
|
-
void onOpenChange
|
|
374
|
-
|
|
375
|
-
if (!isOpen) return null
|
|
376
|
-
|
|
235
|
+
}: MenuPreviewProps) {
|
|
377
236
|
return (
|
|
378
237
|
<MenuStaticContext.Provider value>
|
|
379
|
-
<
|
|
380
|
-
|
|
381
|
-
|
|
238
|
+
<MenuSurface
|
|
239
|
+
asChild={asChild}
|
|
240
|
+
className={className}
|
|
382
241
|
role={role}
|
|
383
|
-
|
|
242
|
+
width={width}
|
|
384
243
|
{...props}
|
|
385
244
|
>
|
|
386
245
|
{children}
|
|
387
|
-
</
|
|
246
|
+
</MenuSurface>
|
|
388
247
|
</MenuStaticContext.Provider>
|
|
389
248
|
)
|
|
390
249
|
}
|
|
@@ -905,7 +764,7 @@ function MenuProgressSpinner({ className }: { className?: string }) {
|
|
|
905
764
|
fill="none"
|
|
906
765
|
stroke="currentColor"
|
|
907
766
|
strokeLinecap="round"
|
|
908
|
-
strokeWidth="
|
|
767
|
+
strokeWidth="var(--bh-icon-stroke-300)"
|
|
909
768
|
/>
|
|
910
769
|
</svg>
|
|
911
770
|
)
|
|
@@ -1023,81 +882,6 @@ function MenuSeparator({
|
|
|
1023
882
|
return <DropdownMenuPrimitive.Separator asChild>{separator}</DropdownMenuPrimitive.Separator>
|
|
1024
883
|
}
|
|
1025
884
|
|
|
1026
|
-
function getMenuCollisionShift({
|
|
1027
|
-
collisionPadding,
|
|
1028
|
-
rect,
|
|
1029
|
-
viewportHeight,
|
|
1030
|
-
viewportWidth,
|
|
1031
|
-
}: {
|
|
1032
|
-
collisionPadding: MenuCollisionPaddingSides
|
|
1033
|
-
rect: Pick<DOMRect, "bottom" | "left" | "right" | "top">
|
|
1034
|
-
viewportHeight: number
|
|
1035
|
-
viewportWidth: number
|
|
1036
|
-
}): MenuCollisionShift {
|
|
1037
|
-
let x = 0
|
|
1038
|
-
let y = 0
|
|
1039
|
-
const minX = collisionPadding.left
|
|
1040
|
-
const minY = collisionPadding.top
|
|
1041
|
-
const maxX = viewportWidth - collisionPadding.right
|
|
1042
|
-
const maxY = viewportHeight - collisionPadding.bottom
|
|
1043
|
-
|
|
1044
|
-
if (rect.left < minX) {
|
|
1045
|
-
x = minX - rect.left
|
|
1046
|
-
} else if (rect.right > maxX) {
|
|
1047
|
-
x = maxX - rect.right
|
|
1048
|
-
}
|
|
1049
|
-
|
|
1050
|
-
if (rect.top < minY) {
|
|
1051
|
-
y = minY - rect.top
|
|
1052
|
-
} else if (rect.bottom > maxY) {
|
|
1053
|
-
y = maxY - rect.bottom
|
|
1054
|
-
}
|
|
1055
|
-
|
|
1056
|
-
return { x: Math.round(x), y: Math.round(y) }
|
|
1057
|
-
}
|
|
1058
|
-
|
|
1059
|
-
function resolveMenuCollisionPadding(
|
|
1060
|
-
collisionPadding: MenuCollisionPadding
|
|
1061
|
-
): MenuCollisionPaddingSides {
|
|
1062
|
-
if (typeof collisionPadding === "number") {
|
|
1063
|
-
const padding = Math.max(0, collisionPadding)
|
|
1064
|
-
|
|
1065
|
-
return {
|
|
1066
|
-
bottom: padding,
|
|
1067
|
-
left: padding,
|
|
1068
|
-
right: padding,
|
|
1069
|
-
top: padding,
|
|
1070
|
-
}
|
|
1071
|
-
}
|
|
1072
|
-
|
|
1073
|
-
return {
|
|
1074
|
-
bottom: Math.max(0, collisionPadding.bottom ?? 0),
|
|
1075
|
-
left: Math.max(0, collisionPadding.left ?? 0),
|
|
1076
|
-
right: Math.max(0, collisionPadding.right ?? 0),
|
|
1077
|
-
top: Math.max(0, collisionPadding.top ?? 0),
|
|
1078
|
-
}
|
|
1079
|
-
}
|
|
1080
|
-
|
|
1081
|
-
function getMenuCollisionTransform(shift: MenuCollisionShift) {
|
|
1082
|
-
return `translate(${Math.round(shift.x)}px, ${Math.round(shift.y)}px)`
|
|
1083
|
-
}
|
|
1084
|
-
|
|
1085
|
-
function mergeMenuTransforms(
|
|
1086
|
-
collisionTransform: string,
|
|
1087
|
-
customTransform: string | undefined
|
|
1088
|
-
) {
|
|
1089
|
-
return customTransform
|
|
1090
|
-
? `${collisionTransform} ${customTransform}`
|
|
1091
|
-
: collisionTransform
|
|
1092
|
-
}
|
|
1093
|
-
|
|
1094
|
-
function isSameMenuCollisionShift(
|
|
1095
|
-
currentShift: MenuCollisionShift,
|
|
1096
|
-
nextShift: MenuCollisionShift
|
|
1097
|
-
) {
|
|
1098
|
-
return currentShift.x === nextShift.x && currentShift.y === nextShift.y
|
|
1099
|
-
}
|
|
1100
|
-
|
|
1101
885
|
export {
|
|
1102
886
|
Menu,
|
|
1103
887
|
MenuCaption,
|
|
@@ -1115,12 +899,14 @@ export {
|
|
|
1115
899
|
MenuItemTitle,
|
|
1116
900
|
MenuLabel,
|
|
1117
901
|
MenuProgress,
|
|
902
|
+
MenuPreview,
|
|
1118
903
|
MenuPortal,
|
|
1119
904
|
MenuRoot,
|
|
1120
905
|
MenuSeparator,
|
|
1121
906
|
MenuSub,
|
|
1122
907
|
MenuSubContent,
|
|
1123
908
|
MenuSubTrigger,
|
|
909
|
+
MenuSurface,
|
|
1124
910
|
MenuTrigger,
|
|
1125
911
|
menuItemContentVariants,
|
|
1126
912
|
menuItemIconVariants,
|
|
@@ -1144,5 +930,7 @@ export type {
|
|
|
1144
930
|
MenuLabelProps,
|
|
1145
931
|
MenuProgressProps,
|
|
1146
932
|
MenuProps,
|
|
933
|
+
MenuPreviewProps,
|
|
934
|
+
MenuSurfaceProps,
|
|
1147
935
|
MenuWidth,
|
|
1148
936
|
}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import * as MenubarPrimitive from "@radix-ui/react-menubar"
|
|
5
|
+
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"
|
|
6
|
+
|
|
7
|
+
import { cn } from "@/lib/utils"
|
|
8
|
+
|
|
9
|
+
type MenubarProps = React.ComponentProps<typeof MenubarPrimitive.Root>
|
|
10
|
+
type MenubarTriggerProps = React.ComponentPropsWithoutRef<
|
|
11
|
+
typeof MenubarPrimitive.Trigger
|
|
12
|
+
>
|
|
13
|
+
type MenubarContentProps = React.ComponentPropsWithoutRef<
|
|
14
|
+
typeof MenubarPrimitive.Content
|
|
15
|
+
>
|
|
16
|
+
type MenubarItemProps = React.ComponentPropsWithoutRef<
|
|
17
|
+
typeof MenubarPrimitive.Item
|
|
18
|
+
> & {
|
|
19
|
+
inset?: boolean
|
|
20
|
+
}
|
|
21
|
+
type MenubarCheckboxItemProps = React.ComponentPropsWithoutRef<
|
|
22
|
+
typeof MenubarPrimitive.CheckboxItem
|
|
23
|
+
>
|
|
24
|
+
type MenubarRadioItemProps = React.ComponentPropsWithoutRef<
|
|
25
|
+
typeof MenubarPrimitive.RadioItem
|
|
26
|
+
>
|
|
27
|
+
type MenubarLabelProps = React.ComponentPropsWithoutRef<
|
|
28
|
+
typeof MenubarPrimitive.Label
|
|
29
|
+
> & {
|
|
30
|
+
inset?: boolean
|
|
31
|
+
}
|
|
32
|
+
type MenubarSeparatorProps = React.ComponentPropsWithoutRef<
|
|
33
|
+
typeof MenubarPrimitive.Separator
|
|
34
|
+
>
|
|
35
|
+
type MenubarShortcutProps = React.ComponentProps<"span">
|
|
36
|
+
|
|
37
|
+
const MenubarMenu = MenubarPrimitive.Menu
|
|
38
|
+
const MenubarGroup = MenubarPrimitive.Group
|
|
39
|
+
const MenubarPortal = MenubarPrimitive.Portal
|
|
40
|
+
const MenubarSub = MenubarPrimitive.Sub
|
|
41
|
+
const MenubarRadioGroup = MenubarPrimitive.RadioGroup
|
|
42
|
+
|
|
43
|
+
const Menubar = React.forwardRef<
|
|
44
|
+
React.ElementRef<typeof MenubarPrimitive.Root>,
|
|
45
|
+
MenubarProps
|
|
46
|
+
>(function Menubar({ className, ...props }, ref) {
|
|
47
|
+
return (
|
|
48
|
+
<MenubarPrimitive.Root
|
|
49
|
+
data-slot="menubar"
|
|
50
|
+
ref={ref}
|
|
51
|
+
className={cn(
|
|
52
|
+
"flex h-[var(--bh-space-7xl-40)] items-center gap-[var(--bh-space-xs-4)] rounded-[var(--bh-radius-lg-8)] border border-[var(--bh-border-subtle)] bg-[var(--bh-bg-raised)] p-[var(--bh-space-xs-4)] shadow-[var(--shadow-component-default)]",
|
|
53
|
+
className
|
|
54
|
+
)}
|
|
55
|
+
{...props}
|
|
56
|
+
/>
|
|
57
|
+
)
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
const MenubarTrigger = React.forwardRef<
|
|
61
|
+
React.ElementRef<typeof MenubarPrimitive.Trigger>,
|
|
62
|
+
MenubarTriggerProps
|
|
63
|
+
>(function MenubarTrigger({ className, ...props }, ref) {
|
|
64
|
+
return (
|
|
65
|
+
<MenubarPrimitive.Trigger
|
|
66
|
+
data-slot="menubar-trigger"
|
|
67
|
+
ref={ref}
|
|
68
|
+
className={cn(
|
|
69
|
+
"flex h-[var(--bh-space-6xl-32)] items-center rounded-[var(--bh-radius-md-6)] px-[var(--bh-space-md-8)] 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 data-[highlighted]:bg-[var(--bh-interactive-ghost-hover)] data-[state=open]:bg-[var(--bh-interactive-soft-default)]",
|
|
70
|
+
className
|
|
71
|
+
)}
|
|
72
|
+
{...props}
|
|
73
|
+
/>
|
|
74
|
+
)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
const menuContentClassName =
|
|
78
|
+
"z-[var(--bh-z-popover)] min-w-[var(--bh-menu-width)] overflow-hidden rounded-[var(--bh-radius-xl-10)] bg-[var(--bh-bg-raised)] p-[var(--bh-space-xs-4)] text-[var(--bh-content-default)] shadow-[var(--shadow-menu)]"
|
|
79
|
+
|
|
80
|
+
const menuItemClassName =
|
|
81
|
+
"relative flex min-h-[var(--bh-menu-item-default-height)] cursor-default select-none items-center gap-[var(--bh-space-md-8)] rounded-[var(--bh-radius-md-6)] px-[var(--bh-space-md-8)] py-[var(--bh-space-sm-6)] 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 data-[disabled]:pointer-events-none data-[disabled]:text-[var(--bh-content-disabled)] data-[highlighted]:bg-[var(--bh-menu-item-hover-bg)]"
|
|
82
|
+
|
|
83
|
+
const MenubarContent = React.forwardRef<
|
|
84
|
+
React.ElementRef<typeof MenubarPrimitive.Content>,
|
|
85
|
+
MenubarContentProps
|
|
86
|
+
>(function MenubarContent({ align = "start", className, ...props }, ref) {
|
|
87
|
+
return (
|
|
88
|
+
<MenubarPortal>
|
|
89
|
+
<MenubarPrimitive.Content
|
|
90
|
+
align={align}
|
|
91
|
+
data-slot="menubar-content"
|
|
92
|
+
ref={ref}
|
|
93
|
+
className={cn(menuContentClassName, className)}
|
|
94
|
+
{...props}
|
|
95
|
+
/>
|
|
96
|
+
</MenubarPortal>
|
|
97
|
+
)
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
const MenubarItem = React.forwardRef<
|
|
101
|
+
React.ElementRef<typeof MenubarPrimitive.Item>,
|
|
102
|
+
MenubarItemProps
|
|
103
|
+
>(function MenubarItem({ className, inset, ...props }, ref) {
|
|
104
|
+
return (
|
|
105
|
+
<MenubarPrimitive.Item
|
|
106
|
+
data-inset={inset ? "true" : undefined}
|
|
107
|
+
data-slot="menubar-item"
|
|
108
|
+
ref={ref}
|
|
109
|
+
className={cn(menuItemClassName, inset && "ps-[var(--bh-space-8xl-48)]", className)}
|
|
110
|
+
{...props}
|
|
111
|
+
/>
|
|
112
|
+
)
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
const MenubarCheckboxItem = React.forwardRef<
|
|
116
|
+
React.ElementRef<typeof MenubarPrimitive.CheckboxItem>,
|
|
117
|
+
MenubarCheckboxItemProps
|
|
118
|
+
>(function MenubarCheckboxItem({ children, className, checked, ...props }, ref) {
|
|
119
|
+
return (
|
|
120
|
+
<MenubarPrimitive.CheckboxItem
|
|
121
|
+
checked={checked}
|
|
122
|
+
data-slot="menubar-checkbox-item"
|
|
123
|
+
ref={ref}
|
|
124
|
+
className={cn(menuItemClassName, "ps-[var(--bh-space-8xl-48)]", className)}
|
|
125
|
+
{...props}
|
|
126
|
+
>
|
|
127
|
+
<span className="absolute start-[var(--bh-space-md-8)] inline-flex size-[var(--bh-space-5xl-24)] items-center justify-center">
|
|
128
|
+
<MenubarPrimitive.ItemIndicator>
|
|
129
|
+
<CheckIcon className="size-[var(--bh-space-3xl-16)]" />
|
|
130
|
+
</MenubarPrimitive.ItemIndicator>
|
|
131
|
+
</span>
|
|
132
|
+
{children}
|
|
133
|
+
</MenubarPrimitive.CheckboxItem>
|
|
134
|
+
)
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
const MenubarRadioItem = React.forwardRef<
|
|
138
|
+
React.ElementRef<typeof MenubarPrimitive.RadioItem>,
|
|
139
|
+
MenubarRadioItemProps
|
|
140
|
+
>(function MenubarRadioItem({ children, className, ...props }, ref) {
|
|
141
|
+
return (
|
|
142
|
+
<MenubarPrimitive.RadioItem
|
|
143
|
+
data-slot="menubar-radio-item"
|
|
144
|
+
ref={ref}
|
|
145
|
+
className={cn(menuItemClassName, "ps-[var(--bh-space-8xl-48)]", className)}
|
|
146
|
+
{...props}
|
|
147
|
+
>
|
|
148
|
+
<span className="absolute start-[var(--bh-space-md-8)] inline-flex size-[var(--bh-space-5xl-24)] items-center justify-center">
|
|
149
|
+
<MenubarPrimitive.ItemIndicator>
|
|
150
|
+
<CircleIcon className="size-[var(--bh-space-md-8)] fill-current" />
|
|
151
|
+
</MenubarPrimitive.ItemIndicator>
|
|
152
|
+
</span>
|
|
153
|
+
{children}
|
|
154
|
+
</MenubarPrimitive.RadioItem>
|
|
155
|
+
)
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
const MenubarLabel = React.forwardRef<
|
|
159
|
+
React.ElementRef<typeof MenubarPrimitive.Label>,
|
|
160
|
+
MenubarLabelProps
|
|
161
|
+
>(function MenubarLabel({ className, inset, ...props }, ref) {
|
|
162
|
+
return (
|
|
163
|
+
<MenubarPrimitive.Label
|
|
164
|
+
data-slot="menubar-label"
|
|
165
|
+
ref={ref}
|
|
166
|
+
className={cn(
|
|
167
|
+
"px-[var(--bh-space-md-8)] py-[var(--bh-space-sm-6)] text-[length:var(--bh-text-body-xs-medium-font-size)] font-[var(--bh-text-body-xs-medium-font-weight)] leading-[var(--bh-text-body-xs-medium-line-height)] tracking-[var(--bh-text-body-xs-medium-letter-spacing)] text-[var(--bh-content-muted)]",
|
|
168
|
+
inset && "ps-[var(--bh-space-8xl-48)]",
|
|
169
|
+
className
|
|
170
|
+
)}
|
|
171
|
+
{...props}
|
|
172
|
+
/>
|
|
173
|
+
)
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
const MenubarSeparator = React.forwardRef<
|
|
177
|
+
React.ElementRef<typeof MenubarPrimitive.Separator>,
|
|
178
|
+
MenubarSeparatorProps
|
|
179
|
+
>(function MenubarSeparator({ className, ...props }, ref) {
|
|
180
|
+
return (
|
|
181
|
+
<MenubarPrimitive.Separator
|
|
182
|
+
data-slot="menubar-separator"
|
|
183
|
+
ref={ref}
|
|
184
|
+
className={cn("my-[var(--bh-space-xs-4)] h-[var(--bh-border-width-default)] bg-[var(--bh-border-subtle)]", className)}
|
|
185
|
+
{...props}
|
|
186
|
+
/>
|
|
187
|
+
)
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
function MenubarShortcut({ className, ...props }: MenubarShortcutProps) {
|
|
191
|
+
return (
|
|
192
|
+
<span
|
|
193
|
+
data-slot="menubar-shortcut"
|
|
194
|
+
className={cn("ms-auto text-[length:var(--bh-text-body-xs-medium-font-size)] font-[var(--bh-text-body-xs-medium-font-weight)] text-[var(--bh-content-muted)]", className)}
|
|
195
|
+
{...props}
|
|
196
|
+
/>
|
|
197
|
+
)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export {
|
|
201
|
+
Menubar,
|
|
202
|
+
MenubarCheckboxItem,
|
|
203
|
+
MenubarContent,
|
|
204
|
+
MenubarGroup,
|
|
205
|
+
MenubarItem,
|
|
206
|
+
MenubarLabel,
|
|
207
|
+
MenubarMenu,
|
|
208
|
+
MenubarPortal,
|
|
209
|
+
MenubarRadioGroup,
|
|
210
|
+
MenubarRadioItem,
|
|
211
|
+
MenubarSeparator,
|
|
212
|
+
MenubarShortcut,
|
|
213
|
+
MenubarSub,
|
|
214
|
+
MenubarTrigger,
|
|
215
|
+
}
|
|
216
|
+
export type {
|
|
217
|
+
MenubarCheckboxItemProps,
|
|
218
|
+
MenubarContentProps,
|
|
219
|
+
MenubarItemProps,
|
|
220
|
+
MenubarLabelProps,
|
|
221
|
+
MenubarProps,
|
|
222
|
+
MenubarRadioItemProps,
|
|
223
|
+
MenubarSeparatorProps,
|
|
224
|
+
MenubarShortcutProps,
|
|
225
|
+
MenubarTriggerProps,
|
|
226
|
+
}
|