actual-css 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/LICENSE +21 -0
- package/README.md +166 -0
- package/dist/actual.css +4929 -0
- package/dist/actual.js +3 -0
- package/dist/actual.js.map +31 -0
- package/dist/actual.min.css +1 -0
- package/docs/README.md +26 -0
- package/docs/components.md +860 -0
- package/docs/design-notes/accessibility-decisions.md +32 -0
- package/docs/design-notes/browser-support.md +93 -0
- package/docs/design-notes/cascade-layer.md +52 -0
- package/docs/design-notes/css-anchor.md +33 -0
- package/docs/design-notes/naming.md +37 -0
- package/docs/design-notes/previous-work.md +5 -0
- package/docs/design-notes/references.md +324 -0
- package/docs/forms.md +1265 -0
- package/docs/javascript.md +426 -0
- package/docs/layout.md +480 -0
- package/docs/mental-model.md +73 -0
- package/docs/patterns.md +415 -0
- package/docs/reserved.md +7 -0
- package/docs/tokens.md +455 -0
- package/docs/typography.md +159 -0
- package/docs/ui.md +937 -0
- package/docs/utilities.md +384 -0
- package/llms.txt +17 -0
- package/package.json +101 -0
- package/src/css/actual.css +17 -0
- package/src/css/actual.full.css +2 -0
- package/src/css/actual.layer.css +3 -0
- package/src/css/base.css +70 -0
- package/src/css/components/accordion.css +97 -0
- package/src/css/components/actions.css +21 -0
- package/src/css/components/alert.css +137 -0
- package/src/css/components/avatar.css +199 -0
- package/src/css/components/badge.css +143 -0
- package/src/css/components/breadcrumb.css +56 -0
- package/src/css/components/busy.css +44 -0
- package/src/css/components/button.css +216 -0
- package/src/css/components/card.css +140 -0
- package/src/css/components/drawer.css +122 -0
- package/src/css/components/flyout.css +243 -0
- package/src/css/components/index.css +41 -0
- package/src/css/components/join.css +106 -0
- package/src/css/components/key.css +25 -0
- package/src/css/components/meter.css +81 -0
- package/src/css/components/modal.css +162 -0
- package/src/css/components/navbar.css +98 -0
- package/src/css/components/overline.css +49 -0
- package/src/css/components/pagination.css +30 -0
- package/src/css/components/progress.css +126 -0
- package/src/css/components/scrollspy.css +27 -0
- package/src/css/components/skeleton.css +67 -0
- package/src/css/components/spinner.css +60 -0
- package/src/css/components/status-bar.css +82 -0
- package/src/css/components/surface.css +48 -0
- package/src/css/components/tab.css +128 -0
- package/src/css/components/table.css +64 -0
- package/src/css/components/tooltip.css +107 -0
- package/src/css/dialog-fallback.css +56 -0
- package/src/css/focus.css +13 -0
- package/src/css/forms/choice-card.css +158 -0
- package/src/css/forms/choice.css +196 -0
- package/src/css/forms/control.css +106 -0
- package/src/css/forms/custom-select.css +93 -0
- package/src/css/forms/form-actions.css +43 -0
- package/src/css/forms/form.css +57 -0
- package/src/css/forms/index.css +15 -0
- package/src/css/forms/input-icon.css +36 -0
- package/src/css/forms/native.css +68 -0
- package/src/css/forms/select.css +36 -0
- package/src/css/forms/switch.css +127 -0
- package/src/css/forms/validation.css +63 -0
- package/src/css/grid.css +95 -0
- package/src/css/intents.css +33 -0
- package/src/css/layout.css +80 -0
- package/src/css/optional/index.css +5 -0
- package/src/css/optional/layout-extra.css +55 -0
- package/src/css/optional/scroll-snap.css +51 -0
- package/src/css/optional/scroller.css +51 -0
- package/src/css/optional/typography-fluid.css +48 -0
- package/src/css/optional/utilities-extra.css +289 -0
- package/src/css/print.css +47 -0
- package/src/css/prose.css +187 -0
- package/src/css/reset.css +56 -0
- package/src/css/theme.css +186 -0
- package/src/css/themes/corporate.css +60 -0
- package/src/css/themes/cyberpunk.css +60 -0
- package/src/css/themes/dark.css +32 -0
- package/src/css/themes/dim.css +33 -0
- package/src/css/themes/edge.css +143 -0
- package/src/css/themes/forest.css +65 -0
- package/src/css/themes/gradient.css +97 -0
- package/src/css/themes/index.css +43 -0
- package/src/css/themes/lavender.css +66 -0
- package/src/css/themes/mono.css +60 -0
- package/src/css/themes/neon.css +66 -0
- package/src/css/themes/ocean.css +60 -0
- package/src/css/themes/petrol.css +64 -0
- package/src/css/themes/spruce.css +64 -0
- package/src/css/themes/square.css +68 -0
- package/src/css/themes/sunset.css +66 -0
- package/src/css/tokens.css +122 -0
- package/src/css/utilities.css +162 -0
- package/src/css/variants.css +118 -0
- package/src/js/command.js +165 -0
- package/src/js/context-menu.js +291 -0
- package/src/js/dialog-fallback.js +163 -0
- package/src/js/dialog.js +503 -0
- package/src/js/enhance.js +208 -0
- package/src/js/events.js +22 -0
- package/src/js/filter.js +122 -0
- package/src/js/floating.js +462 -0
- package/src/js/flyout.js +187 -0
- package/src/js/focus.js +35 -0
- package/src/js/index.js +26 -0
- package/src/js/input.js +47 -0
- package/src/js/keys.js +30 -0
- package/src/js/mask.js +184 -0
- package/src/js/menu.js +88 -0
- package/src/js/password.js +98 -0
- package/src/js/scrollspy.js +121 -0
- package/src/js/selectors.js +59 -0
- package/src/js/status.js +158 -0
- package/src/js/surface.js +358 -0
- package/src/js/tab.js +173 -0
- package/src/js/tooltip.js +374 -0
- package/src/js/validation.js +419 -0
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
# Utilities
|
|
2
|
+
|
|
3
|
+
Utilities are a small escape hatch for common single-purpose needs. They should support composition, not become the primary way to build UI.
|
|
4
|
+
|
|
5
|
+
- Prefer semantic HTML, components, and layout primitives first.
|
|
6
|
+
- Add utilities only when the rule is broadly useful and unlikely to become a component.
|
|
7
|
+
- Keep utility names stable, boring, and few.
|
|
8
|
+
- Utilities should use logical properties where relevant.
|
|
9
|
+
|
|
10
|
+
## Accessibility
|
|
11
|
+
|
|
12
|
+
### Screen Reader Only
|
|
13
|
+
|
|
14
|
+
Use `.sr-only` for text that should be available to assistive technology but visually hidden.
|
|
15
|
+
|
|
16
|
+
```html
|
|
17
|
+
<button class="btn ghost" type="button">
|
|
18
|
+
<i class="ti ti-menu-2" aria-hidden="true"></i>
|
|
19
|
+
<span class="sr-only">Open navigation</span>
|
|
20
|
+
</button>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```css
|
|
24
|
+
.sr-only {
|
|
25
|
+
position: absolute;
|
|
26
|
+
inline-size: 1px;
|
|
27
|
+
block-size: 1px;
|
|
28
|
+
padding: 0;
|
|
29
|
+
margin: -1px;
|
|
30
|
+
overflow: hidden;
|
|
31
|
+
clip: rect(0, 0, 0, 0);
|
|
32
|
+
white-space: nowrap;
|
|
33
|
+
border: 0;
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Overflow
|
|
38
|
+
|
|
39
|
+
> Explicit overflow handling for content that may exceed its container.
|
|
40
|
+
|
|
41
|
+
Use `.overflow-auto` when content may overflow its container, especially tables and code-like regions.
|
|
42
|
+
|
|
43
|
+
```html
|
|
44
|
+
<div class="overflow-auto">
|
|
45
|
+
<table class="table">
|
|
46
|
+
<caption>Team members</caption>
|
|
47
|
+
<thead>
|
|
48
|
+
<tr>
|
|
49
|
+
<th>Name</th>
|
|
50
|
+
<th>Role</th>
|
|
51
|
+
</tr>
|
|
52
|
+
</thead>
|
|
53
|
+
<tbody>
|
|
54
|
+
<tr>
|
|
55
|
+
<td>Alice Johnson</td>
|
|
56
|
+
<td>Admin</td>
|
|
57
|
+
</tr>
|
|
58
|
+
</tbody>
|
|
59
|
+
</table>
|
|
60
|
+
</div>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
```css
|
|
64
|
+
.overflow-auto {
|
|
65
|
+
overflow: auto;
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Sizing And Wrapping
|
|
70
|
+
|
|
71
|
+
> Small layout corrections for controls, labels, and compact rails.
|
|
72
|
+
|
|
73
|
+
Use `.fit` when a control or element should shrink to its content instead of filling the available inline space.
|
|
74
|
+
|
|
75
|
+
```html
|
|
76
|
+
<select class="select fit" aria-label="Theme">
|
|
77
|
+
<option>System</option>
|
|
78
|
+
<option>Light</option>
|
|
79
|
+
<option>Dark</option>
|
|
80
|
+
</select>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Use `.nowrap` on a flex layout such as `.cluster` when the group must stay on one line.
|
|
84
|
+
|
|
85
|
+
```html
|
|
86
|
+
<div class="cluster nowrap sm">
|
|
87
|
+
<select class="select sm fit" aria-label="Segment">
|
|
88
|
+
<option>All segments</option>
|
|
89
|
+
</select>
|
|
90
|
+
<button class="btn sm outline" type="button">Filter</button>
|
|
91
|
+
</div>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Use `.truncate` on the flexible item that should ellipsize inside a constrained row.
|
|
95
|
+
|
|
96
|
+
```html
|
|
97
|
+
<header class="cluster nowrap">
|
|
98
|
+
<strong class="truncate">A long account name that should not push actions away</strong>
|
|
99
|
+
<button class="btn sm ghost" type="button">Open</button>
|
|
100
|
+
</header>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
```css
|
|
104
|
+
.fit {
|
|
105
|
+
inline-size: fit-content;
|
|
106
|
+
max-inline-size: 100%;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.nowrap {
|
|
110
|
+
flex-wrap: nowrap;
|
|
111
|
+
white-space: nowrap;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.truncate {
|
|
115
|
+
min-inline-size: 0;
|
|
116
|
+
overflow: hidden;
|
|
117
|
+
text-overflow: ellipsis;
|
|
118
|
+
white-space: nowrap;
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Scroller
|
|
123
|
+
|
|
124
|
+
Use `.scroller` to apply optional framework scrollbar treatment to a scroll container. It styles the scrollbar only; pair it with `.overflow-auto` or a component that already creates overflow.
|
|
125
|
+
|
|
126
|
+
`scroller` is not imported by `actual.css`. Import it explicitly when a project wants Actual CSS scrollbar chrome instead of the native OS default:
|
|
127
|
+
|
|
128
|
+
```css
|
|
129
|
+
@import "actual-css/css/optional/scroller";
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
```html
|
|
133
|
+
<div class="overflow-auto scroller" style="max-block-size: 12rem">
|
|
134
|
+
<div class="stack">
|
|
135
|
+
<p>Scrollable content keeps the native scrollbar but makes it quieter.</p>
|
|
136
|
+
<p>Long content can keep flowing without forcing every component to invent its own scrollbar rules.</p>
|
|
137
|
+
<p>The utility exposes local custom properties for one-off tuning.</p>
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
```css
|
|
143
|
+
.scroller {
|
|
144
|
+
--scroller-size: 0.625rem;
|
|
145
|
+
--scroller-padding: 0.125rem;
|
|
146
|
+
--scroller-track: transparent;
|
|
147
|
+
--scroller-thumb: var(--border);
|
|
148
|
+
--scroller-thumb-hover: var(--text-muted);
|
|
149
|
+
|
|
150
|
+
scrollbar-color: var(--scroller-thumb) var(--scroller-track);
|
|
151
|
+
scrollbar-width: thin;
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Customize locally when a scroll surface needs more contrast:
|
|
156
|
+
|
|
157
|
+
```html
|
|
158
|
+
<div class="overflow-auto scroller"
|
|
159
|
+
style="--scroller-thumb: var(--text-muted); --scroller-thumb-hover: var(--text)">
|
|
160
|
+
...
|
|
161
|
+
</div>
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
For rounded scroll containers, keep the thumb visually away from the edge by tuning `--scroller-padding` rather than adding extra wrappers or masking pseudo-elements.
|
|
165
|
+
|
|
166
|
+
## Metadata Separator
|
|
167
|
+
|
|
168
|
+
> A small inline dot for separating facts in a metadata row.
|
|
169
|
+
|
|
170
|
+
Use `.dot` between short facts in a byline, timestamp row, or breadcrumb-like list of details — anywhere a plain `·` character would otherwise be typed as text (which screen readers announce awkwardly).
|
|
171
|
+
|
|
172
|
+
```html
|
|
173
|
+
<p class="cluster" style="--cluster-justify: flex-start;">
|
|
174
|
+
<span>Ada Meridian</span>
|
|
175
|
+
<span class="dot" aria-hidden="true"></span>
|
|
176
|
+
<time datetime="2026-06-12">June 12, 2026</time>
|
|
177
|
+
<span class="dot" aria-hidden="true"></span>
|
|
178
|
+
<span>8 min read</span>
|
|
179
|
+
</p>
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
```css
|
|
183
|
+
.dot {
|
|
184
|
+
flex: none;
|
|
185
|
+
inline-size: 0.25rem;
|
|
186
|
+
block-size: 0.25rem;
|
|
187
|
+
border-radius: var(--radius-full);
|
|
188
|
+
background: var(--text-subtle);
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Always mark it `aria-hidden="true"` — it is a visual separator, not content.
|
|
193
|
+
|
|
194
|
+
## Flex Helpers
|
|
195
|
+
|
|
196
|
+
> Small flex helpers for grow behavior and other one-line needs.
|
|
197
|
+
|
|
198
|
+
### Grow
|
|
199
|
+
|
|
200
|
+
Use `.grow` when one item in a flex layout should take available space without overflowing.
|
|
201
|
+
|
|
202
|
+
```html
|
|
203
|
+
<header class="cluster">
|
|
204
|
+
<a href="/" class="brand">Actual CSS</a>
|
|
205
|
+
<nav class="grow" aria-label="Main navigation">
|
|
206
|
+
<a href="/docs">Docs</a>
|
|
207
|
+
<a href="/components">Components</a>
|
|
208
|
+
</nav>
|
|
209
|
+
<button class="btn ghost" type="button">Menu</button>
|
|
210
|
+
</header>
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
```css
|
|
214
|
+
.grow {
|
|
215
|
+
flex: 1 1 auto;
|
|
216
|
+
min-inline-size: 0;
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Item Alignment
|
|
221
|
+
|
|
222
|
+
Use `.items-start` on flex or grid layouts when children should keep their natural height and align to the block-start edge. This is especially useful for form fields in a grid, where the default grid stretch would make short fields as tall as taller neighbors.
|
|
223
|
+
|
|
224
|
+
```html
|
|
225
|
+
<div class="grid items-start">
|
|
226
|
+
<label class="field">
|
|
227
|
+
<span class="field-label">Name</span>
|
|
228
|
+
<input type="text" />
|
|
229
|
+
</label>
|
|
230
|
+
<label class="field">
|
|
231
|
+
<span class="field-label">Notes</span>
|
|
232
|
+
<textarea></textarea>
|
|
233
|
+
</label>
|
|
234
|
+
</div>
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Use `.items-center` when a flex or grid layout should center its children on the cross axis. Use `.items-end` when children should align to the block-end edge.
|
|
238
|
+
|
|
239
|
+
## Spacing Helpers
|
|
240
|
+
|
|
241
|
+
> Semantic step helpers for gap, padding, and margin — the most common inline-style escape hatches.
|
|
242
|
+
|
|
243
|
+
Spacing helpers use a restrained semantic scale:
|
|
244
|
+
|
|
245
|
+
- `-sm` — small step, `--space-2` (0.5rem)
|
|
246
|
+
- Default — standard step, `--space-4` (1rem)
|
|
247
|
+
- `-lg` — large step, `--space-5` (1.5rem)
|
|
248
|
+
|
|
249
|
+
All map to logical properties (`padding-block`, `margin-block-end`, etc.) for writing-direction safety.
|
|
250
|
+
|
|
251
|
+
### Gap
|
|
252
|
+
|
|
253
|
+
Override the default gap from layout primitives (`.stack`, `.cluster`, `.grid`):
|
|
254
|
+
|
|
255
|
+
```html
|
|
256
|
+
<ul class="cluster">
|
|
257
|
+
<li><a href="/about" class="btn ghost">About</a></li>
|
|
258
|
+
<li><a href="/contact" class="btn ghost">Contact</a></li>
|
|
259
|
+
</ul>
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
- `.gap-none` → `gap: 0`
|
|
263
|
+
|
|
264
|
+
### Padding
|
|
265
|
+
|
|
266
|
+
Block (vertical) and inline (horizontal) padding. Values respond to the `.sm` / `.lg` modifiers.
|
|
267
|
+
|
|
268
|
+
```html
|
|
269
|
+
<section role="tabpanel" class="py">
|
|
270
|
+
Panel content with breathing room above and below.
|
|
271
|
+
</section>
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
- `.py` → `padding-block: var(--variant-space)`
|
|
275
|
+
- `.px` → `padding-inline: var(--variant-space)`
|
|
276
|
+
|
|
277
|
+
### Margin
|
|
278
|
+
|
|
279
|
+
Block-start and block-end margin for giving elements room:
|
|
280
|
+
|
|
281
|
+
```html
|
|
282
|
+
<h2 class="mbs">A section heading with space above</h2>
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
- `.mbs` → `margin-block-start: var(--variant-space)`
|
|
286
|
+
- `.mbe` → `margin-block-end: var(--variant-space)`
|
|
287
|
+
|
|
288
|
+
No `mbs-none` / `mbe-none` — use `margin: 0` via `.list-reset` for lists, or a layout primitive that already resets margins (`.stack > *`).
|
|
289
|
+
|
|
290
|
+
## Text Helpers
|
|
291
|
+
|
|
292
|
+
> Lightweight helpers for muted or secondary text without a full color scale.
|
|
293
|
+
|
|
294
|
+
### Muted
|
|
295
|
+
|
|
296
|
+
Use `.muted` for secondary text when no semantic element already carries the meaning.
|
|
297
|
+
|
|
298
|
+
```html
|
|
299
|
+
<p class="muted">Last updated June 12, 2026.</p>
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
```css
|
|
303
|
+
.muted {
|
|
304
|
+
color: var(--text-muted);
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
Do not create a full text color utility scale. Intent colors belong to components and state, not arbitrary text decoration.
|
|
309
|
+
|
|
310
|
+
### Text Alignment
|
|
311
|
+
|
|
312
|
+
Use `.text-start`, `.text-center`, or `.text-end` when a component or layout primitive does not already set alignment. These use logical properties so they follow the writing direction.
|
|
313
|
+
|
|
314
|
+
### Text Wrap
|
|
315
|
+
|
|
316
|
+
`.text-balance` and `.text-pretty` opt elements outside `.prose` into balanced or pretty text wrapping. They are safe progressive enhancements: browsers that do not support a `text-wrap` value ignore that declaration and keep normal wrapping.
|
|
317
|
+
|
|
318
|
+
### Lead
|
|
319
|
+
|
|
320
|
+
`.lead` is a slightly larger, more relaxed reading-introduction paragraph (`1.125em`, `--line-height-relaxed`). Use it for introductory text in editorial surfaces. For fluid headline sizing, use `src/css/optional/typography-fluid.css`.
|
|
321
|
+
|
|
322
|
+
## Shape Helpers
|
|
323
|
+
|
|
324
|
+
> Rare shape utilities for cases that must be perfectly round or square.
|
|
325
|
+
|
|
326
|
+
Shape utilities should be rare because shape is mostly theme-level.
|
|
327
|
+
|
|
328
|
+
### Circle
|
|
329
|
+
|
|
330
|
+
Use `.circle` only when an element must be perfectly round.
|
|
331
|
+
|
|
332
|
+
```html
|
|
333
|
+
<img class="circle" src="https://i.pravatar.cc/48?img=5" alt="Jane Doe" width="48" height="48" />
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
```css
|
|
337
|
+
.circle {
|
|
338
|
+
border-radius: var(--radius-full);
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
Do not add `.rounded-sm`, `.rounded-lg`, `.square`, or `.pill` unless repeated real use proves they are needed.
|
|
343
|
+
|
|
344
|
+
## Content
|
|
345
|
+
|
|
346
|
+
### Measure
|
|
347
|
+
|
|
348
|
+
`.measure` caps a block at a readable width using `--prose-measure`. It does not center — combine with `.center` for the common centered reading column, or with `margin-inline: auto` for a one-off centered block.
|
|
349
|
+
|
|
350
|
+
Use it for any content that needs a comfortable measure: prose articles, TOC lists, form fields, callouts. Avoid using it for full-bleed surfaces.
|
|
351
|
+
|
|
352
|
+
## List Helpers
|
|
353
|
+
|
|
354
|
+
### List Reset
|
|
355
|
+
|
|
356
|
+
`.list-reset` removes the native list chrome (margin, padding, markers) from any list. It is the generic version of `.nav-list` — use `.nav-list` when the list is a navigation list for semantic intent, and `.list-reset` for everything else (tag clouds, footer columns, related items, comment threads, embedded controls).
|
|
357
|
+
|
|
358
|
+
## Editorial Labels
|
|
359
|
+
|
|
360
|
+
### Overline
|
|
361
|
+
|
|
362
|
+
`.overline` is a small editorial label: muted color, smaller size, uppercase, slight letter-spacing. It does not impose a shape by itself. Add `.pill` for a bordered rounded chip, and combine with an intent class (`.primary`, `.success`, etc.) to tint the chip's text, border, and background.
|
|
363
|
+
|
|
364
|
+
The overline exists because categories, kicker labels, and section markers recur across editorial surfaces, and `.badge` is the wrong shape for them. `.badge` is a status indicator; `.overline` is metadata.
|
|
365
|
+
|
|
366
|
+
## Link Variants
|
|
367
|
+
|
|
368
|
+
### Plain
|
|
369
|
+
|
|
370
|
+
`.link-plain` removes the link's underline and inherits the surrounding color. Use for chrome that is conceptually a link (a card title, a table row action, a tag, a breadcrumb segment) but should not look like prose.
|
|
371
|
+
|
|
372
|
+
### Muted
|
|
373
|
+
|
|
374
|
+
`.link-muted` is a `.link-plain` that starts in the muted text color and shifts to the full text color on hover. Use for navigation lists, table of contents, and other secondary navigation surfaces.
|
|
375
|
+
|
|
376
|
+
## Non-Goals
|
|
377
|
+
|
|
378
|
+
> Utilities deliberately excluded to keep the surface small and intentional.
|
|
379
|
+
|
|
380
|
+
- No display scale such as `.block`, `.flex`, `.grid` — use layout primitives.
|
|
381
|
+
- No color scales such as `.text-primary` or `.bg-success` — intent colors belong to components and state.
|
|
382
|
+
- No breakpoint utility variants — use container queries or layout primitives.
|
|
383
|
+
- No utility variants for hover, focus, dark mode, or arbitrary selectors — use component states.
|
|
384
|
+
- No full spacing scale with every step and direction — the 17 spacing helpers above cover the most common escape hatches.
|
package/llms.txt
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Actual CSS
|
|
2
|
+
|
|
3
|
+
> Plain CSS component framework for new projects: semantic classes, shared variants, small tokens, theme hooks, and progressive enhancement.
|
|
4
|
+
|
|
5
|
+
Actual CSS uses a small public grammar: `.component [intent] [variant] [size] [modifier]`. It claims unprefixed class names by design. Existing projects with collisions should use cascade layers, import order, or an application-side prefix transform.
|
|
6
|
+
|
|
7
|
+
## Documentation
|
|
8
|
+
|
|
9
|
+
- [Docs index](docs/README.md): the maintained map of user docs and design notes.
|
|
10
|
+
|
|
11
|
+
## Package Entrypoints
|
|
12
|
+
|
|
13
|
+
`package.json#exports` is the canonical package surface. Use `actual-css` for the
|
|
14
|
+
full CSS framework and `actual-css/js` for the complete runtime. The composition
|
|
15
|
+
guides in [README](README.md) and [JavaScript](docs/javascript.md) show supported
|
|
16
|
+
CSS modules and individual enhancer imports without duplicating the full export
|
|
17
|
+
list here.
|
package/package.json
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "actual-css",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Plain CSS component framework with semantic classes, universal variants, small tokens, theme hooks, and progressive enhancements.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"packageManager": "bun@1.3.14",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"author": "Thomas <thomas@lekoala.be>",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://onedev.kalyptus.ovh/actual-css.git"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://onedev.kalyptus.ovh/actual-css",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://onedev.kalyptus.ovh/actual-css/issues"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"css",
|
|
19
|
+
"css-framework",
|
|
20
|
+
"component-library",
|
|
21
|
+
"semantic",
|
|
22
|
+
"accessibility",
|
|
23
|
+
"dark-mode",
|
|
24
|
+
"themable",
|
|
25
|
+
"no-build",
|
|
26
|
+
"progressive-enhancement"
|
|
27
|
+
],
|
|
28
|
+
"exports": {
|
|
29
|
+
".": "./dist/actual.min.css",
|
|
30
|
+
"./css": "./src/css/actual.css",
|
|
31
|
+
"./css/layer": "./src/css/actual.layer.css",
|
|
32
|
+
"./css/components": "./src/css/components/index.css",
|
|
33
|
+
"./css/forms": "./src/css/forms/index.css",
|
|
34
|
+
"./css/themes": null,
|
|
35
|
+
"./css/themes/*": null,
|
|
36
|
+
"./css/*": "./src/css/*.css",
|
|
37
|
+
"./js": "./src/js/index.js",
|
|
38
|
+
"./js/command": "./src/js/command.js",
|
|
39
|
+
"./js/context-menu": "./src/js/context-menu.js",
|
|
40
|
+
"./js/dialog": "./src/js/dialog.js",
|
|
41
|
+
"./js/dialog-fallback": "./src/js/dialog-fallback.js",
|
|
42
|
+
"./js/enhance": "./src/js/enhance.js",
|
|
43
|
+
"./js/filter": "./src/js/filter.js",
|
|
44
|
+
"./js/floating": "./src/js/floating.js",
|
|
45
|
+
"./js/flyout": "./src/js/flyout.js",
|
|
46
|
+
"./js/input": "./src/js/input.js",
|
|
47
|
+
"./js/mask": "./src/js/mask.js",
|
|
48
|
+
"./js/password": "./src/js/password.js",
|
|
49
|
+
"./js/scrollspy": "./src/js/scrollspy.js",
|
|
50
|
+
"./js/selectors": "./src/js/selectors.js",
|
|
51
|
+
"./js/tab": "./src/js/tab.js",
|
|
52
|
+
"./js/tooltip": "./src/js/tooltip.js",
|
|
53
|
+
"./js/validation": "./src/js/validation.js",
|
|
54
|
+
"./js/status": "./src/js/status.js",
|
|
55
|
+
"./package.json": "./package.json"
|
|
56
|
+
},
|
|
57
|
+
"main": "./dist/actual.js",
|
|
58
|
+
"style": "./dist/actual.min.css",
|
|
59
|
+
"unpkg": "./dist/actual.min.css",
|
|
60
|
+
"jsdelivr": "./dist/actual.min.css",
|
|
61
|
+
"sideEffects": true,
|
|
62
|
+
"files": [
|
|
63
|
+
"dist",
|
|
64
|
+
"!dist/actual-themes.min.css",
|
|
65
|
+
"!dist/actual-themes.min.css.map",
|
|
66
|
+
"src/css",
|
|
67
|
+
"!src/css/themes",
|
|
68
|
+
"src/js",
|
|
69
|
+
"docs",
|
|
70
|
+
"CHANGELOG.md",
|
|
71
|
+
"llms.txt",
|
|
72
|
+
"LICENSE",
|
|
73
|
+
"README.md"
|
|
74
|
+
],
|
|
75
|
+
"engines": {
|
|
76
|
+
"bun": ">=1.0.0"
|
|
77
|
+
},
|
|
78
|
+
"scripts": {
|
|
79
|
+
"lint": "biome check",
|
|
80
|
+
"lint:fix": "biome check --write",
|
|
81
|
+
"build:demo": "bun scripts/build-demo.js",
|
|
82
|
+
"watch:demo": "bun scripts/build-demo.js --watch",
|
|
83
|
+
"build:dist": "bun scripts/build-dist.js",
|
|
84
|
+
"build:js": "bun scripts/build-js.js",
|
|
85
|
+
"build:size": "bun scripts/build-size.js",
|
|
86
|
+
"check:reserved": "bun scripts/check-reserved.js",
|
|
87
|
+
"check:links": "bun scripts/check-doc-links.js",
|
|
88
|
+
"check:templates": "bun scripts/check-templates.js",
|
|
89
|
+
"shot:forced": "bun scripts/forced-colors-shot.js",
|
|
90
|
+
"shot:page": "bun scripts/page-shot.js",
|
|
91
|
+
"check:sync": "bun scripts/check-sync.js",
|
|
92
|
+
"test": "bun test",
|
|
93
|
+
"build:all": "bun run build:demo && bun run build:dist && bun run check:reserved && bun run check:sync && bun run check:links && bun run check:templates && bun run test && bun run build:js && bun run build:size",
|
|
94
|
+
"prepublishOnly": "bun run build:all"
|
|
95
|
+
},
|
|
96
|
+
"devDependencies": {
|
|
97
|
+
"@biomejs/biome": "^2.4.0",
|
|
98
|
+
"happy-dom": "^20.10.6",
|
|
99
|
+
"prismjs": "^1.30.0"
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
@import "./reset.css";
|
|
2
|
+
@import "./dialog-fallback.css";
|
|
3
|
+
@import "./tokens.css";
|
|
4
|
+
@import "./theme.css";
|
|
5
|
+
@import "./base.css";
|
|
6
|
+
@import "./intents.css";
|
|
7
|
+
@import "./layout.css";
|
|
8
|
+
@import "./grid.css";
|
|
9
|
+
@import "./variants.css";
|
|
10
|
+
@import "./prose.css";
|
|
11
|
+
@import "./components/index.css";
|
|
12
|
+
@import "./forms/index.css";
|
|
13
|
+
@import "./utilities.css";
|
|
14
|
+
/* Joined controls are a component, but must load after the controls it groups. */
|
|
15
|
+
@import "./components/join.css";
|
|
16
|
+
@import "./focus.css";
|
|
17
|
+
@import "./print.css";
|
package/src/css/base.css
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Base element styles for native HTML semantics.
|
|
3
|
+
*
|
|
4
|
+
* Sits between reset (browser defaults) and prose (rich content scope).
|
|
5
|
+
* These styles apply everywhere — cards, dialogs, heroes — not only in prose.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
body {
|
|
9
|
+
background: var(--surface);
|
|
10
|
+
color: var(--text);
|
|
11
|
+
font-family: var(--font-sans);
|
|
12
|
+
line-height: var(--line-height);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
a {
|
|
16
|
+
color: inherit;
|
|
17
|
+
text-underline-offset: 0.18em;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
a:focus-visible {
|
|
21
|
+
box-shadow: var(--focus-ring-shadow);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@media (hover: hover) {
|
|
25
|
+
a:hover {
|
|
26
|
+
text-decoration-thickness: 0.12em;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* Global heading chrome: color (--heading or inherit), a tight line-height,
|
|
31
|
+
and progressive text-wrap. No font-size or font-weight is set globally —
|
|
32
|
+
components and .prose own the per-context scale. */
|
|
33
|
+
:where(h1, h2, h3, h4, h5, h6) {
|
|
34
|
+
color: var(--heading, inherit);
|
|
35
|
+
line-height: var(--line-height-tight);
|
|
36
|
+
text-wrap: balance;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/* Compact heading groups. Structural only: display, gap, internal margin reset.
|
|
40
|
+
No font-size, color, or weight is applied here. */
|
|
41
|
+
hgroup {
|
|
42
|
+
display: grid;
|
|
43
|
+
gap: var(--hgroup-gap);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
hgroup > * {
|
|
47
|
+
margin-block: 0;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
hr {
|
|
51
|
+
border: 0;
|
|
52
|
+
border-block-start: var(--border-width) solid var(--border);
|
|
53
|
+
margin-block: var(--space-6);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
code,
|
|
57
|
+
kbd,
|
|
58
|
+
samp,
|
|
59
|
+
pre {
|
|
60
|
+
font-family: var(--font-mono);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
small {
|
|
64
|
+
font-size: 0.875em;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
::selection {
|
|
68
|
+
background: var(--selection-bg, var(--primary));
|
|
69
|
+
color: var(--selection-fg, var(--primary-fg));
|
|
70
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Accordion disclosures built on native details and summary.
|
|
3
|
+
*
|
|
4
|
+
* Keeps the clickable summary affordance aligned and usable without JavaScript
|
|
5
|
+
* or demo styles. Decorative palettes and custom markers belong outside the
|
|
6
|
+
* base component.
|
|
7
|
+
*/
|
|
8
|
+
.accordion {
|
|
9
|
+
--accordion-radius: var(--radius);
|
|
10
|
+
|
|
11
|
+
border: var(--border-width) solid var(--border);
|
|
12
|
+
border-radius: var(--accordion-radius);
|
|
13
|
+
background: var(--surface-raised);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.accordion > details + details {
|
|
17
|
+
border-block-start: var(--border-width) solid var(--border);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.accordion summary {
|
|
21
|
+
display: flex;
|
|
22
|
+
align-items: center;
|
|
23
|
+
gap: var(--space-3);
|
|
24
|
+
cursor: pointer;
|
|
25
|
+
list-style: none;
|
|
26
|
+
padding: var(--space-4);
|
|
27
|
+
color: var(--text);
|
|
28
|
+
font-weight: var(--font-weight-bold);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.accordion summary::-webkit-details-marker {
|
|
32
|
+
display: none;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.accordion summary::after {
|
|
36
|
+
content: "";
|
|
37
|
+
flex: 0 0 auto;
|
|
38
|
+
margin-inline-start: auto;
|
|
39
|
+
inline-size: 1rem;
|
|
40
|
+
block-size: 1rem;
|
|
41
|
+
background-color: var(--text-muted);
|
|
42
|
+
-webkit-mask-image: var(--icon-chevron-mask);
|
|
43
|
+
mask-image: var(--icon-chevron-mask);
|
|
44
|
+
-webkit-mask-repeat: no-repeat;
|
|
45
|
+
mask-repeat: no-repeat;
|
|
46
|
+
-webkit-mask-size: contain;
|
|
47
|
+
mask-size: contain;
|
|
48
|
+
-webkit-mask-position: center;
|
|
49
|
+
mask-position: center;
|
|
50
|
+
transition: transform var(--duration);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.accordion details[open] summary::after {
|
|
54
|
+
transform: rotate(180deg);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.accordion details > summary + * {
|
|
58
|
+
padding-block: 0 var(--space-4);
|
|
59
|
+
padding-inline: var(--space-4);
|
|
60
|
+
color: var(--text-muted);
|
|
61
|
+
margin-block: 0;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.accordion details[open] > summary + * {
|
|
65
|
+
padding-block-start: var(--space-1);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.accordion details > summary + * > :first-child {
|
|
69
|
+
margin-block-start: 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.accordion details > summary + ul,
|
|
73
|
+
.accordion details > summary + ol {
|
|
74
|
+
margin: 0;
|
|
75
|
+
padding-inline-start: 2rem;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@media (forced-colors: active) {
|
|
79
|
+
.accordion {
|
|
80
|
+
border-color: ButtonText;
|
|
81
|
+
background: Canvas;
|
|
82
|
+
color: CanvasText;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.accordion > details + details {
|
|
86
|
+
border-block-start-color: ButtonText;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.accordion summary {
|
|
90
|
+
color: CanvasText;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.accordion summary::after {
|
|
94
|
+
background-color: ButtonText;
|
|
95
|
+
forced-color-adjust: none;
|
|
96
|
+
}
|
|
97
|
+
}
|