actual-css 0.3.1 → 0.4.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 +109 -3
- package/README.md +35 -30
- package/dist/actual.css +66 -4958
- package/dist/actual.full.css +7548 -0
- package/dist/actual.full.js +1 -0
- package/dist/actual.full.min.css +1 -0
- package/dist/actual.js +1 -1
- package/dist/actual.min.css +1 -1
- package/docs/design-notes/app-ui.md +33 -0
- package/docs/design-notes/cascade-layer.md +34 -13
- package/docs/design-notes/column-layout.md +677 -0
- package/docs/design-notes/enhancement-contract.md +25 -0
- package/docs/design-notes/forced-colors.md +3 -0
- package/docs/design-notes/grid.md +785 -0
- package/docs/design-notes/naming.md +15 -0
- package/docs/design-notes/references.md +1 -1
- package/docs/design-notes/widget-primitives.md +1 -0
- package/docs/navigation.json +12 -2
- package/docs/pages/components/alert.md +21 -14
- package/docs/pages/components/app-navigation.md +34 -0
- package/docs/pages/components/aura.md +1 -1
- package/docs/pages/components/avatar.md +16 -6
- package/docs/pages/components/badge.md +9 -7
- package/docs/pages/components/button.md +46 -16
- package/docs/pages/components/card.md +17 -9
- package/docs/pages/components/chat.md +8 -8
- package/docs/pages/components/dialog.md +7 -7
- package/docs/pages/components/drawer.md +3 -3
- package/docs/pages/components/fab.md +9 -7
- package/docs/pages/components/indicator.md +52 -0
- package/docs/pages/components/list.md +62 -0
- package/docs/pages/components/navbar.md +15 -8
- package/docs/pages/components/pagination.md +4 -3
- package/docs/pages/components/rating.md +68 -0
- package/docs/pages/components/skeleton.md +4 -4
- package/docs/pages/components/spinner.md +5 -5
- package/docs/pages/components/steps.md +57 -0
- package/docs/pages/components/table.md +30 -5
- package/docs/pages/enhancements/flyout.md +15 -15
- package/docs/pages/enhancements/overview.md +1 -1
- package/docs/pages/enhancements/scrollspy.md +6 -6
- package/docs/pages/enhancements/status-bar.md +5 -1
- package/docs/pages/enhancements/tabs.md +7 -8
- package/docs/pages/enhancements/tooltip.md +1 -1
- package/docs/pages/examples/overview.md +47 -22
- package/docs/pages/forms/choice-cards.md +11 -6
- package/docs/pages/forms/controls.md +1 -1
- package/docs/pages/forms/detached-actions.md +1 -1
- package/docs/pages/forms/floating-field.md +10 -5
- package/docs/pages/forms/form-actions.md +1 -1
- package/docs/pages/forms/input-policy.md +1 -1
- package/docs/pages/forms/joined-controls.md +4 -4
- package/docs/pages/forms/labels.md +6 -6
- package/docs/pages/forms/otp.md +33 -1
- package/docs/pages/forms/overview.md +19 -19
- package/docs/pages/forms/password.md +1 -1
- package/docs/pages/forms/range.md +1 -1
- package/docs/pages/forms/states-and-sizes.md +44 -48
- package/docs/pages/forms/sticky-actions.md +3 -3
- package/docs/pages/forms/switch.md +110 -2
- package/docs/pages/forms/validation.md +9 -9
- package/docs/pages/foundations/philosophy.md +1 -1
- package/docs/pages/foundations/theming.md +17 -2
- package/docs/pages/foundations/tokens.md +22 -10
- package/docs/pages/foundations/typography.md +50 -20
- package/docs/pages/guides/bootstrap.md +11 -11
- package/docs/pages/guides/integrating-actual-css.md +192 -0
- package/docs/pages/guides/introduction.md +23 -26
- package/docs/pages/guides/modular-import.md +173 -0
- package/docs/pages/guides/progressive-enhancement.md +81 -78
- package/docs/pages/guides/tailwind.md +6 -8
- package/docs/pages/layout/app-layout.md +57 -0
- package/docs/pages/layout/app-shell.md +28 -7
- package/docs/pages/layout/center.md +12 -1
- package/docs/pages/layout/choosing.md +54 -0
- package/docs/pages/layout/column-layout.md +206 -0
- package/docs/pages/layout/frame.md +6 -1
- package/docs/pages/layout/grid.md +133 -102
- package/docs/pages/layout/media.md +1 -1
- package/docs/pages/layout/overview.md +15 -2
- package/docs/pages/layout/scroll-snap.md +2 -2
- package/docs/pages/layout/scroll-target.md +45 -0
- package/docs/pages/layout/sidebar-layout.md +38 -18
- package/docs/pages/layout/stack.md +70 -1
- package/docs/pages/layout/switcher.md +10 -26
- package/docs/pages/layout/topbar.md +2 -2
- package/docs/pages/patterns/actions.md +1 -1
- package/docs/pages/patterns/code-block.md +1 -1
- package/docs/pages/patterns/exclusive-accordion.md +1 -1
- package/docs/pages/patterns/hierarchical-nav.md +1 -1
- package/docs/pages/patterns/icon-input.md +1 -1
- package/docs/pages/patterns/icon-slot.md +61 -0
- package/docs/pages/patterns/intent-nesting.md +1 -1
- package/docs/pages/patterns/navigation-list.md +1 -1
- package/docs/pages/patterns/overview.md +1 -1
- package/docs/pages/patterns/structured-lists.md +38 -40
- package/docs/pages/utilities/accessibility.md +3 -3
- package/docs/pages/utilities/flex.md +15 -15
- package/docs/pages/utilities/links.md +4 -4
- package/docs/pages/utilities/list.md +8 -8
- package/docs/pages/utilities/overflow.md +8 -8
- package/docs/pages/utilities/overview.md +1 -1
- package/docs/pages/utilities/shape.md +3 -3
- package/docs/pages/utilities/sizing-wrapping.md +23 -16
- package/docs/pages/utilities/spacing.md +20 -20
- package/docs/pages/utilities/text.md +10 -10
- package/llms.txt +46 -4
- package/package.json +43 -13
- package/scripts/reserved-classes.json +278 -0
- package/src/cli/actual-css.js +133 -0
- package/src/css/actual.css +1 -31
- package/src/css/actual.full.css +11 -2
- package/src/css/components/alert.css +17 -4
- package/src/css/components/app-nav.css +76 -0
- package/src/css/components/avatar.css +4 -0
- package/src/css/components/badge.css +19 -19
- package/src/css/components/breadcrumb.css +1 -1
- package/src/css/components/button.css +20 -32
- package/src/css/components/card.css +34 -9
- package/src/css/{optional → components}/chat.css +0 -6
- package/src/css/components/drawer.css +24 -5
- package/src/css/{optional → components}/fab.css +1 -7
- package/src/css/components/flyout.css +5 -0
- package/src/css/components/index.css +37 -27
- package/src/css/components/indicator.css +47 -0
- package/src/css/components/join.css +8 -1
- package/src/css/components/key.css +2 -0
- package/src/css/components/list.css +83 -0
- package/src/css/components/menu.css +11 -8
- package/src/css/components/meter.css +4 -1
- package/src/css/components/modal.css +5 -17
- package/src/css/components/navbar.css +6 -15
- package/src/css/components/pagination.css +11 -0
- package/src/css/components/rating.css +101 -0
- package/src/css/components/spinner.css +5 -0
- package/src/css/components/status-bar.css +5 -0
- package/src/css/components/steps.css +122 -0
- package/src/css/components/surface.css +5 -0
- package/src/css/components/tab.css +20 -22
- package/src/css/components/table.css +6 -0
- package/src/css/components/tooltip.css +3 -7
- package/src/css/{focus.css → core/focus.css} +0 -8
- package/src/css/core/index.css +9 -0
- package/src/css/core/print.css +18 -0
- package/src/css/{theme.css → core/theme.css} +19 -19
- package/src/css/{tokens.css → core/tokens.css} +16 -4
- package/src/css/{variants.css → core/variants.css} +3 -2
- package/src/css/{optional → effects}/aura.css +1 -10
- package/src/css/effects/index.css +2 -0
- package/src/css/forms/base.css +8 -0
- package/src/css/forms/choice-card.css +7 -15
- package/src/css/forms/choice.css +49 -37
- package/src/css/forms/control.css +4 -1
- package/src/css/forms/custom-select.css +2 -0
- package/src/css/{optional → forms}/floating-field.css +25 -7
- package/src/css/forms/index.css +10 -13
- package/src/css/forms/native.css +15 -2
- package/src/css/{optional → forms}/otp.css +25 -16
- package/src/css/forms/range.css +14 -4
- package/src/css/forms/switch.css +31 -29
- package/src/css/layout/app-layout.css +102 -0
- package/src/css/layout/app-shell.css +6 -0
- package/src/css/layout/center.css +14 -0
- package/src/css/layout/cluster.css +21 -0
- package/src/css/layout/column-layout.css +144 -0
- package/src/css/layout/container-query.css +15 -0
- package/src/css/layout/frame.css +19 -0
- package/src/css/layout/grid.css +155 -0
- package/src/css/layout/index.css +44 -0
- package/src/css/layout/measure.css +9 -0
- package/src/css/layout/media.css +10 -0
- package/src/css/layout/scroll-target.css +15 -0
- package/src/css/layout/scroller.css +41 -0
- package/src/css/layout/sidebar-layout.css +52 -0
- package/src/css/layout/stack.css +21 -0
- package/src/css/layout/switcher.css +23 -0
- package/src/css/{optional/layout-extra.css → layout/topbar.css} +0 -20
- package/src/css/typography/index.css +5 -0
- package/src/css/typography/lead.css +7 -0
- package/src/css/{components → typography}/overline.css +2 -2
- package/src/css/{prose.css → typography/prose.css} +57 -38
- package/src/css/{utilities.css → utilities/base.css} +2 -0
- package/src/css/utilities/index.css +3 -0
- package/src/js/escape.js +36 -0
- package/src/js/flyout.js +22 -12
- package/src/js/full.js +26 -0
- package/src/js/index.js +5 -21
- package/src/js/surface.js +1 -31
- package/src/js/tooltip.js +48 -19
- package/src/js/validation.js +1 -1
- package/src/tooling/css-bundle.js +308 -0
- package/dist/actual-themes.min.css +0 -1
- package/dist/optional.css +0 -1048
- package/dist/optional.min.css +0 -1
- package/docs/pages/guides/optional-components.md +0 -33
- package/docs/pages/layout/list.md +0 -41
- package/src/css/grid.css +0 -109
- package/src/css/layout.css +0 -123
- package/src/css/optional/index.css +0 -10
- package/src/css/optional/scroller.css +0 -63
- package/src/css/print.css +0 -47
- package/src/css/themes/corporate.css +0 -60
- package/src/css/themes/cyberpunk.css +0 -60
- package/src/css/themes/dim.css +0 -33
- package/src/css/themes/edge.css +0 -117
- package/src/css/themes/forest.css +0 -65
- package/src/css/themes/gradient.css +0 -97
- package/src/css/themes/index.css +0 -47
- package/src/css/themes/indigo.css +0 -33
- package/src/css/themes/lavender.css +0 -66
- package/src/css/themes/mono.css +0 -60
- package/src/css/themes/neon.css +0 -66
- package/src/css/themes/ocean.css +0 -60
- package/src/css/themes/petrol.css +0 -64
- package/src/css/themes/spruce.css +0 -64
- package/src/css/themes/square.css +0 -65
- package/src/css/themes/sunset.css +0 -66
- /package/src/css/{base.css → core/base.css} +0 -0
- /package/src/css/{intents.css → core/intents.css} +0 -0
- /package/src/css/{reset.css → core/reset.css} +0 -0
- /package/src/css/{optional → layout}/scroll-snap.css +0 -0
- /package/src/css/{optional/typography-fluid.css → typography/fluid.css} +0 -0
- /package/src/css/{optional/utilities-extra.css → utilities/extra.css} +0 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# Modular imports
|
|
2
|
+
|
|
3
|
+
Actual CSS ships one minimal core (`actual-css`) and one all-in entrypoint (`actual-css/full`). Projects can also compose the framework from family manifests or individual modules.
|
|
4
|
+
|
|
5
|
+
## Entrypoints
|
|
6
|
+
|
|
7
|
+
```css
|
|
8
|
+
@import "actual-css"; /* minimal core */
|
|
9
|
+
@import "actual-css/full"; /* complete framework */
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
`actual-css` contains the shared baseline: reset, tokens, theme, document defaults, intents, universal variants, focus, and print.
|
|
13
|
+
|
|
14
|
+
It contains no typography, layout, forms, components, effects, or utilities.
|
|
15
|
+
|
|
16
|
+
`actual-css/full` starts from the core and adds every family in cascade order:
|
|
17
|
+
|
|
18
|
+
```text
|
|
19
|
+
core → typography → layout → forms → components → effects → utilities
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Focus is a core invariant
|
|
23
|
+
|
|
24
|
+
The core provides a visible `:focus` outline as the compatibility baseline. Modern browsers limit it to `:focus-visible`, hiding the pointer-focus outline.
|
|
25
|
+
|
|
26
|
+
Components may enhance or replace that treatment in interactive states, but their base styles must not cancel the shared fallback.
|
|
27
|
+
|
|
28
|
+
When an interactive state replaces the outline, it must preserve a visible focus indicator in forced-colors, either with an outline-based fallback or by keeping the replacement out of forced-colors.
|
|
29
|
+
|
|
30
|
+
## Family manifests
|
|
31
|
+
|
|
32
|
+
| Family | Import | Contents |
|
|
33
|
+
| ---------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
|
34
|
+
| Core | `actual-css/css` | reset, tokens, theme, base, intents, variants, focus, print |
|
|
35
|
+
| Typography | `actual-css/css/typography` | prose, overline, fluid |
|
|
36
|
+
| Layout | `actual-css/css/layout` | stack, cluster, center, frame, media, switcher, sidebar-layout, grid, scroller, scroll-snap, topbar, container-query, app-shell |
|
|
37
|
+
| Forms | `actual-css/css/forms` | native control baseline |
|
|
38
|
+
| Forms (complete) | `actual-css/css/forms/all` | base plus input-icon, switch, range, choice-card, custom-select, floating-field, otp |
|
|
39
|
+
| Components | `actual-css/css/components` | buttons, surfaces, overlays, feedback, navigation, data and composed controls |
|
|
40
|
+
| Effects | `actual-css/css/effects` | aura |
|
|
41
|
+
| Utilities | `actual-css/css/utilities` | base and extra utilities |
|
|
42
|
+
|
|
43
|
+
Individual modules can be imported through their domain path:
|
|
44
|
+
|
|
45
|
+
```css
|
|
46
|
+
@import "actual-css/css/forms/otp";
|
|
47
|
+
@import "actual-css/css/components/chat";
|
|
48
|
+
@import "actual-css/css/effects/aura";
|
|
49
|
+
@import "actual-css/css/layout/scroller";
|
|
50
|
+
@import "actual-css/css/typography/fluid";
|
|
51
|
+
@import "actual-css/css/utilities/extra";
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Use your existing CSS pipeline
|
|
55
|
+
|
|
56
|
+
Actual CSS is plain CSS and does not require its own build tool.
|
|
57
|
+
|
|
58
|
+
If a project already uses Vite, PostCSS, Webpack, Parcel, Lightning CSS, or another CSS pipeline, keep using it and import the Actual CSS package exports directly.
|
|
59
|
+
|
|
60
|
+
For example:
|
|
61
|
+
|
|
62
|
+
```css
|
|
63
|
+
@import "actual-css/css";
|
|
64
|
+
@import "actual-css/css/layout";
|
|
65
|
+
@import "actual-css/css/forms/all";
|
|
66
|
+
@import "actual-css/css/components/button";
|
|
67
|
+
@import "actual-css/css/components/card";
|
|
68
|
+
|
|
69
|
+
@import "./theme.css";
|
|
70
|
+
@import "./app.css";
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The consuming pipeline remains responsible for features such as asset handling, URL rebasing, source maps, CSS Modules, import modifiers, transpilation, and browser targeting.
|
|
74
|
+
|
|
75
|
+
Actual CSS intentionally does not require a particular bundler or transpiler.
|
|
76
|
+
|
|
77
|
+
## Optional CLI bundler
|
|
78
|
+
|
|
79
|
+
For projects without a CSS pipeline, Actual CSS includes a small zero-dependency import flattener:
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
npx actual-css bundle src/app.css --out public/app.css
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
or:
|
|
86
|
+
|
|
87
|
+
```sh
|
|
88
|
+
bunx actual-css bundle src/app.css --out public/app.css
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Add `--minify` for lightweight whitespace/comment minification:
|
|
92
|
+
|
|
93
|
+
```sh
|
|
94
|
+
npx actual-css bundle src/app.css --out public/app.css --minify
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
The CLI resolves and inlines:
|
|
98
|
+
|
|
99
|
+
```css
|
|
100
|
+
@import "./local.css";
|
|
101
|
+
@import "actual-css/css/layout";
|
|
102
|
+
@import "actual-css/css/components/card";
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
It deliberately does **not** transpile CSS. Modern syntax such as nesting, `@container`, `@scope`, `:has()`, `color-mix()`, `light-dark()`, and media-query range syntax is preserved for the browser.
|
|
106
|
+
|
|
107
|
+
The CLI is a simple flattener, not a general-purpose CSS build pipeline.
|
|
108
|
+
|
|
109
|
+
### Limitations
|
|
110
|
+
|
|
111
|
+
Local and package imports may be plain imports, or carry a layer modifier:
|
|
112
|
+
|
|
113
|
+
```css
|
|
114
|
+
@import "./local.css";
|
|
115
|
+
@import "./local.css" layer(components);
|
|
116
|
+
@import "./local.css" layer;
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
A layered import is flattened into the block it stands for, so `@import "actual-css/css" layer(actual)` becomes `@layer actual { … }`. A layer declared inside the imported file becomes a sublayer of that wrapper, exactly as the import did.
|
|
120
|
+
|
|
121
|
+
Conditional modifiers are not flattened:
|
|
122
|
+
|
|
123
|
+
```css
|
|
124
|
+
@import "./local.css" supports(display: grid);
|
|
125
|
+
@import "./local.css" screen;
|
|
126
|
+
@import "./local.css" layer(components) supports(display: grid);
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Use an existing CSS pipeline when these features are required.
|
|
130
|
+
|
|
131
|
+
One further case is refused rather than guessed: a remote import inside a layered subtree, because hoisting it before ordinary rules would move it out of its layer.
|
|
132
|
+
|
|
133
|
+
The CLI also does not process or rebase asset URLs such as:
|
|
134
|
+
|
|
135
|
+
```css
|
|
136
|
+
background-image: url("../images/card.svg");
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Those paths remain exactly as written, so projects with relative assets should generally let their existing build pipeline handle CSS imports.
|
|
140
|
+
|
|
141
|
+
Remote and absolute imports are preserved rather than fetched and are moved before ordinary rules so they remain valid CSS.
|
|
142
|
+
|
|
143
|
+
## Cascade layers
|
|
144
|
+
|
|
145
|
+
Actual CSS can participate in a project-owned cascade layer:
|
|
146
|
+
|
|
147
|
+
```css
|
|
148
|
+
@layer actual;
|
|
149
|
+
|
|
150
|
+
@import "actual-css/full" layer(actual);
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Or, when composing families:
|
|
154
|
+
|
|
155
|
+
```css
|
|
156
|
+
@layer actual;
|
|
157
|
+
|
|
158
|
+
@import "actual-css/css" layer(actual);
|
|
159
|
+
@import "actual-css/css/typography" layer(actual);
|
|
160
|
+
@import "actual-css/css/layout" layer(actual);
|
|
161
|
+
@import "actual-css/css/forms/all" layer(actual);
|
|
162
|
+
@import "actual-css/css/components" layer(actual);
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
`actual-css/css/layer` also exposes the minimal core wrapped in `@layer actual`.
|
|
166
|
+
|
|
167
|
+
All of these recipes flatten with `actual-css bundle`: the CLI understands layer modifiers, so a public entrypoint of the framework is never something its own bundler has to refuse.
|
|
168
|
+
|
|
169
|
+
## Custom properties
|
|
170
|
+
|
|
171
|
+
Component-prefixed custom properties documented on component pages are author hooks.
|
|
172
|
+
|
|
173
|
+
Color and sizing otherwise stay within the shared intent, variant, control, and button APIs.
|
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
> The optional JavaScript runtime that progressively enhances Actual's semantic markup — self-registering side-effect modules, the `enhance()` DOM lifecycle, stateless command routing, and the floating and surface contracts for custom widgets.
|
|
4
4
|
|
|
5
|
-
Actual's JavaScript modules are optional. Importing `actual-css/js`
|
|
6
|
-
complete default runtime — every built-in enhancer, including
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
`
|
|
5
|
+
Actual's JavaScript modules are optional. Importing `actual-css/js/full`
|
|
6
|
+
registers the complete default runtime — every built-in enhancer, including
|
|
7
|
+
validation and status. Importing `actual-css/js` registers only the enhancement
|
|
8
|
+
manifest loader; importing a specific module registers only that behavior. The
|
|
9
|
+
runtime does not require `DOMContentLoaded` or manual init calls, and it never
|
|
10
|
+
touches `window`: there is no global object to call into.
|
|
10
11
|
|
|
11
12
|
## Browser support
|
|
12
13
|
|
|
@@ -16,12 +17,12 @@ unsupported — it is not tested, documented as supported, or preserved when the
|
|
|
16
17
|
runtime evolves. The runtime assumes the modern platform primitives available
|
|
17
18
|
across Minimal and ships no compatibility layer or polyfill.
|
|
18
19
|
|
|
19
|
-
| Tier
|
|
20
|
-
|
|
21
|
-
| Degraded
|
|
22
|
-
| **Minimal**
|
|
23
|
-
| Intermediate | 121+
|
|
24
|
-
| Recommended
|
|
20
|
+
| Tier | Firefox | Safari | Chromium |
|
|
21
|
+
|--------------|---------|-----------|----------|
|
|
22
|
+
| Degraded | 78+ | 14+ | 88+ |
|
|
23
|
+
| **Minimal** | **98+** | **15.4+** | **99+** |
|
|
24
|
+
| Intermediate | 121+ | 16+ | 106+ |
|
|
25
|
+
| Recommended | 129+ | 17.5+ | 123+ |
|
|
25
26
|
|
|
26
27
|
The tier definitions live in the browser-support design note.
|
|
27
28
|
|
|
@@ -57,13 +58,14 @@ handle, and cleanup happens per element when an element leaves the DOM.
|
|
|
57
58
|
|
|
58
59
|
## The default runtime
|
|
59
60
|
|
|
60
|
-
Loading `dist/actual.js` as a plain `<script>` (no `type="module"`, no
|
|
61
|
-
no `import`) gets the full runtime. Static HTML that needs to trigger
|
|
62
|
-
from its own inline `<script>` dispatches the module's public event
|
|
63
|
-
calling into a global — `actual:status` for the status bar, for
|
|
61
|
+
Loading `dist/actual.full.js` as a plain `<script>` (no `type="module"`, no
|
|
62
|
+
bundler, no `import`) gets the full runtime. Static HTML that needs to trigger
|
|
63
|
+
something from its own inline `<script>` dispatches the module's public event
|
|
64
|
+
instead of calling into a global — `actual:status` for the status bar, for
|
|
65
|
+
example:
|
|
64
66
|
|
|
65
67
|
```html
|
|
66
|
-
<script src="actual.js"></script>
|
|
68
|
+
<script src="actual.full.js"></script>
|
|
67
69
|
<script>
|
|
68
70
|
document.dispatchEvent(new CustomEvent("actual:status", {
|
|
69
71
|
bubbles: true,
|
|
@@ -72,24 +74,24 @@ calling into a global — `actual:status` for the status bar, for example:
|
|
|
72
74
|
</script>
|
|
73
75
|
```
|
|
74
76
|
|
|
75
|
-
| Module
|
|
76
|
-
|
|
77
|
-
| `actual-css/js/flyout`
|
|
78
|
-
| `actual-css/js/context-menu`
|
|
79
|
-
| `actual-css/js/focus-group`
|
|
80
|
-
| `actual-css/js/dialog`
|
|
81
|
-
| `actual-css/js/dismiss`
|
|
82
|
-
| `actual-css/js/tab`
|
|
83
|
-
| `actual-css/js/tooltip`
|
|
84
|
-
| `actual-css/js/scrollspy`
|
|
85
|
-
| `actual-css/js/filter`
|
|
86
|
-
| `actual-css/js/mask`
|
|
87
|
-
| `actual-css/js/password`
|
|
88
|
-
| `actual-css/js/validation`
|
|
89
|
-
| `actual-css/js/status`
|
|
90
|
-
| `actual-css/js/enhancement-loader` | Declared enhancement manifests (`data-enhance-modules`, `Enhance-Modules`)
|
|
91
|
-
|
|
92
|
-
Use `actual-css/js` for demos, playgrounds, and smoke tests where one import
|
|
77
|
+
| Module | Behavior |
|
|
78
|
+
|------------------------------------|-------------------------------------------------------------------------------|
|
|
79
|
+
| `actual-css/js/flyout` | Trigger → panel surface: positioning, open/close, sheet mode (token `flyout`) |
|
|
80
|
+
| `actual-css/js/context-menu` | Context menus on `data-context-menu` |
|
|
81
|
+
| `actual-css/js/focus-group` | Reusable roving-focus controller; no automatic discovery |
|
|
82
|
+
| `actual-css/js/dialog` | Native `<dialog>` behavior, focus management, dismissal |
|
|
83
|
+
| `actual-css/js/dismiss` | The generic `--dismiss` command |
|
|
84
|
+
| `actual-css/js/tab` | Tab panels and arrow-key navigation (token `tabs`) |
|
|
85
|
+
| `actual-css/js/tooltip` | Tooltips on `data-tooltip` |
|
|
86
|
+
| `actual-css/js/scrollspy` | Scroll-driven nav highlighting (token `scrollspy`) |
|
|
87
|
+
| `actual-css/js/filter` | Input value filtering on `data-filter` |
|
|
88
|
+
| `actual-css/js/mask` | Input masks on `data-mask` |
|
|
89
|
+
| `actual-css/js/password` | Password reveal toggle |
|
|
90
|
+
| `actual-css/js/validation` | Form validation (token `validation`) |
|
|
91
|
+
| `actual-css/js/status` | Singleton status bar on `[data-status][role="status"]` |
|
|
92
|
+
| `actual-css/js/enhancement-loader` | Declared enhancement manifests (`data-enhance-modules`, `Enhance-Modules`) |
|
|
93
|
+
|
|
94
|
+
Use `actual-css/js/full` for demos, playgrounds, and smoke tests where one import
|
|
93
95
|
enables every built-in behavior. Production apps can import individual modules
|
|
94
96
|
such as `actual-css/js/validation` or `actual-css/js/status` when only those are
|
|
95
97
|
needed.
|
|
@@ -122,15 +124,16 @@ For building custom widgets (select, tags, date picker) on Actual's primitives,
|
|
|
122
124
|
see the widget-primitives design note. Every primitive subpath is published in
|
|
123
125
|
`package.json#exports`:
|
|
124
126
|
|
|
125
|
-
| Subpath
|
|
126
|
-
|
|
127
|
-
| `actual-css/js/enhance`
|
|
128
|
-
| `actual-css/js/
|
|
129
|
-
| `actual-css/js/
|
|
130
|
-
| `actual-css/js/
|
|
131
|
-
| `actual-css/js/
|
|
132
|
-
| `actual-css/js/
|
|
133
|
-
| `actual-css/js/
|
|
127
|
+
| Subpath | Purpose |
|
|
128
|
+
|--------------------------|------------------------------------------------------------------|
|
|
129
|
+
| `actual-css/js/enhance` | DOM lifecycle engine: `enhance()`, `registerEnhancement`, tokens |
|
|
130
|
+
| `actual-css/js/escape` | Per-document LIFO Escape dismissal stack |
|
|
131
|
+
| `actual-css/js/events` | The `actual:*` event name constants |
|
|
132
|
+
| `actual-css/js/floating` | Positioning engine (`reposition`, `repositionAt`, `autoUpdate`) |
|
|
133
|
+
| `actual-css/js/focus` | Focusable-item lookup and helpers |
|
|
134
|
+
| `actual-css/js/keys` | Roving-focus item navigation helpers |
|
|
135
|
+
| `actual-css/js/menu` | Menu keyboard/click wiring, item vocabulary |
|
|
136
|
+
| `actual-css/js/surface` | Surface lifecycle (`openSurface`, `closeSurface`, …) |
|
|
134
137
|
|
|
135
138
|
The exports map is explicit — it *is* the statement of what is public.
|
|
136
139
|
|
|
@@ -152,14 +155,14 @@ const stop = autoUpdate(float, () => {
|
|
|
152
155
|
|
|
153
156
|
Options passed to `reposition()`:
|
|
154
157
|
|
|
155
|
-
| Option
|
|
156
|
-
|
|
157
|
-
| `placement`
|
|
158
|
-
| `distance`
|
|
159
|
-
| `flip`
|
|
160
|
-
| `shift`
|
|
161
|
-
| `shiftPadding` | `4`
|
|
162
|
-
| `scope`
|
|
158
|
+
| Option | Default | Contract |
|
|
159
|
+
|----------------|------------------|------------------------------------------------------------------|
|
|
160
|
+
| `placement` | `"bottom-start"` | Preferred side and alignment (`-start` / `-end`) |
|
|
161
|
+
| `distance` | `0` | Gap between the reference and the floating element |
|
|
162
|
+
| `flip` | `true` | Flip to the opposite side when the preferred side is out of view |
|
|
163
|
+
| `shift` | `true` | Shift along the main axis to stay within the boundary |
|
|
164
|
+
| `shiftPadding` | `4` | Minimum space kept from the boundary |
|
|
165
|
+
| `scope` | viewport | Boundary element for overflow decisions |
|
|
163
166
|
|
|
164
167
|
`autoUpdate(element, callback)` batches scroll, resize, and element-resize
|
|
165
168
|
callbacks per document and returns a stop handle; it does not keep a closed or
|
|
@@ -195,30 +198,30 @@ Two non-obvious requirements:
|
|
|
195
198
|
|
|
196
199
|
Lifecycle: `prepareSurface` → `openSurface` → `closeSurface` →
|
|
197
200
|
`disconnectSurface`. `retainSurface(panel)` reference-counts a surface shared by
|
|
198
|
-
several triggers and returns a release function; `
|
|
199
|
-
|
|
200
|
-
|
|
201
|
+
several triggers and returns a release function; `isSurfaceOpen` and
|
|
202
|
+
`getSurfaceAutoClose` read current state. The separate `escape` primitive adds
|
|
203
|
+
visible dismissable UI to the shared per-document Escape stack.
|
|
201
204
|
|
|
202
205
|
`openSurface(menu, opts)` dispatches a cancelable `actual:surface-open` event —
|
|
203
206
|
widgets can veto or decorate opens, and context menus inject their own
|
|
204
207
|
`source`/`restoreFocusTo` through it.
|
|
205
208
|
|
|
206
|
-
| Option
|
|
207
|
-
|
|
208
|
-
| `trigger`
|
|
209
|
-
| `source`
|
|
210
|
-
| `x`, `y`
|
|
211
|
-
| `placement`
|
|
212
|
-
| `distance`
|
|
213
|
-
| `flip`
|
|
214
|
-
| `shift`
|
|
215
|
-
| `shiftPadding`
|
|
216
|
-
| `scope`
|
|
217
|
-
| `mobile`
|
|
218
|
-
| `breakpoint`
|
|
219
|
-
| `autoClose`
|
|
220
|
-
| `dismissOnScroll` | `false`
|
|
221
|
-
| `restoreFocusTo`
|
|
209
|
+
| Option | Default | Contract |
|
|
210
|
+
|-------------------|-----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
211
|
+
| `trigger` | — | Anchoring element; also the focus-restore target by default |
|
|
212
|
+
| `source` | — | Alternate anchor when there is no trigger |
|
|
213
|
+
| `x`, `y` | — | Position at a fixed viewport point instead of an anchor (context menus) |
|
|
214
|
+
| `placement` | `"bottom-start"` | Preferred placement |
|
|
215
|
+
| `distance` | `4` | Gap between anchor and surface |
|
|
216
|
+
| `flip` | `true` | Flip when the preferred side is out of view |
|
|
217
|
+
| `shift` | `true` | Shift to stay within the boundary |
|
|
218
|
+
| `shiftPadding` | `4` | Minimum space kept from the boundary |
|
|
219
|
+
| `scope` | viewport | Boundary element |
|
|
220
|
+
| `mobile` | `"auto"` | `"auto"`, `"sheet"`, `"none"`, or `"anchored"` sheet behavior |
|
|
221
|
+
| `breakpoint` | `768` | Max viewport width for an automatic sheet |
|
|
222
|
+
| `autoClose` | `"outside"` | `"true"` closes for inside and outside clicks; `"inside"` and `"outside"` limit the side; `"false"` disables automatic click closing. Invalid values use `"true"` |
|
|
223
|
+
| `dismissOnScroll` | `false` | Close when scrolling outside the surface follows a new user input; opening/focus scroll is ignored |
|
|
224
|
+
| `restoreFocusTo` | `trigger` or `source` | Element focused on close |
|
|
222
225
|
|
|
223
226
|
The click policy belongs to the surface rather than to a particular menu
|
|
224
227
|
anatomy. The generic primitive defaults to outside-click dismissal; flyout and
|
|
@@ -239,14 +242,14 @@ The runtime dispatches a small set of public `actual:*` events. All are
|
|
|
239
242
|
listenable on the document; cancelable events veto the associated action when
|
|
240
243
|
`preventDefault()` is called.
|
|
241
244
|
|
|
242
|
-
| Event
|
|
243
|
-
|
|
244
|
-
| `actual:surface-open`
|
|
245
|
-
| `actual:context-menu`
|
|
246
|
-
| `actual:status`
|
|
247
|
-
| `actual:invalid`
|
|
248
|
-
| `actual:dialog-cancel` | dialog, before native cancel close
|
|
249
|
-
| `actual:dismiss`
|
|
245
|
+
| Event | Dispatch | Contract |
|
|
246
|
+
|------------------------|--------------------------------------------|------------------------------------------------------------------------------------------------|
|
|
247
|
+
| `actual:surface-open` | `openSurface()`, before a surface opens | Cancelable. `detail: { surface, options }` |
|
|
248
|
+
| `actual:context-menu` | context-menu, before its menu opens | Cancelable. `detail: { menu, context, origin, trigger }` |
|
|
249
|
+
| `actual:status` | status module, or any code | Show or clear the status bar. `detail: { message, intent, duration }`; omit `message` to clear |
|
|
250
|
+
| `actual:invalid` | validation, after a submit was blocked | `detail: { form, firstInvalid, message }` |
|
|
251
|
+
| `actual:dialog-cancel` | dialog, before native cancel close | Cancelable. `detail: { dialog, sourceEvent }` |
|
|
252
|
+
| `actual:dismiss` | `--dismiss` command, after hiding a target | `detail: { trigger }` |
|
|
250
253
|
|
|
251
254
|
## Extending the runtime
|
|
252
255
|
|
|
@@ -25,14 +25,14 @@ The layered import is the cleanest way to keep both stylesheets during the
|
|
|
25
25
|
migration:
|
|
26
26
|
|
|
27
27
|
```css
|
|
28
|
-
/* Migration setup — Actual rules sit in @layer actual */
|
|
29
28
|
@import "tailwind.css"; /* your compiled Tailwind output */
|
|
30
|
-
@
|
|
29
|
+
@layer actual;
|
|
30
|
+
@import "actual-css/full" layer(actual);
|
|
31
31
|
/* Unlayered project overrides stay on top */
|
|
32
32
|
@import "app.css";
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
The full import places every Actual rule in a single `actual` layer, so
|
|
36
36
|
unlayered Tailwind output and project CSS keep precedence while the migration
|
|
37
37
|
runs. See [Cascade layer strategy](https://github.com/lekoala/actual-css/blob/master/docs/design-notes/cascade-layer.md) for the
|
|
38
38
|
limitations of the approach.
|
|
@@ -128,13 +128,11 @@ Actual:
|
|
|
128
128
|
</div>
|
|
129
129
|
```
|
|
130
130
|
|
|
131
|
-
If
|
|
131
|
+
If these are independent items that should reflow with available space:
|
|
132
132
|
|
|
133
133
|
```html
|
|
134
|
-
<div class="
|
|
135
|
-
|
|
136
|
-
...
|
|
137
|
-
</div>
|
|
134
|
+
<div class="grid" style="--grid-min: 16rem">
|
|
135
|
+
...
|
|
138
136
|
</div>
|
|
139
137
|
```
|
|
140
138
|
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# App Layout
|
|
2
|
+
|
|
3
|
+
> Specialized application recipe with a topbar, independently scrolling content, and one adaptive primary navigation landmark.
|
|
4
|
+
|
|
5
|
+
Use `.app-layout` only when all three direct regions are intentional:
|
|
6
|
+
|
|
7
|
+
- `.topbar` is persistent application chrome;
|
|
8
|
+
- `.app-main` is the page's independent scroll container;
|
|
9
|
+
- `.app-nav` changes from bottom navigation to labelled side navigation.
|
|
10
|
+
|
|
11
|
+
This is not a generic wrapper for a website, dashboard, or anything described
|
|
12
|
+
as an "app." It fixes the shell to the dynamic viewport and hides overflow on
|
|
13
|
+
that shell. A public, marketing, editorial, or normally scrolling page should
|
|
14
|
+
use semantic landmarks, optionally `.app-shell` for full-height document flow,
|
|
15
|
+
and `.navbar` for top-level site navigation.
|
|
16
|
+
|
|
17
|
+
```html demo
|
|
18
|
+
<div class="app-shell app-layout" style="block-size: 30rem">
|
|
19
|
+
<header class="topbar">
|
|
20
|
+
<strong>Tasks</strong>
|
|
21
|
+
</header>
|
|
22
|
+
<main class="app-main padding-context">
|
|
23
|
+
<div class="stack">
|
|
24
|
+
<h2>Today</h2>
|
|
25
|
+
<p>The main region scrolls without displacing the application chrome.</p>
|
|
26
|
+
</div>
|
|
27
|
+
</main>
|
|
28
|
+
<nav class="app-nav" aria-label="Primary">
|
|
29
|
+
<a href="#today" aria-current="page"><span aria-hidden="true">☀</span><span>Today</span></a>
|
|
30
|
+
<a href="#tasks"><span aria-hidden="true">✓</span><span>Tasks</span></a>
|
|
31
|
+
<a href="#settings"><span aria-hidden="true">⚙</span><span>Settings</span></a>
|
|
32
|
+
</nav>
|
|
33
|
+
<div class="fab">
|
|
34
|
+
<button class="btn primary circle icon-only" type="button" aria-label="Add task">+</button>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The direct-child relationship is required, not illustrative: `.app-layout`
|
|
40
|
+
assigns those children to named grid areas and changes `.app-nav` from a bottom
|
|
41
|
+
bar to labelled side navigation. Missing, renamed, or wrapped regions mean a
|
|
42
|
+
different layout contract should be used.
|
|
43
|
+
|
|
44
|
+
A direct-child `.fab` overlays the end of the main grid area. It therefore
|
|
45
|
+
clears both bottom and side navigation without copying the navigation size or
|
|
46
|
+
bottom safe-area inset. When navigation moves aside, the layout applies the
|
|
47
|
+
bottom inset at the viewport edge. Outside this recipe, FAB keeps its
|
|
48
|
+
viewport-fixed placement.
|
|
49
|
+
|
|
50
|
+
The recipe uses the dynamic viewport token and gives scrolling to `.app-main`,
|
|
51
|
+
which avoids fixed-position offsets and keeps mobile keyboard resizing within
|
|
52
|
+
the same layout contract. The topbar preserves its normal spacing below the
|
|
53
|
+
top safe-area inset. The recipe provides no routing or page lifecycle.
|
|
54
|
+
|
|
55
|
+
### Hooks
|
|
56
|
+
|
|
57
|
+
- `--app-nav-side-size` controls the side navigation track.
|
|
@@ -1,16 +1,30 @@
|
|
|
1
1
|
# App Shell
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Full-height, single-column document flow. Despite its historical name, this is
|
|
4
|
+
the general shell for ordinary pages as well as simple applications.
|
|
4
5
|
|
|
5
6
|
Header and footer are document landmarks, not required layout classes.
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
Use semantic elements by default. `.app-shell` already supplies the outer
|
|
8
|
+
column, so do not add a `.stack` solely to arrange the page landmarks.
|
|
8
9
|
|
|
9
10
|
```html demo
|
|
10
11
|
<body class="app-shell">
|
|
11
|
-
<header>
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
<header>
|
|
13
|
+
<div class="center">
|
|
14
|
+
<nav class="navbar" aria-label="Main">
|
|
15
|
+
<a class="navbar-brand" href="/">Actual CSS</a>
|
|
16
|
+
</nav>
|
|
17
|
+
</div>
|
|
18
|
+
</header>
|
|
19
|
+
<main class="grow">
|
|
20
|
+
<div class="center stack">
|
|
21
|
+
<h1>Page title</h1>
|
|
22
|
+
<p>Main content</p>
|
|
23
|
+
</div>
|
|
24
|
+
</main>
|
|
25
|
+
<footer>
|
|
26
|
+
<div class="center">Footer links</div>
|
|
27
|
+
</footer>
|
|
14
28
|
</body>
|
|
15
29
|
```
|
|
16
30
|
|
|
@@ -22,4 +36,11 @@ Use semantic elements by default.
|
|
|
22
36
|
}
|
|
23
37
|
```
|
|
24
38
|
|
|
25
|
-
|
|
39
|
+
Keep `.center` inside each full-width landmark when their backgrounds or
|
|
40
|
+
borders should span the viewport. Sticky header/footer behavior remains an
|
|
41
|
+
application choice.
|
|
42
|
+
|
|
43
|
+
Do not upgrade this shell to `.app-layout` merely because the product is an
|
|
44
|
+
application. Use App Layout only for its complete specialized contract: a
|
|
45
|
+
direct-child `.topbar`, independently scrolling `.app-main`, and direct-child
|
|
46
|
+
`.app-nav` that changes from a bottom bar to a labelled side menu.
|
|
@@ -26,4 +26,15 @@ Tune width and side padding with local variables.
|
|
|
26
26
|
|
|
27
27
|
`.center` intentionally uses `box-sizing: content-box`. The max inline size is
|
|
28
28
|
the content measure, while inline padding is added outside that measure. This is
|
|
29
|
-
deliberate even though the global reset uses `border-box`.
|
|
29
|
+
deliberate even though the global reset uses `border-box`. Its explicit inline
|
|
30
|
+
size subtracts that padding, so `.center` also keeps its available width as a
|
|
31
|
+
flex or grid item instead of collapsing to its min-content width.
|
|
32
|
+
|
|
33
|
+
Do not override it with `inline-size: 100%`: because the padding sits outside
|
|
34
|
+
the content box, that would make its outer size exceed the available width by
|
|
35
|
+
both padding edges.
|
|
36
|
+
|
|
37
|
+
As a child of `.stack`, `.center` sizes to its content measure and centers via
|
|
38
|
+
`margin-inline: auto` instead of stretching to the full row. For full-width page
|
|
39
|
+
regions, keep `.center` regions in normal block flow rather than inside a
|
|
40
|
+
`.stack` wrapper (see [stack](stack.md)).
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Choosing a layout
|
|
2
|
+
|
|
3
|
+
Choose a primitive from the relationship between its children, not from the
|
|
4
|
+
number of children visible in one mockup.
|
|
5
|
+
|
|
6
|
+
## Page and application shells
|
|
7
|
+
|
|
8
|
+
| Situation | Recipe |
|
|
9
|
+
|---|---|
|
|
10
|
+
| Public, marketing, editorial, or normally scrolling page | Semantic landmarks; optionally `.app-shell`, with `.navbar` for site navigation |
|
|
11
|
+
| Persistent topbar + independently scrolling main + bottom-to-side primary navigation | `.app-layout` with its exact direct-child contract |
|
|
12
|
+
|
|
13
|
+
Do not choose `.app-layout` from the word "app" or from the presence of a
|
|
14
|
+
header. Its viewport-sized grid, hidden shell overflow, internal main scroll,
|
|
15
|
+
and adaptive `.app-nav` are one indivisible behavior. If any of those is not
|
|
16
|
+
wanted, compose the ordinary page from semantic landmarks and the primitives
|
|
17
|
+
below.
|
|
18
|
+
|
|
19
|
+
## Content relationships
|
|
20
|
+
|
|
21
|
+
| Situation | Primitive |
|
|
22
|
+
|--------------------------------------------------------------|-------------------|
|
|
23
|
+
| Vertical flow | `.stack` |
|
|
24
|
+
| Inline actions, tags, or navigation that may wrap | `.cluster` |
|
|
25
|
+
| Responsive collection; an incomplete final row is acceptable | `.grid` |
|
|
26
|
+
| Known structural density, at most N columns | `.grid-N` |
|
|
27
|
+
| Peer regions that must switch together | `.switcher` |
|
|
28
|
+
| Main content followed by a secondary region | `.sidebar-layout` |
|
|
29
|
+
| Fixed media followed by flexible content | `.media` |
|
|
30
|
+
| Explicit region placement on a shared 12-column canvas | `.column-layout` |
|
|
31
|
+
|
|
32
|
+
For cards, products, results, and galleries, start with `.grid`. Use a fixed
|
|
33
|
+
`.grid-N` only when N columns remain part of the structure at every width. If
|
|
34
|
+
all peers should move together rather than form a partial row, use `.switcher`.
|
|
35
|
+
|
|
36
|
+
For a main region plus an aside, use `.sidebar-layout`.
|
|
37
|
+
|
|
38
|
+
Use `.column-layout` when the placement of each region is itself part of the
|
|
39
|
+
design — a 10-column article starting on column 2, regions in separate sibling
|
|
40
|
+
sections that must share the same column lines, an editorial composition whose
|
|
41
|
+
starts and spans are deliberately aligned across the page. It is the one layout
|
|
42
|
+
primitive with no automatic responsive behavior: the canvas stays twelve
|
|
43
|
+
columns and the application owns narrow-container recomposition. Choose it
|
|
44
|
+
because placement is the design, not because a mockup happens to contain
|
|
45
|
+
columns.
|
|
46
|
+
|
|
47
|
+
Use `--grid-columns` for exact track templates that do not match a built-in
|
|
48
|
+
layout contract: arbitrary structural counts such as seven calendar days,
|
|
49
|
+
asymmetric fractional tracks, or mixed intrinsic/flexible tracks. Once set, the
|
|
50
|
+
application owns narrow-container behavior.
|
|
51
|
+
|
|
52
|
+
`.container-query` is a low-level opt-in for a component that changes its own
|
|
53
|
+
representation according to allocated space. It does not enable responsive
|
|
54
|
+
behavior for layout primitives and never changes their meaning.
|