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,35 @@
|
|
|
1
|
+
import { Button } from "@/components/ui/button"
|
|
2
|
+
import { Toaster, toast } from "@/components/ui/toast"
|
|
3
|
+
|
|
4
|
+
export function ToastDemo() {
|
|
5
|
+
return (
|
|
6
|
+
<div className="grid gap-[var(--bh-space-3xl-16)]">
|
|
7
|
+
<div className="flex flex-wrap gap-[var(--bh-space-md-8)]">
|
|
8
|
+
<Button size="sm" onClick={() => toast.success("Project saved")}>
|
|
9
|
+
Success
|
|
10
|
+
</Button>
|
|
11
|
+
<Button size="sm" variant="warning" onClick={() => toast.warning("Review required")}>
|
|
12
|
+
Warning
|
|
13
|
+
</Button>
|
|
14
|
+
<Button size="sm" variant="danger" onClick={() => toast.danger("Unable to publish")}>
|
|
15
|
+
Danger
|
|
16
|
+
</Button>
|
|
17
|
+
<Button
|
|
18
|
+
size="sm"
|
|
19
|
+
variant="outline"
|
|
20
|
+
onClick={() =>
|
|
21
|
+
toast.info("Invite sent", {
|
|
22
|
+
action: {
|
|
23
|
+
label: "Undo",
|
|
24
|
+
onClick: () => toast("Invite cancelled"),
|
|
25
|
+
},
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
>
|
|
29
|
+
Action
|
|
30
|
+
</Button>
|
|
31
|
+
</div>
|
|
32
|
+
<Toaster />
|
|
33
|
+
</div>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
@@ -6,8 +6,8 @@ export function ToggleDemo() {
|
|
|
6
6
|
const [checked, setChecked] = React.useState(true)
|
|
7
7
|
|
|
8
8
|
return (
|
|
9
|
-
<div className="grid gap-
|
|
10
|
-
<div className="flex flex-wrap items-center gap-
|
|
9
|
+
<div className="grid gap-[var(--bh-space-5xl-24)]">
|
|
10
|
+
<div className="flex flex-wrap items-center gap-[var(--bh-space-3xl-16)]">
|
|
11
11
|
<Toggle
|
|
12
12
|
checked={checked}
|
|
13
13
|
onCheckedChange={setChecked}
|
|
@@ -18,14 +18,14 @@ export function ToggleDemo() {
|
|
|
18
18
|
<Toggle aria-label="Disabled toggle" disabled />
|
|
19
19
|
</div>
|
|
20
20
|
|
|
21
|
-
<div className="grid gap-
|
|
21
|
+
<div className="grid gap-[var(--bh-space-3xl-16)] sm:grid-cols-2">
|
|
22
22
|
<ToggleField
|
|
23
23
|
defaultChecked
|
|
24
24
|
label="Label"
|
|
25
25
|
description="Supporting text"
|
|
26
26
|
/>
|
|
27
27
|
<ToggleField
|
|
28
|
-
className="w-
|
|
28
|
+
className="w-[var(--bh-space-15xl-224)]"
|
|
29
29
|
controlPosition="end"
|
|
30
30
|
label="Label"
|
|
31
31
|
/>
|
|
@@ -42,14 +42,14 @@ export function ToggleDemo() {
|
|
|
42
42
|
/>
|
|
43
43
|
</div>
|
|
44
44
|
|
|
45
|
-
<div dir="rtl" className="grid gap-
|
|
45
|
+
<div dir="rtl" className="grid gap-[var(--bh-space-3xl-16)] sm:grid-cols-2">
|
|
46
46
|
<ToggleField
|
|
47
47
|
defaultChecked
|
|
48
48
|
label={"\u0627\u0644\u062a\u0633\u0645\u064a\u0629"}
|
|
49
49
|
description={"\u0646\u0635 \u0645\u0633\u0627\u0639\u062f"}
|
|
50
50
|
/>
|
|
51
51
|
<ToggleField
|
|
52
|
-
className="w-
|
|
52
|
+
className="w-[var(--bh-space-15xl-224)]"
|
|
53
53
|
controlPosition="end"
|
|
54
54
|
label={"\u0627\u0644\u062a\u0633\u0645\u064a\u0629"}
|
|
55
55
|
/>
|
|
@@ -17,8 +17,8 @@ const rtlSupportText =
|
|
|
17
17
|
export function TooltipDemo() {
|
|
18
18
|
return (
|
|
19
19
|
<TooltipProvider delayDuration={0}>
|
|
20
|
-
<div className="grid gap-
|
|
21
|
-
<div className="flex flex-wrap items-center gap-
|
|
20
|
+
<div className="grid gap-[var(--bh-space-6xl-32)]">
|
|
21
|
+
<div className="flex flex-wrap items-center gap-[var(--bh-space-6xl-32)]">
|
|
22
22
|
<Tooltip defaultOpen>
|
|
23
23
|
<TooltipTrigger asChild>
|
|
24
24
|
<Button size="icon" variant="secondary" aria-label="More information">
|
|
@@ -53,7 +53,7 @@ export function TooltipDemo() {
|
|
|
53
53
|
</Tooltip>
|
|
54
54
|
</div>
|
|
55
55
|
|
|
56
|
-
<div className="flex flex-wrap items-center gap-
|
|
56
|
+
<div className="flex flex-wrap items-center gap-[var(--bh-space-6xl-32)]">
|
|
57
57
|
<Tooltip defaultOpen>
|
|
58
58
|
<TooltipTrigger asChild>
|
|
59
59
|
<Button variant="secondary">Dark large</Button>
|
|
@@ -82,7 +82,7 @@ export function TooltipDemo() {
|
|
|
82
82
|
</Tooltip>
|
|
83
83
|
</div>
|
|
84
84
|
|
|
85
|
-
<div dir="rtl" className="flex flex-wrap items-center gap-
|
|
85
|
+
<div dir="rtl" className="flex flex-wrap items-center gap-[var(--bh-space-6xl-32)]">
|
|
86
86
|
<Tooltip defaultOpen>
|
|
87
87
|
<TooltipTrigger asChild>
|
|
88
88
|
<Button size="icon" variant="secondary" aria-label={rtlLabel}>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Banhaten implementation rules
|
|
2
|
+
|
|
3
|
+
This project uses the Banhaten design system. Treat the installed component API and registry metadata as the source of truth; do not redraw controls from memory or infer defaults from the first documented variant.
|
|
4
|
+
|
|
5
|
+
## Before changing UI
|
|
6
|
+
|
|
7
|
+
1. Run `npx banhaten search <need>` to find the intended component.
|
|
8
|
+
2. Run `npx banhaten docs <component>` to inspect explicit defaults, recommended uses, avoid rules, and recipes.
|
|
9
|
+
3. Run `npx banhaten view <component>` before wrapping or extending its internals.
|
|
10
|
+
4. Prefer the documented golden recipe when the screen resembles a collection filter bar or results toolbar.
|
|
11
|
+
|
|
12
|
+
## Composition rules
|
|
13
|
+
|
|
14
|
+
- Use one semantic `density` across controls in the same row: `compact` is 32px, `default` is 36px, and `comfortable` is 40px.
|
|
15
|
+
- Do not align Banhaten controls with raw height, padding, radius, or font-size utilities. Width and responsive layout utilities are allowed.
|
|
16
|
+
- Use `DatePicker` or `DateRangePicker` for dates. Do not simulate calendar fields with `Input` or native date inputs.
|
|
17
|
+
- Pass explicit `leadingIcon` and `trailingIcon` nodes. Use `showAtSign` or `showInfo` only for those exact semantic affordances. The legacy `hasLeadingIcon` and `hasInformationIcon` flags are deprecated.
|
|
18
|
+
- Use `shortcutKeys={["Mod", "K"]}` or `KbdShortcut` for shortcuts. Never hard-code a single Command glyph for every platform.
|
|
19
|
+
- Use `SegmentedControl` for small mutually exclusive view, density, period, or numeric choices. Do not rebuild joined numeric buttons locally.
|
|
20
|
+
- Use functional `Select` for option menus. `ToolbarSelect` is only a trigger-shaped toolbar primitive.
|
|
21
|
+
- Preserve inherited `dir`; use logical spacing and alignment utilities for RTL-safe composition.
|
|
22
|
+
|
|
23
|
+
## Before finishing
|
|
24
|
+
|
|
25
|
+
Run `npx banhaten doctor` and inspect every diagnostic. Run `npx banhaten diff` before updating installed components, then execute the product's type, behavior, accessibility, and visual tests.
|
|
26
|
+
|
|
27
|
+
Canonical recipes live in `docs/design-system/form-recipes.md` in the Banhaten package.
|
|
@@ -4,24 +4,204 @@ import * as React from "react"
|
|
|
4
4
|
|
|
5
5
|
export type Direction = "ltr" | "rtl"
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
type DirectionStore = {
|
|
8
|
+
listeners: Set<() => void>
|
|
9
|
+
observer?: MutationObserver
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const DirectionContext = React.createContext<Direction | undefined>(undefined)
|
|
13
|
+
const directionStores = new WeakMap<Document, DirectionStore>()
|
|
14
|
+
const noop = () => undefined
|
|
15
|
+
|
|
16
|
+
export type DirectionProviderProps = {
|
|
17
|
+
children: React.ReactNode
|
|
18
|
+
dir: Direction
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function DirectionProvider({
|
|
22
|
+
children,
|
|
23
|
+
dir,
|
|
24
|
+
}: DirectionProviderProps) {
|
|
25
|
+
return React.createElement(DirectionContext.Provider, { value: dir }, children)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function resolveDirection(
|
|
29
|
+
explicitDirection?: Direction,
|
|
30
|
+
element?: Element | null
|
|
31
|
+
): Direction {
|
|
32
|
+
if (explicitDirection) return explicitDirection
|
|
33
|
+
|
|
34
|
+
let ancestor = element?.parentElement
|
|
35
|
+
while (ancestor) {
|
|
36
|
+
const inheritedDirection = normalizeDirection(ancestor.getAttribute("dir"))
|
|
37
|
+
if (inheritedDirection) return inheritedDirection
|
|
38
|
+
ancestor = ancestor.parentElement
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const ownerDocument = element?.ownerDocument ?? getBrowserDocument()
|
|
42
|
+
const documentDirection = normalizeDirection(
|
|
43
|
+
ownerDocument?.documentElement.getAttribute("dir")
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
return documentDirection ?? "ltr"
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function useResolvedDirection<T extends Element>(
|
|
50
|
+
explicitDirection: Direction | undefined,
|
|
51
|
+
elementRef: React.RefObject<T | null>
|
|
52
|
+
) {
|
|
53
|
+
const contextDirection = React.useContext(DirectionContext)
|
|
54
|
+
const preferredDirection = explicitDirection ?? contextDirection
|
|
55
|
+
|
|
56
|
+
const subscribe = React.useCallback(
|
|
57
|
+
(listener: () => void) => {
|
|
58
|
+
if (preferredDirection) return noop
|
|
59
|
+
|
|
60
|
+
const ownerDocument =
|
|
61
|
+
elementRef.current?.ownerDocument ?? getBrowserDocument()
|
|
62
|
+
|
|
63
|
+
return ownerDocument
|
|
64
|
+
? subscribeToDirectionChanges(ownerDocument, listener)
|
|
65
|
+
: noop
|
|
66
|
+
},
|
|
67
|
+
[elementRef, preferredDirection]
|
|
68
|
+
)
|
|
69
|
+
const getSnapshot = React.useCallback(
|
|
70
|
+
() => resolveDirection(preferredDirection, elementRef.current),
|
|
71
|
+
[elementRef, preferredDirection]
|
|
72
|
+
)
|
|
73
|
+
const getServerSnapshot = React.useCallback(
|
|
74
|
+
() => preferredDirection ?? "ltr",
|
|
75
|
+
[preferredDirection]
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
return React.useSyncExternalStore(
|
|
79
|
+
subscribe,
|
|
80
|
+
getSnapshot,
|
|
81
|
+
getServerSnapshot
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function useDirection(defaultDirection?: Direction) {
|
|
86
|
+
const contextDirection = React.useContext(DirectionContext)
|
|
87
|
+
const preferredDirection = defaultDirection ?? contextDirection
|
|
88
|
+
const observedDirection = useDocumentDirection(preferredDirection)
|
|
89
|
+
const observedDirectionRef = React.useRef(observedDirection)
|
|
90
|
+
const [directionOverride, setDirectionOverride] = React.useState<
|
|
91
|
+
Direction | undefined
|
|
92
|
+
>(undefined)
|
|
93
|
+
|
|
94
|
+
observedDirectionRef.current = observedDirection
|
|
95
|
+
|
|
96
|
+
const setDirection = React.useCallback<
|
|
97
|
+
React.Dispatch<React.SetStateAction<Direction>>
|
|
98
|
+
>((nextDirection) => {
|
|
99
|
+
setDirectionOverride((currentDirection) => {
|
|
100
|
+
const selectedDirection =
|
|
101
|
+
currentDirection ?? observedDirectionRef.current
|
|
102
|
+
|
|
103
|
+
return typeof nextDirection === "function"
|
|
104
|
+
? nextDirection(selectedDirection)
|
|
105
|
+
: nextDirection
|
|
106
|
+
})
|
|
107
|
+
}, [])
|
|
9
108
|
|
|
10
109
|
React.useEffect(() => {
|
|
11
|
-
|
|
110
|
+
if (defaultDirection === undefined && contextDirection) {
|
|
111
|
+
setDirectionOverride(contextDirection)
|
|
112
|
+
}
|
|
113
|
+
}, [contextDirection, defaultDirection])
|
|
114
|
+
|
|
115
|
+
return [directionOverride ?? observedDirection, setDirection] as const
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function useDocumentDirection(preferredDirection?: Direction) {
|
|
119
|
+
const subscribe = React.useCallback(
|
|
120
|
+
(listener: () => void) => {
|
|
121
|
+
if (preferredDirection) return noop
|
|
122
|
+
|
|
123
|
+
const ownerDocument = getBrowserDocument()
|
|
124
|
+
return ownerDocument
|
|
125
|
+
? subscribeToDirectionChanges(ownerDocument, listener)
|
|
126
|
+
: noop
|
|
127
|
+
},
|
|
128
|
+
[preferredDirection]
|
|
129
|
+
)
|
|
130
|
+
const getSnapshot = React.useCallback(
|
|
131
|
+
() => resolveDirection(preferredDirection),
|
|
132
|
+
[preferredDirection]
|
|
133
|
+
)
|
|
134
|
+
const getServerSnapshot = React.useCallback(
|
|
135
|
+
() => preferredDirection ?? "ltr",
|
|
136
|
+
[preferredDirection]
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
return React.useSyncExternalStore(
|
|
140
|
+
subscribe,
|
|
141
|
+
getSnapshot,
|
|
142
|
+
getServerSnapshot
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function subscribeToDirectionChanges(
|
|
147
|
+
ownerDocument: Document,
|
|
148
|
+
listener: () => void
|
|
149
|
+
) {
|
|
150
|
+
const store = getDirectionStore(ownerDocument)
|
|
151
|
+
store.listeners.add(listener)
|
|
152
|
+
|
|
153
|
+
if (store.listeners.size === 1) {
|
|
154
|
+
startDirectionObserver(ownerDocument, store)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return () => {
|
|
158
|
+
store.listeners.delete(listener)
|
|
12
159
|
|
|
13
|
-
if (
|
|
14
|
-
|
|
15
|
-
|
|
160
|
+
if (store.listeners.size === 0) {
|
|
161
|
+
store.observer?.disconnect()
|
|
162
|
+
store.observer = undefined
|
|
16
163
|
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
17
166
|
|
|
18
|
-
|
|
19
|
-
|
|
167
|
+
function getDirectionStore(ownerDocument: Document) {
|
|
168
|
+
const existingStore = directionStores.get(ownerDocument)
|
|
169
|
+
if (existingStore) return existingStore
|
|
20
170
|
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
171
|
+
const store: DirectionStore = { listeners: new Set() }
|
|
172
|
+
directionStores.set(ownerDocument, store)
|
|
173
|
+
return store
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function startDirectionObserver(
|
|
177
|
+
ownerDocument: Document,
|
|
178
|
+
store: DirectionStore
|
|
179
|
+
) {
|
|
180
|
+
const MutationObserverConstructor =
|
|
181
|
+
ownerDocument.defaultView?.MutationObserver
|
|
182
|
+
const directionRoot = ownerDocument.documentElement
|
|
183
|
+
|
|
184
|
+
if (!MutationObserverConstructor || !directionRoot) return
|
|
185
|
+
|
|
186
|
+
store.observer = new MutationObserverConstructor(() => {
|
|
187
|
+
for (const listener of [...store.listeners]) {
|
|
188
|
+
listener()
|
|
189
|
+
}
|
|
190
|
+
})
|
|
191
|
+
store.observer.observe(directionRoot, {
|
|
192
|
+
attributeFilter: ["dir"],
|
|
193
|
+
attributes: true,
|
|
194
|
+
subtree: true,
|
|
195
|
+
})
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function getBrowserDocument() {
|
|
199
|
+
return typeof document === "undefined" ? undefined : document
|
|
200
|
+
}
|
|
25
201
|
|
|
26
|
-
|
|
202
|
+
function normalizeDirection(value?: string | null): Direction | undefined {
|
|
203
|
+
const normalizedValue = value?.trim().toLowerCase()
|
|
204
|
+
return normalizedValue === "ltr" || normalizedValue === "rtl"
|
|
205
|
+
? normalizedValue
|
|
206
|
+
: undefined
|
|
27
207
|
}
|