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
2 changes: 2 additions & 0 deletions .changeset/mosaic-dialog-drop-prompt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
Comment thread
austincalvelage marked this conversation as resolved.
35 changes: 35 additions & 0 deletions .claude/skills/mosaic/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,38 @@ layer. Copy from it.
The migration workflow (`migration.md`) ties the flow references together: it
treats the legacy component as the spec and drives you through the model,
controller, and view layers, then verifies parity with `parity-audit.md`.

## Documenting a component in swingset

`packages/swingset/CLAUDE.md` is the house style — archetypes, required section
order, `meta` conventions. One rule on top of it, because it is the one agents
get wrong:

**The docs describe the API as it is. They do not carry the reasoning that
produced it.** No "not a `size`, because…", no rejected alternatives, no history
of what the prop used to be. A reader is there to learn what the thing does, and
every sentence of rationale is a sentence they have to skim past to find it.
State the behaviour plainly and briefly, then stop.

```mdx
<!-- no -->

### Variant

Which surface the dialog holds, and so the geometry it is given. Not a `size`,
because these are different surfaces rather than one surface at two widths — a
second card width would be a size of the `card` variant, with nowhere to sit on
this axis.

<!-- yes -->

### Variant

Which surface the dialog holds, and the geometry that comes with it.
```

This is the opposite of the rule for **code**, where a comment earns its place by
explaining what the code cannot say for itself — the cascade fight behind a
`null`, the measured reason a duration is what it is. Keep that reasoning where a
future maintainer will hit it, which is the source file. The trade you rejected
belongs in a code comment or the PR description; the docs get the conclusion.
1 change: 1 addition & 0 deletions packages/swingset/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ import * as UserButtonStories from './user-button.stories';

- Keep the intro to one short, present-tense paragraph: what the thing is and what it's for. For primitives, say explicitly that it's headless and ships no styles.
- Prose should add what a demo can't — behavior, accessibility, when to reach for it — not restate prop names already in the table.
- Describe the API as it is; leave the reasoning that produced it out. No "not a `size`, because…", no rejected alternatives, no history of what a prop used to be — that belongs in a code comment or the PR. The docs get the conclusion, stated plainly and briefly.
- Lead every page with the heading hierarchy its archetype prescribes; don't invent new top-level sections or reorder them. Consistency across pages is the goal.

### Before you finish
Expand Down
26 changes: 14 additions & 12 deletions packages/swingset/src/stories/confirmation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import * as Stories from './confirmation.stories';

A confirmation for a destructive action that is worth a second look but not worth making the user type for. Removing a connected account, revoking a session, signing out everywhere. For the actions that do warrant typing, use [Destructive](/components/destructive).

It is an `alertdialog`: it announces as an interruption, an outside press cannot dismiss it, and the card carries no corner dismiss. Escape and the footer's Cancel action dismiss it. Under the phone band it arrives as a bottom sheet.

The block holds nothing of its own. Everything that decides what the dialog does next belongs to the caller. `open` closes it, `isConfirming` marks it busy, `errorMessage` explains a failure.

```tsx
Expand Down Expand Up @@ -94,18 +96,18 @@ Opened from a menu item, focus returns to that menu's trigger when the dialog cl

Controlled:

| Prop | Type | Default | Description |
| -------------- | ------------------------- | ------------ | ------------------------------------------------------------------------------ |
| `open` | `boolean` | — (required) | Whether the confirmation is showing. Controlled, the way any dialog is. |
| `onOpenChange` | `(open: boolean) => void` | — (required) | Asks to open or close. Fired by the trigger, Cancel, Escape, and the backdrop. |
| `trigger` | `ReactNode` | — | The button that asks to open the dialog. |
| `title` | `string` | — (required) | Names what is about to happen. |
| `description` | `ReactNode` | — (required) | Spells out what it means. Takes markup, for a name to emphasise. |
| `actionLabel` | `string` | — (required) | The destructive button's label. |
| `cancelLabel` | `string` | `'Cancel'` | The cancel button's label. |
| `onConfirm` | `() => void` | — (required) | Asks the caller to run the action. |
| `isConfirming` | `boolean` | `false` | Renders the action pending and ignores further presses. |
| `errorMessage` | `string` | — | Renders as a negative banner above the actions. |
| Prop | Type | Default | Description |
| -------------- | ------------------------- | ------------ | ------------------------------------------------------------------------------------------ |
| `open` | `boolean` | — (required) | Whether the confirmation is showing. Controlled, the way any dialog is. |
| `onOpenChange` | `(open: boolean) => void` | — (required) | Asks to open or close. Fired by the trigger, Escape, and the `Dialog.Close` Cancel action. |
| `trigger` | `ReactNode` | — | The button that asks to open the dialog. |
| `title` | `string` | — (required) | Names what is about to happen. |
| `description` | `ReactNode` | — (required) | Spells out what it means. Takes markup, for a name to emphasise. |
| `actionLabel` | `string` | — (required) | The destructive button's label. |
| `cancelLabel` | `string` | `'Cancel'` | The cancel button's label. |
| `onConfirm` | `() => void` | — (required) | Asks the caller to run the action. |
| `isConfirming` | `boolean` | `false` | Renders the action pending and ignores further presses. |
| `errorMessage` | `string` | — | Renders as a negative banner above the actions. |

With a handle:

Expand Down
Loading
Loading