Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,63 @@ jobs:

- name: Validate package
run: npm run ${{ matrix.validation-script }}

release-preflight:
name: PR-safe ecosystem release preflight
if: github.event_name == 'pull_request'
needs: quality
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: read
steps:
- name: Checkout Interactive Surface candidate
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5

- name: Use Node.js 22
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
with:
node-version: 22
cache: npm

- name: Install candidate dependencies
run: npm ci

- name: Resolve immutable UI release fixture
id: ui_fixture
run: node scripts/release-fixture-contract.mjs --write-github-outputs

- name: Checkout reviewed UI release fixture
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
with:
repository: ${{ steps.ui_fixture.outputs.ui_repository }}
ref: ${{ steps.ui_fixture.outputs.ui_revision }}
path: _ecosystem/ui-style-kit-css

- name: Install UI fixture dependencies
working-directory: _ecosystem/ui-style-kit-css
run: npm ci

- name: Resolve immutable Layout companion
id: ecosystem_sources
working-directory: _ecosystem/ui-style-kit-css
run: node scripts/write-ecosystem-workflow-outputs.mjs

- name: Checkout reviewed Layout companion
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
with:
repository: ${{ steps.ecosystem_sources.outputs.layout_repository }}
ref: ${{ steps.ecosystem_sources.outputs.layout_revision }}
path: _ecosystem/Layout-Style-CSS

- name: Install Layout companion dependencies
working-directory: _ecosystem/Layout-Style-CSS
run: npm ci

- name: Install clean-consumer Chromium
working-directory: _ecosystem/ui-style-kit-css
run: npx playwright install --with-deps chromium

# Candidate override is an npm-pack tarball; the other two sources stay at reviewed immutable commits.
- name: Run read-only release preflight
run: npm run release:preflight -- --fixture-root $GITHUB_WORKSPACE/_ecosystem/ui-style-kit-css --layout-repo $GITHUB_WORKSPACE/_ecosystem/Layout-Style-CSS --layout-docs-repo $GITHUB_WORKSPACE/_ecosystem/Layout-Style-CSS --interactive-docs-repo $GITHUB_WORKSPACE
39 changes: 39 additions & 0 deletions .github/workflows/npm-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,45 @@ jobs:
- name: Validate publish package
run: npm run validate:publish

- name: Resolve immutable UI release fixture
id: ui_fixture
run: node scripts/release-fixture-contract.mjs --write-github-outputs

- name: Checkout reviewed UI release fixture
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
with:
repository: ${{ steps.ui_fixture.outputs.ui_repository }}
ref: ${{ steps.ui_fixture.outputs.ui_revision }}
path: _ecosystem/ui-style-kit-css

- name: Install UI fixture dependencies
working-directory: _ecosystem/ui-style-kit-css
run: npm ci

- name: Resolve immutable Layout companion
id: ecosystem_sources
working-directory: _ecosystem/ui-style-kit-css
run: node scripts/write-ecosystem-workflow-outputs.mjs

- name: Checkout reviewed Layout companion
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
with:
repository: ${{ steps.ecosystem_sources.outputs.layout_repository }}
ref: ${{ steps.ecosystem_sources.outputs.layout_revision }}
path: _ecosystem/Layout-Style-CSS

- name: Install Layout companion dependencies
working-directory: _ecosystem/Layout-Style-CSS
run: npm ci

- name: Install clean-consumer Chromium
working-directory: _ecosystem/ui-style-kit-css
run: npx playwright install --with-deps chromium

# This gate performs only registry reads, candidate packing, and clean-consumer validation.
- name: Run ecosystem release preflight
run: npm run release:preflight -- --fixture-root $GITHUB_WORKSPACE/_ecosystem/ui-style-kit-css --layout-repo $GITHUB_WORKSPACE/_ecosystem/Layout-Style-CSS --layout-docs-repo $GITHUB_WORKSPACE/_ecosystem/Layout-Style-CSS --interactive-docs-repo $GITHUB_WORKSPACE

- name: Publish to npm
run: npm publish --provenance --access public --ignore-scripts
env:
Expand Down
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,32 @@ All notable changes to this package are documented in this file.

## Unreleased

## 1.6.0 - 2026-08-09

### Added

- Added optional shared semantic fallbacks for standalone paint, control geometry, focus, and default motion while retaining package-specific precedence and all legacy behavior when shared tokens are absent.

### Changed

- Documented the third-party theme integration path, fallback order, and canonical UI Style Kit bridge boundary across the README and wiki without changing ownership or compatibility ranges.

### Fixed

- Preserved legacy standalone behavior when shared semantic tokens are unavailable by retaining the existing fallback chains.

### Accessibility

- Kept the established focus and motion semantics while allowing optional shared focus-color and default-motion values.

### Documentation

- Updated release-facing package, CDN, README, and wiki guidance for the unpublished `1.6.0` candidate.

### Testing

- Added focused contracts for shared semantic fallback precedence and manifest inventory while retaining generated, package, and public-export coverage.

## 1.5.0 - 2026-07-20

### Added
Expand Down
30 changes: 21 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

Framework-agnostic CSS for reliable hover, focus, press, selected, current, loading, disabled, and motion affordances on interactive controls. Use it alone or as the interaction layer beside your existing layout and theme system.

Version 1.5.0 is a release candidate in this repository until its npm release is published. Existing 1.x imports, selectors, data hooks, ARIA hooks, and tokens remain supported.
Version 1.6.0 is a release candidate in this repository until its npm release is published. Existing 1.x imports, selectors, data hooks, ARIA hooks, and tokens remain supported.

The package targets Node.js 20+ for npm installs and local validation. CI proves the minimum Node 20 lane and the preferred Node 22 lane before release.

Expand Down Expand Up @@ -56,11 +56,11 @@ For a no-build page, pin the release:
```html
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/interactive-surface-css@1.5.0/standalone-preset.css"
href="https://cdn.jsdelivr.net/npm/interactive-surface-css@1.6.0/standalone-preset.css"
/>
```

The equivalent unpkg URL is `https://unpkg.com/interactive-surface-css@1.5.0/standalone-preset.css`. To follow future releases deliberately, use `https://cdn.jsdelivr.net/npm/interactive-surface-css@latest/standalone-preset.css` — unpinned opt-in.
The equivalent unpkg URL is `https://unpkg.com/interactive-surface-css@1.6.0/standalone-preset.css`. To follow future releases deliberately, use `https://cdn.jsdelivr.net/npm/interactive-surface-css@latest/standalone-preset.css` — unpinned opt-in.

## Semantic recipes

Expand Down Expand Up @@ -127,7 +127,7 @@ Native `disabled` is preferred because the browser suppresses focus and activati
| `import "interactive-surface-css/interactive-surface.css";` | Complete standalone compatibility bundle | Existing direct-CSS 1.x consumers |
| `import "interactive-surface-css";` | JavaScript entry that imports the complete compatibility bundle | Existing bundlers configured for CSS imports |

`standalone-preset.css` and `interactive-surface.css` are generated from the same authored modules and are behaviorally equivalent in 1.5.0. The compatibility paths remain stable; no 1.x migration is required.
`standalone-preset.css` and `interactive-surface.css` are generated from the same authored modules and are behaviorally equivalent in 1.6.0. The compatibility paths remain stable; no 1.x migration is required.

The package `main` and `module` fields preserve the CommonJS and ESM entries; both load `interactive-surface.css`. The `style`, `unpkg`, and `jsdelivr` fields also resolve to that complete compatibility bundle.

Expand Down Expand Up @@ -169,6 +169,15 @@ For selector details and responsibilities, see the [complete API reference](http

The transition defaults are `translate, box-shadow, outline-color`, the established default motion duration, the standard easing curve, and zero delay. Existing `--interactive-surface-motion-*`, `--interactive-surface-ease-*`, `--motion-*`, and `--ease-*` fallbacks remain supported. All public custom properties use the `--interactive-surface-*` namespace. See the [token ownership tables and full reference](https://github.com/Foscat/Interactive-Surface-CSS/wiki/Token-Reference).

A third-party design system can theme the standalone entry point with the optional shared semantic tokens `--ui-color-surface`, `--ui-color-text`, `--ui-color-muted`, `--ui-color-primary`, `--ui-color-on-primary`, `--ui-color-border`, `--ui-radius-control`, `--ui-shadow-control`, `--ui-focus-color`, `--ui-motion-duration`, and `--ui-motion-easing`. The fallback order is package-specific `--interactive-surface-*` values, then shared semantic values, then existing legacy values and literals. When the shared tokens are absent, standalone output is unchanged.

```js
import "third-party-theme/tokens.css";
import "interactive-surface-css/standalone-preset.css";
```

Use `state-core.css` instead when the third-party theme already paints and sizes the component directly. The full token-to-property mapping is in the [token reference](https://github.com/Foscat/Interactive-Surface-CSS/wiki/Token-Reference).

## Accessibility responsibilities

The CSS package provides visible keyboard focus, persistent-state treatment, disabled precedence, reduced-motion behavior, higher-contrast behavior, forced-colors affordances, hover gating for capable pointers, and standalone icon target sizing. The `:focus-visible` ring remains orthogonal across every focusable non-disabled interaction state.
Expand All @@ -185,23 +194,26 @@ Read the [accessibility guide](https://github.com/Foscat/Interactive-Surface-CSS

## Pair with UI Style Kit CSS

When UI Style Kit owns visual paint, import its opt-in bridge and the state-only core:
When UI Style Kit owns visual paint, import its visual layer, token-and-paint bridge, and the state-only core:

```js
import "ui-style-kit-css/with-bridge.css";
import "ui-style-kit-css/visual.css";
import "ui-style-kit-css/interactive-surface-theme.css";
import "interactive-surface-css/state-core.css";
```

The bridge maps active UI Style Kit theme and mode values into the `--interactive-surface-*` contract. Interactive Surface keeps ownership of focus, hover, pressed, selected, current, loading, disabled, and motion behavior. UI Style Kit remains optional: this package declares no runtime or peer dependency on it, and the documented import order keeps its paint layer before `state-core.css`.
The token-and-paint bridge maps active UI Style Kit theme and mode values into the `--interactive-surface-*` contract. Interactive Surface keeps ownership of focus, hover, pressed, selected, current, loading, disabled, and motion behavior. UI Style Kit remains optional: this package declares no runtime or peer dependency on it, and the documented import order keeps its paint layer before `state-core.css`.

For a generic semantic integration without specialized UI Style Kit variant and level mappings, `ui-style-kit-css/visual.css` may instead precede `interactive-surface-css/standalone-preset.css`. The shared tokens cover the portable control baseline; the canonical token-and-paint bridge above remains the preferred UI Style Kit composition.

## Use all three libraries

Use the established order so paint, interaction, and structure retain clear ownership:

```js
import "ui-style-kit-css/with-bridge.css";
import "ui-style-kit-css/visual.css";
import "ui-style-kit-css/interactive-surface-theme.css";
import "interactive-surface-css/state-core.css";
import "layout-style-css/bridge.css";
import "layout-style-css";
```

Expand Down
4 changes: 4 additions & 0 deletions ecosystem-release-fixture.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"repository": "Foscat/ui-style-kit-css",
"revision": "3869ca49c11d8cc085affa25115e8e80546f7a3c"
}
30 changes: 21 additions & 9 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,7 @@ <h2 id="tokenEditorTitle">Edit token</h2>

Framework-agnostic CSS for reliable hover, focus, press, selected, current, loading, disabled, and motion affordances on interactive controls. Use it alone or as the interaction layer beside your existing layout and theme system.

Version 1.5.0 is a release candidate in this repository until its npm release is published. Existing 1.x imports, selectors, data hooks, ARIA hooks, and tokens remain supported.
Version 1.6.0 is a release candidate in this repository until its npm release is published. Existing 1.x imports, selectors, data hooks, ARIA hooks, and tokens remain supported.

The package targets Node.js 20+ for npm installs and local validation. CI proves the minimum Node 20 lane and the preferred Node 22 lane before release.

Expand Down Expand Up @@ -622,11 +622,11 @@ <h2 id="tokenEditorTitle">Edit token</h2>
```html
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/interactive-surface-css@1.5.0/standalone-preset.css"
href="https://cdn.jsdelivr.net/npm/interactive-surface-css@1.6.0/standalone-preset.css"
/>
```

The equivalent unpkg URL is `https://unpkg.com/interactive-surface-css@1.5.0/standalone-preset.css`. To follow future releases deliberately, use `https://cdn.jsdelivr.net/npm/interactive-surface-css@latest/standalone-preset.css` — unpinned opt-in.
The equivalent unpkg URL is `https://unpkg.com/interactive-surface-css@1.6.0/standalone-preset.css`. To follow future releases deliberately, use `https://cdn.jsdelivr.net/npm/interactive-surface-css@latest/standalone-preset.css` — unpinned opt-in.

## Semantic recipes

Expand Down Expand Up @@ -693,7 +693,7 @@ <h2 id="tokenEditorTitle">Edit token</h2>
| `import "interactive-surface-css/interactive-surface.css";` | Complete standalone compatibility bundle | Existing direct-CSS 1.x consumers |
| `import "interactive-surface-css";` | JavaScript entry that imports the complete compatibility bundle | Existing bundlers configured for CSS imports |

`standalone-preset.css` and `interactive-surface.css` are generated from the same authored modules and are behaviorally equivalent in 1.5.0. The compatibility paths remain stable; no 1.x migration is required.
`standalone-preset.css` and `interactive-surface.css` are generated from the same authored modules and are behaviorally equivalent in 1.6.0. The compatibility paths remain stable; no 1.x migration is required.

The package `main` and `module` fields preserve the CommonJS and ESM entries; both load `interactive-surface.css`. The `style`, `unpkg`, and `jsdelivr` fields also resolve to that complete compatibility bundle.

Expand Down Expand Up @@ -735,6 +735,15 @@ <h2 id="tokenEditorTitle">Edit token</h2>

The transition defaults are `translate, box-shadow, outline-color`, the established default motion duration, the standard easing curve, and zero delay. Existing `--interactive-surface-motion-*`, `--interactive-surface-ease-*`, `--motion-*`, and `--ease-*` fallbacks remain supported. All public custom properties use the `--interactive-surface-*` namespace. See the [token ownership tables and full reference](https://github.com/Foscat/Interactive-Surface-CSS/wiki/Token-Reference).

A third-party design system can theme the standalone entry point with the optional shared semantic tokens `--ui-color-surface`, `--ui-color-text`, `--ui-color-muted`, `--ui-color-primary`, `--ui-color-on-primary`, `--ui-color-border`, `--ui-radius-control`, `--ui-shadow-control`, `--ui-focus-color`, `--ui-motion-duration`, and `--ui-motion-easing`. The fallback order is package-specific `--interactive-surface-*` values, then shared semantic values, then existing legacy values and literals. When the shared tokens are absent, standalone output is unchanged.

```js
import "third-party-theme/tokens.css";
import "interactive-surface-css/standalone-preset.css";
```

Use `state-core.css` instead when the third-party theme already paints and sizes the component directly. The full token-to-property mapping is in the [token reference](https://github.com/Foscat/Interactive-Surface-CSS/wiki/Token-Reference).

## Accessibility responsibilities

The CSS package provides visible keyboard focus, persistent-state treatment, disabled precedence, reduced-motion behavior, higher-contrast behavior, forced-colors affordances, hover gating for capable pointers, and standalone icon target sizing. The `:focus-visible` ring remains orthogonal across every focusable non-disabled interaction state.
Expand All @@ -751,23 +760,26 @@ <h2 id="tokenEditorTitle">Edit token</h2>

## Pair with UI Style Kit CSS

When UI Style Kit owns visual paint, import its opt-in bridge and the state-only core:
When UI Style Kit owns visual paint, import its visual layer, token-and-paint bridge, and the state-only core:

```js
import "ui-style-kit-css/with-bridge.css";
import "ui-style-kit-css/visual.css";
import "ui-style-kit-css/interactive-surface-theme.css";
import "interactive-surface-css/state-core.css";
```

The bridge maps active UI Style Kit theme and mode values into the `--interactive-surface-*` contract. Interactive Surface keeps ownership of focus, hover, pressed, selected, current, loading, disabled, and motion behavior. UI Style Kit remains optional: this package declares no runtime or peer dependency on it, and the documented import order keeps its paint layer before `state-core.css`.
The token-and-paint bridge maps active UI Style Kit theme and mode values into the `--interactive-surface-*` contract. Interactive Surface keeps ownership of focus, hover, pressed, selected, current, loading, disabled, and motion behavior. UI Style Kit remains optional: this package declares no runtime or peer dependency on it, and the documented import order keeps its paint layer before `state-core.css`.

For a generic semantic integration without specialized UI Style Kit variant and level mappings, `ui-style-kit-css/visual.css` may instead precede `interactive-surface-css/standalone-preset.css`. The shared tokens cover the portable control baseline; the canonical token-and-paint bridge above remains the preferred UI Style Kit composition.

## Use all three libraries

Use the established order so paint, interaction, and structure retain clear ownership:

```js
import "ui-style-kit-css/with-bridge.css";
import "ui-style-kit-css/visual.css";
import "ui-style-kit-css/interactive-surface-theme.css";
import "interactive-surface-css/state-core.css";
import "layout-style-css/bridge.css";
import "layout-style-css";
```

Expand Down
Loading