actual-css 0.13.0 → 0.14.1
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/CHANGELOG.md +67 -0
- package/README.md +8 -8
- package/components.json +116 -10
- package/dist/actual.full.css +652 -77
- package/dist/actual.full.js +1 -1
- package/dist/actual.full.min.css +1 -1
- package/docs/design-notes/widget-primitives.md +4 -0
- package/docs/navigation.json +2 -0
- package/docs/pages/components/alert.md +12 -2
- package/docs/pages/components/button.md +3 -2
- package/docs/pages/components/list.md +6 -3
- package/docs/pages/components/segmented.md +83 -0
- package/docs/pages/components/steps.md +4 -2
- package/docs/pages/enhancements/flyout.md +9 -3
- package/docs/pages/enhancements/overview.md +2 -1
- package/docs/pages/enhancements/tabs.md +7 -2
- package/docs/pages/enhancements/tooltip.md +3 -1
- package/docs/pages/examples/overview.md +5 -3
- package/docs/pages/forms/color-swatches.md +131 -0
- package/docs/pages/forms/combobox.md +2 -2
- package/docs/pages/forms/controls.md +6 -3
- package/docs/pages/forms/joined-controls.md +6 -2
- package/docs/pages/forms/overview.md +1 -0
- package/docs/pages/forms/switch.md +4 -2
- package/docs/pages/foundations/theming.md +1 -1
- package/docs/pages/foundations/tokens.md +54 -23
- package/docs/pages/guides/design-tools.md +13 -7
- package/docs/pages/guides/introduction.md +1 -1
- package/docs/pages/layout/scroll-snap.md +4 -2
- package/package.json +5 -4
- package/reserved-classes.json +3 -0
- package/src/cli/actual-css.js +3 -3
- package/src/css/components/alert.css +65 -14
- package/src/css/components/app-nav.css +17 -9
- package/src/css/components/badge.css +23 -9
- package/src/css/components/button.css +17 -2
- package/src/css/components/close.css +6 -3
- package/src/css/components/index.css +1 -0
- package/src/css/components/list.css +18 -3
- package/src/css/components/navbar.css +5 -2
- package/src/css/components/segmented.css +186 -0
- package/src/css/components/steps.css +6 -3
- package/src/css/components/tab.css +1 -1
- package/src/css/core/focus.css +3 -0
- package/src/css/core/tokens.css +20 -4
- package/src/css/core/variants.css +16 -5
- package/src/css/forms/color-swatch.css +163 -0
- package/src/css/forms/form-actions.css +9 -0
- package/src/css/forms/index.css +1 -0
- package/src/css/forms/native.css +50 -20
- package/src/css/forms/switch.css +5 -2
- package/src/css/layout/scroll-snap.css +30 -0
- package/src/css/layout/topbar.css +10 -0
- package/src/js/enhance.js +14 -0
- package/src/js/floating-space.js +26 -0
- package/src/js/flyout.js +3 -1
- package/src/js/focus.js +16 -1
- package/src/js/parse-config.js +5 -2
- package/src/js/surface.js +10 -0
- package/src/js/tooltip.js +2 -2
- package/src/tooling/color.js +14 -1
- package/src/tooling/css-bundle.js +0 -5
- package/src/tooling/design-components.js +9 -5
- package/src/tooling/design-export.js +8 -0
- package/src/tooling/design-tokens.js +163 -43
- package/src/tooling/theme-contrast.js +151 -22
|
@@ -35,6 +35,10 @@ The named exports each module carries:
|
|
|
35
35
|
- `selectors` — `CLASSES`
|
|
36
36
|
|
|
37
37
|
`surface` also owns outside-click and Escape dismissal, and focus restore.
|
|
38
|
+
A click on an element with `data-flyout-close` closes the open panel around
|
|
39
|
+
it, whichever widget opened that panel. The attribute keeps the `flyout` name
|
|
40
|
+
because the panels authors write are flyouts; `surface` is only the code that
|
|
41
|
+
opens and closes them.
|
|
38
42
|
`menu` filters to usable items.
|
|
39
43
|
|
|
40
44
|
## Focus group
|
package/docs/navigation.json
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
- Could have simple or complex html content.
|
|
13
13
|
- A title and a description are plain siblings: the alert owns the small space between its direct content blocks, so neither needs a wrapper. Nested content keeps its own rhythm — wrap several paragraphs in `.prose`, or a differently spaced group in `.stack`, when the message needs a rhythm of its own.
|
|
14
14
|
- Alerts may include a decorative leading icon. Use `.alert-icon` on the icon element; the rest of the content flows into the remaining text column.
|
|
15
|
-
- Use `.compact` or `.spacious`
|
|
15
|
+
- Use `.compact` or `.spacious` on the alert to step its block padding. The inline padding stays stable.
|
|
16
16
|
- Use a [`.close`](close.md) button to make the alert dismissible. It is a direct trailing child in standard alerts and lives inside `.alert-title` in admonitions; the alert makes it compact.
|
|
17
17
|
|
|
18
18
|
Because alerts are soft by default, adding `.soft` to an intent (`.alert.soft.primary`,
|
|
@@ -216,7 +216,7 @@ full-bleed notice.
|
|
|
216
216
|
|
|
217
217
|
## Admonition
|
|
218
218
|
|
|
219
|
-
An admonition is a structured box with a tinted title bar, an optional icon, and body content on the page surface — like the `!!! note` callouts in mkdocs. Use `.alert-title` for the header and `.alert-body` for the content. Intent classes tint the title bar background and the border.
|
|
219
|
+
An admonition is a structured box with a tinted title bar, an optional icon, and body content on the page surface — like the `!!! note` callouts in mkdocs. Use `.alert-title` for the header and `.alert-body` for the content. Intent classes tint the title bar background and the border; shared variants paint the title bar, so `.solid` fills it — and keeps the body's frame neutral — for a notification that needs to stand out.
|
|
220
220
|
|
|
221
221
|
```html demo
|
|
222
222
|
<div class="stack">
|
|
@@ -239,6 +239,16 @@ An admonition is a structured box with a tinted title bar, an optional icon, and
|
|
|
239
239
|
<p>The intent tints the title bar, the border, and the body uses <code>var(--surface)</code>.</p>
|
|
240
240
|
</div>
|
|
241
241
|
</div>
|
|
242
|
+
|
|
243
|
+
<div class="alert success admonition solid">
|
|
244
|
+
<div class="alert-title">
|
|
245
|
+
<i class="ti ti-circle-check" aria-hidden="true"></i>
|
|
246
|
+
Saved
|
|
247
|
+
</div>
|
|
248
|
+
<div class="alert-body">
|
|
249
|
+
<p>A solid title bar for an action response.</p>
|
|
250
|
+
</div>
|
|
251
|
+
</div>
|
|
242
252
|
</div>
|
|
243
253
|
```
|
|
244
254
|
|
|
@@ -153,8 +153,9 @@ Keep one variant family inside a group. Because each button keeps its own
|
|
|
153
153
|
classes, nothing stops `.btn`, `.btn outline` and `.btn soft` from sitting side
|
|
154
154
|
by side — but three fills and three border treatments in one shape read as
|
|
155
155
|
unrelated controls that happen to touch, not as one unit. Change the variant
|
|
156
|
-
only to carry meaning: [Toggle](#toggle) marks
|
|
157
|
-
|
|
156
|
+
only to carry meaning: [Toggle](#toggle) marks a pressed button with a solid
|
|
157
|
+
fill among outlines. For one choice among a few on a shared track, use a
|
|
158
|
+
[segmented control](segmented.md) instead.
|
|
158
159
|
|
|
159
160
|
## Sizes
|
|
160
161
|
|
|
@@ -29,9 +29,12 @@ list markers when order or bullets carry meaning.
|
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
Leading and trailing content are unconstrained: avatars, native choices,
|
|
32
|
-
badges, text, switches, and buttons retain their own component sizing.
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
badges, text, switches, and buttons retain their own component sizing. In a
|
|
33
|
+
narrow row, the trailing region moves under the content rather than breaking a
|
|
34
|
+
word of the title; supporting text still wraps beside it, and a token longer
|
|
35
|
+
than the row breaks instead of widening the page. A `.truncate` line inside
|
|
36
|
+
`.list-item-content` gives up its width, so it ellipsizes next to the trailing
|
|
37
|
+
region (wrap, responsive row, overflow).
|
|
35
38
|
|
|
36
39
|
Both outer regions are optional, and an absent one costs neither space nor a
|
|
37
40
|
gap: `.list-item-content` always takes the row's free space and
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Segmented control
|
|
2
|
+
|
|
3
|
+
> One compact choice among a few options, on a shared track with the selected segment raised.
|
|
4
|
+
|
|
5
|
+
**Related terms:** segmented control, toggle group, pill tabs, view switcher, button group.
|
|
6
|
+
|
|
7
|
+
`.segmented` is the track and each `.segment` a direct child. The look is
|
|
8
|
+
shared; the semantics come from the markup, so pick the anatomy by what the
|
|
9
|
+
choice does:
|
|
10
|
+
|
|
11
|
+
| Use | Markup | Selected | Keyboard |
|
|
12
|
+
| ------------- | ---------------------- | ---------------------- | ------------- |
|
|
13
|
+
| Pick a value | `<fieldset>` of radios | `:checked` | Native arrows |
|
|
14
|
+
| Switch panels | `role="tablist"` | `aria-selected="true"` | Tabs runtime |
|
|
15
|
+
| Navigate | `<nav>` of links | `aria-current="page"` | Tab, Enter |
|
|
16
|
+
|
|
17
|
+
Segments share the width equally and the track is at least `--control-size`
|
|
18
|
+
tall, so it lines up with `.btn` and `.input`; `.sm` and `.lg` size it like
|
|
19
|
+
any control. A long label wraps instead of truncating, and the row grows with
|
|
20
|
+
it. A parent that stretches its children (`.stack`) makes it full width; add
|
|
21
|
+
`.align-self-start` to keep it at its content width.
|
|
22
|
+
|
|
23
|
+
## Pick a value
|
|
24
|
+
|
|
25
|
+
Wrap each radio in its label. The radio is visually hidden but stays focusable
|
|
26
|
+
and submitted; in a browser without `:has()` it stays visible beside the
|
|
27
|
+
label.
|
|
28
|
+
|
|
29
|
+
```html demo
|
|
30
|
+
<fieldset class="segmented">
|
|
31
|
+
<legend class="sr-only">Range</legend>
|
|
32
|
+
<label class="segment"><input type="radio" name="range" value="day">Day</label>
|
|
33
|
+
<label class="segment"><input type="radio" name="range" value="week" checked>Week</label>
|
|
34
|
+
<label class="segment"><input type="radio" name="range" value="month">Month</label>
|
|
35
|
+
</fieldset>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Switch panels
|
|
39
|
+
|
|
40
|
+
A tablist with `data-enhance="tabs"` takes the [tabs](../enhancements/tabs.md)
|
|
41
|
+
runtime unchanged: it reads the roles, not the classes.
|
|
42
|
+
|
|
43
|
+
```html demo
|
|
44
|
+
<div class="segmented" role="tablist" aria-label="View" data-enhance="tabs">
|
|
45
|
+
<button class="segment" type="button" role="tab" id="view-list-tab" aria-selected="true" aria-controls="view-list">List</button>
|
|
46
|
+
<button class="segment" type="button" role="tab" id="view-grid-tab" aria-selected="false" aria-controls="view-grid" tabindex="-1">Grid</button>
|
|
47
|
+
</div>
|
|
48
|
+
<section role="tabpanel" id="view-list" aria-labelledby="view-list-tab">List view</section>
|
|
49
|
+
<section role="tabpanel" id="view-grid" aria-labelledby="view-grid-tab" hidden>Grid view</section>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Navigate
|
|
53
|
+
|
|
54
|
+
```html demo
|
|
55
|
+
<nav class="segmented" aria-label="Period">
|
|
56
|
+
<a class="segment" href="#day" aria-current="page">Day</a>
|
|
57
|
+
<a class="segment" href="#week">Week</a>
|
|
58
|
+
<a class="segment" href="#month">Month</a>
|
|
59
|
+
</nav>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## When to use something else
|
|
63
|
+
|
|
64
|
+
- Several options on at once (bold, italic): `.join` of `.btn` with
|
|
65
|
+
`aria-pressed`, see [joined controls](../forms/joined-controls.md).
|
|
66
|
+
- More options than fit on one row: [tabs](../enhancements/tabs.md), whose
|
|
67
|
+
strip scrolls.
|
|
68
|
+
- Long or descriptive options: [choice cards](../forms/choice-cards.md) or
|
|
69
|
+
plain radios.
|
|
70
|
+
|
|
71
|
+
## Hooks
|
|
72
|
+
|
|
73
|
+
- `--segmented-bg` — track fill.
|
|
74
|
+
- `--segmented-pad` — inset between the track and its segments, also the gap
|
|
75
|
+
between segments; the segment radius is the track radius minus it.
|
|
76
|
+
- `--segmented-radius` — track corner radius.
|
|
77
|
+
- `--segmented-fg` — label ink of the unselected segments; the selected one
|
|
78
|
+
takes `--text`.
|
|
79
|
+
- `--segmented-selected-bg` — fill of the selected segment. Its shadow follows
|
|
80
|
+
`--shadow`, so a flat theme removes it at the theme level.
|
|
81
|
+
- `--segmented-selected-border` — hairline around the selected segment. It is
|
|
82
|
+
what sets the segment apart where its fill is darker than the track; a theme
|
|
83
|
+
whose fill is lighter can fade it.
|
|
@@ -80,9 +80,11 @@ accent, override the tokens on the component:
|
|
|
80
80
|
}
|
|
81
81
|
```
|
|
82
82
|
|
|
83
|
-
`--state-selected` drives the completed fill
|
|
83
|
+
`--state-selected` drives the completed fill and connector;
|
|
84
84
|
`--state-selected-fg` corrects the number inside a completed marker when the
|
|
85
|
-
accent needs a lighter ink.
|
|
85
|
+
accent needs a lighter ink. The current marker sits on the surface, so its
|
|
86
|
+
number and ring read `--state-selected-text` first
|
|
87
|
+
([tokens](../foundations/tokens.md)).
|
|
86
88
|
|
|
87
89
|
## Horizontal steps
|
|
88
90
|
|
|
@@ -67,9 +67,10 @@ For a modal bottom sheet or action sheet, use `dialog.drawer`; use
|
|
|
67
67
|
`dialog.modal` for a centered modal. Those components own modal focus,
|
|
68
68
|
dismissal, scroll locking, and backdrop behavior explicitly.
|
|
69
69
|
|
|
70
|
-
Use `data-flyout-placement` for the preferred anchored placement
|
|
71
|
-
|
|
72
|
-
`bottom-
|
|
70
|
+
Use `data-flyout-placement` for the preferred anchored placement: a side
|
|
71
|
+
(`top`, `bottom`, `left`, `right`), optionally followed by `-start` or `-end`,
|
|
72
|
+
such as `bottom-start` or `right`. An unknown value logs a console warning and
|
|
73
|
+
falls back to `bottom-start`.
|
|
73
74
|
|
|
74
75
|
Use `data-flyout-distance` for the trigger gap in pixels. The default is `4`.
|
|
75
76
|
|
|
@@ -180,6 +181,11 @@ flyout when that specific control must close it regardless of the automatic
|
|
|
180
181
|
policy. This is useful for an Apply or Done action in an `outside` or `false`
|
|
181
182
|
panel. The trigger and Escape continue to close the flyout in every mode.
|
|
182
183
|
|
|
184
|
+
Arrow keys and Space in a radio group never close the flyout: they move
|
|
185
|
+
through the options, and a pointer pick closes it. Opening from the keyboard
|
|
186
|
+
focuses a group at its checked radio. The [palette picker](../forms/color-swatches.md#palette-in-a-flyout)
|
|
187
|
+
relies on both.
|
|
188
|
+
|
|
183
189
|
```html
|
|
184
190
|
<div class="flyout"
|
|
185
191
|
id="filters"
|
|
@@ -56,7 +56,8 @@ is a no-op until the module is loaded again with a DOM.
|
|
|
56
56
|
Load the full bundle **or** the source modules, never both: each evaluation
|
|
57
57
|
owns its registry and document handlers, so a dist bundle mixed with
|
|
58
58
|
`actual-css/js/*` source subpaths (or two dist bundles) registers every
|
|
59
|
-
behavior twice and a flyout opens then immediately closes.
|
|
59
|
+
behavior twice and a flyout opens then immediately closes. The second copy
|
|
60
|
+
logs a console warning when it loads.
|
|
60
61
|
|
|
61
62
|
## Component pages
|
|
62
63
|
|
|
@@ -91,10 +91,15 @@ JavaScript involved:
|
|
|
91
91
|
|
|
92
92
|
## Equal-width tabs
|
|
93
93
|
|
|
94
|
-
To make a few tabs share the strip's width (
|
|
94
|
+
To make a few tabs share the strip's width (full-width, fill), set
|
|
95
95
|
`--tab-flex: 1 1 0` on the strip. `.switcher` does not apply here: a tab strip
|
|
96
96
|
never wraps, so it could never stack.
|
|
97
97
|
|
|
98
|
+
For a few tabs on a track with a raised selected tab (segmented control, pill
|
|
99
|
+
tabs), put the same tablist on [`.segmented`](../components/segmented.md):
|
|
100
|
+
the runtime is unchanged. Its labels wrap instead of scrolling, so keep it to
|
|
101
|
+
what fits on one row.
|
|
102
|
+
|
|
98
103
|
```html demo
|
|
99
104
|
<nav aria-label="Pricing sections">
|
|
100
105
|
<ul class="tabs" style="--tab-flex: 1 1 0">
|
|
@@ -158,5 +163,5 @@ Do not put a flyout trigger in a `role="tablist"`: a tablist holds only
|
|
|
158
163
|
## CSS hooks
|
|
159
164
|
|
|
160
165
|
- `--tab-flex` — flex of each item; set `1 1 0` on the strip for equal-width tabs
|
|
161
|
-
(
|
|
166
|
+
(fill the width). A strip that cannot fit its labels still scrolls.
|
|
162
167
|
- `--tab-gap` — space between an icon and the label text (default `0.375em`).
|
|
@@ -115,7 +115,9 @@ viewport-aware maximum width.
|
|
|
115
115
|
## Positioning
|
|
116
116
|
|
|
117
117
|
Set `data-tooltip-placement` to control where the tooltip appears relative to
|
|
118
|
-
its trigger
|
|
118
|
+
its trigger: a side (`top`, `bottom`, `left`, `right`), optionally followed by
|
|
119
|
+
`-start` or `-end`. An unknown value logs a console warning and falls back to
|
|
120
|
+
`top`. The arrow follows the placement automatically.
|
|
119
121
|
|
|
120
122
|
The runtime also picks the coordinate space, and writes `position` to match. A
|
|
121
123
|
tooltip whose trigger scrolls with the page is placed in document coordinates
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
The examples live in the repository under `demo/` and load `actual.full.css`
|
|
6
6
|
and `actual.full.js` from `dist/`, plus the theme palettes bundle from
|
|
7
|
-
`demo/assets/`.
|
|
8
|
-
`bun run build:
|
|
7
|
+
`demo/assets/`. Both are build output: in a clone, run `bun run build:dist`,
|
|
8
|
+
`bun run build:js` and `bun run build:themes` before opening a page.
|
|
9
9
|
|
|
10
10
|
## Templates
|
|
11
11
|
|
|
@@ -23,13 +23,15 @@ rest show it composed, isolated, or under stress.
|
|
|
23
23
|
Whole pages, composed the way a real product would.
|
|
24
24
|
|
|
25
25
|
- [Dashboard](../../demo/templates/dashboard.html) - data-heavy overview page
|
|
26
|
+
- [Order management](../../demo/templates/order-management.html) - one state at three levels (a badge in a selectable list, a message in context, a notification with its own action) composed on the `admin-neutral` business-interface theme
|
|
26
27
|
- [App](../../demo/templates/app.html) - application shell with sidebar
|
|
27
28
|
- [Workspaces](../../demo/templates/workspaces.html) - sectioned sidebar, master/detail list with native current state, and workspace cards
|
|
28
29
|
- [Marketing](../../demo/templates/marketing.html) - landing page with typography and fluid type
|
|
29
30
|
- [Blog](../../demo/templates/blog.html) - article page with prose
|
|
30
31
|
- [Settings modal](../../demo/templates/settings-modal.html) - two-pane preferences dialog, with the local CSS it needs audited rule by rule
|
|
31
32
|
- [Modal patterns](../../demo/templates/modal-patterns.html) - eight application modals, each the modal surface plus the smallest application CSS it needs
|
|
32
|
-
- [Workspace settings](../../demo/templates/settings-pricing.html) - plans with visible native choices, preferences and
|
|
33
|
+
- [Workspace settings](../../demo/templates/settings-pricing.html) - plans with visible native choices, preferences and segmented tabs
|
|
34
|
+
- [iOS-style settings](../../demo/templates/settings-ios.html) - iOS-like controls and grouped settings from unchanged framework markup, a local theme, and its findings listed rule by rule
|
|
33
35
|
- [Card compositions](../../demo/templates/card-compositions.html) - editorial, team, sign-in and horizontal cards composed from existing primitives
|
|
34
36
|
- [Register form](../../demo/templates/register-form.html) - registration page with choice cards, masks, the password toggle, `tel-prefix` validation, an OTP verification dialog, and status feedback
|
|
35
37
|
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Color swatches
|
|
2
|
+
|
|
3
|
+
> Pick a color from a palette the application defines, inline or from a flyout.
|
|
4
|
+
|
|
5
|
+
**Related terms:** color picker, palette, swatch, color chip, accent color, label color.
|
|
6
|
+
|
|
7
|
+
`.color-swatch` is a `<label>` wrapping a native radio, with the color in
|
|
8
|
+
`--color-swatch-value`. The radio stays the control: it submits, takes the
|
|
9
|
+
arrow keys and carries the name in `aria-label`. The checked swatch shows a
|
|
10
|
+
double ring that reads on any color. Use checkboxes for several colors at once.
|
|
11
|
+
|
|
12
|
+
For a free color, use the native [`.color`](controls.md) picker; a custom
|
|
13
|
+
spectrum or RGB sliders are outside Actual.
|
|
14
|
+
|
|
15
|
+
## Palette
|
|
16
|
+
|
|
17
|
+
Lay the swatches out with `.cluster` or `.grid`, and space them with `--gap`
|
|
18
|
+
(`.tight`, `.loose` or an inline value), not `gap`: the hit area reaches
|
|
19
|
+
half of `--gap` past the swatch, up to `--control-size`, so neighbours split
|
|
20
|
+
the gap between them. A tighter palette trades target size for density. Set
|
|
21
|
+
the column count with `--grid-columns: repeat(6, max-content)` on `.grid`.
|
|
22
|
+
|
|
23
|
+
```html demo
|
|
24
|
+
<fieldset class="field-group cluster">
|
|
25
|
+
<legend>Category color</legend>
|
|
26
|
+
<label class="color-swatch" style="--color-swatch-value: #2563eb"><input type="radio" name="category" value="#2563eb" aria-label="Blue" checked></label>
|
|
27
|
+
<label class="color-swatch" style="--color-swatch-value: #10b981"><input type="radio" name="category" value="#10b981" aria-label="Green"></label>
|
|
28
|
+
<label class="color-swatch" style="--color-swatch-value: #f59e0b"><input type="radio" name="category" value="#f59e0b" aria-label="Amber"></label>
|
|
29
|
+
<label class="color-swatch" style="--color-swatch-value: #e11d48"><input type="radio" name="category" value="#e11d48" aria-label="Rose"></label>
|
|
30
|
+
<label class="color-swatch" style="--color-swatch-value: #ffffff"><input type="radio" name="category" value="#ffffff" aria-label="White"></label>
|
|
31
|
+
</fieldset>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Palette in a flyout
|
|
35
|
+
|
|
36
|
+
A `<button class="color-swatch">` shows the current color and opens the
|
|
37
|
+
palette as a [flyout](../enhancements/flyout.md). A pointer pick closes it;
|
|
38
|
+
the arrow keys move through the colors with the panel open, and Escape returns
|
|
39
|
+
to the button. Give the panel `--flyout-pad` so the focus ring fits inside it.
|
|
40
|
+
Application code shows the pick on the button.
|
|
41
|
+
|
|
42
|
+
```html demo
|
|
43
|
+
<span class="field-label" id="accent-label">Accent color</span>
|
|
44
|
+
<div class="flyout-trigger">
|
|
45
|
+
<button class="color-swatch" type="button" data-enhance="flyout"
|
|
46
|
+
aria-controls="accent-palette" aria-expanded="false"
|
|
47
|
+
aria-labelledby="accent-label accent-name"
|
|
48
|
+
style="--color-swatch-value: #2563eb">
|
|
49
|
+
<span class="sr-only" id="accent-name">Blue</span>
|
|
50
|
+
</button>
|
|
51
|
+
<div class="flyout" id="accent-palette" style="--flyout-pad: var(--space-30)" hidden>
|
|
52
|
+
<div class="cluster" role="radiogroup" aria-labelledby="accent-label">
|
|
53
|
+
<label class="color-swatch" style="--color-swatch-value: #2563eb"><input type="radio" name="accent" value="#2563eb" aria-label="Blue" checked></label>
|
|
54
|
+
<label class="color-swatch" style="--color-swatch-value: #10b981"><input type="radio" name="accent" value="#10b981" aria-label="Green"></label>
|
|
55
|
+
<label class="color-swatch" style="--color-swatch-value: #f59e0b"><input type="radio" name="accent" value="#f59e0b" aria-label="Amber"></label>
|
|
56
|
+
<label class="color-swatch" style="--color-swatch-value: #e11d48"><input type="radio" name="accent" value="#e11d48" aria-label="Rose"></label>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
<script>
|
|
61
|
+
(() => {
|
|
62
|
+
const preview = document.currentScript.closest(".docs-preview");
|
|
63
|
+
const trigger = preview.querySelector("button.color-swatch");
|
|
64
|
+
preview.querySelector(".flyout").addEventListener("change", (event) => {
|
|
65
|
+
trigger.style.setProperty("--color-swatch-value", event.target.value);
|
|
66
|
+
trigger.querySelector(".sr-only").textContent = event.target.getAttribute("aria-label");
|
|
67
|
+
});
|
|
68
|
+
})();
|
|
69
|
+
</script>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Palette and custom color
|
|
73
|
+
|
|
74
|
+
Add the native [`.color`](controls.md) picker to the panel for a color
|
|
75
|
+
outside the palette. Two changes to the flyout above:
|
|
76
|
+
|
|
77
|
+
- `data-flyout-auto-close="outside"` on the panel, so opening the color dialog
|
|
78
|
+
does not close it, and `data-flyout-close` on each swatch, so a pointer pick
|
|
79
|
+
still does. The arrow keys still move through the palette with the panel
|
|
80
|
+
open.
|
|
81
|
+
- The custom input sits in a `<label class="cluster">`, which centers it on
|
|
82
|
+
its text; `.choice` aligns checkboxes, radios and switches only.
|
|
83
|
+
- The custom input takes its own name. Application code unchecks the palette
|
|
84
|
+
when a custom color is chosen, so the form sends `brand`, or `brand-custom`
|
|
85
|
+
when no palette color is checked.
|
|
86
|
+
|
|
87
|
+
```html demo
|
|
88
|
+
<span class="field-label" id="brand-label">Brand color</span>
|
|
89
|
+
<div class="flyout-trigger">
|
|
90
|
+
<button class="color-swatch" type="button" data-enhance="flyout"
|
|
91
|
+
aria-controls="brand-palette" aria-expanded="false"
|
|
92
|
+
aria-labelledby="brand-label brand-name"
|
|
93
|
+
style="--color-swatch-value: #2563eb">
|
|
94
|
+
<span class="sr-only" id="brand-name">Blue</span>
|
|
95
|
+
</button>
|
|
96
|
+
<div class="flyout stack" id="brand-palette" data-flyout-auto-close="outside"
|
|
97
|
+
style="--flyout-pad: var(--space-30)" hidden>
|
|
98
|
+
<div class="cluster" role="radiogroup" aria-labelledby="brand-label">
|
|
99
|
+
<label class="color-swatch" data-flyout-close style="--color-swatch-value: #2563eb"><input type="radio" name="brand" value="#2563eb" aria-label="Blue" checked></label>
|
|
100
|
+
<label class="color-swatch" data-flyout-close style="--color-swatch-value: #10b981"><input type="radio" name="brand" value="#10b981" aria-label="Green"></label>
|
|
101
|
+
<label class="color-swatch" data-flyout-close style="--color-swatch-value: #f59e0b"><input type="radio" name="brand" value="#f59e0b" aria-label="Amber"></label>
|
|
102
|
+
<label class="color-swatch" data-flyout-close style="--color-swatch-value: #e11d48"><input type="radio" name="brand" value="#e11d48" aria-label="Rose"></label>
|
|
103
|
+
</div>
|
|
104
|
+
<label class="cluster"><input class="color" type="color" name="brand-custom" value="#7048e8"> Custom…</label>
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
<script>
|
|
108
|
+
(() => {
|
|
109
|
+
const preview = document.currentScript.closest(".docs-preview");
|
|
110
|
+
const trigger = preview.querySelector("button.color-swatch");
|
|
111
|
+
const palette = preview.querySelector(".flyout");
|
|
112
|
+
palette.addEventListener("change", (event) => {
|
|
113
|
+
const custom = event.target.type === "color";
|
|
114
|
+
if (custom) for (const radio of palette.querySelectorAll('[type="radio"]')) radio.checked = false;
|
|
115
|
+
trigger.style.setProperty("--color-swatch-value", event.target.value);
|
|
116
|
+
trigger.querySelector(".sr-only").textContent = custom
|
|
117
|
+
? `Custom ${event.target.value}`
|
|
118
|
+
: event.target.getAttribute("aria-label");
|
|
119
|
+
});
|
|
120
|
+
})();
|
|
121
|
+
</script>
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The color dialog is the browser's own and looks different on each platform.
|
|
125
|
+
|
|
126
|
+
## Hooks
|
|
127
|
+
|
|
128
|
+
- `--color-swatch-value` — the color, set on each swatch.
|
|
129
|
+
- `--color-swatch-size` — visible swatch size, the height of a `.switch` track
|
|
130
|
+
by default. `.sm` and `.lg` scale it and the hit area.
|
|
131
|
+
- `--color-swatch-radius` — corner radius; round by default.
|
|
@@ -93,9 +93,9 @@ contrast contracts apply to the combobox for free:
|
|
|
93
93
|
|
|
94
94
|
.actual-combobox .cb-chip {
|
|
95
95
|
border: var(--border-width) solid
|
|
96
|
-
color-mix(in oklab, var(--
|
|
96
|
+
color-mix(in oklab, var(--primary) calc(100% - var(--soft-border-mix, 100%)), transparent);
|
|
97
97
|
border-radius: var(--radius-full);
|
|
98
|
-
background: color-mix(in oklab, var(--
|
|
98
|
+
background: color-mix(in oklab, var(--primary) calc(100% - var(--soft-bg-mix)), transparent);
|
|
99
99
|
color: color-mix(in oklab, var(--primary) var(--soft-fg-mix), var(--text));
|
|
100
100
|
font-size: var(--font-size-xs);
|
|
101
101
|
font-weight: var(--font-weight-semibold);
|
|
@@ -6,9 +6,12 @@ Native-only control chrome: the file input and color picker mostly defeat custom
|
|
|
6
6
|
|
|
7
7
|
> Small, theme-aware chrome for the native color picker.
|
|
8
8
|
|
|
9
|
-
Use `.color` on an `input[type="color"]` to
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
Use `.color` on an `input[type="color"]` to show the native picker as a round
|
|
10
|
+
swatch the height of a [switch](switch.md), on a control-sized hit area, with
|
|
11
|
+
the framework's edge, disabled, and focus styles. `--color-size` sets the
|
|
12
|
+
swatch. The color dialog remains browser-native. To choose from a fixed
|
|
13
|
+
palette instead, use [color swatches](color-swatches.md), which share this
|
|
14
|
+
geometry.
|
|
12
15
|
|
|
13
16
|
```html demo
|
|
14
17
|
<label class="field">
|
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
> Use `.join` when controls need to be visually joined into a single unit.
|
|
4
4
|
|
|
5
|
-
**Related terms:**
|
|
5
|
+
**Related terms:** button group, input group, toolbar.
|
|
6
|
+
|
|
7
|
+
`.join` groups controls that keep their own identity and function. For one
|
|
8
|
+
choice among a few on a shared track, use a
|
|
9
|
+
[segmented control](../components/segmented.md).
|
|
6
10
|
|
|
7
11
|
## Class reference
|
|
8
12
|
|
|
@@ -13,7 +17,7 @@
|
|
|
13
17
|
|
|
14
18
|
Add `.join` to the wrapper that groups the controls. Use `.join-addon` for static prefix/suffix content such as currency symbols, units, or protocol text. Action buttons inside the group should use `.btn`. The wrapper should still carry `role="group"` with a label for accessibility.
|
|
15
19
|
|
|
16
|
-
`.join` reshapes corners and shared edges; it does not unify the segments' treatments, and the children keep whatever classes they carry. Give them one variant family so the group reads as a single unit, and change a segment's variant only to mark state — a solid button among outlines for
|
|
20
|
+
`.join` reshapes corners and shared edges; it does not unify the segments' treatments, and the children keep whatever classes they carry. Give them one variant family so the group reads as a single unit, and change a segment's variant only to mark state — a solid button among outlines for a pressed toggle. A group mixing `.btn`, `.btn outline` and `.btn soft` is valid markup that renders as three unrelated controls stuck together.
|
|
17
21
|
|
|
18
22
|
When composing source files manually, import `components/join.css` after the controls it groups. `.join` writes child border-radius longhands directly so joined corners win at equal specificity.
|
|
19
23
|
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
| `.range` | Component | Native range slider, theme-aware accent. |
|
|
29
29
|
| `.file` | Component | Native file input, themed picker button. |
|
|
30
30
|
| `.color` | Component | Native color picker in a control-sized box. |
|
|
31
|
+
| `.color-swatch` | Component | Palette color on a radio, or its trigger. |
|
|
31
32
|
| `.field` | Composition | Field wrapper, on `<label>` or `<div>`. |
|
|
32
33
|
| `.field-label` | Composition | Label text, element-agnostic. |
|
|
33
34
|
| `.field-help` | Composition | Supporting helper text under a control. |
|
|
@@ -132,8 +132,10 @@ same optical line. Change the type or the control size and they stay level:
|
|
|
132
132
|
- `--switch-width` — track width.
|
|
133
133
|
- `--switch-block-size` — track height.
|
|
134
134
|
- `--switch-knob-margin` — inset between knob and track.
|
|
135
|
+
- `--switch-knob-inline-size` — knob width; wider than its height makes a
|
|
136
|
+
capsule knob. Defaults to the knob height.
|
|
135
137
|
|
|
136
|
-
Knob size and travel distance are derived from
|
|
137
|
-
|
|
138
|
+
Knob size and travel distance are derived from these hooks; set them rather
|
|
139
|
+
than the derived values. The knob is concentric in its track: the
|
|
138
140
|
inset is measured inside the border on both axes, so it clears the rails by the
|
|
139
141
|
same distance it clears the ends.
|
|
@@ -56,7 +56,7 @@ Set `--form-actions-justify` (and `--form-actions-align`).
|
|
|
56
56
|
|
|
57
57
|
### Customize a switch's size
|
|
58
58
|
|
|
59
|
-
Change `--switch-width`, `--switch-block-size`, and `--switch-knob-margin`; knob size and travel are derived from them. To rescale the whole row of inline choices at once, use `.sm` / `.lg` on `.choice`, or set `--choice-control-size` directly — the checkbox, the radio, and the switch track all follow it. Density contexts leave inline choices alone.
|
|
59
|
+
Change `--switch-width`, `--switch-block-size`, and `--switch-knob-margin`; knob size and travel are derived from them. `--switch-knob-inline-size` widens the knob into a capsule. To rescale the whole row of inline choices at once, use `.sm` / `.lg` on `.choice`, or set `--choice-control-size` directly — the checkbox, the radio, and the switch track all follow it. Density contexts leave inline choices alone.
|
|
60
60
|
|
|
61
61
|
→ Forms · Switch
|
|
62
62
|
|