banhaten 0.1.2 → 0.1.3
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/README.md +93 -328
- package/banhaten.config.example.json +1 -1
- package/docs/design-system/README.md +11 -0
- package/docs/design-system/appearance-presets.md +184 -0
- package/docs/design-system/appearances/default.md +94 -0
- package/docs/design-system/appearances/rounded.md +95 -0
- package/docs/design-system/appearances/sharp.md +95 -0
- package/docs/design-system/component-showcase-consistency-report.md +217 -0
- package/docs/design-system/component-token-consistency-audit.md +163 -0
- package/docs/design-system/components/README.md +74 -0
- package/docs/design-system/components/accordion.md +51 -0
- package/docs/design-system/components/activity-feed.md +92 -0
- package/docs/design-system/components/alert-dialog.md +70 -0
- package/docs/design-system/components/alert.md +79 -0
- package/docs/design-system/components/aspect-ratio.md +44 -0
- package/docs/design-system/components/attribute.md +87 -0
- package/docs/design-system/components/autocomplete.md +74 -0
- package/docs/design-system/components/avatar.md +52 -0
- package/docs/design-system/components/badge.md +53 -0
- package/docs/design-system/components/banner.md +85 -0
- package/docs/design-system/components/breadcrumbs.md +174 -0
- package/docs/design-system/components/button-group.md +83 -0
- package/docs/design-system/components/button.md +77 -0
- package/docs/design-system/components/card.md +78 -0
- package/docs/design-system/components/carousel.md +44 -0
- package/docs/design-system/components/catalog-components.md +45 -0
- package/docs/design-system/components/chart.md +43 -0
- package/docs/design-system/components/checkbox.md +52 -0
- package/docs/design-system/components/collapsible.md +48 -0
- package/docs/design-system/components/command-bar.md +57 -0
- package/docs/design-system/components/command.md +60 -0
- package/docs/design-system/components/context-menu.md +44 -0
- package/docs/design-system/components/date-picker.md +77 -0
- package/docs/design-system/components/divider.md +101 -0
- package/docs/design-system/components/empty-state.md +55 -0
- package/docs/design-system/components/field.md +69 -0
- package/docs/design-system/components/file-upload.md +185 -0
- package/docs/design-system/components/hover-card.md +46 -0
- package/docs/design-system/components/icons.md +48 -0
- package/docs/design-system/components/input-group.md +56 -0
- package/docs/design-system/components/input-otp.md +55 -0
- package/docs/design-system/components/input.md +48 -0
- package/docs/design-system/components/kbd.md +44 -0
- package/docs/design-system/components/label.md +48 -0
- package/docs/design-system/components/menu.md +59 -0
- package/docs/design-system/components/menubar.md +45 -0
- package/docs/design-system/components/modal.md +98 -0
- package/docs/design-system/components/native-select.md +52 -0
- package/docs/design-system/components/navigation-menu.md +48 -0
- package/docs/design-system/components/onboarding-step-list-item.md +80 -0
- package/docs/design-system/components/page-header.md +84 -0
- package/docs/design-system/components/pagination.md +49 -0
- package/docs/design-system/components/popover.md +58 -0
- package/docs/design-system/components/progress-slider.md +48 -0
- package/docs/design-system/components/progress.md +75 -0
- package/docs/design-system/components/radio-card.md +49 -0
- package/docs/design-system/components/radio-group.md +55 -0
- package/docs/design-system/components/resizable.md +42 -0
- package/docs/design-system/components/scroll-area.md +45 -0
- package/docs/design-system/components/select.md +50 -0
- package/docs/design-system/components/sheet.md +65 -0
- package/docs/design-system/components/sidebar.md +68 -0
- package/docs/design-system/components/skeleton.md +73 -0
- package/docs/design-system/components/slideout.md +63 -0
- package/docs/design-system/components/slider.md +61 -0
- package/docs/design-system/components/social-button.md +47 -0
- package/docs/design-system/components/spinner.md +61 -0
- package/docs/design-system/components/steps.md +63 -0
- package/docs/design-system/components/table.md +397 -0
- package/docs/design-system/components/tabs.md +52 -0
- package/docs/design-system/components/tag.md +78 -0
- package/docs/design-system/components/textarea.md +48 -0
- package/docs/design-system/components/timeline.md +81 -0
- package/docs/design-system/components/toast.md +56 -0
- package/docs/design-system/components/toggle.md +79 -0
- package/docs/design-system/components/toolbar.md +85 -0
- package/docs/design-system/components/tooltip.md +90 -0
- package/docs/design-system/components/typography.md +18 -0
- package/docs/design-system/design-system-test-missing-items.md +368 -0
- package/docs/design-system/icons.md +69 -0
- package/docs/design-system/registry-and-cli.md +41 -0
- package/docs/design-system/tabs.md +53 -0
- package/docs/design-system/token-governance.md +38 -0
- package/package.json +83 -65
- package/registry/components/alert-dialog.tsx +297 -0
- package/registry/components/aspect-ratio.tsx +30 -0
- package/registry/components/carousel.tsx +234 -0
- package/registry/components/chart.tsx +170 -0
- package/registry/components/collapsible.tsx +69 -0
- package/registry/components/command.tsx +174 -0
- package/registry/components/context-menu.tsx +236 -0
- package/registry/components/date-picker.tsx +1 -1
- package/registry/components/expanded/PageHeader.tsx +1 -1
- package/registry/components/expanded/breadcrumbs.css +139 -139
- package/registry/components/expanded/catalogComponentsShowcase.css +83 -83
- package/registry/components/expanded/steps.css +274 -274
- package/registry/components/expanded/timeline.css +264 -264
- package/registry/components/field.tsx +230 -0
- package/registry/components/hover-card.tsx +48 -0
- package/registry/components/input-group.tsx +130 -0
- package/registry/components/input.tsx +2 -2
- package/registry/components/kbd.tsx +44 -0
- package/registry/components/label.tsx +78 -0
- package/registry/components/menu.tsx +3 -1
- package/registry/components/menubar.tsx +226 -0
- package/registry/components/modal.tsx +109 -76
- package/registry/components/native-select.tsx +205 -0
- package/registry/components/navigation-menu.tsx +171 -0
- package/registry/components/radio-group.tsx +1 -1
- package/registry/components/resizable.tsx +74 -0
- package/registry/components/scroll-area.tsx +67 -0
- package/registry/components/select.tsx +2 -4
- package/registry/components/sheet.tsx +305 -0
- package/registry/components/sidebar.tsx +352 -0
- package/registry/components/social-button.tsx +74 -10
- package/registry/components/{expanded/tabs.css → tabs.css} +127 -106
- package/registry/components/tabs.tsx +242 -0
- package/registry/components/textarea.tsx +1 -1
- package/registry/components/toast.tsx +131 -0
- package/registry/examples/alert-dialog-demo.tsx +42 -0
- package/registry/examples/aspect-ratio-demo.tsx +11 -0
- package/registry/examples/carousel-demo.tsx +25 -0
- package/registry/examples/chart-demo.tsx +33 -0
- package/registry/examples/collapsible-demo.tsx +16 -0
- package/registry/examples/command-demo.tsx +42 -0
- package/registry/examples/context-menu-demo.tsx +29 -0
- package/registry/examples/expanded/tabs-demo.tsx +1 -1
- package/registry/examples/field-demo.tsx +51 -0
- package/registry/examples/hover-card-demo.tsx +23 -0
- package/registry/examples/input-group-demo.tsx +16 -0
- package/registry/examples/kbd-demo.tsx +11 -0
- package/registry/examples/label-demo.tsx +20 -0
- package/registry/examples/menubar-demo.tsx +34 -0
- package/registry/examples/native-select-demo.tsx +16 -0
- package/registry/examples/navigation-menu-demo.tsx +29 -0
- package/registry/examples/resizable-demo.tsx +22 -0
- package/registry/examples/scroll-area-demo.tsx +15 -0
- package/registry/examples/sheet-demo.tsx +47 -0
- package/registry/examples/sidebar-demo.tsx +55 -0
- package/registry/examples/tabs-demo.tsx +13 -0
- package/registry/examples/toast-demo.tsx +35 -0
- package/registry/index.json +655 -11
- package/registry/styles/globals.css +4733 -4690
- package/registry.json +1612 -0
- package/schema/config.schema.json +48 -0
- package/schema/registry.schema.json +85 -0
- package/schema/tokens.schema.json +63 -0
- package/src/cli/index.js +312 -18
- package/tokens/banhaten.tokens.json +1 -1
- package/registry/assets/avatars/avatar-02.jpg +0 -0
- package/registry/assets/avatars/avatar-03.jpg +0 -0
- package/registry/assets/avatars/avatar-04.jpg +0 -0
- package/registry/assets/avatars/avatar-05.jpg +0 -0
- package/registry/assets/avatars/avatar-06.jpg +0 -0
- package/registry/assets/avatars/avatar-07.jpg +0 -0
- package/registry/assets/avatars/avatar-08.jpg +0 -0
- package/registry/assets/avatars/avatar-09.jpg +0 -0
- package/registry/assets/avatars/avatar-10.jpg +0 -0
- package/registry/assets/avatars/avatar-11.jpg +0 -0
- package/registry/assets/avatars/avatar-12.jpg +0 -0
- package/registry/assets/avatars/avatar-13.jpg +0 -0
- package/registry/assets/avatars/avatar-14.jpg +0 -0
- package/registry/assets/avatars/avatar-15.jpg +0 -0
- package/registry/assets/avatars/avatar-16.jpg +0 -0
- package/registry/assets/avatars/avatar-17.jpg +0 -0
- package/registry/assets/avatars/avatar-18.jpg +0 -0
- package/registry/assets/avatars/avatar-19.jpg +0 -0
- package/registry/assets/avatars/avatar-20.jpg +0 -0
- package/registry/assets/avatars/avatar-21.jpg +0 -0
- package/registry/assets/avatars/avatar-22.jpg +0 -0
- package/registry/assets/avatars/avatar-23.jpg +0 -0
- package/registry/assets/avatars/avatar-24.jpg +0 -0
- package/registry/assets/avatars/avatar-25.jpg +0 -0
- package/registry/assets/avatars/avatar-26.jpg +0 -0
- package/registry/assets/avatars/avatar-27.jpg +0 -0
- package/registry/assets/avatars/avatar-28.jpg +0 -0
- package/registry/assets/avatars/avatar-29.jpg +0 -0
- package/registry/assets/avatars/avatar-30.jpg +0 -0
- package/registry/assets/avatars/avatar-31.jpg +0 -0
- package/registry/assets/avatars/avatar-32.jpg +0 -0
- package/registry/assets/avatars/avatar-33.jpg +0 -0
- package/registry/assets/avatars/avatar-34.jpg +0 -0
- package/registry/assets/avatars/avatar-35.jpg +0 -0
- package/registry/assets/image-assets.json +0 -744
- package/registry/assets/images/art-02.jpg +0 -0
- package/registry/assets/images/art-03.jpg +0 -0
- package/registry/assets/images/art-04.jpg +0 -0
- package/registry/assets/images/art-05.jpg +0 -0
- package/registry/assets/images/art-06.jpg +0 -0
- package/registry/assets/images/art-07.jpg +0 -0
- package/registry/assets/images/art-08.jpg +0 -0
- package/registry/assets/images/art-09.jpg +0 -0
- package/registry/assets/images/art-10.jpg +0 -0
- package/registry/assets/images/art-11.jpg +0 -0
- package/registry/assets/images/art-12.jpg +0 -0
- package/registry/assets/images/art-13.jpg +0 -0
- package/registry/assets/images/art-14.jpg +0 -0
- package/registry/assets/images/art-15.jpg +0 -0
- package/registry/assets/images/art-16.jpg +0 -0
- package/registry/assets/images/art-17.jpg +0 -0
- package/registry/assets/images/art-18.jpg +0 -0
- package/registry/assets/images/art-19.jpg +0 -0
- package/registry/assets/images/art-20.jpg +0 -0
- package/registry/assets/images/art-21.jpg +0 -0
- package/registry/assets/images/art-22.jpg +0 -0
- package/registry/assets/images/art-23.jpg +0 -0
- package/registry/assets/images/art-24.jpg +0 -0
- package/registry/assets/images/art-25.jpg +0 -0
- package/registry/assets/images/art-26.jpg +0 -0
- package/registry/assets/images/art-27.jpg +0 -0
- package/registry/assets/images/nature-01.jpg +0 -0
- package/registry/assets/images/nature-02.jpg +0 -0
- package/registry/assets/images/nature-03.jpg +0 -0
- package/registry/assets/images/nature-04.jpg +0 -0
- package/registry/assets/images/nature-05.jpg +0 -0
- package/registry/assets/images/nature-06.jpg +0 -0
- package/registry/assets/images/nature-07.jpg +0 -0
- package/registry/assets/images/nature-08.jpg +0 -0
- package/registry/assets/images/nature-09.jpg +0 -0
- package/registry/assets/images/nature-10.jpg +0 -0
- package/registry/assets/images/nature-11.jpg +0 -0
- package/registry/assets/images/nature-12.jpg +0 -0
- package/registry/assets/images/nature-13.jpg +0 -0
- package/registry/assets/images/nature-14.jpg +0 -0
- package/registry/assets/images/nature-15.jpg +0 -0
- package/registry/assets/images/nature-16.jpg +0 -0
- package/registry/assets/images/nature-17.jpg +0 -0
- package/registry/assets/images/nature-18.jpg +0 -0
- package/registry/assets/images/nature-19.jpg +0 -0
- package/registry/assets/images/nature-20.jpg +0 -0
- package/registry/components/expanded/Tabs.tsx +0 -86
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Steps
|
|
2
|
+
|
|
3
|
+
Steps show progress through a sequential task. The implementation follows the Figma nodes `HorizontalSteps` (`570:2780`), `VerticalSteps` (`567:76719`), `VerticalStepItem` (`567:5342`), and `HorizontalStepItem` (`569:78346`).
|
|
4
|
+
|
|
5
|
+
## API
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
<Steps
|
|
9
|
+
direction="horizontal"
|
|
10
|
+
indicator="icon"
|
|
11
|
+
dir="ltr"
|
|
12
|
+
items={[
|
|
13
|
+
{ label: "Label", caption: "Caption", supportText: "Support" },
|
|
14
|
+
{ label: "Label", caption: "Caption", supportText: "Support" },
|
|
15
|
+
]}
|
|
16
|
+
/>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
| Prop | Values | Default |
|
|
20
|
+
| --- | --- | --- |
|
|
21
|
+
| `direction` | `horizontal`, `vertical` | `horizontal` |
|
|
22
|
+
| `indicator` | `icon`, `number` | `icon` |
|
|
23
|
+
| `alignment` | `leading`, `trailing` | `leading` |
|
|
24
|
+
| `dir` | `ltr`, `rtl` | `ltr` |
|
|
25
|
+
| `items` | `StepItem[]` | six default steps |
|
|
26
|
+
|
|
27
|
+
## Pixel Rules
|
|
28
|
+
|
|
29
|
+
- Step markers are `28px` circles using `--bg-inverse` with white icon or semibold number text.
|
|
30
|
+
- Connector lines are `1px` using `--border-default`.
|
|
31
|
+
- Horizontal items are `240px` wide in standalone mode and flex equally inside `HorizontalSteps`.
|
|
32
|
+
- Horizontal item content uses `15px / 24px` medium labels and `14px / 20px` captions.
|
|
33
|
+
- Vertical items are `400px` wide with a `24px` gap between marker rail and content.
|
|
34
|
+
- Vertical item labels use `17px / 28px`; support text and captions use `15px / 24px`.
|
|
35
|
+
- Vertical slot content is `76px` tall with the purple subtle background and dashed purple border.
|
|
36
|
+
- Action buttons are `36px` tall with the design-system primary and secondary treatment.
|
|
37
|
+
- RTL mirrors marker placement, text alignment, support text order, and horizontal connector direction.
|
|
38
|
+
|
|
39
|
+
## Install
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npx banhaten add steps
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Examples
|
|
46
|
+
|
|
47
|
+
Primary registry example: `examples/expanded/steps-demo.tsx`.
|
|
48
|
+
|
|
49
|
+
Open the live component page or run `npx banhaten docs steps` to inspect source files, install command, and examples.
|
|
50
|
+
|
|
51
|
+
## Token Contract
|
|
52
|
+
|
|
53
|
+
Component styles must resolve through Banhaten semantic tokens, component aliases, or documented exception-ledger values.
|
|
54
|
+
Do not add raw colors, pixel values, opacity utilities, z-index values, durations, or shadow literals directly to component source.
|
|
55
|
+
Covered source files: `components/expanded/steps.css`, `components/expanded/Steps.tsx`.
|
|
56
|
+
|
|
57
|
+
## RTL Rules
|
|
58
|
+
|
|
59
|
+
This component has no special RTL contract beyond inherited document direction and logical spacing.
|
|
60
|
+
|
|
61
|
+
## Accessibility
|
|
62
|
+
|
|
63
|
+
Keep native semantics, accessible names, keyboard reachability, focus-visible treatment, and status/error announcements intact when composing this component.
|
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
# Table
|
|
2
|
+
|
|
3
|
+
The table component family includes `Table` and `DataTable`.
|
|
4
|
+
|
|
5
|
+
`Table` is the composable data surface. It owns layout, headers, row states, selection, sortable header affordances, and RTL mirroring. Cells are filled by table item variants, so new content can be added without creating one-off row layouts.
|
|
6
|
+
|
|
7
|
+
`DataTable` is the dataset workflow wrapper. It composes the existing Banhaten `Table`, `Toolbar`, `Pagination`, and `Spinner` components to provide search, filters, sorting, selection summary, bulk actions, pagination, and empty/loading/error states.
|
|
8
|
+
|
|
9
|
+
Figma references:
|
|
10
|
+
|
|
11
|
+
- `Table Example`, node `449:2354`
|
|
12
|
+
- `Table item 1.2`, node `438:41157`
|
|
13
|
+
|
|
14
|
+
## Structure
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
<Table
|
|
18
|
+
dir="ltr"
|
|
19
|
+
columns={columns}
|
|
20
|
+
rows={rows}
|
|
21
|
+
selectedRowIds={selectedRowIds}
|
|
22
|
+
onSelectedRowIdsChange={setSelectedRowIds}
|
|
23
|
+
/>
|
|
24
|
+
|
|
25
|
+
<DataTable
|
|
26
|
+
title="Component Operations"
|
|
27
|
+
description="Track component readiness across design-system work."
|
|
28
|
+
columns={columns}
|
|
29
|
+
rows={rows}
|
|
30
|
+
selectedRowIds={selectedRowIds}
|
|
31
|
+
onSelectedRowIdsChange={setSelectedRowIds}
|
|
32
|
+
search={{ label: "Search projects", placeholder: "Search projects..." }}
|
|
33
|
+
filters={filters}
|
|
34
|
+
pagination={{ pageSize: 10 }}
|
|
35
|
+
/>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The table is composed from these parts:
|
|
39
|
+
|
|
40
|
+
- `Table`: scroll container and semantic table/grid root.
|
|
41
|
+
- `TableHeader`: one header row with sortable header cells.
|
|
42
|
+
- `TableRow`: one data row with `default`, `selected`, and `disabled` states plus native hover styling.
|
|
43
|
+
- `TableCell`: the layout shell for any table item.
|
|
44
|
+
- `TableItem`: the content variant rendered inside a cell.
|
|
45
|
+
- `DataTable`: composed workflow shell for search, filters, actions, pagination, and table states.
|
|
46
|
+
|
|
47
|
+
Use semantic `<table>` markup when the table is mostly read-only data. Use an ARIA grid only when the product needs cell-level keyboard navigation. Interactive content inside cells, such as checkboxes, toggles, and actions, must remain real controls.
|
|
48
|
+
|
|
49
|
+
## Layout
|
|
50
|
+
|
|
51
|
+
The Figma sample is `1024px` wide, but the implementation should be responsive. Fixed columns keep their design widths and the primary text column fills the remaining space.
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
const exampleColumns = [
|
|
55
|
+
{ id: "select", width: 40, kind: "selection" },
|
|
56
|
+
{ id: "project", header: "Project Name", width: "fill", sortable: true },
|
|
57
|
+
{ id: "leader", header: "Project Leader", width: 203, sortable: true },
|
|
58
|
+
{ id: "status", header: "Status", width: 147, sortable: true },
|
|
59
|
+
{ id: "progress", header: "Progress", width: 160, sortable: true },
|
|
60
|
+
{ id: "deadline", header: "Deadline", width: 155, sortable: true },
|
|
61
|
+
{ id: "actions", width: 44, kind: "actions" },
|
|
62
|
+
];
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
RTL tables reverse the visual column order and align cell content to the end. The selection cell moves to the far right, and the action cell moves to the far left. The row data order should not change.
|
|
66
|
+
|
|
67
|
+
## Sizing
|
|
68
|
+
|
|
69
|
+
| Area | Size | LTR height | RTL height |
|
|
70
|
+
| --- | --- | ---: | ---: |
|
|
71
|
+
| Header row | `sm` | `44px` | `44px` |
|
|
72
|
+
| Body row | `sm` | `48px` | `44px` |
|
|
73
|
+
| Body row | `lg` | `56px` | `56px` |
|
|
74
|
+
|
|
75
|
+
Cell padding is `8px` on the inline axis. Inline content gap is `6px`; header label and sort icon gap is `4px`. The base checkbox and action columns use fixed dimensions so hover, selected, and icon states do not shift the table.
|
|
76
|
+
|
|
77
|
+
## States
|
|
78
|
+
|
|
79
|
+
| State | Treatment |
|
|
80
|
+
| --- | --- |
|
|
81
|
+
| `default` | Default background with a subtle bottom divider. |
|
|
82
|
+
| Native hover | Ghost hover background across the full row. |
|
|
83
|
+
| `selected` | Selected row background and checked selection control. |
|
|
84
|
+
| `disabled` | Disabled content color and no row actions. |
|
|
85
|
+
|
|
86
|
+
The selected checkbox uses the brand or checkbox fill and a white check icon. Header checkbox supports checked, unchecked, and indeterminate states.
|
|
87
|
+
|
|
88
|
+
## Token Mapping
|
|
89
|
+
|
|
90
|
+
The Figma nodes use names such as `interactive/table/header`, `interactive/ghost/hover`, and `bg/neutral/soft`. In this documentation set, map those to the semantic token contract:
|
|
91
|
+
|
|
92
|
+
| Figma intent | Design-system token |
|
|
93
|
+
| --- | --- |
|
|
94
|
+
| Table header background | `background.muted` |
|
|
95
|
+
| Row hover background | `background.hover` |
|
|
96
|
+
| Row selected background | `background.selected` |
|
|
97
|
+
| Row divider | `border.subtle` |
|
|
98
|
+
| Body text | `content.default` |
|
|
99
|
+
| Header text and secondary labels | `content.subtle` |
|
|
100
|
+
| Checkbox active fill | `background.brand` |
|
|
101
|
+
| Progress track | `background.muted` |
|
|
102
|
+
| Progress fill | `background.success` or component success fill |
|
|
103
|
+
| Row height | `density.tableRowHeight` |
|
|
104
|
+
| Control radius | `shape.control` |
|
|
105
|
+
| Avatar, badge, and progress radius | `shape.badge` |
|
|
106
|
+
|
|
107
|
+
Do not hard-code preset-specific values in the table. Appearance presets may change density, radius, borders, and hover treatment while preserving the same component API.
|
|
108
|
+
|
|
109
|
+
## Column API
|
|
110
|
+
|
|
111
|
+
Use semantic names in code even if the Figma variant labels are title-cased.
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
type TableDirection = "ltr" | "rtl";
|
|
115
|
+
type TableSize = "sm" | "lg";
|
|
116
|
+
type TableRowState = "default" | "selected" | "disabled";
|
|
117
|
+
|
|
118
|
+
type TableColumn<Row> = {
|
|
119
|
+
id: string;
|
|
120
|
+
header?: string;
|
|
121
|
+
width?: number | "fill";
|
|
122
|
+
minWidth?: number;
|
|
123
|
+
align?: "start" | "center" | "end";
|
|
124
|
+
sortable?: boolean;
|
|
125
|
+
sortValue?: (row: Row) => TableSortValue;
|
|
126
|
+
searchValue?: (row: Row) => string;
|
|
127
|
+
kind?: "data" | "selection" | "actions";
|
|
128
|
+
item?: TableItemFactory<Row>;
|
|
129
|
+
renderCell?: (row: Row) => React.ReactNode;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
type TableItemFactory<Row> = (row: Row) => TableItem;
|
|
133
|
+
type TableSortValue = string | number | boolean | Date | null | undefined;
|
|
134
|
+
type TableSortState = { columnId: string; direction: "asc" | "desc" } | null;
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Use `item` for standard content variants and `renderCell` only for custom product-specific cells. Custom cells still render inside `TableCell`, so spacing, alignment, row height, truncation, RTL behavior, and disabled state stay consistent.
|
|
138
|
+
|
|
139
|
+
Use `sortValue` when the visible cell content should sort by an underlying value, such as dates, percentages, status rank, or formatted numbers. Use `searchValue` when the cell should contribute searchable text that is different from the visible content.
|
|
140
|
+
|
|
141
|
+
## Table Items
|
|
142
|
+
|
|
143
|
+
The item catalog in Figma supports these cell content variants. Code may normalize visual variants into semantic item types; for example, `baseLeading`, `baseRegular`, and `subtle` all map to the `text` item with different `weight` and `tone` values.
|
|
144
|
+
|
|
145
|
+
| Figma item type | Use for | Notes |
|
|
146
|
+
| --- | --- | --- |
|
|
147
|
+
| `checkbox` | Row selection | Fixed selection column. |
|
|
148
|
+
| `baseLeading` | Primary label | Medium body label. |
|
|
149
|
+
| `baseRegular` | Standard body text | Regular body label. |
|
|
150
|
+
| `subtle` | Secondary text | Uses subtle content color. |
|
|
151
|
+
| `avatarText` | Person, owner, assignee | Avatar plus label; `lg` may include caption. |
|
|
152
|
+
| `rating` | Star rating | Five 20px stars with full, half, and empty states. |
|
|
153
|
+
| `progress` | Percent completion | 8px track, percent label, mirrored fill in RTL. |
|
|
154
|
+
| `toggle` | Binary row setting | 32px switch in `sm`; preserve native button semantics. |
|
|
155
|
+
| `badges` | Status and categorical chips | Supports multiple badges and overflow count. |
|
|
156
|
+
| `onlyAvatar` | Compact person cell | Single avatar centered or aligned by column. |
|
|
157
|
+
| `avatarStack` | Team or group membership | Overlapped 20px avatars, optional count and add button. |
|
|
158
|
+
| `tags` | Neutral labels | Bordered tags with compact 24px height. |
|
|
159
|
+
| `file` | Attachment indicator | Icon-only file cell. |
|
|
160
|
+
| `brandLogoText` | Brand or account identity | Logo plus label. |
|
|
161
|
+
| `payment` | Payment method | Payment icon plus optional label. |
|
|
162
|
+
| `image` | Thumbnail item | Image thumbnail plus label. |
|
|
163
|
+
| `action` | Single row menu | Icon button, usually overflow menu. |
|
|
164
|
+
| `actionGroup` | Multiple row actions | View, edit, delete group; reverse order in RTL. |
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
type TableItem =
|
|
168
|
+
| { type: "checkbox"; checked: boolean; indeterminate?: boolean }
|
|
169
|
+
| { type: "text"; tone?: "default" | "subtle"; weight?: "regular" | "medium"; value: string }
|
|
170
|
+
| { type: "avatarText"; name: string; caption?: string; src?: string; status?: "top" | "bottom" }
|
|
171
|
+
| { type: "rating"; value: number; max?: 5 }
|
|
172
|
+
| { type: "progress"; value: number; label?: string; tone?: "success" | "brand" }
|
|
173
|
+
| { type: "toggle"; checked: boolean; disabled?: boolean }
|
|
174
|
+
| { type: "badges"; items: BadgeItem[]; maxVisible?: number }
|
|
175
|
+
| { type: "onlyAvatar"; src?: string; alt: string }
|
|
176
|
+
| { type: "avatarStack"; avatars: AvatarItem[]; count?: number; canAdd?: boolean }
|
|
177
|
+
| { type: "tags"; items: string[]; maxVisible?: number }
|
|
178
|
+
| { type: "file"; label?: string }
|
|
179
|
+
| { type: "brandLogoText"; label: string; logoSrc?: string }
|
|
180
|
+
| { type: "payment"; brand: "maestro" | "mastercard" | "visa" | string; label?: string }
|
|
181
|
+
| { type: "image"; label: string; src: string }
|
|
182
|
+
| { type: "action"; label: string; icon: "more"; onAction: () => void }
|
|
183
|
+
| { type: "actionGroup"; actions: TableAction[] };
|
|
184
|
+
|
|
185
|
+
type BadgeItem = {
|
|
186
|
+
label: string;
|
|
187
|
+
tone?: "blue" | "fuchsia" | "amber" | "neutral" | "success" | "warning" | "danger";
|
|
188
|
+
dot?: boolean;
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
type AvatarItem = {
|
|
192
|
+
src?: string;
|
|
193
|
+
alt: string;
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
type TableAction = {
|
|
197
|
+
label: string;
|
|
198
|
+
icon: "view" | "edit" | "delete" | "more";
|
|
199
|
+
onAction: () => void;
|
|
200
|
+
};
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
The item union intentionally describes content, not layout. `TableCell` decides padding, alignment, truncation, and RTL mirroring.
|
|
204
|
+
|
|
205
|
+
## Adding Items
|
|
206
|
+
|
|
207
|
+
Add a new table item by defining it on a column. The row supplies content values; the column controls presentation.
|
|
208
|
+
|
|
209
|
+
```tsx
|
|
210
|
+
const columns: TableColumn<Project>[] = [
|
|
211
|
+
{
|
|
212
|
+
id: "project",
|
|
213
|
+
header: "Project Name",
|
|
214
|
+
width: "fill",
|
|
215
|
+
sortable: true,
|
|
216
|
+
item: (project) => ({
|
|
217
|
+
type: "text",
|
|
218
|
+
value: project.name,
|
|
219
|
+
weight: "regular",
|
|
220
|
+
}),
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
id: "leader",
|
|
224
|
+
header: "Project Leader",
|
|
225
|
+
width: 203,
|
|
226
|
+
sortable: true,
|
|
227
|
+
item: (project) => ({
|
|
228
|
+
type: "avatarText",
|
|
229
|
+
name: project.leader.name,
|
|
230
|
+
src: project.leader.avatarUrl,
|
|
231
|
+
}),
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
id: "status",
|
|
235
|
+
header: "Status",
|
|
236
|
+
width: 147,
|
|
237
|
+
sortable: true,
|
|
238
|
+
item: (project) => ({
|
|
239
|
+
type: "badges",
|
|
240
|
+
items: [{ label: project.status, tone: "blue", dot: true }],
|
|
241
|
+
}),
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
id: "progress",
|
|
245
|
+
header: "Progress",
|
|
246
|
+
width: 160,
|
|
247
|
+
sortable: true,
|
|
248
|
+
item: (project) => ({
|
|
249
|
+
type: "progress",
|
|
250
|
+
value: project.progress,
|
|
251
|
+
label: `${project.progress}%`,
|
|
252
|
+
tone: "success",
|
|
253
|
+
}),
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
id: "deadline",
|
|
257
|
+
header: "Deadline",
|
|
258
|
+
width: 155,
|
|
259
|
+
sortable: true,
|
|
260
|
+
item: (project) => ({
|
|
261
|
+
type: "text",
|
|
262
|
+
value: project.deadlineLabel,
|
|
263
|
+
}),
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
id: "actions",
|
|
267
|
+
width: 44,
|
|
268
|
+
kind: "actions",
|
|
269
|
+
item: (project) => ({
|
|
270
|
+
type: "action",
|
|
271
|
+
label: `Open actions for ${project.name}`,
|
|
272
|
+
icon: "more",
|
|
273
|
+
onAction: () => openProjectActions(project.id),
|
|
274
|
+
}),
|
|
275
|
+
},
|
|
276
|
+
];
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
For a custom item, first check whether the content can be represented by the existing union. Add a new item type only when the content appears in more than one table or needs shared behavior such as keyboard handling, truncation, or overflow.
|
|
280
|
+
|
|
281
|
+
## Header Behavior
|
|
282
|
+
|
|
283
|
+
Sortable headers render the label plus the expand-up-down icon. When sorted, the header cell sets `aria-sort` to `ascending` or `descending`; otherwise it uses `none`. Header controls must have a clear label such as `Sort by Project Name`.
|
|
284
|
+
|
|
285
|
+
`Table` accepts `sort` and `onSortChange` when the host owns sorting. `DataTable` can own sorting internally with `defaultSort`, or operate as a controlled component with `sort` and `onSortChange`.
|
|
286
|
+
|
|
287
|
+
The select-all checkbox announces:
|
|
288
|
+
|
|
289
|
+
- unchecked when no visible rows are selected;
|
|
290
|
+
- checked when all visible rows are selected;
|
|
291
|
+
- indeterminate when some visible rows are selected.
|
|
292
|
+
|
|
293
|
+
## Data Table
|
|
294
|
+
|
|
295
|
+
Use `DataTable` when the product needs the complete dataset browsing workflow instead of only rows and columns.
|
|
296
|
+
|
|
297
|
+
```tsx
|
|
298
|
+
const filters = [
|
|
299
|
+
{
|
|
300
|
+
id: "review",
|
|
301
|
+
label: "Status",
|
|
302
|
+
value: "Review",
|
|
303
|
+
active: statusFilter === "Review",
|
|
304
|
+
onAction: () => setStatusFilter("Review"),
|
|
305
|
+
predicate: (row) => row.status === "Review",
|
|
306
|
+
},
|
|
307
|
+
];
|
|
308
|
+
|
|
309
|
+
<DataTable
|
|
310
|
+
actions={[{ label: "Export", variant: "soft" }]}
|
|
311
|
+
bulkActions={[{ label: "Archive", variant: "outline" }]}
|
|
312
|
+
columns={columns}
|
|
313
|
+
defaultSort={{ columnId: "project", direction: "asc" }}
|
|
314
|
+
emptyState={{
|
|
315
|
+
title: "No matching projects",
|
|
316
|
+
description: "Try another search or return to all statuses.",
|
|
317
|
+
}}
|
|
318
|
+
filters={filters}
|
|
319
|
+
pagination={{ pageSize: 10 }}
|
|
320
|
+
rows={rows}
|
|
321
|
+
search={{ label: "Search projects", placeholder: "Search projects..." }}
|
|
322
|
+
/>
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
`DataTable` applies active filter predicates, searches row text from `getRowSearchText`, column `searchValue`, or table item text, sorts by column `sortValue` or table item value, and paginates the resulting rows. Set `pagination={false}` for unpaginated datasets.
|
|
326
|
+
|
|
327
|
+
## Accessibility
|
|
328
|
+
|
|
329
|
+
- Preserve native controls for checkbox, toggle, buttons, and menu triggers.
|
|
330
|
+
- Use `aria-selected` on selected rows.
|
|
331
|
+
- Provide labels for icon-only actions.
|
|
332
|
+
- Keep focus outlines visible through `border.focus`.
|
|
333
|
+
- Truncate long text visually, but keep the full value available through `title` or an accessible label when useful.
|
|
334
|
+
- Do not put multiple unrelated buttons into one unlabeled cell; group row actions with a clear accessible name.
|
|
335
|
+
|
|
336
|
+
## Usage
|
|
337
|
+
|
|
338
|
+
```tsx
|
|
339
|
+
<Table
|
|
340
|
+
dir="ltr"
|
|
341
|
+
columns={columns}
|
|
342
|
+
rows={projects}
|
|
343
|
+
selectedRowIds={selectedRowIds}
|
|
344
|
+
onSelectedRowIdsChange={setSelectedRowIds}
|
|
345
|
+
/>
|
|
346
|
+
|
|
347
|
+
<Table
|
|
348
|
+
dir="rtl"
|
|
349
|
+
columns={columns}
|
|
350
|
+
rows={projects}
|
|
351
|
+
selectedRowIds={selectedRowIds}
|
|
352
|
+
onSelectedRowIdsChange={setSelectedRowIds}
|
|
353
|
+
/>
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
## Preset Impact
|
|
357
|
+
|
|
358
|
+
- `default`: normal row density, quiet header background, modest control radius.
|
|
359
|
+
- `rounded`: slightly taller rows, softer hover treatment, larger badges and control radius.
|
|
360
|
+
- `sharp`: denser rows, stronger dividers, square or near-square controls.
|
|
361
|
+
|
|
362
|
+
## Implementation Notes
|
|
363
|
+
|
|
364
|
+
- Use Remix icons for Figma icon matches: `expand-up-down-line`, `more-fill`, `check-fill`, `eye-line`, `pencil-line`, and `delete-bin-line`.
|
|
365
|
+
- Progress bars are `8px` high and pill-shaped. In RTL, the filled segment grows from the right.
|
|
366
|
+
- Badges are `24px` tall, pill-shaped, and use `11px / 14px` medium text.
|
|
367
|
+
- Tags are `24px` tall with a 1px border and `13px / 20px` medium text.
|
|
368
|
+
- Avatar-only and avatar-stack cells use 20px avatars in compact rows and 32px avatars where the `lg` item variant calls for it.
|
|
369
|
+
- Action buttons are fixed `28px` in `sm` rows and `32px` in `lg` rows.
|
|
370
|
+
|
|
371
|
+
## Install
|
|
372
|
+
|
|
373
|
+
```bash
|
|
374
|
+
npx banhaten add table
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
## API
|
|
378
|
+
|
|
379
|
+
Public exports: `Table`, `DataTable`.
|
|
380
|
+
|
|
381
|
+
Use the live registry docs for the generated API table and source-backed examples.
|
|
382
|
+
|
|
383
|
+
## Examples
|
|
384
|
+
|
|
385
|
+
Primary registry example: `examples/expanded/table-demo.tsx`.
|
|
386
|
+
|
|
387
|
+
Open the live component page or run `npx banhaten docs table` to inspect source files, install command, and examples.
|
|
388
|
+
|
|
389
|
+
## Token Contract
|
|
390
|
+
|
|
391
|
+
Component styles must resolve through Banhaten semantic tokens, component aliases, or documented exception-ledger values.
|
|
392
|
+
Do not add raw colors, pixel values, opacity utilities, z-index values, durations, or shadow literals directly to component source.
|
|
393
|
+
Covered source files: `components/expanded/table.css`, `components/expanded/Table.tsx`.
|
|
394
|
+
|
|
395
|
+
## RTL Rules
|
|
396
|
+
|
|
397
|
+
This component has no special RTL contract beyond inherited document direction and logical spacing.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Tabs
|
|
2
|
+
|
|
3
|
+
Tabs is a Radix-backed local navigation primitive with underline, segmented, and rounded treatments across size, full-width behavior, controlled state, LTR, and RTL.
|
|
4
|
+
|
|
5
|
+
## API
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
<Tabs
|
|
9
|
+
ariaLabel="Project sections"
|
|
10
|
+
items={["Overview", "Activity", "Settings"]}
|
|
11
|
+
variant="underline"
|
|
12
|
+
/>
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
| Prop | Values |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| `variant` | `underline`, `segment`, `rounded` |
|
|
18
|
+
| `size` | `md`, `sm`, `xs` |
|
|
19
|
+
| `fullWidth` | `boolean` |
|
|
20
|
+
| `activeIndex`, `defaultActiveIndex` | controlled or uncontrolled index |
|
|
21
|
+
| `onActiveIndexChange` | selected-index callback |
|
|
22
|
+
|
|
23
|
+
## Token Contract
|
|
24
|
+
|
|
25
|
+
Tabs uses Banhaten tab CSS variables for sizes, spacing, border, radius, active indicators, surfaces, and content states.
|
|
26
|
+
|
|
27
|
+
## RTL
|
|
28
|
+
|
|
29
|
+
Tabs accepts `dir="rtl"` and mirrors layout through inherited direction. Labels should remain short enough for each treatment and viewport.
|
|
30
|
+
|
|
31
|
+
## Accessibility
|
|
32
|
+
|
|
33
|
+
Tabs uses Radix Tabs so keyboard behavior, roving focus, activation mode, trigger state, and panel relationships come from the primitive.
|
|
34
|
+
|
|
35
|
+
## Install
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npx banhaten add tabs
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Examples
|
|
42
|
+
|
|
43
|
+
Primary registry example: `examples/tabs-demo.tsx`.
|
|
44
|
+
|
|
45
|
+
Open the live component page or run `npx banhaten docs tabs` to inspect source files, install command, and examples.
|
|
46
|
+
|
|
47
|
+
## RTL Rules
|
|
48
|
+
|
|
49
|
+
- `inheritsDirection`: true
|
|
50
|
+
- `keyboard`: Radix receives dir so arrow-key navigation follows the document direction.
|
|
51
|
+
- `textDirection`: Trigger labels use dir="auto" by default for Arabic and English tab labels.
|
|
52
|
+
- `spacing`: Uses inherited direction and logical inline spacing so underline, segmented, and rounded treatments mirror naturally.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Tag
|
|
2
|
+
|
|
3
|
+
Tags identify compact metadata, filters, or removable selections.
|
|
4
|
+
|
|
5
|
+
The implementation follows the Figma component at `Design system 3.0 Copy / Tag` (`188:64712`). It supports every variant in the matrix: `simple`, `dot`, `flag`, `avatar`, and `icon`; `default`, `active`, and `disabled` states with native hover and focus-visible styling; `xs`, `md`, and `lg` sizes; optional close button; LTR and RTL.
|
|
6
|
+
|
|
7
|
+
## API
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
<Tag
|
|
11
|
+
type="simple"
|
|
12
|
+
size="md"
|
|
13
|
+
state="default"
|
|
14
|
+
showCloseButton={false}
|
|
15
|
+
dir="ltr"
|
|
16
|
+
>
|
|
17
|
+
Label
|
|
18
|
+
</Tag>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
| Prop | Values | Default |
|
|
22
|
+
| --- | --- | --- |
|
|
23
|
+
| `type` | `simple`, `dot`, `flag`, `avatar`, `icon` | `simple` |
|
|
24
|
+
| `size` | `xs`, `md`, `lg` | `md` |
|
|
25
|
+
| `state` | `default`, `active`, `disabled` | `default` |
|
|
26
|
+
| `showCloseButton` | `boolean` | `false` |
|
|
27
|
+
| `disabled` | `boolean` | `false` |
|
|
28
|
+
| `dir` | `ltr`, `rtl`, `auto` | `auto` |
|
|
29
|
+
| `avatar` | `ReactNode` | initials placeholder |
|
|
30
|
+
| `flag` | `ReactNode` | token-colored placeholder |
|
|
31
|
+
| `icon` | `ReactNode` | plus icon |
|
|
32
|
+
| `onClose` | close-button click handler | none |
|
|
33
|
+
|
|
34
|
+
## Token Contract
|
|
35
|
+
|
|
36
|
+
The component consumes semantic design-system tokens only:
|
|
37
|
+
|
|
38
|
+
- Text and icons: `content.default`, `content.disabled`, `content.primary`, `content.onColor`, `content.muted`
|
|
39
|
+
- Backgrounds: `background.default`, `background.hover`, `background.pressed`, `background.disabled`, `background.selected`, `background.danger`
|
|
40
|
+
- Borders: `border.default`, `border.disabled`, `border.brand`, `border.focus`, `border.subtle`
|
|
41
|
+
- Shape: `shape.control`, `shape.badge`, `shape.avatar`
|
|
42
|
+
- Density: `density.controlHeight`, `density.controlPaddingX`
|
|
43
|
+
|
|
44
|
+
## Pixel Rules
|
|
45
|
+
|
|
46
|
+
- `xs` tags are `24px` tall and use body-xs medium text.
|
|
47
|
+
- `md` tags are `28px` tall and use body-sm medium text.
|
|
48
|
+
- `lg` tags are `36px` tall and use body-md medium text.
|
|
49
|
+
- Simple tags use centered text and no leading slot.
|
|
50
|
+
- Dot, flag, avatar, and icon tags use a `20px` leading slot.
|
|
51
|
+
- Close buttons are `16px` with a `12px` icon.
|
|
52
|
+
- Focused tags use a brand border plus an outside focus ring at reduced opacity.
|
|
53
|
+
- Active tags use selected/brand treatment and a stronger brand border.
|
|
54
|
+
- Disabled tags use disabled background, border, and content tokens.
|
|
55
|
+
- RTL uses logical inline padding and inherited direction so leading media, label, and close button mirror naturally.
|
|
56
|
+
|
|
57
|
+
## Install
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npx banhaten add tag
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Examples
|
|
64
|
+
|
|
65
|
+
Primary registry example: `examples/tag-demo.tsx`.
|
|
66
|
+
|
|
67
|
+
Open the live component page or run `npx banhaten docs tag` to inspect source files, install command, and examples.
|
|
68
|
+
|
|
69
|
+
## RTL Rules
|
|
70
|
+
|
|
71
|
+
- `inheritsDirection`: true
|
|
72
|
+
- `spacing`: Uses logical inline padding and inherited flex direction so the leading media, label, and close button mirror naturally.
|
|
73
|
+
- `textDirection`: Text labels use dir="auto" for short Arabic and English tag labels.
|
|
74
|
+
- `closeButton`: The close affordance is a 16px token-sized icon button using currentColor and the tag disabled state.
|
|
75
|
+
|
|
76
|
+
## Accessibility
|
|
77
|
+
|
|
78
|
+
This component relies on `@radix-ui/react-slot` for its base accessibility behavior. Keep required labels, titles, descriptions, and focusable trigger/content relationships intact when composing it.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Textarea
|
|
2
|
+
|
|
3
|
+
Textarea is the multiline field primitive for comments, notes, descriptions, and tag-style text entry. It supports label, helper and error text, default and tags modes, placeholder, filled, disabled, and RTL states.
|
|
4
|
+
|
|
5
|
+
## API
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
<Textarea label="Comments" placeholder="Add context..." />
|
|
9
|
+
<Textarea mode="tags" label="Tags" defaultValue="Design, System" />
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
| Prop | Values |
|
|
13
|
+
| --- | --- |
|
|
14
|
+
| `mode` | `default`, `tags` |
|
|
15
|
+
| `state` | `placeholder`, `filled`, `disabled` |
|
|
16
|
+
| `hasError` | `boolean` |
|
|
17
|
+
| `label`, `helperText` | `ReactNode` |
|
|
18
|
+
| `dir` | `ltr`, `rtl` |
|
|
19
|
+
|
|
20
|
+
## Token Contract
|
|
21
|
+
|
|
22
|
+
Textarea uses Banhaten field surface, text, label, helper, error, tag, spacing, border, radius, disabled, and focus tokens.
|
|
23
|
+
|
|
24
|
+
## RTL
|
|
25
|
+
|
|
26
|
+
Textarea uses `text-start`, inherited direction, and logical field layout. Labels, helper text, and tag chips mirror without physical left/right styling.
|
|
27
|
+
|
|
28
|
+
## Accessibility
|
|
29
|
+
|
|
30
|
+
Connect labels and helper/error text through component props. Use visible error text with `hasError` rather than color alone.
|
|
31
|
+
|
|
32
|
+
## Install
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npx banhaten add textarea
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Examples
|
|
39
|
+
|
|
40
|
+
Primary registry example: `examples/textarea-demo.tsx`.
|
|
41
|
+
|
|
42
|
+
Open the live component page or run `npx banhaten docs textarea` to inspect source files, install command, and examples.
|
|
43
|
+
|
|
44
|
+
## RTL Rules
|
|
45
|
+
|
|
46
|
+
- `inheritsDirection`: true
|
|
47
|
+
- `textAlignment`: Uses text-start and dir="auto" so Arabic and English content align naturally.
|
|
48
|
+
- `spacing`: Uses inherited direction and flex order so labels, helper icons, and tag chips mirror without physical left/right rules.
|