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
4 changes: 2 additions & 2 deletions .claude/docs/COMPONENT_REQUIREMENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.**

Expand Down Expand Up @@ -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

Expand Down
6 changes: 3 additions & 3 deletions .claude/rules/compound-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 `<Table.Row>`'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 `<Table.Row>`'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).
Expand Down Expand Up @@ -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 `<Table>`. 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

Expand Down Expand Up @@ -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 `<name>-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 `<Root.Part>` 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`.
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/component-scaffold/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 `<Dialog.Trigger>` 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 `<Dialog.Trigger>` 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** (`./<name>-<part>`) so consumers don't see the folder nesting; only the right-hand side changes:

Expand Down
16 changes: 8 additions & 8 deletions docs/OVERVIEW_LINT.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

---

Expand Down
2 changes: 1 addition & 1 deletion packages/webkit/docs/STYLEGUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

---

Expand Down
Loading