@chromvoid/uikit 0.1.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/LICENSE +8 -0
- package/README.md +96 -0
- package/dist/components/cv-accordion-item.d.ts +69 -0
- package/dist/components/cv-accordion-item.js +176 -0
- package/dist/components/cv-accordion.d.ts +79 -0
- package/dist/components/cv-accordion.js +310 -0
- package/dist/components/cv-alert-dialog.d.ts +86 -0
- package/dist/components/cv-alert-dialog.js +393 -0
- package/dist/components/cv-alert.d.ts +48 -0
- package/dist/components/cv-alert.js +156 -0
- package/dist/components/cv-badge.d.ts +56 -0
- package/dist/components/cv-badge.js +280 -0
- package/dist/components/cv-breadcrumb-item.d.ts +35 -0
- package/dist/components/cv-breadcrumb-item.js +64 -0
- package/dist/components/cv-breadcrumb.d.ts +39 -0
- package/dist/components/cv-breadcrumb.js +160 -0
- package/dist/components/cv-button.d.ts +83 -0
- package/dist/components/cv-button.js +541 -0
- package/dist/components/cv-callout.d.ts +32 -0
- package/dist/components/cv-callout.js +221 -0
- package/dist/components/cv-card.d.ts +48 -0
- package/dist/components/cv-card.js +269 -0
- package/dist/components/cv-carousel-slide.d.ts +25 -0
- package/dist/components/cv-carousel-slide.js +51 -0
- package/dist/components/cv-carousel.d.ts +96 -0
- package/dist/components/cv-carousel.js +457 -0
- package/dist/components/cv-checkbox.d.ts +84 -0
- package/dist/components/cv-checkbox.js +274 -0
- package/dist/components/cv-combobox-group.d.ts +15 -0
- package/dist/components/cv-combobox-group.js +34 -0
- package/dist/components/cv-combobox-option.d.ts +30 -0
- package/dist/components/cv-combobox-option.js +66 -0
- package/dist/components/cv-combobox.d.ts +135 -0
- package/dist/components/cv-combobox.js +834 -0
- package/dist/components/cv-command-item.d.ts +30 -0
- package/dist/components/cv-command-item.js +68 -0
- package/dist/components/cv-command-palette.d.ts +105 -0
- package/dist/components/cv-command-palette.js +578 -0
- package/dist/components/cv-context-menu.d.ts +98 -0
- package/dist/components/cv-context-menu.js +515 -0
- package/dist/components/cv-copy-button.d.ts +61 -0
- package/dist/components/cv-copy-button.js +318 -0
- package/dist/components/cv-date-picker.d.ts +161 -0
- package/dist/components/cv-date-picker.js +803 -0
- package/dist/components/cv-dialog.d.ts +89 -0
- package/dist/components/cv-dialog.js +459 -0
- package/dist/components/cv-disclosure.d.ts +57 -0
- package/dist/components/cv-disclosure.js +241 -0
- package/dist/components/cv-drawer.d.ts +102 -0
- package/dist/components/cv-drawer.js +595 -0
- package/dist/components/cv-feed-article.d.ts +26 -0
- package/dist/components/cv-feed-article.js +52 -0
- package/dist/components/cv-feed.d.ts +62 -0
- package/dist/components/cv-feed.js +310 -0
- package/dist/components/cv-grid-cell.d.ts +30 -0
- package/dist/components/cv-grid-cell.js +57 -0
- package/dist/components/cv-grid-column.d.ts +30 -0
- package/dist/components/cv-grid-column.js +43 -0
- package/dist/components/cv-grid-row.d.ts +30 -0
- package/dist/components/cv-grid-row.js +42 -0
- package/dist/components/cv-grid.d.ts +119 -0
- package/dist/components/cv-grid.js +567 -0
- package/dist/components/cv-icon.d.ts +57 -0
- package/dist/components/cv-icon.js +352 -0
- package/dist/components/cv-input.d.ts +127 -0
- package/dist/components/cv-input.js +482 -0
- package/dist/components/cv-landmark.d.ts +32 -0
- package/dist/components/cv-landmark.js +62 -0
- package/dist/components/cv-link.d.ts +22 -0
- package/dist/components/cv-link.js +99 -0
- package/dist/components/cv-listbox-group.d.ts +15 -0
- package/dist/components/cv-listbox-group.js +42 -0
- package/dist/components/cv-listbox.d.ts +81 -0
- package/dist/components/cv-listbox.js +388 -0
- package/dist/components/cv-menu-button.d.ts +118 -0
- package/dist/components/cv-menu-button.js +822 -0
- package/dist/components/cv-menu-group.d.ts +20 -0
- package/dist/components/cv-menu-group.js +48 -0
- package/dist/components/cv-menu-item.d.ts +52 -0
- package/dist/components/cv-menu-item.js +105 -0
- package/dist/components/cv-menu.d.ts +62 -0
- package/dist/components/cv-menu.js +414 -0
- package/dist/components/cv-meter.d.ts +66 -0
- package/dist/components/cv-meter.js +154 -0
- package/dist/components/cv-number.d.ts +139 -0
- package/dist/components/cv-number.js +553 -0
- package/dist/components/cv-option.d.ts +30 -0
- package/dist/components/cv-option.js +84 -0
- package/dist/components/cv-popover.d.ts +87 -0
- package/dist/components/cv-popover.js +373 -0
- package/dist/components/cv-progress-ring.d.ts +45 -0
- package/dist/components/cv-progress-ring.js +169 -0
- package/dist/components/cv-progress.d.ts +45 -0
- package/dist/components/cv-progress.js +148 -0
- package/dist/components/cv-radio-group.d.ts +79 -0
- package/dist/components/cv-radio-group.js +398 -0
- package/dist/components/cv-radio.d.ts +36 -0
- package/dist/components/cv-radio.js +123 -0
- package/dist/components/cv-select-group.d.ts +15 -0
- package/dist/components/cv-select-group.js +44 -0
- package/dist/components/cv-select-option.d.ts +30 -0
- package/dist/components/cv-select-option.js +66 -0
- package/dist/components/cv-select.d.ts +128 -0
- package/dist/components/cv-select.js +666 -0
- package/dist/components/cv-sidebar-item.d.ts +26 -0
- package/dist/components/cv-sidebar-item.js +142 -0
- package/dist/components/cv-sidebar.d.ts +171 -0
- package/dist/components/cv-sidebar.js +767 -0
- package/dist/components/cv-slider-multi-thumb.d.ts +73 -0
- package/dist/components/cv-slider-multi-thumb.js +374 -0
- package/dist/components/cv-slider.d.ts +84 -0
- package/dist/components/cv-slider.js +328 -0
- package/dist/components/cv-spinbutton.d.ts +121 -0
- package/dist/components/cv-spinbutton.js +486 -0
- package/dist/components/cv-spinner.d.ts +18 -0
- package/dist/components/cv-spinner.js +95 -0
- package/dist/components/cv-switch.d.ts +81 -0
- package/dist/components/cv-switch.js +285 -0
- package/dist/components/cv-tab-panel.d.ts +20 -0
- package/dist/components/cv-tab-panel.js +37 -0
- package/dist/components/cv-tab.d.ts +40 -0
- package/dist/components/cv-tab.js +132 -0
- package/dist/components/cv-table-cell.d.ts +31 -0
- package/dist/components/cv-table-cell.js +49 -0
- package/dist/components/cv-table-column.d.ts +37 -0
- package/dist/components/cv-table-column.js +63 -0
- package/dist/components/cv-table-row.d.ts +30 -0
- package/dist/components/cv-table-row.js +45 -0
- package/dist/components/cv-table.d.ts +147 -0
- package/dist/components/cv-table.js +607 -0
- package/dist/components/cv-tabs.d.ts +70 -0
- package/dist/components/cv-tabs.js +524 -0
- package/dist/components/cv-textarea.d.ts +108 -0
- package/dist/components/cv-textarea.js +328 -0
- package/dist/components/cv-toast-region.d.ts +39 -0
- package/dist/components/cv-toast-region.js +162 -0
- package/dist/components/cv-toast.d.ts +67 -0
- package/dist/components/cv-toast.js +315 -0
- package/dist/components/cv-toolbar-item.d.ts +25 -0
- package/dist/components/cv-toolbar-item.js +72 -0
- package/dist/components/cv-toolbar-separator.d.ts +25 -0
- package/dist/components/cv-toolbar-separator.js +45 -0
- package/dist/components/cv-toolbar.d.ts +63 -0
- package/dist/components/cv-toolbar.js +295 -0
- package/dist/components/cv-tooltip.d.ts +83 -0
- package/dist/components/cv-tooltip.js +455 -0
- package/dist/components/cv-treegrid-cell.d.ts +30 -0
- package/dist/components/cv-treegrid-cell.js +57 -0
- package/dist/components/cv-treegrid-column.d.ts +37 -0
- package/dist/components/cv-treegrid-column.js +53 -0
- package/dist/components/cv-treegrid-row.d.ts +55 -0
- package/dist/components/cv-treegrid-row.js +90 -0
- package/dist/components/cv-treegrid.d.ts +96 -0
- package/dist/components/cv-treegrid.js +632 -0
- package/dist/components/cv-treeitem.d.ts +58 -0
- package/dist/components/cv-treeitem.js +144 -0
- package/dist/components/cv-treeview.d.ts +70 -0
- package/dist/components/cv-treeview.js +396 -0
- package/dist/components/cv-window-splitter.d.ts +79 -0
- package/dist/components/cv-window-splitter.js +316 -0
- package/dist/components/index.d.ts +94 -0
- package/dist/components/index.js +79 -0
- package/dist/dialog/create-dialog-controller.d.ts +31 -0
- package/dist/dialog/create-dialog-controller.js +320 -0
- package/dist/dialog/index.d.ts +2 -0
- package/dist/dialog/index.js +1 -0
- package/dist/form-associated/FormAssociatedReatomElement.d.ts +25 -0
- package/dist/form-associated/FormAssociatedReatomElement.js +70 -0
- package/dist/form-associated/withFormAssociated.d.ts +5 -0
- package/dist/form-associated/withFormAssociated.js +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +9 -0
- package/dist/reatom-lit/ReatomLitElement.d.ts +27 -0
- package/dist/reatom-lit/ReatomLitElement.js +118 -0
- package/dist/reatom-lit/html.d.ts +4 -0
- package/dist/reatom-lit/html.js +10 -0
- package/dist/reatom-lit/index.d.ts +4 -0
- package/dist/reatom-lit/index.js +4 -0
- package/dist/reatom-lit/watch.d.ts +15 -0
- package/dist/reatom-lit/watch.js +40 -0
- package/dist/reatom-lit/withReatomElement.d.ts +4 -0
- package/dist/reatom-lit/withReatomElement.js +57 -0
- package/dist/register.d.ts +1 -0
- package/dist/register.js +84 -0
- package/dist/styles/component-styles.d.ts +4 -0
- package/dist/styles/component-styles.js +78 -0
- package/dist/theme/cv-theme-provider.d.ts +32 -0
- package/dist/theme/cv-theme-provider.js +110 -0
- package/dist/theme/index.d.ts +4 -0
- package/dist/theme/index.js +2 -0
- package/dist/theme/theme-engine.d.ts +4 -0
- package/dist/theme/theme-engine.js +67 -0
- package/dist/theme/tokens.css +265 -0
- package/dist/theme/types.d.ts +7 -0
- package/dist/theme/types.js +1 -0
- package/dist/toast/create-toast-controller.d.ts +12 -0
- package/dist/toast/create-toast-controller.js +12 -0
- package/dist/toast/index.d.ts +2 -0
- package/dist/toast/index.js +1 -0
- package/package.json +146 -0
- package/specs/_template.md +110 -0
- package/specs/components/accordion.md +207 -0
- package/specs/components/alert.md +83 -0
- package/specs/components/badge.md +183 -0
- package/specs/components/breadcrumb.md +152 -0
- package/specs/components/button.md +227 -0
- package/specs/components/callout.md +153 -0
- package/specs/components/card.md +192 -0
- package/specs/components/carousel.md +232 -0
- package/specs/components/checkbox.md +141 -0
- package/specs/components/combobox.md +427 -0
- package/specs/components/context-menu.md +375 -0
- package/specs/components/copy-button.md +236 -0
- package/specs/components/date-picker.md +290 -0
- package/specs/components/dialog.md +184 -0
- package/specs/components/disclosure.md +151 -0
- package/specs/components/drawer.md +216 -0
- package/specs/components/feed.md +266 -0
- package/specs/components/grid.md +423 -0
- package/specs/components/input.md +237 -0
- package/specs/components/landmark.md +92 -0
- package/specs/components/link.md +117 -0
- package/specs/components/listbox.md +327 -0
- package/specs/components/menu.md +508 -0
- package/specs/components/meter.md +148 -0
- package/specs/components/number.md +268 -0
- package/specs/components/option.md +167 -0
- package/specs/components/popover.md +207 -0
- package/specs/components/progress-ring.md +134 -0
- package/specs/components/progress.md +110 -0
- package/specs/components/radio.md +208 -0
- package/specs/components/select.md +305 -0
- package/specs/components/sidebar.md +204 -0
- package/specs/components/spinbutton.md +157 -0
- package/specs/components/spinner.md +83 -0
- package/specs/components/switch.md +145 -0
- package/specs/components/table.md +372 -0
- package/specs/components/tabs.md +242 -0
- package/specs/components/textarea.md +166 -0
- package/specs/components/theme.md +364 -0
- package/specs/components/toast.md +198 -0
- package/specs/components/toolbar.md +258 -0
- package/specs/components/tooltip.md +152 -0
- package/specs/components/treegrid.md +363 -0
- package/specs/components/treeview.md +263 -0
- package/specs/components/window-splitter.md +225 -0
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
# cv-table
|
|
2
|
+
|
|
3
|
+
Data table for displaying structured tabular content with optional sorting, row selection, and grid-style keyboard navigation.
|
|
4
|
+
|
|
5
|
+
**Headless:** [`createTable`](https://github.com/chromvoid/headless-ui/blob/main/specs/components/table.md)
|
|
6
|
+
|
|
7
|
+
## Anatomy
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
<cv-table> (host)
|
|
11
|
+
└── <div part="base" role="table|grid">
|
|
12
|
+
├── <div role="rowgroup" part="head">
|
|
13
|
+
│ └── <div role="row" part="head-row">
|
|
14
|
+
│ └── <slot name="columns"> ← accepts <cv-table-column> children
|
|
15
|
+
└── <div role="rowgroup" part="body" @cv-table-row-slotchange>
|
|
16
|
+
└── <slot name="rows"> ← accepts <cv-table-row> children
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Attributes
|
|
20
|
+
|
|
21
|
+
| Attribute | Type | Default | Description |
|
|
22
|
+
| -------------------- | ------- | -------- | --------------------------------------------------------------------------------- |
|
|
23
|
+
| `sort-column` | String | `""` | Currently sorted column id (reflected) |
|
|
24
|
+
| `sort-direction` | String | `"none"` | Sort direction: `none` \| `ascending` \| `descending` (reflected) |
|
|
25
|
+
| `aria-label` | String | `""` | Accessible label for the table root |
|
|
26
|
+
| `aria-labelledby` | String | `""` | `aria-labelledby` reference for the table root |
|
|
27
|
+
| `total-column-count` | Number | `0` | Logical column count for virtualization (reflected) |
|
|
28
|
+
| `total-row-count` | Number | `0` | Logical row count for virtualization (reflected) |
|
|
29
|
+
| `selectable` | String | `""` | Row selection mode: `single` \| `multi`. Empty or absent disables selection. |
|
|
30
|
+
| `interactive` | Boolean | `false` | Enables grid navigation mode (switches role to `grid`, activates roving tabindex) |
|
|
31
|
+
| `sticky-header` | Boolean | `false` | Makes the header row stick to the top when scrolling |
|
|
32
|
+
| `striped` | Boolean | `false` | Alternating row background colors |
|
|
33
|
+
| `compact` | Boolean | `false` | Reduced cell padding for denser display |
|
|
34
|
+
| `bordered` | Boolean | `false` | Visible borders between all cells |
|
|
35
|
+
| `page-size` | Number | `10` | Rows per page for PageUp/PageDown in grid navigation mode (minimum 1) |
|
|
36
|
+
|
|
37
|
+
## Slots
|
|
38
|
+
|
|
39
|
+
| Slot | Description |
|
|
40
|
+
| --------- | ---------------------------------------------------- |
|
|
41
|
+
| `columns` | `<cv-table-column>` children defining column headers |
|
|
42
|
+
| `rows` | `<cv-table-row>` children containing table data rows |
|
|
43
|
+
|
|
44
|
+
## CSS Parts
|
|
45
|
+
|
|
46
|
+
| Part | Element | Description |
|
|
47
|
+
| ---------- | ------- | ----------------------------------------------------- |
|
|
48
|
+
| `base` | `<div>` | Root table/grid element with role and ARIA attributes |
|
|
49
|
+
| `head` | `<div>` | Header rowgroup wrapper |
|
|
50
|
+
| `head-row` | `<div>` | Header row containing column slots |
|
|
51
|
+
| `body` | `<div>` | Body rowgroup wrapper containing row slots |
|
|
52
|
+
|
|
53
|
+
## CSS Custom Properties
|
|
54
|
+
|
|
55
|
+
| Property | Default | Description |
|
|
56
|
+
| ---------------------------------------- | ------------------------------------------------------------------------ | ---------------------------------------------- |
|
|
57
|
+
| `--cv-table-border-radius` | `var(--cv-radius-md, 10px)` | Border radius of the table container |
|
|
58
|
+
| `--cv-table-border-color` | `var(--cv-color-border, #2a3245)` | Border color of the table and cells |
|
|
59
|
+
| `--cv-table-background` | `var(--cv-color-surface, #141923)` | Table background color |
|
|
60
|
+
| `--cv-table-header-background` | `color-mix(in oklab, var(--cv-color-surface, #141923) 82%, transparent)` | Header row background |
|
|
61
|
+
| `--cv-table-stripe-background` | `color-mix(in oklab, var(--cv-color-surface, #141923) 90%, transparent)` | Background for alternating rows when `striped` |
|
|
62
|
+
| `--cv-table-row-selected-background` | `color-mix(in oklab, var(--cv-color-primary, #65d7ff) 12%, transparent)` | Background for selected rows |
|
|
63
|
+
| `--cv-table-cell-padding-block` | `var(--cv-space-2, 8px)` | Vertical cell padding |
|
|
64
|
+
| `--cv-table-cell-padding-inline` | `var(--cv-space-3, 12px)` | Horizontal cell padding |
|
|
65
|
+
| `--cv-table-compact-cell-padding-block` | `var(--cv-space-1, 4px)` | Vertical cell padding in compact mode |
|
|
66
|
+
| `--cv-table-compact-cell-padding-inline` | `var(--cv-space-2, 8px)` | Horizontal cell padding in compact mode |
|
|
67
|
+
| `--cv-table-focus-outline-color` | `var(--cv-color-primary, #65d7ff)` | Focus ring color for grid navigation |
|
|
68
|
+
|
|
69
|
+
Additionally, component styles depend on theme tokens through fallback values:
|
|
70
|
+
|
|
71
|
+
| Theme Property | Default | Description |
|
|
72
|
+
| -------------------- | --------- | ---------------------------------------------------- |
|
|
73
|
+
| `--cv-color-border` | `#2a3245` | Base border color |
|
|
74
|
+
| `--cv-color-surface` | `#141923` | Surface background color |
|
|
75
|
+
| `--cv-color-text` | `#e8ecf6` | Default text color |
|
|
76
|
+
| `--cv-color-primary` | `#65d7ff` | Primary accent color (focus, selection, active sort) |
|
|
77
|
+
| `--cv-radius-md` | `10px` | Border radius fallback |
|
|
78
|
+
| `--cv-space-1` | `4px` | Small spacing scale |
|
|
79
|
+
| `--cv-space-2` | `8px` | Medium spacing scale |
|
|
80
|
+
| `--cv-space-3` | `12px` | Medium-large spacing scale |
|
|
81
|
+
|
|
82
|
+
## Visual States
|
|
83
|
+
|
|
84
|
+
| Host selector | Description |
|
|
85
|
+
| ------------------------ | -------------------------------------------------------------- |
|
|
86
|
+
| `:host([striped])` | Alternating row backgrounds via `--cv-table-stripe-background` |
|
|
87
|
+
| `:host([compact])` | Reduced cell padding via compact custom properties |
|
|
88
|
+
| `:host([bordered])` | Visible borders between all cells |
|
|
89
|
+
| `:host([sticky-header])` | Header row uses `position: sticky; top: 0` |
|
|
90
|
+
| `:host([interactive])` | Grid navigation mode active; focus ring on active cell |
|
|
91
|
+
| `:host([selectable])` | Row selection enabled; selected rows highlighted |
|
|
92
|
+
|
|
93
|
+
## Events
|
|
94
|
+
|
|
95
|
+
| Event | Detail | Description |
|
|
96
|
+
| --------------------- | ------------------------------------------------------------------- | ------------------------------------------------------- |
|
|
97
|
+
| `cv-input` | `{sortColumnId: string \| null, sortDirection: TableSortDirection}` | Fires on sort interaction (before commit) |
|
|
98
|
+
| `cv-change` | `{sortColumnId: string \| null, sortDirection: TableSortDirection}` | Fires when sort state changes |
|
|
99
|
+
| `cv-selection-change` | `{selectedRowIds: string[], selectable: 'single' \| 'multi'}` | Fires when row selection changes via user interaction |
|
|
100
|
+
| `cv-focus-change` | `{rowIndex: number \| null, columnIndex: number \| null}` | Fires when focused cell changes in grid navigation mode |
|
|
101
|
+
|
|
102
|
+
Sort events (`cv-input` / `cv-change`) fire only when sort state changes due to user interaction (column header click or keyboard activation). They share the same detail shape and follow the convention where `cv-input` fires on interaction and `cv-change` fires on committed state change.
|
|
103
|
+
|
|
104
|
+
`cv-selection-change` fires when selection changes due to user interaction (row click, Space key, Ctrl+A). It does not fire for programmatic attribute changes.
|
|
105
|
+
|
|
106
|
+
`cv-focus-change` fires when the focused cell changes during grid navigation. It does not fire for programmatic `setFocusedCell` calls.
|
|
107
|
+
|
|
108
|
+
## Reactive State Mapping
|
|
109
|
+
|
|
110
|
+
`cv-table` is a visual adapter over headless `createTable`.
|
|
111
|
+
|
|
112
|
+
### UIKit Property to Headless Binding
|
|
113
|
+
|
|
114
|
+
| UIKit Property | Direction | Headless Binding |
|
|
115
|
+
| -------------------- | ------------- | ---------------------------------------------------------------------------------- |
|
|
116
|
+
| `sort-column` | attr → action | `actions.sortBy(value, direction)` or `actions.clearSort()` when attribute changes |
|
|
117
|
+
| `sort-direction` | attr → action | `actions.sortBy(column, value)` or `actions.clearSort()` when attribute changes |
|
|
118
|
+
| `aria-label` | attr → option | passed as `ariaLabel` in `createTable(options)` |
|
|
119
|
+
| `aria-labelledby` | attr → option | passed as `ariaLabelledBy` in `createTable(options)` |
|
|
120
|
+
| `total-column-count` | attr → option | passed as `totalColumnCount` in `createTable(options)` |
|
|
121
|
+
| `total-row-count` | attr → option | passed as `totalRowCount` in `createTable(options)` |
|
|
122
|
+
| `selectable` | attr → option | passed as `selectable` in `createTable(options)` |
|
|
123
|
+
| `interactive` | attr → option | passed as `interactive` in `createTable(options)` |
|
|
124
|
+
| `page-size` | attr → option | passed as `pageSize` in `createTable(options)` |
|
|
125
|
+
|
|
126
|
+
### Headless State to DOM Reflection
|
|
127
|
+
|
|
128
|
+
| Headless State | Direction | DOM Reflection |
|
|
129
|
+
| ---------------------------- | ------------ | ------------------------------------------------------- |
|
|
130
|
+
| `state.sortColumnId()` | state → attr | `cv-table[sort-column]` host attribute |
|
|
131
|
+
| `state.sortDirection()` | state → attr | `cv-table[sort-direction]` host attribute |
|
|
132
|
+
| `state.selectedRowIds()` | state → attr | `cv-table-row[selected]` boolean attribute on each row |
|
|
133
|
+
| `state.focusedRowIndex()` | state → DOM | Active cell receives `tabindex="0"` and `.focus()` call |
|
|
134
|
+
| `state.focusedColumnIndex()` | state → DOM | Active cell receives `tabindex="0"` and `.focus()` call |
|
|
135
|
+
|
|
136
|
+
### Headless Actions Called
|
|
137
|
+
|
|
138
|
+
| Action | UIKit Trigger |
|
|
139
|
+
| ----------------------------------------------- | --------------------------------------------------------------------- |
|
|
140
|
+
| `actions.sortBy(columnId, direction)` | Column header click or keyboard activation cycles sort direction |
|
|
141
|
+
| `actions.clearSort()` | Sort direction cycles back to `none` |
|
|
142
|
+
| `actions.selectRow(rowId)` | Row click when `selectable="single"` |
|
|
143
|
+
| `actions.toggleRowSelection(rowId)` | Row click when `selectable="multi"`, or Space key in interactive mode |
|
|
144
|
+
| `actions.selectAllRows()` | Ctrl/Cmd+A in interactive mode when `selectable="multi"` |
|
|
145
|
+
| `actions.clearSelection()` | Programmatic API |
|
|
146
|
+
| `actions.deselectRow(rowId)` | Programmatic API |
|
|
147
|
+
| `actions.handleKeyDown(event)` | `keydown` event on the grid root when `interactive` is `true` |
|
|
148
|
+
| `actions.moveFocus(direction)` | Arrow key navigation (delegated via `handleKeyDown`) |
|
|
149
|
+
| `actions.moveFocusToStart()` | Ctrl/Cmd+Home (delegated via `handleKeyDown`) |
|
|
150
|
+
| `actions.moveFocusToEnd()` | Ctrl/Cmd+End (delegated via `handleKeyDown`) |
|
|
151
|
+
| `actions.moveFocusToRowStart()` | Home key (delegated via `handleKeyDown`) |
|
|
152
|
+
| `actions.moveFocusToRowEnd()` | End key (delegated via `handleKeyDown`) |
|
|
153
|
+
| `actions.pageUp()` | PageUp key (delegated via `handleKeyDown`) |
|
|
154
|
+
| `actions.pageDown()` | PageDown key (delegated via `handleKeyDown`) |
|
|
155
|
+
| `actions.setFocusedCell(rowIndex, columnIndex)` | Cell click in interactive mode |
|
|
156
|
+
|
|
157
|
+
### Headless Contracts Spread
|
|
158
|
+
|
|
159
|
+
| Contract | UIKit Target |
|
|
160
|
+
| --------------------------------------------- | ------------------------------------------------ |
|
|
161
|
+
| `contracts.getTableProps()` | Spread onto `[part="base"]` root element |
|
|
162
|
+
| `contracts.getRowProps(rowId)` | Spread onto each `cv-table-row` element |
|
|
163
|
+
| `contracts.getCellProps(rowId, colId, span?)` | Spread onto each `cv-table-cell` element |
|
|
164
|
+
| `contracts.getColumnHeaderProps(colId)` | Spread onto each `cv-table-column` element |
|
|
165
|
+
| `contracts.getRowHeaderProps(rowId, colId)` | Spread onto `cv-table-cell[row-header]` elements |
|
|
166
|
+
|
|
167
|
+
### UIKit-Only Concerns (Not in Headless)
|
|
168
|
+
|
|
169
|
+
- **Display variants** (`striped`, `compact`, `bordered`): CSS-only visual modifiers, not part of headless state.
|
|
170
|
+
- **Sticky header** (`sticky-header`): CSS `position: sticky` on header, not part of headless state.
|
|
171
|
+
- **Visual selection indicators**: Row background highlighting for selected rows.
|
|
172
|
+
- **DOM focus management**: Calling `.focus()` on cells when `focusedRowIndex`/`focusedColumnIndex` change in headless state.
|
|
173
|
+
- **`preventDefault()`**: Called on keyboard events handled by `handleKeyDown` to prevent scrolling.
|
|
174
|
+
- **`cv-input` / `cv-change` / `cv-selection-change` / `cv-focus-change` events**: Custom DOM events dispatched by the UIKit wrapper, not part of the headless model.
|
|
175
|
+
- **Auto-generated fallback values**: `value` attributes on columns and rows receive auto-generated fallbacks (`column-N`, `row-N`) when not explicitly set.
|
|
176
|
+
- **Slot-based model rebuild**: Model is rebuilt from slotted children on `slotchange` events.
|
|
177
|
+
|
|
178
|
+
UIKit does not own sort, selection, or navigation logic; headless state is the source of truth.
|
|
179
|
+
|
|
180
|
+
## Usage
|
|
181
|
+
|
|
182
|
+
```html
|
|
183
|
+
<!-- Basic table -->
|
|
184
|
+
<cv-table aria-label="Users">
|
|
185
|
+
<cv-table-column value="name" label="Name" sortable></cv-table-column>
|
|
186
|
+
<cv-table-column value="email" label="Email"></cv-table-column>
|
|
187
|
+
<cv-table-column value="role" label="Role"></cv-table-column>
|
|
188
|
+
|
|
189
|
+
<cv-table-row value="user-1">
|
|
190
|
+
<cv-table-cell column="name" row-header>Alice</cv-table-cell>
|
|
191
|
+
<cv-table-cell column="email">alice@example.com</cv-table-cell>
|
|
192
|
+
<cv-table-cell column="role">Admin</cv-table-cell>
|
|
193
|
+
</cv-table-row>
|
|
194
|
+
<cv-table-row value="user-2">
|
|
195
|
+
<cv-table-cell column="name" row-header>Bob</cv-table-cell>
|
|
196
|
+
<cv-table-cell column="email">bob@example.com</cv-table-cell>
|
|
197
|
+
<cv-table-cell column="role">Editor</cv-table-cell>
|
|
198
|
+
</cv-table-row>
|
|
199
|
+
</cv-table>
|
|
200
|
+
|
|
201
|
+
<!-- Striped, compact, bordered with sticky header -->
|
|
202
|
+
<cv-table aria-label="Log entries" striped compact bordered sticky-header>
|
|
203
|
+
<cv-table-column value="timestamp" label="Time" sortable></cv-table-column>
|
|
204
|
+
<cv-table-column value="level" label="Level"></cv-table-column>
|
|
205
|
+
<cv-table-column value="message" label="Message"></cv-table-column>
|
|
206
|
+
|
|
207
|
+
<cv-table-row value="log-1">
|
|
208
|
+
<cv-table-cell column="timestamp">12:01:33</cv-table-cell>
|
|
209
|
+
<cv-table-cell column="level">INFO</cv-table-cell>
|
|
210
|
+
<cv-table-cell column="message">Server started</cv-table-cell>
|
|
211
|
+
</cv-table-row>
|
|
212
|
+
</cv-table>
|
|
213
|
+
|
|
214
|
+
<!-- Selectable rows (multi) -->
|
|
215
|
+
<cv-table aria-label="Files" selectable="multi">
|
|
216
|
+
<cv-table-column value="name" label="Name"></cv-table-column>
|
|
217
|
+
<cv-table-column value="size" label="Size"></cv-table-column>
|
|
218
|
+
|
|
219
|
+
<cv-table-row value="file-1">
|
|
220
|
+
<cv-table-cell column="name">readme.md</cv-table-cell>
|
|
221
|
+
<cv-table-cell column="size">4 KB</cv-table-cell>
|
|
222
|
+
</cv-table-row>
|
|
223
|
+
<cv-table-row value="file-2">
|
|
224
|
+
<cv-table-cell column="name">index.ts</cv-table-cell>
|
|
225
|
+
<cv-table-cell column="size">12 KB</cv-table-cell>
|
|
226
|
+
</cv-table-row>
|
|
227
|
+
</cv-table>
|
|
228
|
+
|
|
229
|
+
<!-- Interactive grid with selection -->
|
|
230
|
+
<cv-table aria-label="Spreadsheet" interactive selectable="multi" page-size="5">
|
|
231
|
+
<cv-table-column value="a" label="A"></cv-table-column>
|
|
232
|
+
<cv-table-column value="b" label="B"></cv-table-column>
|
|
233
|
+
<cv-table-column value="c" label="C"></cv-table-column>
|
|
234
|
+
|
|
235
|
+
<cv-table-row value="row-1">
|
|
236
|
+
<cv-table-cell column="a">1</cv-table-cell>
|
|
237
|
+
<cv-table-cell column="b">2</cv-table-cell>
|
|
238
|
+
<cv-table-cell column="c">3</cv-table-cell>
|
|
239
|
+
</cv-table-row>
|
|
240
|
+
<cv-table-row value="row-2">
|
|
241
|
+
<cv-table-cell column="a">4</cv-table-cell>
|
|
242
|
+
<cv-table-cell column="b">5</cv-table-cell>
|
|
243
|
+
<cv-table-cell column="c">6</cv-table-cell>
|
|
244
|
+
</cv-table-row>
|
|
245
|
+
</cv-table>
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## Child Elements
|
|
249
|
+
|
|
250
|
+
### cv-table-column
|
|
251
|
+
|
|
252
|
+
Column header definition within the table header row.
|
|
253
|
+
|
|
254
|
+
#### Anatomy
|
|
255
|
+
|
|
256
|
+
```
|
|
257
|
+
<cv-table-column> (host)
|
|
258
|
+
└── <span part="base">
|
|
259
|
+
├── <slot>${label}</slot>
|
|
260
|
+
└── sort indicator (▲/▼) ← only when sort-direction is ascending/descending
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
#### Attributes
|
|
264
|
+
|
|
265
|
+
| Attribute | Type | Default | Description |
|
|
266
|
+
| ---------------- | ------- | -------- | ----------------------------------------------------------------------------- |
|
|
267
|
+
| `value` | String | `""` | Unique column identifier. Auto-generated as `column-N` if empty. |
|
|
268
|
+
| `label` | String | `""` | Column header text (used as default slot fallback) |
|
|
269
|
+
| `index` | Number | `0` | 1-based aria-colindex override for virtualized tables |
|
|
270
|
+
| `sortable` | Boolean | `false` | Enables sort interaction on this column |
|
|
271
|
+
| `sort-direction` | String | `"none"` | Current sort state: `none` \| `ascending` \| `descending` (managed by parent) |
|
|
272
|
+
|
|
273
|
+
#### Slots
|
|
274
|
+
|
|
275
|
+
| Slot | Description |
|
|
276
|
+
| ----------- | ------------------------------------------------------- |
|
|
277
|
+
| `(default)` | Column header content (falls back to `label` attribute) |
|
|
278
|
+
|
|
279
|
+
#### CSS Parts
|
|
280
|
+
|
|
281
|
+
| Part | Element | Description |
|
|
282
|
+
| ------ | -------- | ------------------------------------------------------- |
|
|
283
|
+
| `base` | `<span>` | Inline-flex wrapper containing label and sort indicator |
|
|
284
|
+
|
|
285
|
+
#### Visual States
|
|
286
|
+
|
|
287
|
+
| Host selector | Description |
|
|
288
|
+
| -------------------------------------- | ------------------------------------------------------ |
|
|
289
|
+
| `:host([sortable])` | `cursor: pointer` indicating interactive sort |
|
|
290
|
+
| `:host([sort-direction="ascending"])` | Primary color text with ascending indicator (▲) |
|
|
291
|
+
| `:host([sort-direction="descending"])` | Primary color text with descending indicator (▼) |
|
|
292
|
+
| `:host(:focus-visible)` | Focus ring for keyboard activation of sortable columns |
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
### cv-table-row
|
|
297
|
+
|
|
298
|
+
Data row containing cells within the table body.
|
|
299
|
+
|
|
300
|
+
#### Anatomy
|
|
301
|
+
|
|
302
|
+
```
|
|
303
|
+
<cv-table-row> (host)
|
|
304
|
+
└── <slot> ← accepts <cv-table-cell> children
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
#### Attributes
|
|
308
|
+
|
|
309
|
+
| Attribute | Type | Default | Description |
|
|
310
|
+
| ---------- | ------- | ------- | ------------------------------------------------------------ |
|
|
311
|
+
| `value` | String | `""` | Unique row identifier. Auto-generated as `row-N` if empty. |
|
|
312
|
+
| `index` | Number | `0` | 1-based aria-rowindex override for virtualized tables |
|
|
313
|
+
| `selected` | Boolean | `false` | Whether this row is selected (reflected from headless state) |
|
|
314
|
+
|
|
315
|
+
#### CSS Parts
|
|
316
|
+
|
|
317
|
+
| Part | Element | Description |
|
|
318
|
+
| ------ | ------- | --------------------------------------- |
|
|
319
|
+
| `base` | host | Row element (uses `display: table-row`) |
|
|
320
|
+
|
|
321
|
+
#### Events
|
|
322
|
+
|
|
323
|
+
| Event | Detail | Description |
|
|
324
|
+
| ------------------------- | ------ | ---------------------------------------------------------------------------- |
|
|
325
|
+
| `cv-table-row-slotchange` | -- | Fires when slotted cell children change; bubbles to parent for model rebuild |
|
|
326
|
+
|
|
327
|
+
#### Visual States
|
|
328
|
+
|
|
329
|
+
| Host selector | Description |
|
|
330
|
+
| ------------------- | ---------------------------------------------------------------- |
|
|
331
|
+
| `:host([selected])` | Selected row background via `--cv-table-row-selected-background` |
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
### cv-table-cell
|
|
336
|
+
|
|
337
|
+
Individual data cell within a table row.
|
|
338
|
+
|
|
339
|
+
#### Anatomy
|
|
340
|
+
|
|
341
|
+
```
|
|
342
|
+
<cv-table-cell> (host)
|
|
343
|
+
└── <slot>
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
#### Attributes
|
|
347
|
+
|
|
348
|
+
| Attribute | Type | Default | Description |
|
|
349
|
+
| ------------ | ------- | ------- | ----------------------------------------------------------------------------- |
|
|
350
|
+
| `column` | String | `""` | Column id this cell belongs to. Auto-resolved from positional index if empty. |
|
|
351
|
+
| `row-header` | Boolean | `false` | Marks this cell as a row header (`role="rowheader"`) |
|
|
352
|
+
| `colspan` | Number | `0` | Column span (applied as `aria-colspan` when >= 2) |
|
|
353
|
+
| `rowspan` | Number | `0` | Row span (applied as `aria-rowspan` when >= 2) |
|
|
354
|
+
|
|
355
|
+
#### Slots
|
|
356
|
+
|
|
357
|
+
| Slot | Description |
|
|
358
|
+
| ----------- | ------------ |
|
|
359
|
+
| `(default)` | Cell content |
|
|
360
|
+
|
|
361
|
+
#### CSS Parts
|
|
362
|
+
|
|
363
|
+
| Part | Element | Description |
|
|
364
|
+
| ------ | ------- | ----------------------------------------- |
|
|
365
|
+
| `base` | host | Cell element (uses `display: table-cell`) |
|
|
366
|
+
|
|
367
|
+
#### Visual States
|
|
368
|
+
|
|
369
|
+
| Host selector | Description |
|
|
370
|
+
| ----------------------------- | ----------------------------------------------------------------------------------- |
|
|
371
|
+
| `:host([row-header])` | Bold text (`font-weight: 600`) for row header cells |
|
|
372
|
+
| `:host([data-active="true"])` | Active cell in grid navigation mode (receives `tabindex="0"` via headless contract) |
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
# cv-tabs
|
|
2
|
+
|
|
3
|
+
Tabbed interface for switching between related content panels.
|
|
4
|
+
|
|
5
|
+
**Headless:** [`createTabs`](https://github.com/chromvoid/headless-ui/blob/main/specs/components/tabs.md)
|
|
6
|
+
|
|
7
|
+
## Anatomy
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
<cv-tabs> (host)
|
|
11
|
+
└── <div part="base">
|
|
12
|
+
├── <div part="list" role="tablist">
|
|
13
|
+
│ ├── <slot name="nav"> ← accepts <cv-tab> children
|
|
14
|
+
│ └── <div part="indicator"> ← animated active indicator
|
|
15
|
+
└── <div part="panels">
|
|
16
|
+
└── <slot> ← accepts <cv-tab-panel> children
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Attributes
|
|
20
|
+
|
|
21
|
+
| Attribute | Type | Default | Description |
|
|
22
|
+
| ----------------- | ------ | -------------- | ----------------------------------- |
|
|
23
|
+
| `value` | String | `""` | Currently selected tab value |
|
|
24
|
+
| `orientation` | String | `"horizontal"` | Layout: `horizontal` \| `vertical` |
|
|
25
|
+
| `activation-mode` | String | `"automatic"` | Activation: `automatic` \| `manual` |
|
|
26
|
+
| `aria-label` | String | `""` | Accessible label for the tablist |
|
|
27
|
+
|
|
28
|
+
## Slots
|
|
29
|
+
|
|
30
|
+
| Slot | Description |
|
|
31
|
+
| ----------- | ------------------------- |
|
|
32
|
+
| `nav` | `<cv-tab>` children |
|
|
33
|
+
| `(default)` | `<cv-tab-panel>` children |
|
|
34
|
+
|
|
35
|
+
## CSS Parts
|
|
36
|
+
|
|
37
|
+
| Part | Element | Description |
|
|
38
|
+
| ----------- | ------- | ----------------------------------------------------------- |
|
|
39
|
+
| `base` | `<div>` | Root layout container |
|
|
40
|
+
| `list` | `<div>` | Tablist wrapper |
|
|
41
|
+
| `indicator` | `<div>` | Animated active indicator positioned under the selected tab |
|
|
42
|
+
| `panels` | `<div>` | Panel container |
|
|
43
|
+
|
|
44
|
+
## CSS Custom Properties
|
|
45
|
+
|
|
46
|
+
| Property | Default | Description |
|
|
47
|
+
| --------------------------- | ---------------------------------- | -------------------------------------------------------------------------------------- |
|
|
48
|
+
| `--cv-tabs-indicator-color` | `var(--cv-color-primary, #65d7ff)` | Color of the active indicator |
|
|
49
|
+
| `--cv-tabs-indicator-size` | `3px` | Indicator thickness: height for horizontal orientation, width for vertical orientation |
|
|
50
|
+
|
|
51
|
+
Additionally, component styles depend on theme tokens through fallback values:
|
|
52
|
+
|
|
53
|
+
| Theme Property | Default | Description |
|
|
54
|
+
| -------------------- | --------- | ------------------------------- |
|
|
55
|
+
| `--cv-space-1` | `4px` | Gap between tabs, list padding |
|
|
56
|
+
| `--cv-space-2` | `8px` | Gap between list and panels |
|
|
57
|
+
| `--cv-space-3` | `12px` | Panels padding |
|
|
58
|
+
| `--cv-radius-md` | `10px` | List and panels border radius |
|
|
59
|
+
| `--cv-color-border` | `#2a3245` | List and panels border |
|
|
60
|
+
| `--cv-color-surface` | `#141923` | List and panels background |
|
|
61
|
+
| `--cv-color-primary` | `#65d7ff` | Focus and selected accent color |
|
|
62
|
+
|
|
63
|
+
## Visual States
|
|
64
|
+
|
|
65
|
+
| Host selector | Description |
|
|
66
|
+
| --------------------------------- | --------------------------------------------------- |
|
|
67
|
+
| `:host([orientation="vertical"])` | Layout switches to vertical tablist + panel columns |
|
|
68
|
+
|
|
69
|
+
## Events
|
|
70
|
+
|
|
71
|
+
| Event | Detail | Description |
|
|
72
|
+
| ----------- | -------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
|
|
73
|
+
| `cv-input` | `{activeTabId: string \| null, selectedTabId: string \| null}` | Fires on any active or selected state change, including active-only changes that do not change selection |
|
|
74
|
+
| `cv-change` | `{activeTabId: string \| null, selectedTabId: string \| null}` | Fires when selected tab changes |
|
|
75
|
+
|
|
76
|
+
`cv-input` fires on every user-driven state transition (active or selected). `cv-change` fires only when `selectedTabId` changes. Both events share the same detail shape. In `manual` activation mode, arrow-key navigation fires `cv-input` (active change) without `cv-change`; pressing `Enter`/`Space` fires both `cv-input` and `cv-change`.
|
|
77
|
+
|
|
78
|
+
## Reactive State Mapping
|
|
79
|
+
|
|
80
|
+
`cv-tabs` is a visual adapter over headless `createTabs` reactive state.
|
|
81
|
+
|
|
82
|
+
### UIKit Property to Headless Binding
|
|
83
|
+
|
|
84
|
+
| UIKit Property | Direction | Headless Binding |
|
|
85
|
+
| ----------------- | ------------- | ------------------------------------------------------ |
|
|
86
|
+
| `value` | attr → action | `actions.select(value)` when `value` attribute changes |
|
|
87
|
+
| `orientation` | attr → option | passed as `orientation` in `createTabs(options)` |
|
|
88
|
+
| `activation-mode` | attr → option | passed as `activationMode` in `createTabs(options)` |
|
|
89
|
+
| `aria-label` | attr → option | passed as `ariaLabel` in `createTabs(options)` |
|
|
90
|
+
|
|
91
|
+
### Headless State to DOM Reflection
|
|
92
|
+
|
|
93
|
+
| Headless State | Direction | DOM Reflection |
|
|
94
|
+
| ----------------------- | ------------ | --------------------------------------------------------------------- |
|
|
95
|
+
| `state.selectedTabId()` | state → attr | `cv-tabs[value]` host attribute |
|
|
96
|
+
| `state.activeTabId()` | state → attr | `cv-tab[active]` boolean attribute on the active tab element |
|
|
97
|
+
| `state.selectedTabId()` | state → attr | `cv-tab[selected]` boolean attribute on the selected tab element |
|
|
98
|
+
| `state.selectedTabId()` | state → attr | `cv-tab-panel[selected]` and `cv-tab-panel[hidden]` on panel elements |
|
|
99
|
+
|
|
100
|
+
### Headless Actions Called
|
|
101
|
+
|
|
102
|
+
| Action | UIKit Trigger |
|
|
103
|
+
| ------------------------------ | --------------------------------------------- |
|
|
104
|
+
| `actions.select(id)` | Tab is clicked or tapped (pointer activation) |
|
|
105
|
+
| `actions.handleKeyDown(event)` | `keydown` event on a tab element |
|
|
106
|
+
|
|
107
|
+
### Headless Contracts Spread
|
|
108
|
+
|
|
109
|
+
| Contract | UIKit Target |
|
|
110
|
+
| ----------------------------- | ------------------------------------------------------------ |
|
|
111
|
+
| `contracts.getTabListProps()` | Spread onto `[part="list"]` element |
|
|
112
|
+
| `contracts.getTabProps(id)` | Spread onto each `cv-tab` element (via attribute sync) |
|
|
113
|
+
| `contracts.getPanelProps(id)` | Spread onto each `cv-tab-panel` element (via attribute sync) |
|
|
114
|
+
|
|
115
|
+
### UIKit-Only Concerns (Not in Headless)
|
|
116
|
+
|
|
117
|
+
- **Active indicator**: Positioned and animated at the UIKit layer using `selectedTabId` to determine which tab to highlight.
|
|
118
|
+
- **Closable tabs**: Close button rendering and close orchestration are UIKit concerns. Headless handles selection fallback implicitly through model rebuild with an updated tab list (without the closed tab).
|
|
119
|
+
- **`cv-input` / `cv-change` events**: Custom DOM events dispatched by the UIKit wrapper, not part of the headless model.
|
|
120
|
+
|
|
121
|
+
UIKit does not own tab selection logic; headless state is the source of truth.
|
|
122
|
+
|
|
123
|
+
## Usage
|
|
124
|
+
|
|
125
|
+
```html
|
|
126
|
+
<cv-tabs value="tab-1">
|
|
127
|
+
<cv-tab slot="nav" value="tab-1">First</cv-tab>
|
|
128
|
+
<cv-tab slot="nav" value="tab-2">Second</cv-tab>
|
|
129
|
+
<cv-tab slot="nav" value="tab-3" disabled>Disabled</cv-tab>
|
|
130
|
+
|
|
131
|
+
<cv-tab-panel tab="tab-1">Content for first tab.</cv-tab-panel>
|
|
132
|
+
<cv-tab-panel tab="tab-2">Content for second tab.</cv-tab-panel>
|
|
133
|
+
<cv-tab-panel tab="tab-3">Content for disabled tab.</cv-tab-panel>
|
|
134
|
+
</cv-tabs>
|
|
135
|
+
|
|
136
|
+
<cv-tabs orientation="vertical" activation-mode="manual">
|
|
137
|
+
<cv-tab slot="nav" value="overview">Overview</cv-tab>
|
|
138
|
+
<cv-tab slot="nav" value="history">History</cv-tab>
|
|
139
|
+
<cv-tab-panel tab="overview">Overview panel.</cv-tab-panel>
|
|
140
|
+
<cv-tab-panel tab="history">History panel.</cv-tab-panel>
|
|
141
|
+
</cv-tabs>
|
|
142
|
+
|
|
143
|
+
<cv-tabs value="home">
|
|
144
|
+
<cv-tab slot="nav" value="home" closable>Home</cv-tab>
|
|
145
|
+
<cv-tab slot="nav" value="settings" closable>Settings</cv-tab>
|
|
146
|
+
<cv-tab-panel tab="home">Home content.</cv-tab-panel>
|
|
147
|
+
<cv-tab-panel tab="settings">Settings content.</cv-tab-panel>
|
|
148
|
+
</cv-tabs>
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Child Elements
|
|
152
|
+
|
|
153
|
+
### cv-tab
|
|
154
|
+
|
|
155
|
+
Individual tab trigger within the tablist.
|
|
156
|
+
|
|
157
|
+
#### Anatomy
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
<cv-tab> (host)
|
|
161
|
+
└── <div class="tab" part="base">
|
|
162
|
+
├── <slot>
|
|
163
|
+
└── <button part="close-button"> ← only when [closable]
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
#### Attributes
|
|
167
|
+
|
|
168
|
+
| Attribute | Type | Default | Description |
|
|
169
|
+
| ---------- | ------- | ------- | ------------------------------------------------------- |
|
|
170
|
+
| `value` | String | `""` | Unique identifier linking this tab to a panel |
|
|
171
|
+
| `disabled` | Boolean | `false` | Prevents selection and keyboard activation |
|
|
172
|
+
| `active` | Boolean | `false` | Whether this tab has roving focus (managed by parent) |
|
|
173
|
+
| `selected` | Boolean | `false` | Whether this tab's panel is visible (managed by parent) |
|
|
174
|
+
| `closable` | Boolean | `false` | Shows close affordance for removal flows |
|
|
175
|
+
|
|
176
|
+
#### Slots
|
|
177
|
+
|
|
178
|
+
| Slot | Description |
|
|
179
|
+
| ----------- | ----------------- |
|
|
180
|
+
| `(default)` | Tab label content |
|
|
181
|
+
|
|
182
|
+
#### CSS Parts
|
|
183
|
+
|
|
184
|
+
| Part | Element | Description |
|
|
185
|
+
| -------------- | ---------- | ---------------------------------------------------------- |
|
|
186
|
+
| `base` | `<div>` | Tab interactive wrapper |
|
|
187
|
+
| `close-button` | `<button>` | Close affordance (rendered only when `closable` is `true`) |
|
|
188
|
+
|
|
189
|
+
#### Visual States
|
|
190
|
+
|
|
191
|
+
| Host selector | Description |
|
|
192
|
+
| ------------------- | ------------------------------------------------ |
|
|
193
|
+
| `:host([active])` | Focused tab in roving tabindex model |
|
|
194
|
+
| `:host([selected])` | Selected tab with visible panel |
|
|
195
|
+
| `:host([disabled])` | Disabled appearance and non-interactive behavior |
|
|
196
|
+
|
|
197
|
+
#### Events
|
|
198
|
+
|
|
199
|
+
| Event | Detail | Description |
|
|
200
|
+
| ---------- | ----------------- | --------------------------------------------------------------- |
|
|
201
|
+
| `cv-close` | `{value: string}` | Requests removal of this tab when close affordance is activated |
|
|
202
|
+
|
|
203
|
+
The `cv-close` event bubbles and is composed. It is dispatched when the user activates the close button. The `value` in the detail corresponds to the tab's `value` attribute. The parent `cv-tabs` handles close orchestration: it determines a fallback tab, transitions selection if the closed tab was active or selected, and expects the consumer to remove the `cv-tab` and `cv-tab-panel` elements from the DOM.
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
### cv-tab-panel
|
|
208
|
+
|
|
209
|
+
Content panel associated with a tab.
|
|
210
|
+
|
|
211
|
+
#### Anatomy
|
|
212
|
+
|
|
213
|
+
```
|
|
214
|
+
<cv-tab-panel> (host)
|
|
215
|
+
└── <div part="base" role="tabpanel">
|
|
216
|
+
└── <slot>
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
#### Attributes
|
|
220
|
+
|
|
221
|
+
| Attribute | Type | Default | Description |
|
|
222
|
+
| ---------- | ------- | ------- | ------------------------------------------------- |
|
|
223
|
+
| `tab` | String | `""` | Value of the associated `<cv-tab>` |
|
|
224
|
+
| `selected` | Boolean | `false` | Whether this panel is visible (managed by parent) |
|
|
225
|
+
|
|
226
|
+
#### Slots
|
|
227
|
+
|
|
228
|
+
| Slot | Description |
|
|
229
|
+
| ----------- | ------------- |
|
|
230
|
+
| `(default)` | Panel content |
|
|
231
|
+
|
|
232
|
+
#### CSS Parts
|
|
233
|
+
|
|
234
|
+
| Part | Element | Description |
|
|
235
|
+
| ------ | ------- | --------------------- |
|
|
236
|
+
| `base` | `<div>` | Panel content wrapper |
|
|
237
|
+
|
|
238
|
+
#### Visual States
|
|
239
|
+
|
|
240
|
+
| Host selector | Description |
|
|
241
|
+
| ----------------- | --------------------------------- |
|
|
242
|
+
| `:host([hidden])` | Hidden when panel is not selected |
|