banhaten 0.2.0 → 0.4.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 +55 -0
- package/README.md +5 -5
- package/docs/design-system/component-implementation-ownership-audit.md +245 -0
- package/docs/design-system/component-quality-audit-2026-08-20.md +225 -0
- package/docs/design-system/component-showcase-consistency-report.md +2 -0
- package/docs/design-system/components/README.md +1 -0
- package/docs/design-system/components/activity-feed.md +2 -0
- package/docs/design-system/components/activity-heatmap.md +73 -0
- package/docs/design-system/components/alert-dialog.md +1 -1
- package/docs/design-system/components/alert.md +3 -3
- package/docs/design-system/components/attribute.md +1 -1
- package/docs/design-system/components/avatar.md +2 -2
- package/docs/design-system/components/badge.md +1 -1
- package/docs/design-system/components/banner.md +6 -2
- package/docs/design-system/components/breadcrumbs.md +5 -2
- package/docs/design-system/components/button-group.md +3 -2
- package/docs/design-system/components/button.md +2 -2
- package/docs/design-system/components/card.md +11 -3
- package/docs/design-system/components/catalog-components.md +3 -0
- package/docs/design-system/components/date-picker.md +3 -1
- package/docs/design-system/components/file-upload.md +5 -1
- package/docs/design-system/components/input.md +8 -6
- package/docs/design-system/components/item.md +3 -1
- package/docs/design-system/components/kbd.md +11 -8
- package/docs/design-system/components/menu.md +2 -2
- package/docs/design-system/components/modal.md +1 -1
- package/docs/design-system/components/navigation-menu.md +1 -1
- package/docs/design-system/components/onboarding-step-list-item.md +3 -2
- package/docs/design-system/components/page-header.md +3 -1
- package/docs/design-system/components/pagination.md +3 -2
- package/docs/design-system/components/radio-card.md +1 -1
- package/docs/design-system/components/resizable.md +1 -1
- package/docs/design-system/components/scroll-area.md +7 -3
- package/docs/design-system/components/select.md +1 -1
- package/docs/design-system/components/sidebar.md +60 -18
- package/docs/design-system/components/slideout.md +4 -1
- package/docs/design-system/components/steps.md +7 -2
- package/docs/design-system/components/table.md +25 -7
- package/docs/design-system/components/tag.md +3 -3
- package/docs/design-system/components/timeline.md +4 -1
- package/docs/design-system/components/toggle.md +1 -1
- package/docs/design-system/components/toolbar.md +1 -1
- package/docs/design-system/components/tooltip.md +1 -1
- package/docs/design-system/density-and-elevation.md +23 -2
- package/docs/design-system/gap-promotion-report.md +1 -67
- package/docs/design-system/icons.md +6 -1
- package/docs/design-system/installation.md +1 -1
- package/docs/design-system/launch-comparison-shadcn.md +10 -10
- package/docs/design-system/token-governance.md +7 -8
- package/package.json +3 -2
- package/registry/components/alert-dialog.tsx +1 -1
- package/registry/components/alert.tsx +17 -13
- package/registry/components/attribute.tsx +8 -2
- package/registry/components/avatar.tsx +28 -20
- package/registry/components/badge.tsx +17 -17
- package/registry/components/button-group.tsx +4 -2
- package/registry/components/button.tsx +3 -3
- package/registry/components/card.tsx +19 -3
- package/registry/components/carousel.tsx +14 -0
- package/registry/components/command.tsx +37 -3
- package/registry/components/date-picker.tsx +83 -35
- package/registry/components/expanded/ActivityFeed.tsx +3 -7
- package/registry/components/expanded/ActivityHeatmap.tsx +64 -0
- package/registry/components/expanded/Banner.tsx +0 -1
- package/registry/components/expanded/Breadcrumbs.tsx +3 -0
- package/registry/components/expanded/CatalogComponentsShowcase.tsx +3 -4
- package/registry/components/expanded/CatalogDivider.tsx +3 -2
- package/registry/components/expanded/FileUpload.tsx +7 -5
- package/registry/components/expanded/OnboardingStepListItem.tsx +6 -7
- package/registry/components/expanded/PageHeader.tsx +35 -44
- package/registry/components/expanded/Slideout.tsx +18 -13
- package/registry/components/expanded/Steps.tsx +147 -9
- package/registry/components/expanded/Table.tsx +50 -18
- package/registry/components/expanded/Timeline.tsx +11 -24
- package/registry/components/expanded/activityFeed.css +8 -8
- package/registry/components/expanded/activityHeatmap.css +66 -0
- package/registry/components/expanded/banner.css +30 -15
- package/registry/components/expanded/breadcrumbs.css +5 -5
- package/registry/components/expanded/fileUpload.css +4 -4
- package/registry/components/expanded/onboardingStepListItem.css +16 -7
- package/registry/components/expanded/pageHeader.css +14 -11
- package/registry/components/expanded/slideout.css +3 -7
- package/registry/components/expanded/steps.css +75 -12
- package/registry/components/expanded/table.css +63 -69
- package/registry/components/expanded/timeline.css +17 -16
- package/registry/components/field.tsx +61 -8
- package/registry/components/input.tsx +12 -5
- package/registry/components/item.tsx +1 -1
- package/registry/components/kbd.tsx +109 -15
- package/registry/components/menu.tsx +57 -7
- package/registry/components/modal.tsx +1 -1
- package/registry/components/navigation-menu.tsx +1 -1
- package/registry/components/pagination.css +36 -0
- package/registry/components/pagination.tsx +20 -13
- package/registry/components/progress-slider.tsx +1 -1
- package/registry/components/radio-card.tsx +1 -2
- package/registry/components/resizable.tsx +36 -2
- package/registry/components/scroll-area.tsx +30 -6
- package/registry/components/select.tsx +35 -12
- package/registry/components/sidebar.tsx +940 -62
- package/registry/components/social-button.tsx +12 -5
- package/registry/components/table-elements.tsx +128 -0
- package/registry/components/tabs.tsx +5 -10
- package/registry/components/tag.tsx +2 -2
- package/registry/components/toggle.tsx +2 -2
- package/registry/components/toolbar.tsx +6 -6
- package/registry/components/tooltip.tsx +1 -1
- package/registry/examples/attribute-demo.tsx +1 -1
- package/registry/examples/avatar-demo.tsx +7 -4
- package/registry/examples/command-palette-demo.tsx +0 -1
- package/registry/examples/expanded/activity-heatmap-demo.tsx +29 -0
- package/registry/examples/expanded/breadcrumbs-demo.tsx +3 -3
- package/registry/examples/kbd-demo.tsx +2 -1
- package/registry/examples/pagination-demo.tsx +5 -5
- package/registry/examples/sidebar-demo.tsx +59 -13
- package/registry/guidance/USAGE.md +1 -1
- package/registry/index.json +621 -60
- package/registry/styles/globals.css +211 -151
- package/registry.json +44 -6
- package/tokens/banhaten.tokens.json +325 -95
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# Launch Comparison: Banhaten and shadcn/ui
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Benchmark references reviewed against the official shadcn/ui CLI, registry, theming, and RTL documentation on 2026-07-10; Banhaten implementation status refreshed on 2026-08-20. shadcn/ui is the distribution and documentation benchmark—not Banhaten’s visual source.
|
|
4
4
|
|
|
5
5
|
## Outcome
|
|
6
6
|
|
|
7
7
|
Banhaten is a launch candidate with a distinct product contract: Arabic and English-first typography, inherited RTL by default, seven brand themes, three radius modes, stable primitives separated from larger Patterns, and a hard rule that distributable components consume canonical Banhaten tokens.
|
|
8
8
|
|
|
9
|
-
The
|
|
9
|
+
The former color-contrast exception is closed. The reviewed semantic-role corrections preserve the Banhaten palette while selecting valid foreground/background roles across themes and states. The Color Contrast page now evaluates 910 theme/mode scenarios and reports **910 passes and 0 failures**, with every pair, score, threshold, state, and swatch retained as inspectable evidence.
|
|
10
10
|
|
|
11
11
|
## Benchmark Summary
|
|
12
12
|
|
|
@@ -14,7 +14,7 @@ The only intentionally unresolved visual exception is color contrast. The review
|
|
|
14
14
|
| --- | --- | --- | --- |
|
|
15
15
|
| Distribution | Source registry and CLI installation | Canonical Banhaten registry plus generated shadcn-compatible `registry.json` | Verified |
|
|
16
16
|
| Component ownership | Copied source is consumer-owned | Receipt-backed generated ownership; local drift blocks updates unless explicitly forced | Stronger safety |
|
|
17
|
-
| Registry dependencies | Dependency closure and typed registry items | Dependency graph, schema validation, mirror checks, and isolated compilation of all
|
|
17
|
+
| Registry dependencies | Dependency closure and typed registry items | Dependency graph, schema validation, mirror checks, and isolated compilation of all 68 items | Verified |
|
|
18
18
|
| CLI | `init`, `add`, `view`, `docs`, migrations, presets | `init`, `add`, real `diff`, safe `update`, `list`, `search`, full `docs`, and `view` | Launch scope verified |
|
|
19
19
|
| Framework setup | Multiple framework templates | Vite auto-configuration and framework-neutral/Next-style source installation | Verified |
|
|
20
20
|
| Package managers | npm, pnpm, Yarn, Bun | Detection and install hints tested for all four | Verified |
|
|
@@ -23,7 +23,7 @@ The only intentionally unresolved visual exception is color contrast. The review
|
|
|
23
23
|
| RTL | First-class RTL and install-time transformations | Authored logical layout, inherited direction hook/provider, Arabic font, explicit message catalogs, and RTL keyboard tests | Banhaten-specific |
|
|
24
24
|
| Documentation | Live preview/code, component examples, API and CLI docs | Live registry previews, exact example source, extracted TypeScript props, token contract, accessibility contract, RTL, files, navigation/token search, and copy actions | Verified |
|
|
25
25
|
| Components vs blocks | Components and larger blocks | Stable Components and broader Patterns; experiments and visual QA isolated under Lab | Verified |
|
|
26
|
-
| Accessibility | Primitive semantics and per-component guidance | Native/Radix semantics, focus handling, dialog traps, tabs contract, reduced motion, forced colors,
|
|
26
|
+
| Accessibility | Primitive semantics and per-component guidance | Native/Radix semantics, focus handling, dialog traps, tabs contract, reduced motion, forced colors, 910/910 contrast, strict route Axe, and Chromium/Firefox/WebKit tests | Verified |
|
|
27
27
|
| Release governance | Changelog and frequent CLI/schema evolution | Changelog, security, contributing, support matrix, stability tiers, deprecation, release gate, and roadmap | Verified |
|
|
28
28
|
|
|
29
29
|
## Full Finding Register
|
|
@@ -35,18 +35,18 @@ The only intentionally unresolved visual exception is color contrast. The review
|
|
|
35
35
|
- Repaired Command Bar search/clear/submit behavior, Table disabled/action behavior, File Upload progress semantics, Spinner reduced-motion behavior, and Date Picker presets/month-year interaction.
|
|
36
36
|
- Standardized direction resolution for Alert, Pagination, Input OTP, Carousel, and Toast through explicit props, `DirectionProvider`, nearest `[dir]`, then document direction.
|
|
37
37
|
- Corrected Arabic Pagination copy and kept product strings explicit rather than silently localizing demo text.
|
|
38
|
-
- Added focused behavior tests; the component suite currently runs
|
|
38
|
+
- Added focused behavior tests; the component suite currently runs 205 tests.
|
|
39
39
|
|
|
40
40
|
### Colors and tokens
|
|
41
41
|
|
|
42
|
-
-
|
|
42
|
+
- Repaired semantic foreground/background role selection across component states while preserving the canonical palette; all 910 generated contrast combinations now pass.
|
|
43
43
|
- Split system, typography, effects, component variables, dark effects, and
|
|
44
44
|
scoped aliases into owned `tokens/source/` fragments that compile to
|
|
45
45
|
`tokens/banhaten.tokens.json`.
|
|
46
46
|
- Generated live `var(...)` alias graphs rather than flattened semantic values and verified custom-property closure.
|
|
47
47
|
- Added named categorical chart semantics, spinner/skeleton/motion tokens, exact icon stroke tokens, Item tokens, default border/transition wiring, reduced motion, and forced-color focus rules.
|
|
48
|
-
- Generated exact component token metadata from source. All
|
|
49
|
-
- Deduplicated theme CSS against the default cascade
|
|
48
|
+
- Generated exact component token metadata from source. All 68 registry components have non-empty, current token contracts.
|
|
49
|
+
- Deduplicated theme CSS against the default cascade and kept generated CSS at 156,729 bytes after the accessibility and component-token additions.
|
|
50
50
|
- Documented the no-global-density decision and the semantic elevation hierarchy.
|
|
51
51
|
|
|
52
52
|
### Usage and composition
|
|
@@ -70,7 +70,7 @@ The only intentionally unresolved visual exception is color contrast. The review
|
|
|
70
70
|
### Documentation and presentation
|
|
71
71
|
|
|
72
72
|
- Removed launch-blocking `noindex`, added description/social metadata, dynamic page titles, skip link, release status/version, and responsive searchable navigation.
|
|
73
|
-
- Reframed the overview around quick start, token rules, safe updates, and the
|
|
73
|
+
- Reframed the overview around quick start, token rules, safe updates, and the now-enforced contrast contract.
|
|
74
74
|
- Added focus trap, Escape, initial focus, and focus return to Customize and Component Matrix dialogs.
|
|
75
75
|
- Completed Preview/Code tab IDs, `aria-controls`, `aria-labelledby`, roving focus, and keyboard navigation.
|
|
76
76
|
- Renamed ambiguous “Copy Page” to “Copy page link” and added clipboard fallback.
|
|
@@ -79,7 +79,7 @@ The only intentionally unresolved visual exception is color contrast. The review
|
|
|
79
79
|
### Verification and release
|
|
80
80
|
|
|
81
81
|
- Browser checks cover Chromium, Firefox, and WebKit; visual baselines stay on Chromium for deterministic snapshots.
|
|
82
|
-
- Automated checks cover LTR/RTL behavior, portals, focus return, docs navigation, mobile navigation, token copy/search, live theme overrides, the
|
|
82
|
+
- Automated checks cover LTR/RTL behavior, portals, focus return, docs navigation, mobile navigation, token copy/search, live theme overrides, the 910/910 contrast totals, reduced motion, forced colors, and strict route-wide Axe findings without a color-rule exception.
|
|
83
83
|
- Bundle budgets, schema validation, token generation, token-only styling, registry mirrors, documentation coverage, CLI integration, isolated installs, package audit, and tarball contents are release gates.
|
|
84
84
|
|
|
85
85
|
## Deliberate Differences, Not Missing Copies
|
|
@@ -29,14 +29,13 @@ that authored CSS source.
|
|
|
29
29
|
|
|
30
30
|
The generator emits the complete default-theme graph once, then emits only declarations whose values differ for each alternate theme. Dark mode and alternate themes inherit unchanged scoped aliases through the cascade. This keeps the live graph auditable without duplicating identical declarations.
|
|
31
31
|
|
|
32
|
-
The default appearance
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
`cssContract.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
explicitly changed.
|
|
32
|
+
The default appearance uses `gray` for both brand roles and the neutral ramp.
|
|
33
|
+
As a result, product surfaces, links, focus states, and primary actions are
|
|
34
|
+
monochrome by default. `cssContract.defaultTheme` and
|
|
35
|
+
`cssContract.defaultNeutralTheme` record that composition. `npm run
|
|
36
|
+
tokens:build` synchronizes it into the authored default theme and semantic
|
|
37
|
+
color-mode values before compiling the public artifacts. Alternate brand themes
|
|
38
|
+
keep their reviewed neutral ramps unless their source is explicitly changed.
|
|
40
39
|
|
|
41
40
|
Color values are design-owned. The generated Color Contrast page reports failing combinations and recommendations, but automation must not silently change source colors. A color change requires an explicit design review and regeneration of the contrast baseline.
|
|
42
41
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "banhaten",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Banhaten design system: an Arabic and English-first React design system with shadcn-style component installation.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"build": "npm --prefix playground ci --include=dev --include=optional && npm --prefix playground run build",
|
|
35
35
|
"build:railway": "npm --prefix playground ci --include=dev --include=optional && npm --prefix playground run build:railway",
|
|
36
36
|
"start": "node playground/scripts/serve-static.mjs playground/dist",
|
|
37
|
-
"check": "node --check src/cli/index.js && node --check src/cli/command-line.js && node --check src/cli/doctor.js && node --check src/cli/config-editors.js && node --check src/cli/source-scanner.js && node --check src/cli/jsonc.js && node --check src/cli/vite-config.js && node --check src/cli/install-plan.js && node --check src/cli/install-receipt.js && node --check src/cli/package-install-state.js && node --check src/cli/package-manager.js && node --check src/cli/package-plan.js && node --check src/cli/package-version.js && node --check scripts/compile-token-catalog.mjs && node --check scripts/sync-default-theme-neutral-values.mjs && node --check scripts/token-catalog-test.mjs && node --check scripts/registry-catalog.mjs && node --check scripts/generate-registry-index.mjs && node --check scripts/generate-shadcn-registry.mjs && node --check scripts/normalize-component-docs.mjs && node --check scripts/package-artifact.mjs && node --check scripts/check-package-contents.mjs && node --check scripts/select-react-compatibility.mjs && npm run contracts:check && npm run cli:test && npm run tokens:check && npm run registry:check && npm run docs:check && npm run package:check && npm run playground:build && npm run playground:test:browser && npm run playground:audit",
|
|
37
|
+
"check": "node --check src/cli/index.js && node --check src/cli/command-line.js && node --check src/cli/doctor.js && node --check src/cli/config-editors.js && node --check src/cli/source-scanner.js && node --check src/cli/jsonc.js && node --check src/cli/vite-config.js && node --check src/cli/install-plan.js && node --check src/cli/install-receipt.js && node --check src/cli/package-install-state.js && node --check src/cli/package-manager.js && node --check src/cli/package-plan.js && node --check src/cli/package-version.js && node --check scripts/compile-token-catalog.mjs && node --check scripts/sync-default-theme-neutral-values.mjs && node --check scripts/token-catalog-test.mjs && node --check scripts/registry-catalog.mjs && node --check scripts/generate-registry-index.mjs && node --check scripts/generate-shadcn-registry.mjs && node --check scripts/normalize-component-docs.mjs && node --check scripts/package-artifact.mjs && node --check scripts/check-package-contents.mjs && node --check scripts/select-react-compatibility.mjs && npm run contracts:check && npm run cli:test && npm run tokens:check && npm run components:ownership:check && npm run registry:check && npm run docs:check && npm run package:check && npm run playground:build && npm run playground:test:browser && npm run playground:audit",
|
|
38
38
|
"contracts:check": "node scripts/validate-contracts.mjs",
|
|
39
39
|
"cli:test": "node scripts/cli-argument-test.mjs && node scripts/cli-dependency-test.mjs && node scripts/cli-install-plan-test.mjs && node scripts/cli-integration-test.mjs && node scripts/cli-doctor-test.mjs",
|
|
40
40
|
"playground:build": "npm --prefix playground run build",
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"registry:exports": "node scripts/check-isolated-registry-installs.mjs --write-exports",
|
|
50
50
|
"registry:sync": "node scripts/check-registry-mirrors.mjs --write",
|
|
51
51
|
"components:tokens:check": "node scripts/check-component-token-usage.mjs",
|
|
52
|
+
"components:ownership:check": "npm --prefix playground run test:ownership",
|
|
52
53
|
"components:tokens:metadata": "node scripts/sync-component-token-metadata.mjs",
|
|
53
54
|
"docs:check": "node scripts/check-component-docs.mjs && node scripts/normalize-component-docs.mjs",
|
|
54
55
|
"docs:normalize": "node scripts/normalize-component-docs.mjs --write",
|
|
@@ -16,7 +16,7 @@ const alertDialogContentVariants = cva(
|
|
|
16
16
|
"fixed left-1/2 top-1/2 z-[var(--bh-z-overlay)] flex max-h-[calc(100vh-(var(--bh-space-8xl-48)*2))] w-[var(--bh-alert-dialog-width)]",
|
|
17
17
|
"max-w-[calc(100vw-(var(--bh-space-4xl-20)*2))] -translate-x-1/2 -translate-y-1/2 flex-col overflow-hidden",
|
|
18
18
|
"rounded-[var(--bh-radius-2xl-12)] bg-[var(--bh-bg-raised)] text-[var(--bh-content-default)] shadow-[var(--shadow-modal)] outline-none",
|
|
19
|
-
"[--bh-alert-dialog-border:var(--bh-border-subtle)] [--shadow-modal:inset_0px_0px_0px_var(--bh-border-width-default)_var(--bh-alert-dialog-border),var(--shadow-
|
|
19
|
+
"[--bh-alert-dialog-border:var(--bh-border-subtle)] [--shadow-modal:inset_0px_0px_0px_var(--bh-border-width-default)_var(--bh-alert-dialog-border),var(--shadow-2xl)]",
|
|
20
20
|
],
|
|
21
21
|
{
|
|
22
22
|
variants: {
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
|
|
12
12
|
import { cn } from "@/lib/utils"
|
|
13
13
|
import { useResolvedDirection } from "@/hooks/use-direction"
|
|
14
|
+
import { Button } from "@/components/ui/button"
|
|
14
15
|
|
|
15
16
|
const alertVariants = cva(
|
|
16
17
|
[
|
|
@@ -22,13 +23,13 @@ const alertVariants = cva(
|
|
|
22
23
|
variants: {
|
|
23
24
|
status: {
|
|
24
25
|
danger:
|
|
25
|
-
"[--alert-bg:var(--bh-bg-danger-subtle)] [--alert-border:var(--bh-border-danger-subtle)] [--alert-title:var(--bh-content-danger-strong)] [--alert-description:var(--bh-content-danger-
|
|
26
|
+
"[--alert-bg:var(--bh-bg-danger-subtle)] [--alert-border:var(--bh-border-danger-subtle)] [--alert-title:var(--bh-content-danger-strong)] [--alert-description:var(--bh-content-danger-strong)] [--alert-icon:var(--bh-content-danger-default)]",
|
|
26
27
|
success:
|
|
27
|
-
"[--alert-bg:var(--bh-bg-success-subtle)] [--alert-border:var(--bh-border-success-subtle)] [--alert-title:var(--bh-content-success-strong)] [--alert-description:var(--bh-content-success-
|
|
28
|
+
"[--alert-bg:var(--bh-bg-success-subtle)] [--alert-border:var(--bh-border-success-subtle)] [--alert-title:var(--bh-content-success-strong)] [--alert-description:var(--bh-content-success-strong)] [--alert-icon:var(--bh-content-success-default)]",
|
|
28
29
|
warning:
|
|
29
|
-
"[--alert-bg:var(--bh-bg-warning-subtle)] [--alert-border:var(--bh-border-warning-subtle)] [--alert-title:var(--bh-content-warning-strong)] [--alert-description:var(--bh-content-warning-
|
|
30
|
+
"[--alert-bg:var(--bh-bg-warning-subtle)] [--alert-border:var(--bh-border-warning-subtle)] [--alert-title:var(--bh-content-warning-strong)] [--alert-description:var(--bh-content-warning-strong)] [--alert-icon:var(--bh-content-warning-default)]",
|
|
30
31
|
info:
|
|
31
|
-
"[--alert-bg:var(--bh-bg-info-subtle)] [--alert-border:var(--bh-border-info-subtle)] [--alert-title:var(--bh-content-brand-strong)] [--alert-description:var(--bh-content-brand-
|
|
32
|
+
"[--alert-bg:var(--bh-bg-info-subtle)] [--alert-border:var(--bh-border-info-subtle)] [--alert-title:var(--bh-content-brand-strong)] [--alert-description:var(--bh-content-brand-strong)] [--alert-icon:var(--bh-content-brand-default)]",
|
|
32
33
|
neutral:
|
|
33
34
|
"[--alert-bg:var(--bh-bg-neutral-subtle)] [--alert-border:var(--bh-border-subtle)] [--alert-title:var(--bh-content-default)] [--alert-description:var(--bh-content-default)] [--alert-icon:var(--bh-content-default)]",
|
|
34
35
|
},
|
|
@@ -158,7 +159,7 @@ const Alert = React.forwardRef<HTMLElement, AlertProps>(function Alert(
|
|
|
158
159
|
>
|
|
159
160
|
<span
|
|
160
161
|
data-slot="alert-icon"
|
|
161
|
-
className="inline-flex size-[var(--bh-alert-icon-size)] shrink-0 items-center justify-center text-[var(--alert-icon)]"
|
|
162
|
+
className="inline-flex size-[var(--bh-alert-icon-slot-size)] shrink-0 items-center justify-center text-[var(--alert-icon)]"
|
|
162
163
|
>
|
|
163
164
|
<AlertStatusIcon status={resolvedStatus} />
|
|
164
165
|
</span>
|
|
@@ -194,7 +195,7 @@ const Alert = React.forwardRef<HTMLElement, AlertProps>(function Alert(
|
|
|
194
195
|
<p
|
|
195
196
|
data-slot="alert-description"
|
|
196
197
|
dir="auto"
|
|
197
|
-
className="m-0 w-full break-words text-[length:var(--bh-text-body-sm-regular-font-size)] font-[var(--bh-font-weight-regular)] leading-[var(--bh-text-body-sm-regular-line-height)] tracking-[var(--bh-text-body-sm-regular-letter-spacing)] text-[var(--alert-description)]
|
|
198
|
+
className="m-0 w-full break-words text-[length:var(--bh-text-body-sm-regular-font-size)] font-[var(--bh-font-weight-regular)] leading-[var(--bh-text-body-sm-regular-line-height)] tracking-[var(--bh-text-body-sm-regular-letter-spacing)] text-[var(--alert-description)]"
|
|
198
199
|
>
|
|
199
200
|
{description}
|
|
200
201
|
</p>
|
|
@@ -212,15 +213,17 @@ const Alert = React.forwardRef<HTMLElement, AlertProps>(function Alert(
|
|
|
212
213
|
)}
|
|
213
214
|
|
|
214
215
|
{visibleCloseButton && (
|
|
215
|
-
<
|
|
216
|
+
<Button
|
|
216
217
|
data-slot="alert-close"
|
|
217
218
|
aria-label={resolvedCloseLabel}
|
|
218
|
-
className="
|
|
219
|
+
className="size-[var(--bh-alert-icon-slot-size)] shrink-0 rounded-[var(--bh-radius-full)] p-0 text-[var(--bh-content-subtle)]"
|
|
219
220
|
onClick={onClose}
|
|
221
|
+
size="icon-xs"
|
|
220
222
|
type="button"
|
|
223
|
+
variant="ghost"
|
|
221
224
|
>
|
|
222
225
|
<CloseIcon />
|
|
223
|
-
</
|
|
226
|
+
</Button>
|
|
224
227
|
)}
|
|
225
228
|
</section>
|
|
226
229
|
)
|
|
@@ -237,15 +240,16 @@ function AlertActions({
|
|
|
237
240
|
className="flex shrink-0 items-center gap-[var(--bh-space-3xl-16)]"
|
|
238
241
|
>
|
|
239
242
|
{actions.map((action, index) => (
|
|
240
|
-
<
|
|
243
|
+
<Button
|
|
241
244
|
data-slot="alert-action"
|
|
242
|
-
className="
|
|
245
|
+
className="h-auto shrink-0 gap-[var(--bh-space-xxs-2)] p-0 text-start text-[length:var(--bh-text-body-md-underline-font-size)] font-[var(--bh-text-body-md-underline-font-weight)] leading-[var(--bh-text-body-md-underline-line-height)] tracking-[var(--bh-text-body-md-underline-letter-spacing)] text-[var(--bh-content-default)] underline [text-underline-position:from-font]"
|
|
243
246
|
key={index}
|
|
244
247
|
onClick={action.onClick}
|
|
245
248
|
type="button"
|
|
249
|
+
variant="ghost"
|
|
246
250
|
>
|
|
247
251
|
{action.label}
|
|
248
|
-
</
|
|
252
|
+
</Button>
|
|
249
253
|
))}
|
|
250
254
|
</div>
|
|
251
255
|
)
|
|
@@ -273,7 +277,7 @@ function AlertStatusIcon({ status }: { status: AlertStatus }) {
|
|
|
273
277
|
|
|
274
278
|
function CloseIcon() {
|
|
275
279
|
return (
|
|
276
|
-
<XIcon aria-hidden="true" className="size-[var(--bh-
|
|
280
|
+
<XIcon aria-hidden="true" className="size-[var(--bh-space-3xl-16)]" strokeWidth="var(--bh-icon-stroke-225)" />
|
|
277
281
|
)
|
|
278
282
|
}
|
|
279
283
|
|
|
@@ -208,9 +208,15 @@ const AttributeHeader = React.forwardRef<HTMLElement, AttributeHeaderProps>(
|
|
|
208
208
|
{icon ? (
|
|
209
209
|
<span
|
|
210
210
|
data-slot="attribute-header-icon"
|
|
211
|
-
className="grid size-[var(--bh-attribute-header-icon-size)] place-items-center rounded-[var(--bh-radius-full)] bg-[var(--bh-bg-neutral-soft)] text-[var(--bh-content-subtle)] sm:size-[var(--bh-attribute-header-icon-size-lg)]
|
|
211
|
+
className="grid size-[var(--bh-attribute-header-icon-size)] place-items-center rounded-[var(--bh-radius-full)] bg-[var(--bh-bg-neutral-soft)] text-[var(--bh-content-subtle)] sm:size-[var(--bh-attribute-header-icon-size-lg)]"
|
|
212
212
|
>
|
|
213
|
-
|
|
213
|
+
<span
|
|
214
|
+
aria-hidden="true"
|
|
215
|
+
data-slot="attribute-header-icon-slot"
|
|
216
|
+
className="grid size-[var(--bh-icon-slot-size-default)] place-items-center [&_svg]:size-[var(--bh-icon-size-default)] sm:size-[var(--bh-space-5xl-24)] sm:[&_svg]:size-[var(--bh-space-5xl-24)]"
|
|
217
|
+
>
|
|
218
|
+
{icon}
|
|
219
|
+
</span>
|
|
214
220
|
</span>
|
|
215
221
|
) : null}
|
|
216
222
|
<span
|
|
@@ -16,20 +16,20 @@ import { cn } from "@/lib/utils"
|
|
|
16
16
|
|
|
17
17
|
const avatarSizeVariants = {
|
|
18
18
|
"2xs":
|
|
19
|
-
"[--bh-avatar-size:var(--bh-avatar-size-2xs)] [--bh-avatar-fallback-size:var(--bh-avatar-fallback-font-size-2xs)] [--bh-avatar-icon-size:var(--bh-avatar-icon-size-2xs)]",
|
|
20
|
-
xs: "[--bh-avatar-size:var(--bh-avatar-size-xs)] [--bh-avatar-fallback-size:var(--bh-avatar-fallback-font-size-xs)] [--bh-avatar-icon-size:var(--bh-avatar-icon-size-xs)]",
|
|
21
|
-
sm: "[--bh-avatar-size:var(--bh-avatar-size-sm)] [--bh-avatar-fallback-size:var(--bh-avatar-fallback-font-size-sm)] [--bh-avatar-icon-size:var(--bh-avatar-icon-size-sm)]",
|
|
22
|
-
md: "[--bh-avatar-size:var(--bh-avatar-size-md)] [--bh-avatar-fallback-size:var(--bh-avatar-fallback-font-size-md)] [--bh-avatar-icon-size:var(--bh-avatar-icon-size-md)]",
|
|
23
|
-
lg: "[--bh-avatar-size:var(--bh-avatar-size-lg)] [--bh-avatar-fallback-size:var(--bh-avatar-fallback-font-size-lg)] [--bh-avatar-icon-size:var(--bh-avatar-icon-size-lg)]",
|
|
19
|
+
"[--bh-avatar-size:var(--bh-avatar-size-2xs)] [--bh-avatar-fallback-size:var(--bh-avatar-fallback-font-size-2xs)] [--bh-avatar-icon-size:var(--bh-avatar-icon-size-2xs)] [--bh-avatar-icon-slot-size:var(--bh-avatar-icon-size)]",
|
|
20
|
+
xs: "[--bh-avatar-size:var(--bh-avatar-size-xs)] [--bh-avatar-fallback-size:var(--bh-avatar-fallback-font-size-xs)] [--bh-avatar-icon-size:var(--bh-avatar-icon-size-xs)] [--bh-avatar-icon-slot-size:var(--bh-avatar-icon-size)]",
|
|
21
|
+
sm: "[--bh-avatar-size:var(--bh-avatar-size-sm)] [--bh-avatar-fallback-size:var(--bh-avatar-fallback-font-size-sm)] [--bh-avatar-icon-size:var(--bh-avatar-icon-size-sm)] [--bh-avatar-icon-slot-size:var(--bh-avatar-icon-size)]",
|
|
22
|
+
md: "[--bh-avatar-size:var(--bh-avatar-size-md)] [--bh-avatar-fallback-size:var(--bh-avatar-fallback-font-size-md)] [--bh-avatar-icon-size:var(--bh-avatar-icon-size-md)] [--bh-avatar-icon-slot-size:var(--bh-icon-slot-size-default)]",
|
|
23
|
+
lg: "[--bh-avatar-size:var(--bh-avatar-size-lg)] [--bh-avatar-fallback-size:var(--bh-avatar-fallback-font-size-lg)] [--bh-avatar-icon-size:var(--bh-avatar-icon-size-lg)] [--bh-avatar-icon-slot-size:var(--bh-icon-slot-size-default)]",
|
|
24
24
|
default:
|
|
25
|
-
"[--bh-avatar-size:var(--bh-avatar-size-xl)] [--bh-avatar-fallback-size:var(--bh-avatar-fallback-font-size-xl)] [--bh-avatar-icon-size:var(--bh-avatar-icon-size-xl)]",
|
|
26
|
-
xl: "[--bh-avatar-size:var(--bh-avatar-size-xl)] [--bh-avatar-fallback-size:var(--bh-avatar-fallback-font-size-xl)] [--bh-avatar-icon-size:var(--bh-avatar-icon-size-xl)]",
|
|
25
|
+
"[--bh-avatar-size:var(--bh-avatar-size-xl)] [--bh-avatar-fallback-size:var(--bh-avatar-fallback-font-size-xl)] [--bh-avatar-icon-size:var(--bh-avatar-icon-size-xl)] [--bh-avatar-icon-slot-size:var(--bh-avatar-icon-size)]",
|
|
26
|
+
xl: "[--bh-avatar-size:var(--bh-avatar-size-xl)] [--bh-avatar-fallback-size:var(--bh-avatar-fallback-font-size-xl)] [--bh-avatar-icon-size:var(--bh-avatar-icon-size-xl)] [--bh-avatar-icon-slot-size:var(--bh-avatar-icon-size)]",
|
|
27
27
|
"2xl":
|
|
28
|
-
"[--bh-avatar-size:var(--bh-avatar-size-2xl)] [--bh-avatar-fallback-size:var(--bh-avatar-fallback-font-size-2xl)] [--bh-avatar-icon-size:var(--bh-avatar-icon-size-2xl)]",
|
|
28
|
+
"[--bh-avatar-size:var(--bh-avatar-size-2xl)] [--bh-avatar-fallback-size:var(--bh-avatar-fallback-font-size-2xl)] [--bh-avatar-icon-size:var(--bh-avatar-icon-size-2xl)] [--bh-avatar-icon-slot-size:var(--bh-avatar-icon-size)]",
|
|
29
29
|
"3xl":
|
|
30
|
-
"[--bh-avatar-size:var(--bh-avatar-size-3xl)] [--bh-avatar-fallback-size:var(--bh-avatar-fallback-font-size-3xl)] [--bh-avatar-icon-size:var(--bh-avatar-icon-size-3xl)]",
|
|
30
|
+
"[--bh-avatar-size:var(--bh-avatar-size-3xl)] [--bh-avatar-fallback-size:var(--bh-avatar-fallback-font-size-3xl)] [--bh-avatar-icon-size:var(--bh-avatar-icon-size-3xl)] [--bh-avatar-icon-slot-size:var(--bh-avatar-icon-size)]",
|
|
31
31
|
"4xl":
|
|
32
|
-
"[--bh-avatar-size:var(--bh-avatar-size-4xl)] [--bh-avatar-fallback-size:var(--bh-avatar-fallback-font-size-4xl)] [--bh-avatar-icon-size:var(--bh-avatar-icon-size-4xl)]",
|
|
32
|
+
"[--bh-avatar-size:var(--bh-avatar-size-4xl)] [--bh-avatar-fallback-size:var(--bh-avatar-fallback-font-size-4xl)] [--bh-avatar-icon-size:var(--bh-avatar-icon-size-4xl)] [--bh-avatar-icon-slot-size:var(--bh-avatar-icon-size)]",
|
|
33
33
|
} as const
|
|
34
34
|
|
|
35
35
|
const avatarVariants = cva(
|
|
@@ -50,7 +50,7 @@ const avatarVariants = cva(
|
|
|
50
50
|
)
|
|
51
51
|
|
|
52
52
|
const avatarFallbackVariants = cva(
|
|
53
|
-
"flex size-full items-center justify-center rounded-[var(--bh-avatar-radius,var(--bh-radius-full))] bg-[var(--bh-bg-neutral-subtle)] text-[length:var(--bh-avatar-fallback-size,var(--bh-text-body-sm-medium-font-size))] font-[var(--bh-font-weight-semibold)] leading-none text-[var(--bh-content-
|
|
53
|
+
"flex size-full items-center justify-center rounded-[var(--bh-avatar-radius,var(--bh-radius-full))] bg-[var(--bh-bg-neutral-subtle)] text-[length:var(--bh-avatar-fallback-size,var(--bh-text-body-sm-medium-font-size))] font-[var(--bh-font-weight-semibold)] leading-none text-[var(--bh-content-default)] whitespace-nowrap",
|
|
54
54
|
{
|
|
55
55
|
variants: {
|
|
56
56
|
size: avatarSizeVariants,
|
|
@@ -62,7 +62,7 @@ const avatarFallbackVariants = cva(
|
|
|
62
62
|
)
|
|
63
63
|
|
|
64
64
|
const avatarIconVariants = cva(
|
|
65
|
-
"flex size-full items-center justify-center rounded-[var(--bh-avatar-radius,var(--bh-radius-full))] bg-[var(--bh-bg-neutral-subtle)] text-[var(--bh-content-
|
|
65
|
+
"flex size-full items-center justify-center rounded-[var(--bh-avatar-radius,var(--bh-radius-full))] bg-[var(--bh-bg-neutral-subtle)] text-[var(--bh-content-default)]",
|
|
66
66
|
{
|
|
67
67
|
variants: {
|
|
68
68
|
size: avatarSizeVariants,
|
|
@@ -147,7 +147,9 @@ const avatarActionVariants = cva(
|
|
|
147
147
|
)
|
|
148
148
|
|
|
149
149
|
function Avatar({
|
|
150
|
+
"aria-label": ariaLabel,
|
|
150
151
|
className,
|
|
152
|
+
role,
|
|
151
153
|
size,
|
|
152
154
|
shape,
|
|
153
155
|
...props
|
|
@@ -155,9 +157,11 @@ function Avatar({
|
|
|
155
157
|
VariantProps<typeof avatarVariants>) {
|
|
156
158
|
return (
|
|
157
159
|
<AvatarPrimitive.Root
|
|
160
|
+
aria-label={ariaLabel}
|
|
158
161
|
data-slot="avatar"
|
|
159
162
|
data-size={size ?? "default"}
|
|
160
163
|
data-shape={shape ?? "circular"}
|
|
164
|
+
role={role ?? (ariaLabel ? "img" : undefined)}
|
|
161
165
|
className={cn(avatarVariants({ size, shape, className }))}
|
|
162
166
|
{...props}
|
|
163
167
|
/>
|
|
@@ -208,13 +212,17 @@ function AvatarIcon({
|
|
|
208
212
|
className={cn(avatarIconVariants({ size, className }))}
|
|
209
213
|
{...props}
|
|
210
214
|
>
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
215
|
+
<span
|
|
216
|
+
data-slot="avatar-icon-slot"
|
|
217
|
+
className="flex size-[var(--bh-avatar-icon-slot-size,var(--bh-avatar-icon-size))] shrink-0 items-center justify-center [&_svg]:size-[var(--bh-avatar-icon-size)]"
|
|
218
|
+
>
|
|
219
|
+
{children ?? (
|
|
220
|
+
<UserIcon
|
|
221
|
+
aria-hidden="true"
|
|
222
|
+
strokeWidth="var(--bh-icon-stroke-210)"
|
|
223
|
+
/>
|
|
224
|
+
)}
|
|
225
|
+
</span>
|
|
218
226
|
</span>
|
|
219
227
|
)
|
|
220
228
|
}
|
|
@@ -307,7 +315,7 @@ function AvatarGroupCount({
|
|
|
307
315
|
data-slot="avatar-group-count"
|
|
308
316
|
className={cn(
|
|
309
317
|
avatarVariants({ size }),
|
|
310
|
-
"-ms-[var(--bh-space-md-8)] bg-[var(--bh-bg-neutral-subtle)] text-[length:var(--bh-avatar-fallback-size,var(--bh-text-body-sm-medium-font-size))] font-[var(--bh-font-weight-semibold)] leading-none text-[var(--bh-content-
|
|
318
|
+
"-ms-[var(--bh-space-md-8)] bg-[var(--bh-bg-neutral-subtle)] text-[length:var(--bh-avatar-fallback-size,var(--bh-text-body-sm-medium-font-size))] font-[var(--bh-font-weight-semibold)] leading-none text-[var(--bh-content-default)] ring-[var(--bh-space-xxs-2)] ring-[var(--bh-bg-default)]",
|
|
311
319
|
className
|
|
312
320
|
)}
|
|
313
321
|
{...props}
|
|
@@ -192,13 +192,13 @@ const badgeVariants = cva(
|
|
|
192
192
|
badgeStyle: "outline",
|
|
193
193
|
color: "neutral",
|
|
194
194
|
class:
|
|
195
|
-
"border-[var(--bh-border-strong)] text-[var(--bh-content-
|
|
195
|
+
"border-[var(--bh-border-strong)] text-[var(--bh-content-default)] [--badge-dot-color:var(--bh-content-default)] [--badge-split-border-color:var(--bh-border-default)]",
|
|
196
196
|
},
|
|
197
197
|
{
|
|
198
198
|
badgeStyle: "solid",
|
|
199
199
|
color: "neutral",
|
|
200
200
|
class:
|
|
201
|
-
"bg-[var(--bh-bg-neutral-
|
|
201
|
+
"bg-[var(--bh-bg-neutral-bold)] text-[var(--bh-content-on-neutral)] [--badge-dot-color:var(--bh-content-on-neutral)] [--badge-split-border-color:var(--bh-border-subtle)]",
|
|
202
202
|
},
|
|
203
203
|
{
|
|
204
204
|
badgeStyle: "light",
|
|
@@ -210,13 +210,13 @@ const badgeVariants = cva(
|
|
|
210
210
|
badgeStyle: "outline",
|
|
211
211
|
color: "blue",
|
|
212
212
|
class:
|
|
213
|
-
"border-[var(--bh-border-accent-blue-strong)] text-[var(--bh-content-accent-blue-
|
|
213
|
+
"border-[var(--bh-border-accent-blue-strong)] text-[var(--bh-content-accent-blue-strong)] [--badge-dot-color:var(--bh-content-accent-blue-strong)] [--badge-split-border-color:var(--bh-border-accent-blue-subtle)]",
|
|
214
214
|
},
|
|
215
215
|
{
|
|
216
216
|
badgeStyle: "solid",
|
|
217
217
|
color: "blue",
|
|
218
218
|
class:
|
|
219
|
-
"bg-[var(--bh-bg-accent-blue-
|
|
219
|
+
"bg-[var(--bh-bg-accent-blue-bold)] text-[var(--bh-content-on-color)] [--badge-dot-color:var(--bh-content-on-color)] [--badge-split-border-color:var(--bh-border-accent-blue-subtle)]",
|
|
220
220
|
},
|
|
221
221
|
{
|
|
222
222
|
badgeStyle: "light",
|
|
@@ -228,13 +228,13 @@ const badgeVariants = cva(
|
|
|
228
228
|
badgeStyle: "outline",
|
|
229
229
|
color: "green",
|
|
230
230
|
class:
|
|
231
|
-
"border-[var(--bh-border-accent-green-strong)] text-[var(--bh-content-accent-green-
|
|
231
|
+
"border-[var(--bh-border-accent-green-strong)] text-[var(--bh-content-accent-green-strong)] [--badge-dot-color:var(--bh-content-accent-green-strong)] [--badge-split-border-color:var(--bh-border-accent-green-subtle)]",
|
|
232
232
|
},
|
|
233
233
|
{
|
|
234
234
|
badgeStyle: "solid",
|
|
235
235
|
color: "green",
|
|
236
236
|
class:
|
|
237
|
-
"bg-[var(--bh-bg-accent-green-default)] text-[var(--bh-content-on-
|
|
237
|
+
"bg-[var(--bh-bg-accent-green-default)] text-[var(--bh-content-on-light)] [--badge-dot-color:var(--bh-content-on-light)] [--badge-split-border-color:var(--bh-border-accent-green-subtle)]",
|
|
238
238
|
},
|
|
239
239
|
{
|
|
240
240
|
badgeStyle: "light",
|
|
@@ -246,13 +246,13 @@ const badgeVariants = cva(
|
|
|
246
246
|
badgeStyle: "outline",
|
|
247
247
|
color: "amber",
|
|
248
248
|
class:
|
|
249
|
-
"border-[var(--bh-border-accent-amber-strong)] text-[var(--bh-content-accent-amber-
|
|
249
|
+
"border-[var(--bh-border-accent-amber-strong)] text-[var(--bh-content-accent-amber-strong)] [--badge-dot-color:var(--bh-content-accent-amber-strong)] [--badge-split-border-color:var(--bh-border-accent-amber-subtle)]",
|
|
250
250
|
},
|
|
251
251
|
{
|
|
252
252
|
badgeStyle: "solid",
|
|
253
253
|
color: "amber",
|
|
254
254
|
class:
|
|
255
|
-
"bg-[var(--bh-bg-accent-amber-default)] text-[var(--bh-content-on-
|
|
255
|
+
"bg-[var(--bh-bg-accent-amber-default)] text-[var(--bh-content-on-light)] [--badge-dot-color:var(--bh-content-on-light)] [--badge-split-border-color:var(--bh-border-accent-amber-subtle)]",
|
|
256
256
|
},
|
|
257
257
|
{
|
|
258
258
|
badgeStyle: "light",
|
|
@@ -264,7 +264,7 @@ const badgeVariants = cva(
|
|
|
264
264
|
badgeStyle: "outline",
|
|
265
265
|
color: "danger",
|
|
266
266
|
class:
|
|
267
|
-
"border-[var(--bh-border-accent-red-strong)] text-[var(--bh-content-accent-red-
|
|
267
|
+
"border-[var(--bh-border-accent-red-strong)] text-[var(--bh-content-accent-red-strong)] [--badge-dot-color:var(--bh-content-accent-red-strong)] [--badge-split-border-color:var(--bh-border-accent-red-subtle)]",
|
|
268
268
|
},
|
|
269
269
|
{
|
|
270
270
|
badgeStyle: "solid",
|
|
@@ -282,7 +282,7 @@ const badgeVariants = cva(
|
|
|
282
282
|
badgeStyle: "outline",
|
|
283
283
|
color: "purple",
|
|
284
284
|
class:
|
|
285
|
-
"border-[var(--bh-border-accent-purple-strong)] text-[var(--bh-content-accent-purple-
|
|
285
|
+
"border-[var(--bh-border-accent-purple-strong)] text-[var(--bh-content-accent-purple-strong)] [--badge-dot-color:var(--bh-content-accent-purple-strong)] [--badge-split-border-color:var(--bh-border-accent-purple-subtle)]",
|
|
286
286
|
},
|
|
287
287
|
{
|
|
288
288
|
badgeStyle: "solid",
|
|
@@ -300,13 +300,13 @@ const badgeVariants = cva(
|
|
|
300
300
|
badgeStyle: "outline",
|
|
301
301
|
color: "fuchsia",
|
|
302
302
|
class:
|
|
303
|
-
"border-[var(--bh-border-accent-fuchsia-strong)] text-[var(--bh-content-accent-fuchsia-
|
|
303
|
+
"border-[var(--bh-border-accent-fuchsia-strong)] text-[var(--bh-content-accent-fuchsia-strong)] [--badge-dot-color:var(--bh-content-accent-fuchsia-strong)] [--badge-split-border-color:var(--bh-border-accent-fuchsia-subtle)]",
|
|
304
304
|
},
|
|
305
305
|
{
|
|
306
306
|
badgeStyle: "solid",
|
|
307
307
|
color: "fuchsia",
|
|
308
308
|
class:
|
|
309
|
-
"bg-[var(--bh-bg-accent-fuchsia-default)] text-[var(--bh-content-on-
|
|
309
|
+
"bg-[var(--bh-bg-accent-fuchsia-default)] text-[var(--bh-content-on-light)] [--badge-dot-color:var(--bh-content-on-light)] [--badge-split-border-color:var(--bh-border-accent-fuchsia-subtle)]",
|
|
310
310
|
},
|
|
311
311
|
{
|
|
312
312
|
badgeStyle: "light",
|
|
@@ -318,13 +318,13 @@ const badgeVariants = cva(
|
|
|
318
318
|
badgeStyle: "outline",
|
|
319
319
|
color: "rose",
|
|
320
320
|
class:
|
|
321
|
-
"border-[var(--bh-border-accent-rose-strong)] text-[var(--bh-content-accent-rose-
|
|
321
|
+
"border-[var(--bh-border-accent-rose-strong)] text-[var(--bh-content-accent-rose-strong)] [--badge-dot-color:var(--bh-content-accent-rose-strong)] [--badge-split-border-color:var(--bh-border-accent-rose-subtle)]",
|
|
322
322
|
},
|
|
323
323
|
{
|
|
324
324
|
badgeStyle: "solid",
|
|
325
325
|
color: "rose",
|
|
326
326
|
class:
|
|
327
|
-
"bg-[var(--bh-bg-accent-rose-
|
|
327
|
+
"bg-[var(--bh-bg-accent-rose-bold)] text-[var(--bh-content-on-color)] [--badge-dot-color:var(--bh-content-on-color)] [--badge-split-border-color:var(--bh-border-accent-rose-subtle)]",
|
|
328
328
|
},
|
|
329
329
|
{
|
|
330
330
|
badgeStyle: "light",
|
|
@@ -336,13 +336,13 @@ const badgeVariants = cva(
|
|
|
336
336
|
badgeStyle: "outline",
|
|
337
337
|
color: "sky",
|
|
338
338
|
class:
|
|
339
|
-
"border-[var(--bh-border-accent-sky-strong)] text-[var(--bh-content-accent-sky-
|
|
339
|
+
"border-[var(--bh-border-accent-sky-strong)] text-[var(--bh-content-accent-sky-strong)] [--badge-dot-color:var(--bh-content-accent-sky-strong)] [--badge-split-border-color:var(--bh-border-accent-sky-subtle)]",
|
|
340
340
|
},
|
|
341
341
|
{
|
|
342
342
|
badgeStyle: "solid",
|
|
343
343
|
color: "sky",
|
|
344
344
|
class:
|
|
345
|
-
"bg-[var(--bh-bg-accent-sky-base)] text-[var(--bh-content-on-
|
|
345
|
+
"bg-[var(--bh-bg-accent-sky-base)] text-[var(--bh-content-on-light)] [--badge-dot-color:var(--bh-content-on-light)] [--badge-split-border-color:var(--bh-border-accent-sky-subtle)]",
|
|
346
346
|
},
|
|
347
347
|
{
|
|
348
348
|
badgeStyle: "light",
|
|
@@ -354,7 +354,7 @@ const badgeVariants = cva(
|
|
|
354
354
|
badgeStyle: "outline",
|
|
355
355
|
color: "golden",
|
|
356
356
|
class:
|
|
357
|
-
"border-[var(--bh-border-accent-golden-strong)] text-[var(--bh-content-accent-golden-
|
|
357
|
+
"border-[var(--bh-border-accent-golden-strong)] text-[var(--bh-content-accent-golden-strong)] [--badge-dot-color:var(--bh-content-accent-golden-strong)] [--badge-split-border-color:var(--bh-border-accent-golden-subtle)]",
|
|
358
358
|
},
|
|
359
359
|
{
|
|
360
360
|
badgeStyle: "solid",
|
|
@@ -32,7 +32,7 @@ type ToggleGroupContextValue = {
|
|
|
32
32
|
const toggleGroupContext = React.createContext<ToggleGroupContextValue | null>(null)
|
|
33
33
|
|
|
34
34
|
const buttonGroupVariants = cva(
|
|
35
|
-
"inline-flex w-fit items-center overflow-hidden rounded-[var(--bh-button-group-radius)] bg-[var(--bh-button-group-bg)] text-[var(--bh-button-group-content)] shadow-[var(--shadow-button-group)] [--shadow-button-group:inset_0px_0px_0px_var(--bh-border-width-default)_var(--bh-button-group-border),var(--shadow-component-default)]",
|
|
35
|
+
"inline-flex w-fit max-w-full items-center overflow-x-auto overflow-y-hidden rounded-[var(--bh-button-group-radius)] bg-[var(--bh-button-group-bg)] text-[var(--bh-button-group-content)] shadow-[var(--shadow-button-group)] outline-none focus-visible:shadow-[var(--shadow-button-group-focus)] [--shadow-button-group:inset_0px_0px_0px_var(--bh-border-width-default)_var(--bh-button-group-border),var(--shadow-component-default)]",
|
|
36
36
|
{
|
|
37
37
|
variants: {
|
|
38
38
|
size: {
|
|
@@ -48,7 +48,7 @@ const buttonGroupVariants = cva(
|
|
|
48
48
|
)
|
|
49
49
|
|
|
50
50
|
const buttonGroupItemVariants = cva(
|
|
51
|
-
"relative inline-flex shrink-0 items-center justify-center whitespace-nowrap bg-[var(--bh-button-group-item-bg)] text-[length:var(--bh-text-button-font-size)] font-[var(--bh-text-button-font-weight)] leading-[var(--bh-text-button-line-height)] tracking-[var(--bh-text-button-letter-spacing)] text-[var(--bh-button-group-content)] outline-none transition-[background-color,box-shadow,color] before:absolute before:inset-y-0 before:start-0 before:w-[var(--bh-border-width-default)] before:bg-[var(--bh-button-group-divider)] before:content-[''] first:before:hidden hover:bg-[var(--bh-button-group-item-hover-bg)] active:bg-[var(--bh-button-group-item-pressed-bg)] focus-visible:z-[var(--bh-z-raised)] focus-visible:shadow-[var(--shadow-button-group-focus)] aria-[pressed=true]:bg-[var(--bh-button-group-item-active-bg)] aria-[pressed=true]:text-[var(--bh-button-group-content-active)] data-[active=true]:bg-[var(--bh-button-group-item-active-bg)] data-[active=true]:text-[var(--bh-button-group-content-active)] disabled:pointer-events-none disabled:bg-[var(--bh-button-group-item-disabled-bg)] disabled:text-[var(--bh-button-group-content-disabled)] [&_svg]:pointer-events-none [&_svg]:size-[var(--bh-button-group-icon-size)] [&_svg]:shrink-0 rtl:[&_svg[data-rtl-flip='true']]:-scale-x-100",
|
|
51
|
+
"relative inline-flex shrink-0 items-center justify-center whitespace-nowrap bg-[var(--bh-button-group-item-bg)] text-[length:var(--bh-text-button-font-size)] font-[var(--bh-text-button-font-weight)] leading-[var(--bh-text-button-line-height)] tracking-[var(--bh-text-button-letter-spacing)] text-[var(--bh-button-group-content)] outline-none transition-[background-color,box-shadow,color] before:absolute before:inset-y-0 before:start-0 before:w-[var(--bh-border-width-default)] before:bg-[var(--bh-button-group-divider)] before:content-[''] first:before:hidden hover:bg-[var(--bh-button-group-item-hover-bg)] active:bg-[var(--bh-button-group-item-pressed-bg)] focus-visible:z-[var(--bh-z-raised)] focus-visible:shadow-[var(--shadow-button-group-focus)] aria-[pressed=true]:bg-[var(--bh-button-group-item-active-bg)] aria-[pressed=true]:text-[var(--bh-button-group-content-active)] data-[active=true]:bg-[var(--bh-button-group-item-active-bg)] data-[active=true]:text-[var(--bh-button-group-content-active)] disabled:pointer-events-none disabled:bg-[var(--bh-button-group-item-disabled-bg)] disabled:text-[var(--bh-button-group-content-disabled)] [&_svg]:pointer-events-none [&_svg]:size-[var(--bh-button-group-icon-size)] [&_svg]:m-[calc((var(--bh-button-group-icon-slot-size)-var(--bh-button-group-icon-size))/2)] [&_svg]:shrink-0 rtl:[&_svg[data-rtl-flip='true']]:-scale-x-100",
|
|
52
52
|
{
|
|
53
53
|
variants: {
|
|
54
54
|
size: {
|
|
@@ -200,6 +200,7 @@ const ButtonGroup = React.forwardRef<HTMLDivElement, ButtonGroupProps>(function
|
|
|
200
200
|
mode = "default",
|
|
201
201
|
children,
|
|
202
202
|
role = "group",
|
|
203
|
+
tabIndex = 0,
|
|
203
204
|
...props
|
|
204
205
|
}, ref) {
|
|
205
206
|
const resolvedSize = resolveButtonGroupSize(density, size)
|
|
@@ -222,6 +223,7 @@ const ButtonGroup = React.forwardRef<HTMLDivElement, ButtonGroupProps>(function
|
|
|
222
223
|
data-slot="button-group"
|
|
223
224
|
ref={ref}
|
|
224
225
|
role={role}
|
|
226
|
+
tabIndex={tabIndex}
|
|
225
227
|
className={cn(buttonGroupVariants({ size: contextValue.size }), className)}
|
|
226
228
|
{...props}
|
|
227
229
|
>
|
|
@@ -7,7 +7,7 @@ import { cn } from "@/lib/utils"
|
|
|
7
7
|
type ControlDensity = "compact" | "default" | "comfortable"
|
|
8
8
|
|
|
9
9
|
const buttonVariants = cva(
|
|
10
|
-
"group/button inline-flex min-w-0 items-center justify-center whitespace-nowrap rounded-[var(--bh-control-default)] text-[length:var(--bh-text-button-font-size)] font-[var(--bh-text-button-font-weight)] leading-[var(--bh-text-button-line-height)] tracking-[var(--bh-text-button-letter-spacing)] outline-none transition-[background-color,border-color,color,box-shadow] focus-visible:shadow-[var(--shadow-button-focus)] disabled:pointer-events-none disabled:shadow-none aria-invalid:border-[length:var(--bh-border-width-default)] aria-invalid:border-[var(--bh-border-danger-strong)] aria-invalid:shadow-[var(--shadow-button-danger-focus)] [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-[var(--bh-button-icon-size)] [&_svg[data-icon='inline-start']]:ms-[var(--bh-button-icon-offset)] [&_svg[data-icon='inline-end']]:me-[var(--bh-button-icon-offset)] rtl:[&_svg[data-rtl-flip='true']]:-scale-x-100",
|
|
10
|
+
"group/button inline-flex min-w-0 items-center justify-center whitespace-nowrap rounded-[var(--bh-control-default)] text-[length:var(--bh-text-button-font-size)] font-[var(--bh-text-button-font-weight)] leading-[var(--bh-text-button-line-height)] tracking-[var(--bh-text-button-letter-spacing)] outline-none transition-[background-color,border-color,color,box-shadow] focus-visible:shadow-[var(--shadow-button-focus)] disabled:pointer-events-none disabled:shadow-none aria-invalid:border-[length:var(--bh-border-width-default)] aria-invalid:border-[var(--bh-border-danger-strong)] aria-invalid:shadow-[var(--shadow-button-danger-focus)] [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-[var(--bh-button-icon-size)] [&_svg:not([class*='size-'])]:m-[calc((var(--bh-button-icon-slot-size)-var(--bh-button-icon-size))/2)] [&_svg[data-icon='inline-start']]:ms-[calc(var(--bh-button-icon-offset)+(var(--bh-button-icon-slot-size)-var(--bh-button-icon-size))/2)] [&_svg[data-icon='inline-end']]:me-[calc(var(--bh-button-icon-offset)+(var(--bh-button-icon-slot-size)-var(--bh-button-icon-size))/2)] rtl:[&_svg[data-rtl-flip='true']]:-scale-x-100",
|
|
11
11
|
{
|
|
12
12
|
variants: {
|
|
13
13
|
variant: {
|
|
@@ -18,9 +18,9 @@ const buttonVariants = cva(
|
|
|
18
18
|
destructive:
|
|
19
19
|
"bg-[var(--bh-interactive-danger-default)] text-[var(--bh-content-on-color)] shadow-[var(--shadow-button-raised)] hover:bg-[var(--bh-interactive-danger-hover)] active:bg-[var(--bh-interactive-danger-pressed)] focus-visible:shadow-[var(--shadow-button-danger-focus)] disabled:bg-[var(--bh-interactive-danger-disabled)] disabled:text-[var(--bh-content-disabled)]",
|
|
20
20
|
success:
|
|
21
|
-
"bg-[var(--bh-
|
|
21
|
+
"bg-[var(--bh-interactive-success-default)] text-[var(--bh-content-on-success)] shadow-[var(--shadow-button-raised)] hover:bg-[var(--bh-interactive-success-hover)] active:bg-[var(--bh-interactive-success-pressed)] disabled:bg-[var(--bh-interactive-brand-disabled)] disabled:text-[var(--bh-content-disabled)]",
|
|
22
22
|
warning:
|
|
23
|
-
"bg-[var(--bh-
|
|
23
|
+
"bg-[var(--bh-interactive-warning-default)] text-[var(--bh-content-on-warning)] shadow-[var(--shadow-button-raised)] hover:bg-[var(--bh-interactive-warning-hover)] active:bg-[var(--bh-interactive-warning-pressed)] disabled:bg-[var(--bh-interactive-brand-disabled)] disabled:text-[var(--bh-content-disabled)]",
|
|
24
24
|
secondary:
|
|
25
25
|
"bg-[var(--bh-interactive-secondary-default)] text-[var(--bh-content-default)] shadow-[var(--shadow-button-secondary)] [--bh-button-secondary-border:var(--bh-border-default)] hover:bg-[var(--bh-interactive-secondary-hover)] active:bg-[var(--bh-interactive-secondary-pressed)] focus-visible:[--bh-button-secondary-focus-border:var(--bh-border-brand-strong)] focus-visible:shadow-[var(--shadow-button-secondary-focus)] disabled:border-[length:var(--bh-border-width-default)] disabled:border-[var(--bh-border-disabled)] disabled:bg-[var(--bh-interactive-secondary-disabled)] disabled:text-[var(--bh-content-disabled)]",
|
|
26
26
|
soft:
|