Some checks failed
CI/CD / detect-changes (pull_request) Successful in 4s
CI/CD / build-and-deploy (pull_request) Has been cancelled
CI/CD / test-sqlite (pull_request) Has been cancelled
CI/CD / test-go-pg (pull_request) Has been cancelled
CI/CD / test-frontend (pull_request) Has been cancelled
Prefix enforcement prevents extension CSS from leaking into the kernel
or sibling extensions. All 12 in-tree packages migrated to .ext-{slug}-*
naming convention.
- Add data-ext attribute to extension mount container
- Add CSS linter (scripts/lint-package-css.sh) enforcing .ext-{slug} prefix
- Add kernel CSS contract doc (docs/EXTENSION-CSS.md)
- Migrate 12 packages: chat, dashboard, editor, git-board, hello-dashboard,
icd-test-runner, notes, schedules, sdk-test-runner, tasks,
team-activity-log, workflow-demo (CSS + JS in lockstep)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
150 lines
4.6 KiB
Markdown
150 lines
4.6 KiB
Markdown
# Extension CSS Contract
|
|
|
|
> **Version**: v0.6.12 — Extension CSS Isolation
|
|
|
|
This document defines the CSS contract between the Armature kernel and extension
|
|
packages. Extensions **must** follow these rules; the kernel guarantees the listed
|
|
classes and variables are stable public API.
|
|
|
|
---
|
|
|
|
## Naming Rule
|
|
|
|
All class selectors in extension CSS (`packages/{slug}/css/main.css`) must start
|
|
with `.ext-{slug}-`. The `{slug}` is the package directory name.
|
|
|
|
```css
|
|
/* Good */
|
|
.ext-my-app-sidebar { ... }
|
|
.ext-my-app-card { ... }
|
|
|
|
/* Bad — will be rejected by the linter */
|
|
.sidebar { ... }
|
|
.my-sidebar { ... }
|
|
```
|
|
|
|
**Compound selectors**: Descendant classes scoped under your `.ext-{slug}` root
|
|
are allowed to reference kernel classes or state modifiers:
|
|
|
|
```css
|
|
/* Allowed — kernel class scoped under extension namespace */
|
|
.ext-my-app .sw-btn { margin-top: 8px; }
|
|
|
|
/* Allowed — state modifier on an extension element */
|
|
.ext-my-app-item.active { ... }
|
|
```
|
|
|
|
Run `bash scripts/lint-package-css.sh` to validate. The linter checks that the
|
|
**first** class selector in every rule starts with `.ext-{slug}`.
|
|
|
|
---
|
|
|
|
## Stable Kernel Classes
|
|
|
|
Extensions may reference these classes in compound selectors. They are part of
|
|
the public API and will not change without a major version bump.
|
|
|
|
### Components (from `sw-primitives.css`)
|
|
|
|
| Class pattern | Component |
|
|
|---------------|-----------|
|
|
| `.sw-btn`, `.sw-btn--{variant}`, `.sw-btn--{size}` | Buttons |
|
|
| `.sw-input` | Text inputs |
|
|
| `.sw-field`, `.sw-field__label`, `.sw-field__hint` | Form fields |
|
|
| `.sw-dialog`, `.sw-dialog__header`, `.sw-dialog__body`, `.sw-dialog__footer` | Dialogs |
|
|
| `.sw-toast`, `.sw-toast-container` | Toast notifications |
|
|
| `.sw-menu`, `.sw-menu-item` | Context menus |
|
|
| `.sw-tabs`, `.sw-tab-btn` | Tab strips |
|
|
| `.sw-dropdown` | Custom dropdowns |
|
|
| `.sw-spinner` | Loading spinners |
|
|
| `.sw-avatar` | User avatars |
|
|
| `.sw-drawer` | Slide-out drawers |
|
|
| `.sw-banner` | Banner bars |
|
|
| `.sw-tooltip` | Tooltips |
|
|
|
|
### Extension Mount
|
|
|
|
The extension surface container has a `data-ext` attribute set to the package
|
|
slug. Use this for scoping if needed:
|
|
|
|
```css
|
|
[data-ext="my-app"] .ext-my-app-sidebar { ... }
|
|
```
|
|
|
|
---
|
|
|
|
## Stable CSS Variables
|
|
|
|
All variables from `variables.css` are public API. Extensions should use these
|
|
instead of hardcoded colors to respect the user's theme.
|
|
|
|
### Colors
|
|
|
|
| Variable | Purpose |
|
|
|----------|---------|
|
|
| `--bg` | Page background |
|
|
| `--bg-secondary` | Secondary/darker background |
|
|
| `--bg-elevated` | Elevated surface background |
|
|
| `--bg-raised` | Raised card background |
|
|
| `--bg-surface` | Surface-level background |
|
|
| `--bg-hover` | Hover state background |
|
|
| `--bg-active` | Active/pressed state background |
|
|
| `--bg-code` | Code block background |
|
|
| `--text` | Primary text color |
|
|
| `--text-2` | Secondary text color |
|
|
| `--text-3` | Tertiary/muted text color |
|
|
| `--text-on-color` | Text on colored backgrounds |
|
|
| `--accent` | Primary accent color |
|
|
| `--accent-dim` | Dimmed accent for backgrounds |
|
|
| `--accent-hover` | Accent hover state |
|
|
| `--accent-light` | Light accent variant |
|
|
| `--border` | Default border color |
|
|
| `--border-light` | Light border variant |
|
|
| `--border-elevated` | Border for elevated surfaces |
|
|
| `--danger` | Error/destructive color |
|
|
| `--danger-dim` | Dimmed danger background |
|
|
| `--danger-light` | Light danger variant |
|
|
| `--success` | Success/positive color |
|
|
| `--success-dim` | Dimmed success background |
|
|
| `--success-light` | Light success variant |
|
|
| `--warning` | Warning/caution color |
|
|
| `--warning-dim` | Dimmed warning background |
|
|
| `--warning-light` | Light warning variant |
|
|
| `--purple` | Purple accent |
|
|
| `--purple-dim` | Dimmed purple background |
|
|
|
|
### Layout & Typography
|
|
|
|
| Variable | Purpose |
|
|
|----------|---------|
|
|
| `--font` | Primary font family |
|
|
| `--mono` | Monospace font family |
|
|
| `--radius` | Default border-radius (8px) |
|
|
| `--radius-lg` | Large border-radius (12px) |
|
|
| `--transition` | Default transition timing |
|
|
| `--shadow-lg` | Large elevation shadow |
|
|
| `--overlay` | Modal overlay color |
|
|
| `--glass` | Glassmorphism backdrop |
|
|
| `--input-bg` | Form input background |
|
|
| `--sidebar-w` | Sidebar width |
|
|
|
|
---
|
|
|
|
## What Is Internal
|
|
|
|
Everything not listed above is **internal kernel CSS** and may change between
|
|
minor versions. Extensions must not depend on:
|
|
|
|
- Kernel layout classes (`.admin-*`, `.surface-*`, `.sidebar`, etc.)
|
|
- Kernel CSS file load order
|
|
- Specific HTML structure of the shell or topbar
|
|
- Undocumented CSS variables
|
|
|
|
---
|
|
|
|
## Enforcement
|
|
|
|
The linter script `scripts/lint-package-css.sh` runs against all
|
|
`packages/*/css/main.css` files. It exits non-zero if any rule's first class
|
|
selector does not start with `.ext-{slug}`.
|