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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
76 changes: 38 additions & 38 deletions .claude/commands/component.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Parse `$ARGUMENTS` as two space-separated words:

- **Word 1** component name (`<Name>`). Must be PascalCase.
- **Word 2** target directory (`<dir>`). Must be one of: `theme` · `common` · `page` · `section`.
- **Word 1** - component name (`<Name>`). Must be PascalCase.
- **Word 2** - target directory (`<dir>`). Must be one of: `theme` · `common` · `page` · `section`.

If either word is missing or invalid, stop and say:

Expand All @@ -20,46 +20,46 @@ If either word is missing or invalid, stop and say:

---

## Step 0 Read reference files
## Step 0 - Read reference files

Read ALL of these before doing anything else they are the authoritative source of truth:
Read ALL of these before doing anything else - they are the authoritative source of truth:

1. `packages/design-system/design-system.md` architecture rules
2. `.claude/skills/theme-usage/SKILL.md` rules for consuming theme primitives in non-theme components
3. `.claude/skills/css-in-js/SKILL.md` CSS-in-JS and styled-system conventions
4. `.claude/skills/code-style/SKILL.md` TypeScript and JavaScript coding conventions
5. `.claude/skills/wcag/SKILL.md` accessibility rules (ARIA, contrast, keyboard, landmarks)
6. `src/section/section.md` section conventions (read only when `<dir>` is `section`)
1. `packages/design-system/design-system.md` - architecture rules
2. `.claude/skills/theme-usage/SKILL.md` - rules for consuming theme primitives in non-theme components
3. `.claude/skills/css-in-js/SKILL.md` - CSS-in-JS and styled-system conventions
4. `.claude/skills/code-style/SKILL.md` - TypeScript and JavaScript coding conventions
5. `.claude/skills/wcag/SKILL.md` - accessibility rules (ARIA, contrast, keyboard, landmarks)
6. `src/section/section.md` - section conventions (read only when `<dir>` is `section`)

---

## Step 1 Detect mode
## Step 1 - Detect mode

Check whether `<root-path>` already exists.

- **Exists** → **rework**. Read all existing files in the folder, then go to Step 4 (rework rules apply). Skip Steps 23.
- **Exists** → **rework**. Read all existing files in the folder, then go to Step 4 (rework rules apply). Skip Steps 2-3.
- **Does not exist** → **new component**. Follow all steps in order.

---

## Step 2 Clarify intent (new components only)
## Step 2 - Clarify intent (new components only)

If the task spec (everything in `$ARGUMENTS` after the two required words) already makes the component's purpose, base element, and props clear, state your interpretation explicitly and proceed.

Otherwise ask:

> What is `<Name>`'s primary purpose and base HTML element?
> (e.g. `"section a page region with a heading and body"`)
> (e.g. `"section - a page region with a heading and body"`)

Do not generate any files until you have enough information to make concrete decisions.

---

## Step 3 Audit for reuse
## Step 3 - Audit for reuse

Before writing any code, scan for existing work that should be reused instead of duplicated:

**Theme primitives** check `@soroush.tech/design-system/` for components that cover the layout or styling need:
**Theme primitives** - check `@soroush.tech/design-system/` for components that cover the layout or styling need:

- Block container → `View`
- Flex layout → `Flex`
Expand All @@ -69,41 +69,41 @@ Before writing any code, scan for existing work that should be reused instead of
- Clickable → `Button`
- Input → `TextInput`

If a theme primitive covers the need, use it as a composed child never reimplement it.
If a theme primitive covers the need, use it as a composed child - never reimplement it.

**Utils** grep `src/utils/` and all sibling component folders for functions that match the logic needed. If a match exists, import it. If it lives in another component's folder (`src/common/OtherComponent/utils.ts`), present a proposal to move it to `src/utils/` and wait for approval before touching that file.
**Utils** - grep `src/utils/` and all sibling component folders for functions that match the logic needed. If a match exists, import it. If it lives in another component's folder (`src/common/OtherComponent/utils.ts`), present a proposal to move it to `src/utils/` and wait for approval before touching that file.

**Hooks** grep `src/hooks/` and sibling component folders for hooks that match. Same rule: if a hook is generic enough to share, propose moving it to `src/hooks/` first.
**Hooks** - grep `src/hooks/` and sibling component folders for hooks that match. Same rule: if a hook is generic enough to share, propose moving it to `src/hooks/` first.

Present a short summary of what you found and what you plan to reuse before proceeding.

---

## Step 4 Generate files
## Step 4 - Generate files

Every component lives in its own folder regardless of `<dir>`. Create `<root-path>` with these files:

### `index.ts` barrel re-export only
### `index.ts` - barrel re-export only

```ts
export * from './<Name>'
```

### `<Name>.tsx` component
### `<Name>.tsx` - component

Rules that apply to **all** `<dir>` values:

- Compose using theme primitives (`View`, `Flex`, `Typography`, `Button`, etc.) pass layout, color, and spacing via their token props, not inline styles.
- Compose using theme primitives (`View`, `Flex`, `Typography`, `Button`, etc.) - pass layout, color, and spacing via their token props, not inline styles.
- Never pass raw hex values, pixel literals, or hardcoded font-family strings.
- Extract reusable pure functions to `<Name>/utils.ts`. Extract stateful logic to `<Name>/use<Name>.ts` (or a more specific name). Keep `<Name>.tsx` a thin composition layer.
- Do **not** write custom CSS (`styled`, template literals, or `css` prop) without first presenting a proposal that explains why a theme primitive cannot cover the case. Wait for approval before implementing.
- **Assets:** SVG icons and images used by the component must be placed in `src/assets/` (icons in `src/assets/icons/`), not inlined or co-located next to the component.

**If `<dir>` is `theme`** additionally follow all `packages/design-system/design-system.md` rules:
**If `<dir>` is `theme`** - additionally follow all `packages/design-system/design-system.md` rules:

- `styled` base with `createShouldForwardProp([...props, ...customProps])`
- Custom props wired via `system()` against theme scales
- Prop types derived from `Theme` (`keyof Theme['scaleName']`) no manual unions
- Prop types derived from `Theme` (`keyof Theme['scaleName']`) - no manual unions
- Export all prop types

**If `<dir>` is `common`, `page`, or `section`:**
Expand All @@ -120,8 +120,8 @@ For components where a prop selects a palette (not a raw CSS property), use a ne
button: Record<'primary' | 'secondary' | ..., { main, hover, active, contrast }>
```

- Derive type via `keyof Theme['button']` never a manual union
- Use a `variantStyles` function, not `system()` `system()` handles 1:1 prop→CSS; nested/conditional mappings need a function
- Derive type via `keyof Theme['button']` - never a manual union
- Use a `variantStyles` function, not `system()` - `system()` handles 1:1 prop→CSS; nested/conditional mappings need a function
- Hover/active states: hex-opacity suffix `${main}14` (8%) or `${main}20` (12%)

**Kinetic OS design tokens for interactive elements:**
Expand All @@ -132,11 +132,11 @@ Buttons use `borderRadius: 0`, `textTransform: uppercase`, `fontWeight: bold`, `

When a layout calls for a specific font size, weight, or line height, match it to the nearest `Typography` variant or theme token prop (`fontSize`, `fontWeight`, `lineHeight` from `theme.fontSizes`, `theme.fontWeights`, `theme.lineHeights`). State the mapping explicitly:

> "I'm using `variant="body2"` (14px, normal weight) does that match the intended style?"
> "I'm using `variant="body2"` (14px, normal weight) - does that match the intended style?"

Wait for confirmation before committing to a specific variant or size token.

### `<Name>.test.tsx` unit tests
### `<Name>.test.tsx` - unit tests

- Wrap every render in `renderWithTheme` (or `ThemeProvider`).
- Cover: children render, each meaningful prop produces the correct CSS or DOM output, HTML attribute passthrough (`className`, `data-*`, `aria-*`), element mapping if a variant prop exists.
Expand All @@ -145,22 +145,22 @@ Wait for confirmation before committing to a specific variant or size token.
**jsdom caveats (theme components):**

- `backgroundColor` transparent value will convert to rgba
- Elements with `visibility: hidden` are excluded from accessible name use `data-testid` selectors
- Elements with `visibility: hidden` are excluded from accessible name - use `data-testid` selectors

### `README.md` prop documentation
### `README.md` - prop documentation

- Document every prop: type, default, description.
- Color / bg / border tables use palette constant names only `kineticGreen[500]`, never hex.
- Color / bg / border tables use palette constant names only - `kineticGreen[500]`, never hex.
- Include a usage example.
- Keep in sync with actual token values in `themes.ts`.

### `<Name>.stories.tsx` Storybook (required for `theme`; optional but recommended for `common` / `section`)
### `<Name>.stories.tsx` - Storybook (required for `theme`; optional but recommended for `common` / `section`)

- Import option arrays from `@soroush.tech/design-system/utils/test/storiesArgs.ts` and `@soroush.tech/design-system/utils/test/storiesOptions.ts` never hardcode inline.
- `controls.include` whitelist no autodiscovery.
- Import option arrays from `@soroush.tech/design-system/utils/test/storiesArgs.ts` and `@soroush.tech/design-system/utils/test/storiesOptions.ts` - never hardcode inline.
- `controls.include` whitelist - no autodiscovery.
- Every prop in `controls.include` must have a matching `argType` with `control`, `description`, and `table.category`.
- Category names: Content · Typography · Layout · Visual · Spacing.
- No top-level `name:` in any argType. `table.name` inside `table:` is safe only affects autodocs display.
- No top-level `name:` in any argType. `table.name` inside `table:` is safe - only affects autodocs display.
- When adding new token arrays to the options file, constrain with `satisfies`: `export const myTokens = [...] satisfies MyToken[]`
- Control types: `opacity` → `{ type: 'range', min: 0, max: 1, step: 0.05 }` · space props → `{ type: 'select' }, options: spaceTokens` · booleans → `'boolean'`

Expand All @@ -178,7 +178,7 @@ Static data the component renders. Co-locate it here and import it into both `<N

---

## Step 5 Custom CSS proposal gate
## Step 5 - Custom CSS proposal gate

If at any point you determine that custom CSS is necessary (a theme primitive genuinely cannot cover a visual requirement), stop and present a proposal:

Expand All @@ -192,7 +192,7 @@ Do not write the CSS until the user approves.

---

## Step 6 Cross-component impact
## Step 6 - Cross-component impact

After generating all files, check whether the changes affect other components:

Expand Down
50 changes: 25 additions & 25 deletions .claude/commands/design_system.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
The component name is the first word of `$ARGUMENTS`.
The remainder of `$ARGUMENTS` (if any) is the task spec extract agreed props, behaviours, and constraints from it to inform Steps 2 and 3.
The remainder of `$ARGUMENTS` (if any) is the task spec - extract agreed props, behaviours, and constraints from it to inform Steps 2 and 3.

If the first word is not a valid PascalCase name, stop and say:

> "Please start with a PascalCase component name, e.g. `/design_system Button [optional task spec]`"

---

## Step 0 Detect mode
## Step 0 - Detect mode

Check whether `packages/design-system/src/<Name>/` already exists.

Expand All @@ -16,15 +16,15 @@ Check whether `packages/design-system/src/<Name>/` already exists.

---

## Step 1 Read reference files
## Step 1 - Read reference files

Read these files in order before doing anything else:

1. `@soroush.tech/design-system/Typography/Typography.tsx` canonical component implementation
2. `@soroush.tech/design-system/Typography/README.md` canonical documentation format
3. `@soroush.tech/design-system/Typography/Typography.stories.tsx` canonical story structure
4. `@soroush.tech/design-system/storybookOptions.ts` existing token arrays and import patterns
5. `packages/design-system/design-system.md` full architecture rules (authoritative source of truth)
1. `@soroush.tech/design-system/Typography/Typography.tsx` - canonical component implementation
2. `@soroush.tech/design-system/Typography/README.md` - canonical documentation format
3. `@soroush.tech/design-system/Typography/Typography.stories.tsx` - canonical story structure
4. `@soroush.tech/design-system/storybookOptions.ts` - existing token arrays and import patterns
5. `packages/design-system/design-system.md` - full architecture rules (authoritative source of truth)

If reworking an existing component, also read its current files:

Expand All @@ -35,14 +35,14 @@ If reworking an existing component, also read its current files:

---

## Step 2 Clarify base element (new components only)
## Step 2 - Clarify base element (new components only)

If the task spec already makes the base HTML element and props clear, state your interpretation and proceed without asking.

Otherwise ask:

> What is the base HTML element for `<Name>`, and what is its primary purpose?
> (e.g. `"div a layout container"` or `"button an interactive action trigger"`)
> (e.g. `"div - a layout container"` or `"button - an interactive action trigger"`)

Use the answer to decide:

Expand All @@ -54,13 +54,13 @@ Do not generate any files until confirmed.

---

## Step 3 Generate or update files
## Step 3 - Generate or update files

### New component

Create the folder `packages/design-system/src/<Name>/` with these five files:

**`index.ts`** re-export only:
**`index.ts`** - re-export only:

```ts
export * from './<Name>'
Expand All @@ -71,19 +71,19 @@ export * from './<Name>'
- `styled` base with `createShouldForwardProp([...props, ...customProps])`
- Only include styled-system groups relevant to this component
- Wire `color` → `scale: 'text'` and `bg` → `scale: 'background'` via `system()` if color props are needed
- Derive all prop types from `Theme` via `keyof Theme['scaleName']` no manual unions
- Derive all prop types from `Theme` via `keyof Theme['scaleName']` - no manual unions
- Export named prop types (e.g. `<Name>Props`)

**`README.md`**

- Document every prop: type, default, description
- Color/bg tables use palette constant names only `kineticGreen[500]`, never hex
- Color/bg tables use palette constant names only - `kineticGreen[500]`, never hex
- Mirror the section structure of `@soroush.tech/design-system/Typography/README.md`

**`<Name>.stories.tsx`**

- Import all option arrays from `@soroush.tech/design-system/storybookOptions.ts` never hardcode inline
- `controls.include` whitelist no autodiscovery
- Import all option arrays from `@soroush.tech/design-system/storybookOptions.ts` - never hardcode inline
- `controls.include` whitelist - no autodiscovery
- Every prop in `controls.include` must have a matching `argType` with `control`, `description`, and `table.category`
- Category names: Content · Typography · Layout · Color · Spacing
- No top-level `name:` in any argType
Expand All @@ -93,22 +93,22 @@ export * from './<Name>'
- Cover: CSS output for each prop, HTML attribute passthrough, element mapping if a variant prop exists
- Wrap renders in `ThemeProvider`

Update `@soroush.tech/design-system/storybookOptions.ts` only if new token arrays are needed never duplicate existing ones.
Update `@soroush.tech/design-system/storybookOptions.ts` only if new token arrays are needed - never duplicate existing ones.

### Rework (existing component)

Apply only the changes required by the task spec. For every change made:

- **`<Name>.tsx`** update the component
- **`<Name>.test.tsx`** add or update tests to cover the change; remove any tests made obsolete
- **`README.md`** update prop documentation to reflect the change; fix any stale references
- **`<Name>.stories.tsx`** add the new prop to `controls.include` and `argTypes`; add a story if the change warrants one
- **`<Name>.tsx`** - update the component
- **`<Name>.test.tsx`** - add or update tests to cover the change; remove any tests made obsolete
- **`README.md`** - update prop documentation to reflect the change; fix any stale references
- **`<Name>.stories.tsx`** - add the new prop to `controls.include` and `argTypes`; add a story if the change warrants one

Do not touch unrelated parts of any file.

---

## Step 4 Cross-component impact
## Step 4 - Cross-component impact

After any change, check whether other components are affected:

Expand All @@ -118,9 +118,9 @@ After any change, check whether other components are affected:

> **Impact on other components**
>
> - `Flex` inherits `cursor` automatically, no changes needed
> - `Grid` inherits `cursor` automatically, no changes needed
> - `Paper` not yet implemented; `cursor` will be available when built
> - `Flex` - inherits `cursor` automatically, no changes needed
> - `Grid` - inherits `cursor` automatically, no changes needed
> - `Paper` - not yet implemented; `cursor` will be available when built

Wait for the user to confirm before making changes to other components.

Expand Down
Loading
Loading