actual-css 0.9.2 → 0.11.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 +169 -1
- package/README.md +65 -44
- package/components.json +35 -14
- package/dist/actual.full.css +877 -583
- package/dist/actual.full.js +1 -1
- package/dist/actual.full.min.css +1 -1
- package/docs/design-notes/app-ui.md +1 -1
- package/docs/design-notes/column-layout.md +103 -520
- package/docs/design-notes/enhancement-contract.md +16 -7
- package/docs/design-notes/forced-colors.md +12 -1
- package/docs/design-notes/naming.md +1 -1
- package/docs/design-notes/platform-alignment.md +8 -4
- package/docs/design-notes/rich-text.md +61 -0
- package/docs/design-notes/steps.md +2 -2
- package/docs/design-notes/surface-reparenting.md +8 -9
- package/docs/navigation.json +4 -0
- package/docs/pages/components/accordion.md +55 -1
- package/docs/pages/components/alert.md +9 -15
- package/docs/pages/components/aura.md +12 -13
- package/docs/pages/components/badge.md +16 -7
- package/docs/pages/components/bleed.md +42 -0
- package/docs/pages/components/button.md +30 -4
- package/docs/pages/components/card.md +21 -86
- package/docs/pages/components/chat.md +5 -0
- package/docs/pages/components/close.md +48 -0
- package/docs/pages/components/data-list.md +26 -1
- package/docs/pages/components/dialog.md +21 -18
- package/docs/pages/components/drawer.md +9 -9
- package/docs/pages/components/navbar.md +5 -5
- package/docs/pages/components/pagination.md +15 -15
- package/docs/pages/components/shimmer.md +57 -0
- package/docs/pages/components/skeleton.md +2 -1
- package/docs/pages/components/spinner.md +14 -9
- package/docs/pages/components/table.md +13 -0
- package/docs/pages/enhancements/flyout.md +2 -0
- package/docs/pages/enhancements/overview.md +5 -0
- package/docs/pages/enhancements/tabs.md +4 -0
- package/docs/pages/enhancements/tooltip.md +3 -1
- package/docs/pages/examples/overview.md +2 -1
- package/docs/pages/forms/choice-cards.md +116 -4
- package/docs/pages/forms/combobox.md +39 -12
- package/docs/pages/forms/joined-controls.md +2 -5
- package/docs/pages/forms/overview.md +10 -1
- package/docs/pages/forms/range.md +110 -5
- package/docs/pages/forms/rich-text.md +110 -0
- package/docs/pages/forms/validation.md +5 -1
- package/docs/pages/foundations/theming.md +110 -18
- package/docs/pages/foundations/tokens.md +41 -13
- package/docs/pages/guides/bootstrap.md +2 -1
- package/docs/pages/guides/introduction.md +15 -23
- package/docs/pages/guides/modular-import.md +54 -7
- package/docs/pages/guides/progressive-enhancement.md +19 -17
- package/docs/pages/guides/tailwind.md +21 -7
- package/docs/pages/layout/column-layout.md +92 -54
- package/docs/pages/layout/media.md +1 -1
- package/docs/pages/layout/overview.md +1 -1
- package/docs/pages/utilities/overview.md +1 -1
- package/docs/pages/utilities/sizing-wrapping.md +5 -3
- package/llms.txt +25 -4
- package/package.json +10 -6
- package/reserved-classes.json +6 -30
- package/skills/actual-css/PROJECT.md.example +65 -0
- package/skills/actual-css/README.md +64 -0
- package/skills/actual-css/SKILL.md +234 -0
- package/skills/actual-css/references/accessibility.md +44 -0
- package/skills/actual-css/references/api-and-vocabulary.md +94 -0
- package/skills/actual-css/references/enhancements.md +59 -0
- package/skills/actual-css/references/forms.md +49 -0
- package/skills/actual-css/references/layout-and-theming.md +82 -0
- package/skills/actual-css/references/review-checklist.md +51 -0
- package/skills/actual-css/scripts/inspect-actual-css.mjs +171 -0
- package/src/css/components/accordion.css +44 -7
- package/src/css/components/alert.css +23 -43
- package/src/css/components/app-nav.css +9 -0
- package/src/css/components/avatar.css +1 -1
- package/src/css/components/badge.css +11 -39
- package/src/css/components/bleed.css +79 -0
- package/src/css/components/button.css +6 -17
- package/src/css/components/card.css +7 -40
- package/src/css/components/close.css +91 -0
- package/src/css/components/data-list.css +18 -0
- package/src/css/components/drawer.css +15 -56
- package/src/css/components/fab.css +10 -0
- package/src/css/components/flyout.css +5 -1
- package/src/css/components/index.css +2 -0
- package/src/css/components/join.css +36 -20
- package/src/css/components/menu.css +12 -0
- package/src/css/components/meter.css +1 -1
- package/src/css/components/modal.css +10 -57
- package/src/css/components/navbar.css +27 -0
- package/src/css/components/pagination.css +3 -2
- package/src/css/components/rating.css +1 -1
- package/src/css/components/status-bar.css +2 -2
- package/src/css/components/steps.css +3 -3
- package/src/css/components/tab.css +3 -3
- package/src/css/components/table.css +6 -0
- package/src/css/components/tooltip.css +1 -1
- package/src/css/core/focus.css +19 -3
- package/src/css/core/theme.css +33 -43
- package/src/css/core/tokens.css +9 -5
- package/src/css/core/variants.css +5 -34
- package/src/css/effects/aura.css +51 -33
- package/src/css/effects/index.css +1 -0
- package/src/css/effects/shimmer.css +57 -0
- package/src/css/forms/choice-card.css +142 -24
- package/src/css/forms/choice.css +2 -3
- package/src/css/forms/control.css +17 -10
- package/src/css/forms/custom-select.css +4 -4
- package/src/css/forms/native.css +4 -4
- package/src/css/forms/otp.css +9 -1
- package/src/css/forms/range.css +72 -14
- package/src/css/forms/switch.css +2 -3
- package/src/css/layout/app-layout.css +1 -1
- package/src/css/layout/column-layout.css +26 -111
- package/src/css/utilities/extra.css +7 -6
- package/src/js/command.js +61 -32
- package/src/js/dialog.js +103 -47
- package/src/js/dismiss.js +1 -2
- package/src/js/enhance.js +91 -126
- package/src/js/escape.js +1 -0
- package/src/js/flyout.js +10 -1
- package/src/js/focus-group.js +2 -1
- package/src/js/full.js +1 -0
- package/src/js/keys.js +14 -0
- package/src/js/menu.js +2 -1
- package/src/js/password.js +1 -8
- package/src/js/range.js +151 -0
- package/src/js/scrollspy.js +4 -5
- package/src/js/status.js +21 -10
- package/src/js/surface.js +12 -8
- package/src/js/tab.js +2 -1
- package/src/js/tooltip.js +29 -2
- package/src/js/validation.js +8 -15
- package/dist/actual.css +0 -876
- package/dist/actual.js +0 -1
- package/dist/actual.min.css +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,9 +2,177 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
|
|
6
|
+
## [0.11.0] - 2026-09-30
|
|
7
|
+
|
|
8
|
+
### Breaking changes
|
|
9
|
+
|
|
10
|
+
- `enhancementSelector()` and `hasEnhancement()` are no longer exported from `actual-css/js/enhance`; query `[data-enhance~="name"]` directly.
|
|
11
|
+
- `registerCommands()` drops the `prepare` callback; write `aria-controls`, `aria-haspopup`, and `aria-pressed` on command buttons in the markup.
|
|
12
|
+
- `registerCommands()` and `commandSelector()` throw on a name that is neither a native `command` keyword nor a custom `--` command.
|
|
13
|
+
- `FormValidator.init()` is removed; the module self-registers, and `applyEnhancement("validation", selector)` opts forms in by selector.
|
|
14
|
+
- The non-modal dialog command is `command="--show"`; `command="show"` is not an HTML keyword and no longer opens a dialog.
|
|
15
|
+
- `.choice-card` shows its control on the leading edge — a ring (radio) or box (checkbox) at rest that fills with the check — instead of a corner badge shown only once checked; the badge is now the "Corner badge" recipe in `docs/pages/forms/choice-cards.md`.
|
|
16
|
+
- `.choice-card` is a two-column grid: each child element of the label becomes a row beside the indicator, so loose text needs an element.
|
|
17
|
+
- `--choice-card-check-size` defaults to `1.25em` and also sets the width of the `.choice-card` indicator column.
|
|
18
|
+
- `--aura-width` is the whole painted `.aura` frame (the border, no padding); `--aura-width: 3px` reproduces the former default frame.
|
|
19
|
+
- `.aura` defaults to a thin lit line: `--aura-width: 1px` and `--aura-intensity: 0.4`.
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- `--surface-opaque` and `--surface-solid-fg` let a theme paint translucent surfaces while rings, separators and inverse text stay opaque.
|
|
24
|
+
- `report:theme-contrast` reports the `--surface-solid-fg` on `--surface-solid` text pair.
|
|
25
|
+
- `scripts/utils/color.js` holds the WCAG contrast and OKLCH math for reports and browser tests; `contrast()` refuses translucent colors.
|
|
26
|
+
- `glass` demo theme: translucent surfaces over a theme-painted backdrop, a stress test of the opaque surface roles.
|
|
27
|
+
- `tests/browser/translucent-surface.test.js` keeps rings, separators, step markers, and inverse text opaque over translucent surfaces.
|
|
28
|
+
- `--choice-card-gap` sets the space between a `.choice-card` indicator and its label.
|
|
29
|
+
- `tests/browser/choice-card.test.js` locks the leading indicator: visible at rest, level with the first line of a wrapping label, and kept under forced colors.
|
|
30
|
+
- `.shimmer` (`actual-css/css/effects/shimmer`) sweeps a highlight across a text label for an activity in progress; hooks `--shimmer-color` and `--shimmer-highlight`.
|
|
31
|
+
- `.range` moves to a `1.125rem` thumb on a `0.625rem` track with a `data-enhance="range"` fill (`--range-progress`) and named `datalist` values (`aria-valuetext` plus `output` sync).
|
|
32
|
+
- `--flyout-pad` gives rich flyout panels dialog air.
|
|
33
|
+
- `tests/browser/control-geometry.test.js` locks the shared control block geometry: input, select, addon, and buttons (including busy and icon-only) share one height per size, and the spinner follows its context at `1em`.
|
|
34
|
+
|
|
35
|
+
### Changed
|
|
36
|
+
|
|
37
|
+
- `--indicator-ring`, the `.avatar-stack` ring, the `.range` thumb separator, segmented `.meter` separators and `.steps` markers read `--surface-opaque`.
|
|
38
|
+
- `.tooltip` text reads `--surface-solid-fg`.
|
|
39
|
+
- `.aura` masks its frame under the child with `--surface-opaque`, so a transparent or translucent child is framed rather than filled.
|
|
40
|
+
- The `.aura` far halo is an outer `box-shadow`, so it never paints under the child.
|
|
41
|
+
- `.status-bar` without an intent paints `--surface-solid` / `--surface-solid-fg` instead of `--text` / `--surface`.
|
|
42
|
+
- `registerEnhancement()` discovers every named behavior through one shared `[data-enhance]` query per root instead of one `[data-enhance~="name"]` selector each.
|
|
43
|
+
- The command router calls `event.preventDefault()` once a target resolves, before `handle`; handlers no longer cancel the click themselves.
|
|
44
|
+
- `--focus-outline` (the generic `currentColor` focus fallback) is `--focus-ring-width` wide instead of `2 × --border-width`: 3px instead of 4px under `prefers-contrast: more`.
|
|
45
|
+
|
|
46
|
+
### Fixed
|
|
47
|
+
|
|
48
|
+
- `actual-css/js/range` synchronizes fill, `aria-valuetext`, and outputs after a native form reset, including controls associated through `form="…"`, while respecting cancellation and teardown.
|
|
49
|
+
- Docs search leaves Enter on the close button and IME confirmation alone, and ArrowUp from no selection reaches the last result.
|
|
50
|
+
- `demo/sites/admini/chat.html` loads the shared composer recipe before local overrides so the bottom bar keeps its flat border and compact textarea.
|
|
51
|
+
- `.otp` with `.input` on its native input no longer draws the field focus ring around all the cells.
|
|
52
|
+
- Docs search keeps focus in the input while arrowing through results (`aria-activedescendant` + `Home`/`End`), so the second and later matches are reachable by keyboard; `Enter` follows the highlight instead of closing the dialog.
|
|
53
|
+
- `.tab` and `.rating` draw the component focus ring (`--focus-ring-width` solid `--focus`): an intent on the rating no longer becomes the focus color, and neither ring is 4px under `prefers-contrast: more`.
|
|
54
|
+
- `commandSelector()` matches native command keywords case-insensitively, as the router does.
|
|
55
|
+
- The command router ignores a trigger disabled through a `<fieldset disabled>` ancestor.
|
|
56
|
+
- `tooltip.js` shows on focus only when the trigger matches `:focus-visible`: a pointer press, or focus handed back by a dialog closed with the pointer, no longer brings the tooltip back.
|
|
57
|
+
|
|
58
|
+
### Documentation and tooling
|
|
59
|
+
|
|
60
|
+
- Choice cards: a stacked-list demo, and a "Corner badge" recipe (`.choice-tile`) that the Neon Ramen item page uses for its tiles.
|
|
61
|
+
- `tests/browser/choice-chip.test.js` asserts the chip's dot layer keeps its height, not just its clip and colour.
|
|
62
|
+
- `tests/exports.test.js` keys its inventory on every JS subpath of `package.json#exports`, so a new subpath or an export on an unlisted module now fails the suite.
|
|
63
|
+
- Docs search ranks a query token inside a longer alias (`select` finds the Combobox page via `searchable select`) and matches body text on word boundaries, so `selection` no longer outranks `select`; Combobox and Forms carry `select`, `custom select`, and `form controls` aliases.
|
|
64
|
+
- `focus.css` documents two focus contracts: text-like elements keep the `currentColor` fallback, boxed components draw the `--focus` ring, and an invalid field's `--form-invalid-border` ring is the one exception.
|
|
65
|
+
- `tests/css-audit.test.js` fails on any framework `outline` outside the two focus contracts.
|
|
66
|
+
- `report:theme-contrast` reports each preset's invalid-field focus line against the field background.
|
|
67
|
+
- `check:sync` fails when the `.sm` and `.lg` participant lists in `variants.css` diverge.
|
|
68
|
+
- Tailwind guide: `.outline` is named as the dangerous collision, with `.table`, `.sticky`, `.truncate`, `.prose`, and `.sr-only`.
|
|
69
|
+
- Tailwind and Bootstrap guides: a prefix transform is consumer-pipeline work and must also rename the runtime state classes in `actual-css/js/selectors`.
|
|
70
|
+
- Table: clarified the responsive boundary — horizontal overflow (`.table-wrap` + `--table-min` + accessible scroll) stays the strategy, and the docs now name the alternatives (list/media view, `.data-list`, dedicated data grid).
|
|
71
|
+
- Badge vs choice chip vs removable tag vocabulary: a badge is information (non-interactive), `choice-card.chip` is a selectable label (never nest a `.close` inside it), and removable tags belong to the widget that produced them.
|
|
72
|
+
- Combobox: a "Bridge contract" section names what Actual owns (tokens, focus, invalid, `.join`, contrast) versus the widget (behavior, multi-value, i18n), and keeps the bridge CSS in docs/demo.
|
|
73
|
+
- Tabs: the `.tabs` strip / `.tab` trigger pair is documented as the container/item convention, with the `tab` module versus `tabs` token split stated.
|
|
74
|
+
- Pagination: items are documented as `.btn.ghost` with chevrons on Previous/Next, so `aria-current="page"` is the only filled item.
|
|
75
|
+
- Rich text: `demo/templates/rich-text.html` is now an `@lekoala/rich-text` integration (`@0.2` from jsDelivr) instead of a hand-wired Squire prototype, with the skin reduced to a `--rt-*` token bridge plus a rich composer reusing `.composer` chrome.
|
|
76
|
+
|
|
77
|
+
## [0.10.0] - 2026-09-25
|
|
78
|
+
|
|
79
|
+
### Breaking changes
|
|
80
|
+
|
|
81
|
+
- `.inverted` is removed: it mixed a contrasting surface with theme inversion while remapping only part of the palette. Use a `data-theme` island for a complete light/dark subtree, or paint a local band in application CSS.
|
|
82
|
+
- `.white-space-normal` is renamed `.text-wrap`, the counterpart of `.text-nowrap`.
|
|
83
|
+
- `.dialog-close`, `.drawer-close`, and `.alert-dismiss` are replaced by the shared `.close` (`components/close.css`); a modular build imports it next to its host.
|
|
84
|
+
- A removable badge needs `<button class="close">`: a bare `.badge > button` is no longer styled, and an empty one no longer paints an X.
|
|
85
|
+
- `--alert-dismiss-size` and `--badge-dismiss-icon-size` are replaced by `--close-size` / `--close-icon-size`.
|
|
86
|
+
- The dialog corner applies to a `.close` that is a direct child of the dialog, of its `form` or `header`, or of a `form` inside that header.
|
|
87
|
+
- `getSurfaceAutoClose` is removed from `surface.js`: it had no caller, and the code that opens a surface passes its own `autoClose`.
|
|
88
|
+
- `.column-span-1…12` and `.column-start-1…12` are replaced by the `--column-span` / `--column-start` hooks on each `.column-layout` child.
|
|
89
|
+
- The bare `actual-css` entrypoint resolves to the complete compiled framework, like `actual-css/full`, `style`, `unpkg`, and `jsdelivr`; import `actual-css/css` for the core alone.
|
|
90
|
+
- `package.json#main` is removed.
|
|
91
|
+
- `dist/actual.css` and `dist/actual.min.css` are no longer built or published; compose the core from `actual-css/css`.
|
|
92
|
+
- `dist/actual.js` (the compiled loader alone) is no longer built or published; bundle your own entry from `actual-css/js` and `actual-css/js/*`.
|
|
93
|
+
- `.input`, `.textarea`, `.select`, and an open custom select draw a `--focus-ring-width` inset outline in `--focus` instead of a focus border plus outer halo.
|
|
94
|
+
- `.join` no longer moves a field's focus ring onto the group: each segment keeps its own indicator.
|
|
95
|
+
- `.btn`, `.close`, `.check`, `.radio`, `.switch`, `.choice-card`, `.file`, and `.color` draw a solid `--focus-ring-width` line in `--focus` at `--focus-outline-offset` instead of a translucent halo.
|
|
96
|
+
- `.range` thumb focus ring is solid `--focus` instead of `--focus-ring`.
|
|
97
|
+
- `--focus-ring` and `--focus-ring-shadow` are removed; every focus indicator reads `--focus`.
|
|
98
|
+
- `--btn-focus-color` and `--btn-focus-ring-color` are removed: a button's focus color no longer follows its intent.
|
|
99
|
+
- `.check`, `.radio`, and `.switch` keep their resting border on focus instead of switching it to `--focus`.
|
|
100
|
+
- The default `--focus` is `hsl(268 30% 55%)` in both schemes instead of `var(--neutral)`: a primary-hued mid-tone that holds 3:1 against `--surface` and `--surface-solid`.
|
|
101
|
+
- `--focus-ring-width` is `2px` instead of `3px`, and `3px` instead of `4px` under `prefers-contrast: more`.
|
|
102
|
+
- `bootstrap-v6` sets `--focus: #3d8bfd` and `--focus-ring-width: 3px` instead of its own ring recipe.
|
|
103
|
+
|
|
104
|
+
### Added
|
|
105
|
+
|
|
106
|
+
- `.bleed` is a shared surface contract: `src/css/components/bleed.css` reads the relayed `--surface-pad`, so a direct child of a `.drawer` or of an accordion panel escapes its inset like a card child already did.
|
|
107
|
+
- `--accordion-pad` hook: the summary row and the panel no longer hard-code their inset, and the panel relays it so `.accordion.separated` items accept a `.bleed` child.
|
|
108
|
+
- `--accordion-marker-size` hook.
|
|
109
|
+
- `.data-list.stacked`: the value sits under its term instead of beside it.
|
|
110
|
+
- `--bleed-pad` is a public read-only hook: `padding: var(--bleed-pad)` pads a `.bleed` band that is not a header, footer, or figure.
|
|
111
|
+
- `.join` supports a control nested one wrapper level deep (e.g. a combobox element): the wrapper carries the group corners and primary-edge `z-index`, the inner control inherits the radius, and no widget is named.
|
|
112
|
+
- `.nav-link` works on a `<button>`: UA button chrome is neutralized with `<a>`-identical metrics.
|
|
113
|
+
- `material` demo theme: Material 3 baseline palette, filled underline fields and addons whose focus thickens the bottom line, pill buttons, and a joined outline action drawn as one more filled segment.
|
|
114
|
+
- `.choice-card.chip`: compact pill form for filter chips and selectable tags, with a leading dot that turns into the check without moving the label.
|
|
115
|
+
- `--choice-chip-dot` is a read-only hook on the chip's `::before`: the check-slot centre, so a theme can grow the dot's `circle()` clip into a selected fill.
|
|
116
|
+
- The `material` theme grows the chip dot into a tonal fill.
|
|
117
|
+
- The `gradient` theme demos the outer-halo field focus; `bootstrap-v6` and `edge` have no field focus override.
|
|
118
|
+
- `demo/templates/contrast-contexts.html`: the page, `data-theme` islands, a card island, a named theme and an application-painted band with every intent variant, a form, a combobox, a date picker and focus lines measured live, plus a `.join` gallery with no focus adaptation.
|
|
119
|
+
|
|
120
|
+
### Fixed
|
|
121
|
+
|
|
122
|
+
- `dialog.js` only backdrop-dismisses when the press started on the backdrop: a text selection released over the backdrop no longer closes (or shakes) the dialog.
|
|
123
|
+
- `dialog.js` restores the horizontal scroll position on open, not just the vertical one.
|
|
124
|
+
- `tab.js`, `focus-group.js`, `menu.js`, and the flyout trigger ignore IME-composed and ctrl/alt/meta-modified keys; `escape.js` ignores composition too.
|
|
125
|
+
- `status.js` restores its bar when the host dialog was removed from the DOM (htmx/Turbo swap): the next `status()` heals instead of no-opping forever.
|
|
126
|
+
- `tooltip.js` resynchronizes shorthand `data-tooltip` text on every show, so a "Copy" → "Copied!" update displays without rewiring.
|
|
127
|
+
- The text of a visible shorthand tip updates on the next show, never mid-flight.
|
|
128
|
+
- `flyout.js` sets `aria-haspopup="menu"` only for a true `role="menu"` panel: `<menu>` carries the implicit list role.
|
|
129
|
+
- `dialog.js` respects `closedby="none"` on `cancel` when `HTMLDialogElement.closedBy` is unavailable, while explicit close requests still work.
|
|
130
|
+
- `dialog.js` restores generated ARIA attributes, title IDs, and rewritten `closedby` values on disconnect without overwriting author changes.
|
|
131
|
+
- A last `.bleed` child of an accordion panel had square corners over the rounded `.separated` item or the group's last item.
|
|
132
|
+
- `applyEnhancement("validation", …)` did not wire an already-connected form: `validation.js` now registers through `registerEnhancement`.
|
|
133
|
+
- `--app-nav-side-size` was invisible to `check:css-api` (header read `Public hook:`).
|
|
134
|
+
- A custom `data-theme` on `<html>` kept the default palette's `--*-soft-fg` calibration instead of resetting it, so the same theme resolved a different soft ink on `<html data-theme>` than on a nested island.
|
|
135
|
+
- `.nav-link` hover/current and `.app-nav` hover fill with a tint of their own ink and follow `--ui-fg`, so they read on a bar with its own `--ui-bg`.
|
|
136
|
+
- `.flyout` owns `color: var(--text)`, like modal and drawer.
|
|
137
|
+
- Preset themes: every `--focus` is a mid-tone that holds 3:1 on `--surface` and `--surface-solid`, and a `--soft-fg-mix` keeps every soft ink at 4.5:1 (`report:theme-contrast` lists no failing pair).
|
|
138
|
+
- `report:theme-contrast` measures `.badge.soft` explicitly, so a preset that fills badges by default (`bootstrap-v6`) is no longer reported against a solid pair.
|
|
139
|
+
- `ocean` theme: light `--danger` darkened (solid text 4.1:1 → 5.2:1), `--soft-fg-mix: 50%` (soft inks from 2.0–4.3:1 to ≥ 4.8:1), and a mid-tone `--focus` that holds 3:1 on both surfaces.
|
|
140
|
+
- `.join-addon` honours `--control-border-block-end-color` / `-width` like text controls, so a theme's underline or accent edge reaches the addon segment.
|
|
141
|
+
- `gradient` theme: the focus halo follows validation (`--form-invalid-border`), and it and `material` restyle the open customizable select with their field focus instead of the core `:open` outline.
|
|
142
|
+
- `--dialog-focus-bleed` and `--drawer-focus-bleed` reserve `max(--focus-ring-width, 2 × --border-width)` past the offset, so a 3px component line (`bootstrap-v6`) is no longer clipped by 1px in a scrollable modal or drawer body.
|
|
143
|
+
- A focused field in `.join` stacks above an adjacent field (`z-index: 4` rule now follows the primary-edge rule), so the neighbour no longer covers its shared edge.
|
|
144
|
+
- A field wrapped one level deep in `.join` fills its stretched wrapper (`block-size: 100%`) instead of stopping short of a taller sibling.
|
|
145
|
+
- Focus indicators on a `--surface-solid` band and on a card nested in it hold 3:1 (a primary button's ring measured 1.1:1, a neutral one in a nested card 1.0:1).
|
|
146
|
+
|
|
5
147
|
### Documentation and tooling
|
|
6
148
|
|
|
7
|
-
-
|
|
149
|
+
- Combobox: the bridge recipe targets `@lekoala/combobox` 0.5.0, replaces its halo with the field inset outline, reads `--form-invalid-border`, and inherits `.join` corners.
|
|
150
|
+
- `tests/browser/field-focus.test.js` asserts the field outline stays inside the border box (default and `prefers-contrast`) and that `--focus` holds 3:1 on `--surface` and `--surface-solid` in both schemes.
|
|
151
|
+
- `bun run report:theme-contrast` also reports each preset's `--focus` against `--surface` and `--surface-solid`.
|
|
152
|
+
- Theming: "Make a dark (or light) section" replaces the `.inverted` recipe — a `data-theme` island for a whole context, application CSS for a painted band.
|
|
153
|
+
- Button: a dark button (formerly `.btn.inverted`) is a custom intent, `--intent: var(--surface-solid)` / `--intent-fg: var(--surface)`.
|
|
154
|
+
- `demo/templates/surfaces.html` is removed; `contrast-contexts.html` covers surface boundaries.
|
|
155
|
+
- `tests/browser/inverted.test.js` becomes `surface-context.test.js`, on an application-painted band.
|
|
156
|
+
- Pushing a version tag publishes the GitHub release: `bun run release` bumps, dates, rebuilds, commits and tags on the bare format, `bun run release:notes` extracts (and validates) the dated changelog section, and the CI `release` job attaches `dist/`.
|
|
157
|
+
- Theming: a "Replace the palette with my own brand" entry names the tinted neutrals and soft-ink tokens a partial override leaves behind, and points at the minimal recolor set.
|
|
158
|
+
- Tokens: the minimal recolor theme includes `--shadow-color`.
|
|
159
|
+
- Tokens: a "Where a token is declared" section separates global, component-scoped, and relay properties, and shows the `var(--card-pad, <default>)` form for reading a component hook from outside.
|
|
160
|
+
- Button: `--ui-bg` is the lever for an opaque fill under an intent-colored border, which no shared variant expresses; the rule must load after Actual CSS.
|
|
161
|
+
- Accordion: the marker is a masked box, so a decorated marker needs a real element — the opt-out recipe paints the chevron and keeps the hover and forced-colors behavior.
|
|
162
|
+
- `llms.txt` lists the four `data-enhance` tokens and what the vocabulary does not have (compound intents, breakpoint prefixes, spacing scale, `is-*`, standalone modifiers).
|
|
163
|
+
- `parseHookSections` throws on a near-miss section label (`Public hook:`) instead of silently dropping the hooks under it.
|
|
164
|
+
- `components.json`: an entry no longer lists another component's class it only styles (`bleed` → `card`), and `plumbingHooks` carries the "Framework plumbing:" section.
|
|
165
|
+
- Progressive enhancement guide: built-in `data-*` behaviors expose no `refresh()`; insert the element with its attribute set.
|
|
166
|
+
- `utilities/extra.css` header no longer calls extra utilities non-API.
|
|
167
|
+
- `skills/actual-css/`: a copyable starter agent skill for building with Actual CSS, shipped in the package and pointed to from the README and `llms.txt`.
|
|
168
|
+
- Install docs lead with modular source imports; the full bundle is the zero-config and CDN option.
|
|
169
|
+
- Modular import guide: "Start from the full entry" copies `actual.full.css` / `full.js` into the app and prunes them, and names the three shared CSS modules (`close`, `bleed`, `spinner`).
|
|
170
|
+
- Tailwind v4 guide: explicit layer order plus the `--font-sans` / `--font-mono` / `--font-weight-*` / `--radius-*` token collisions.
|
|
171
|
+
- Choice cards: the CSS hooks list `--choice-card-border`, `--choice-card-bg`, and `--choice-chip-dot`.
|
|
172
|
+
- `tests/browser/choice-chip.test.js` asserts the chip label never moves on check, the native inputs stay the controls, Tab focus draws the outer ring, and forced colors keep checked distinct.
|
|
173
|
+
- Theming: a `data-theme` island paints nothing; give it a surface, and put it on a wrapper rather than a `<fieldset>`, whose legend straddles the border.
|
|
174
|
+
- `demo/scripts/theme-picker.js`: every demo page uses one `<theme-picker>` fed by a single theme list, replacing 30 hand-copied selects and `admini-theme.js`.
|
|
175
|
+
- `check:templates` fails when `theme-picker.js` drifts from `src/css/themes/index.css` or a page hand-copies a theme list.
|
|
8
176
|
|
|
9
177
|
|
|
10
178
|
## [0.9.2] - 2026-09-22
|
package/README.md
CHANGED
|
@@ -14,42 +14,46 @@ prefix transform.
|
|
|
14
14
|
npm install actual-css
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
Import
|
|
17
|
+
### Import what you use
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
`actual-css/full` ships every functional family. The bare `actual-css` entrypoint is the minimal core (reset, tokens, theme, base, intents, variants, focus, print).
|
|
24
|
-
|
|
25
|
-
Or import only the pieces you use:
|
|
19
|
+
Copy the package's `src/css/actual.full.css` into your project as your entry,
|
|
20
|
+
rewrite its relative imports to package paths, and delete what you do not need
|
|
21
|
+
— see [Start from the full entry](docs/pages/guides/modular-import.md#start-from-the-full-entry):
|
|
26
22
|
|
|
27
23
|
```css
|
|
28
|
-
@import "actual-css/css";
|
|
24
|
+
@import "actual-css/css"; /* core */
|
|
29
25
|
@import "actual-css/css/layout";
|
|
26
|
+
@import "actual-css/css/forms/all";
|
|
30
27
|
@import "actual-css/css/components/button";
|
|
31
28
|
@import "actual-css/css/components/card";
|
|
32
|
-
@import "actual-css/css/forms";
|
|
33
|
-
@import "actual-css/css/components/flyout";
|
|
34
29
|
@import "actual-css/css/utilities";
|
|
35
30
|
```
|
|
36
31
|
|
|
37
|
-
`actual-css/css` is the
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
complete Forms family.
|
|
42
|
-
[modular import guide](docs/pages/guides/modular-import.md)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
32
|
+
`actual-css/css` is the core (reset, tokens, theme, base, intents, variants,
|
|
33
|
+
focus, print). Family manifests (`css/layout`, `css/components`,
|
|
34
|
+
`css/typography`, `css/effects`, `css/utilities`) and their modules map
|
|
35
|
+
one-to-one to `src/css/`; `css/forms` is the exception — it points at the
|
|
36
|
+
native-controls base, with `css/forms/all` exposing the complete Forms family.
|
|
37
|
+
See the [modular import guide](docs/pages/guides/modular-import.md#family-manifests)
|
|
38
|
+
for the full map.
|
|
39
|
+
|
|
40
|
+
Flatten the composition for production with
|
|
41
|
+
`npx actual-css bundle src/app.css --out public/app.css --minify`. The CLI
|
|
42
|
+
resolves package subpaths and relative files, then inlines them without
|
|
47
43
|
transpiling modern CSS.
|
|
48
44
|
|
|
49
|
-
|
|
45
|
+
### Full bundle (zero-config)
|
|
46
|
+
|
|
47
|
+
The bare `actual-css` entrypoint and `actual-css/full` both resolve to the
|
|
48
|
+
complete compiled framework — useful for prototypes, CDN usage, or when bundle
|
|
49
|
+
size is not worth optimizing:
|
|
50
|
+
|
|
51
|
+
```css
|
|
52
|
+
@import "actual-css/full";
|
|
53
|
+
```
|
|
50
54
|
|
|
51
55
|
```html
|
|
52
|
-
<link rel="stylesheet" href="actual.full.min.css">
|
|
56
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/actual-css@0.11/dist/actual.full.min.css">
|
|
53
57
|
```
|
|
54
58
|
|
|
55
59
|
## Usage
|
|
@@ -65,7 +69,7 @@ Add classes to your HTML. Components define the structure, variants change the s
|
|
|
65
69
|
|
|
66
70
|
Intents such as `.primary`, `.secondary`, `.success`, `.warning`, and `.danger` work across components.
|
|
67
71
|
|
|
68
|
-
Variants such as `.solid`, `.soft`, `.outline`, and `.surface` are shared by components like buttons, badges, alerts, and cards.
|
|
72
|
+
Variants such as `.solid`, `.soft`, `.outline`, and `.surface` are shared by components like buttons, badges, alerts, and cards. A dark or light section is a `data-theme` island. `.ghost` and `.link` are button-only variants.
|
|
69
73
|
|
|
70
74
|
Size variants `.sm` and `.lg` scale typography and participating component
|
|
71
75
|
geometry consistently. Density contexts `.compact` and `.spacious` change
|
|
@@ -80,7 +84,7 @@ Actual CSS uses a small unprefixed class grammar:
|
|
|
80
84
|
.component [intent] [variant] [size] [modifier]
|
|
81
85
|
```
|
|
82
86
|
|
|
83
|
-
Components, layout helpers, form helpers, and utilities claim their documented class names. Intents are `.primary`, `.secondary`, `.success`, `.warning`, and `.danger`; shared variants are `.solid`, `.soft`, `.outline`, and `.surface`;
|
|
87
|
+
Components, layout helpers, form helpers, and utilities claim their documented class names. Intents are `.primary`, `.secondary`, `.success`, `.warning`, and `.danger`; shared variants are `.solid`, `.soft`, `.outline`, and `.surface`; button-only variants are `.ghost` and `.link`; shared sizes are `.sm` and `.lg`; density contexts are `.compact` and `.spacious`.
|
|
84
88
|
|
|
85
89
|
Undocumented `is-*` classes are runtime internals.
|
|
86
90
|
|
|
@@ -108,8 +112,8 @@ The family manifests are the module catalog: `core`, `layout`, `typography`,
|
|
|
108
112
|
`forms`, `components`, `effects`, and `utilities` under `src/css/`, each with
|
|
109
113
|
an `index.css` manifest and per-module files. Import a manifest to get the
|
|
110
114
|
family, or a single file for one module. See the
|
|
111
|
-
[modular import guide](docs/pages/guides/modular-import.md)
|
|
112
|
-
of module names to import paths.
|
|
115
|
+
[modular import guide](docs/pages/guides/modular-import.md#family-manifests)
|
|
116
|
+
for the full map of module names to import paths.
|
|
113
117
|
|
|
114
118
|
## JavaScript enhancers
|
|
115
119
|
|
|
@@ -117,32 +121,38 @@ Some components can be enhanced with JavaScript: dialog/drawer, flyout, tooltip,
|
|
|
117
121
|
|
|
118
122
|
Presentation (`class`) and behaviour (`data-enhance`) are separate layers — import any primitive independently to build custom widgets. See [enhancement contract](docs/design-notes/enhancement-contract.md) and [widget primitives](docs/design-notes/widget-primitives.md).
|
|
119
123
|
|
|
120
|
-
|
|
124
|
+
Two ways to load it — pick one, never both, since each copy owns its own
|
|
125
|
+
registries:
|
|
121
126
|
|
|
122
|
-
|
|
123
|
-
<script src="actual.full.js" type="module"></script>
|
|
124
|
-
```
|
|
127
|
+
* **Full runtime, zero-config** — every built-in enhancer, compiled:
|
|
125
128
|
|
|
126
|
-
|
|
129
|
+
```html
|
|
130
|
+
<script src="https://cdn.jsdelivr.net/npm/actual-css@0.11/dist/actual.full.js" type="module"></script>
|
|
131
|
+
```
|
|
127
132
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
import "actual-css/js
|
|
134
|
-
|
|
133
|
+
* **Your own build** — copy the package's `src/js/full.js` as your entry,
|
|
134
|
+
rewrite its imports to package paths, keep the enhancers you need, and
|
|
135
|
+
bundle it with your app:
|
|
136
|
+
|
|
137
|
+
```js
|
|
138
|
+
import "actual-css/js"; // enhancement-manifest loader (optional)
|
|
139
|
+
import "actual-css/js/dialog";
|
|
140
|
+
import "actual-css/js/flyout";
|
|
141
|
+
import "actual-css/js/tooltip";
|
|
142
|
+
```
|
|
135
143
|
|
|
136
|
-
|
|
144
|
+
Modular entrypoints map to source files and import `@lekoala/floating` as a bare specifier, so they need a bundler or an import map. JavaScript modules are safe to import during server-side rendering; outside a browser, registration is a no-op.
|
|
137
145
|
|
|
138
|
-
For project-specific behavior, use `actual-css/js/enhance` and the small input helpers rather than patching built-in modules. See [
|
|
146
|
+
For project-specific behavior, use `actual-css/js/enhance` and the small input helpers rather than patching built-in modules. See the [progressive enhancement guide](docs/pages/guides/progressive-enhancement.md#extending-the-runtime) for custom filters, textarea autogrow, ajax forms, and htmx-like patterns.
|
|
139
147
|
|
|
140
148
|
## Distribution
|
|
141
149
|
|
|
142
|
-
* `dist/actual.css` — readable core CSS.
|
|
143
|
-
* `dist/actual.min.css` — the core, minified for production.
|
|
144
150
|
* `dist/actual.full.css` — readable full-bundle CSS (every family).
|
|
145
|
-
* `dist/actual.full.min.css` — the full bundle, minified
|
|
151
|
+
* `dist/actual.full.min.css` — the full bundle, minified (`actual-css`, `actual-css/full`).
|
|
152
|
+
* `dist/actual.full.js` — the complete runtime, every built-in enhancer registered.
|
|
153
|
+
|
|
154
|
+
Only the full framework is compiled. To compose, import the sources:
|
|
155
|
+
`actual-css/css/*` for CSS, `actual-css/js/*` for JavaScript.
|
|
146
156
|
|
|
147
157
|
Modern syntax such as `light-dark()`, `color-mix()`, `@container`, `:has()`, `100dvh`, and `100vi` is preserved in the distributed files.
|
|
148
158
|
|
|
@@ -179,6 +189,17 @@ Actual CSS is layer-compatible, not layer-dependent. The default `actual.css` fi
|
|
|
179
189
|
|
|
180
190
|
Actual CSS uses AI-assisted tooling for code generation, refactoring, and debugging. Patterns and architecture come from hand-written prototypes and iterative human-driven refinement. AI output is reviewed, tested, and owned by the maintainer.
|
|
181
191
|
|
|
192
|
+
## Coding agents
|
|
193
|
+
|
|
194
|
+
Actual CSS ships a starter agent skill under [`skills/actual-css/`](skills/actual-css/).
|
|
195
|
+
|
|
196
|
+
It teaches coding agents how to use the framework's vocabulary, public hooks,
|
|
197
|
+
layout primitives and progressive enhancements without recreating framework
|
|
198
|
+
behavior in application CSS.
|
|
199
|
+
|
|
200
|
+
Copy it into your project's agent skills and extend it with your application's
|
|
201
|
+
theme, loaded modules and local conventions.
|
|
202
|
+
|
|
182
203
|
## License
|
|
183
204
|
|
|
184
205
|
MIT
|
package/components.json
CHANGED
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
],
|
|
11
11
|
"publicHooks": [
|
|
12
12
|
"--accordion-radius",
|
|
13
|
-
"--accordion-
|
|
13
|
+
"--accordion-pad",
|
|
14
|
+
"--accordion-marker-color",
|
|
15
|
+
"--accordion-marker-size"
|
|
14
16
|
],
|
|
15
17
|
"states": [
|
|
16
18
|
"open"
|
|
@@ -34,7 +36,6 @@
|
|
|
34
36
|
"classes": [
|
|
35
37
|
"admonition",
|
|
36
38
|
"alert",
|
|
37
|
-
"alert-dismiss",
|
|
38
39
|
"callout"
|
|
39
40
|
],
|
|
40
41
|
"publicHooks": [
|
|
@@ -43,7 +44,6 @@
|
|
|
43
44
|
"--alert-font-size",
|
|
44
45
|
"--alert-radius",
|
|
45
46
|
"--alert-icon-size",
|
|
46
|
-
"--alert-dismiss-size",
|
|
47
47
|
"--alert-border-inline-start-color",
|
|
48
48
|
"--alert-border-inline-start-width"
|
|
49
49
|
],
|
|
@@ -53,8 +53,7 @@
|
|
|
53
53
|
"--alert-default-border",
|
|
54
54
|
"--alert-bg",
|
|
55
55
|
"--alert-fg",
|
|
56
|
-
"--alert-border"
|
|
57
|
-
"--alert-dismiss-icon-size"
|
|
56
|
+
"--alert-border"
|
|
58
57
|
]
|
|
59
58
|
},
|
|
60
59
|
{
|
|
@@ -114,8 +113,7 @@
|
|
|
114
113
|
"--badge-font-size",
|
|
115
114
|
"--badge-icon-size",
|
|
116
115
|
"--badge-dot-size",
|
|
117
|
-
"--badge-radius"
|
|
118
|
-
"--badge-dismiss-icon-size"
|
|
116
|
+
"--badge-radius"
|
|
119
117
|
],
|
|
120
118
|
"internalHooks": [
|
|
121
119
|
"--badge-default-bg",
|
|
@@ -132,6 +130,20 @@
|
|
|
132
130
|
"disabled"
|
|
133
131
|
]
|
|
134
132
|
},
|
|
133
|
+
{
|
|
134
|
+
"name": "bleed",
|
|
135
|
+
"source": "src/css/components/bleed.css",
|
|
136
|
+
"cssImport": "actual-css/css/components/bleed",
|
|
137
|
+
"classes": [
|
|
138
|
+
"bleed"
|
|
139
|
+
],
|
|
140
|
+
"publicHooks": [
|
|
141
|
+
"--bleed-pad"
|
|
142
|
+
],
|
|
143
|
+
"plumbingHooks": [
|
|
144
|
+
"--surface-pad"
|
|
145
|
+
]
|
|
146
|
+
},
|
|
135
147
|
{
|
|
136
148
|
"name": "breadcrumb",
|
|
137
149
|
"source": "src/css/components/breadcrumb.css",
|
|
@@ -172,7 +184,6 @@
|
|
|
172
184
|
"--btn-min-size",
|
|
173
185
|
"--btn-pad-x",
|
|
174
186
|
"--btn-radius",
|
|
175
|
-
"--btn-focus-color",
|
|
176
187
|
"--btn-gap",
|
|
177
188
|
"--btn-hover-overlay",
|
|
178
189
|
"--btn-default-bg",
|
|
@@ -185,7 +196,6 @@
|
|
|
185
196
|
"--btn-fg",
|
|
186
197
|
"--btn-border",
|
|
187
198
|
"--btn-default-hover-bg",
|
|
188
|
-
"--btn-focus-ring-color",
|
|
189
199
|
"--btn-border-block-end-color",
|
|
190
200
|
"--btn-border-block-end-width",
|
|
191
201
|
"--spinner-width"
|
|
@@ -243,12 +253,25 @@
|
|
|
243
253
|
"--chat-bubble-border"
|
|
244
254
|
]
|
|
245
255
|
},
|
|
256
|
+
{
|
|
257
|
+
"name": "close",
|
|
258
|
+
"source": "src/css/components/close.css",
|
|
259
|
+
"cssImport": "actual-css/css/components/close",
|
|
260
|
+
"classes": [
|
|
261
|
+
"close"
|
|
262
|
+
],
|
|
263
|
+
"publicHooks": [
|
|
264
|
+
"--close-size",
|
|
265
|
+
"--close-icon-size"
|
|
266
|
+
]
|
|
267
|
+
},
|
|
246
268
|
{
|
|
247
269
|
"name": "data-list",
|
|
248
270
|
"source": "src/css/components/data-list.css",
|
|
249
271
|
"cssImport": "actual-css/css/components/data-list",
|
|
250
272
|
"classes": [
|
|
251
|
-
"data-list"
|
|
273
|
+
"data-list",
|
|
274
|
+
"stacked"
|
|
252
275
|
]
|
|
253
276
|
},
|
|
254
277
|
{
|
|
@@ -257,7 +280,6 @@
|
|
|
257
280
|
"cssImport": "actual-css/css/components/drawer",
|
|
258
281
|
"classes": [
|
|
259
282
|
"drawer",
|
|
260
|
-
"drawer-close",
|
|
261
283
|
"is-static"
|
|
262
284
|
],
|
|
263
285
|
"publicHooks": [
|
|
@@ -304,7 +326,8 @@
|
|
|
304
326
|
],
|
|
305
327
|
"publicHooks": [
|
|
306
328
|
"--flyout-inline-size",
|
|
307
|
-
"--flyout-max-inline-size"
|
|
329
|
+
"--flyout-max-inline-size",
|
|
330
|
+
"--flyout-pad"
|
|
308
331
|
],
|
|
309
332
|
"internalHooks": [
|
|
310
333
|
"--menu-item-size",
|
|
@@ -430,7 +453,6 @@
|
|
|
430
453
|
"source": "src/css/components/modal.css",
|
|
431
454
|
"cssImport": "actual-css/css/components/modal",
|
|
432
455
|
"classes": [
|
|
433
|
-
"dialog-close",
|
|
434
456
|
"dialog-confirmation",
|
|
435
457
|
"dialog-icon",
|
|
436
458
|
"had-scrollbar",
|
|
@@ -446,7 +468,6 @@
|
|
|
446
468
|
"--dialog-icon-glyph-size"
|
|
447
469
|
],
|
|
448
470
|
"internalHooks": [
|
|
449
|
-
"--dialog-close-icon-size",
|
|
450
471
|
"--dialog-focus-bleed",
|
|
451
472
|
"--dialog-viewport-block",
|
|
452
473
|
"--dialog-viewport-gap-default",
|