# Interactive Surface

Interactive Surface is a framework-agnostic CSS interaction primitive for buttons, cards, icon controls, and similar click targets.

It provides consistent hover, focus-visible, active, press, and disabled behavior with token-driven theming, accessibility guardrails, and minimal integration friction.

## Documentation

Project docs live in this repository:

- [Wiki Home](./wiki/Home.md)
- [Getting Started](./wiki/Getting-Started.md)
- [Installation and Usage](./wiki/Installation-and-Usage.md)
- [API Reference](./wiki/API-Reference.md)
- [Token Reference](./wiki/Token-Reference.md)
- [Accessibility](./wiki/Accessibility.md)
- [Testing and Quality](./wiki/Testing-and-Quality.md)
- [Publishing and Releases](./wiki/Publishing-and-Releases.md)
- [FAQ](./wiki/FAQ.md)
- [Roadmap](./wiki/Roadmap.md)

Community and governance docs:

- [Contributing](./CONTRIBUTING.md)
- [Code of Conduct](./CODE_OF_CONDUCT.md)
- [Security Policy](./SECURITY.md)

## Package

- Package name: `interactive-surface-css`
- Primary stylesheet: `interactive-surface.css`
- JavaScript entry: `index.js` (imports CSS for bundler-friendly usage)
- Live demo: `https://foscat.github.io/Interactive-Surface-CSS/`

Install:

```bash
npm install interactive-surface-css
```

Import:

```js
import "interactive-surface-css";
```

Or import CSS directly:

```js
import "interactive-surface-css/interactive-surface.css";
```

Note: The JavaScript entry imports CSS, so it should be used in bundlers or toolchains that support CSS imports. If you want the most portable, framework-agnostic path, import `interactive-surface-css/interactive-surface.css` directly. The package supports both approaches to accommodate different project setups and preferences.

Webpack:

1. Install loaders:

    ```bash
    npm install -D css-loader style-loader
    ```

2. Configure `webpack.config.js`:

    ```js
    module.exports = {
      module: {
        rules: [
          {
            test: /\.css$/i,
            use: ["style-loader", "css-loader"]
          }
        ]
      }
    };
    ```

3. Import in your app entry:

    ```js
    import "interactive-surface-css";
    ```

CDN:

```html
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/interactive-surface-css@latest/interactive-surface.css" />
<link rel="stylesheet" href="https://unpkg.com/interactive-surface-css@latest/interactive-surface.css" />
```

## Quick Start

```html
<button class="interactive-surface">Save</button>
```

```html
<button class="interactive-surface size-lg variant-primary">Continue</button>
```

```html
<button class="interactive-surface icon-only" aria-label="Settings">
  <svg aria-hidden="true" viewBox="0 0 24 24">...</svg>
</button>
```

Live demo: [Interactive Surface Demo](https://foscat.github.io/Interactive-Surface-CSS/)

The demo page is a practical customization playground for this library:

- It provides guided token editing controls instead of freehand CSS typing.
- It supports importing and exporting token CSS so teams can reuse exact values.
- It helps reduce manual entry mistakes when creating app-level theme overrides.

## Class API

Base:

- `.interactive-surface`

Size modifiers:

- `.size-sm`
- `.size-lg`
- medium is default when no size class is set

State helpers:

- `.is-active`
- `.is-disabled`

Semantic states:

- `[aria-pressed="true"]`
- `[aria-disabled="true"]`
- `:disabled`

Visual variants:

- `.variant-primary`
- `.variant-secondary`
- `.variant-accent`
- `.variant-subtle`
- `.variant-warning`
- `.variant-danger`

Icon pattern:

- `.icon-only`

## Token Contract

Preferred token namespace:

- `--interactive-surface-*`

The package also supports legacy fallback tokens and semantic fallback tokens. Full details and examples are in [Token Reference](./wiki/Token-Reference.md).

## Integration with UI Style Kit CSS

`interactive-surface-css` and `ui-style-kit-css` are designed to work separately and complementarily.

UI Style Kit owns visual theme tokens. Interactive Surface owns interaction behavior on `.interactive-surface`.

With `ui-style-kit-css@2.0.1`, the default full bundle does not include the bridge. Use the opt-in bridge bundle when you want UI Style Kit's runtime style switcher and Interactive Surface token mapping in one import:

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

If you use per-style UI Style Kit imports, include the bridge. This order is supported:

```js
import "ui-style-kit-css/styles/minimal-saas.css";
import "ui-style-kit-css/interactive-surface-bridge";
import "interactive-surface-css/interactive-surface.css";
```

So is the order shown in the UI Style Kit docs:

```js
import "interactive-surface-css/interactive-surface.css";
import "ui-style-kit-css/styles/minimal-saas.css";
import "ui-style-kit-css/interactive-surface-bridge";
```

The bridge maps active `data-ui`, `data-theme`, and `data-mode` tokens to Interactive Surface's public token contract, including variant, icon-role, state-layer, and optional surface-level hooks. UI Style Kit owns the bridge token mapping; Interactive Surface keeps ownership of `.interactive-surface` interaction behavior.

## Accessibility

Built-in support includes:

- `:focus-visible` behavior with fallback handling
- reduced-motion preference handling
- high-contrast and forced-colors handling
- ARIA pressed/disabled styling
- 44x44 minimum target size for `.icon-only`

See [Accessibility](./wiki/Accessibility.md) for implementation guidance.

## Testing

```bash
npm run check:no-hex-colors
npm run lint:css
npm run test:install
npm test
npm run test:chromium
npm run pack:dry
npm run validate
```

## Publishing

This repo is configured for release-driven npm publish through GitHub Actions at `.github/workflows/npm-publish.yml`.

Release checklist:

1. Add repository secret `NPM_TOKEN` (npm token with publish rights).
2. Bump `version` in `package.json`.
3. Update `CHANGELOG.md`.
4. Push to `main`.
5. Create and publish a GitHub Release tag (for example `v1.2.4`).
6. Verify the `Publish to npm` workflow succeeds.
7. Verify CDN availability:
   - `https://cdn.jsdelivr.net/npm/interactive-surface-css@<version>/interactive-surface.css`
   - `https://unpkg.com/interactive-surface-css@<version>/interactive-surface.css`

Manual fallback:

```bash
npm adduser
npm publish --access public
```

The `prepublishOnly` guard intentionally avoids browser downloads so `npm publish` does not stall on a fresh Playwright cache. Run `npm run validate` before publishing when you want the full local release check, including Playwright browser installation and tests.

## Guardrail

`interactive-surface` should be the only transform-based motion owner on its host element.

Avoid applying additional `transform`, `translate`, `scale`, or `rotate` rules to the same node. If you need extra animation, apply it to a child element.
