@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,198 @@
|
|
|
1
|
+
# cv-toast-region
|
|
2
|
+
|
|
3
|
+
Container that manages a queue of toast notifications with positioning, stacking layout, and auto-dismiss lifecycle.
|
|
4
|
+
|
|
5
|
+
**Headless:** [`createToast`](https://github.com/chromvoid/headless-ui/blob/main/specs/components/toast.md)
|
|
6
|
+
|
|
7
|
+
## Anatomy
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
<cv-toast-region> (host)
|
|
11
|
+
└── <section part="base" role="region" aria-live="polite" aria-atomic="false">
|
|
12
|
+
├── <cv-toast part="item" role="status|alert" data-level="info">
|
|
13
|
+
├── <cv-toast part="item" role="alert" data-level="error">
|
|
14
|
+
└── …
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Attributes
|
|
18
|
+
|
|
19
|
+
| Attribute | Type | Default | Description |
|
|
20
|
+
| ------------- | ------ | ----------- | ------------------------------------------------------------------------------------------------------------------------ |
|
|
21
|
+
| `position` | String | `"top-end"` | Positioning of the region: `top-start` \| `top-center` \| `top-end` \| `bottom-start` \| `bottom-center` \| `bottom-end` |
|
|
22
|
+
| `max-visible` | Number | `3` | Maximum number of toasts displayed simultaneously |
|
|
23
|
+
|
|
24
|
+
## Slots
|
|
25
|
+
|
|
26
|
+
| Slot | Description |
|
|
27
|
+
| -------- | ------------------------------------------------------------------------------- |
|
|
28
|
+
| _(none)_ | Content is rendered programmatically from the toast queue; no user-facing slots |
|
|
29
|
+
|
|
30
|
+
## CSS Parts
|
|
31
|
+
|
|
32
|
+
| Part | Element | Description |
|
|
33
|
+
| ------ | ----------- | -------------------------------------------------------- |
|
|
34
|
+
| `base` | `<section>` | Root region element with `role="region"` and `aria-live` |
|
|
35
|
+
|
|
36
|
+
## CSS Custom Properties
|
|
37
|
+
|
|
38
|
+
| Property | Default | Description |
|
|
39
|
+
| ----------------------------- | ------------------------- | --------------------------------- |
|
|
40
|
+
| `--cv-toast-region-gap` | `var(--cv-space-2, 8px)` | Spacing between stacked toasts |
|
|
41
|
+
| `--cv-toast-region-inset` | `var(--cv-space-4, 16px)` | Distance from viewport edges |
|
|
42
|
+
| `--cv-toast-region-z-index` | `9999` | Stacking order above page content |
|
|
43
|
+
| `--cv-toast-region-max-width` | `420px` | Maximum width of the toast region |
|
|
44
|
+
|
|
45
|
+
## Visual States
|
|
46
|
+
|
|
47
|
+
| Host selector | Description |
|
|
48
|
+
| ----------------------------------- | ----------------------------------- |
|
|
49
|
+
| `:host([position="top-start"])` | Region fixed to top-left |
|
|
50
|
+
| `:host([position="top-center"])` | Region fixed to top-center |
|
|
51
|
+
| `:host([position="top-end"])` | Region fixed to top-right (default) |
|
|
52
|
+
| `:host([position="bottom-start"])` | Region fixed to bottom-left |
|
|
53
|
+
| `:host([position="bottom-center"])` | Region fixed to bottom-center |
|
|
54
|
+
| `:host([position="bottom-end"])` | Region fixed to bottom-right |
|
|
55
|
+
|
|
56
|
+
## Events
|
|
57
|
+
|
|
58
|
+
| Event | Detail | Description |
|
|
59
|
+
| ---------- | ---------------- | ------------------------------------------------------------------------------- |
|
|
60
|
+
| `cv-close` | `{ id: string }` | Fires when a toast is removed from the queue (auto-dismiss or explicit dismiss) |
|
|
61
|
+
|
|
62
|
+
## Reactive State Mapping
|
|
63
|
+
|
|
64
|
+
`cv-toast-region` is a visual adapter over headless `createToast`.
|
|
65
|
+
|
|
66
|
+
| UIKit Property | Direction | Headless Binding |
|
|
67
|
+
| -------------- | ------------- | --------------------------------------------------------------------------------------------------------- |
|
|
68
|
+
| `max-visible` | attr → option | Passed as `maxVisible` in `createToast(options)` |
|
|
69
|
+
| _(controller)_ | property | `createToastController()` wraps `createToast()` and exposes `push`, `dismiss`, `clear`, `pause`, `resume` |
|
|
70
|
+
|
|
71
|
+
| Headless State | Direction | DOM Reflection |
|
|
72
|
+
| ---------------------- | ---------------- | --------------------------------------------------------------------------- |
|
|
73
|
+
| `state.visibleItems()` | state → render | Drives the rendered list of `cv-toast` items |
|
|
74
|
+
| `state.isPaused()` | state → internal | Tracked internally; toggled by `mouseenter`/`mouseleave` on `[part="base"]` |
|
|
75
|
+
|
|
76
|
+
- `contracts.getRegionProps()` is spread onto the inner `[part="base"]` element to apply `id`, `role="region"`, `aria-live`, and `aria-atomic`.
|
|
77
|
+
- `mouseenter` on `[part="base"]` calls `actions.pause()`; `mouseleave` calls `actions.resume()`.
|
|
78
|
+
- UIKit tracks the previous set of toast IDs across renders and dispatches a `cv-close` event for each ID that disappears from the queue.
|
|
79
|
+
- UIKit does not own queue logic, timer management, or visibility slicing; headless state is the source of truth.
|
|
80
|
+
|
|
81
|
+
## Usage
|
|
82
|
+
|
|
83
|
+
```html
|
|
84
|
+
<!-- Basic usage (imperative API via controller) -->
|
|
85
|
+
<cv-toast-region></cv-toast-region>
|
|
86
|
+
|
|
87
|
+
<script>
|
|
88
|
+
const region = document.querySelector('cv-toast-region')
|
|
89
|
+
region.controller.push({message: 'File saved', level: 'success'})
|
|
90
|
+
region.controller.push({message: 'Connection lost', level: 'error', durationMs: 0})
|
|
91
|
+
</script>
|
|
92
|
+
|
|
93
|
+
<!-- Positioned bottom-center -->
|
|
94
|
+
<cv-toast-region position="bottom-center"></cv-toast-region>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Child Elements
|
|
98
|
+
|
|
99
|
+
### cv-toast
|
|
100
|
+
|
|
101
|
+
Individual toast notification item rendered within `cv-toast-region`. Displays a message with severity-based styling, an optional icon, and an optional dismiss button.
|
|
102
|
+
|
|
103
|
+
#### Anatomy
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
<cv-toast> (host)
|
|
107
|
+
└── <div part="base" role="status|alert" data-level="info">
|
|
108
|
+
├── <span part="icon">
|
|
109
|
+
│ └── <slot name="icon"> ← severity icon
|
|
110
|
+
├── <div part="content">
|
|
111
|
+
│ └── <span part="label">
|
|
112
|
+
│ └── <slot> ← message text
|
|
113
|
+
└── <button part="dismiss"> ← only when closable
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
#### Attributes
|
|
117
|
+
|
|
118
|
+
| Attribute | Type | Default | Description |
|
|
119
|
+
| ---------- | ------- | -------- | ----------------------------------------------------------------- |
|
|
120
|
+
| `level` | String | `"info"` | Severity level: `info` \| `success` \| `warning` \| `error` |
|
|
121
|
+
| `closable` | Boolean | `true` | Whether the dismiss button is shown |
|
|
122
|
+
| `toast-id` | String | `""` | Identifier for the toast, included in the `cv-close` event detail |
|
|
123
|
+
|
|
124
|
+
#### Slots
|
|
125
|
+
|
|
126
|
+
| Slot | Description |
|
|
127
|
+
| ----------- | ------------------------------------------------------- |
|
|
128
|
+
| `(default)` | Message text content |
|
|
129
|
+
| `icon` | Severity icon; overrides the default icon for the level |
|
|
130
|
+
|
|
131
|
+
#### CSS Parts
|
|
132
|
+
|
|
133
|
+
| Part | Element | Description |
|
|
134
|
+
| --------- | ---------- | ------------------------------------------------------------ |
|
|
135
|
+
| `base` | `<div>` | Root wrapper for the toast item with `role` and `data-level` |
|
|
136
|
+
| `icon` | `<span>` | Wrapper around the `icon` slot |
|
|
137
|
+
| `content` | `<div>` | Wrapper around the message area |
|
|
138
|
+
| `label` | `<span>` | Wrapper around the default slot (message text) |
|
|
139
|
+
| `dismiss` | `<button>` | Dismiss/close button |
|
|
140
|
+
|
|
141
|
+
#### CSS Custom Properties
|
|
142
|
+
|
|
143
|
+
| Property | Default | Description |
|
|
144
|
+
| --------------------------- | --------------------------------------------------- | ------------------------------------------------- |
|
|
145
|
+
| `--cv-toast-padding-inline` | `var(--cv-space-3, 12px)` | Horizontal padding |
|
|
146
|
+
| `--cv-toast-padding-block` | `var(--cv-space-2, 8px)` | Vertical padding |
|
|
147
|
+
| `--cv-toast-border-radius` | `var(--cv-radius-md, 10px)` | Border radius |
|
|
148
|
+
| `--cv-toast-gap` | `var(--cv-space-2, 8px)` | Spacing between icon, content, and dismiss button |
|
|
149
|
+
| `--cv-toast-background` | `var(--cv-color-surface-elevated, #1d2432)` | Background color |
|
|
150
|
+
| `--cv-toast-border-color` | `var(--cv-color-border, #2a3245)` | Default border color |
|
|
151
|
+
| `--cv-toast-color` | `var(--cv-color-text, #e8ecf6)` | Text color |
|
|
152
|
+
| `--cv-toast-shadow` | `var(--cv-shadow-1, 0 2px 8px rgba(0, 0, 0, 0.24))` | Box shadow |
|
|
153
|
+
|
|
154
|
+
Additionally, component styles depend on theme tokens through fallback values:
|
|
155
|
+
|
|
156
|
+
| Theme Property | Default | Description |
|
|
157
|
+
| ----------------------------- | --------- | ------------------------------------ |
|
|
158
|
+
| `--cv-color-border` | `#2a3245` | Base border color |
|
|
159
|
+
| `--cv-color-surface-elevated` | `#1d2432` | Elevated surface background |
|
|
160
|
+
| `--cv-color-text` | `#e8ecf6` | Default text color |
|
|
161
|
+
| `--cv-color-text-muted` | `#9aa6bf` | Muted text color (dismiss button) |
|
|
162
|
+
| `--cv-color-primary` | `#65d7ff` | Primary accent (focus ring) |
|
|
163
|
+
| `--cv-color-success` | `#6ef7c8` | Success tint for border |
|
|
164
|
+
| `--cv-color-warning` | `#ffd36e` | Warning tint for border |
|
|
165
|
+
| `--cv-color-danger` | `#ff7d86` | Error/danger tint for border |
|
|
166
|
+
| `--cv-radius-md` | `10px` | Medium border radius |
|
|
167
|
+
| `--cv-radius-sm` | `6px` | Small border radius (dismiss button) |
|
|
168
|
+
| `--cv-space-2` | `8px` | Spacing scale |
|
|
169
|
+
| `--cv-space-3` | `12px` | Spacing scale |
|
|
170
|
+
|
|
171
|
+
#### Visual States
|
|
172
|
+
|
|
173
|
+
| Host selector / Part selector | Description |
|
|
174
|
+
| ----------------------------- | --------------------------------------------------------- |
|
|
175
|
+
| `[data-level="info"]` | Default styling with standard border |
|
|
176
|
+
| `[data-level="success"]` | Border tinted with `--cv-color-success` via `color-mix()` |
|
|
177
|
+
| `[data-level="warning"]` | Border tinted with `--cv-color-warning` via `color-mix()` |
|
|
178
|
+
| `[data-level="error"]` | Border tinted with `--cv-color-danger` via `color-mix()` |
|
|
179
|
+
|
|
180
|
+
#### Events
|
|
181
|
+
|
|
182
|
+
| Event | Detail | Description |
|
|
183
|
+
| ---------- | ---------------- | ----------------------------------------------------------------- |
|
|
184
|
+
| `cv-close` | `{ id: string }` | Fires when the dismiss button is clicked; bubbles and is composed |
|
|
185
|
+
|
|
186
|
+
#### Reactive State Mapping
|
|
187
|
+
|
|
188
|
+
Each toast item is bound to headless contracts per toast ID.
|
|
189
|
+
|
|
190
|
+
| Headless Contract | Direction | DOM Binding |
|
|
191
|
+
| ------------------------------------- | ------------- | ------------------------------------------------------------------------------------------------------ |
|
|
192
|
+
| `contracts.getToastProps(id)` | state → attrs | Spread onto `[part="base"]`: `id`, `role` (`status` or `alert`), `data-level` |
|
|
193
|
+
| `contracts.getDismissButtonProps(id)` | state → attrs | Spread onto `[part="dismiss"]`: `id`, `role="button"`, `tabindex="0"`, `aria-label`, `onClick` handler |
|
|
194
|
+
|
|
195
|
+
- `role` is determined by the headless contract based on level: `role="status"` for `info`/`success`, `role="alert"` for `warning`/`error`.
|
|
196
|
+
- In standalone usage, `cv-toast` computes role from its `level` property matching the headless contract logic.
|
|
197
|
+
- When rendered within `cv-toast-region`, the region spreads headless contract props onto each inline toast item.
|
|
198
|
+
- The dismiss button `onClick` handler from `getDismissButtonProps(id)` calls `actions.dismiss(id)` internally.
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
# cv-toolbar
|
|
2
|
+
|
|
3
|
+
Container of interactive elements that provides a single tab stop and arrow-key navigation between items, with separator support and focus memory.
|
|
4
|
+
|
|
5
|
+
**Headless:** [`createToolbar`](https://github.com/chromvoid/headless-ui/blob/main/specs/components/toolbar.md)
|
|
6
|
+
|
|
7
|
+
## Anatomy
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
<cv-toolbar> (host)
|
|
11
|
+
└── <div part="base" role="toolbar" aria-orientation="…">
|
|
12
|
+
└── <slot> ← accepts <cv-toolbar-item> and <cv-toolbar-separator> children
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Attributes
|
|
16
|
+
|
|
17
|
+
| Attribute | Type | Default | Description |
|
|
18
|
+
| ------------- | ------- | -------------- | ----------------------------------------------------------------------------------------------------- |
|
|
19
|
+
| `value` | String | `""` | Active item value (reflects `activeId` from headless state) |
|
|
20
|
+
| `orientation` | String | `"horizontal"` | Navigation axis: `horizontal` \| `vertical` |
|
|
21
|
+
| `wrap` | Boolean | `true` | Whether arrow navigation wraps from last to first and vice versa. When `false`, clamps at boundaries. |
|
|
22
|
+
| `aria-label` | String | `""` | Accessible label for the toolbar |
|
|
23
|
+
|
|
24
|
+
## Slots
|
|
25
|
+
|
|
26
|
+
| Slot | Description |
|
|
27
|
+
| ----------- | --------------------------------------------------------- |
|
|
28
|
+
| `(default)` | `<cv-toolbar-item>` and `<cv-toolbar-separator>` children |
|
|
29
|
+
|
|
30
|
+
## CSS Parts
|
|
31
|
+
|
|
32
|
+
| Part | Element | Description |
|
|
33
|
+
| ------ | ------- | ------------------------------------------- |
|
|
34
|
+
| `base` | `<div>` | Root layout container with `role="toolbar"` |
|
|
35
|
+
|
|
36
|
+
## CSS Custom Properties
|
|
37
|
+
|
|
38
|
+
| Property | Default | Description |
|
|
39
|
+
| ---------------------------- | --------------------------- | ----------------------------------------- |
|
|
40
|
+
| `--cv-toolbar-gap` | `var(--cv-space-1, 4px)` | Spacing between toolbar children |
|
|
41
|
+
| `--cv-toolbar-padding` | `var(--cv-space-1, 4px)` | Internal padding of the toolbar container |
|
|
42
|
+
| `--cv-toolbar-border-radius` | `var(--cv-radius-md, 10px)` | Border radius of the toolbar container |
|
|
43
|
+
|
|
44
|
+
Additionally, component styles depend on theme tokens through fallback values:
|
|
45
|
+
|
|
46
|
+
| Theme Property | Default | Description |
|
|
47
|
+
| -------------------- | --------- | ------------------------ |
|
|
48
|
+
| `--cv-color-border` | `#2a3245` | Toolbar border color |
|
|
49
|
+
| `--cv-color-surface` | `#141923` | Toolbar background color |
|
|
50
|
+
| `--cv-space-1` | `4px` | Gap and padding fallback |
|
|
51
|
+
| `--cv-radius-md` | `10px` | Border radius fallback |
|
|
52
|
+
|
|
53
|
+
## Visual States
|
|
54
|
+
|
|
55
|
+
| Host selector | Description |
|
|
56
|
+
| --------------------------------- | -------------------------------------------------------------- |
|
|
57
|
+
| `:host([orientation="vertical"])` | Flex direction switches to column; items stretch to fill width |
|
|
58
|
+
|
|
59
|
+
## Events
|
|
60
|
+
|
|
61
|
+
| Event | Detail | Description |
|
|
62
|
+
| ----------- | ---------------------------- | -------------------------------------------------------------------------------------------- |
|
|
63
|
+
| `cv-input` | `{activeId: string \| null}` | Fires on any user-driven active item change (arrow keys, click, focus) |
|
|
64
|
+
| `cv-change` | `{activeId: string \| null}` | Fires when active item commits (same detail as `cv-input`; both fire together on navigation) |
|
|
65
|
+
|
|
66
|
+
Both `cv-input` and `cv-change` fire when user interaction changes the active item. Programmatic `value` attribute changes that result in a headless state update also dispatch these events.
|
|
67
|
+
|
|
68
|
+
## Reactive State Mapping
|
|
69
|
+
|
|
70
|
+
`cv-toolbar` is a visual adapter over headless `createToolbar`.
|
|
71
|
+
|
|
72
|
+
### UIKit Property to Headless Binding
|
|
73
|
+
|
|
74
|
+
| UIKit Property | Direction | Headless Binding |
|
|
75
|
+
| -------------- | -------------- | --------------------------------------------------------- |
|
|
76
|
+
| `value` | attr -> action | `actions.setActive(value)` when `value` attribute changes |
|
|
77
|
+
| `orientation` | attr -> option | passed as `orientation` in `createToolbar(options)` |
|
|
78
|
+
| `wrap` | attr -> option | passed as `wrap` in `createToolbar(options)` |
|
|
79
|
+
| `aria-label` | attr -> option | passed as `ariaLabel` in `createToolbar(options)` |
|
|
80
|
+
|
|
81
|
+
### Headless State to DOM Reflection
|
|
82
|
+
|
|
83
|
+
| Headless State | Direction | DOM Reflection |
|
|
84
|
+
| ------------------ | ------------- | ---------------------------------------------------------------------- |
|
|
85
|
+
| `state.activeId()` | state -> attr | `cv-toolbar[value]` host attribute |
|
|
86
|
+
| `state.activeId()` | state -> attr | `cv-toolbar-item[active]` boolean attribute on the active item element |
|
|
87
|
+
| `state.activeId()` | state -> prop | `cv-toolbar-item.tabIndex` set to `0` for active, `-1` for others |
|
|
88
|
+
|
|
89
|
+
### Headless Actions Called
|
|
90
|
+
|
|
91
|
+
| Action | UIKit Trigger |
|
|
92
|
+
| ------------------------------ | -------------------------------------------------------------------------------------------------- |
|
|
93
|
+
| `actions.setActive(id)` | Item receives focus or click; also called when `value` attribute changes |
|
|
94
|
+
| `actions.handleKeyDown(event)` | `keydown` event on the toolbar root `[part="base"]` |
|
|
95
|
+
| `actions.handleToolbarFocus()` | `focusin` event on toolbar root when toolbar was not previously focused (re-entry detection) |
|
|
96
|
+
| `actions.handleToolbarBlur()` | `focusout` event on toolbar root when `relatedTarget` is outside the toolbar (full blur detection) |
|
|
97
|
+
|
|
98
|
+
### Headless Contracts Spread
|
|
99
|
+
|
|
100
|
+
| Contract | UIKit Target |
|
|
101
|
+
| --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
102
|
+
| `contracts.getRootProps()` | Spread onto the `[part="base"]` element (`id`, `role`, `aria-orientation`, `aria-label`) |
|
|
103
|
+
| `contracts.getItemProps(id)` | Spread onto each `cv-toolbar-item` element (`id`, `tabindex`, `aria-disabled`, `data-active`). The `onFocus` callback is bound to the element's `focus` event. |
|
|
104
|
+
| `contracts.getSeparatorProps(id)` | Spread onto each `cv-toolbar-separator` element (`id`, `role`, `aria-orientation`) |
|
|
105
|
+
|
|
106
|
+
### UIKit-Only Concerns (Not in Headless)
|
|
107
|
+
|
|
108
|
+
- **Focus management DOM calls**: Calling `.focus()` on the DOM element matching `activeId` after keyboard navigation. Headless sets state; UIKit moves DOM focus.
|
|
109
|
+
- **Focus-in/focus-out tracking**: UIKit must detect toolbar entry vs. internal focus moves (e.g., using a `hasFocus` flag updated on `focusin`/`focusout` with `relatedTarget` checks).
|
|
110
|
+
- **Separator rendering**: Visual appearance of separators (line style, thickness, spacing) is a UIKit concern. Headless only provides ARIA props.
|
|
111
|
+
- **Slot change handling**: Rebuilding the headless model when children are added or removed via `slotchange`.
|
|
112
|
+
- **`cv-input` / `cv-change` events**: Custom DOM events dispatched by the UIKit wrapper, not part of the headless model.
|
|
113
|
+
|
|
114
|
+
UIKit does not own navigation or focus-memory logic; headless state is the source of truth.
|
|
115
|
+
|
|
116
|
+
## Keyboard Interaction
|
|
117
|
+
|
|
118
|
+
| Key | Horizontal | Vertical |
|
|
119
|
+
| ------------ | --------------------- | --------------------- |
|
|
120
|
+
| `ArrowRight` | Move to next item | — |
|
|
121
|
+
| `ArrowLeft` | Move to previous item | — |
|
|
122
|
+
| `ArrowDown` | — | Move to next item |
|
|
123
|
+
| `ArrowUp` | — | Move to previous item |
|
|
124
|
+
| `Home` | Move to first item | Move to first item |
|
|
125
|
+
| `End` | Move to last item | Move to last item |
|
|
126
|
+
|
|
127
|
+
- Disabled items and separators are skipped during keyboard navigation.
|
|
128
|
+
- When `wrap` is `true` (default), navigation wraps from last to first and vice versa.
|
|
129
|
+
- When `wrap` is `false`, navigation clamps at boundaries (first/last item).
|
|
130
|
+
- Roving tabindex: only the active item has `tabindex="0"`; all others have `tabindex="-1"`.
|
|
131
|
+
- Focus memory: re-entering the toolbar via Tab restores focus to the last-active item.
|
|
132
|
+
|
|
133
|
+
## Usage
|
|
134
|
+
|
|
135
|
+
```html
|
|
136
|
+
<cv-toolbar aria-label="Text formatting">
|
|
137
|
+
<cv-toolbar-item value="bold">Bold</cv-toolbar-item>
|
|
138
|
+
<cv-toolbar-item value="italic">Italic</cv-toolbar-item>
|
|
139
|
+
<cv-toolbar-item value="underline">Underline</cv-toolbar-item>
|
|
140
|
+
</cv-toolbar>
|
|
141
|
+
|
|
142
|
+
<cv-toolbar aria-label="Actions" wrap="false">
|
|
143
|
+
<cv-toolbar-item value="cut">Cut</cv-toolbar-item>
|
|
144
|
+
<cv-toolbar-item value="copy">Copy</cv-toolbar-item>
|
|
145
|
+
<cv-toolbar-separator></cv-toolbar-separator>
|
|
146
|
+
<cv-toolbar-item value="paste">Paste</cv-toolbar-item>
|
|
147
|
+
</cv-toolbar>
|
|
148
|
+
|
|
149
|
+
<cv-toolbar orientation="vertical" aria-label="Tools">
|
|
150
|
+
<cv-toolbar-item value="brush">Brush</cv-toolbar-item>
|
|
151
|
+
<cv-toolbar-item value="eraser">Eraser</cv-toolbar-item>
|
|
152
|
+
<cv-toolbar-separator></cv-toolbar-separator>
|
|
153
|
+
<cv-toolbar-item value="fill">Fill</cv-toolbar-item>
|
|
154
|
+
<cv-toolbar-item value="picker" disabled>Picker</cv-toolbar-item>
|
|
155
|
+
</cv-toolbar>
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Child Elements
|
|
159
|
+
|
|
160
|
+
### cv-toolbar-item
|
|
161
|
+
|
|
162
|
+
Interactive element within a toolbar that participates in roving tabindex navigation.
|
|
163
|
+
|
|
164
|
+
#### Anatomy
|
|
165
|
+
|
|
166
|
+
```
|
|
167
|
+
<cv-toolbar-item> (host)
|
|
168
|
+
└── <div part="base">
|
|
169
|
+
└── <slot>
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
#### Attributes
|
|
173
|
+
|
|
174
|
+
| Attribute | Type | Default | Description |
|
|
175
|
+
| ---------- | ------- | ------- | ------------------------------------------------------------------------ |
|
|
176
|
+
| `value` | String | `""` | Unique identifier for this item. Auto-generated as `item-{n}` if empty. |
|
|
177
|
+
| `disabled` | Boolean | `false` | Prevents this item from receiving focus via keyboard navigation |
|
|
178
|
+
| `active` | Boolean | `false` | Whether this item is the current roving-focus target (managed by parent) |
|
|
179
|
+
|
|
180
|
+
#### Slots
|
|
181
|
+
|
|
182
|
+
| Slot | Description |
|
|
183
|
+
| ----------- | ------------------------------------------------ |
|
|
184
|
+
| `(default)` | Item content (text, icon, or any inline content) |
|
|
185
|
+
|
|
186
|
+
#### CSS Parts
|
|
187
|
+
|
|
188
|
+
| Part | Element | Description |
|
|
189
|
+
| ------ | ------- | ------------------------ |
|
|
190
|
+
| `base` | `<div>` | Root interactive wrapper |
|
|
191
|
+
|
|
192
|
+
#### CSS Custom Properties
|
|
193
|
+
|
|
194
|
+
| Property | Default | Description |
|
|
195
|
+
| ---------------------------------- | -------------------------- | ------------------------------ |
|
|
196
|
+
| `--cv-toolbar-item-min-height` | `32px` | Minimum block size of the item |
|
|
197
|
+
| `--cv-toolbar-item-padding-inline` | `var(--cv-space-3, 12px)` | Horizontal padding |
|
|
198
|
+
| `--cv-toolbar-item-border-radius` | `var(--cv-radius-sm, 6px)` | Border radius |
|
|
199
|
+
|
|
200
|
+
Additionally, component styles depend on theme tokens through fallback values:
|
|
201
|
+
|
|
202
|
+
| Theme Property | Default | Description |
|
|
203
|
+
| ---------------------- | --------- | -------------------------- |
|
|
204
|
+
| `--cv-color-border` | `#2a3245` | Item border color |
|
|
205
|
+
| `--cv-color-surface` | `#141923` | Item background color |
|
|
206
|
+
| `--cv-color-text` | `#e8ecf6` | Item text color |
|
|
207
|
+
| `--cv-color-primary` | `#65d7ff` | Active state accent color |
|
|
208
|
+
| `--cv-duration-fast` | `120ms` | Transition duration |
|
|
209
|
+
| `--cv-easing-standard` | `ease` | Transition timing function |
|
|
210
|
+
|
|
211
|
+
#### Visual States
|
|
212
|
+
|
|
213
|
+
| Host selector | Description |
|
|
214
|
+
| ----------------------- | ----------------------------------------------------------------------- |
|
|
215
|
+
| `:host([active])` | Primary-tinted border and blended background using `--cv-color-primary` |
|
|
216
|
+
| `:host([disabled])` | Reduced opacity (`0.55`) |
|
|
217
|
+
| `:host(:focus-visible)` | Focus ring: `2px solid var(--cv-color-primary)` with `1px` offset |
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
### cv-toolbar-separator
|
|
222
|
+
|
|
223
|
+
Non-interactive visual divider within a toolbar. Separators are skipped by keyboard navigation and cannot receive focus.
|
|
224
|
+
|
|
225
|
+
#### Anatomy
|
|
226
|
+
|
|
227
|
+
```
|
|
228
|
+
<cv-toolbar-separator> (host)
|
|
229
|
+
└── <div part="base" role="separator" aria-orientation="…">
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
The separator's `aria-orientation` is perpendicular to the toolbar's orientation: a horizontal toolbar renders vertical separators, and vice versa.
|
|
233
|
+
|
|
234
|
+
#### Attributes
|
|
235
|
+
|
|
236
|
+
| Attribute | Type | Default | Description |
|
|
237
|
+
| --------- | ------ | ------- | ---------------------------------------------------------------- |
|
|
238
|
+
| `value` | String | `""` | Identifier used to match the separator in the headless item list |
|
|
239
|
+
|
|
240
|
+
#### CSS Parts
|
|
241
|
+
|
|
242
|
+
| Part | Element | Description |
|
|
243
|
+
| ------ | ------- | ---------------------------------------------- |
|
|
244
|
+
| `base` | `<div>` | Separator line element with `role="separator"` |
|
|
245
|
+
|
|
246
|
+
#### CSS Custom Properties
|
|
247
|
+
|
|
248
|
+
| Property | Default | Description |
|
|
249
|
+
| ------------------------------- | --------------------------------- | ------------------------------- |
|
|
250
|
+
| `--cv-toolbar-separator-size` | `1px` | Thickness of the separator line |
|
|
251
|
+
| `--cv-toolbar-separator-color` | `var(--cv-color-border, #2a3245)` | Color of the separator line |
|
|
252
|
+
| `--cv-toolbar-separator-margin` | `var(--cv-space-1, 4px)` | Margin around the separator |
|
|
253
|
+
|
|
254
|
+
#### Visual States
|
|
255
|
+
|
|
256
|
+
| Host selector | Description |
|
|
257
|
+
| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
258
|
+
| `:host` | In a horizontal toolbar: vertical line (`height: auto`, `width: --cv-toolbar-separator-size`). In a vertical toolbar: horizontal line (`width: auto`, `height: --cv-toolbar-separator-size`). Orientation is communicated via the parent spreading `getSeparatorProps`. |
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# cv-tooltip
|
|
2
|
+
|
|
3
|
+
Contextual information overlay that appears near a trigger element on hover, focus, click, or programmatic control.
|
|
4
|
+
|
|
5
|
+
**Headless:** [`createTooltip`](https://github.com/chromvoid/headless-ui/blob/main/specs/components/tooltip.md)
|
|
6
|
+
|
|
7
|
+
## Anatomy
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
<cv-tooltip> (host)
|
|
11
|
+
└── <span part="base">
|
|
12
|
+
├── <span part="trigger">
|
|
13
|
+
│ └── <slot name="trigger">
|
|
14
|
+
└── <span part="content" role="tooltip">
|
|
15
|
+
├── <slot name="content">
|
|
16
|
+
└── <span part="arrow"> ← only when [arrow]
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Attributes
|
|
20
|
+
|
|
21
|
+
| Attribute | Type | Default | Description |
|
|
22
|
+
| ------------ | ------- | --------------- | -------------------------------------------------------------------------- |
|
|
23
|
+
| `open` | Boolean | `false` | Reflects tooltip visibility; can be set to programmatically show or hide |
|
|
24
|
+
| `disabled` | Boolean | `false` | Disables all trigger interactions; removes `aria-describedby` from trigger |
|
|
25
|
+
| `show-delay` | Number | `120` | Milliseconds to wait before showing the tooltip |
|
|
26
|
+
| `hide-delay` | Number | `80` | Milliseconds to wait before hiding the tooltip |
|
|
27
|
+
| `trigger` | String | `'hover focus'` | Space-separated trigger modes: `hover` \| `focus` \| `click` \| `manual` |
|
|
28
|
+
| `arrow` | Boolean | `false` | Renders the `part="arrow"` CSS triangle pointing toward the trigger |
|
|
29
|
+
|
|
30
|
+
## Slots
|
|
31
|
+
|
|
32
|
+
| Slot | Description |
|
|
33
|
+
| --------- | ---------------------------------------------------------------------------- |
|
|
34
|
+
| `trigger` | The element that activates the tooltip (receives `aria-describedby` linkage) |
|
|
35
|
+
| `content` | Rich HTML tooltip body content |
|
|
36
|
+
|
|
37
|
+
## CSS Parts
|
|
38
|
+
|
|
39
|
+
| Part | Element | Description |
|
|
40
|
+
| --------- | -------- | -------------------------------------------------------------------- |
|
|
41
|
+
| `base` | `<span>` | Root layout wrapper, positioned relatively |
|
|
42
|
+
| `trigger` | `<span>` | Wrapper around the trigger slot; receives event listeners |
|
|
43
|
+
| `content` | `<span>` | Tooltip body container with `role="tooltip"`; hidden when not open |
|
|
44
|
+
| `arrow` | `<span>` | Optional CSS triangle indicator; rendered only when `[arrow]` is set |
|
|
45
|
+
|
|
46
|
+
## CSS Custom Properties
|
|
47
|
+
|
|
48
|
+
Component styles depend on theme tokens through inline fallback values:
|
|
49
|
+
|
|
50
|
+
> **Note:** Component-level `--cv-tooltip-*` custom property indirection is not implemented.
|
|
51
|
+
> Styles reference theme tokens directly.
|
|
52
|
+
|
|
53
|
+
| Theme Property | Default | Description |
|
|
54
|
+
| ----------------------------- | ------------------------------- | --------------------------- |
|
|
55
|
+
| `--cv-color-surface-elevated` | `#1d2432` | Elevated surface background |
|
|
56
|
+
| `--cv-color-border` | `#2a3245` | Border color |
|
|
57
|
+
| `--cv-color-text` | `#e8ecf6` | Default text color |
|
|
58
|
+
| `--cv-shadow-1` | `0 2px 8px rgba(0, 0, 0, 0.24)` | Drop shadow |
|
|
59
|
+
| `--cv-radius-sm` | `6px` | Border radius |
|
|
60
|
+
| `--cv-space-1` | `4px` | Small spacing scale |
|
|
61
|
+
| `--cv-space-2` | `8px` | Medium spacing scale |
|
|
62
|
+
|
|
63
|
+
## Visual States
|
|
64
|
+
|
|
65
|
+
| Host selector | Description |
|
|
66
|
+
| ------------------- | ------------------------------------------------------------------- |
|
|
67
|
+
| `:host([open])` | Tooltip content is visible; `[part="content"]` has `hidden` removed |
|
|
68
|
+
| `:host([disabled])` | All trigger interactions are blocked; `aria-describedby` is removed |
|
|
69
|
+
| `:host([arrow])` | Arrow indicator (`[part="arrow"]`) is rendered and visible |
|
|
70
|
+
|
|
71
|
+
## Events
|
|
72
|
+
|
|
73
|
+
| Event | Detail | Description |
|
|
74
|
+
| ----------- | ------------------- | ------------------------------------------------------------- |
|
|
75
|
+
| `cv-input` | `{ open: boolean }` | Fires on every open/close transition triggered by interaction |
|
|
76
|
+
| `cv-change` | `{ open: boolean }` | Fires when the open state commits after interaction |
|
|
77
|
+
|
|
78
|
+
Both events bubble and are composed. They are dispatched together on every transition of `isOpen`.
|
|
79
|
+
|
|
80
|
+
## Reactive State Mapping
|
|
81
|
+
|
|
82
|
+
`cv-tooltip` is a visual adapter over headless `createTooltip`.
|
|
83
|
+
|
|
84
|
+
| UIKit Property | Direction | Headless Binding |
|
|
85
|
+
| -------------- | ------------- | ------------------------------------------------------------------- |
|
|
86
|
+
| `open` | attr → action | `actions.open()` / `actions.close()` depending on value |
|
|
87
|
+
| `disabled` | attr → action | `actions.setDisabled(value)` |
|
|
88
|
+
| `show-delay` | attr → option | passed as `showDelay` to `createTooltip(options)` (recreates model) |
|
|
89
|
+
| `hide-delay` | attr → option | passed as `hideDelay` to `createTooltip(options)` (recreates model) |
|
|
90
|
+
| `trigger` | attr → option | passed as `trigger` to `createTooltip(options)` |
|
|
91
|
+
|
|
92
|
+
| Headless State | Direction | DOM Reflection |
|
|
93
|
+
| -------------------- | ------------ | --------------------------- |
|
|
94
|
+
| `state.isOpen()` | state → attr | `[open]` host attribute |
|
|
95
|
+
| `state.isDisabled()` | state → attr | `[disabled]` host attribute |
|
|
96
|
+
|
|
97
|
+
- `contracts.getTriggerProps()` is spread onto `[part="trigger"]` to apply `id`, `aria-describedby`, and all active event handlers (`onPointerEnter`, `onPointerLeave`, `onFocus`, `onBlur`, `onClick`, `onKeyDown`) depending on the active `trigger` modes.
|
|
98
|
+
- `contracts.getTooltipProps()` is spread onto `[part="content"]` to apply `id`, `role="tooltip"`, `tabindex="-1"`, and `hidden`.
|
|
99
|
+
- `aria-describedby` is also propagated to assigned slotted trigger elements directly via `syncTriggerAria`.
|
|
100
|
+
- UIKit dispatches `cv-input` and `cv-change` events by observing transitions of `isOpen` caused by interaction; programmatic `open`/`close` calls that do not change state do not re-emit.
|
|
101
|
+
- UIKit does not own trigger or delay logic; headless state is the source of truth.
|
|
102
|
+
- When `show-delay` or `hide-delay` changes, the model is recreated with the current `open` state preserved as `initialOpen`.
|
|
103
|
+
- Public methods `show()` and `hide()` delegate to `model.actions.show()` / `model.actions.hide()` for `manual` mode consumers.
|
|
104
|
+
|
|
105
|
+
## Usage
|
|
106
|
+
|
|
107
|
+
```html
|
|
108
|
+
<!-- Default: hover + focus triggers -->
|
|
109
|
+
<cv-tooltip>
|
|
110
|
+
<button slot="trigger">Hover me</button>
|
|
111
|
+
<span slot="content">Contextual info</span>
|
|
112
|
+
</cv-tooltip>
|
|
113
|
+
|
|
114
|
+
<!-- Click trigger only -->
|
|
115
|
+
<cv-tooltip trigger="click">
|
|
116
|
+
<button slot="trigger">Click me</button>
|
|
117
|
+
<span slot="content">Shown on click</span>
|
|
118
|
+
</cv-tooltip>
|
|
119
|
+
|
|
120
|
+
<!-- With arrow indicator -->
|
|
121
|
+
<cv-tooltip arrow>
|
|
122
|
+
<button slot="trigger">With arrow</button>
|
|
123
|
+
<span slot="content">Tooltip with arrow</span>
|
|
124
|
+
</cv-tooltip>
|
|
125
|
+
|
|
126
|
+
<!-- Disabled -->
|
|
127
|
+
<cv-tooltip disabled>
|
|
128
|
+
<button slot="trigger">No tooltip</button>
|
|
129
|
+
<span slot="content">Never shown</span>
|
|
130
|
+
</cv-tooltip>
|
|
131
|
+
|
|
132
|
+
<!-- Manual mode (programmatic control) -->
|
|
133
|
+
<cv-tooltip trigger="manual" id="my-tip">
|
|
134
|
+
<button slot="trigger">Target</button>
|
|
135
|
+
<span slot="content">Shown programmatically</span>
|
|
136
|
+
</cv-tooltip>
|
|
137
|
+
<script>
|
|
138
|
+
document.querySelector('#my-tip').show()
|
|
139
|
+
</script>
|
|
140
|
+
|
|
141
|
+
<!-- Custom delays -->
|
|
142
|
+
<cv-tooltip show-delay="300" hide-delay="200">
|
|
143
|
+
<button slot="trigger">Delayed</button>
|
|
144
|
+
<span slot="content">Appears after 300ms</span>
|
|
145
|
+
</cv-tooltip>
|
|
146
|
+
|
|
147
|
+
<!-- Rich HTML content -->
|
|
148
|
+
<cv-tooltip>
|
|
149
|
+
<button slot="trigger">Rich tooltip</button>
|
|
150
|
+
<span slot="content"> <strong>Title</strong><br />Supporting text </span>
|
|
151
|
+
</cv-tooltip>
|
|
152
|
+
```
|