diff --git a/.claude/docs/COMPONENT_REQUIREMENTS.md b/.claude/docs/COMPONENT_REQUIREMENTS.md index 7c9d9c1d4..e8987b30f 100644 --- a/.claude/docs/COMPONENT_REQUIREMENTS.md +++ b/.claude/docs/COMPONENT_REQUIREMENTS.md @@ -304,7 +304,7 @@ Components do **not** have a per-folder `package.json`. Module resolution goes t ## TypeScript Declarations -TypeScript declaration files (`.d.ts`) are **auto-generated** using Vue TSC. They are emitted at publish time by `packages/webkit/.releaserc`'s `prepareCmd` (`vue-tsc --declaration --emitDeclarationOnly`) and ship to npm consumers; declaration-emit is validated in CI by `type-check` (`vue-tsc --noEmit`). +TypeScript declaration files (`.d.ts`) are **auto-generated** using Vue TSC. They are emitted at publish time by the publish workflow (`.github/workflows/package-webkit.yml` runs `vue-tsc --declaration --emitDeclarationOnly` right before `npm publish`, on release-please's `release: published`) and ship to npm consumers; declaration-emit is validated in CI by `type-check` (`vue-tsc --noEmit`). **DO NOT manually edit `.d.ts` or `.d.ts.map` files.** @@ -745,7 +745,7 @@ When creating a new component, ensure you've completed all requirements: **Problem:** `.d.ts` files are missing or outdated -**Solution:** Declarations are generated at publish time by `packages/webkit/.releaserc`'s `prepareCmd` (`vue-tsc --declaration --emitDeclarationOnly`); declaration-emit is validated locally and in CI by `type-check` (`vue-tsc --noEmit`). Run `pnpm webkit:type-check` to surface declaration errors. +**Solution:** Declarations are generated at publish time by the publish workflow (`.github/workflows/package-webkit.yml`, `vue-tsc --declaration --emitDeclarationOnly`); declaration-emit is validated locally and in CI by `type-check` (`vue-tsc --noEmit`). Run `pnpm webkit:type-check` to surface declaration errors. ### Export Not Found diff --git a/.claude/rules/compound-api.md b/.claude/rules/compound-api.md index 432add836..97b9125d0 100644 --- a/.claude/rules/compound-api.md +++ b/.claude/rules/compound-api.md @@ -10,7 +10,7 @@ It rests on three decisions, in priority order: ## The compound API shape -Each composition component ships an **`index.ts`** next to the root `.vue`. The root is the default export with the sub-components attached via `Object.assign`. Because the package is consumed as source, the consumer's toolchain derives ``'s type straight from `index.ts`; at publish time `.releaserc` also emits an adjacent `index.d.ts` for non-source consumers. +Each composition component ships an **`index.ts`** next to the root `.vue`. The root is the default export with the sub-components attached via `Object.assign`. Because the package is consumed as source, the consumer's toolchain derives ``'s type straight from `index.ts`; at publish time the publish workflow also emits an adjacent `index.d.ts` for non-source consumers. ```ts // index.ts — one source of truth (runtime + the type vue-tsc derives from it). @@ -59,7 +59,7 @@ The dot-notation **must** use a PascalCase root binding (`Table`). `table` (lowe ``` The compound path cannot be tree-shaken: `Object.assign(Table, { Row, Cell, ... })` in `index.ts` references every sub-component, so a bundler retains them all even when the consumer only renders ``. The `-root` key resolves straight to the root `.vue`, so a root-only import pulls in nothing else. Sub-components are already individually importable; this gives the **root** the same tree-shakeable path. The compound (`./table` → `index.ts`) still leads the docs — the `-root` key is the opt-in for consumers who want only the root. - **Sub-component exports stay flat and unchanged** — one entry per public sub-component pointing at its `.vue` (`"./data/table-row": ".../table-row/table-row.vue"`). -- **The package ships source and is consumed as source** (the exports map points at `./src/...`, and `.vue` files already import `.ts` such as `injection-key.ts`). A `.ts` index is therefore safe — the consumer's build transpiles it the same way it transpiles every `.vue` and the shared `injection-key.ts`. `.d.ts` files are gitignored and generated at publish time by `.releaserc`'s `prepareCmd` (`vue-tsc --declaration --emitDeclarationOnly`), not in dev or CI. +- **The package ships source and is consumed as source** (the exports map points at `./src/...`, and `.vue` files already import `.ts` such as `injection-key.ts`). A `.ts` index is therefore safe — the consumer's build transpiles it the same way it transpiles every `.vue` and the shared `injection-key.ts`. `.d.ts` files are gitignored and generated at publish time by the publish workflow ([`package-webkit.yml`](../../.github/workflows/package-webkit.yml) runs `vue-tsc --declaration --emitDeclarationOnly` right before `npm publish`, on release-please's `release: published`), not in dev or CI. ## Naming — anatomy, not generic convention @@ -99,7 +99,7 @@ Interactivity alone does not justify a sub-component. A clickable row is `@click - Do not export composition sub-components without also attaching them to the root compound (`index.ts` via `Object.assign`). - Do not ship the compound `index.ts` root export without **also** adding the standalone `-root` export pointing at the root `.vue`. The compound path retains every sub-component (`Object.assign`), so a root-only consumer has no tree-shakeable way in without the `-root` key. - Do not make the index a plain `index.js` — `vue-tsc` cannot derive types from it (no `allowJs`), so `` ends up untyped. It must be `index.ts`. -- Do not hand-write `index.d.ts` — it is gitignored and generated at publish time (via `.releaserc`'s `prepareCmd`) from `index.ts`, not committed or built in dev. +- Do not hand-write `index.d.ts` — it is gitignored and generated at publish time (by the publish workflow's `vue-tsc --declaration --emitDeclarationOnly` step) from `index.ts`, not committed or built in dev. - Do not invent a `Trigger` (or any overlay part name) on a component that has no `data-state="open|closed"`. - Do not turn a slot-shaped concern into a prop (config arrays of UI). Anatomy is elements; props are data + scalar config. - Do not require the consumer to wire shared state by hand when a context-aware sub-component can read it from `inject`. diff --git a/.claude/skills/component-scaffold/SKILL.md b/.claude/skills/component-scaffold/SKILL.md index ceb6b550c..7f7e23bce 100644 --- a/.claude/skills/component-scaffold/SKILL.md +++ b/.claude/skills/component-scaffold/SKILL.md @@ -197,7 +197,7 @@ packages/webkit/src/components/actions/button/ }) ``` - **The index is `.ts`, not `.js`** — `vue-tsc` cannot derive declarations from a plain `.js` (no `allowJs`), so `` would be untyped. **Do not hand-write `index.d.ts`** — it is gitignored and generated at publish time (via `.releaserc`), not in dev. The package is consumed as source (the exports map points at `./src/...`, and `.vue` files already import `.ts` like `injection-key.ts`), so the consumer transpiles `index.ts` the same way. + **The index is `.ts`, not `.js`** — `vue-tsc` cannot derive declarations from a plain `.js` (no `allowJs`), so `` would be untyped. **Do not hand-write `index.d.ts`** — it is gitignored and generated at publish time (by the publish workflow), not in dev. The package is consumed as source (the exports map points at `./src/...`, and `.vue` files already import `.ts` like `injection-key.ts`), so the consumer transpiles `index.ts` the same way. 5. **Update `packages/webkit/package.json#exports`** — add one entry per public component (the compound root, the standalone root, and each public sub-component) preserving alphabetical order inside the category. The **public export path stays flat** (`./-`) so consumers don't see the folder nesting; only the right-hand side changes: diff --git a/docs/OVERVIEW_LINT.md b/docs/OVERVIEW_LINT.md index c2dd9fd52..5a3bcaebd 100644 --- a/docs/OVERVIEW_LINT.md +++ b/docs/OVERVIEW_LINT.md @@ -185,29 +185,29 @@ Two complementary gates: **Config:** [`commitlint.config.js`](../commitlint.config.js), run by husky on every `commit-msg`. -Commits aren't just style here — they **drive releases**. `semantic-release` reads the same header format to compute version bumps, so commitlint's job is making sure a commit that passes locally also releases correctly. +Commits aren't just style here — they **drive releases**. release-please reads the same header format to compute version bumps — and because merges to `main` are squash merges, the commit it parses is the **PR title**. commitlint's job is making sure a header that passes locally also releases correctly. -**Header shape** (custom `headerPattern`, mirrored in every `packages/*/.releaserc`): +**Header shape** (custom `headerPattern`; release-please's stock parser is not configurable, so the header must **start with the bare type** — a ticket tag goes in the subject, after the colon, and only when a real ticket exists): ``` -[ENG-1231] feat(webkit): add table export ← optional ticket prefix +feat(webkit): [ENG-1231] add table export ← optional ticket tag, after the colon fix(webkit): correct paginator focus ring chore: bump tooling feat(webkit)!: drop tone prop ← “!” = breaking = major ``` -**Types and the release each produces:** +**Types and the release each produces (stock release-please):** | Type | Release bump | |---|---| | `feat` | **minor** | -| `fix` · `hotfix` · `chore` · `docs` · `style` · `refactor` · `perf` | **patch** | -| `test` · `ci` · `revert` | **none** (allowed for hygiene) | +| `fix` | **patch** | +| `chore` · `docs` · `style` · `refactor` · `perf` · `test` · `ci` · `revert` | **none** on their own (allowed for hygiene; they ride along in the next `feat`/`fix` release) | | any type with `!` or a `BREAKING CHANGE:` footer | **major** | -**Other rules:** type required and lower-case, scope lower-case, subject required, header ≤ 100 chars, subject-case unrestricted. +**Other rules:** type required and lower-case, scope lower-case, subject required, header ≤ 100 chars, subject-case unrestricted. A **leading** ticket tag (`[ENG-…] feat: …`) is rejected — release-please cannot parse it, so it would release **nothing** (the #804 incident) — and `[NO-ISSUE]` is rejected anywhere: no ticket → no tag. -**The sync invariant** ([`release-types.md`](../.claude/rules/release-types.md)): this type list must stay **identical** in four places — `commitlint.config.js`, every `packages/*/.releaserc` (`webkit`, `theme`, `icons`), `CONTRIBUTING.md`, and the `/open-pr` + `/create-branch` flows. A type added in one place and not the others produces commits that pass lint but silently don't release. +**The sync invariant** ([`release-types.md`](../.claude/rules/release-types.md)): this type list must stay **identical** in four places — `commitlint.config.js`, [`release-please-config.json`](../release-please-config.json) (stock `node` release type, no per-type bump customization), `CONTRIBUTING.md`, and the `/open-pr` + `/create-branch` flows. A type added in one place and not the others produces commits that pass lint but silently don't release. --- diff --git a/packages/webkit/docs/STYLEGUIDE.md b/packages/webkit/docs/STYLEGUIDE.md index 49ea77811..52de9ec80 100644 --- a/packages/webkit/docs/STYLEGUIDE.md +++ b/packages/webkit/docs/STYLEGUIDE.md @@ -494,7 +494,7 @@ variant?: string **Enforced by:** `webkit/authoring-standards` (bare `@deprecated`) · `webkit/no-deprecated-component` (imports of deprecated components, with the suggested -replacement) · `.releaserc` maps removal to a major. +replacement) · release-please maps removal (`!` / `BREAKING CHANGE:`) to a major. ---