@oleksandr-94/aura-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/LICENSE +21 -0
- package/README.md +593 -0
- package/dist/aura-flat.css +1611 -0
- package/dist/aura-flat.min.css +1 -0
- package/dist/aura-neu.css +1622 -0
- package/dist/aura-neu.min.css +1 -0
- package/dist/aura.css +1634 -0
- package/dist/aura.min.css +1 -0
- package/dist/interactions.d.ts +57 -0
- package/dist/interactions.global.min.js +1 -0
- package/dist/interactions.min.mjs +1 -0
- package/dist/interactions.mjs +208 -0
- package/package.json +72 -0
- package/src/_config.scss +72 -0
- package/src/_functions.scss +23 -0
- package/src/_layers.scss +4 -0
- package/src/_surface.scss +49 -0
- package/src/_tokens.scss +65 -0
- package/src/base/_a11y.scss +31 -0
- package/src/base/_reset.scss +7 -0
- package/src/components/_accordion.scss +62 -0
- package/src/components/_alert.scss +43 -0
- package/src/components/_avatar.scss +50 -0
- package/src/components/_badge.scss +61 -0
- package/src/components/_button.scss +79 -0
- package/src/components/_card.scss +58 -0
- package/src/components/_checkbox.scss +51 -0
- package/src/components/_dropdown.scss +73 -0
- package/src/components/_file.scss +42 -0
- package/src/components/_group.scss +51 -0
- package/src/components/_input.scss +85 -0
- package/src/components/_modal.scss +43 -0
- package/src/components/_pagination.scss +87 -0
- package/src/components/_progress.scss +44 -0
- package/src/components/_radio.scss +42 -0
- package/src/components/_range.scss +27 -0
- package/src/components/_rating.scss +43 -0
- package/src/components/_segmented.scss +60 -0
- package/src/components/_switch.scss +79 -0
- package/src/components/_table.scss +38 -0
- package/src/components/_tabs.scss +150 -0
- package/src/components/_toast.scss +59 -0
- package/src/components/_tooltip.scss +60 -0
- package/src/index.scss +32 -0
- package/src/js/global.js +7 -0
- package/src/js/interactions.auto.js +5 -0
- package/src/js/interactions.js +192 -0
- package/src/skins/_flat.scss +29 -0
- package/src/skins/_glass.scss +40 -0
- package/src/skins/_neu.scss +49 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 aura-css authors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,593 @@
|
|
|
1
|
+
# Aura
|
|
2
|
+
|
|
3
|
+
A framework-agnostic, themeable, skinnable CSS component library authored in SCSS.
|
|
4
|
+
Works in any project — plain HTML, React/Vue/Svelte, or alongside Tailwind — via a
|
|
5
|
+
single stylesheet. Theming and surface style ("skin") are decoupled from markup, so the
|
|
6
|
+
same components can be glass in one app and flat in another, on different palettes.
|
|
7
|
+
|
|
8
|
+
> **Status:** early foundation. Complete theming/skin/token system + **2 components**
|
|
9
|
+
> (`button`, `card`). More components are being added on top of this base.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Quick start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# from aura/
|
|
17
|
+
npm install # sass + postcss + esbuild toolchain (dev only)
|
|
18
|
+
npm run build # → dist/ : CSS (expanded + min, per skin) + JS bundles + types
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Include the stylesheet and set a theme on the root element:
|
|
22
|
+
|
|
23
|
+
```html
|
|
24
|
+
<html data-theme="aura-dark">
|
|
25
|
+
<head>
|
|
26
|
+
<link rel="stylesheet" href="dist/aura.css" />
|
|
27
|
+
</head>
|
|
28
|
+
<body>
|
|
29
|
+
<button class="btn">Primary</button>
|
|
30
|
+
<div class="card"><h3 class="card__title">Hello</h3></div>
|
|
31
|
+
</body>
|
|
32
|
+
</html>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
No build in your consuming project? Just ship the compiled `dist/aura.css`.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## The three config levers
|
|
40
|
+
|
|
41
|
+
Everything adapts through `src/_config.scss`. Override with Sass configuration:
|
|
42
|
+
|
|
43
|
+
```scss
|
|
44
|
+
@use "aura/src/index" with (
|
|
45
|
+
$prefix: 'au-', // namespace all classes → .au-btn (default: none)
|
|
46
|
+
$skin: flat, // surface treatment: glass | flat | neu
|
|
47
|
+
$themes: ( ... ) // your colour palettes (see Theming)
|
|
48
|
+
);
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
| Lever | What it controls | Default |
|
|
52
|
+
|-------|------------------|---------|
|
|
53
|
+
| `$prefix` | Class-name namespace (avoid collisions with other libs) | `''` |
|
|
54
|
+
| `$skin` | Surface look — glass / flat / neu | `glass` |
|
|
55
|
+
| `$themes` | Colour palettes, swapped at runtime via `data-theme` | dark + light |
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Theming
|
|
60
|
+
|
|
61
|
+
Colours follow **[Material 3 color roles](https://m3.material.io/styles/color/roles)**:
|
|
62
|
+
every fill colour has a paired `on-*` content colour for guaranteed contrast, and a
|
|
63
|
+
subtle `*-container` tint for badges/alerts.
|
|
64
|
+
|
|
65
|
+
You only define **base colours** — each `on-*` (text-on-colour) is **derived
|
|
66
|
+
automatically** by luminance, so "white-on-white" is structurally impossible.
|
|
67
|
+
|
|
68
|
+
### Token contract
|
|
69
|
+
|
|
70
|
+
Components reference **only** these CSS variables (never hardcoded colours):
|
|
71
|
+
|
|
72
|
+
**Accents & status** — each has `--<role>`, `--on-<role>`, `--<role>-container`, `--on-<role>-container`:
|
|
73
|
+
`primary`, `secondary`, `accent`, `success`, `warning`, `error`, `info`
|
|
74
|
+
|
|
75
|
+
**Surfaces & lines**
|
|
76
|
+
| Token | Use |
|
|
77
|
+
|-------|-----|
|
|
78
|
+
| `--surface` | Page background |
|
|
79
|
+
| `--surface-1` / `--surface-2` | Card / elevated (modal, popover) |
|
|
80
|
+
| `--on-surface` / `--on-surface-muted` | Body text / secondary text |
|
|
81
|
+
| `--outline` / `--outline-strong` | Dividers / control borders |
|
|
82
|
+
| `--glass-film` / `--glass-film-2` | Frosted film (glass skin only) |
|
|
83
|
+
| `--shadow-1` / `--shadow-2` | Elevation |
|
|
84
|
+
|
|
85
|
+
**Static scales** (theme-independent)
|
|
86
|
+
`--radius-sm|md|lg|pill` · `--space-1|2|3|4|6|8` · `--font` · `--fs-xs|sm|md|lg|xl` ·
|
|
87
|
+
`--blur` · `--z-dropdown|sticky|modal|toast` ·
|
|
88
|
+
`--gradient` (general brand gradient, auto-built from the theme's accents)
|
|
89
|
+
|
|
90
|
+
### Add a theme
|
|
91
|
+
|
|
92
|
+
**Quickest:** open `docs/theme-generator.html` — pick accent colours + a base mode, get a
|
|
93
|
+
live preview and a ready-to-paste `[data-theme]` block (with `on-*` and containers derived).
|
|
94
|
+
|
|
95
|
+
Or add an entry to `$themes` — only base colours required:
|
|
96
|
+
|
|
97
|
+
```scss
|
|
98
|
+
$themes: (
|
|
99
|
+
ocean: (
|
|
100
|
+
primary: #0EA5E9, secondary: #6366F1, accent: #22D3EE,
|
|
101
|
+
success: #16A34A, warning: #D97706, error: #DC2626, info: #3B82F6,
|
|
102
|
+
surface: #0b1220, surface-1: #131c2e, surface-2: #1b2740,
|
|
103
|
+
on-surface: #e6edf7, on-surface-muted: rgba(230,237,247,.62),
|
|
104
|
+
outline: rgba(255,255,255,.14), outline-strong: rgba(255,255,255,.24),
|
|
105
|
+
glass-film: rgba(255,255,255,.06), glass-film-2: rgba(255,255,255,.10),
|
|
106
|
+
shadow-1: (0 8px 32px rgba(0,0,0,.4)), shadow-2: (0 16px 44px rgba(0,0,0,.5)),
|
|
107
|
+
),
|
|
108
|
+
);
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Rebuild, then use it: `<html data-theme="ocean">`. Themes can also be layered per
|
|
112
|
+
subtree — nest `data-theme` on any element.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Skins
|
|
117
|
+
|
|
118
|
+
The **skin** is the surface treatment, independent of colour. Components request their
|
|
119
|
+
chrome via three mixins — `surface()` (panels/cards), `field()` (input wells) and
|
|
120
|
+
`control()` (filled buttons) — and the active skin renders each. So buttons, inputs and
|
|
121
|
+
cards all adapt together.
|
|
122
|
+
|
|
123
|
+
| Skin | Card (`surface`) | Button (`control`) | Input (`field`) |
|
|
124
|
+
|------|------------------|--------------------|-----------------|
|
|
125
|
+
| `glass` | Frosted film + blur | Solid + soft glow + gloss | Translucent well + blur |
|
|
126
|
+
| `flat` | Solid + border | Solid fill | Solid + border |
|
|
127
|
+
| `neu` | Extruded shadows | Extruded, inset on press | Inset well |
|
|
128
|
+
|
|
129
|
+
Switch at build time with `$skin`. Each skin lives in its own file under `src/skins/`;
|
|
130
|
+
adding a new one = new file + one branch in `src/_surface.scss`.
|
|
131
|
+
|
|
132
|
+
Prebuilt skin outputs: `dist/aura.css` (glass, default), `dist/aura-flat.css`,
|
|
133
|
+
`dist/aura-neu.css`.
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Components
|
|
138
|
+
|
|
139
|
+
### Button — `.btn`
|
|
140
|
+
|
|
141
|
+
Base class renders the **primary** button. Add modifiers to change colour, style, size.
|
|
142
|
+
|
|
143
|
+
| Class | Effect |
|
|
144
|
+
|-------|--------|
|
|
145
|
+
| `.btn` | Primary (default) |
|
|
146
|
+
| `.btn--secondary` / `.btn--accent` | Accent colours |
|
|
147
|
+
| `.btn--success` / `.btn--warning` / `.btn--error` / `.btn--info` | Status colours |
|
|
148
|
+
| `.btn--ghost` | Transparent, bordered |
|
|
149
|
+
| `.btn--outline` | Outlined; combine with a colour modifier |
|
|
150
|
+
| `.btn--gradient` | Gradient fill — follows the colour; combine with a colour modifier (`.btn--gradient.btn--success`) |
|
|
151
|
+
| `.btn--sm` / `.btn--lg` | Sizes |
|
|
152
|
+
| `.btn--block` | Full width |
|
|
153
|
+
| `.btn--disabled` / `[disabled]` | Disabled state |
|
|
154
|
+
|
|
155
|
+
States handled automatically: `:hover`, `:active`, `:focus-visible`, `:disabled`.
|
|
156
|
+
|
|
157
|
+
```html
|
|
158
|
+
<button class="btn">Primary</button>
|
|
159
|
+
<button class="btn btn--secondary">Secondary</button>
|
|
160
|
+
<button class="btn btn--error btn--outline">Delete</button>
|
|
161
|
+
<button class="btn btn--lg btn--block">Continue</button>
|
|
162
|
+
<button class="btn" disabled>Disabled</button>
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Card — `.card`
|
|
166
|
+
|
|
167
|
+
Surface container rendered through the active skin (glass/flat/neu).
|
|
168
|
+
|
|
169
|
+
| Class | Element / effect |
|
|
170
|
+
|-------|------------------|
|
|
171
|
+
| `.card` | Container (padded, uses `surface()`) |
|
|
172
|
+
| `.card__header` / `.card__title` / `.card__body` / `.card__actions` | Header row / heading / text / footer |
|
|
173
|
+
| `.card--success` / `--warning` / `--error` / `--info` | Coloured status accent (left bar) |
|
|
174
|
+
| `.card--gradient` | Gradient fill; combine with a colour modifier |
|
|
175
|
+
|
|
176
|
+
```html
|
|
177
|
+
<div class="card card--success">
|
|
178
|
+
<div class="card__header">
|
|
179
|
+
<h3 class="card__title">Acme Inc.</h3>
|
|
180
|
+
<span class="badge badge--success">Active</span>
|
|
181
|
+
</div>
|
|
182
|
+
<p class="card__body">Enterprise plan · renews 12 Aug.</p>
|
|
183
|
+
</div>
|
|
184
|
+
|
|
185
|
+
<div class="card card--gradient card--error"> … </div>
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Input — `.input` / `.select` / `.textarea`
|
|
189
|
+
|
|
190
|
+
Text controls whose "well" is rendered through the `field()` mixin, so they adopt the
|
|
191
|
+
active skin (glass / flat / neu). Wrap with `.field` to attach a label and hint.
|
|
192
|
+
|
|
193
|
+
| Class | Effect |
|
|
194
|
+
|-------|--------|
|
|
195
|
+
| `.input` / `.select` / `.textarea` | Base controls |
|
|
196
|
+
| `.input--sm` / `.input--lg` | Sizes |
|
|
197
|
+
| `.input--error` (also `--select`/`--textarea`) | Error state (red border) |
|
|
198
|
+
| `.field` | Labelled wrapper (label + control + hint) |
|
|
199
|
+
| `.field__label` | Label |
|
|
200
|
+
| `.field__hint` / `.field__hint--error` | Helper / error text |
|
|
201
|
+
|
|
202
|
+
States handled automatically: `:focus-visible` (primary ring), `:disabled`.
|
|
203
|
+
|
|
204
|
+
```html
|
|
205
|
+
<div class="field">
|
|
206
|
+
<label class="field__label" for="email">Email</label>
|
|
207
|
+
<input id="email" class="input" type="email" placeholder="you@studio.dev">
|
|
208
|
+
</div>
|
|
209
|
+
|
|
210
|
+
<div class="field">
|
|
211
|
+
<label class="field__label" for="pw">Password</label>
|
|
212
|
+
<input id="pw" class="input input--error" type="password">
|
|
213
|
+
<span class="field__hint field__hint--error">At least 8 characters.</span>
|
|
214
|
+
</div>
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Badge — `.badge`
|
|
218
|
+
|
|
219
|
+
Small status label. Colour variants use soft `*-container` tints with a guaranteed-contrast
|
|
220
|
+
content colour.
|
|
221
|
+
|
|
222
|
+
| Class | Effect |
|
|
223
|
+
|-------|--------|
|
|
224
|
+
| `.badge` | Base (neutral) |
|
|
225
|
+
| `.badge--primary` / `--secondary` / `--accent` | Accent tints |
|
|
226
|
+
| `.badge--success` / `--warning` / `--error` / `--info` | Status tints |
|
|
227
|
+
| `.badge--outline` | Transparent, bordered |
|
|
228
|
+
| `.badge--sm` / `.badge--lg` | Sizes |
|
|
229
|
+
| `.badge__dot` | Leading status dot |
|
|
230
|
+
|
|
231
|
+
```html
|
|
232
|
+
<span class="badge badge--success"><i class="badge__dot"></i> Active</span>
|
|
233
|
+
<span class="badge badge--error badge--outline">Failed</span>
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Alert — `.alert`
|
|
237
|
+
|
|
238
|
+
A message panel with an accent bar and icon. Colour variants carry status meaning.
|
|
239
|
+
|
|
240
|
+
| Class | Effect |
|
|
241
|
+
|-------|--------|
|
|
242
|
+
| `.alert` | Base (primary) panel |
|
|
243
|
+
| `.alert--success` / `--warning` / `--error` / `--info` | Status colours |
|
|
244
|
+
| `.alert__icon` | Leading icon |
|
|
245
|
+
| `.alert__title` / `.alert__body` | Bold heading / muted description |
|
|
246
|
+
|
|
247
|
+
```html
|
|
248
|
+
<div class="alert alert--error">
|
|
249
|
+
<span class="alert__icon">✕</span>
|
|
250
|
+
<div>
|
|
251
|
+
<div class="alert__title">Payment failed</div>
|
|
252
|
+
<div class="alert__body">Your card was declined.</div>
|
|
253
|
+
</div>
|
|
254
|
+
</div>
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Switch — `.switch`
|
|
258
|
+
|
|
259
|
+
A toggle for boolean settings. The track is a skin-aware well; when checked it fills with
|
|
260
|
+
the accent colour and shows a white thumb.
|
|
261
|
+
|
|
262
|
+
| Class | Effect |
|
|
263
|
+
|-------|--------|
|
|
264
|
+
| `.switch` | Toggle (wraps a checkbox) |
|
|
265
|
+
| `.switch__track` / `.switch__thumb` | Track / knob |
|
|
266
|
+
| `.switch--success` / `--warning` / `--error` | Checked colour |
|
|
267
|
+
| `.switch--sm` / `.switch--lg` | Sizes |
|
|
268
|
+
|
|
269
|
+
```html
|
|
270
|
+
<label class="switch">
|
|
271
|
+
<input type="checkbox" checked>
|
|
272
|
+
<span class="switch__track"></span>
|
|
273
|
+
<span class="switch__thumb"></span>
|
|
274
|
+
</label>
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Checkbox — `.checkbox` · Radio — `.radio`
|
|
278
|
+
|
|
279
|
+
Custom controls set directly on the native input. The box/circle is a skin-aware well;
|
|
280
|
+
checked fills with the accent colour + white mark. `:indeterminate` (checkbox) shows a dash.
|
|
281
|
+
|
|
282
|
+
| Class | Effect |
|
|
283
|
+
|-------|--------|
|
|
284
|
+
| `.checkbox` / `.radio` | On the native input |
|
|
285
|
+
| `.checkbox--success` / `--warning` / `--error` | Checked colour |
|
|
286
|
+
| `.radio--success` / `--warning` / `--error` | Checked colour |
|
|
287
|
+
|
|
288
|
+
```html
|
|
289
|
+
<input type="checkbox" class="checkbox" checked>
|
|
290
|
+
<input type="radio" name="plan" class="radio radio--success" checked>
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Select — `.select`
|
|
294
|
+
|
|
295
|
+
Native `<select>` with a custom chevron. Same sizes (`--sm`/`--lg`) and validation
|
|
296
|
+
(`--error`/`--success`) as text inputs.
|
|
297
|
+
|
|
298
|
+
### Range — `.range` · File — `.file` · Rating — `.rating`
|
|
299
|
+
|
|
300
|
+
| Class | Effect |
|
|
301
|
+
|-------|--------|
|
|
302
|
+
| `.range` | Themed slider · `--success`/`--warning`/`--error` · `--sm`/`--lg` |
|
|
303
|
+
| `.file` | Styled file input · `.file--ghost` |
|
|
304
|
+
| `.rating` | Star rating on radios (CSS-only, submittable) · `--sm`/`--lg` |
|
|
305
|
+
|
|
306
|
+
```html
|
|
307
|
+
<input class="range range--success" type="range" value="80">
|
|
308
|
+
<input class="file" type="file">
|
|
309
|
+
<div class="rating">
|
|
310
|
+
<input type="radio" name="r" value="5"><label>★</label>
|
|
311
|
+
<input type="radio" name="r" value="4" checked><label>★</label>
|
|
312
|
+
…
|
|
313
|
+
</div>
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
**Validation** — add `--error` / `--success` to any control; use `.field__label--required`
|
|
317
|
+
(adds `*`) and `.field__hint--error` / `--success` for messages.
|
|
318
|
+
|
|
319
|
+
### Tabs — `.tabs`
|
|
320
|
+
|
|
321
|
+
A tab bar with switchable panels. Point each `.tab` at a panel with `data-tab="#id"`; the
|
|
322
|
+
JS activates it and toggles panel visibility. Frameworks render active tab + panel from state.
|
|
323
|
+
|
|
324
|
+
| Class | Effect |
|
|
325
|
+
|-------|--------|
|
|
326
|
+
| `.tabs` | Container: pill (default) · `--underline` / `--lift` · `--sm` / `--lg` · `--block` |
|
|
327
|
+
| `.tab` / `.tab--active` | Tab item / selected |
|
|
328
|
+
| `.tab-panel` | Content panel (toggled via `hidden`) |
|
|
329
|
+
| `.tab-panels` | Panel container (plain by default; card after `--lift` tabs) |
|
|
330
|
+
| `.tab-card` | Wraps `.tabs` + `.tab-panels` into one connected card (no gap) |
|
|
331
|
+
|
|
332
|
+
```html
|
|
333
|
+
<div class="tabs" role="tablist">
|
|
334
|
+
<button class="tab tab--active" data-tab="#p1">Overview</button>
|
|
335
|
+
<button class="tab" data-tab="#p2">Activity</button>
|
|
336
|
+
</div>
|
|
337
|
+
<div id="p1" class="tab-panel">Overview…</div>
|
|
338
|
+
<div id="p2" class="tab-panel" hidden>Activity…</div>
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### Group — `.group` (alias `.btn-group`)
|
|
342
|
+
|
|
343
|
+
Joins adjacent controls — buttons **and** form fields — into one segmented unit (square
|
|
344
|
+
inner corners, single shared border). Fields grow, buttons stay natural. `.group--block`
|
|
345
|
+
for full width.
|
|
346
|
+
|
|
347
|
+
```html
|
|
348
|
+
<!-- button group -->
|
|
349
|
+
<div class="group">
|
|
350
|
+
<button class="btn btn--ghost">Day</button>
|
|
351
|
+
<button class="btn btn--ghost">Week</button>
|
|
352
|
+
</div>
|
|
353
|
+
|
|
354
|
+
<!-- input group -->
|
|
355
|
+
<div class="group">
|
|
356
|
+
<input class="input" placeholder="Search…">
|
|
357
|
+
<button class="btn">Search</button>
|
|
358
|
+
</div>
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
**Radio segmented** — for single-select, `.segmented` uses native radios (CSS-only,
|
|
362
|
+
keyboard-accessible, form-submittable); the checked pill is skin-aware.
|
|
363
|
+
|
|
364
|
+
```html
|
|
365
|
+
<div class="segmented" role="radiogroup">
|
|
366
|
+
<label class="segmented__option"><input type="radio" name="v" checked><span>Day</span></label>
|
|
367
|
+
<label class="segmented__option"><input type="radio" name="v"><span>Week</span></label>
|
|
368
|
+
</div>
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### Table — `.table`
|
|
372
|
+
|
|
373
|
+
Transparent data table (place in a `.card`). `.table--zebra` for stripes, `.table--compact` for tighter rows.
|
|
374
|
+
|
|
375
|
+
```html
|
|
376
|
+
<table class="table table--zebra"> … </table>
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
### Progress — `.progress` · Spinner — `.spinner`
|
|
380
|
+
|
|
381
|
+
| Class | Effect |
|
|
382
|
+
|-------|--------|
|
|
383
|
+
| `.progress` / `.progress__bar` | Track / fill (set width inline) |
|
|
384
|
+
| `.progress--success` / `--warning` / `--error` | Fill colour |
|
|
385
|
+
| `.spinner` | Loading spinner · `--sm` / `--lg` |
|
|
386
|
+
|
|
387
|
+
```html
|
|
388
|
+
<div class="progress"><span class="progress__bar" style="width:72%"></span></div>
|
|
389
|
+
<span class="spinner"></span>
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### Tooltip — `.tooltip`
|
|
393
|
+
|
|
394
|
+
Pure-CSS tooltip on hover/focus, inverted vs. the theme. `.tooltip--bottom` to flip placement.
|
|
395
|
+
|
|
396
|
+
```html
|
|
397
|
+
<span class="tooltip">
|
|
398
|
+
<button class="btn">Hover me</button>
|
|
399
|
+
<span class="tooltip__text">Helpful hint</span>
|
|
400
|
+
</span>
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
---
|
|
404
|
+
|
|
405
|
+
## Interactive components (Modal, Dropdown)
|
|
406
|
+
|
|
407
|
+
Stateful components keep their state **in the DOM** as `data-state="open|closed"`; CSS
|
|
408
|
+
renders it. Nothing in the contract is tied to the library name.
|
|
409
|
+
|
|
410
|
+
- **Vanilla** — load the optional behaviour layer; it auto-wires triggers and adds
|
|
411
|
+
scroll-lock, focus-trap, Esc and outside/backdrop close:
|
|
412
|
+
```html
|
|
413
|
+
<script type="module" src="src/js/interactions.auto.js"></script>
|
|
414
|
+
```
|
|
415
|
+
Triggers: `data-open="#id"`, `data-close`, `data-toggle`. (Prefix them via
|
|
416
|
+
`configure({ prefix: 'ui' })` → `data-ui-open`.)
|
|
417
|
+
- **React / Vue / anything** — no library JS needed. Bind `data-state` to your own state
|
|
418
|
+
and handle clicks your way. Optionally import pure helpers:
|
|
419
|
+
`import { open, close, trapFocus, lockScroll } from './src/js/interactions.js'`.
|
|
420
|
+
|
|
421
|
+
### Modal — `.modal-overlay` + `.modal`
|
|
422
|
+
|
|
423
|
+
Mark the overlay `data-overlay` so the JS applies scroll-lock + focus-trap + backdrop-close.
|
|
424
|
+
|
|
425
|
+
```html
|
|
426
|
+
<button class="btn" data-open="#dlg">Open</button>
|
|
427
|
+
<div class="modal-overlay" id="dlg" data-state="closed" data-overlay>
|
|
428
|
+
<div class="modal" role="dialog" aria-modal="true">
|
|
429
|
+
<h3 class="modal__title">Title</h3>
|
|
430
|
+
<p class="modal__body">Body…</p>
|
|
431
|
+
<div class="modal__actions"><button class="btn btn--ghost" data-close>Close</button></div>
|
|
432
|
+
</div>
|
|
433
|
+
</div>
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
### Dropdown — `.dropdown`
|
|
437
|
+
|
|
438
|
+
```html
|
|
439
|
+
<div class="dropdown" data-state="closed">
|
|
440
|
+
<button class="btn" data-toggle>Menu <span class="dropdown__caret"></span></button>
|
|
441
|
+
<div class="dropdown__menu">
|
|
442
|
+
<a class="dropdown__item" href="#">Profile</a>
|
|
443
|
+
<div class="dropdown__divider"></div>
|
|
444
|
+
<a class="dropdown__item" href="#">Sign out</a>
|
|
445
|
+
</div>
|
|
446
|
+
</div>
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
### Avatar — `.avatar`
|
|
450
|
+
|
|
451
|
+
Image or initials, with `--sm`/`--lg`/`--square`, an `.avatar__status` dot, and an
|
|
452
|
+
overlapping `.avatar-group`.
|
|
453
|
+
|
|
454
|
+
### Accordion — `.accordion`
|
|
455
|
+
|
|
456
|
+
Built on native `<details>` — zero JS. Add `name="…"` to items to make them exclusive.
|
|
457
|
+
|
|
458
|
+
```html
|
|
459
|
+
<div class="accordion">
|
|
460
|
+
<details class="accordion__item" name="faq" open>
|
|
461
|
+
<summary class="accordion__head">Question</summary>
|
|
462
|
+
<div class="accordion__body">Answer…</div>
|
|
463
|
+
</details>
|
|
464
|
+
</div>
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
### Toast — `.toast`
|
|
468
|
+
|
|
469
|
+
Show imperatively with the JS helper (auto-creates the container, auto-dismisses):
|
|
470
|
+
|
|
471
|
+
```js
|
|
472
|
+
import { toast } from './dist/interactions.mjs';
|
|
473
|
+
toast('Changes saved.', { type: 'success', timeout: 4000 });
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
### Pagination — `.pagination`
|
|
477
|
+
|
|
478
|
+
`.pagination__item` for pages/arrows; `--active` (skin-aware) / `--disabled`.
|
|
479
|
+
Variants: `.pagination--joined` (button-group style, shared borders) · `.pagination--sm`.
|
|
480
|
+
Use `.pagination__ellipsis` for `…` gaps in long ranges.
|
|
481
|
+
|
|
482
|
+
---
|
|
483
|
+
|
|
484
|
+
## Distribution
|
|
485
|
+
|
|
486
|
+
`npm run build` produces everything into `dist/` — Sass compiles the CSS (expanded +
|
|
487
|
+
minified per skin), PostCSS/autoprefixer adds vendor prefixes (targets from the
|
|
488
|
+
`browserslist` field), and esbuild bundles the JS.
|
|
489
|
+
|
|
490
|
+
**CSS** — one file per skin, expanded and minified:
|
|
491
|
+
|
|
492
|
+
| Skin | Expanded | Minified |
|
|
493
|
+
|------|----------|----------|
|
|
494
|
+
| glass (default) | `dist/aura.css` | `dist/aura.min.css` |
|
|
495
|
+
| flat | `dist/aura-flat.css` | `dist/aura-flat.min.css` |
|
|
496
|
+
| neu | `dist/aura-neu.css` | `dist/aura-neu.min.css` |
|
|
497
|
+
|
|
498
|
+
**JS** (optional behaviour layer):
|
|
499
|
+
|
|
500
|
+
| File | Use |
|
|
501
|
+
|------|-----|
|
|
502
|
+
| `dist/interactions.mjs` / `.min.mjs` | ESM — `import { open, toast } from '@oleksandr-94/aura-css'` (frameworks, `<script type=module>`) |
|
|
503
|
+
| `dist/interactions.global.min.js` | Minified IIFE — `<script src>` exposes `window.Aura` + auto-wires triggers |
|
|
504
|
+
| `dist/interactions.d.ts` | TypeScript types |
|
|
505
|
+
|
|
506
|
+
The global name is esbuild's `--global-name` flag — rename freely; the DOM contract is
|
|
507
|
+
unaffected.
|
|
508
|
+
|
|
509
|
+
**Package entry points** (`exports`):
|
|
510
|
+
|
|
511
|
+
```js
|
|
512
|
+
import { open, toast } from '@oleksandr-94/aura-css'; // JS (ESM) + types
|
|
513
|
+
import '@oleksandr-94/aura-css/css'; // glass CSS (also: @oleksandr-94/aura-css/css/min)
|
|
514
|
+
import '@oleksandr-94/aura-css/flat'; // flat skin (also: @oleksandr-94/aura-css/flat/min)
|
|
515
|
+
import '@oleksandr-94/aura-css/neu'; // neu skin
|
|
516
|
+
// SCSS source for custom builds: @use '@oleksandr-94/aura-css/scss' with ($skin: flat, $prefix: 'ui');
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
---
|
|
520
|
+
|
|
521
|
+
## Accessibility
|
|
522
|
+
|
|
523
|
+
- **Reduced motion** — Aura component transitions/animations are neutralised under
|
|
524
|
+
`prefers-reduced-motion: reduce` (in the last cascade layer, so it never touches the
|
|
525
|
+
host app's own motion).
|
|
526
|
+
- **Keyboard** — Modal: focus-trap, Esc, focus return. Dropdown: `↑`/`↓`/`Home`/`End`
|
|
527
|
+
over items, Esc, `aria-expanded`, focus return. Tabs: `←`/`→` roving focus.
|
|
528
|
+
- **Screen readers** — Toasts announce via an `aria-live="polite"` region (errors use
|
|
529
|
+
`role="alert"`); a `.sr-only` helper is provided for visually-hidden labels.
|
|
530
|
+
- **Focus visible** — every interactive component has a `:focus-visible` ring.
|
|
531
|
+
|
|
532
|
+
## Browser support
|
|
533
|
+
|
|
534
|
+
Aura targets an **evergreen baseline** (Chrome/Edge 111+, Firefox 113+, Safari 16.4+),
|
|
535
|
+
which is required for:
|
|
536
|
+
|
|
537
|
+
| Feature | Used for | If missing |
|
|
538
|
+
|---------|----------|------------|
|
|
539
|
+
| `color-mix()` | tints, hovers, neu shadows | no practical polyfill — hard requirement |
|
|
540
|
+
| Cascade layers (`@layer`) | override control | hard requirement |
|
|
541
|
+
| `backdrop-filter` | **glass skin only** | glass loses blur (film stays); use `flat`/`neu` |
|
|
542
|
+
|
|
543
|
+
These features are the same generation, so there is no meaningful fallback to add — the
|
|
544
|
+
baseline is documented rather than polyfilled. Non-glass skins (`flat`, `neu`) have the
|
|
545
|
+
lightest requirements.
|
|
546
|
+
|
|
547
|
+
---
|
|
548
|
+
|
|
549
|
+
## Architecture
|
|
550
|
+
|
|
551
|
+
```
|
|
552
|
+
aura/
|
|
553
|
+
├── src/ # library source
|
|
554
|
+
│ ├── _config.scss # the 3 levers: $prefix, $skin, $themes
|
|
555
|
+
│ ├── _functions.scss # auto on-colour (contrast) derivation
|
|
556
|
+
│ ├── _tokens.scss # emits static scales + generates every theme
|
|
557
|
+
│ ├── _surface.scss # skin dispatcher: surface() / field()
|
|
558
|
+
│ ├── skins/ # _glass · _flat · _neu
|
|
559
|
+
│ ├── base/_reset.scss # minimal reset in @layer base
|
|
560
|
+
│ ├── components/ # _button · _card
|
|
561
|
+
│ ├── _layers.scss # cascade-layer order
|
|
562
|
+
│ └── index.scss # entry (default = glass)
|
|
563
|
+
├── builds/ # build presets (recipes): flat.scss …
|
|
564
|
+
├── dist/ # compiled CSS output
|
|
565
|
+
├── demo/ # live demo page
|
|
566
|
+
└── package.json
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
- **Cascade layers** — all Aura CSS lives in `@layer base, components`; your app's own
|
|
570
|
+
unlayered styles always win, so overriding is easy.
|
|
571
|
+
- **Coexistence** — set `$prefix` to avoid class clashes with other libraries. With
|
|
572
|
+
Tailwind v4 you can also map Aura's role variables into `@theme` to share one palette.
|
|
573
|
+
|
|
574
|
+
---
|
|
575
|
+
|
|
576
|
+
## Testing
|
|
577
|
+
|
|
578
|
+
Unit tests cover the JS behaviour layer (`interactions.js`) with Vitest + happy-dom:
|
|
579
|
+
|
|
580
|
+
```bash
|
|
581
|
+
npm test # run once
|
|
582
|
+
npm run test:watch
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
Covered: open/close/toggle, `mount()` trigger delegation, `activateTab`, ref-counted
|
|
586
|
+
scroll-lock, `toast()` lifecycle, and prefix config.
|
|
587
|
+
|
|
588
|
+
## Not yet (roadmap)
|
|
589
|
+
|
|
590
|
+
- Components: `breadcrumbs`, `menu`/sidebar, `steps`, `skeleton`, `stat`, `drawer`, `popover`.
|
|
591
|
+
- More prebuilt themes (the token system supports them cheaply).
|
|
592
|
+
- Visual-regression tests (Playwright over the docs, per skin × theme) + a11y audit (axe).
|
|
593
|
+
- RTL audit · `prefers-color-scheme` auto-theme · per-component CSS imports (tree-shaking).
|