Skip to content

0.10.0

Choose a tag to compare

@github-actions github-actions released this 25 Sep 18:49
· 190 commits to master since this release

Breaking changes

  • .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.
  • .white-space-normal is renamed .text-wrap, the counterpart of .text-nowrap.
  • .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.
  • A removable badge needs <button class="close">: a bare .badge > button is no longer styled, and an empty one no longer paints an X.
  • --alert-dismiss-size and --badge-dismiss-icon-size are replaced by --close-size / --close-icon-size.
  • 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.
  • getSurfaceAutoClose is removed from surface.js: it had no caller, and the code that opens a surface passes its own autoClose.
  • .column-span-1…12 and .column-start-1…12 are replaced by the --column-span / --column-start hooks on each .column-layout child.
  • 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.
  • package.json#main is removed.
  • dist/actual.css and dist/actual.min.css are no longer built or published; compose the core from actual-css/css.
  • 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/*.
  • .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.
  • .join no longer moves a field's focus ring onto the group: each segment keeps its own indicator.
  • .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.
  • .range thumb focus ring is solid --focus instead of --focus-ring.
  • --focus-ring and --focus-ring-shadow are removed; every focus indicator reads --focus.
  • --btn-focus-color and --btn-focus-ring-color are removed: a button's focus color no longer follows its intent.
  • .check, .radio, and .switch keep their resting border on focus instead of switching it to --focus.
  • 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.
  • --focus-ring-width is 2px instead of 3px, and 3px instead of 4px under prefers-contrast: more.
  • bootstrap-v6 sets --focus: #3d8bfd and --focus-ring-width: 3px instead of its own ring recipe.

Added

  • .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.
  • --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.
  • --accordion-marker-size hook.
  • .data-list.stacked: the value sits under its term instead of beside it.
  • --bleed-pad is a public read-only hook: padding: var(--bleed-pad) pads a .bleed band that is not a header, footer, or figure.
  • .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.
  • .nav-link works on a <button>: UA button chrome is neutralized with <a>-identical metrics.
  • 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.
  • .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.
  • --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.
  • The material theme grows the chip dot into a tonal fill.
  • The gradient theme demos the outer-halo field focus; bootstrap-v6 and edge have no field focus override.
  • 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.

Fixed

  • 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.
  • dialog.js restores the horizontal scroll position on open, not just the vertical one.
  • 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.
  • 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.
  • tooltip.js resynchronizes shorthand data-tooltip text on every show, so a "Copy" → "Copied!" update displays without rewiring.
  • The text of a visible shorthand tip updates on the next show, never mid-flight.
  • flyout.js sets aria-haspopup="menu" only for a true role="menu" panel: <menu> carries the implicit list role.
  • dialog.js respects closedby="none" on cancel when HTMLDialogElement.closedBy is unavailable, while explicit close requests still work.
  • dialog.js restores generated ARIA attributes, title IDs, and rewritten closedby values on disconnect without overwriting author changes.
  • A last .bleed child of an accordion panel had square corners over the rounded .separated item or the group's last item.
  • applyEnhancement("validation", …) did not wire an already-connected form: validation.js now registers through registerEnhancement.
  • --app-nav-side-size was invisible to check:css-api (header read Public hook:).
  • 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.
  • .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.
  • .flyout owns color: var(--text), like modal and drawer.
  • 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).
  • 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.
  • 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.
  • .join-addon honours --control-border-block-end-color / -width like text controls, so a theme's underline or accent edge reaches the addon segment.
  • 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.
  • --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.
  • 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.
  • A field wrapped one level deep in .join fills its stretched wrapper (block-size: 100%) instead of stopping short of a taller sibling.
  • 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).

Documentation and tooling

  • 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.
  • 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.
  • bun run report:theme-contrast also reports each preset's --focus against --surface and --surface-solid.
  • 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.
  • Button: a dark button (formerly .btn.inverted) is a custom intent, --intent: var(--surface-solid) / --intent-fg: var(--surface).
  • demo/templates/surfaces.html is removed; contrast-contexts.html covers surface boundaries.
  • tests/browser/inverted.test.js becomes surface-context.test.js, on an application-painted band.
  • Pushing a version tag publishes the GitHub release: .npmrc keeps npm version on the bare tag format, bun run release:notes extracts (and validates) the dated changelog section, and the CI release job attaches dist/.
  • 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.
  • Tokens: the minimal recolor theme includes --shadow-color.
  • 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.
  • 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.
  • 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.
  • llms.txt lists the four data-enhance tokens and what the vocabulary does not have (compound intents, breakpoint prefixes, spacing scale, is-*, standalone modifiers).
  • parseHookSections throws on a near-miss section label (Public hook:) instead of silently dropping the hooks under it.
  • components.json: an entry no longer lists another component's class it only styles (bleed → card), and plumbingHooks carries the "Framework plumbing:" section.
  • Progressive enhancement guide: built-in data-* behaviors expose no refresh(); insert the element with its attribute set.
  • utilities/extra.css header no longer calls extra utilities non-API.
  • 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.
  • Install docs lead with modular source imports; the full bundle is the zero-config and CDN option.
  • 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).
  • Tailwind v4 guide: explicit layer order plus the --font-sans / --font-mono / --font-weight-* / --radius-* token collisions.
  • Choice cards: the CSS hooks list --choice-card-border, --choice-card-bg, and --choice-chip-dot.
  • 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.
  • 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.
  • 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.
  • check:templates fails when theme-picker.js drifts from src/css/themes/index.css or a page hand-copies a theme list.