diff --git a/.plop/templates/component/component.mdx.hbs b/.plop/templates/component/component.mdx.hbs
new file mode 100644
index 000000000..4d79153a2
--- /dev/null
+++ b/.plop/templates/component/component.mdx.hbs
@@ -0,0 +1,74 @@
+import { Canvas, Controls, Meta, Subtitle, Title } from '@storybook/addon-docs/blocks'
+
+import * as {{pascalCase name}}Stories from './{{dashCase name}}.stories'
+
+
+
+
+
+One-line summary of what {{pascalCase name}} is for.
+
+## Overview
+
+What {{pascalCase name}} is and the problem it solves, in a sentence or two. For design
+guidance (anatomy, when to use, do and don't), see the
+[{{pascalCase name}} handbook page](https://github.com/Doist/component-libraries/blob/main/handbook/components/{{dashCase name}}.md).
+
+{/* Verify this handbook link: the slug isn't always the component's dash-name (e.g.
+ buttons.md, menus.md, switches.md) and some pages don't exist yet. */}
+
+## When to use
+
+{/* Two or more concrete scenarios. Trim to what the handbook doesn't already cover. */}
+
+- Use {{pascalCase name}} when ...
+- Prefer another component when ...
+
+## Basic usage
+
+The simplest real example. Pass `variant` and `children`.
+
+
+
+## Variants
+
+{{pascalCase name}} supports a `primary` and a `secondary` variant.
+
+
+
+## States
+
+{/* Visual states (idle, hover, disabled, loading) live here. Add a `States` story and
+ reference it with , or delete this
+ section if the component has no distinct states. */}
+
+## API
+
+
+
+{/* Composable components: add `ArgTypes` to the import above and document each exported
+ part with its own block, e.g.
+
+### `<{{pascalCase name}}.Item>`
+
+
+
+Repeat per exported sub-component. */}
+
+## Custom properties
+
+The following CSS custom properties customize the {{pascalCase name}} appearance. The values
+shown are the defaults.
+
+```css
+--reactist-{{dashCase name}}-tint
+--reactist-{{dashCase name}}-fill
+```
+
+## Accessibility
+
+- **Keyboard**: describe focus order and keys the component handles.
+- **Screen reader**: the name, role, and state it exposes (and via which prop).
+- **Focus**: focus management / trapping behavior, if any.
+
+
diff --git a/.plop/templates/component/component.stories.tsx.hbs b/.plop/templates/component/component.stories.tsx.hbs
index 9c093b586..8ea0a9efc 100644
--- a/.plop/templates/component/component.stories.tsx.hbs
+++ b/.plop/templates/component/component.stories.tsx.hbs
@@ -1,8 +1,9 @@
import * as React from 'react'
-import type { Meta, StoryObj } from '@storybook/react'
import { {{pascalCase name}} } from './{{dashCase name}}'
+import type { Meta, StoryObj } from '@storybook/react'
+
const meta = {
title: 'Design system/{{pascalCase name}}',
component: {{pascalCase name}},
@@ -32,7 +33,7 @@ export const Playground: Story = {
control: { type: 'text' },
},
},
- render(args) {
+ render(args: React.ComponentProps) {
return (
<{{pascalCase name}} {...args} />
@@ -40,3 +41,24 @@ export const Playground: Story = {
)
},
}
+
+export const Variants: Story = {
+ render() {
+ return (
+
+ <{{pascalCase name}} variant="primary">Primary{{pascalCase name}}>{' '}
+ <{{pascalCase name}} variant="secondary">Secondary{{pascalCase name}}>
+
+ )
+ },
+}
+
+export const Accessibility: Story = {
+ render() {
+ return (
+
+ <{{pascalCase name}} variant="primary">Accessible content{{pascalCase name}}>
+
+ )
+ },
+}
diff --git a/.plop/templates/component/component.test.tsx.hbs b/.plop/templates/component/component.test.tsx.hbs
index dbe0405ad..e91960a16 100644
--- a/.plop/templates/component/component.test.tsx.hbs
+++ b/.plop/templates/component/component.test.tsx.hbs
@@ -1,5 +1,7 @@
import * as React from 'react'
+
import { render, screen } from '@testing-library/react'
+
import { {{pascalCase name}} } from './{{dashCase name}}'
describe('{{pascalCase name}}', () => {
diff --git a/.plop/templates/component/component.tsx.hbs b/.plop/templates/component/component.tsx.hbs
index f1da8df32..a42def267 100644
--- a/.plop/templates/component/component.tsx.hbs
+++ b/.plop/templates/component/component.tsx.hbs
@@ -1,5 +1,7 @@
import * as React from 'react'
+
import { Box } from '../box'
+
import styles from './{{dashCase name}}.module.css'
type {{pascalCase name}}Props = {
@@ -14,11 +16,7 @@ type {{pascalCase name}}Props = {
}
function {{pascalCase name}}({ children, variant }: {{pascalCase name}}Props) {
- return (
-
- {children}
-
- )
+ return {children}
}
export { {{pascalCase name}} }
diff --git a/.plop/templates/component/index.ts.hbs b/.plop/templates/component/index.ts.hbs
index 45e186b92..cd311cbf9 100644
--- a/.plop/templates/component/index.ts.hbs
+++ b/.plop/templates/component/index.ts.hbs
@@ -1,2 +1,2 @@
-export { {{pascalCase name}} } from './{{dashCase name}}'
export type { {{pascalCase name}}Props } from './{{dashCase name}}'
+export { {{pascalCase name}} } from './{{dashCase name}}'
diff --git a/CLAUDE.md b/CLAUDE.md
index 663e47b86..d74c887e7 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -27,7 +27,8 @@ src/
component-name.tsx # Implementation
component-name.module.css # CSS Modules styles
component-name.test.tsx # Tests
- component-name.stories.mdx # Storybook docs (or .tsx)
+ component-name.stories.tsx # Storybook stories (CSF)
+ component-name.mdx # Storybook MDX docs page
styles/
design-tokens.css # Global CSS custom properties (--reactist-*)
utils/
@@ -43,7 +44,7 @@ src/
### File structure
-Every component has `index.ts`, `component.tsx`, `component.module.css`, `component.test.tsx`, and a story file. Use `npm run plop component` to scaffold new components.
+Every component has `index.ts`, `component.tsx`, `component.module.css`, `component.test.tsx`, a `component.stories.tsx` story file, and a `component.mdx` docs page. Use `npm run plop component` to scaffold new components.
### Implementation patterns
diff --git a/README.md b/README.md
index d5dcdba8d..536ef58e5 100644
--- a/README.md
+++ b/README.md
@@ -76,6 +76,8 @@ The generated source files include the component implementation with sample prop
You also need to export your new component by adding a reference to it in the [top-level index file](src/index.ts).
+The generator also creates a `.mdx` documentation page next to the stories. Edit it to document the component: fill in the Overview and link the matching [design handbook page](https://github.com/Doist/component-libraries/tree/main/handbook/components), keep the sections that apply, and delete the ones that don't. For composable components (multiple exported parts), repeat the API block per part. Its live examples render from the generated `Playground`, `Variants`, and `Accessibility` stories.
+
## Storybook
For the first development mode run:
diff --git a/plopfile.mjs b/plopfile.mjs
index 14bfb6212..626a2ed94 100644
--- a/plopfile.mjs
+++ b/plopfile.mjs
@@ -56,6 +56,12 @@ function componentGenerator(plop) {
templateFile: templateFile('component/component.stories.tsx'),
})
+ actions.push({
+ type: 'add',
+ path: 'src/{{dashCase name}}/{{dashCase name}}.mdx',
+ templateFile: templateFile('component/component.mdx'),
+ })
+
return actions
},
})