diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e45cd5b..de59cfe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,6 +8,9 @@ on: branches: - main +permissions: + contents: read + jobs: quality: name: Lint, Build, Unit Tests @@ -34,6 +37,82 @@ jobs: - name: Run unit tests run: npm run test:unit + ecosystem-packs: + name: Packed Ecosystem Contract + needs: quality + runs-on: ubuntu-latest + steps: + - name: Checkout UI Style Kit + uses: actions/checkout@v6 + + - name: Setup Node + uses: actions/setup-node@v6 + with: + node-version: 20 + cache: npm + + - name: Install UI Style Kit dependencies + run: npm ci + + # The compatibility contract, rather than a mutable branch or release tag, + # selects the exact companion artifacts exercised by this integration job. + - name: Resolve immutable ecosystem fixture sources + id: ecosystem_sources + shell: bash + run: node scripts/write-ecosystem-workflow-outputs.mjs + + # The companion commits must be pushed first; checking remote object reachability + # makes that sequencing failure explicit before Actions attempts a checkout. + - name: Require pushed companion commits before UI validation + shell: bash + env: + INTERACTIVE_REPOSITORY: ${{ steps.ecosystem_sources.outputs.interactive_repository }} + INTERACTIVE_REVISION: ${{ steps.ecosystem_sources.outputs.interactive_revision }} + LAYOUT_REPOSITORY: ${{ steps.ecosystem_sources.outputs.layout_repository }} + LAYOUT_REVISION: ${{ steps.ecosystem_sources.outputs.layout_revision }} + run: | + set -euo pipefail + for source in "${INTERACTIVE_REPOSITORY}:${INTERACTIVE_REVISION}" "${LAYOUT_REPOSITORY}:${LAYOUT_REVISION}"; do + repository="${source%%:*}" + revision="${source##*:}" + fixture_dir="$(mktemp -d)" + if ! git init --bare "${fixture_dir}" >/dev/null || ! git -C "${fixture_dir}" fetch --no-tags --depth=1 "https://github.com/${repository}.git" "${revision}" >/dev/null 2>&1 || ! git -C "${fixture_dir}" cat-file -e "${revision}^{commit}"; then + echo "::error::${repository}@${revision} is unavailable. Push the companion commit, verify its remote object, then push or validate this UI branch." + rm -rf "${fixture_dir}" + exit 1 + fi + rm -rf "${fixture_dir}" + done + + - name: Checkout Layout Style CSS contract fixture + uses: actions/checkout@v6 + with: + repository: ${{ steps.ecosystem_sources.outputs.layout_repository }} + ref: ${{ steps.ecosystem_sources.outputs.layout_revision }} + path: _ecosystem/Layout-Style-CSS + + - name: Checkout Interactive Surface CSS contract fixture + uses: actions/checkout@v6 + with: + repository: ${{ steps.ecosystem_sources.outputs.interactive_repository }} + ref: ${{ steps.ecosystem_sources.outputs.interactive_revision }} + path: _ecosystem/Interactive-Surface-CSS + + - name: Install Layout Style CSS fixture dependencies + working-directory: _ecosystem/Layout-Style-CSS + run: npm ci + + - name: Install Interactive Surface CSS fixture dependencies + working-directory: _ecosystem/Interactive-Surface-CSS + run: npm ci + + - name: Install clean-consumer browser + run: npx playwright install --with-deps chromium + + # Explicit candidate mode exempts only the unpublished UI version; every companion version still comes from npm. + - name: Run PR-safe ecosystem release preflight + run: npm run release:preflight -- --candidate-package ui-style-kit-css --layout-repo $GITHUB_WORKSPACE/_ecosystem/Layout-Style-CSS --interactive-repo $GITHUB_WORKSPACE/_ecosystem/Interactive-Surface-CSS --layout-docs-repo $GITHUB_WORKSPACE/_ecosystem/Layout-Style-CSS --interactive-docs-repo $GITHUB_WORKSPACE/_ecosystem/Interactive-Surface-CSS + playwright: name: Playwright E2E needs: quality diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index be6d5e7..42e4a2e 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -122,6 +122,13 @@ jobs: - name: Install dependencies run: npm ci + # Release verification packs the immutable Task 4 companion artifacts + # selected by the checked-in compatibility contract. + - name: Resolve immutable ecosystem fixture sources + id: ecosystem_sources + shell: bash + run: node scripts/write-ecosystem-workflow-outputs.mjs + - name: Check if version already exists on npm id: npm_version_check shell: bash @@ -138,6 +145,30 @@ jobs: echo "${PACKAGE_NAME}@${PACKAGE_VERSION} is not published yet. Proceeding to publish." fi + # Publishing validates the same remote companion objects after they are + # pushed, so a release never substitutes a stale registry artifact. + - name: Require pushed companion commits before publish verification + if: steps.npm_version_check.outputs.already_published != 'true' + shell: bash + env: + INTERACTIVE_REPOSITORY: ${{ steps.ecosystem_sources.outputs.interactive_repository }} + INTERACTIVE_REVISION: ${{ steps.ecosystem_sources.outputs.interactive_revision }} + LAYOUT_REPOSITORY: ${{ steps.ecosystem_sources.outputs.layout_repository }} + LAYOUT_REVISION: ${{ steps.ecosystem_sources.outputs.layout_revision }} + run: | + set -euo pipefail + for source in "${INTERACTIVE_REPOSITORY}:${INTERACTIVE_REVISION}" "${LAYOUT_REPOSITORY}:${LAYOUT_REVISION}"; do + repository="${source%%:*}" + revision="${source##*:}" + fixture_dir="$(mktemp -d)" + if ! git init --bare "${fixture_dir}" >/dev/null || ! git -C "${fixture_dir}" fetch --no-tags --depth=1 "https://github.com/${repository}.git" "${revision}" >/dev/null 2>&1 || ! git -C "${fixture_dir}" cat-file -e "${revision}^{commit}"; then + echo "::error::${repository}@${revision} is unavailable. Push the companion commit and verify its remote object before publish verification." + rm -rf "${fixture_dir}" + exit 1 + fi + rm -rf "${fixture_dir}" + done + - name: Ensure npm token exists if: steps.npm_version_check.outputs.already_published != 'true' shell: bash @@ -157,16 +188,24 @@ jobs: if: steps.npm_version_check.outputs.already_published != 'true' run: npm run test:e2e:install:ci - # The package prepublish gate runs packed ecosystem checks against the - # staged Layout Style CSS 2.1 line before this UI package reaches npm. + # Stage the immutable companion sources so the prepublish gate packs the + # coordinated artifacts and scans their explicitly maintained documentation. - name: Checkout Layout Style CSS for publish verification if: steps.npm_version_check.outputs.already_published != 'true' uses: actions/checkout@v6 with: - repository: Foscat/Layout-Style-CSS - ref: 2.1.0 + repository: ${{ steps.ecosystem_sources.outputs.layout_repository }} + ref: ${{ steps.ecosystem_sources.outputs.layout_revision }} path: _ecosystem/Layout-Style-CSS + - name: Checkout Interactive Surface CSS documentation for publish verification + if: steps.npm_version_check.outputs.already_published != 'true' + uses: actions/checkout@v6 + with: + repository: ${{ steps.ecosystem_sources.outputs.interactive_repository }} + ref: ${{ steps.ecosystem_sources.outputs.interactive_revision }} + path: _ecosystem/Interactive-Surface-CSS + # Layout's prepack contract tests inspect its installed UI dependency, so # install its locked dependency graph before packing it as an ecosystem fixture. - name: Install Layout Style CSS dependencies for publish verification @@ -174,9 +213,23 @@ jobs: working-directory: _ecosystem/Layout-Style-CSS run: npm ci + - name: Install Interactive Surface CSS dependencies for publish verification + if: steps.npm_version_check.outputs.already_published != 'true' + working-directory: _ecosystem/Interactive-Surface-CSS + run: npm ci + + # Explicit candidate mode exempts only the UI package being published; all + # minimum and companion versions must already resolve from npm. + - name: Run ecosystem release preflight + if: steps.npm_version_check.outputs.already_published != 'true' + run: npm run release:preflight -- --candidate-package ui-style-kit-css --layout-repo $GITHUB_WORKSPACE/_ecosystem/Layout-Style-CSS --interactive-repo $GITHUB_WORKSPACE/_ecosystem/Interactive-Surface-CSS --layout-docs-repo $GITHUB_WORKSPACE/_ecosystem/Layout-Style-CSS --interactive-docs-repo $GITHUB_WORKSPACE/_ecosystem/Interactive-Surface-CSS + - name: Publish package if: steps.npm_version_check.outputs.already_published != 'true' - run: npm publish --access public + run: npm publish --access public --ignore-scripts env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} UI_STYLE_KIT_LAYOUT_REPO: ${{ github.workspace }}/_ecosystem/Layout-Style-CSS + UI_STYLE_KIT_LAYOUT_DOCS_REPO: ${{ github.workspace }}/_ecosystem/Layout-Style-CSS + UI_STYLE_KIT_INTERACTIVE_REPO: ${{ github.workspace }}/_ecosystem/Interactive-Surface-CSS + UI_STYLE_KIT_INTERACTIVE_DOCS_REPO: ${{ github.workspace }}/_ecosystem/Interactive-Surface-CSS diff --git a/.github/workflows/release-version-alignment.yml b/.github/workflows/release-version-alignment.yml index 7aea5a4..180f170 100644 --- a/.github/workflows/release-version-alignment.yml +++ b/.github/workflows/release-version-alignment.yml @@ -49,6 +49,37 @@ jobs: - name: Run full UI matrix run: npm run test:matrix + - name: Resolve immutable ecosystem fixture sources + id: ecosystem_sources + shell: bash + run: node scripts/write-ecosystem-workflow-outputs.mjs + + - name: Checkout Layout Style CSS contract fixture + uses: actions/checkout@v6 + with: + repository: ${{ steps.ecosystem_sources.outputs.layout_repository }} + ref: ${{ steps.ecosystem_sources.outputs.layout_revision }} + path: _ecosystem/Layout-Style-CSS + + - name: Checkout Interactive Surface CSS contract fixture + uses: actions/checkout@v6 + with: + repository: ${{ steps.ecosystem_sources.outputs.interactive_repository }} + ref: ${{ steps.ecosystem_sources.outputs.interactive_revision }} + path: _ecosystem/Interactive-Surface-CSS + + - name: Install Layout Style CSS fixture dependencies + working-directory: _ecosystem/Layout-Style-CSS + run: npm ci + + - name: Install Interactive Surface CSS fixture dependencies + working-directory: _ecosystem/Interactive-Surface-CSS + run: npm ci + + # Explicit candidate mode exempts only the UI tag under review while retaining every published companion check. + - name: Run ecosystem release preflight + run: npm run release:preflight -- --candidate-package ui-style-kit-css --layout-repo $GITHUB_WORKSPACE/_ecosystem/Layout-Style-CSS --interactive-repo $GITHUB_WORKSPACE/_ecosystem/Interactive-Surface-CSS --layout-docs-repo $GITHUB_WORKSPACE/_ecosystem/Layout-Style-CSS --interactive-docs-repo $GITHUB_WORKSPACE/_ecosystem/Interactive-Surface-CSS + - name: Restrict manual runs to main if: github.event_name == 'workflow_dispatch' && github.ref != 'refs/heads/main' shell: bash diff --git a/CHANGELOG.md b/CHANGELOG.md index f6d2bba..50dde7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,22 @@ All notable changes to **UI Style Kit CSS** will be documented here. +## [Unreleased] + +## [2.2.0] - 2026-08-09 + +### Added + +- Added the public 12-token shared semantic producer contract and its machine-readable manifest inventory for companion and third-party consumers. +- Implemented the manifest-backed semantic component API with 29 exact `.ui-*` selectors, context-constrained `data-ui-variant` values, and unchanged-markup runtime switching across all 11 presets. +- Added a persistent semantic component demo whose DOM nodes and classes remain stable through every preset switch. +- Documented native `` as the neutral modal/dialog fallback without inventing `.ui-modal` or `.ui-dialog` selectors. + +### Changed + +- Clarified that generated default, visual, with-bridge, and focused entrypoints provide semantic aliases, while raw preset sources, partial extras, and deprecated structural aliases remain prefixed compatibility or advanced APIs. +- Preserved `.ui-spinner` and `.ui-tooltip` as retained hooks while generating the other 27 selectors from existing preset declarations. + ## [2.1.0] - 2026-07-20 ### Added diff --git a/README.md b/README.md index 2b41f4a..4313d7b 100644 --- a/README.md +++ b/README.md @@ -9,13 +9,13 @@ It is separate from, but complementary to, **Interactive Surface CSS**. Use **UI ## Current Release -`v2.1.0` introduces a visual-only public API, a machine-readable capability manifest, a five-layer build architecture, and a canonical token-only Interactive Surface theme bridge. Existing default and focused entrypoints remain compatible, including their deprecated structural helpers, and parser-based minification remains exactly pinned. +`v2.2.0` adds the shared 12-token semantic producer contract and a manifest-backed 29-selector `.ui-*` component API across all 11 presets. Existing default and focused entrypoints remain compatible, including their deprecated structural helpers, and parser-based minification remains exactly pinned. [Showcase website](https://foscat.github.io/ui-style-kit-css/) ## How the library fits together -UI Style Kit CSS owns visual identity: themes, component paint, native HTML styling, and the prefixed class API. It can be used alone, or paired with the sibling libraries when a project needs structural layout primitives or richer interaction-state behavior. +UI Style Kit CSS owns visual identity: themes, semantic `.ui-*` component paint, native HTML styling, and the advanced prefixed class API. It can be used alone, or paired with the sibling libraries when a project needs structural layout primitives or richer interaction-state behavior. ```mermaid flowchart LR @@ -50,14 +50,18 @@ These libraries stay standalone, but the current aligned set is: | Library | Aligned version | Owns | |---|---:|---| -| `ui-style-kit-css@2.1.0` | published release | visual identity, color themes, UI paint, native HTML styling, content wrapping, and bridge tokens | -| `interactive-surface-css@1.5.0` | published release | interaction-state primitives, surface behavior, state layers, and input affordances | -| `layout-style-css@2.1.0` | staged source target | structural wrappers, grids, sections, app shells, and layout recipes | +| `ui-style-kit-css@2.2.0` | current package version | visual identity, color themes, UI paint, native HTML styling, content wrapping, and bridge tokens | +| `interactive-surface-css@1.6.0` | published release | interaction-state primitives, surface behavior, state layers, and input affordances | +| `layout-style-css@3.0.1` | published release | structural wrappers, grids, sections, app shells, and layout recipes | -UI Style Kit `2.1.0` and Interactive Surface `1.5.0` are released companion packages for this upgrade path. Layout Style `2.1.0` remains a staged source target until its separate release approval completes. +The current combination is `ui-style-kit-css@2.2.0`, `interactive-surface-css@1.6.0`, and `layout-style-css@3.0.1`. UI Style Kit `2.2.0` is the current package version, and the release pipeline treats it as the active candidate only while that exact npm version is absent. Interactive Surface `1.6.0` and Layout Style `3.0.1` are published releases. The validated minimum remains `ui-style-kit-css@2.1.0`, `interactive-surface-css@1.5.0`, and `layout-style-css@3.0.0`. Use one, two, or all three depending on the project. UI Style Kit does not require the sibling libraries, and the optional bridge only maps shared `--usk-*` roles into Interactive Surface tokens when consumers import it. +Every UI Style Kit visual or preset entrypoint also publishes a small, fully typed `--ui-*` semantic handshake. These tokens let companion libraries and third-party themes share paint, control geometry, focus, and default motion without depending on preset-specific names. They are optional fallbacks for consumers: package-specific tokens still take precedence, and standalone packages keep their existing legacy and literal defaults when the handshake is absent. See the [token contract](docs/TOKENS.md#shared-semantic-token-handshake) for the exact 12-token inventory. + +A third-party producer can load its semantic token stylesheet before `interactive-surface-css/standalone-preset.css`. UI Style Kit's visual entrypoints support the same portable composition; keep the canonical theme bridge with `state-core.css` when specialized variant, level, and icon-role mappings are required. + For import order, ownership boundaries, and adoption paths, see the [Ecosystem guide](docs/ECOSYSTEM.md). ## Features @@ -77,7 +81,7 @@ For import order, ownership boundaries, and adoption paths, see the [Ecosystem g - Visible tooltip classes and native `[role="tooltip"]` styling inside each UI scope - Font-family override variables for body, headings, controls, and mono text - Canonical token-and-paint-only theme bridge for `interactive-surface-css/state-core.css` -- Deprecated stateful bridge exports retained unchanged for backward compatibility +- Deprecated stateful bridge exports retained for backward compatibility - Reduced-motion, high-contrast, forced-colors, and print support - Cascade-layered CSS for easier consumer overrides - No runtime dependencies @@ -88,64 +92,67 @@ For import order, ownership boundaries, and adoption paths, see the [Ecosystem g npm install ui-style-kit-css ``` +### v2 distribution defaults + +The default bundle remains unchanged for all v2 releases. The root package and canonical `.` export resolve to the readable `dist/ui-style-kit.css`; the canonical `./min.css` export resolves to the minified `dist/ui-style-kit.min.css`. The focused `visual/.css` entrypoints remain available for applications fixed to one visual system. + +`ui-style-kit-css/visual.css` is the recommended entrypoint when consumers own layout. Making `visual.css` the package default remains only a v3 proposal; no v2 export is redirected as part of that proposal. + +The `./css`, `./css.css`, and `./min` exports are redundant deprecated compatibility aliases. They remain available throughout v2 with their existing targets: `./css` and `./css.css` match `.`, while `./min` matches `./min.css`. New integrations should use the canonical exports. + ## Import -Use a single style import for production apps that use one visual system: +Use the generated default bundle for semantic components that can switch across every preset at runtime: ```js -import "ui-style-kit-css/minimal-saas.css"; +import "ui-style-kit-css"; ``` -The existing focused entrypoints retain the v2 structural helpers. New integrations that already own layout should use a focused visual-only entrypoint: +Use `ui-style-kit-css/visual.css` for the same 29-selector semantic runtime API without the deprecated prefixed layout selectors. The generated default, visual, and with-bridge bundles all support all 11 `data-ui` values. + +Applications fixed to one preset can use a generated focused visual entrypoint. It includes semantic aliases scoped to that preset only: ```js import "ui-style-kit-css/visual/minimal-saas.css"; ``` -Use `ui-style-kit-css/visual.css` for runtime preset switching without the deprecated prefixed layout selectors. The exact preset, theme, mode, class, and native-part capability matrix is available from `ui-style-kit-css/manifest.json`. +The exact preset, theme, mode, class, and native-part capability matrix is available from `ui-style-kit-css/manifest.json`. -In `v2.1.0`, legacy standalone style files continue to import the shared color-scheme, native-element fallback, and content-overflow layers. Bundlers that understand CSS `@import` resolve them automatically. If your build pipeline does not resolve CSS imports, import the shared dependencies before the style file: +### Advanced prefixed and raw imports + +The standalone preset exports and longer `styles/*` paths remain advanced compatibility entrypoints. They preserve the prefixed API and do not promise multi-preset semantic switching: ```js -import "ui-style-kit-css/theme-colors.css"; -import "ui-style-kit-css/native-elements.css"; -import "ui-style-kit-css/content-overflow.css"; import "ui-style-kit-css/minimal-saas.css"; +// Equivalent raw source export: +import "ui-style-kit-css/styles/minimal-saas.css"; ``` -The longer `styles/*` paths are also exported: +In `v2.1.0`, legacy standalone style files continue to import the shared color-scheme, native-element fallback, and content-overflow layers. Bundlers that understand CSS `@import` resolve them automatically. If your build pipeline does not resolve CSS imports, import the shared dependencies before the style file: ```js -import "ui-style-kit-css/styles/minimal-saas.css"; -import "ui-style-kit-css/styles/cyberpunk.css"; +import "ui-style-kit-css/theme-colors.css"; +import "ui-style-kit-css/native-elements.css"; +import "ui-style-kit-css/content-overflow.css"; +import "ui-style-kit-css/minimal-saas.css"; ``` -Use the full bundle when users need to switch `data-ui` systems at runtime: +The explicit distribution path is also available for runtime switching: ```js import "ui-style-kit-css/dist/ui-style-kit.css"; ``` -For the canonical state-only integration, import visual paint, the token-only theme bridge, and Interactive Surface state mechanics as separate ownership layers: +For the canonical all-three integration, import visual paint, the token-only theme bridge, Interactive Surface state mechanics, and Layout structure in this order: ```js -import "ui-style-kit-css/visual/minimal-saas.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"; ``` -The older stateful bridge and combined bundle remain available for compatibility, but they are deprecated and have not been redirected to the token-only behavior: - -```js -import "ui-style-kit-css/with-bridge.css"; -``` - -Or import the bridge by itself when you are using a single style file: - -```js -import "ui-style-kit-css/minimal-saas.css"; -import "ui-style-kit-css/interactive-surface-bridge"; -``` +The older stateful bridge and combined bundle remain public, deprecated compatibility paths. See the [bridge migration guide](docs/BRIDGE-MIGRATION.md) when upgrading an existing v2 integration. The default and visual-only bundles do **not** include either bridge. That keeps UI paint independent and prevents accidental duplicate bridge imports. @@ -155,11 +162,11 @@ When the bridge is attached, add `.interactive-surface` to interactable elements | Import | Raw | Gzip | Best for | |---|---:|---:|---| -| `ui-style-kit-css/dist/ui-style-kit.min.css` | ~299 KB | ~39 KB | Compatible runtime UI-system switchers and demos | -| `ui-style-kit-css/visual.min.css` | ~290 KB | ~38 KB | Runtime visual switching with consumer-owned layout | -| `ui-style-kit-css/with-bridge.css` | ~369 KB | ~44 KB | Deprecated runtime switcher plus stateful bridge | +| `ui-style-kit-css/dist/ui-style-kit.min.css` | ~357 KB | ~44 KB | Compatible runtime UI-system switchers and demos | +| `ui-style-kit-css/visual.min.css` | ~348 KB | ~43 KB | Runtime visual switching with consumer-owned layout | +| `ui-style-kit-css/with-bridge.css` | ~431 KB | ~52 KB | Deprecated runtime switcher plus stateful bridge | | `ui-style-kit-css/theme-colors.css` | ~25 KB | ~3 KB | Shared color schemes for standalone style imports | -| `ui-style-kit-css/native-elements.css` | ~21 KB | ~3 KB | Shared native HTML fallback styling | +| `ui-style-kit-css/native-elements.css` | ~22 KB | ~4 KB | Shared native HTML fallback styling | | `ui-style-kit-css/content-overflow.css` | ~7 KB | ~1 KB | Shared long-text containment for standalone style imports | | `ui-style-kit-css/interactive-surface-theme.css` | ~8 KB | ~1 KB | Canonical token-and-paint bridge for Interactive Surface state core | | Single style imports | ~26-28 KB | ~5-6 KB | Production apps with one visual system | @@ -175,22 +182,20 @@ Use the latest published NPM package: For production, pin the exact approved release rather than relying on `latest`: ```html - + ``` ## Basic usage ```html -
-
-
-

UI Style Kit CSS

-

Switch UI systems, themes, and modes with attributes.

- - -
-
+
+
+

UI Style Kit CSS

+

Switch UI systems, themes, and modes without changing component classes.

+ + +
``` @@ -203,6 +208,47 @@ document.body.dataset.theme = "midnight-gold"; document.body.dataset.mode = "dark"; ``` +This changes the semantic components' visual preset without replacing their DOM nodes or rewriting their `.ui-*` classes. + +## Semantic component API + +`manifest.json#semanticComponentApi` is the authoritative specification for the implemented generic component API. Its 29 selectors keep the same class names while `data-ui` changes across all 11 presets. `implementationStatus` records the two retained `.ui-spinner` and `.ui-tooltip` hooks, the 27 generated semantic aliases, and an empty pending set. + +| Role | Generic selectors | Switching coverage | +|---|---|---| +| Buttons | `.ui-button`, `.ui-icon-button` | all 11 presets | +| Card | `.ui-card` | all 11 presets | +| Forms | `.ui-field`, `.ui-label`, `.ui-help-text`, `.ui-input`, `.ui-select`, `.ui-textarea` | all 11 presets | +| Choice controls | `.ui-check`, `.ui-check-control`, `.ui-radio`, `.ui-radio-control`, `.ui-switch`, `.ui-switch-track`, `.ui-switch-thumb` | all 11 presets | +| Badge | `.ui-badge` | all 11 presets | +| Alert | `.ui-alert`, `.ui-alert-title`, `.ui-alert-body` | all 11 presets | +| Navigation | `.ui-nav`, `.ui-nav-link` | all 11 presets | +| Table | `.ui-table`, `.ui-table-wrap` | all 11 presets | +| Progress | `.ui-progress`, `.ui-progress-bar` | all 11 presets | +| Toolbar | `.ui-toolbar` | all 11 presets | +| Existing generic hooks | `.ui-spinner`, `.ui-tooltip` | all 11 presets | + +The only new attribute is context-constrained `data-ui-variant`. Omit it for the neutral treatment. + +| Selector | `data-ui-variant` values | +|---|---| +| `.ui-button` | `primary`, `secondary`, `danger`, `ghost` | +| `.ui-badge` | `primary`, `secondary`, `success`, `warning`, `danger` | +| `.ui-alert` | `success`, `warning`, `danger` | + +```html + + +
...
+ +``` + +Modal and dialog roles deliberately use a neutral native `` fallback. There is no `.ui-modal` or `.ui-dialog` selector. The semantic API also does not define `data-ui-state`, `data-ui-size`, or `data-ui-placement`; continue to use native and ARIA state hooks, `.is-active`, and `[data-ui-tooltip-anchor]` where supported. + +Preset-prefixed classes remain supported compatibility and advanced APIs. Partial preset extras, typography and paint utilities, surface/size/placement helpers, shape and accessibility utilities, and the deprecated `page`, `container`, `section`, `grid`, `stack`, `cluster`, and `split` structural aliases remain prefix-bound rather than entering the generic contract. + +For example, a fixed Minimal SaaS integration may continue to use ` + Ready + +``` + +Changing only the ancestor `data-ui` value restyles that markup across all 11 presets in the generated default, visual, and with-bridge bundles. A generated `visual/.css` focused entrypoint supplies the same semantic aliases for its selected preset only. Raw `styles/*` and standalone preset exports remain advanced prefixed APIs and do not promise multi-preset semantic switching. + ## UI systems Color schemes are defined once in `styles/theme-colors.css`. Native HTML fallback selectors are defined once in `styles/native-elements.css`. Long-text containment rules are defined once in `styles/content-overflow.css`. Each UI system file imports all shared layers, aliases `--usk-*` RGB roles back to its prefix, and maps `--usk-native-*` tokens into the preset's visual identity. @@ -66,3 +79,26 @@ The bridge inherits from shared `--usk-*` color roles, then applies `.interactiv - `light` - `dark` - `contrast` + +## Semantic component contract + +The machine-readable source of truth is `manifest.json#semanticComponentApi`. Its 29 implemented generic selectors map only to source suffixes with 11-of-11 composed preset coverage. The `implementationStatus` section records `.ui-spinner` and `.ui-tooltip` as retained hooks, the other 27 selectors as generated aliases, and no pending selectors. + +| Role | Generic selector -> current source suffix | +|---|---| +| Button | `.ui-button` -> `button`; `.ui-icon-button` -> `icon-button` | +| Card | `.ui-card` -> `card` | +| Form | `.ui-field` -> `field`; `.ui-label` -> `label`; `.ui-help-text` -> `help-text`; `.ui-input` -> `input`; `.ui-select` -> `select`; `.ui-textarea` -> `textarea` | +| Choice control | `.ui-check` -> `check`; `.ui-check-control` -> `check-control`; `.ui-radio` -> `radio`; `.ui-radio-control` -> `radio-control`; `.ui-switch` -> `switch`; `.ui-switch-track` -> `switch-track`; `.ui-switch-thumb` -> `switch-thumb` | +| Badge | `.ui-badge` -> `badge` | +| Alert | `.ui-alert` -> `alert`; `.ui-alert-title` -> `alert-title`; `.ui-alert-body` -> `alert-body` | +| Navigation | `.ui-nav` -> `nav`; `.ui-nav-link` -> `nav-link` | +| Table | `.ui-table` -> `table`; `.ui-table-wrap` -> `table-wrap` | +| Progress | `.ui-progress` -> `progress`; `.ui-progress-bar` -> `progress-bar` | +| Toolbar | `.ui-toolbar` -> `toolbar` | +| Loading | `.ui-spinner` -> `spinner` | +| Tooltip | `.ui-tooltip` -> `tooltip` | + +`data-ui-variant` is the only new attribute. Omission means neutral. `.ui-button` accepts `primary`, `secondary`, `danger`, and `ghost`; `.ui-badge` accepts `primary`, `secondary`, `success`, `warning`, and `danger`; `.ui-alert` accepts `success`, `warning`, and `danger`. + +Modal and dialog roles retain native `` as their one neutral fallback; `.ui-modal` and `.ui-dialog` are not defined. Preset-prefixed classes remain supported for compatibility and advanced use. Partial preset extras and the seven deprecated structural suffixes stay out of the semantic contract. diff --git a/demo/demo.css b/demo/demo.css index 9e0b686..3aea8cf 100644 --- a/demo/demo.css +++ b/demo/demo.css @@ -107,6 +107,85 @@ min-height: 100vh; } +.demo-semantic-section { + display: grid; + gap: 1.25rem; + width: min(calc(100% - 2rem), 90rem); + margin: 1.5rem auto; +} + +.demo-semantic-heading { + max-width: 72rem; +} + +.demo-semantic-heading > * { + margin-block: 0; +} + +.demo-semantic-heading > * + * { + margin-block-start: .65rem; +} + +.demo-semantic-heading h1 { + font-size: clamp(1.8rem, 4vw, 3.6rem); + line-height: 1.05; + letter-spacing: -.035em; +} + +.demo-semantic-kicker { + font-size: .78rem; + font-weight: 850; + letter-spacing: .11em; + text-transform: uppercase; +} + +.demo-semantic-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 1rem; + align-items: start; +} + +.demo-semantic-grid > .ui-card { + display: grid; + gap: 1rem; + min-width: 0; +} + +.demo-semantic-row { + display: flex; + flex-wrap: wrap; + gap: .75rem; + align-items: center; + min-width: 0; +} + +.demo-semantic-dialog-note { + margin: 0; + overflow-wrap: anywhere; +} + +/* Keep the persistent semantic cards readable without borrowing preset-prefixed layout helpers. */ +@media (max-width: 979.98px) { + .demo-semantic-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .demo-semantic-grid > .ui-card:last-child { + grid-column: 1 / -1; + } +} + +@media (max-width: 719.98px) { + .demo-semantic-grid { + grid-template-columns: 1fr; + } + + .demo-semantic-grid > .ui-card:last-child { + grid-column: auto; + } +} + .demo-section-lede { max-width: 72rem; } diff --git a/demo/demo.js b/demo/demo.js index 5c0758c..7255f93 100644 --- a/demo/demo.js +++ b/demo/demo.js @@ -59,7 +59,7 @@ const uiSelect = document.getElementById("uiSelect"); const themeSelect = document.getElementById("themeSelect"); const modeSelect = document.getElementById("modeSelect"); const styleKitStylesheet = document.getElementById("styleKitStylesheet"); -const main = document.getElementById("main"); +const demoContent = document.getElementById("demoContent"); const skip = document.getElementById("skip"); const defaultBundle = styleKitStylesheet.dataset.defaultHref || styleKitStylesheet.getAttribute("href"); const bridgeAwareBundle = @@ -618,7 +618,8 @@ function render() { const activeColorTokens = getActiveColorTokens(); - main.innerHTML = ` + // The prefixed compatibility showcase remains dynamic while the semantic section keeps stable DOM nodes. + demoContent.innerHTML = `