actual-css 0.2.0 → 0.3.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 +38 -1
- package/README.md +24 -9
- package/dist/actual-themes.min.css +1 -0
- package/dist/actual.css +1244 -915
- package/dist/actual.js +1 -3
- package/dist/actual.min.css +1 -1
- package/dist/optional.css +1048 -0
- package/dist/optional.min.css +1 -0
- package/docs/design-notes/browser-support.md +94 -14
- package/docs/design-notes/cascade-layer.md +1 -1
- package/docs/design-notes/enhancement-contract.md +11 -14
- package/docs/design-notes/forced-colors.md +105 -0
- package/docs/design-notes/naming.md +2 -1
- package/docs/design-notes/platform-alignment.md +492 -0
- package/docs/design-notes/references.md +8 -0
- package/docs/design-notes/widget-primitives.md +37 -1
- package/docs/navigation.json +135 -0
- package/docs/pages/components/accordion.md +80 -0
- package/docs/pages/components/alert.md +203 -0
- package/docs/pages/components/aura.md +35 -0
- package/docs/pages/components/avatar.md +95 -0
- package/docs/pages/components/badge.md +102 -0
- package/docs/pages/components/breadcrumb.md +19 -0
- package/docs/pages/components/button.md +205 -0
- package/docs/pages/components/card.md +183 -0
- package/docs/pages/components/chat.md +50 -0
- package/docs/pages/components/dialog.md +367 -0
- package/docs/pages/components/drawer.md +113 -0
- package/docs/pages/components/fab.md +118 -0
- package/docs/pages/components/key.md +33 -0
- package/docs/pages/components/meter.md +23 -0
- package/docs/pages/components/navbar.md +92 -0
- package/docs/pages/components/pagination.md +55 -0
- package/docs/pages/components/progress.md +29 -0
- package/docs/pages/components/skeleton.md +38 -0
- package/docs/pages/components/spinner.md +93 -0
- package/docs/pages/components/table.md +102 -0
- package/docs/pages/enhancements/flyout.md +391 -0
- package/docs/pages/enhancements/overview.md +36 -0
- package/docs/pages/enhancements/scrollspy.md +71 -0
- package/docs/pages/enhancements/status-bar.md +72 -0
- package/docs/pages/enhancements/tabs.md +80 -0
- package/docs/pages/enhancements/tooltip.md +130 -0
- package/docs/pages/examples/overview.md +41 -0
- package/docs/pages/forms/choice-cards.md +102 -0
- package/docs/pages/forms/controls.md +32 -0
- package/docs/pages/forms/detached-actions.md +59 -0
- package/docs/pages/forms/floating-field.md +88 -0
- package/docs/pages/forms/form-actions.md +56 -0
- package/docs/pages/forms/input-policy.md +91 -0
- package/docs/pages/forms/joined-controls.md +37 -0
- package/docs/pages/forms/labels.md +42 -0
- package/docs/pages/forms/otp.md +50 -0
- package/docs/pages/forms/overview.md +188 -0
- package/docs/pages/forms/password.md +40 -0
- package/docs/pages/forms/range.md +17 -0
- package/docs/pages/forms/states-and-sizes.md +321 -0
- package/docs/pages/forms/sticky-actions.md +187 -0
- package/docs/pages/forms/switch.md +31 -0
- package/docs/pages/forms/validation.md +241 -0
- package/docs/{mental-model.md → pages/foundations/philosophy.md} +33 -18
- package/docs/pages/foundations/theming.md +92 -0
- package/docs/pages/foundations/tokens.md +421 -0
- package/docs/{typography.md → pages/foundations/typography.md} +27 -9
- package/docs/pages/guides/bootstrap.md +438 -0
- package/docs/pages/guides/introduction.md +157 -0
- package/docs/pages/guides/optional-components.md +33 -0
- package/docs/pages/guides/progressive-enhancement.md +686 -0
- package/docs/pages/guides/tailwind.md +455 -0
- package/docs/pages/layout/app-shell.md +25 -0
- package/docs/pages/layout/center.md +29 -0
- package/docs/pages/layout/cluster.md +57 -0
- package/docs/pages/layout/frame.md +30 -0
- package/docs/pages/layout/grid.md +142 -0
- package/docs/pages/layout/list.md +41 -0
- package/docs/pages/layout/media.md +21 -0
- package/docs/pages/layout/overview.md +37 -0
- package/docs/pages/layout/scroll-snap.md +54 -0
- package/docs/pages/layout/sidebar-layout.md +27 -0
- package/docs/pages/layout/stack.md +18 -0
- package/docs/pages/layout/switcher.md +36 -0
- package/docs/pages/layout/topbar.md +23 -0
- package/docs/pages/patterns/actions.md +52 -0
- package/docs/pages/patterns/code-block.md +36 -0
- package/docs/pages/patterns/exclusive-accordion.md +16 -0
- package/docs/pages/patterns/hierarchical-nav.md +26 -0
- package/docs/pages/patterns/icon-input.md +25 -0
- package/docs/pages/patterns/intent-nesting.md +3 -0
- package/docs/pages/patterns/navigation-list.md +235 -0
- package/docs/pages/patterns/overview.md +58 -0
- package/docs/pages/patterns/structured-lists.md +47 -0
- package/docs/pages/utilities/accessibility.md +34 -0
- package/docs/pages/utilities/flex.md +105 -0
- package/docs/pages/utilities/links.md +18 -0
- package/docs/pages/utilities/list.md +31 -0
- package/docs/pages/utilities/overflow.md +43 -0
- package/docs/pages/utilities/overview.md +18 -0
- package/docs/pages/utilities/shape.md +25 -0
- package/docs/pages/utilities/sizing-wrapping.md +115 -0
- package/docs/pages/utilities/spacing.md +79 -0
- package/docs/pages/utilities/text.md +43 -0
- package/llms.txt +4 -4
- package/package.json +20 -12
- package/src/css/actual.css +12 -1
- package/src/css/base.css +3 -5
- package/src/css/components/accordion.css +18 -30
- package/src/css/components/actions.css +4 -1
- package/src/css/components/alert.css +126 -99
- package/src/css/components/avatar.css +16 -10
- package/src/css/components/badge.css +55 -35
- package/src/css/components/breadcrumb.css +7 -15
- package/src/css/components/busy.css +6 -0
- package/src/css/components/button.css +78 -32
- package/src/css/components/card.css +17 -37
- package/src/css/components/drawer.css +30 -13
- package/src/css/components/flyout.css +39 -109
- package/src/css/components/index.css +1 -0
- package/src/css/components/join.css +14 -2
- package/src/css/components/key.css +2 -0
- package/src/css/components/menu.css +125 -0
- package/src/css/components/meter.css +0 -23
- package/src/css/components/modal.css +162 -7
- package/src/css/components/navbar.css +17 -18
- package/src/css/components/overline.css +0 -7
- package/src/css/components/pagination.css +1 -1
- package/src/css/components/progress.css +8 -26
- package/src/css/components/skeleton.css +7 -0
- package/src/css/components/spinner.css +6 -7
- package/src/css/components/status-bar.css +15 -24
- package/src/css/components/surface.css +2 -8
- package/src/css/components/tab.css +19 -48
- package/src/css/components/table.css +7 -5
- package/src/css/components/tooltip.css +14 -7
- package/src/css/focus.css +14 -38
- package/src/css/forms/choice-card.css +13 -14
- package/src/css/forms/choice.css +21 -27
- package/src/css/forms/control.css +16 -17
- package/src/css/forms/custom-select.css +9 -11
- package/src/css/forms/form-actions.css +14 -3
- package/src/css/forms/form.css +7 -4
- package/src/css/forms/index.css +4 -4
- package/src/css/forms/input-icon.css +30 -12
- package/src/css/forms/native.css +50 -11
- package/src/css/forms/range.css +17 -9
- package/src/css/forms/select.css +8 -8
- package/src/css/forms/switch.css +14 -12
- package/src/css/forms/validation.css +32 -5
- package/src/css/grid.css +19 -18
- package/src/css/intents.css +2 -2
- package/src/css/layout.css +29 -1
- package/src/css/optional/aura.css +93 -0
- package/src/css/optional/chat.css +105 -0
- package/src/css/optional/fab.css +104 -0
- package/src/css/optional/floating-field.css +87 -0
- package/src/css/optional/index.css +5 -0
- package/src/css/optional/layout-extra.css +7 -4
- package/src/css/optional/otp.css +115 -0
- package/src/css/optional/scroll-snap.css +6 -0
- package/src/css/optional/scroller.css +13 -7
- package/src/css/optional/typography-fluid.css +5 -0
- package/src/css/optional/utilities-extra.css +17 -2
- package/src/css/prose.css +18 -8
- package/src/css/reset.css +0 -10
- package/src/css/theme.css +21 -5
- package/src/css/themes/cyberpunk.css +1 -1
- package/src/css/themes/dim.css +3 -3
- package/src/css/themes/edge.css +8 -10
- package/src/css/themes/index.css +3 -3
- package/src/css/themes/{dark.css → indigo.css} +5 -4
- package/src/css/themes/neon.css +5 -5
- package/src/css/themes/square.css +0 -3
- package/src/css/tokens.css +74 -20
- package/src/css/utilities.css +8 -10
- package/src/css/variants.css +37 -65
- package/src/js/command.js +1 -3
- package/src/js/context-menu.js +67 -35
- package/src/js/dialog.js +68 -79
- package/src/js/dismiss.js +15 -0
- package/src/js/enhance.js +54 -23
- package/src/js/enhancement-loader.js +301 -0
- package/src/js/events.js +3 -0
- package/src/js/filter.js +3 -3
- package/src/js/floating.js +101 -131
- package/src/js/flyout.js +104 -87
- package/src/js/focus-group.js +116 -0
- package/src/js/focus.js +6 -1
- package/src/js/index.js +4 -2
- package/src/js/input.js +1 -1
- package/src/js/keys.js +27 -0
- package/src/js/mask.js +7 -6
- package/src/js/menu.js +87 -34
- package/src/js/parse-config.js +47 -0
- package/src/js/password.js +9 -1
- package/src/js/scrollspy.js +12 -4
- package/src/js/selectors.js +0 -7
- package/src/js/status.js +3 -1
- package/src/js/surface.js +185 -136
- package/src/js/tab.js +36 -53
- package/src/js/tooltip.js +53 -31
- package/src/js/validation.js +34 -8
- package/dist/actual.js.map +0 -31
- package/docs/README.md +0 -28
- package/docs/components.md +0 -860
- package/docs/design-notes/previous-work.md +0 -5
- package/docs/forms.md +0 -1265
- package/docs/javascript.md +0 -496
- package/docs/layout.md +0 -480
- package/docs/patterns.md +0 -504
- package/docs/reserved.md +0 -7
- package/docs/tokens.md +0 -455
- package/docs/ui.md +0 -929
- package/docs/utilities.md +0 -384
- package/src/css/dialog-fallback.css +0 -56
- package/src/js/dialog-fallback.js +0 -163
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Tooltip
|
|
2
|
+
|
|
3
|
+
> Supplemental label for a trigger, shown on hover and focus, hidden on dismissal.
|
|
4
|
+
|
|
5
|
+
Tooltips are supplemental: `data-tooltip` on the trigger wires a `.tooltip`
|
|
6
|
+
element (`role="tooltip"`) that appears near the trigger. Position, placement,
|
|
7
|
+
and arrow position are written by JavaScript; the element is shown and hidden
|
|
8
|
+
with the `hidden` attribute.
|
|
9
|
+
|
|
10
|
+
- Use `data-tooltip` on the trigger. With text (`data-tooltip="Help"`), the tooltip element is generated. Empty (`data-tooltip`) marks an explicit tooltip connected via `aria-describedby`.
|
|
11
|
+
- Tooltips are supplemental. Do not put required information or interactive controls inside them.
|
|
12
|
+
- Show on hover and focus. Hide on Escape, blur, pointer leave, or scroll when appropriate.
|
|
13
|
+
- JavaScript can generate tooltip elements from `data-tooltip`.
|
|
14
|
+
- Add `data-tooltip-click` to toggle it on click instead of hover/focus.
|
|
15
|
+
- Add `data-tooltip-visible` to show it immediately and keep it visible while its trigger is in view.
|
|
16
|
+
- Use `data-tooltip-placement` to set the preferred placement (default `top`).
|
|
17
|
+
- The arrow inherits the tooltip background — custom gradients carry through automatically.
|
|
18
|
+
- Avoid relying on the native `title` attribute as the primary implementation.
|
|
19
|
+
|
|
20
|
+
```html demo
|
|
21
|
+
<button class="btn ghost"
|
|
22
|
+
type="button"
|
|
23
|
+
data-tooltip
|
|
24
|
+
aria-describedby="tooltip-save"
|
|
25
|
+
aria-label="Save">
|
|
26
|
+
<i class="ti ti-device-floppy" aria-hidden="true"></i>
|
|
27
|
+
</button>
|
|
28
|
+
|
|
29
|
+
<div class="tooltip" role="tooltip" id="tooltip-save" hidden>
|
|
30
|
+
Save changes
|
|
31
|
+
</div>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
```html demo
|
|
35
|
+
<button class="btn" type="button" data-tooltip="Save changes">
|
|
36
|
+
Save
|
|
37
|
+
</button>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Display modes
|
|
41
|
+
|
|
42
|
+
Click tooltips stay open when the pointer leaves and close on a second click or
|
|
43
|
+
Escape. They remain supplemental, non-interactive content; use a flyout when the
|
|
44
|
+
floating content contains controls.
|
|
45
|
+
|
|
46
|
+
```html demo
|
|
47
|
+
<p class="cluster">
|
|
48
|
+
<button class="btn outline" type="button"
|
|
49
|
+
data-tooltip="Click again or press Escape to close"
|
|
50
|
+
data-tooltip-click>
|
|
51
|
+
Toggle on click
|
|
52
|
+
</button>
|
|
53
|
+
|
|
54
|
+
<button class="btn outline" type="button"
|
|
55
|
+
data-tooltip="Always visible while this trigger is in view"
|
|
56
|
+
data-tooltip-visible
|
|
57
|
+
data-tooltip-placement="bottom">
|
|
58
|
+
Always visible
|
|
59
|
+
</button>
|
|
60
|
+
</p>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## HTML and long content
|
|
64
|
+
|
|
65
|
+
The `data-tooltip="…"` shorthand is intentionally plain text. For trusted HTML,
|
|
66
|
+
use an explicit tooltip referenced by `aria-describedby`. Keep its content
|
|
67
|
+
non-interactive and concise; long content wraps up to the tooltip's
|
|
68
|
+
viewport-aware maximum width.
|
|
69
|
+
|
|
70
|
+
```html demo
|
|
71
|
+
<button class="btn" type="button"
|
|
72
|
+
data-tooltip
|
|
73
|
+
aria-describedby="tip-rich-long"
|
|
74
|
+
data-tooltip-placement="bottom">
|
|
75
|
+
Long HTML tooltip
|
|
76
|
+
</button>
|
|
77
|
+
|
|
78
|
+
<div class="tooltip" role="tooltip" id="tip-rich-long" hidden>
|
|
79
|
+
<strong>Keyboard shortcut:</strong> press <kbd>Ctrl</kbd> + <kbd>K</kbd> to open search.
|
|
80
|
+
This longer explanation demonstrates wrapping when a supplemental label needs a little more context.
|
|
81
|
+
</div>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Positioning
|
|
85
|
+
|
|
86
|
+
Set `data-tooltip-placement` to control where the tooltip appears relative to
|
|
87
|
+
its trigger. The arrow follows the placement automatically.
|
|
88
|
+
|
|
89
|
+
```html demo
|
|
90
|
+
<p>
|
|
91
|
+
<button class="btn outline" type="button" data-tooltip="Above the button" data-tooltip-placement="top">Top</button>
|
|
92
|
+
<button class="btn outline" type="button" data-tooltip="To the right" data-tooltip-placement="right">Right</button>
|
|
93
|
+
<button class="btn outline" type="button" data-tooltip="Below the button" data-tooltip-placement="bottom">Bottom</button>
|
|
94
|
+
<button class="btn outline" type="button" data-tooltip="To the left" data-tooltip-placement="left">Left</button>
|
|
95
|
+
</p>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Custom styling
|
|
99
|
+
|
|
100
|
+
Override `--tooltip-bg` and `--tooltip-fg` on the tooltip element to change the
|
|
101
|
+
background and text color. The arrow picks up `background: inherit` so gradients
|
|
102
|
+
and solid colors both work.
|
|
103
|
+
|
|
104
|
+
```html demo
|
|
105
|
+
<button class="btn primary" type="button"
|
|
106
|
+
data-tooltip
|
|
107
|
+
aria-describedby="tip-grad"
|
|
108
|
+
data-tooltip-placement="right">
|
|
109
|
+
Hover for gradient
|
|
110
|
+
</button>
|
|
111
|
+
|
|
112
|
+
<div class="tooltip" role="tooltip" id="tip-grad" hidden
|
|
113
|
+
style="background-color: #5b2d9e;
|
|
114
|
+
--tooltip-bg: linear-gradient(135deg, oklch(0.45 0.22 280), oklch(0.5 0.2 10));
|
|
115
|
+
--tooltip-fg: white;
|
|
116
|
+
padding: 0.4em 0.8em;
|
|
117
|
+
font-weight: var(--font-weight-medium);">
|
|
118
|
+
<strong>Custom gradient tooltip:</strong> the arrow matches the background, and this longer
|
|
119
|
+
sentence demonstrates how the tooltip wraps and flips when the preferred side lacks space.
|
|
120
|
+
</div>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## CSS hooks
|
|
124
|
+
|
|
125
|
+
- `--tooltip-bg` — bubble background (defaults to `var(--surface-solid)`); the arrow follows it.
|
|
126
|
+
- `--tooltip-fg` — text color.
|
|
127
|
+
- `--tooltip-arrow-size` — arrow size.
|
|
128
|
+
|
|
129
|
+
`--arrow-x` and `--arrow-y` are written by the positioner at runtime, not set by
|
|
130
|
+
the author. See the JavaScript runtime documentation.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Examples
|
|
2
|
+
|
|
3
|
+
> Real pages built with Actual CSS - an admin application and a set of standalone templates - to see the primitives, components, and patterns composed the way they are meant to be used.
|
|
4
|
+
|
|
5
|
+
The examples live in the repository under `demo/` and load the shipped bundles
|
|
6
|
+
from `dist/` (`actual.css`, `optional.css`, `actual-themes.min.css`,
|
|
7
|
+
`actual.js`), referenced with stable URLs.
|
|
8
|
+
|
|
9
|
+
## Admin application
|
|
10
|
+
|
|
11
|
+
`demo/admini/` is a complete admin interface: application shell, navigation,
|
|
12
|
+
tables, forms, dialogs, and feedback states.
|
|
13
|
+
|
|
14
|
+
- [Dashboard](../../demo/admini/index.html) - app shell, navbar, stat cards, charts, recent activity
|
|
15
|
+
- [Login](../../demo/admini/login.html) - centered auth card with social actions
|
|
16
|
+
- [Forms](../../demo/admini/forms.html) - inputs, choice cards, validation, joined controls, sticky actions
|
|
17
|
+
- [Tables](../../demo/admini/tables.html) - data tables, status badges, bulk actions
|
|
18
|
+
- [Kanban](../../demo/admini/kanban.html) - drag-free column layout with cards
|
|
19
|
+
- [Chat](../../demo/admini/chat.html) - conversation list, message thread, composer
|
|
20
|
+
- [Calendar](../../demo/admini/calendar.html) - month grid with event cards
|
|
21
|
+
- [Invoice](../../demo/admini/invoice.html) - structured document layout
|
|
22
|
+
- [Profile](../../demo/admini/profile.html) - avatar, tabs, settings rows
|
|
23
|
+
- [Settings](../../demo/admini/settings.html) - grouped settings with switches
|
|
24
|
+
- [User grid](../../demo/admini/user-grid.html) - avatar grid, filters, pagination
|
|
25
|
+
- [404](../../demo/admini/404.html) - empty state
|
|
26
|
+
|
|
27
|
+
## Templates
|
|
28
|
+
|
|
29
|
+
`demo/templates/` are standalone pages covering common page shapes.
|
|
30
|
+
|
|
31
|
+
- [Kitchen sink](../../demo/templates/kitchen-sink.html) - every component and variant on one page
|
|
32
|
+
- [Keyboard controls](../../demo/templates/keyboard-controls.html) - hands-on keyboard support matrix and focus test bench
|
|
33
|
+
- [Dashboard](../../demo/templates/dashboard.html) - data-heavy overview page
|
|
34
|
+
- [App](../../demo/templates/app.html) - application shell with sidebar
|
|
35
|
+
- [Marketing](../../demo/templates/marketing.html) - landing page with typography and fluid type
|
|
36
|
+
- [Blog](../../demo/templates/blog.html) - article page with prose
|
|
37
|
+
- [Blocks](../../demo/templates/blocks.html) - layout building blocks
|
|
38
|
+
- [Density](../../demo/templates/density.html) - compact control density
|
|
39
|
+
|
|
40
|
+
> Note: the examples reference the repository's source files, so they open from
|
|
41
|
+
> the checkout, not from a standalone copy of `site`.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Choice Cards
|
|
2
|
+
|
|
3
|
+
> Card-style radio and checkbox labels where the whole card acts as a clickable target.
|
|
4
|
+
|
|
5
|
+
## Class reference
|
|
6
|
+
|
|
7
|
+
| Class | Kind | Description |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| `.choice-card` | Component | Card-style `<label>` wrapping a native radio or checkbox; the whole card is the click target. |
|
|
10
|
+
| `.primary` / `.secondary` | Intent | Intent accent for the selected state (supported on the card). |
|
|
11
|
+
|
|
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
|
+
- 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.
|
|
14
|
+
- Pair with grid or flex utilities for group layout. The badge overhangs the top-right corner, so avoid `overflow: hidden` on the direct container.
|
|
15
|
+
- Supports disabled, checked, focus-visible, and invalid states.
|
|
16
|
+
|
|
17
|
+
```html demo
|
|
18
|
+
<div class="grid-3">
|
|
19
|
+
<label class="choice-card">
|
|
20
|
+
<input type="radio" name="cpu" value="1" checked />
|
|
21
|
+
<strong>8-core CPU</strong>
|
|
22
|
+
<span class="muted">32 GB RAM</span>
|
|
23
|
+
</label>
|
|
24
|
+
<label class="choice-card">
|
|
25
|
+
<input type="radio" name="cpu" value="2" />
|
|
26
|
+
<strong>6-core CPU</strong>
|
|
27
|
+
<span class="muted">24 GB RAM</span>
|
|
28
|
+
</label>
|
|
29
|
+
<label class="choice-card">
|
|
30
|
+
<input type="radio" name="cpu" value="3" />
|
|
31
|
+
<strong>4-core CPU</strong>
|
|
32
|
+
<span class="muted">16 GB RAM</span>
|
|
33
|
+
</label>
|
|
34
|
+
</div>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```html demo
|
|
38
|
+
<fieldset class="field-group">
|
|
39
|
+
<legend class="field-label">Features</legend>
|
|
40
|
+
<div class="grid-3">
|
|
41
|
+
<label class="choice-card">
|
|
42
|
+
<input type="checkbox" name="features" value="wifi" checked />
|
|
43
|
+
<strong>WiFi</strong>
|
|
44
|
+
<span class="muted">Dual-band 2.4/5 GHz</span>
|
|
45
|
+
</label>
|
|
46
|
+
<label class="choice-card">
|
|
47
|
+
<input type="checkbox" name="features" value="bluetooth" />
|
|
48
|
+
<strong>Bluetooth</strong>
|
|
49
|
+
<span class="muted">5.3, low energy</span>
|
|
50
|
+
</label>
|
|
51
|
+
<label class="choice-card">
|
|
52
|
+
<input type="checkbox" name="features" value="nfc" disabled />
|
|
53
|
+
<strong>NFC</strong>
|
|
54
|
+
<span class="muted">Coming soon</span>
|
|
55
|
+
</label>
|
|
56
|
+
</div>
|
|
57
|
+
</fieldset>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Validation follows the shared pattern: `aria-invalid="true"` on the input (set manually or by the `.needs-validation` enhancer) turns the card border to danger, and a `.field-error` inside a `.field` wrapper is shown.
|
|
61
|
+
|
|
62
|
+
```html demo
|
|
63
|
+
<fieldset class="field field-group">
|
|
64
|
+
<legend class="field-label">Plan</legend>
|
|
65
|
+
<div class="grid-3">
|
|
66
|
+
<label class="choice-card">
|
|
67
|
+
<input type="radio" name="plan" value="starter"
|
|
68
|
+
aria-invalid="true" aria-describedby="plan-error" />
|
|
69
|
+
<strong>Starter</strong>
|
|
70
|
+
<span class="muted">1 project</span>
|
|
71
|
+
</label>
|
|
72
|
+
<label class="choice-card">
|
|
73
|
+
<input type="radio" name="plan" value="pro"
|
|
74
|
+
aria-invalid="true" aria-describedby="plan-error" />
|
|
75
|
+
<strong>Pro</strong>
|
|
76
|
+
<span class="muted">Unlimited projects</span>
|
|
77
|
+
</label>
|
|
78
|
+
<label class="choice-card">
|
|
79
|
+
<input type="radio" name="plan" value="team"
|
|
80
|
+
aria-invalid="true" aria-describedby="plan-error" />
|
|
81
|
+
<strong>Team</strong>
|
|
82
|
+
<span class="muted">Unlimited + SSO</span>
|
|
83
|
+
</label>
|
|
84
|
+
</div>
|
|
85
|
+
<span class="field-error" id="plan-error" role="alert">
|
|
86
|
+
Choose a plan to continue.
|
|
87
|
+
</span>
|
|
88
|
+
</fieldset>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Sizes follow the shared `.sm` and `.lg` modifiers. Intent classes (`.primary`, `.secondary`) are supported on the `.choice-card` element.
|
|
92
|
+
|
|
93
|
+
## CSS hooks
|
|
94
|
+
|
|
95
|
+
- `--choice-card-pad` — inner padding.
|
|
96
|
+
- `--choice-card-radius` — corner radius.
|
|
97
|
+
- `--choice-card-check-size` — size of the check indicator.
|
|
98
|
+
|
|
99
|
+
Plain `.check` / `.radio` controls expose one hook:
|
|
100
|
+
|
|
101
|
+
- `--choice-control-offset` — top offset that aligns the control with the first
|
|
102
|
+
line of a multi-line label.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Controls
|
|
2
|
+
|
|
3
|
+
Native-only control chrome: the file input and color picker mostly defeat custom styling, so the framework stays out of the way and keeps them readable and theme-aware.
|
|
4
|
+
|
|
5
|
+
## Color
|
|
6
|
+
|
|
7
|
+
> Small, theme-aware chrome for the native color picker.
|
|
8
|
+
|
|
9
|
+
Use `.color` on an `input[type="color"]` to give the native picker a control-sized
|
|
10
|
+
box with the framework's border, radius, surface, disabled, and focus styles.
|
|
11
|
+
The color dialog and selected-color swatch remain browser-native.
|
|
12
|
+
|
|
13
|
+
```html demo
|
|
14
|
+
<label class="field">
|
|
15
|
+
<span class="field-label">Accent color</span>
|
|
16
|
+
<input class="color" type="color" value="#6d5dfc" />
|
|
17
|
+
</label>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## File
|
|
21
|
+
|
|
22
|
+
Use `.file` on an `input[type="file"]` to keep the field native while theming the
|
|
23
|
+
picker button with the framework's surface, border, radius, and hover states.
|
|
24
|
+
The filename area stays muted.
|
|
25
|
+
|
|
26
|
+
```html demo
|
|
27
|
+
<label class="field">
|
|
28
|
+
<span class="field-label">Profile picture</span>
|
|
29
|
+
<input class="file" type="file" accept="image/*" aria-describedby="file-help" />
|
|
30
|
+
<span class="field-help" id="file-help">JPG, PNG or WebP — max 2 MB</span>
|
|
31
|
+
</label>
|
|
32
|
+
```
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Detached Actions
|
|
2
|
+
|
|
3
|
+
> `.form-actions` is class-only. It may live inside or outside the `<form>`. Use the native `form` attribute to connect a detached submit button to its form.
|
|
4
|
+
|
|
5
|
+
The simplest case stays inside the form.
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<form novalidate>
|
|
9
|
+
<div class="stack">
|
|
10
|
+
<!-- fields -->
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<div class="form-actions">
|
|
14
|
+
<button type="button" class="btn outline">Cancel</button>
|
|
15
|
+
<button type="submit" class="btn primary">Save changes</button>
|
|
16
|
+
</div>
|
|
17
|
+
</form>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
For sticky page footers, dialog footers, card footers, and split layouts, detach the actions and connect the submit button with `form="<id>"`.
|
|
21
|
+
|
|
22
|
+
```html
|
|
23
|
+
<form id="profile-form" novalidate>
|
|
24
|
+
<div class="stack">
|
|
25
|
+
<!-- long form fields -->
|
|
26
|
+
</div>
|
|
27
|
+
</form>
|
|
28
|
+
|
|
29
|
+
<footer class="form-actions">
|
|
30
|
+
<button type="button" class="btn outline">Cancel</button>
|
|
31
|
+
<button type="submit" class="btn primary" form="profile-form">
|
|
32
|
+
Save changes
|
|
33
|
+
</button>
|
|
34
|
+
</footer>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
For multiple submit intents, pair the `form` attribute with `formaction`. The form has one action; each submit button can override it.
|
|
38
|
+
|
|
39
|
+
```html
|
|
40
|
+
<form id="article-form"
|
|
41
|
+
action="/articles/publish"
|
|
42
|
+
method="post">
|
|
43
|
+
<!-- fields -->
|
|
44
|
+
</form>
|
|
45
|
+
|
|
46
|
+
<div class="form-actions">
|
|
47
|
+
<button type="submit"
|
|
48
|
+
class="btn outline"
|
|
49
|
+
form="article-form"
|
|
50
|
+
formaction="/articles/draft">
|
|
51
|
+
Save draft
|
|
52
|
+
</button>
|
|
53
|
+
<button type="submit"
|
|
54
|
+
class="btn primary"
|
|
55
|
+
form="article-form">
|
|
56
|
+
Publish
|
|
57
|
+
</button>
|
|
58
|
+
</div>
|
|
59
|
+
```
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Floating labels
|
|
2
|
+
|
|
3
|
+
> **Optional** — import `actual-css/css/optional/floating-field` or `actual-css/css/optional`.
|
|
4
|
+
|
|
5
|
+
`.floating-field` turns a control and its label into a floating-label cell:
|
|
6
|
+
the label rests inside the control and floats to the top when the control is
|
|
7
|
+
focused or filled. It composes the existing `.field` layout and the text
|
|
8
|
+
controls (`.input`, `.textarea`, `.select`) with zero JavaScript.
|
|
9
|
+
|
|
10
|
+
The cell holds the control and its label only. Help and error messages stay in
|
|
11
|
+
the surrounding `.field`, otherwise the resting label centers on the whole
|
|
12
|
+
field instead of the control.
|
|
13
|
+
|
|
14
|
+
```html demo
|
|
15
|
+
<div class="field">
|
|
16
|
+
<label class="floating-field">
|
|
17
|
+
<input class="input" type="email" placeholder=" " aria-describedby="email-help" />
|
|
18
|
+
<span class="field-label">Email</span>
|
|
19
|
+
</label>
|
|
20
|
+
<span class="field-help" id="email-help">We'll never share your email.</span>
|
|
21
|
+
</div>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Every `.input` and `.textarea` needs `placeholder=" "` so `:placeholder-shown`
|
|
25
|
+
can detect emptiness — the space keeps the placeholder invisible while making
|
|
26
|
+
the state detectable. `:autofill` is covered too, so a password manager that
|
|
27
|
+
prefills a field still lifts the label.
|
|
28
|
+
|
|
29
|
+
## Textarea
|
|
30
|
+
|
|
31
|
+
A textarea's resting label aligns with the first text line instead of centering
|
|
32
|
+
in the tall control.
|
|
33
|
+
|
|
34
|
+
```html demo
|
|
35
|
+
<div class="field">
|
|
36
|
+
<label class="floating-field">
|
|
37
|
+
<textarea class="textarea" rows="4" placeholder=" "></textarea>
|
|
38
|
+
<span class="field-label">Message</span>
|
|
39
|
+
</label>
|
|
40
|
+
</div>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Select and date/time inputs
|
|
44
|
+
|
|
45
|
+
Selects have no `:placeholder-shown` signal, and date/time inputs render their
|
|
46
|
+
placeholder inconsistently (Firefox shows none). These controls stay floated in
|
|
47
|
+
every state, so their label always sits at the top.
|
|
48
|
+
|
|
49
|
+
```html demo
|
|
50
|
+
<div class="stack">
|
|
51
|
+
<label class="floating-field">
|
|
52
|
+
<select class="select">
|
|
53
|
+
<option value="">Choose a country</option>
|
|
54
|
+
<option>Belgium</option>
|
|
55
|
+
<option>France</option>
|
|
56
|
+
<option>Netherlands</option>
|
|
57
|
+
</select>
|
|
58
|
+
<span class="field-label">Country</span>
|
|
59
|
+
</label>
|
|
60
|
+
|
|
61
|
+
<label class="floating-field">
|
|
62
|
+
<input class="input" type="date" />
|
|
63
|
+
<span class="field-label">Start date</span>
|
|
64
|
+
</label>
|
|
65
|
+
</div>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Density
|
|
69
|
+
|
|
70
|
+
The reserved headroom responds to control density through `--control-size`:
|
|
71
|
+
`.sm` and `.lg` on the cell or an ancestor resize the control geometry and the
|
|
72
|
+
label spacing with it. Typography is untouched, as everywhere in the framework.
|
|
73
|
+
The floating label does add height — the headroom reserves a second vertical
|
|
74
|
+
line on top of the control's minimum size.
|
|
75
|
+
|
|
76
|
+
## CSS hooks
|
|
77
|
+
|
|
78
|
+
- `--floating-pad-block-start` — headroom reserved above the control for the
|
|
79
|
+
floated label; defaults to half the control height plus one spacing step.
|
|
80
|
+
|
|
81
|
+
Validation and focus come from the existing form contracts: the control's
|
|
82
|
+
border and focus ring flip through `--form-invalid-border` and the shared
|
|
83
|
+
control focus rules. Coloring the label itself on focus or invalid state is
|
|
84
|
+
left to the surrounding recipe — the joined floating form in the
|
|
85
|
+
[blocks demo](../../demo/templates/blocks.html) shows one such recipe.
|
|
86
|
+
|
|
87
|
+
> Not currently compatible with `.input-icon`; use standard labels when an
|
|
88
|
+
> embedded leading icon is required.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Form Actions
|
|
2
|
+
|
|
3
|
+
> `.form-actions` is a class-only flex row that closes a form. It may live
|
|
4
|
+
> inside or outside the `<form>` (see Detached Actions) and has an opt-in
|
|
5
|
+
> sticky variant (see Sticky Actions).
|
|
6
|
+
|
|
7
|
+
The default layout is a wrapping flex row: items are centered on the cross
|
|
8
|
+
axis and start-aligned on the main axis, with a default top margin that
|
|
9
|
+
separates the actions from the fields above.
|
|
10
|
+
|
|
11
|
+
```html
|
|
12
|
+
<form novalidate>
|
|
13
|
+
<div class="stack">
|
|
14
|
+
<!-- fields -->
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<div class="form-actions">
|
|
18
|
+
<button type="button" class="btn outline">Cancel</button>
|
|
19
|
+
<button type="submit" class="btn primary">Save changes</button>
|
|
20
|
+
</div>
|
|
21
|
+
</form>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## CSS hooks
|
|
25
|
+
|
|
26
|
+
The three layout hooks are unset by default and fall back to the values below.
|
|
27
|
+
|
|
28
|
+
- `--form-actions-align` — `center` — cross-axis alignment (`align-items`).
|
|
29
|
+
- `--form-actions-justify` — `flex-start` — main-axis distribution (`justify-content`).
|
|
30
|
+
- `--form-actions-margin-block-start` — `var(--space-50)` — top margin separating actions from the form.
|
|
31
|
+
|
|
32
|
+
### Common arrangements
|
|
33
|
+
|
|
34
|
+
Right-align the submit on wide rows:
|
|
35
|
+
|
|
36
|
+
```css
|
|
37
|
+
.form-actions {
|
|
38
|
+
--form-actions-justify: flex-end;
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Stretch each action to fill the full row width:
|
|
43
|
+
|
|
44
|
+
```css
|
|
45
|
+
.form-actions {
|
|
46
|
+
--form-actions-align: stretch;
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Because the hooks are inherited custom properties, set them on a page or
|
|
51
|
+
container to apply one arrangement to every `.form-actions` inside it.
|
|
52
|
+
|
|
53
|
+
> The sticky variant adds `--form-actions-sticky-block-offset`,
|
|
54
|
+
> `--form-actions-sticky-padding`, and `--form-actions-sticky-inline-offset` —
|
|
55
|
+
> see Sticky Actions. `.form-actions` is class-only and works inside or
|
|
56
|
+
> outside the form — see Detached Actions.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Input Policy
|
|
2
|
+
|
|
3
|
+
> Native input intent first. Actual's runtime filters values only when explicitly asked, and fixed-shape masks stay opt-in through `data-mask`.
|
|
4
|
+
|
|
5
|
+
`inputmode` changes the virtual keyboard but does not constrain the value. Actual
|
|
6
|
+
does not filter plain `inputmode` fields by default because numeric entry often
|
|
7
|
+
needs temporary, signed, grouped, or locale-specific values while the user types.
|
|
8
|
+
|
|
9
|
+
When the JavaScript runtime is loaded, Actual enhances `input[data-filter]`.
|
|
10
|
+
Textareas are left alone.
|
|
11
|
+
|
|
12
|
+
Add an explicit `data-filter` value when the field should enforce one of
|
|
13
|
+
Actual's small built-in filters. Unsupported filter names are ignored. An
|
|
14
|
+
empty `data-filter` never filters — `inputmode` is not read as a fallback,
|
|
15
|
+
even when it is `numeric` or `decimal`. `data-filter="numeric"` /
|
|
16
|
+
`data-filter="decimal"` are intentionally destructive (they rewrite the
|
|
17
|
+
value as the user types), unlike `inputmode`, which only hints the virtual
|
|
18
|
+
keyboard.
|
|
19
|
+
|
|
20
|
+
```html demo
|
|
21
|
+
<label class="field">
|
|
22
|
+
<span class="field-label">Quantity</span>
|
|
23
|
+
<input class="input" inputmode="numeric" data-filter="numeric" placeholder="42" />
|
|
24
|
+
</label>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
```html demo
|
|
28
|
+
<label class="field">
|
|
29
|
+
<span class="field-label">Amount</span>
|
|
30
|
+
<input class="input" inputmode="decimal" data-filter="decimal" placeholder="12.34" />
|
|
31
|
+
</label>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Built-in filters
|
|
35
|
+
|
|
36
|
+
The built-in filters are intentionally narrow. They are input helpers, not
|
|
37
|
+
domain validation.
|
|
38
|
+
|
|
39
|
+
- `numeric` — Keeps ASCII digits only: `0` through `9`.
|
|
40
|
+
- `decimal` — Converts `,` to `.`, keeps ASCII digits, and keeps the first `.` separator.
|
|
41
|
+
- `lower` — Converts the value with `toLocaleLowerCase()`.
|
|
42
|
+
- `upper` — Converts the value with `toLocaleUpperCase()`.
|
|
43
|
+
- `letters` — Keeps Unicode letters only. Digits, punctuation, symbols, and spaces are removed.
|
|
44
|
+
- `slug` — Normalizes accents, lowercases text, turns runs of non-letter and non-digit characters into `-`, collapses repeated `-`, and trims edge separators.
|
|
45
|
+
|
|
46
|
+
During direct typing, `slug` may keep a trailing `-` until the next character so
|
|
47
|
+
words do not merge while the user is still entering text.
|
|
48
|
+
|
|
49
|
+
Filters can be piped with `|` when a field needs more than one transform. They
|
|
50
|
+
run from left to right.
|
|
51
|
+
|
|
52
|
+
```html demo
|
|
53
|
+
<label class="field">
|
|
54
|
+
<span class="field-label">Slug</span>
|
|
55
|
+
<input class="input" data-filter="lower|slug" autocomplete="off" placeholder="release-notes" />
|
|
56
|
+
</label>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
```html demo
|
|
60
|
+
<label class="field">
|
|
61
|
+
<span class="field-label">Code</span>
|
|
62
|
+
<input class="input" data-filter="upper|letters" autocomplete="off" placeholder="ABC" />
|
|
63
|
+
</label>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
For signed numbers, locale formatting, currency rules, time ranges, or
|
|
67
|
+
app-specific character policies, use application code. Those rules are domain
|
|
68
|
+
policy, not a framework default. See the JavaScript docs for custom filter
|
|
69
|
+
patterns built on `enhance()`.
|
|
70
|
+
|
|
71
|
+
### Pattern mask
|
|
72
|
+
|
|
73
|
+
Use `data-mask` when the input has a fixed shape. Tokens are `9` for a digit,
|
|
74
|
+
`a` for a letter, and `*` for any character.
|
|
75
|
+
|
|
76
|
+
```html demo
|
|
77
|
+
<label class="field">
|
|
78
|
+
<span class="field-label">Reference</span>
|
|
79
|
+
<input class="input" data-mask="aaa-999" autocomplete="off" placeholder="abc-123" />
|
|
80
|
+
</label>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
```html demo
|
|
84
|
+
<label class="field">
|
|
85
|
+
<span class="field-label">Date</span>
|
|
86
|
+
<input class="input" data-mask="9999-99-99" inputmode="numeric" autocomplete="off" placeholder="yyyy-mm-dd" />
|
|
87
|
+
</label>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Masks enforce shape, not domain validity. Use application validation when a date
|
|
91
|
+
must reject impossible values such as `2026-13-40`.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Joined Controls
|
|
2
|
+
|
|
3
|
+
> Use `.join` when controls need to be visually joined into a single unit.
|
|
4
|
+
|
|
5
|
+
## Class reference
|
|
6
|
+
|
|
7
|
+
| Class | Kind | Description |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| `.join` | Composition | Visually joins adjacent controls into a single unit. |
|
|
10
|
+
| `.join-addon` | Composition | Static prefix/suffix content such as currency symbols, units, or protocol text. |
|
|
11
|
+
|
|
12
|
+
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.
|
|
13
|
+
|
|
14
|
+
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.
|
|
15
|
+
|
|
16
|
+
```html demo
|
|
17
|
+
<div class="field">
|
|
18
|
+
<label class="field-label" id="amount-label" for="amount">Amount</label>
|
|
19
|
+
<div class="join" role="group" aria-labelledby="amount-label">
|
|
20
|
+
<span class="join-addon">$</span>
|
|
21
|
+
<input class="input" id="amount" name="amount" inputmode="decimal" />
|
|
22
|
+
<button class="btn outline" type="button">Clear</button>
|
|
23
|
+
</div>
|
|
24
|
+
<span class="field-help">Enter the invoice total before tax.</span>
|
|
25
|
+
</div>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`.join` handles border-radius and border collapsing between adjacent children. It works with any direct child — `.input`, `.btn`, `.select`, or `.join-addon`.
|
|
29
|
+
When an `.input`, `.textarea`, or `.select` receives keyboard-relevant focus,
|
|
30
|
+
the focus ring surrounds the complete joined field. Attached buttons keep their
|
|
31
|
+
own focus indicator when reached directly, so the actionable segment remains
|
|
32
|
+
identifiable.
|
|
33
|
+
|
|
34
|
+
## CSS hooks
|
|
35
|
+
|
|
36
|
+
- `--join-radius` — outer corner radius of the joined group. The per-corner
|
|
37
|
+
values of each child are derived from it.
|