banhaten 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/README.md +1 -1
- package/docs/design-system/component-implementation-ownership-audit.md +244 -0
- package/docs/design-system/component-quality-audit-2026-08-20.md +223 -0
- package/docs/design-system/component-showcase-consistency-report.md +2 -0
- package/docs/design-system/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 +2 -2
- package/docs/design-system/components/avatar.md +1 -1
- package/docs/design-system/components/badge.md +1 -1
- package/docs/design-system/components/banner.md +5 -1
- package/docs/design-system/components/breadcrumbs.md +3 -0
- package/docs/design-system/components/button-group.md +1 -0
- package/docs/design-system/components/button.md +1 -1
- 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 +1 -1
- package/docs/design-system/components/file-upload.md +4 -0
- 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 +1 -0
- package/docs/design-system/components/page-header.md +3 -1
- package/docs/design-system/components/pagination.md +1 -0
- package/docs/design-system/components/resizable.md +1 -1
- package/docs/design-system/components/scroll-area.md +7 -3
- package/docs/design-system/components/sidebar.md +3 -1
- 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 +1 -1
- 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 +18 -1
- package/docs/design-system/gap-promotion-report.md +1 -67
- package/docs/design-system/launch-comparison-shadcn.md +10 -10
- package/package.json +3 -2
- package/registry/components/alert-dialog.tsx +1 -1
- package/registry/components/alert.tsx +15 -11
- package/registry/components/avatar.tsx +7 -3
- package/registry/components/badge.tsx +17 -17
- package/registry/components/button-group.tsx +3 -1
- package/registry/components/button.tsx +2 -2
- 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 +67 -31
- 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 +0 -2
- 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 +21 -11
- package/registry/components/expanded/breadcrumbs.css +1 -1
- package/registry/components/expanded/fileUpload.css +1 -1
- package/registry/components/expanded/onboardingStepListItem.css +2 -2
- 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 +58 -67
- package/registry/components/expanded/timeline.css +17 -16
- package/registry/components/field.tsx +61 -8
- package/registry/components/menu.tsx +56 -6
- 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 +8 -6
- package/registry/components/progress-slider.tsx +1 -1
- package/registry/components/resizable.tsx +36 -2
- package/registry/components/scroll-area.tsx +30 -6
- package/registry/components/select.tsx +34 -11
- package/registry/components/sidebar.tsx +11 -5
- 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 +1 -1
- package/registry/components/toggle.tsx +2 -2
- package/registry/components/toolbar.tsx +5 -5
- package/registry/components/tooltip.tsx +1 -1
- package/registry/examples/avatar-demo.tsx +7 -4
- package/registry/examples/expanded/activity-heatmap-demo.tsx +29 -0
- package/registry/examples/expanded/breadcrumbs-demo.tsx +3 -3
- package/registry/examples/pagination-demo.tsx +5 -5
- package/registry/examples/sidebar-demo.tsx +4 -2
- package/registry/index.json +392 -33
- package/registry/styles/globals.css +68 -42
- package/registry.json +40 -3
- package/tokens/banhaten.tokens.json +165 -55
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
This file is generated from background scenario gap metadata. A candidate appears when the same normalized need occurs in at least three distinct backgrounds. Heuristics cover common shells, navigation, tables, steps, composers, timelines, assets, and elevation; use `promotionKey` on a gap when an explicit cross-background grouping is more accurate.
|
|
4
4
|
|
|
5
|
-
Scanned
|
|
5
|
+
Scanned 100 gaps across 38 backgrounds. Found 4 promotion candidates at the 3-background threshold.
|
|
6
6
|
|
|
7
7
|
## Application/workspace shell
|
|
8
8
|
|
|
@@ -58,46 +58,6 @@ Backgrounds: `ai-growth-marketing`, `ai-node-detail`, `bauhow-room-planning`, `c
|
|
|
58
58
|
| `shipment-list` | carrier brand mark (`shipment-carrier-brand-mark`) | icon asset | approximation |
|
|
59
59
|
| `sku-management` | product and assistant icon set (`sku-product-icons`) | icon asset | approximation |
|
|
60
60
|
|
|
61
|
-
## Sidebar navigation
|
|
62
|
-
|
|
63
|
-
Key: `sidebar-navigation` · 11 backgrounds
|
|
64
|
-
|
|
65
|
-
Backgrounds: `acme-finance-advisor`, `ai-growth-marketing`, `audit-log`, `bauhow-room-planning`, `data-source-browser`, `debt-payoff`, `marcohr-people`, `people-add-member`, `shipment-list`, `sku-management`, `stripe-demo-account`
|
|
66
|
-
|
|
67
|
-
| Background | Gap | Kind | Status |
|
|
68
|
-
| --- | --- | --- | --- |
|
|
69
|
-
| `acme-finance-advisor` | compact app sidebar navigation (`acme-sidebar-navigation`) | component | missing |
|
|
70
|
-
| `ai-growth-marketing` | report sidebar navigation (`report-sidebar-navigation`) | component | missing |
|
|
71
|
-
| `audit-log` | audit sidebar navigation (`audit-sidebar-navigation`) | component | missing |
|
|
72
|
-
| `bauhow-room-planning` | planning sidebar navigation (`room-planning-sidebar-navigation`) | component | missing |
|
|
73
|
-
| `data-source-browser` | sidebar navigation with pinned list (`sidebar-navigation-with-pinned-list`) | component | missing |
|
|
74
|
-
| `debt-payoff` | planning sidebar navigation (`planning-sidebar-navigation`) | component | missing |
|
|
75
|
-
| `marcohr-people` | HR sidebar navigation (`marcohr-sidebar-navigation`) | component | missing |
|
|
76
|
-
| `people-add-member` | HR sidebar navigation (`people-sidebar-navigation`) | component | missing |
|
|
77
|
-
| `shipment-list` | shipment sidebar navigation (`shipment-sidebar-navigation`) | component | missing |
|
|
78
|
-
| `sku-management` | cropped app sidebar navigation (`sku-sidebar-navigation`) | component | missing |
|
|
79
|
-
| `stripe-demo-account` | payments sidebar navigation (`payments-sidebar-navigation`) | component | missing |
|
|
80
|
-
|
|
81
|
-
## Data table pattern
|
|
82
|
-
|
|
83
|
-
Key: `data-table-pattern` · 10 backgrounds
|
|
84
|
-
|
|
85
|
-
Backgrounds: `audit-log`, `debt-payoff`, `inference-providers`, `marcohr-people`, `people-add-member`, `recent-orders`, `school-assignments`, `share-of-voice`, `sku-management`, `stripe-demo-account`
|
|
86
|
-
|
|
87
|
-
| Background | Gap | Kind | Status |
|
|
88
|
-
| --- | --- | --- | --- |
|
|
89
|
-
| `audit-log` | audit activity table (`audit-activity-table`) | component | missing |
|
|
90
|
-
| `debt-payoff` | debt table and pagination (`debt-table-and-pagination`) | component | approximation |
|
|
91
|
-
| `inference-providers` | expandable provider configuration table (`expandable-provider-table`) | component | missing |
|
|
92
|
-
| `marcohr-people` | employee policy table (`marcohr-employee-table`) | component | approximation |
|
|
93
|
-
| `people-add-member` | people table with status rows (`people-table-and-status-rows`) | component | approximation |
|
|
94
|
-
| `recent-orders` | orders table controls and rows (`orders-table-region`) | component | approximation |
|
|
95
|
-
| `school-assignments` | assignments table (`assignments-table`) | component | missing |
|
|
96
|
-
| `share-of-voice` | analytics table density (`share-of-voice-analytics-table`) | component | approximation |
|
|
97
|
-
| `sku-management` | SKU data table and pagination (`sku-data-table`) | component | approximation |
|
|
98
|
-
| `stripe-demo-account` | metric table cards (`metric-table-cards`) | component | approximation |
|
|
99
|
-
| `stripe-demo-account` | sales tabs and table (`sales-tabs-and-table`) | component | approximation |
|
|
100
|
-
|
|
101
61
|
## Elevation/blur semantic effects
|
|
102
62
|
|
|
103
63
|
Key: `elevation-effects` · 10 backgrounds
|
|
@@ -135,32 +95,6 @@ Backgrounds: `delivery-tracking`, `investor-profile`, `mcp-settings`, `profile-m
|
|
|
135
95
|
| `school-assignments` | teacher avatar (`teacher-avatar`) | image asset | missing |
|
|
136
96
|
| `stripe-demo-account` | Stripe mark and account avatar (`stripe-brand-and-avatar-assets`) | image asset | approximation |
|
|
137
97
|
|
|
138
|
-
## Progress/step indicator
|
|
139
|
-
|
|
140
|
-
Key: `progress-step-indicator` · 5 backgrounds
|
|
141
|
-
|
|
142
|
-
Backgrounds: `accounting-workspace-setup`, `benefits-enrollment`, `mcp-settings`, `quran-audio-add-employee`, `refund-simulation`
|
|
143
|
-
|
|
144
|
-
| Background | Gap | Kind | Status |
|
|
145
|
-
| --- | --- | --- | --- |
|
|
146
|
-
| `accounting-workspace-setup` | step progress indicator (`setup-progress-indicator`) | component | approximation |
|
|
147
|
-
| `benefits-enrollment` | enrollment progress header (`enrollment-progress-header`) | component | missing |
|
|
148
|
-
| `mcp-settings` | numbered setup steps (`numbered-setup-steps`) | component | missing |
|
|
149
|
-
| `quran-audio-add-employee` | three-step employee progress indicator (`quran-audio-progress-stepper`) | component | approximation |
|
|
150
|
-
| `refund-simulation` | refund progress timeline (`refund-progress-timeline`) | component | missing |
|
|
151
|
-
|
|
152
|
-
## Composer pattern
|
|
153
|
-
|
|
154
|
-
Key: `composer-pattern` · 3 backgrounds
|
|
155
|
-
|
|
156
|
-
Backgrounds: `acme-finance-advisor`, `email-compose`, `order-shipment-timeline`
|
|
157
|
-
|
|
158
|
-
| Background | Gap | Kind | Status |
|
|
159
|
-
| --- | --- | --- | --- |
|
|
160
|
-
| `acme-finance-advisor` | advisor prompt composer (`acme-advisor-composer`) | component | approximation |
|
|
161
|
-
| `email-compose` | compose modal shell (`compose-modal-shell`) | layout/composition pattern | missing |
|
|
162
|
-
| `order-shipment-timeline` | note composer (`note-composer`) | component | missing |
|
|
163
|
-
|
|
164
98
|
## Review rule
|
|
165
99
|
|
|
166
100
|
A report entry is a prioritization signal, not automatic authorization to add a primitive. Review the mapped backgrounds, define the smallest stable API, migrate at least one real background, and remove the resolved gap metadata only after behavior, RTL, accessibility, and visual checks pass.
|
|
@@ -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
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "banhaten",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.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-lg)]",
|
|
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
|
},
|
|
@@ -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-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
|
)
|
|
@@ -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
|
/>
|
|
@@ -307,7 +311,7 @@ function AvatarGroupCount({
|
|
|
307
311
|
data-slot="avatar-group-count"
|
|
308
312
|
className={cn(
|
|
309
313
|
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-
|
|
314
|
+
"-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
315
|
className
|
|
312
316
|
)}
|
|
313
317
|
{...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: {
|
|
@@ -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
|
>
|
|
@@ -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:
|
|
@@ -58,7 +58,7 @@ const cardVariants = cva(
|
|
|
58
58
|
orientation: "horizontal",
|
|
59
59
|
breakpoint: "desktop",
|
|
60
60
|
class:
|
|
61
|
-
"min-h-[var(--bh-card-horizontal-min-height)] w-[min(100%,var(--bh-card-horizontal-width))]",
|
|
61
|
+
"min-h-[var(--bh-card-horizontal-min-height)] w-[min(100%,var(--bh-card-horizontal-width))] flex-wrap",
|
|
62
62
|
},
|
|
63
63
|
{
|
|
64
64
|
orientation: "horizontal",
|
|
@@ -109,6 +109,20 @@ type CardActionsProps = React.ComponentProps<"div"> & {
|
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
type CardFooterProps = React.ComponentProps<"div">
|
|
112
|
+
type CardSurfaceProps = React.ComponentPropsWithoutRef<"article">
|
|
113
|
+
|
|
114
|
+
const CardSurface = React.forwardRef<HTMLElement, CardSurfaceProps>(
|
|
115
|
+
function CardSurface({ className, ...props }, ref) {
|
|
116
|
+
return (
|
|
117
|
+
<article
|
|
118
|
+
data-slot="card-surface"
|
|
119
|
+
ref={ref}
|
|
120
|
+
className={cn(cardVariants(), className)}
|
|
121
|
+
{...props}
|
|
122
|
+
/>
|
|
123
|
+
)
|
|
124
|
+
}
|
|
125
|
+
)
|
|
112
126
|
|
|
113
127
|
const Card = React.forwardRef<HTMLElement, CardProps>(function Card({
|
|
114
128
|
actions,
|
|
@@ -362,7 +376,7 @@ function CardBody({
|
|
|
362
376
|
className={cn(
|
|
363
377
|
"flex min-w-0 flex-col",
|
|
364
378
|
horizontal
|
|
365
|
-
? "flex-
|
|
379
|
+
? "min-w-[min(100%,var(--bh-card-vertical-width))] flex-[1_1_var(--bh-card-vertical-width)] gap-[var(--bh-space-5xl-24)] p-[var(--bh-card-horizontal-padding)]"
|
|
366
380
|
: "w-full gap-[var(--bh-space-5xl-24)] p-[var(--bh-card-content-padding)]"
|
|
367
381
|
)}
|
|
368
382
|
>
|
|
@@ -566,7 +580,7 @@ function getCardMediaClassName(
|
|
|
566
580
|
breakpoint: CardBreakpoint
|
|
567
581
|
) {
|
|
568
582
|
if (orientation === "horizontal" && breakpoint === "desktop") {
|
|
569
|
-
return "h-
|
|
583
|
+
return "min-h-[var(--bh-card-media-height)] w-[min(100%,var(--bh-card-horizontal-media-width))] shrink flex-[1_1_var(--bh-card-horizontal-media-width)]"
|
|
570
584
|
}
|
|
571
585
|
|
|
572
586
|
return "h-[var(--bh-card-media-height)] w-full"
|
|
@@ -611,6 +625,7 @@ export {
|
|
|
611
625
|
CardActions,
|
|
612
626
|
CardFooter,
|
|
613
627
|
CardMedia,
|
|
628
|
+
CardSurface,
|
|
614
629
|
cardVariants,
|
|
615
630
|
type CardActionsProps,
|
|
616
631
|
type CardBreakpoint,
|
|
@@ -618,5 +633,6 @@ export {
|
|
|
618
633
|
type CardMediaProps,
|
|
619
634
|
type CardOrientation,
|
|
620
635
|
type CardProps,
|
|
636
|
+
type CardSurfaceProps,
|
|
621
637
|
type CardType,
|
|
622
638
|
}
|
|
@@ -17,16 +17,22 @@ type CarouselPlugin = UseCarouselParameters[1]
|
|
|
17
17
|
type CarouselOrientation = "horizontal" | "vertical"
|
|
18
18
|
|
|
19
19
|
type CarouselMessages = {
|
|
20
|
+
carouselLabel: string
|
|
21
|
+
carouselRoleDescription: string
|
|
20
22
|
nextSlide: string
|
|
21
23
|
previousSlide: string
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
const defaultCarouselMessages: CarouselMessages = {
|
|
27
|
+
carouselLabel: "Carousel",
|
|
28
|
+
carouselRoleDescription: "carousel",
|
|
25
29
|
nextSlide: "Next slide",
|
|
26
30
|
previousSlide: "Previous slide",
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
const arabicCarouselMessages: CarouselMessages = {
|
|
34
|
+
carouselLabel: "\u0639\u0627\u0631\u0636 \u0627\u0644\u0634\u0631\u0627\u0626\u062d",
|
|
35
|
+
carouselRoleDescription: "\u0639\u0627\u0631\u0636 \u0634\u0631\u0627\u0626\u062d",
|
|
30
36
|
nextSlide: "\u0627\u0644\u0634\u0631\u064a\u062d\u0629 \u0627\u0644\u062a\u0627\u0644\u064a\u0629",
|
|
31
37
|
previousSlide: "\u0627\u0644\u0634\u0631\u064a\u062d\u0629 \u0627\u0644\u0633\u0627\u0628\u0642\u0629",
|
|
32
38
|
}
|
|
@@ -58,6 +64,9 @@ const CarouselContext = React.createContext<CarouselContextValue | null>(null)
|
|
|
58
64
|
const Carousel = React.forwardRef<HTMLDivElement, CarouselProps>(
|
|
59
65
|
function Carousel(
|
|
60
66
|
{
|
|
67
|
+
"aria-label": ariaLabel,
|
|
68
|
+
"aria-labelledby": ariaLabelledBy,
|
|
69
|
+
"aria-roledescription": ariaRoleDescription,
|
|
61
70
|
children,
|
|
62
71
|
className,
|
|
63
72
|
dir,
|
|
@@ -138,6 +147,11 @@ const Carousel = React.forwardRef<HTMLDivElement, CarouselProps>(
|
|
|
138
147
|
dir={direction}
|
|
139
148
|
ref={setRootRef}
|
|
140
149
|
role="region"
|
|
150
|
+
aria-label={ariaLabelledBy ? undefined : (ariaLabel ?? messages.carouselLabel)}
|
|
151
|
+
aria-labelledby={ariaLabelledBy}
|
|
152
|
+
aria-roledescription={
|
|
153
|
+
ariaRoleDescription ?? messages.carouselRoleDescription
|
|
154
|
+
}
|
|
141
155
|
className={cn("relative", className)}
|
|
142
156
|
{...props}
|
|
143
157
|
>
|