@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,204 @@
|
|
|
1
|
+
# `cv-sidebar`
|
|
2
|
+
|
|
3
|
+
Persistent layout sidebar with desktop expand/collapse, mobile overlay mode, and opt-in same-page `scrollspy`.
|
|
4
|
+
|
|
5
|
+
**Headless base:** [`createSidebar`](https://github.com/chromvoid/headless-ui/blob/main/specs/components/sidebar.md)
|
|
6
|
+
|
|
7
|
+
## Anatomy
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
<cv-sidebar>
|
|
11
|
+
├── <div part="overlay">
|
|
12
|
+
└── <aside part="panel">
|
|
13
|
+
├── <header part="header">
|
|
14
|
+
│ ├── <slot name="header">
|
|
15
|
+
│ └── <button part="toggle">
|
|
16
|
+
│ └── <slot name="toggle">
|
|
17
|
+
├── <nav part="body">
|
|
18
|
+
│ └── <slot>
|
|
19
|
+
└── <footer part="footer">
|
|
20
|
+
└── <slot name="footer">
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Attributes
|
|
24
|
+
|
|
25
|
+
| Attribute | Type | Default | Description |
|
|
26
|
+
| -------------------------- | ------------------------------------- | ---------------------- | ---------------------------------------------------------- |
|
|
27
|
+
| `expanded` | Boolean | `true` | Desktop full-width mode |
|
|
28
|
+
| `collapsed` | Boolean | `false` | Desktop rail mode; inverse of `expanded` |
|
|
29
|
+
| `mobile` | Boolean | `false` | Mobile/overlay mode |
|
|
30
|
+
| `overlay-open` | Boolean | `false` | Mobile overlay visibility |
|
|
31
|
+
| `size` | `"small" \| "medium" \| "large"` | `"medium"` | Width preset |
|
|
32
|
+
| `breakpoint` | String | `"768px"` | Auto-switch breakpoint for mobile mode |
|
|
33
|
+
| `close-on-escape` | Boolean | `true` | Whether `Escape` closes mobile overlay |
|
|
34
|
+
| `close-on-outside-pointer` | Boolean | `true` | Whether outside pointer closes mobile overlay |
|
|
35
|
+
| `initial-focus-id` | String | --- | Initial focus target when overlay opens |
|
|
36
|
+
| `aria-label` | String | `"Sidebar navigation"` | Accessible label for the panel landmark/dialog |
|
|
37
|
+
| `scrollspy` | Boolean | `false` | Enables same-page hash navigation tracking |
|
|
38
|
+
| `scrollspy-offset-top` | Number | `0` | Top offset used when resolving the active section |
|
|
39
|
+
| `scrollspy-strategy` | `"top-anchor" \| "viewport-dominant"` | `"top-anchor"` | Strategy used to resolve the active section |
|
|
40
|
+
| `scrollspy-smooth-scroll` | Boolean | `true` | Uses `scrollIntoView({behavior: "smooth"})` for hash items |
|
|
41
|
+
|
|
42
|
+
## Properties
|
|
43
|
+
|
|
44
|
+
| Property | Type | Default | Description |
|
|
45
|
+
| --------------- | ------------------------------------------- | ------- | ------------------------------------------------ |
|
|
46
|
+
| `scrollspyRoot` | `Document \| ShadowRoot \| Element \| null` | `null` | Explicit root used for resolving section targets |
|
|
47
|
+
| `activeId` | `string \| null` | `null` | Readonly id of the active `scrollspy` target |
|
|
48
|
+
|
|
49
|
+
When `scrollspyRoot` is `null`, `cv-sidebar` resolves section targets in the host element root (`Document` or parent `ShadowRoot`).
|
|
50
|
+
|
|
51
|
+
## Slots
|
|
52
|
+
|
|
53
|
+
| Slot | Description |
|
|
54
|
+
| -------- | --------------------------------------------------------------------- |
|
|
55
|
+
| default | Navigation content, including `cv-sidebar-item` or plain hash anchors |
|
|
56
|
+
| `header` | Header content |
|
|
57
|
+
| `toggle` | Custom toggle icon/content |
|
|
58
|
+
| `footer` | Footer content |
|
|
59
|
+
|
|
60
|
+
## CSS Parts
|
|
61
|
+
|
|
62
|
+
| Part | Description |
|
|
63
|
+
| --------- | --------------------------------- |
|
|
64
|
+
| `overlay` | Mobile backdrop |
|
|
65
|
+
| `panel` | Sidebar panel |
|
|
66
|
+
| `header` | Header area |
|
|
67
|
+
| `toggle` | Expand/collapse or overlay toggle |
|
|
68
|
+
| `body` | Main nav body |
|
|
69
|
+
| `footer` | Footer area |
|
|
70
|
+
|
|
71
|
+
## CSS Custom Properties
|
|
72
|
+
|
|
73
|
+
| Property | Default |
|
|
74
|
+
| ---------------------------------- | --------------------------------------------- |
|
|
75
|
+
| `--cv-sidebar-inline-size` | `280px` |
|
|
76
|
+
| `--cv-sidebar-rail-inline-size` | `56px` |
|
|
77
|
+
| `--cv-sidebar-z-index` | `30` |
|
|
78
|
+
| `--cv-sidebar-background` | `var(--cv-color-surface, #141923)` |
|
|
79
|
+
| `--cv-sidebar-border-color` | `var(--cv-color-border, #2a3245)` |
|
|
80
|
+
| `--cv-sidebar-padding-block` | `var(--cv-space-3, 12px)` |
|
|
81
|
+
| `--cv-sidebar-padding-inline` | `var(--cv-space-3, 12px)` |
|
|
82
|
+
| `--cv-sidebar-overlay-color` | `color-mix(in oklab, black 56%, transparent)` |
|
|
83
|
+
| `--cv-sidebar-transition-duration` | `var(--cv-duration-normal, 200ms)` |
|
|
84
|
+
| `--cv-sidebar-transition-easing` | `var(--cv-easing-standard, ease)` |
|
|
85
|
+
|
|
86
|
+
## Events
|
|
87
|
+
|
|
88
|
+
| Event | Detail | Description |
|
|
89
|
+
| ------------------------ | ---------------------------- | ----------------------------------------- |
|
|
90
|
+
| `cv-input` | `{expanded: boolean}` | Desktop user-driven expand/collapse |
|
|
91
|
+
| `cv-change` | `{expanded: boolean}` | Desktop committed expand/collapse |
|
|
92
|
+
| `cv-input` | `{overlayOpen: boolean}` | Mobile user-driven overlay open/close |
|
|
93
|
+
| `cv-change` | `{overlayOpen: boolean}` | Mobile committed overlay open/close |
|
|
94
|
+
| `cv-expand` | --- | Desktop expand lifecycle start |
|
|
95
|
+
| `cv-after-expand` | --- | Desktop expand lifecycle end |
|
|
96
|
+
| `cv-collapse` | --- | Desktop collapse lifecycle start |
|
|
97
|
+
| `cv-after-collapse` | --- | Desktop collapse lifecycle end |
|
|
98
|
+
| `cv-overlay-open` | --- | Mobile overlay open lifecycle start |
|
|
99
|
+
| `cv-after-overlay-open` | --- | Mobile overlay open lifecycle end |
|
|
100
|
+
| `cv-overlay-close` | --- | Mobile overlay close lifecycle start |
|
|
101
|
+
| `cv-after-overlay-close` | --- | Mobile overlay close lifecycle end |
|
|
102
|
+
| `cv-scrollspy-change` | `{activeId: string \| null}` | Fires when the active hash target changes |
|
|
103
|
+
|
|
104
|
+
## Scrollspy behavior
|
|
105
|
+
|
|
106
|
+
- `scrollspy` only manages same-page hash items (`href="#section-id"`).
|
|
107
|
+
- Slotted `cv-sidebar-item` elements receive `active` state automatically.
|
|
108
|
+
- Slotted plain anchors receive `aria-current="location"` automatically.
|
|
109
|
+
- Same-page hash clicks are intercepted and resolved by the sidebar scrollspy controller.
|
|
110
|
+
- No `scroll` listeners are used. Active state is derived from `IntersectionObserver`.
|
|
111
|
+
- `top-anchor` keeps classic TOC semantics based on the section closest to the configured top anchor.
|
|
112
|
+
- `viewport-dominant` resolves the active section from effective viewport dominance using visible coverage, distance to viewport center, and hysteresis.
|
|
113
|
+
- In `viewport-dominant`, same-page hash clicks scroll the target to the viewport center instead of the top edge.
|
|
114
|
+
- In `viewport-dominant`, same-page hash clicks do not optimistically switch `activeId`; the active item updates only after observer-driven recompute.
|
|
115
|
+
|
|
116
|
+
## `cv-sidebar-item`
|
|
117
|
+
|
|
118
|
+
Lightweight sidebar navigation item that adapts to expanded and collapsed rail modes.
|
|
119
|
+
|
|
120
|
+
### Anatomy
|
|
121
|
+
|
|
122
|
+
```text
|
|
123
|
+
<cv-sidebar-item>
|
|
124
|
+
└── <a part="base">
|
|
125
|
+
├── <span part="prefix">
|
|
126
|
+
│ └── <slot name="prefix">
|
|
127
|
+
├── <span part="label">
|
|
128
|
+
│ └── <slot>
|
|
129
|
+
└── <span part="suffix">
|
|
130
|
+
└── <slot name="suffix">
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Attributes
|
|
134
|
+
|
|
135
|
+
| Attribute | Type | Default | Description |
|
|
136
|
+
| ---------- | ------- | ------- | -------------------- |
|
|
137
|
+
| `href` | String | `""` | Item target |
|
|
138
|
+
| `active` | Boolean | `false` | Current/active state |
|
|
139
|
+
| `disabled` | Boolean | `false` | Disables interaction |
|
|
140
|
+
|
|
141
|
+
### Slots
|
|
142
|
+
|
|
143
|
+
| Slot | Description |
|
|
144
|
+
| -------- | ------------------------ |
|
|
145
|
+
| default | Label |
|
|
146
|
+
| `prefix` | Leading icon/content |
|
|
147
|
+
| `suffix` | Trailing badge/indicator |
|
|
148
|
+
|
|
149
|
+
### CSS Parts
|
|
150
|
+
|
|
151
|
+
| Part | Description |
|
|
152
|
+
| -------- | -------------- |
|
|
153
|
+
| `base` | Root anchor |
|
|
154
|
+
| `prefix` | Prefix wrapper |
|
|
155
|
+
| `label` | Label wrapper |
|
|
156
|
+
| `suffix` | Suffix wrapper |
|
|
157
|
+
|
|
158
|
+
### CSS Custom Properties
|
|
159
|
+
|
|
160
|
+
| Property | Default |
|
|
161
|
+
| ------------------------------------- | ------------------------------------- |
|
|
162
|
+
| `--cv-sidebar-item-gap` | `var(--cv-space-2, 8px)` |
|
|
163
|
+
| `--cv-sidebar-item-min-block-size` | `32px` |
|
|
164
|
+
| `--cv-sidebar-item-padding-block` | `var(--cv-space-2, 8px)` |
|
|
165
|
+
| `--cv-sidebar-item-padding-inline` | `var(--cv-space-3, 12px)` |
|
|
166
|
+
| `--cv-sidebar-item-border-radius` | `var(--cv-radius-sm, 6px)` |
|
|
167
|
+
| `--cv-sidebar-item-color` | `var(--cv-color-text-muted, #9aa6bf)` |
|
|
168
|
+
| `--cv-sidebar-item-color-hover` | `var(--cv-color-text, #e8ecf6)` |
|
|
169
|
+
| `--cv-sidebar-item-color-active` | `var(--cv-color-primary, #65d7ff)` |
|
|
170
|
+
| `--cv-sidebar-item-background` | `transparent` |
|
|
171
|
+
| `--cv-sidebar-item-background-hover` | mixed surface highlight |
|
|
172
|
+
| `--cv-sidebar-item-background-active` | `transparent` |
|
|
173
|
+
| `--cv-sidebar-item-indicator-width` | `2px` |
|
|
174
|
+
| `--cv-sidebar-item-indicator-color` | `var(--cv-color-primary, #65d7ff)` |
|
|
175
|
+
|
|
176
|
+
`cv-sidebar` propagates `collapsed` and `mobile` context to direct child `cv-sidebar-item` elements so labels and suffix content are visually hidden in desktop rail mode without consumer-specific wiring.
|
|
177
|
+
|
|
178
|
+
## Usage
|
|
179
|
+
|
|
180
|
+
```html
|
|
181
|
+
<cv-sidebar>
|
|
182
|
+
<span slot="header">Threat Model</span>
|
|
183
|
+
|
|
184
|
+
<cv-sidebar-item href="#assets">
|
|
185
|
+
<cv-icon slot="prefix" name="database"></cv-icon>
|
|
186
|
+
Assets
|
|
187
|
+
</cv-sidebar-item>
|
|
188
|
+
|
|
189
|
+
<cv-sidebar-item href="#crypto" active>
|
|
190
|
+
<cv-icon slot="prefix" name="shield"></cv-icon>
|
|
191
|
+
Crypto
|
|
192
|
+
<cv-badge slot="suffix">Active</cv-badge>
|
|
193
|
+
</cv-sidebar-item>
|
|
194
|
+
</cv-sidebar>
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
```html
|
|
198
|
+
<cv-sidebar scrollspy scrollspy-offset-top="80">
|
|
199
|
+
<span slot="header">On this page</span>
|
|
200
|
+
<cv-sidebar-item href="#assets">Assets</cv-sidebar-item>
|
|
201
|
+
<cv-sidebar-item href="#trust-boundaries">Trust Boundaries</cv-sidebar-item>
|
|
202
|
+
<cv-sidebar-item href="#crypto">Crypto</cv-sidebar-item>
|
|
203
|
+
</cv-sidebar>
|
|
204
|
+
```
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# cv-spinbutton
|
|
2
|
+
|
|
3
|
+
Numeric spinbutton input with keyboard, stepper controls, form-associated behavior, and headless-driven ARIA contracts.
|
|
4
|
+
|
|
5
|
+
**Headless:** [`createSpinbutton`](https://github.com/chromvoid/headless-ui/blob/main/specs/components/spinbutton.md)
|
|
6
|
+
|
|
7
|
+
## Anatomy
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
<cv-spinbutton> (host)
|
|
11
|
+
└── <div part="base">
|
|
12
|
+
├── <input part="input" role="spinbutton" inputmode="decimal">
|
|
13
|
+
└── <div part="actions">
|
|
14
|
+
├── <button part="increment" type="button">
|
|
15
|
+
└── <button part="decrement" type="button">
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Attributes
|
|
19
|
+
|
|
20
|
+
| Attribute | Type | Default | Description |
|
|
21
|
+
| ------------------ | ------- | ------- | ------------------------------------------------------- |
|
|
22
|
+
| `name` | String | `""` | Form field name for submit serialization |
|
|
23
|
+
| `value` | Number | `0` | Current numeric value |
|
|
24
|
+
| `min` | Number | — | Optional minimum boundary |
|
|
25
|
+
| `max` | Number | — | Optional maximum boundary |
|
|
26
|
+
| `step` | Number | `1` | Small increment/decrement step |
|
|
27
|
+
| `large-step` | Number | `10` | Large increment/decrement step (`PageUp`/`PageDown`) |
|
|
28
|
+
| `disabled` | Boolean | `false` | Blocks interaction and omits value from form submission |
|
|
29
|
+
| `read-only` | Boolean | `false` | Keeps focusable/announced but blocks user mutation |
|
|
30
|
+
| `required` | Boolean | `false` | Enables constraint-validation checks |
|
|
31
|
+
| `aria-label` | String | `""` | Accessible label |
|
|
32
|
+
| `aria-labelledby` | String | `""` | ID reference to visible label |
|
|
33
|
+
| `aria-describedby` | String | `""` | ID reference to description |
|
|
34
|
+
|
|
35
|
+
## Slots
|
|
36
|
+
|
|
37
|
+
None.
|
|
38
|
+
|
|
39
|
+
## CSS Parts
|
|
40
|
+
|
|
41
|
+
| Part | Element | Description |
|
|
42
|
+
| ----------- | ---------- | ------------------------------------------------- |
|
|
43
|
+
| `base` | `<div>` | Layout container for input and actions |
|
|
44
|
+
| `input` | `<input>` | Focusable spinbutton control, editable text input |
|
|
45
|
+
| `actions` | `<div>` | Wrapper for increment/decrement controls |
|
|
46
|
+
| `increment` | `<button>` | Increments value by `step` |
|
|
47
|
+
| `decrement` | `<button>` | Decrements value by `step` |
|
|
48
|
+
|
|
49
|
+
## CSS Custom Properties
|
|
50
|
+
|
|
51
|
+
No component-scoped `--cv-spinbutton-*` properties are currently defined.
|
|
52
|
+
|
|
53
|
+
Theme tokens used with fallbacks:
|
|
54
|
+
|
|
55
|
+
| Theme Property | Default | Description |
|
|
56
|
+
| ----------------------------- | --------- | ------------------------- |
|
|
57
|
+
| `--cv-space-1` | `4px` | Internal spacing |
|
|
58
|
+
| `--cv-radius-sm` | `6px` | Base radius |
|
|
59
|
+
| `--cv-color-border` | `#2a3245` | Border color |
|
|
60
|
+
| `--cv-color-surface` | `#141923` | Base background |
|
|
61
|
+
| `--cv-color-surface-elevated` | `#1d2432` | Stepper button background |
|
|
62
|
+
| `--cv-color-text` | `#e8ecf6` | Foreground color |
|
|
63
|
+
| `--cv-color-primary` | `#65d7ff` | Focus ring color |
|
|
64
|
+
|
|
65
|
+
## Visual States
|
|
66
|
+
|
|
67
|
+
| Host selector | Description |
|
|
68
|
+
| -------------------- | ------------------------------------------------------------------- |
|
|
69
|
+
| `:host([disabled])` | Base and controls are visually muted and non-interactive |
|
|
70
|
+
| `:host([read-only])` | Input remains focusable; stepper controls are muted/non-interactive |
|
|
71
|
+
|
|
72
|
+
## Reactive State Mapping
|
|
73
|
+
|
|
74
|
+
`cv-spinbutton` is a thin adapter over headless `createSpinbutton`.
|
|
75
|
+
|
|
76
|
+
| UIKit Property | Direction | Headless Binding |
|
|
77
|
+
| ------------------ | ------------- | ------------------------------------- |
|
|
78
|
+
| `value` | attr → action | `actions.setValue(value)` |
|
|
79
|
+
| `disabled` | attr → action | `actions.setDisabled(value)` |
|
|
80
|
+
| `read-only` | attr → action | `actions.setReadOnly(value)` |
|
|
81
|
+
| `min` | attr → option | passed to `createSpinbutton(options)` |
|
|
82
|
+
| `max` | attr → option | passed to `createSpinbutton(options)` |
|
|
83
|
+
| `step` | attr → option | passed to `createSpinbutton(options)` |
|
|
84
|
+
| `large-step` | attr → option | passed to `createSpinbutton(options)` |
|
|
85
|
+
| `aria-label` | attr → option | passed as `ariaLabel` |
|
|
86
|
+
| `aria-labelledby` | attr → option | passed as `ariaLabelledBy` |
|
|
87
|
+
| `aria-describedby` | attr → option | passed as `ariaDescribedBy` |
|
|
88
|
+
|
|
89
|
+
| Headless State/Contract | Direction | DOM Reflection |
|
|
90
|
+
| ------------------------------------- | ---------------- | ------------------------------------------------------------ |
|
|
91
|
+
| `state.value()` | state → value | `[part="input"].value` and host `value` property |
|
|
92
|
+
| `contracts.getSpinbuttonProps()` | contract → attrs | role, tabindex, and ARIA attributes on `[part="input"]` |
|
|
93
|
+
| `contracts.getIncrementButtonProps()` | contract → attrs | id/tabindex/aria-disabled/aria-label on `[part="increment"]` |
|
|
94
|
+
| `contracts.getDecrementButtonProps()` | contract → attrs | id/tabindex/aria-disabled/aria-label on `[part="decrement"]` |
|
|
95
|
+
|
|
96
|
+
- UIKit may hold transient draft text while editing.
|
|
97
|
+
- Draft text commits to headless on `Enter` or `blur` only.
|
|
98
|
+
- UIKit does not implement keyboard stepping, clamping, snapping, or ARIA computation itself.
|
|
99
|
+
|
|
100
|
+
## Events
|
|
101
|
+
|
|
102
|
+
| Event | Detail | Description |
|
|
103
|
+
| ----------- | ----------------- | --------------------------------------------------------------------- |
|
|
104
|
+
| `cv-input` | `{value: number}` | Fires on each user-triggered value mutation (buttons/stepping/commit) |
|
|
105
|
+
| `cv-change` | `{value: number}` | Fires together with `cv-input` for the same user-triggered mutation |
|
|
106
|
+
|
|
107
|
+
Programmatic mutations through imperative API do not emit `cv-input`/`cv-change`.
|
|
108
|
+
|
|
109
|
+
## Imperative API
|
|
110
|
+
|
|
111
|
+
| Method / Property | Description |
|
|
112
|
+
| ---------------------------- | ------------------------------------------------------- |
|
|
113
|
+
| `stepUp(times = 1)` | Increments by `step` `times` times |
|
|
114
|
+
| `stepDown(times = 1)` | Decrements by `step` `times` times |
|
|
115
|
+
| `pageUp(times = 1)` | Increments by `largeStep` `times` times |
|
|
116
|
+
| `pageDown(times = 1)` | Decrements by `largeStep` `times` times |
|
|
117
|
+
| `setValue(value)` | Sets numeric value through headless normalization |
|
|
118
|
+
| `getValue()` | Returns current committed numeric value |
|
|
119
|
+
| `setRange(min, max)` | Updates range boundaries (`min`/`max`) |
|
|
120
|
+
| `focus(options?)` | Focuses inner input control |
|
|
121
|
+
| `select()` | Selects text in inner input control |
|
|
122
|
+
| `checkValidity()` | Runs current validation checks |
|
|
123
|
+
| `reportValidity()` | Reports validation state to UA when supported |
|
|
124
|
+
| `setCustomValidity(message)` | Sets/clears custom validity message |
|
|
125
|
+
| `form` | Form owner when form-associated internals are supported |
|
|
126
|
+
| `validity` | Current validity state when supported |
|
|
127
|
+
| `validationMessage` | Current validation message |
|
|
128
|
+
| `willValidate` | Whether control participates in validation |
|
|
129
|
+
|
|
130
|
+
UA callbacks supported for form-associated lifecycle:
|
|
131
|
+
|
|
132
|
+
- `formDisabledCallback(disabled)`
|
|
133
|
+
- `formResetCallback()`
|
|
134
|
+
- `formStateRestoreCallback(state)`
|
|
135
|
+
|
|
136
|
+
## Form Association
|
|
137
|
+
|
|
138
|
+
- Component is form-associated via `ElementInternals` when available.
|
|
139
|
+
- Submit value is serialized as raw numeric string from committed `value`.
|
|
140
|
+
- `disabled` state removes form value from submission.
|
|
141
|
+
- Reset restores the initial `value` snapshot captured on first connection.
|
|
142
|
+
|
|
143
|
+
## Usage
|
|
144
|
+
|
|
145
|
+
```html
|
|
146
|
+
<cv-spinbutton name="quantity" value="2" min="0" max="10" step="1"></cv-spinbutton>
|
|
147
|
+
|
|
148
|
+
<cv-spinbutton value="50" min="0" max="100" step="5" large-step="25"></cv-spinbutton>
|
|
149
|
+
|
|
150
|
+
<cv-spinbutton value="5" aria-label="Quantity"></cv-spinbutton>
|
|
151
|
+
|
|
152
|
+
<cv-spinbutton value="3" read-only></cv-spinbutton>
|
|
153
|
+
|
|
154
|
+
<form>
|
|
155
|
+
<cv-spinbutton name="items" value="1" required></cv-spinbutton>
|
|
156
|
+
</form>
|
|
157
|
+
```
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# cv-spinner
|
|
2
|
+
|
|
3
|
+
Indeterminate loading spinner with SVG track and indicator animation.
|
|
4
|
+
|
|
5
|
+
**Headless:** [`createSpinner`](https://github.com/chromvoid/headless-ui/blob/main/specs/components/spinner.md)
|
|
6
|
+
|
|
7
|
+
## Anatomy
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
<cv-spinner> (host)
|
|
11
|
+
└── <svg part="base" role="progressbar" aria-label="...">
|
|
12
|
+
├── <circle part="track">
|
|
13
|
+
└── <circle part="indicator">
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Attributes
|
|
17
|
+
|
|
18
|
+
| Attribute | Type | Default | Description |
|
|
19
|
+
| --------- | ------ | ----------- | ------------------------------------------------- |
|
|
20
|
+
| `label` | String | `"Loading"` | Accessible name announced by assistive technology |
|
|
21
|
+
|
|
22
|
+
No `size` attribute is provided. Sizing is controlled entirely via CSS `font-size` on the host element; the SVG scales relative to `1em`.
|
|
23
|
+
|
|
24
|
+
## Slots
|
|
25
|
+
|
|
26
|
+
None. The spinner is purely visual with no slotted content.
|
|
27
|
+
|
|
28
|
+
## CSS Parts
|
|
29
|
+
|
|
30
|
+
| Part | Element | Description |
|
|
31
|
+
| ----------- | ---------- | ---------------------------------------------- |
|
|
32
|
+
| `base` | `<svg>` | Root SVG element with ARIA attributes |
|
|
33
|
+
| `track` | `<circle>` | Background circle (static ring) |
|
|
34
|
+
| `indicator` | `<circle>` | Animated arc indicating indeterminate progress |
|
|
35
|
+
|
|
36
|
+
## CSS Custom Properties
|
|
37
|
+
|
|
38
|
+
| Property | Default | Description |
|
|
39
|
+
| ------------------------------ | ---------------------------------- | ---------------------------------------- |
|
|
40
|
+
| `--cv-spinner-track-width` | `4px` | Stroke width of both track and indicator |
|
|
41
|
+
| `--cv-spinner-track-color` | `var(--cv-color-border, #2a3245)` | Color of the background track ring |
|
|
42
|
+
| `--cv-spinner-indicator-color` | `var(--cv-color-primary, #65d7ff)` | Color of the animated indicator arc |
|
|
43
|
+
| `--cv-spinner-speed` | `600ms` | Duration of one full rotation cycle |
|
|
44
|
+
|
|
45
|
+
## Visual States
|
|
46
|
+
|
|
47
|
+
None. The spinner is always animating when rendered; there are no conditional visual states.
|
|
48
|
+
|
|
49
|
+
## Events
|
|
50
|
+
|
|
51
|
+
None. The spinner is purely presentational and does not emit events.
|
|
52
|
+
|
|
53
|
+
## Reactive State Mapping
|
|
54
|
+
|
|
55
|
+
`cv-spinner` is a visual adapter over headless `createSpinner`.
|
|
56
|
+
|
|
57
|
+
| UIKit Property | Direction | Headless Binding |
|
|
58
|
+
| -------------- | -------------- | ------------------------- |
|
|
59
|
+
| `label` | attr -> action | `actions.setLabel(value)` |
|
|
60
|
+
|
|
61
|
+
| Headless State | Direction | DOM Reflection |
|
|
62
|
+
| --------------- | ----------------- | -------------------------------- |
|
|
63
|
+
| `state.label()` | state -> contract | Consumed via `getSpinnerProps()` |
|
|
64
|
+
|
|
65
|
+
- `contracts.getSpinnerProps()` is spread onto the inner `[part="base"]` SVG element to apply `role="progressbar"` and `aria-label`.
|
|
66
|
+
- UIKit does not own ARIA semantics; headless state is the source of truth.
|
|
67
|
+
- `aria-valuenow`, `aria-valuemin`, `aria-valuemax`, and `aria-valuetext` are never present (indeterminate mode only).
|
|
68
|
+
|
|
69
|
+
## Usage
|
|
70
|
+
|
|
71
|
+
```html
|
|
72
|
+
<!-- Default spinner -->
|
|
73
|
+
<cv-spinner></cv-spinner>
|
|
74
|
+
|
|
75
|
+
<!-- Custom accessible label -->
|
|
76
|
+
<cv-spinner label="Saving changes"></cv-spinner>
|
|
77
|
+
|
|
78
|
+
<!-- Sized via CSS font-size -->
|
|
79
|
+
<cv-spinner style="font-size: 2rem;"></cv-spinner>
|
|
80
|
+
|
|
81
|
+
<!-- Themed via custom properties -->
|
|
82
|
+
<cv-spinner style="--cv-spinner-indicator-color: #ff7d86; --cv-spinner-speed: 800ms;"></cv-spinner>
|
|
83
|
+
```
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# cv-switch
|
|
2
|
+
|
|
3
|
+
Toggle control that represents an on/off state, visually distinct from a checkbox.
|
|
4
|
+
|
|
5
|
+
**Headless:** [`createSwitch`](https://github.com/chromvoid/headless-ui/blob/main/specs/components/switch.md)
|
|
6
|
+
|
|
7
|
+
## Anatomy
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
<cv-switch> (host)
|
|
11
|
+
└── <div part="base">
|
|
12
|
+
├── <div part="control" role="switch">
|
|
13
|
+
│ ├── <span part="toggled" hidden>
|
|
14
|
+
│ │ └── <slot name="toggled">
|
|
15
|
+
│ ├── <span part="untoggled" hidden>
|
|
16
|
+
│ │ └── <slot name="untoggled">
|
|
17
|
+
│ └── <span part="thumb">
|
|
18
|
+
├── <span part="label">
|
|
19
|
+
│ └── <slot>
|
|
20
|
+
└── <span part="help-text" id="{idBase}-help-text">
|
|
21
|
+
└── <slot name="help-text">
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
When `checked` is `true`, the `toggled` wrapper is visible and `untoggled` is hidden. When `checked` is `false`, the opposite applies. Both wrappers are always in the DOM; visibility is toggled via CSS or the `hidden` attribute.
|
|
25
|
+
|
|
26
|
+
The `help-text` part is rendered only when the `help-text` attribute is set or the `help-text` slot is populated.
|
|
27
|
+
|
|
28
|
+
## Attributes
|
|
29
|
+
|
|
30
|
+
| Attribute | Type | Default | Description |
|
|
31
|
+
| ----------- | ------- | ---------- | ------------------------------------------- |
|
|
32
|
+
| `checked` | Boolean | `false` | On/off state |
|
|
33
|
+
| `disabled` | Boolean | `false` | Prevents interaction |
|
|
34
|
+
| `size` | String | `"medium"` | Size: `small` \| `medium` \| `large` |
|
|
35
|
+
| `help-text` | String | `""` | Descriptive text displayed below the switch |
|
|
36
|
+
|
|
37
|
+
## Sizes
|
|
38
|
+
|
|
39
|
+
| Size | `--cv-switch-width` | `--cv-switch-height` | `--cv-switch-thumb-size` |
|
|
40
|
+
| -------- | ------------------- | -------------------- | ------------------------ |
|
|
41
|
+
| `small` | `36px` | `20px` | `14px` |
|
|
42
|
+
| `medium` | `44px` | `24px` | `18px` |
|
|
43
|
+
| `large` | `52px` | `28px` | `22px` |
|
|
44
|
+
|
|
45
|
+
## Slots
|
|
46
|
+
|
|
47
|
+
| Slot | Description |
|
|
48
|
+
| ----------- | ---------------------------------------------------------------------- |
|
|
49
|
+
| `(default)` | Label text displayed beside the switch |
|
|
50
|
+
| `toggled` | Content shown inside the track when checked (e.g., icon, text) |
|
|
51
|
+
| `untoggled` | Content shown inside the track when unchecked (e.g., icon, text) |
|
|
52
|
+
| `help-text` | Descriptive text below the switch; overrides the `help-text` attribute |
|
|
53
|
+
|
|
54
|
+
## CSS Parts
|
|
55
|
+
|
|
56
|
+
| Part | Element | Description |
|
|
57
|
+
| ----------- | -------- | ------------------------------------------------------------ |
|
|
58
|
+
| `base` | `<div>` | Root layout wrapper (contains control + label + help-text) |
|
|
59
|
+
| `control` | `<div>` | Track/oval with `role="switch"` |
|
|
60
|
+
| `thumb` | `<span>` | Sliding knob inside the control |
|
|
61
|
+
| `toggled` | `<span>` | Wrapper around the `toggled` slot (visible when checked) |
|
|
62
|
+
| `untoggled` | `<span>` | Wrapper around the `untoggled` slot (visible when unchecked) |
|
|
63
|
+
| `label` | `<span>` | Wrapper around the default slot |
|
|
64
|
+
| `help-text` | `<span>` | Wrapper around the `help-text` slot or attribute text |
|
|
65
|
+
|
|
66
|
+
## CSS Custom Properties
|
|
67
|
+
|
|
68
|
+
| Property | Default | Description |
|
|
69
|
+
| --------------------------------- | ------------------------------------- | --------------------------------------- |
|
|
70
|
+
| `--cv-switch-width` | `44px` | Inline size of the control track |
|
|
71
|
+
| `--cv-switch-height` | `24px` | Block size of the control track |
|
|
72
|
+
| `--cv-switch-thumb-size` | `18px` | Size of the thumb knob |
|
|
73
|
+
| `--cv-switch-gap` | `var(--cv-space-2, 8px)` | Spacing between control track and label |
|
|
74
|
+
| `--cv-switch-help-text-color` | `var(--cv-color-text-muted, #9aa6bf)` | Color of the help text |
|
|
75
|
+
| `--cv-switch-help-text-font-size` | `0.85em` | Font size of the help text |
|
|
76
|
+
|
|
77
|
+
## Visual States
|
|
78
|
+
|
|
79
|
+
| Host selector | Description |
|
|
80
|
+
| ----------------------- | ------------------------------------------------------------------------------------------------------- |
|
|
81
|
+
| `:host([checked])` | Primary-tinted track, thumb translated to end position; `toggled` part visible, `untoggled` part hidden |
|
|
82
|
+
| `:host([disabled])` | Reduced opacity (`0.55`), `cursor: not-allowed` |
|
|
83
|
+
| `:host([size="small"])` | Small size overrides |
|
|
84
|
+
| `:host([size="large"])` | Large size overrides |
|
|
85
|
+
|
|
86
|
+
## Reactive State Mapping
|
|
87
|
+
|
|
88
|
+
`cv-switch` is a visual adapter over headless `createSwitch`.
|
|
89
|
+
|
|
90
|
+
| UIKit Property | Direction | Headless Binding |
|
|
91
|
+
| -------------- | -------------- | --------------------------------------------------------------------------------------------------------------------- |
|
|
92
|
+
| `checked` | attr -> action | `actions.setOn(value)` |
|
|
93
|
+
| `disabled` | attr -> action | `actions.setDisabled(value)` |
|
|
94
|
+
| `help-text` | attr -> option | When present, generates an id for the help-text element and passes it as `ariaDescribedBy` in `createSwitch(options)` |
|
|
95
|
+
|
|
96
|
+
| Headless State | Direction | DOM Reflection |
|
|
97
|
+
| -------------------- | ------------- | --------------------------- |
|
|
98
|
+
| `state.isOn()` | state -> attr | `[checked]` host attribute |
|
|
99
|
+
| `state.isDisabled()` | state -> attr | `[disabled]` host attribute |
|
|
100
|
+
|
|
101
|
+
- `contracts.getSwitchProps()` is spread onto the inner `[part="control"]` element to apply `role`, `aria-checked`, `aria-disabled`, `tabindex`, and keyboard/click handlers.
|
|
102
|
+
- When help text is present (via attribute or slot), the component generates the id `{idBase}-help-text` for the help-text element and passes it as the `ariaDescribedBy` option to `createSwitch`, which produces the `aria-describedby` attribute in `getSwitchProps()`.
|
|
103
|
+
- UIKit dispatches `cv-input` and `cv-change` events by observing `isOn` changes triggered by user activation (not by controlled `setOn`).
|
|
104
|
+
- Toggled/untoggled slot visibility is purely visual (CSS-driven); no headless state or ARIA changes are involved.
|
|
105
|
+
- UIKit does not own toggle or keyboard logic; headless state is the source of truth.
|
|
106
|
+
|
|
107
|
+
## Events
|
|
108
|
+
|
|
109
|
+
| Event | Detail | Description |
|
|
110
|
+
| ----------- | -------------------- | -------------------------------- |
|
|
111
|
+
| `cv-input` | `{checked: boolean}` | Fires on toggle interaction |
|
|
112
|
+
| `cv-change` | `{checked: boolean}` | Fires when checked state commits |
|
|
113
|
+
|
|
114
|
+
## Usage
|
|
115
|
+
|
|
116
|
+
```html
|
|
117
|
+
<cv-switch>Dark mode</cv-switch>
|
|
118
|
+
|
|
119
|
+
<cv-switch checked>Notifications</cv-switch>
|
|
120
|
+
|
|
121
|
+
<cv-switch disabled>Locked setting</cv-switch>
|
|
122
|
+
|
|
123
|
+
<cv-switch size="small">Compact</cv-switch>
|
|
124
|
+
|
|
125
|
+
<cv-switch size="large">Large toggle</cv-switch>
|
|
126
|
+
|
|
127
|
+
<cv-switch help-text="Reduces blue light emission after sunset"> Night mode </cv-switch>
|
|
128
|
+
|
|
129
|
+
<cv-switch>
|
|
130
|
+
Airplane mode
|
|
131
|
+
<span slot="help-text">Disables all wireless connections</span>
|
|
132
|
+
</cv-switch>
|
|
133
|
+
|
|
134
|
+
<cv-switch checked>
|
|
135
|
+
Wi-Fi
|
|
136
|
+
<cv-icon slot="toggled" name="wifi-on"></cv-icon>
|
|
137
|
+
<cv-icon slot="untoggled" name="wifi-off"></cv-icon>
|
|
138
|
+
</cv-switch>
|
|
139
|
+
|
|
140
|
+
<cv-switch>
|
|
141
|
+
Sound
|
|
142
|
+
<span slot="toggled">ON</span>
|
|
143
|
+
<span slot="untoggled">OFF</span>
|
|
144
|
+
</cv-switch>
|
|
145
|
+
```
|