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
1 change: 1 addition & 0 deletions .ai/rules/code-conformance.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ Reference: [Linting tools](../../CONTRIBUTOR-DOCS/02_style-guide/03_linting-tool

**What to check:**

- Every item in the Component CSS PR checklist passes — work through it explicitly, do not skim
- CSS property ordering matches the documented order
- Custom property naming follows the convention
- No patterns from the anti-patterns guide are present
Expand Down
8 changes: 5 additions & 3 deletions .ai/rules/migration-phase-awareness.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ Apply any time:

## Before declaring a phase complete

Before ending a response that declares a migration phase complete, verify against two sources and perform one update:
Before ending a response that declares a migration phase complete, verify against two sources and perform two updates:

1. **Phase skill quality gate** — every checklist item in the active skill's quality gate section
2. **Migration plan** — read `CONTRIBUTOR-DOCS/03_project-planning/03_components/[component]/migration-plan.md` and verify that the work done in this phase matches what the plan specifies for it. If the plan is missing, note that as a risk. If the implementation drifted from the plan, call it out explicitly — do not silently accept drift.
3. **Consistency pass** — the checks described in `.ai/rules/consistency-pass.md` have been run on files changed in this phase, or are explicitly deferred and noted in the checkpoint
4. **Status table** — update `CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/01_status.md` to reflect the completed phase for this component
3. **Migration plan checklist** — update the plan's checklist for the current phase: mark every completed item `[x]`, fill in any "to be determined" values that were resolved, and leave incomplete items unchecked with a note. The checklist is the per-component record that this phase was done and what was produced — keep it current.
4. **Consistency pass** — the checks described in `.ai/rules/consistency-pass.md` have been run on files changed in this phase, or are explicitly deferred and noted in the checkpoint
5. **Status table** — update `CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/01_status.md` to reflect the completed phase for this component

Do not silently skip incomplete items. If something cannot be completed, say so and record it in the checkpoint.

Expand All @@ -35,6 +36,7 @@ When you complete a migration phase, end your response with a Migration Checkpoi
**Migration Checkpoint: [Component Name]**
Phase completed: [N] — [Phase Name]
Next phase: [N+1] — [Phase Name] (invoke `migration-[skill]`)
Plan checklist: [updated | not updated — reason]
Consistency pass: [done | not yet run | deferred — reason]
Phase blockers: [items from this phase that are incomplete or at risk; "none" if clean — do not include future-phase concerns]
---
Expand Down
2 changes: 2 additions & 0 deletions .ai/skills/consumer-migration-guide/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ Create per-component migration guidance for application developers upgrading app

Before writing anything, read `CONTRIBUTOR-DOCS/03_project-planning/03_components/[component]/migration-plan.md`. Locate every item in the documentation checklist that is flagged as "deferred to consumer migration guide" — these are the breaking changes Phase 7 has already identified as needing coverage here. They are the primary input for this guide's `## What changed` and `## Update your code` sections. If the migration plan is absent, derive the breaking changes from the 1st-gen and 2nd-gen source comparison and note the risk.

**Scope the guide to what actually shipped.** The migration plan categories (Must-ship, Additive, Deferred) reflect planning intent, not final state — by the time the guide is written, some Additive items may have been implemented and some Must-ship items may have slipped. The 2nd-gen source is the only authority. For every feature you consider including: verify it exists in the shipped source. If it is there, include it regardless of how the plan categorized it. If it is not in the source, exclude it regardless of how the plan categorized it.

### Consistent import and tag patterns

All guides follow the same import and tag name conventions. Do not grep for these — derive them from the component name:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Keep the guide **short, direct, and scannable**. A consumer should be able to co
- `::part()` shadow parts unless a part is explicitly public API
- Maintainer-facing migration rationale or sequencing
- **Links to `CONTRIBUTOR-DOCS/` project-planning docs.** Those are maintainer-facing. Do not include them in the guide.
- **Unshipped features** — do not include any feature that is not present in the 2nd-gen source, regardless of how it is categorized in the migration plan. Migration plan categories (Must-ship, Additive, Deferred) reflect planning intent; the source is the final authority on what shipped.

### Structure steps logically

Expand Down Expand Up @@ -110,7 +111,7 @@ Replace `<sp-badge>` with `<swc-badge>` and update the import. The public API is
Use up to three `###` sub-section tables — **only include a sub-section if it has entries**. Each sub-section is a table focused on one kind of change:

- **`### Renamed`** — tag, import path, property prefixes, or other 1:1 renames. Columns: `Area | Spectrum 1 | Spectrum 2`.
- **`### Added in Spectrum 2`** — new attributes, variants, slots, or custom properties the consumer may adopt. Columns: `Addition | Notes`.
- **`### Added in Spectrum 2`** — new attributes, variants, slots, or custom properties confirmed present in the shipped 2nd-gen source that the consumer may adopt. Columns: `Addition | Notes`. Verify each entry against the source — migration plan categories (Additive, Deferred) reflect planning intent and may not match final state.
- **`### Removed in Spectrum 2`** — removed public API with replacement guidance. Columns: `Removed | Replacement`.

Do **not** include an `### Unchanged` sub-section. Unchanged API requires no consumer action and adds noise.
Expand Down
8 changes: 8 additions & 0 deletions .ai/skills/migration-documentation/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,14 @@ Return to the list from Step 0. For each unchecked documentation item in the mig
- If it belongs in the consumer migration guide (breaking changes, migration paths from 1st-gen), note it as deferred to the `consumer-migration-guide` skill — do **not** add it to the stories file.
- If it is genuinely missing from both stories and the consumer guide, flag it to the user.

**Verify `@cssprop` completeness and accuracy.** Read the component's CSS file (`2nd-gen/packages/swc/components/[component]/[component].css`) and list every exposed `--swc-*` property. Then read the SWC class (`2nd-gen/packages/swc/components/[component]/[Component].ts`) and confirm:

- Every exposed property has a `@cssprop` tag on the primary class export.
- Each description is accurate: it names what the property controls and its default token, with no stale or invented values.
- No `--_swc-*` private properties are tagged.

Fix any missing or inaccurate `@cssprop` tags before marking Phase 7 complete. If Phase 5 was skipped or the tags were never added, add them now.

---

## What NOT to include in stories JSDoc
Expand Down
12 changes: 12 additions & 0 deletions .ai/skills/migration-styling/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,15 @@ Common case: confirming that subcomponent class names follow the single-hyphen s
If a rename is needed, make the template change first, confirm the component still renders correctly in Storybook, then write the CSS.

**Step 4 — Execute the phase.** Follow **[Phase 5: Styling](../../../CONTRIBUTOR-DOCS/03_project-planning/02_workstreams/02_2nd-gen-component-migration/02_step-by-step/01_washing-machine-workflow.md#phase-5-styling)** in the washing machine workflow doc — it covers what to do, what to check, common problems, and the quality gate for this phase.

**Step 5 — Document exposed custom properties.** After writing the CSS, add a `@cssprop` JSDoc tag to the SWC component class (`2nd-gen/packages/swc/components/[component]/[Component].ts`) for every exposed `--swc-*` property. Place all `@cssprop` tags on the primary SWC class export (not the core base class). Each tag should name the property and give a one-line description of what it controls, including its default token where relevant.

```ts
/**
* @cssprop --swc-badge-height - Block size of the badge. Defaults to the medium component height token.
* @cssprop --swc-badge-background-color - Background fill. Defaults to the neutral subdued background token.
*/
export class Badge extends BadgeBase { … }
```

Storybook picks these up automatically and surfaces them in the API docs panel. Do not add `@cssprop` tags for private `--_swc-*` properties — those are internal only.
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,11 @@

### 1. `:host` vs Component Class

Put only layout-participation styles on `:host`. Put actual visuals on `.swcComponentName` or internal parts.
→ See [01_component-css](../../../../CONTRIBUTOR-DOCS/02_style-guide/01_css/01_component-css.md)
Put only layout-participation styles on `:host`. Put actual visuals on `.swc-ComponentName` or internal parts.

**Exception**: three categories of styles may legitimately live on `:host` — each for a distinct reason: UA resets when the browser applies default styles directly to the host element (for example, the native popover stylesheet); transition properties (`opacity`, `transition-*`, `transition-behavior: allow-discrete`) when the host is itself the transition target (for example, when `@starting-style` applies to the host); and positioning surface (`position: absolute`, `inset: auto`, dimension constraints) when an external controller such as a placement controller writes coordinates directly to the host element.

→ See [01_component-css#when-to-use-host](../../../../CONTRIBUTOR-DOCS/02_style-guide/01_css/01_component-css.md#when-to-use-host)

### 2. Stylesheet Order

Expand All @@ -84,6 +87,15 @@ Follow the prescribed stylesheet order to manage specificity and reduce selector

Use `token()` for design token values. Use `--swc-*` only for intentionally exposed override points, and `--_swc-*` for internal/private properties. Do not keep old `--mod-*` chains.

Key rules:

- **`--_swc-*` on `:host`/`:host()` is not private.** Properties on the host element are part of the external style surface — consumers can set them regardless of the prefix. Declare truly private properties on the internal wrapper (`.swc-ComponentName`), not on `:host`.
- **Expose only when the component itself overrides the property** based on its own variant, state, or size needs. Do not expose for consumer convenience. Exceptions: nested component relationships and shared utility properties.
- **No size-specific custom properties.** When a property changes per size, expose a single property (e.g. `--swc-button-padding-vertical`) and override it per size selector (`:host([size="s"])`). Do not create size-specific properties — they become publicly addressable API.
- **Prefer variant overrides over per-variant redefinition.** For component API attributes (size, variant, fill-style), set a CSS property once on the base using a custom property and override it per `:host([variant])`. Never create variant-specific custom property names.
- **Native browser states on internal elements need state-specific custom properties.** For properties that change across `:hover`, `:focus-visible`, `:active` on an internal wrapper (e.g. `.swc-Button`), expose one property per state (`--swc-button-background-color-default`, `-hover`, `-focus`, `-down`). Override the full set from `:host([variant])` and `:host([static-color])`. This is the mechanism that makes static-color compound overrides possible. Exception: properties that never vary by variant (e.g. `outline` on `:focus-visible`) — define those directly on the state selector.
- **Use full property names** in custom property names: `padding` not `pad`, `background` not `bg`, `color` not `clr`.

Every exposed `--swc-*` property must be documented with a `@cssprop` JSDoc tag on the primary component class export (the SWC layer class, not the core base). Storybook picks these up automatically and surfaces them in the API docs panel.

```ts
Expand Down Expand Up @@ -125,3 +137,36 @@ Keep selector specificity at or below `(0,1,0)`. If you need a compounded select

Only add `@media (forced-colors: active)` if browser defaults are not conveying correct semantic intent, and always put it at the end of the component stylesheet.
→ See [01_component-css#forced-colors-requirements](../../../../CONTRIBUTOR-DOCS/02_style-guide/01_css/01_component-css.md#forced-colors-requirements)

### 8. Browser API selectors

Prefer native CSS pseudo-classes over attribute selectors when one exists for the same state (`:host(:popover-open)` not `:host([open])`; `:host(:disabled)` not `:host([disabled])`). Use attribute selectors for custom attributes and ARIA states with no native pseudo-class.
→ See [01_component-css#state-implementation-patterns](../../../../CONTRIBUTOR-DOCS/02_style-guide/01_css/01_component-css.md#state-implementation-patterns)

### 9. Sub-element inheritance

When a sub-element must always match a variant-driven property on the parent, use `inherit` rather than repeating the `var()` reference in each variant rule.
→ See [01_component-css#variant-implementation-patterns](../../../../CONTRIBUTOR-DOCS/02_style-guide/01_css/01_component-css.md#variant-implementation-patterns)

### 10. Compound pseudo-classes on `:host()` via CSS nesting

CSS nesting inside a `:host([...])` rule — e.g. `&:dir(rtl)` — expands to `:host([...]):dir(rtl)`, which chains the pseudo-class **outside** the `:host()` argument. Browsers do not support this; the rule silently fails with no parse error.

```css
/* ❌ Silent failure: :dir(rtl) is outside :host() */
:host([placement='start']:popover-open) {
&:dir(rtl) {
transform: translateX(1rem);
}
}

/* ✅ All conditions inside the :host() argument */
:host(:dir(rtl)[placement='start']:popover-open) {
transform: translateX(1rem);
}
```

**Exception**: when the parent selector targets a descendant (e.g. `:host([...]) .swc-Child`), nesting `&:dir(rtl)` correctly applies `:dir()` to the inner element — that is valid and fine.

**Migration note**: `:dir()` is a common place this surfaces. Whenever you add `:dir()` to a `:host`-level rule, write a separate `:host(:dir(rtl)[...])` rule instead of nesting.
→ See [05_anti-patterns#9](../../../../CONTRIBUTOR-DOCS/02_style-guide/01_css/05_anti-patterns.md#9-nesting-compound-pseudo-classes-on-host-via-css-nesting)
Loading
Loading