@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,207 @@
|
|
|
1
|
+
# cv-popover
|
|
2
|
+
|
|
3
|
+
Non-modal overlay anchored to a trigger element for contextual content such as menus, tooltips, or forms.
|
|
4
|
+
|
|
5
|
+
**Headless:** [`createPopover`](https://github.com/chromvoid/headless-ui/blob/main/specs/components/popover.md)
|
|
6
|
+
|
|
7
|
+
## Anatomy
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
<cv-popover> (host)
|
|
11
|
+
└── <div part="base">
|
|
12
|
+
├── <button part="trigger" type="button">
|
|
13
|
+
│ └── <slot name="trigger">
|
|
14
|
+
├── <div part="content" role="dialog">
|
|
15
|
+
│ ├── <slot>
|
|
16
|
+
│ └── <span part="arrow">
|
|
17
|
+
│ └── <slot name="arrow">
|
|
18
|
+
└── (document-level listeners for outside dismiss)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Attributes
|
|
22
|
+
|
|
23
|
+
| Attribute | Type | Default | Description |
|
|
24
|
+
| -------------------------- | ------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
25
|
+
| `open` | Boolean | `false` | Whether the popover content is visible |
|
|
26
|
+
| `placement` | String | `"bottom-start"` | Content placement relative to the anchor: `top` \| `top-start` \| `top-end` \| `bottom` \| `bottom-start` \| `bottom-end` \| `left` \| `left-start` \| `left-end` \| `right` \| `right-start` \| `right-end` |
|
|
27
|
+
| `anchor` | String | `"trigger"` | Positioning reference: `trigger` \| `host` |
|
|
28
|
+
| `offset` | Number | `4` | Distance (in px) between anchor and content |
|
|
29
|
+
| `arrow` | Boolean | `false` | Show an arrow pointing toward the anchor |
|
|
30
|
+
| `close-on-escape` | Boolean | `true` | Whether Escape key closes the popover |
|
|
31
|
+
| `close-on-outside-pointer` | Boolean | `true` | Whether clicking outside closes the popover |
|
|
32
|
+
| `close-on-outside-focus` | Boolean | `true` | Whether focusing outside closes the popover |
|
|
33
|
+
| `aria-label` | String | `""` | Accessible label for content panel |
|
|
34
|
+
| `aria-labelledby` | String | `""` | Id of element labelling the content panel |
|
|
35
|
+
|
|
36
|
+
## Slots
|
|
37
|
+
|
|
38
|
+
| Slot | Description |
|
|
39
|
+
| ----------- | --------------------------------------------- |
|
|
40
|
+
| `(default)` | Popover content |
|
|
41
|
+
| `trigger` | Trigger element (defaults to a styled button) |
|
|
42
|
+
| `arrow` | Custom arrow content (replaces default arrow) |
|
|
43
|
+
|
|
44
|
+
## CSS Parts
|
|
45
|
+
|
|
46
|
+
| Part | Element | Description |
|
|
47
|
+
| --------- | ---------- | --------------------------------------------- |
|
|
48
|
+
| `base` | `<div>` | Root layout wrapper with `position: relative` |
|
|
49
|
+
| `trigger` | `<button>` | Trigger element that opens/closes the popover |
|
|
50
|
+
| `content` | `<div>` | Popover content panel with `role="dialog"` |
|
|
51
|
+
| `arrow` | `<span>` | Arrow element pointing toward the anchor |
|
|
52
|
+
|
|
53
|
+
## CSS Custom Properties
|
|
54
|
+
|
|
55
|
+
| Property | Default | Description |
|
|
56
|
+
| ------------------------------ | -------------------------------- | ------------------------------------- |
|
|
57
|
+
| `--cv-popover-offset` | `var(--cv-space-1, 4px)` | Distance between anchor and content |
|
|
58
|
+
| `--cv-popover-min-inline-size` | `max(220px, 100%)` | Minimum width of content panel |
|
|
59
|
+
| `--cv-popover-max-inline-size` | `min(560px, calc(100vw - 32px))` | Maximum width of content panel |
|
|
60
|
+
| `--cv-popover-padding` | `var(--cv-space-3, 12px)` | Content panel padding |
|
|
61
|
+
| `--cv-popover-border-radius` | `var(--cv-radius-md, 10px)` | Content panel border radius |
|
|
62
|
+
| `--cv-popover-z-index` | `20` | Content panel stacking order |
|
|
63
|
+
| `--cv-popover-arrow-size` | `8px` | Width and height of the arrow element |
|
|
64
|
+
|
|
65
|
+
Additionally, component styles depend on theme tokens through fallback values:
|
|
66
|
+
|
|
67
|
+
| Theme Property | Default | Description |
|
|
68
|
+
| ----------------------------- | ------------------------------- | ------------------------------------ |
|
|
69
|
+
| `--cv-color-border` | `#2a3245` | Border color for trigger and content |
|
|
70
|
+
| `--cv-color-surface` | `#141923` | Trigger background color |
|
|
71
|
+
| `--cv-color-surface-elevated` | `#1d2432` | Content panel background color |
|
|
72
|
+
| `--cv-color-text` | `#e8ecf6` | Default text color |
|
|
73
|
+
| `--cv-color-primary` | `#65d7ff` | Focus ring color |
|
|
74
|
+
| `--cv-shadow-1` | `0 2px 8px rgba(0, 0, 0, 0.24)` | Content panel box shadow |
|
|
75
|
+
| `--cv-radius-sm` | `6px` | Trigger border radius fallback |
|
|
76
|
+
| `--cv-radius-md` | `10px` | Content border radius fallback |
|
|
77
|
+
| `--cv-space-1` | `4px` | Small spacing scale fallback |
|
|
78
|
+
| `--cv-space-2` | `8px` | Medium spacing scale fallback |
|
|
79
|
+
| `--cv-space-3` | `12px` | Medium-large spacing scale fallback |
|
|
80
|
+
|
|
81
|
+
## Visual States
|
|
82
|
+
|
|
83
|
+
| Host selector | Description |
|
|
84
|
+
| ----------------------------------- | -------------------------------------------------------- |
|
|
85
|
+
| `:host([open])` | Content panel is visible |
|
|
86
|
+
| `:host(:not([open]))` | Content panel is hidden |
|
|
87
|
+
| `:host([placement="top"])` | Content positioned above anchor, centered |
|
|
88
|
+
| `:host([placement="top-start"])` | Content positioned above anchor, start-aligned |
|
|
89
|
+
| `:host([placement="top-end"])` | Content positioned above anchor, end-aligned |
|
|
90
|
+
| `:host([placement="bottom"])` | Content positioned below anchor, centered |
|
|
91
|
+
| `:host([placement="bottom-start"])` | Content positioned below anchor, start-aligned (default) |
|
|
92
|
+
| `:host([placement="bottom-end"])` | Content positioned below anchor, end-aligned |
|
|
93
|
+
| `:host([placement="left"])` | Content positioned to the left, centered |
|
|
94
|
+
| `:host([placement="left-start"])` | Content positioned to the left, start-aligned |
|
|
95
|
+
| `:host([placement="left-end"])` | Content positioned to the left, end-aligned |
|
|
96
|
+
| `:host([placement="right"])` | Content positioned to the right, centered |
|
|
97
|
+
| `:host([placement="right-start"])` | Content positioned to the right, start-aligned |
|
|
98
|
+
| `:host([placement="right-end"])` | Content positioned to the right, end-aligned |
|
|
99
|
+
| `:host([anchor="host"])` | Content positioned relative to host instead of trigger |
|
|
100
|
+
| `:host([arrow])` | Arrow element is visible |
|
|
101
|
+
|
|
102
|
+
## Events
|
|
103
|
+
|
|
104
|
+
| Event | Detail | Cancelable | Description |
|
|
105
|
+
| -------------- | -------------------------------------------------------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
106
|
+
| `beforetoggle` | `{open: boolean, openedBy: string \| null, dismissIntent: string \| null}` | Yes (on open) | Fires before the open state changes. Canceling (via `preventDefault()`) when opening prevents the popover from opening. Not cancelable on close. |
|
|
107
|
+
| `toggle` | `{open: boolean, openedBy: string \| null, dismissIntent: string \| null}` | No | Fires after the open state has changed |
|
|
108
|
+
|
|
109
|
+
Event detail fields:
|
|
110
|
+
|
|
111
|
+
- `open` — the new visibility state (`true` when opening, `false` when closing)
|
|
112
|
+
- `openedBy` — how the popover was opened: `"keyboard"` \| `"pointer"` \| `"programmatic"` \| `null`
|
|
113
|
+
- `dismissIntent` — why the popover was closed: `"escape"` \| `"outside-pointer"` \| `"outside-focus"` \| `"programmatic"` \| `null`
|
|
114
|
+
|
|
115
|
+
## Reactive State Mapping
|
|
116
|
+
|
|
117
|
+
`cv-popover` is a visual adapter over headless `createPopover`.
|
|
118
|
+
|
|
119
|
+
| UIKit Property | Direction | Headless Binding |
|
|
120
|
+
| -------------------------- | -------------- | ----------------------------------------------------------------------- |
|
|
121
|
+
| `open` | attr -> action | `actions.open(source)` / `actions.close(intent)` based on boolean value |
|
|
122
|
+
| `close-on-escape` | attr -> option | `closeOnEscape` passed to `createPopover(options)` |
|
|
123
|
+
| `close-on-outside-pointer` | attr -> option | `closeOnOutsidePointer` passed to `createPopover(options)` |
|
|
124
|
+
| `close-on-outside-focus` | attr -> option | `closeOnOutsideFocus` passed to `createPopover(options)` |
|
|
125
|
+
| `aria-label` | attr -> option | `ariaLabel` passed to `createPopover(options)` |
|
|
126
|
+
| `aria-labelledby` | attr -> option | `ariaLabelledBy` passed to `createPopover(options)` |
|
|
127
|
+
|
|
128
|
+
| Headless State | Direction | DOM Reflection |
|
|
129
|
+
| --------------------------- | -------------- | ------------------------------------------------------- |
|
|
130
|
+
| `state.isOpen()` | state -> attr | `[open]` host attribute |
|
|
131
|
+
| `state.openedBy()` | state -> event | Included in `beforetoggle` / `toggle` event detail |
|
|
132
|
+
| `state.lastDismissIntent()` | state -> event | Included in `beforetoggle` / `toggle` event detail |
|
|
133
|
+
| `state.restoreTargetId()` | state -> DOM | Focus restored to trigger element after close |
|
|
134
|
+
| `state.useNativePopover()` | state -> DOM | Controls native `showPopover()` / `hidePopover()` calls |
|
|
135
|
+
|
|
136
|
+
- `contracts.getTriggerProps()` is spread onto the inner `[part="trigger"]` element to apply `role`, `aria-haspopup`, `aria-expanded`, `aria-controls`, `tabindex`, `popovertarget` (when native), and keyboard/click handlers.
|
|
137
|
+
- `contracts.getContentProps()` is spread onto the inner `[part="content"]` element to apply `role`, `aria-modal`, `aria-label`, `aria-labelledby`, `tabindex`, `hidden` (when manual mode), `popover="manual"` (when native), and keyboard/outside-dismiss handlers.
|
|
138
|
+
- UIKit dispatches `beforetoggle` (cancelable on open) and `toggle` events by observing `isOpen` changes from user activation.
|
|
139
|
+
- UIKit does not own open/close, keyboard, or dismiss logic; headless state is the source of truth.
|
|
140
|
+
- When `beforetoggle` is canceled on open, UIKit calls `actions.close()` to revert headless state.
|
|
141
|
+
|
|
142
|
+
### Native Popover API Progressive Enhancement
|
|
143
|
+
|
|
144
|
+
UIKit auto-detects native Popover API support via feature check (`typeof HTMLElement.prototype.showPopover === 'function'`). When supported:
|
|
145
|
+
|
|
146
|
+
1. `useNativePopover: true` is passed to `createPopover(options)`.
|
|
147
|
+
2. Content element receives `popover="manual"` attribute (from headless contract) instead of `hidden`.
|
|
148
|
+
3. UIKit calls `contentElement.showPopover()` when `state.isOpen()` transitions to `true`.
|
|
149
|
+
4. UIKit calls `contentElement.hidePopover()` when `state.isOpen()` transitions to `false`.
|
|
150
|
+
5. UIKit listens for native `toggle` events on the content element and calls `actions.handleNativeToggle(newState)` to synchronize headless state.
|
|
151
|
+
|
|
152
|
+
When the native Popover API is not available, the component falls back to `hidden` attribute-based visibility management. Behavior is identical in both modes; the headless layer manages all open/close logic regardless.
|
|
153
|
+
|
|
154
|
+
### Placement (UIKit-only)
|
|
155
|
+
|
|
156
|
+
Placement is CSS-only (no Floating UI). The `placement` attribute maps to `data-placement` on the content element, which drives absolute positioning rules via CSS selectors. The `anchor` attribute controls whether the content panel is positioned relative to the trigger button or the host element. The `offset` attribute maps to `--cv-popover-offset`.
|
|
157
|
+
|
|
158
|
+
### Arrow (UIKit-only)
|
|
159
|
+
|
|
160
|
+
When the `arrow` boolean attribute is present, the `[part="arrow"]` element is rendered inside the content panel. It is positioned via CSS to point toward the anchor, with its direction derived from the current `placement`. The `arrow` slot allows custom arrow content. Arrow size is controlled by `--cv-popover-arrow-size`.
|
|
161
|
+
|
|
162
|
+
## Usage
|
|
163
|
+
|
|
164
|
+
```html
|
|
165
|
+
<!-- Basic popover -->
|
|
166
|
+
<cv-popover>
|
|
167
|
+
<span slot="trigger">Options</span>
|
|
168
|
+
<p>Popover content here</p>
|
|
169
|
+
</cv-popover>
|
|
170
|
+
|
|
171
|
+
<!-- Custom placement -->
|
|
172
|
+
<cv-popover placement="top" offset="8">
|
|
173
|
+
<span slot="trigger">Help</span>
|
|
174
|
+
<p>Helpful information</p>
|
|
175
|
+
</cv-popover>
|
|
176
|
+
|
|
177
|
+
<!-- With arrow -->
|
|
178
|
+
<cv-popover arrow placement="bottom">
|
|
179
|
+
<span slot="trigger">Info</span>
|
|
180
|
+
<p>Content with arrow pointer</p>
|
|
181
|
+
</cv-popover>
|
|
182
|
+
|
|
183
|
+
<!-- Close policies disabled -->
|
|
184
|
+
<cv-popover close-on-escape="false" close-on-outside-pointer="false">
|
|
185
|
+
<span slot="trigger">Sticky</span>
|
|
186
|
+
<p>Only closes via trigger toggle</p>
|
|
187
|
+
</cv-popover>
|
|
188
|
+
|
|
189
|
+
<!-- Anchored to host -->
|
|
190
|
+
<cv-popover anchor="host" placement="bottom-end">
|
|
191
|
+
<span slot="trigger">Menu</span>
|
|
192
|
+
<nav>Navigation items</nav>
|
|
193
|
+
</cv-popover>
|
|
194
|
+
|
|
195
|
+
<!-- Programmatic open -->
|
|
196
|
+
<cv-popover open>
|
|
197
|
+
<span slot="trigger">Already open</span>
|
|
198
|
+
<p>Visible on mount</p>
|
|
199
|
+
</cv-popover>
|
|
200
|
+
|
|
201
|
+
<!-- With custom arrow -->
|
|
202
|
+
<cv-popover arrow placement="top">
|
|
203
|
+
<span slot="trigger">Custom arrow</span>
|
|
204
|
+
<svg slot="arrow" viewBox="0 0 16 8"><polygon points="8,0 16,8 0,8" /></svg>
|
|
205
|
+
<p>Content</p>
|
|
206
|
+
</cv-popover>
|
|
207
|
+
```
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# cv-progress-ring
|
|
2
|
+
|
|
3
|
+
A read-only circular indicator that communicates determinate or indeterminate loading/completion progress via an SVG ring.
|
|
4
|
+
|
|
5
|
+
**Headless:** [`createProgress`](https://github.com/chromvoid/headless-ui/blob/main/specs/components/progress.md)
|
|
6
|
+
|
|
7
|
+
## Anatomy
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
<cv-progress-ring> (host)
|
|
11
|
+
└── <div part="base" role="progressbar">
|
|
12
|
+
└── <svg part="svg" viewBox="0 0 100 100">
|
|
13
|
+
│ ├── <circle part="track">
|
|
14
|
+
│ └── <circle part="indicator">
|
|
15
|
+
└── <span part="label">
|
|
16
|
+
└── <slot>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Attributes
|
|
20
|
+
|
|
21
|
+
| Attribute | Type | Default | Description |
|
|
22
|
+
| --------------- | ------- | ------- | ----------------------------------------------------------------------------------- |
|
|
23
|
+
| `value` | Number | `0` | Current progress value; clamped to `[min, max]` |
|
|
24
|
+
| `min` | Number | `0` | Minimum boundary |
|
|
25
|
+
| `max` | Number | `100` | Maximum boundary |
|
|
26
|
+
| `indeterminate` | Boolean | `false` | Switches to indeterminate (spinning animation) mode |
|
|
27
|
+
| `value-text` | String | — | Static override for `aria-valuetext`; takes precedence over the percentage fallback |
|
|
28
|
+
| `aria-label` | String | — | Accessible label passed through to headless |
|
|
29
|
+
|
|
30
|
+
## Slots
|
|
31
|
+
|
|
32
|
+
| Slot | Description |
|
|
33
|
+
| ----------- | ------------------------------------------------------------- |
|
|
34
|
+
| `(default)` | Label content rendered inside the ring (e.g. percentage text) |
|
|
35
|
+
|
|
36
|
+
## CSS Parts
|
|
37
|
+
|
|
38
|
+
| Part | Element | Description |
|
|
39
|
+
| ----------- | ---------- | ---------------------------------------------------------------- |
|
|
40
|
+
| `base` | `<div>` | Outer container with `role="progressbar"` |
|
|
41
|
+
| `svg` | `<svg>` | SVG element containing track and indicator circles |
|
|
42
|
+
| `track` | `<circle>` | Background circle representing the full track |
|
|
43
|
+
| `indicator` | `<circle>` | Foreground arc representing current progress |
|
|
44
|
+
| `label` | `<span>` | Content overlay centered inside the ring; wraps the default slot |
|
|
45
|
+
|
|
46
|
+
## CSS Custom Properties
|
|
47
|
+
|
|
48
|
+
| Property | Default | Description |
|
|
49
|
+
| ------------------------------------ | ---------------------------------- | ----------------------------------------------------------- |
|
|
50
|
+
| `--cv-progress-ring-size` | `80px` | Diameter of the ring (sets both inline-size and block-size) |
|
|
51
|
+
| `--cv-progress-ring-track-width` | `4px` | Stroke width of the background track circle |
|
|
52
|
+
| `--cv-progress-ring-indicator-width` | `4px` | Stroke width of the progress indicator arc |
|
|
53
|
+
| `--cv-progress-ring-track-color` | `var(--cv-color-surface, #141923)` | Background color of the track circle stroke |
|
|
54
|
+
| `--cv-progress-ring-indicator-color` | `var(--cv-color-primary, #65d7ff)` | Color of the filled indicator arc stroke |
|
|
55
|
+
| `--cv-progress-ring-label-color` | `var(--cv-color-text, #e8ecf6)` | Text color for the label slot content |
|
|
56
|
+
|
|
57
|
+
## Visual States
|
|
58
|
+
|
|
59
|
+
| Host selector | Description |
|
|
60
|
+
| ------------------------ | ----------------------------------------------------------------------------------- |
|
|
61
|
+
| `:host([indeterminate])` | Spinning/rotating animation on the indicator arc; indicator has a fixed arc length |
|
|
62
|
+
| `:host([data-complete])` | Success appearance when `value >= max` (indicator stroke uses `--cv-color-success`) |
|
|
63
|
+
|
|
64
|
+
## Reactive State Mapping
|
|
65
|
+
|
|
66
|
+
`cv-progress-ring` is a visual adapter over headless `createProgress`.
|
|
67
|
+
|
|
68
|
+
| UIKit Property | Direction | Headless Binding |
|
|
69
|
+
| --------------- | -------------- | -------------------------------------------------- |
|
|
70
|
+
| `value` | attr -> action | `actions.setValue(value)` |
|
|
71
|
+
| `min` | attr -> option | Passed as `min` in `createProgress(options)` |
|
|
72
|
+
| `max` | attr -> option | Passed as `max` in `createProgress(options)` |
|
|
73
|
+
| `indeterminate` | attr -> action | `actions.setIndeterminate(value)` |
|
|
74
|
+
| `value-text` | attr -> option | Passed as `valueText` in `createProgress(options)` |
|
|
75
|
+
| `aria-label` | attr -> option | Passed as `ariaLabel` in `createProgress(options)` |
|
|
76
|
+
|
|
77
|
+
| Headless State | Direction | DOM Reflection |
|
|
78
|
+
| ------------------------- | -------------- | -------------------------------------------------------------------------------- |
|
|
79
|
+
| `state.percentage()` | state -> style | Sets `stroke-dashoffset` on the indicator `<circle>` to represent the filled arc |
|
|
80
|
+
| `state.isIndeterminate()` | state -> attr | `[indeterminate]` host attribute |
|
|
81
|
+
| `state.isComplete()` | state -> attr | `[data-complete]` host attribute |
|
|
82
|
+
|
|
83
|
+
- `contracts.getProgressProps()` is spread onto the inner `[part="base"]` element to apply `role`, `aria-valuenow`, `aria-valuemin`, `aria-valuemax`, `aria-valuetext`, `aria-label`, and `id`.
|
|
84
|
+
- ARIA value attributes are present only in determinate mode; headless omits them in indeterminate mode.
|
|
85
|
+
- `aria-valuetext` resolution order (determinate only): `valueText` static override > rounded percentage fallback.
|
|
86
|
+
- UIKit does not own clamping, completion, or percentage logic; headless state is the source of truth.
|
|
87
|
+
|
|
88
|
+
## Events
|
|
89
|
+
|
|
90
|
+
None. `cv-progress-ring` is a read-only indicator with no user-modifiable state.
|
|
91
|
+
|
|
92
|
+
## Usage
|
|
93
|
+
|
|
94
|
+
```html
|
|
95
|
+
<!-- Basic determinate -->
|
|
96
|
+
<cv-progress-ring value="40" aria-label="Upload progress"></cv-progress-ring>
|
|
97
|
+
|
|
98
|
+
<!-- With label slot -->
|
|
99
|
+
<cv-progress-ring value="72" aria-label="Download">72%</cv-progress-ring>
|
|
100
|
+
|
|
101
|
+
<!-- Custom range -->
|
|
102
|
+
<cv-progress-ring value="3" min="0" max="10" aria-label="Steps completed"> 3/10 </cv-progress-ring>
|
|
103
|
+
|
|
104
|
+
<!-- Custom aria-valuetext -->
|
|
105
|
+
<cv-progress-ring value="3" max="10" value-text="Step 3 of 10" aria-label="Wizard progress">
|
|
106
|
+
</cv-progress-ring>
|
|
107
|
+
|
|
108
|
+
<!-- Indeterminate -->
|
|
109
|
+
<cv-progress-ring indeterminate aria-label="Loading"></cv-progress-ring>
|
|
110
|
+
|
|
111
|
+
<!-- Custom sizing and stroke widths -->
|
|
112
|
+
<cv-progress-ring
|
|
113
|
+
value="60"
|
|
114
|
+
aria-label="Battery"
|
|
115
|
+
style="
|
|
116
|
+
--cv-progress-ring-size: 120px;
|
|
117
|
+
--cv-progress-ring-track-width: 8px;
|
|
118
|
+
--cv-progress-ring-indicator-width: 8px;
|
|
119
|
+
--cv-progress-ring-indicator-color: limegreen;
|
|
120
|
+
"
|
|
121
|
+
>60%</cv-progress-ring
|
|
122
|
+
>
|
|
123
|
+
|
|
124
|
+
<!-- Small ring with thin stroke -->
|
|
125
|
+
<cv-progress-ring
|
|
126
|
+
value="80"
|
|
127
|
+
aria-label="Completion"
|
|
128
|
+
style="
|
|
129
|
+
--cv-progress-ring-size: 40px;
|
|
130
|
+
--cv-progress-ring-track-width: 2px;
|
|
131
|
+
--cv-progress-ring-indicator-width: 3px;
|
|
132
|
+
"
|
|
133
|
+
></cv-progress-ring>
|
|
134
|
+
```
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# cv-progress
|
|
2
|
+
|
|
3
|
+
A read-only indicator that communicates determinate or indeterminate loading/completion progress.
|
|
4
|
+
|
|
5
|
+
**Headless:** [`createProgress`](https://github.com/chromvoid/headless-ui/blob/main/specs/components/progress.md)
|
|
6
|
+
|
|
7
|
+
## Anatomy
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
<cv-progress> (host)
|
|
11
|
+
└── <div part="base" role="progressbar">
|
|
12
|
+
└── <div part="indicator">
|
|
13
|
+
└── <span part="label">
|
|
14
|
+
└── <slot>
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Attributes
|
|
18
|
+
|
|
19
|
+
| Attribute | Type | Default | Description |
|
|
20
|
+
| --------------- | ------- | ------- | ----------------------------------------------------------------------------------- |
|
|
21
|
+
| `value` | Number | `0` | Current progress value; clamped to `[min, max]` |
|
|
22
|
+
| `min` | Number | `0` | Minimum boundary |
|
|
23
|
+
| `max` | Number | `100` | Maximum boundary |
|
|
24
|
+
| `indeterminate` | Boolean | `false` | Switches to indeterminate (animated) mode |
|
|
25
|
+
| `value-text` | String | — | Static override for `aria-valuetext`; takes precedence over the percentage fallback |
|
|
26
|
+
| `aria-label` | String | — | Accessible label passed through to headless |
|
|
27
|
+
|
|
28
|
+
## Slots
|
|
29
|
+
|
|
30
|
+
| Slot | Description |
|
|
31
|
+
| ----------- | ------------------------------------------------------------------ |
|
|
32
|
+
| `(default)` | Label content rendered inside the indicator (e.g. percentage text) |
|
|
33
|
+
|
|
34
|
+
## CSS Parts
|
|
35
|
+
|
|
36
|
+
| Part | Element | Description |
|
|
37
|
+
| ----------- | -------- | -------------------------------------------------------- |
|
|
38
|
+
| `base` | `<div>` | Outer track container with `role="progressbar"` |
|
|
39
|
+
| `indicator` | `<div>` | Filled portion representing current progress |
|
|
40
|
+
| `label` | `<span>` | Content overlay inside indicator; wraps the default slot |
|
|
41
|
+
|
|
42
|
+
## CSS Custom Properties
|
|
43
|
+
|
|
44
|
+
| Property | Default | Description |
|
|
45
|
+
| ------------------------------- | ---------------------------------- | ------------------------------------- |
|
|
46
|
+
| `--cv-progress-height` | `10px` | Block size (height) of the track |
|
|
47
|
+
| `--cv-progress-track-color` | `var(--cv-color-surface, #141923)` | Background color of the track |
|
|
48
|
+
| `--cv-progress-indicator-color` | `var(--cv-color-primary, #65d7ff)` | Base color of the filled indicator |
|
|
49
|
+
| `--cv-progress-label-color` | `var(--cv-color-text, #e8ecf6)` | Text color for the label slot content |
|
|
50
|
+
|
|
51
|
+
## Visual States
|
|
52
|
+
|
|
53
|
+
| Host selector | Description |
|
|
54
|
+
| ------------------------ | ------------------------------------------------------------------ |
|
|
55
|
+
| `:host([indeterminate])` | Animated sliding bar; indicator width fixed, translateX animation |
|
|
56
|
+
| `:host([data-complete])` | Success appearance when `value >= max` (uses `--cv-color-success`) |
|
|
57
|
+
|
|
58
|
+
## Reactive State Mapping
|
|
59
|
+
|
|
60
|
+
`cv-progress` is a visual adapter over headless `createProgress`.
|
|
61
|
+
|
|
62
|
+
| UIKit Property | Direction | Headless Binding |
|
|
63
|
+
| --------------- | ------------- | -------------------------------------------------- |
|
|
64
|
+
| `value` | attr → action | `actions.setValue(value)` |
|
|
65
|
+
| `min` | attr → option | Passed as `min` in `createProgress(options)` |
|
|
66
|
+
| `max` | attr → option | Passed as `max` in `createProgress(options)` |
|
|
67
|
+
| `indeterminate` | attr → action | `actions.setIndeterminate(value)` |
|
|
68
|
+
| `value-text` | attr → option | Passed as `valueText` in `createProgress(options)` |
|
|
69
|
+
| `aria-label` | attr → option | Passed as `ariaLabel` in `createProgress(options)` |
|
|
70
|
+
|
|
71
|
+
| Headless State | Direction | DOM Reflection |
|
|
72
|
+
| ------------------------- | ------------- | ------------------------------------------------------- |
|
|
73
|
+
| `state.percentage()` | state → style | Sets `--cv-progress-width` on indicator for inline-size |
|
|
74
|
+
| `state.isIndeterminate()` | state → attr | `[indeterminate]` host attribute |
|
|
75
|
+
| `state.isComplete()` | state → attr | `[data-complete]` host attribute |
|
|
76
|
+
|
|
77
|
+
- `contracts.getProgressProps()` is spread onto the inner `[part="base"]` element to apply `role`, `aria-valuenow`, `aria-valuemin`, `aria-valuemax`, `aria-valuetext`, `aria-label`, and `id`.
|
|
78
|
+
- ARIA value attributes are present only in determinate mode; headless omits them in indeterminate mode.
|
|
79
|
+
- `aria-valuetext` resolution order (determinate only): `valueText` static override > rounded percentage fallback.
|
|
80
|
+
- UIKit does not own clamping or completion logic; headless state is the source of truth.
|
|
81
|
+
|
|
82
|
+
## Events
|
|
83
|
+
|
|
84
|
+
None. `cv-progress` is a read-only indicator with no user-modifiable state.
|
|
85
|
+
|
|
86
|
+
## Usage
|
|
87
|
+
|
|
88
|
+
```html
|
|
89
|
+
<!-- Basic determinate -->
|
|
90
|
+
<cv-progress value="40" aria-label="Upload progress"></cv-progress>
|
|
91
|
+
|
|
92
|
+
<!-- With label slot -->
|
|
93
|
+
<cv-progress value="72" aria-label="Download">72%</cv-progress>
|
|
94
|
+
|
|
95
|
+
<!-- Custom range -->
|
|
96
|
+
<cv-progress value="3" min="0" max="10" aria-label="Steps completed"></cv-progress>
|
|
97
|
+
|
|
98
|
+
<!-- Custom aria-valuetext -->
|
|
99
|
+
<cv-progress value="3" max="10" value-text="Step 3 of 10" aria-label="Wizard progress"></cv-progress>
|
|
100
|
+
|
|
101
|
+
<!-- Indeterminate -->
|
|
102
|
+
<cv-progress indeterminate aria-label="Loading"></cv-progress>
|
|
103
|
+
|
|
104
|
+
<!-- Styled via CSS custom properties -->
|
|
105
|
+
<cv-progress
|
|
106
|
+
value="60"
|
|
107
|
+
aria-label="Battery"
|
|
108
|
+
style="--cv-progress-height: 16px; --cv-progress-indicator-color: limegreen;"
|
|
109
|
+
></cv-progress>
|
|
110
|
+
```
|