actual-css 0.5.0 → 0.7.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/CHANGELOG.md +63 -0
- package/dist/actual.css +1 -0
- package/dist/actual.full.css +589 -131
- package/dist/actual.full.js +1 -1
- package/dist/actual.full.min.css +1 -1
- package/dist/actual.min.css +1 -1
- package/docs/design-notes/browser-support.md +39 -14
- package/docs/design-notes/css-anchor.md +1 -1
- package/docs/design-notes/enhancement-contract.md +30 -13
- package/docs/design-notes/forced-colors.md +11 -7
- package/docs/design-notes/grid.md +4 -4
- package/docs/design-notes/naming.md +15 -9
- package/docs/design-notes/platform-alignment.md +60 -0
- package/docs/design-notes/popover-manual-poc.md +248 -0
- package/docs/design-notes/references.md +4 -0
- package/docs/design-notes/steps.md +748 -0
- package/docs/design-notes/surface-reparenting.md +122 -0
- package/docs/design-notes/widget-primitives.md +32 -15
- package/docs/navigation.json +1 -0
- package/docs/pages/components/alert.md +13 -8
- package/docs/pages/components/aura.md +102 -6
- package/docs/pages/components/avatar.md +9 -6
- package/docs/pages/components/badge.md +11 -7
- package/docs/pages/components/button.md +17 -17
- package/docs/pages/components/card.md +15 -8
- package/docs/pages/components/chat.md +1 -1
- package/docs/pages/components/dialog.md +10 -7
- package/docs/pages/components/drawer.md +1 -1
- package/docs/pages/components/fab.md +12 -10
- package/docs/pages/components/indicator.md +6 -6
- package/docs/pages/components/list.md +11 -2
- package/docs/pages/components/navbar.md +1 -1
- package/docs/pages/components/pagination.md +1 -1
- package/docs/pages/components/rating.md +4 -4
- package/docs/pages/components/skeleton.md +1 -1
- package/docs/pages/components/spinner.md +1 -1
- package/docs/pages/components/steps.md +376 -52
- package/docs/pages/components/table.md +5 -5
- package/docs/pages/enhancements/flyout.md +104 -12
- package/docs/pages/enhancements/overview.md +2 -2
- package/docs/pages/enhancements/scrollspy.md +1 -1
- package/docs/pages/enhancements/status-bar.md +20 -0
- package/docs/pages/enhancements/tabs.md +1 -1
- package/docs/pages/enhancements/tooltip.md +12 -0
- package/docs/pages/examples/overview.md +2 -0
- package/docs/pages/forms/choice-cards.md +4 -4
- package/docs/pages/forms/combobox.md +87 -0
- package/docs/pages/forms/floating-field.md +5 -3
- package/docs/pages/forms/joined-controls.md +4 -4
- package/docs/pages/forms/labels.md +8 -5
- package/docs/pages/forms/overview.md +25 -18
- package/docs/pages/forms/password.md +3 -2
- package/docs/pages/forms/range.md +13 -2
- package/docs/pages/forms/states-and-sizes.md +6 -4
- package/docs/pages/forms/validation.md +13 -9
- package/docs/pages/foundations/philosophy.md +15 -1
- package/docs/pages/foundations/theming.md +8 -0
- package/docs/pages/foundations/tokens.md +9 -6
- package/docs/pages/foundations/typography.md +1 -1
- package/docs/pages/guides/bootstrap.md +3 -3
- package/docs/pages/guides/introduction.md +1 -1
- package/docs/pages/guides/modular-import.md +21 -10
- package/docs/pages/guides/progressive-enhancement.md +96 -73
- package/docs/pages/guides/tailwind.md +2 -2
- package/docs/pages/layout/app-shell.md +4 -4
- package/docs/pages/layout/choosing.md +10 -6
- package/docs/pages/layout/grid.md +11 -10
- package/docs/pages/layout/stack.md +10 -6
- package/docs/pages/patterns/structured-lists.md +7 -7
- package/docs/pages/utilities/accessibility.md +1 -1
- package/docs/pages/utilities/flex.md +20 -13
- package/docs/pages/utilities/links.md +1 -1
- package/docs/pages/utilities/list.md +1 -1
- package/docs/pages/utilities/overflow.md +14 -7
- package/docs/pages/utilities/overview.md +22 -0
- package/docs/pages/utilities/shape.md +1 -1
- package/docs/pages/utilities/sizing-wrapping.md +10 -8
- package/docs/pages/utilities/spacing.md +26 -19
- package/docs/pages/utilities/text.md +1 -1
- package/llms.txt +27 -4
- package/package.json +7 -4
- package/scripts/reserved-classes.json +4 -1
- package/src/css/components/fab.css +44 -8
- package/src/css/components/flyout.css +49 -3
- package/src/css/components/join.css +7 -0
- package/src/css/components/list.css +3 -1
- package/src/css/components/menu.css +16 -10
- package/src/css/components/steps.css +277 -69
- package/src/css/components/tooltip.css +37 -1
- package/src/css/core/tokens.css +1 -0
- package/src/css/effects/aura.css +101 -11
- package/src/css/forms/custom-select.css +1 -1
- package/src/css/forms/floating-field.css +8 -6
- package/src/css/layout/container-query.css +37 -13
- package/src/css/layout/grid.css +7 -7
- package/src/css/layout/index.css +1 -1
- package/src/js/password.js +1 -1
- package/src/js/status.js +38 -2
- package/src/js/surface.js +28 -12
- package/src/js/tooltip.js +2 -2
- package/src/js/floating.js +0 -432
|
@@ -6,16 +6,18 @@
|
|
|
6
6
|
|
|
7
7
|
## Class reference
|
|
8
8
|
|
|
9
|
-
| Class | Kind | Description
|
|
10
|
-
|
|
11
|
-
| `.flyout-trigger` | Composition | Positioning wrapper for
|
|
12
|
-
| `.stretch` | Modifier |
|
|
13
|
-
| `.flyout` | Component | Floating
|
|
14
|
-
| `.menu` | Component | Action-list primitive
|
|
15
|
-
| `.menu-item` | Component | One action row;
|
|
16
|
-
| `.menu-item-icon` | Slot | Fixed leading column for
|
|
17
|
-
| `.menu-item-text` | Slot | Flexible label column; truncates
|
|
18
|
-
| `.menu-item-end` | Slot | Trailing
|
|
9
|
+
| Class | Kind | Description |
|
|
10
|
+
| ----------------- | ----------- | ------------------------------------------- |
|
|
11
|
+
| `.flyout-trigger` | Composition | Positioning wrapper for trigger and panel. |
|
|
12
|
+
| `.stretch` | Modifier | Spans a `.flyout-trigger` to its container. |
|
|
13
|
+
| `.flyout` | Component | Floating surface, positioned by JavaScript. |
|
|
14
|
+
| `.menu` | Component | Action-list primitive. |
|
|
15
|
+
| `.menu-item` | Component | One action row; joins roving focus. |
|
|
16
|
+
| `.menu-item-icon` | Slot | Fixed leading column for an icon. |
|
|
17
|
+
| `.menu-item-text` | Slot | Flexible label column; truncates. |
|
|
18
|
+
| `.menu-item-end` | Slot | Trailing shortcut, badge or status. |
|
|
19
|
+
|
|
20
|
+
`.menu` has a strict `.menu > li > .menu-item` anatomy.
|
|
19
21
|
| `.menu-label` | Variant | Muted section heading inside a menu; not interactive. |
|
|
20
22
|
| `.menu-separator` | Variant | Divider between menu groups (`<hr role="separator">`). |
|
|
21
23
|
| `.sm` / `.lg` | Variant | Compact or large density. |
|
|
@@ -72,8 +74,98 @@ placement strings supported by the floating runtime, such as `bottom-start`,
|
|
|
72
74
|
|
|
73
75
|
Use `data-flyout-distance` for the trigger gap in pixels. The default is `4`.
|
|
74
76
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
### Native popover lifecycle
|
|
78
|
+
|
|
79
|
+
The `.flyout` presentation also composes with an element carrying `popover`.
|
|
80
|
+
Actual neutralizes the native popover geometry that conflicts with anchored
|
|
81
|
+
positioning and recognizes `:popover-open` as the visible state. The browser or
|
|
82
|
+
another library may therefore own opening, dismissal, and focus without
|
|
83
|
+
requiring `.is-open` or `[hidden]`.
|
|
84
|
+
|
|
85
|
+
Actual CSS does not position that independently managed popover. Its positioner
|
|
86
|
+
must write fixed viewport coordinates (and may write `--available-height` and
|
|
87
|
+
`--surface-anchor-width`); the built-in `surface.js` runtime remains the full
|
|
88
|
+
fallback when Actual owns the lifecycle too. A bare `[popover]` without
|
|
89
|
+
`.flyout` or `.tooltip` keeps its platform appearance.
|
|
90
|
+
|
|
91
|
+
Native Popover is optional and is not part of Actual's Minimal contract:
|
|
92
|
+
browsers within the Minimal range may not support it. Actual gates its own
|
|
93
|
+
geometry reset behind `@supports selector(:popover-open)`, so an engine without
|
|
94
|
+
Popover no longer gets a mispositioned panel — but that engine also never hides
|
|
95
|
+
or promotes a `popover` element, so nothing dismisses the panel either.
|
|
96
|
+
|
|
97
|
+
When the lifecycle must work across the full Minimal range, use `surface.js`.
|
|
98
|
+
Otherwise using the native lifecycle is an application support decision. The
|
|
99
|
+
two are alternatives, not layers.
|
|
100
|
+
|
|
101
|
+
#### Choose one lifecycle owner
|
|
102
|
+
|
|
103
|
+
The Actual runtime path, where `surface.js` owns opening, dismissal, focus and
|
|
104
|
+
placement:
|
|
105
|
+
|
|
106
|
+
```html
|
|
107
|
+
<div class="flyout-trigger">
|
|
108
|
+
<button data-enhance="flyout" aria-controls="actions" aria-expanded="false">
|
|
109
|
+
Actions
|
|
110
|
+
</button>
|
|
111
|
+
|
|
112
|
+
<ul id="actions" class="flyout menu" hidden>
|
|
113
|
+
<li><button class="menu-item" type="button">Rename</button></li>
|
|
114
|
+
</ul>
|
|
115
|
+
</div>
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
The native path, where the browser owns the lifecycle and the top layer:
|
|
119
|
+
|
|
120
|
+
```html
|
|
121
|
+
<button popovertarget="actions">Actions</button>
|
|
122
|
+
|
|
123
|
+
<ul id="actions" class="flyout menu" popover>
|
|
124
|
+
<li><button class="menu-item" type="button">Rename</button></li>
|
|
125
|
+
</ul>
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Do not combine them. `surface.js` opens a panel by clearing `[hidden]` and
|
|
129
|
+
adding `.is-open`; it never calls `showPopover()`, so a `popover` element handed
|
|
130
|
+
to the runtime has two owners and stays closed. The runtime logs a warning if it
|
|
131
|
+
is asked to retain one.
|
|
132
|
+
|
|
133
|
+
**The native path still needs a positioner.** `popovertarget` gives the panel an
|
|
134
|
+
implicit anchor reference to its invoker, but it does not place it: Actual's
|
|
135
|
+
geometry reset clears the UA's centering, so an unpositioned native flyout is
|
|
136
|
+
laid out at its static position rather than under its trigger. Supply
|
|
137
|
+
coordinates the same way `surface.js` does:
|
|
138
|
+
|
|
139
|
+
```js
|
|
140
|
+
import { autoUpdate, reposition } from "@lekoala/floating";
|
|
141
|
+
|
|
142
|
+
const trigger = document.querySelector("[popovertarget='actions']");
|
|
143
|
+
const panel = document.getElementById("actions");
|
|
144
|
+
|
|
145
|
+
// One tracker at a time. autoUpdate returns its own cleanup; releasing it
|
|
146
|
+
// before every state change keeps repeated opens from stacking trackers, and
|
|
147
|
+
// stops the scroll/resize work as soon as the panel closes.
|
|
148
|
+
let stop;
|
|
149
|
+
|
|
150
|
+
panel.addEventListener("toggle", (event) => {
|
|
151
|
+
stop?.();
|
|
152
|
+
stop = undefined;
|
|
153
|
+
if (event.newState !== "open") return;
|
|
154
|
+
|
|
155
|
+
stop = autoUpdate(trigger, panel, () => {
|
|
156
|
+
reposition(trigger, panel, { placement: "bottom-start", distance: 4 });
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
CSS Anchor Positioning will eventually cover the simple anchored case from the
|
|
162
|
+
stylesheet alone, using that implicit anchor reference. It is still only
|
|
163
|
+
partially supported and is not the documented recipe yet.
|
|
164
|
+
|
|
165
|
+
**When `surface.js` owns the lifecycle**, use `data-flyout-auto-close` if the
|
|
166
|
+
default click dismissal behavior is not right. Escape still follows the shared
|
|
167
|
+
surface lifecycle. These options do not reach a natively managed
|
|
168
|
+
`popover="auto"`, whose dismissal belongs to the browser.
|
|
77
169
|
|
|
78
170
|
- `true` is the default. Clicks inside or outside close the flyout.
|
|
79
171
|
- `inside` closes on inside clicks only.
|
|
@@ -15,7 +15,7 @@ class API, shared tokens, and progressive enhancement.
|
|
|
15
15
|
|
|
16
16
|
## Modules
|
|
17
17
|
|
|
18
|
-
The full runtime is `actual-css/js`. Each enhancer is also importable on its own
|
|
18
|
+
The full runtime is `actual-css/js/full`. Each enhancer is also importable on its own
|
|
19
19
|
for projects that use custom components or want a smaller behavior surface:
|
|
20
20
|
|
|
21
21
|
```js
|
|
@@ -32,5 +32,5 @@ is a no-op until the module is loaded again with a DOM.
|
|
|
32
32
|
|
|
33
33
|
Each interactive component has its own page documenting the exact markup its
|
|
34
34
|
enhancement expects: Dialog, Drawer, Flyout, Tooltip, Tabs, Scrollspy, and
|
|
35
|
-
Status Bar. The
|
|
35
|
+
Status Bar. The full runtime is loaded on the docs pages, so the examples
|
|
36
36
|
work with the documented markup alone.
|
|
@@ -9,7 +9,7 @@ or style `[aria-current]` yourself.
|
|
|
9
9
|
## Class reference
|
|
10
10
|
|
|
11
11
|
| Class | Kind | Description |
|
|
12
|
-
|
|
12
|
+
| ------------ | ----------- | --------------------------------------------------------------- |
|
|
13
13
|
| `.scrollspy` | Component | Marks the nav region for the enhancer; adds no visual styles. |
|
|
14
14
|
| `.nav-list` | Composition | Vertical list of navigation links. |
|
|
15
15
|
| `.nav-link` | Component | Navigation link whose active state comes from `[aria-current]`. |
|
|
@@ -15,6 +15,7 @@ runtime targets, empty by default.
|
|
|
15
15
|
- Use it for transient status (`Saved.`, `Reconnected.`, `Copied.`). Critical, persistent, or actionable information belongs in `.alert`, inline messages, or dialogs.
|
|
16
16
|
- Intents: `danger`, `success`, `warning`, `neutral`. The default (no intent) is a neutral dark pill.
|
|
17
17
|
- On mobile, the runtime keeps the bar above the software keyboard by tracking `visualViewport` while a message is showing.
|
|
18
|
+
- A message originating inside an open modal dialog temporarily moves the singleton bar into that dialog. This keeps it in the active top-layer and accessibility subtree; the bar returns to its original DOM position after its exit.
|
|
18
19
|
|
|
19
20
|
Clearing is deferred, not immediate: the bar closes first and only empties its
|
|
20
21
|
text and intent once the exit transition has finished, so it leaves at the size
|
|
@@ -77,6 +78,25 @@ document.dispatchEvent(new CustomEvent("actual:status", {
|
|
|
77
78
|
}));
|
|
78
79
|
```
|
|
79
80
|
|
|
81
|
+
Dispatch from the control or region that produced the feedback when it lives
|
|
82
|
+
inside a dialog; bubbling lets the runtime infer the active surface:
|
|
83
|
+
|
|
84
|
+
```js
|
|
85
|
+
saveButton.dispatchEvent(new CustomEvent("actual:status", {
|
|
86
|
+
bubbles: true,
|
|
87
|
+
detail: { message: "Saved.", intent: "success" },
|
|
88
|
+
}));
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Code importing `status()` directly passes the same origin as `source`:
|
|
92
|
+
|
|
93
|
+
```js
|
|
94
|
+
status("Saved.", { intent: "success", source: saveButton });
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Validation and declarative status commands propagate their source
|
|
98
|
+
automatically.
|
|
99
|
+
|
|
80
100
|
## CSS hooks
|
|
81
101
|
|
|
82
102
|
- `--status-bg` — bar background.
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
## Class reference
|
|
6
6
|
|
|
7
7
|
| Class | Kind | Description |
|
|
8
|
-
|
|
8
|
+
| ---------- | --------- | -------------------------------------------- |
|
|
9
9
|
| `.tabs` | Component | Tab strip; pairs with `role="tablist"`. |
|
|
10
10
|
| `.tab` | Component | One tab trigger; pairs with `role="tab"`. |
|
|
11
11
|
| `.primary` | Intent | Tints the selected tab's indicator and text. |
|
|
@@ -17,6 +17,18 @@ with the `hidden` attribute.
|
|
|
17
17
|
- The arrow inherits the tooltip background — custom gradients carry through automatically.
|
|
18
18
|
- Avoid relying on the native `title` attribute as the primary implementation.
|
|
19
19
|
|
|
20
|
+
A `.tooltip[popover]` may use a native or third-party-owned popover lifecycle.
|
|
21
|
+
Actual removes the native inset, margin, and overflow that conflict with
|
|
22
|
+
positioning and with the projecting arrow, while leaving bare `[popover]`
|
|
23
|
+
elements untouched. The lifecycle owner must still write the fixed viewport
|
|
24
|
+
coordinates and arrow position; Actual only supplies the presentation.
|
|
25
|
+
|
|
26
|
+
That reset is gated on `@supports selector(:popover-open)`. Native Popover is
|
|
27
|
+
optional and is not part of Actual's Minimal contract: browsers within the
|
|
28
|
+
Minimal range may not support it, and there the attribute carries no behavior,
|
|
29
|
+
so nothing shows or hides the tip. Use `data-tooltip` and the built-in runtime
|
|
30
|
+
when the lifecycle must work across the full Minimal range.
|
|
31
|
+
|
|
20
32
|
```html demo
|
|
21
33
|
<button class="btn ghost"
|
|
22
34
|
type="button"
|
|
@@ -22,6 +22,8 @@ and `actual.full.js` from `dist/`, plus the theme palettes bundle from
|
|
|
22
22
|
- [Layout reference](../../demo/templates/layouts.html) - canonical compositions built only with the layout primitives
|
|
23
23
|
- [Grid density](../../demo/templates/grid.html) - the grid contracts on resizable stages, with the pitfalls called out
|
|
24
24
|
- [Density](../../demo/templates/density.html) - compact control density
|
|
25
|
+
- [Data grid](../../demo/templates/data-grid.html) - an external data grid component themed with Actual tokens (sort, filter, search, selection)
|
|
26
|
+
- [Combobox](../../demo/templates/combobox.html) - an external combobox themed with Actual tokens (search, tags, autocomplete)
|
|
25
27
|
|
|
26
28
|
## Sites
|
|
27
29
|
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
## Class reference
|
|
6
6
|
|
|
7
|
-
| Class | Kind | Description
|
|
8
|
-
|
|
9
|
-
| `.choice-card` | Component | Card-style `<label>`
|
|
10
|
-
| `.primary` / `.secondary` | Intent |
|
|
7
|
+
| Class | Kind | Description |
|
|
8
|
+
| ------------------------- | --------- | --------------------------------------------- |
|
|
9
|
+
| `.choice-card` | Component | Card-style `<label>` around a native control. |
|
|
10
|
+
| `.primary` / `.secondary` | Intent | Accent for the selected state. |
|
|
11
11
|
|
|
12
12
|
- Use `.choice-card` on a `<label>` wrapping a native `<input type="radio">` or `<input type="checkbox">`. The input is visually hidden; in browsers without `:has()` it stays visible so selection state never disappears.
|
|
13
13
|
- Selected items show a primary border, subtle background tint, and a checkmark badge at the top-right corner — round for radio, rounded square for checkbox.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Combobox
|
|
2
|
+
|
|
3
|
+
> A searchable or multi-value combobox is not shipped by the framework — the native `<select>` and `<datalist>` stay the baseline. Theme an external combobox with Actual tokens instead.
|
|
4
|
+
|
|
5
|
+
The `.select` class keeps the native baseline with a CSS chevron, and the optional
|
|
6
|
+
`custom-select` module adds the `appearance: base-select` native picker where the
|
|
7
|
+
browser supports it. Beyond those, apply the framework's judgment from the
|
|
8
|
+
[data grid template](../../demo/templates/data-grid.html) to the problem: when a
|
|
9
|
+
real product needs a JavaScript combobox (searchable select, removable tags,
|
|
10
|
+
autocomplete suggestions), load a dedicated component and bridge its custom
|
|
11
|
+
properties onto Actual's tokens.
|
|
12
|
+
|
|
13
|
+
**Related terms:** combo box, combobox, autocomplete, datalist, searchable select, enhanced select, multiple select, tags, chips, tag input, pill input.
|
|
14
|
+
|
|
15
|
+
## Theme bridge
|
|
16
|
+
|
|
17
|
+
The [combobox template](../../demo/templates/combobox.html) themes
|
|
18
|
+
[`@lekoala/combobox`](https://github.com/lekoala/combobox) entirely with Actual
|
|
19
|
+
tokens: the control mirrors `.input`, chips re-derive the `.badge` soft recipe,
|
|
20
|
+
and the picker popover follows `--surface-raised` and `--shadow-popout`. No
|
|
21
|
+
adapter, no compatibility layer — a handful of `--cb-*` assignments and shared
|
|
22
|
+
mix tokens.
|
|
23
|
+
|
|
24
|
+
```html
|
|
25
|
+
<label class="field actual-combobox">
|
|
26
|
+
<span class="field-label">Skills</span>
|
|
27
|
+
<combo-box placeholder="Search or add a skill…">
|
|
28
|
+
<select class="select" name="skills[]" multiple>
|
|
29
|
+
<option value="design" selected>Design</option>
|
|
30
|
+
<option value="css" selected>CSS</option>
|
|
31
|
+
<option value="javascript" selected>JavaScript</option>
|
|
32
|
+
</select>
|
|
33
|
+
</combo-box>
|
|
34
|
+
</label>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The card in the template documents the full token map of this recipe.
|
|
38
|
+
|
|
39
|
+
## Lightweight pass-through
|
|
40
|
+
|
|
41
|
+
Most of the skin is three one-line token bridges. The visible vocabulary —
|
|
42
|
+
surface, border, radius, focus ring, danger, hover overlay and the `--soft-*`
|
|
43
|
+
mix — stays the Actual one, so light/dark mode, the preset themes and their
|
|
44
|
+
contrast contracts apply to the combobox for free:
|
|
45
|
+
|
|
46
|
+
```css
|
|
47
|
+
.actual-combobox {
|
|
48
|
+
--cb-bg: var(--surface);
|
|
49
|
+
--cb-color: var(--text);
|
|
50
|
+
--cb-border-color: var(--border);
|
|
51
|
+
--cb-border-radius: var(--radius);
|
|
52
|
+
--cb-focus-color: var(--focus);
|
|
53
|
+
--cb-muted-color: var(--text-muted);
|
|
54
|
+
--cb-error-color: var(--danger);
|
|
55
|
+
--cb-chip-bg: transparent;
|
|
56
|
+
--cb-control-height: var(--control-size);
|
|
57
|
+
--cb-option-min-height: var(--control-size);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.actual-combobox .cb-control:focus-within,
|
|
61
|
+
.actual-combobox .cb-text-control:focus {
|
|
62
|
+
outline: 2px solid transparent;
|
|
63
|
+
box-shadow: var(--focus-ring-shadow);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.actual-combobox .cb-chip-remove:focus-visible {
|
|
67
|
+
outline: 2px solid transparent;
|
|
68
|
+
box-shadow: 0 0 0 2px var(--focus-ring);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.actual-combobox .cb-chip {
|
|
72
|
+
border: var(--border-width) solid
|
|
73
|
+
color-mix(in oklab, var(--surface) var(--soft-border-mix), var(--primary));
|
|
74
|
+
border-radius: var(--radius-full);
|
|
75
|
+
background: color-mix(in oklab, var(--surface) var(--soft-bg-mix), var(--primary));
|
|
76
|
+
color: color-mix(in oklab, var(--primary) var(--soft-fg-mix), var(--text));
|
|
77
|
+
font-size: var(--font-size-xs);
|
|
78
|
+
font-weight: var(--font-weight-strong);
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The composite focus ring follows any internal focus, not just the search
|
|
83
|
+
input: focus a chip or its remove × and the control shows the same field ring,
|
|
84
|
+
with the local `:focus-visible` indicator on the chip or its × on top.
|
|
85
|
+
|
|
86
|
+
The same approach works for any widget that exposes a custom-property skin —
|
|
87
|
+
keep the widget's behavior, restyle its tokens through the shared vocabulary.
|
|
@@ -7,9 +7,11 @@ the label rests inside the control and floats to the top when the control is
|
|
|
7
7
|
focused or filled. It composes the existing `.field` layout and the text
|
|
8
8
|
controls (`.input`, `.textarea`, `.select`) with zero JavaScript.
|
|
9
9
|
|
|
10
|
-
The cell holds
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
The cell holds exactly one control and its label, with the control before the
|
|
11
|
+
label. Label placement is linked through the general sibling combinator, so an
|
|
12
|
+
injected node between the two (a password manager, an extension wrapper) is
|
|
13
|
+
tolerated. Help and error messages stay in the surrounding `.field`, otherwise
|
|
14
|
+
the resting label centers on the whole field instead of the control.
|
|
13
15
|
|
|
14
16
|
```html demo
|
|
15
17
|
<div class="field">
|
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
|
|
7
7
|
## Class reference
|
|
8
8
|
|
|
9
|
-
| Class | Kind | Description
|
|
10
|
-
|
|
11
|
-
| `.join` | Composition |
|
|
12
|
-
| `.join-addon` | Composition | Static prefix
|
|
9
|
+
| Class | Kind | Description |
|
|
10
|
+
| ------------- | ----------- | ------------------------------------------- |
|
|
11
|
+
| `.join` | Composition | Joins adjacent controls into a single unit. |
|
|
12
|
+
| `.join-addon` | Composition | Static prefix or suffix content. |
|
|
13
13
|
|
|
14
14
|
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
15
|
|
|
@@ -4,11 +4,14 @@
|
|
|
4
4
|
|
|
5
5
|
## Class reference
|
|
6
6
|
|
|
7
|
-
| Class | Kind | Description
|
|
8
|
-
|
|
9
|
-
| `.field` | Composition | Field wrapper; canonical on `<label>` or `<div>`.
|
|
10
|
-
| `.field-label` | Composition | Label text, element-agnostic
|
|
11
|
-
| `.required-mark` | Composition | Visual required marker (`aria-hidden`)
|
|
7
|
+
| Class | Kind | Description |
|
|
8
|
+
| ---------------- | ----------- | ------------------------------------------------- |
|
|
9
|
+
| `.field` | Composition | Field wrapper; canonical on `<label>` or `<div>`. |
|
|
10
|
+
| `.field-label` | Composition | Label text, element-agnostic. |
|
|
11
|
+
| `.required-mark` | Composition | Visual required marker (`aria-hidden`). |
|
|
12
|
+
|
|
13
|
+
`.field-label` works on a `<span>`, on a detached `<label for>`, or on a
|
|
14
|
+
`<legend>`. `.required-mark` goes inside a label.
|
|
12
15
|
|
|
13
16
|
Use a **wrapped label** for simple hand-authored forms. The whole label area becomes the click target, there is no `id` noise, and the markup is harder to break.
|
|
14
17
|
|
|
@@ -9,27 +9,34 @@
|
|
|
9
9
|
- Proper focus style that preserves keyboard navigation.
|
|
10
10
|
- `.field-group` and `.choice` provide layout without depending on parent scope.
|
|
11
11
|
- Customizable select is progressive enhancement only — the native select remains the baseline.
|
|
12
|
+
- Searchable selects, tags and autocomplete are a JavaScript widget concern; theme an external combobox with Actual tokens — see the [combobox template](../../demo/templates/combobox.html).
|
|
12
13
|
|
|
13
14
|
## Class reference
|
|
14
15
|
|
|
15
|
-
| Class | Kind | Description
|
|
16
|
-
|
|
17
|
-
| `.input` | Component | Text input
|
|
18
|
-
| `.textarea` | Component | Multi-line text control.
|
|
19
|
-
| `.select` | Component | Dropdown
|
|
20
|
-
| `.check` | Component | Styled checkbox.
|
|
21
|
-
| `.radio` | Component | Styled radio button.
|
|
22
|
-
| `.switch` | Component | Toggle switch on a
|
|
23
|
-
| `.range` | Component | Native range slider
|
|
24
|
-
| `.file` | Component | Native file input
|
|
25
|
-
| `.color` | Component | Native color picker in a control-sized box.
|
|
26
|
-
| `.field` | Composition | Field wrapper
|
|
27
|
-
| `.field-label` | Composition | Label text
|
|
28
|
-
| `.field-help` | Composition | Supporting helper text under a control.
|
|
29
|
-
| `.field-error` | Composition | Inline error message shown while
|
|
30
|
-
| `.field-group` | Composition |
|
|
31
|
-
| `.choice` | Composition | Choice-label layout
|
|
32
|
-
| `.form-actions` | Composition | Class-only flex row that closes a form
|
|
16
|
+
| Class | Kind | Description |
|
|
17
|
+
| --------------- | ----------- | --------------------------------------------- |
|
|
18
|
+
| `.input` | Component | Text input. |
|
|
19
|
+
| `.textarea` | Component | Multi-line text control. |
|
|
20
|
+
| `.select` | Component | Dropdown, native baseline with a CSS chevron. |
|
|
21
|
+
| `.check` | Component | Styled checkbox. |
|
|
22
|
+
| `.radio` | Component | Styled radio button. |
|
|
23
|
+
| `.switch` | Component | Toggle switch on a `role="switch"` checkbox. |
|
|
24
|
+
| `.range` | Component | Native range slider, theme-aware accent. |
|
|
25
|
+
| `.file` | Component | Native file input, themed picker button. |
|
|
26
|
+
| `.color` | Component | Native color picker in a control-sized box. |
|
|
27
|
+
| `.field` | Composition | Field wrapper, on `<label>` or `<div>`. |
|
|
28
|
+
| `.field-label` | Composition | Label text, element-agnostic. |
|
|
29
|
+
| `.field-help` | Composition | Supporting helper text under a control. |
|
|
30
|
+
| `.field-error` | Composition | Inline error message, shown while invalid. |
|
|
31
|
+
| `.field-group` | Composition | `<fieldset>` with a tunable legend gutter. |
|
|
32
|
+
| `.choice` | Composition | Choice-label layout around an inline control. |
|
|
33
|
+
| `.form-actions` | Composition | Class-only flex row that closes a form. |
|
|
34
|
+
|
|
35
|
+
`.input` shares the text-control recipe with `.textarea` and `.select`, and
|
|
36
|
+
`.select` also has an opt-in enhanced picker. `.field-label` works on a
|
|
37
|
+
`<span>`, a detached `<label>` or a `<legend>`. `.choice` wraps a `.check`,
|
|
38
|
+
`.radio` or `.switch`, and `.form-actions` works inside or outside the
|
|
39
|
+
`<form>`.
|
|
33
40
|
|
|
34
41
|
## Example form
|
|
35
42
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
# Password Toggle
|
|
2
2
|
|
|
3
3
|
> A password field reveals its value through a linked button. The markup is a
|
|
4
|
-
> plain command invoker; the behavior ships with the JS runtime
|
|
5
|
-
> (`actual-css/js`
|
|
4
|
+
> plain command invoker; the behavior ships with the full JS runtime
|
|
5
|
+
> (`actual-css/js/full`) and can also be imported independently
|
|
6
|
+
> (`actual-css/js/password`).
|
|
6
7
|
|
|
7
8
|
Point a `button` at the input with `commandfor` and
|
|
8
9
|
`command="--password-toggle"`. Use `.join` when the button should sit attached
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
# Range
|
|
2
2
|
|
|
3
|
-
> Native range
|
|
3
|
+
> Native range input with a lightweight theme-aware custom skin.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
`.range` keeps the native range control and its interaction semantics, while
|
|
6
|
+
customizing the track, thumb, focus state, intents, and disabled state. The
|
|
7
|
+
focus ring targets the thumb — the surface the user actually manipulates —
|
|
8
|
+
rather than the CSS box.
|
|
6
9
|
|
|
7
10
|
**Related terms:** slider, range input, scrubber.
|
|
8
11
|
|
|
@@ -13,7 +16,15 @@ Core: native range, enhanced by `accent-color`. Optional richer skin may come la
|
|
|
13
16
|
</label>
|
|
14
17
|
```
|
|
15
18
|
|
|
19
|
+
Actual deliberately does not emulate filled tracks, tick marks, value labels,
|
|
20
|
+
or multi-thumb ranges. Those still require engine-specific pseudo-elements or a
|
|
21
|
+
value duplicated out of the HTML into CSS. Prefer the platform as richer range
|
|
22
|
+
styling becomes interoperable — see
|
|
23
|
+
[Enhanced range controls](https://github.com/lekoala/actual-css/blob/master/docs/design-notes/platform-alignment.md).
|
|
24
|
+
|
|
16
25
|
## CSS hooks
|
|
17
26
|
|
|
18
27
|
- `--range-thumb-size` — thumb diameter.
|
|
19
28
|
- `--range-track-height` — track thickness.
|
|
29
|
+
- `--range-thumb-bg` — thumb color. Defaults to the local intent, then `--primary`.
|
|
30
|
+
- `--range-track-bg` — track color.
|
|
@@ -4,10 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
## Class reference
|
|
6
6
|
|
|
7
|
-
| Class | Kind | Description
|
|
8
|
-
|
|
9
|
-
| `.sm` | Modifier | Compact control height and spacing rhythm
|
|
10
|
-
| `.lg` | Modifier | Large control height and spacing rhythm
|
|
7
|
+
| Class | Kind | Description |
|
|
8
|
+
| ----- | -------- | ------------------------------------------ |
|
|
9
|
+
| `.sm` | Modifier | Compact control height and spacing rhythm. |
|
|
10
|
+
| `.lg` | Modifier | Large control height and spacing rhythm. |
|
|
11
|
+
|
|
12
|
+
Each sets `--control-size` to `--control-size-sm` or `--control-size-lg`.
|
|
11
13
|
|
|
12
14
|
Use `readonly` for text-like values that can still be focused, selected, and submitted. Use `disabled` for unavailable controls that should not receive focus or submit a value.
|
|
13
15
|
|
|
@@ -6,14 +6,18 @@
|
|
|
6
6
|
|
|
7
7
|
## Class reference
|
|
8
8
|
|
|
9
|
-
| Class | Kind | Description
|
|
10
|
-
|
|
11
|
-
| `.field-error` | Composition | Canonical inline error message
|
|
12
|
-
| `.field-help` | Composition | Canonical helper text
|
|
13
|
-
| `.field.danger` | Modifier | Manual invalid marking on the
|
|
14
|
-
| `.needs-validation` | Modifier | Opt-in
|
|
15
|
-
| `.was-validated` | Modifier |
|
|
16
|
-
| `.status-bar` | Component | Optional status element
|
|
9
|
+
| Class | Kind | Description |
|
|
10
|
+
| ------------------- | ----------- | -------------------------------------------- |
|
|
11
|
+
| `.field-error` | Composition | Canonical inline error message. |
|
|
12
|
+
| `.field-help` | Composition | Canonical helper text. |
|
|
13
|
+
| `.field.danger` | Modifier | Manual invalid marking on the wrapper. |
|
|
14
|
+
| `.needs-validation` | Modifier | Opt-in for the enhancer and `:user-invalid`. |
|
|
15
|
+
| `.was-validated` | Modifier | Set by the enhancer after a submit attempt. |
|
|
16
|
+
| `.status-bar` | Component | Optional form-level status element. |
|
|
17
|
+
|
|
18
|
+
`.field-error` shows while the field is invalid; `.field-help` carries
|
|
19
|
+
supporting copy before and after validation. `.status-bar` shows
|
|
20
|
+
`data-validation-message` on an invalid submit.
|
|
17
21
|
|
|
18
22
|
- `.field-error` is the canonical error message. It is wired to `aria-invalid="true"` via the input, so the visual border and the assistive-tech announcement move together.
|
|
19
23
|
- `.field-help` is the canonical helper text. It carries supporting copy before and after validation.
|
|
@@ -49,7 +53,7 @@
|
|
|
49
53
|
|
|
50
54
|
Native validation first; the enhancer only adds state and focus behavior.
|
|
51
55
|
|
|
52
|
-
Actual CSS ships validation *styles*. Invalid fields are marked with `aria-invalid="true"` (or the manual `.field.danger` wrapper class). The default forms bundle imports `forms/validation.css`; custom builds may omit that file when validation styling is app-owned. A small enhancer (`actual-css/js/validation`), included in the
|
|
56
|
+
Actual CSS ships validation *styles*. Invalid fields are marked with `aria-invalid="true"` (or the manual `.field.danger` wrapper class). The default forms bundle imports `forms/validation.css`; custom builds may omit that file when validation styling is app-owned. A small enhancer (`actual-css/js/validation`), included in the full runtime (`actual-css/js/full`) and also importable on its own, prevents premature error display, marks invalid fields on blur and submit, focuses the first invalid field on submit, and supports a few custom rules. It is not a validation framework — server and AJAX validation stay in app code.
|
|
53
57
|
|
|
54
58
|
Opt in with the `.needs-validation` class. Importing the module registers the behavior; there is no init call.
|
|
55
59
|
|
|
@@ -75,6 +75,19 @@ As inherited contexts, one class tightens or loosens the whole subtree:
|
|
|
75
75
|
</div>
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
+
Application chrome can use the same scope; no separate `.compact` mode is
|
|
79
|
+
needed:
|
|
80
|
+
|
|
81
|
+
```html demo
|
|
82
|
+
<header class="navbar sm">
|
|
83
|
+
<a class="navbar-brand" href="/">Workspace</a>
|
|
84
|
+
<nav class="cluster" aria-label="Workspace actions">
|
|
85
|
+
<button class="btn ghost">Search</button>
|
|
86
|
+
<button class="btn primary">Create</button>
|
|
87
|
+
</nav>
|
|
88
|
+
</header>
|
|
89
|
+
```
|
|
90
|
+
|
|
78
91
|
The same class on a component is local density, not a second meaning:
|
|
79
92
|
|
|
80
93
|
```html demo
|
|
@@ -86,7 +99,8 @@ This is not "`.sm` sometimes means density and sometimes size": `.sm` always
|
|
|
86
99
|
establishes the same density tokens — only the scope changes. The density
|
|
87
100
|
tokens are `--gap`, `--density-space`, `--control-size`, and
|
|
88
101
|
`--density-compact-size`. Components consume the dimensions that make sense
|
|
89
|
-
for them and opt out of the rest.
|
|
102
|
+
for them and opt out of the rest. The absolute `--space-*` scale is not rebound
|
|
103
|
+
by density scopes.
|
|
90
104
|
|
|
91
105
|
Components with bespoke sizing (`.avatar`, `.spinner`) define local `.sm`/`.lg`
|
|
92
106
|
instead of consuming the shared tokens.
|
|
@@ -70,6 +70,14 @@ Native controls that no component class restyles — a bare checkbox, radio, ran
|
|
|
70
70
|
|
|
71
71
|
→ Forms · Overview · Foundations · Tokens (theme contract)
|
|
72
72
|
|
|
73
|
+
### Store a theme name without applying it
|
|
74
|
+
|
|
75
|
+
`data-theme` is an active theme boundary on every element that carries it, not
|
|
76
|
+
a generic storage attribute. Use a different name such as `data-theme-value`,
|
|
77
|
+
or a form control's `value`, when the element should only hold a theme name.
|
|
78
|
+
Apply `data-theme` deliberately when that element and its subtree should paint
|
|
79
|
+
with the selected palette — a theme swatch is a useful example.
|
|
80
|
+
|
|
73
81
|
### Loading / busy overlay on a container
|
|
74
82
|
|
|
75
83
|
Use `aria-busy="true"` with a direct last-child `.spinner`; tint the overlay with `--busy-overlay-bg`.
|
|
@@ -247,6 +247,7 @@ Icons used by CSS-only controls are public tokens because users may need to repl
|
|
|
247
247
|
--icon-chevron: url("data:image/svg+xml,...");
|
|
248
248
|
--icon-check: url("data:image/svg+xml,...");
|
|
249
249
|
--icon-close: url("data:image/svg+xml,...");
|
|
250
|
+
--icon-plus: url("data:image/svg+xml,...");
|
|
250
251
|
}
|
|
251
252
|
```
|
|
252
253
|
|
|
@@ -275,12 +276,14 @@ Under `forced-colors: active`, `--backdrop-fill` maps to `Canvas`.
|
|
|
275
276
|
|
|
276
277
|
A small z-index scale orders non-dialog overlays. Native `<dialog>` elements (modal, drawer) render on the platform top-layer, which has no numeric z-index and always paints above the page — they never compete with this scale.
|
|
277
278
|
|
|
278
|
-
| Token | Value | Used by
|
|
279
|
-
|
|
280
|
-
| `--z-sticky` | 10 |
|
|
281
|
-
| `--z-menu` | 20 | Floating menus (`flyout`)
|
|
282
|
-
| `--z-tooltip` | 50 | Tooltips
|
|
283
|
-
| `--z-status` | 60 | `status-bar
|
|
279
|
+
| Token | Value | Used by |
|
|
280
|
+
| ------------- | ----- | ------------------------------- |
|
|
281
|
+
| `--z-sticky` | 10 | `form-actions.sticky`, `topbar` |
|
|
282
|
+
| `--z-menu` | 20 | Floating menus (`flyout`) |
|
|
283
|
+
| `--z-tooltip` | 50 | Tooltips |
|
|
284
|
+
| `--z-status` | 60 | `status-bar` |
|
|
285
|
+
|
|
286
|
+
`.surface-backdrop` sits just under the menus, at `calc(var(--z-menu) - 1)`.
|
|
284
287
|
|
|
285
288
|
Stacking-context traps: a flyout or tooltip that is a DOM descendant of a dialog, or of a container with `transform`, `filter`, `contain`, `isolation`, or `will-change`, is confined to that ancestor's stacking context. Its z-index token only orders it against siblings within that context. When a dialog's top-layer clips a descendant flyout, move the flyout markup outside the dialog or use a portal/popover to escape the stacking context.
|
|
286
289
|
|
|
@@ -66,7 +66,7 @@ documentation homepages) import it manually:
|
|
|
66
66
|
The module exposes three size tokens and three composed classes. It is deliberately not the foundation: body text, app UI, and the default prose scale stay static.
|
|
67
67
|
|
|
68
68
|
| Token | Class | Purpose |
|
|
69
|
-
|
|
69
|
+
| ----------------- | --------------- | ------------------------------------- |
|
|
70
70
|
| `--fluid-display` | `.text-display` | Hero / display sizes. |
|
|
71
71
|
| `--fluid-title` | `.text-title` | Section titles. |
|
|
72
72
|
| `--fluid-lead` | `.text-lead` | Intro paragraphs on display surfaces. |
|