Skip to content

Commit bfaecd4

Browse files
authored
Merge pull request #3 from oasisprotocol/ml/storybook
Storybook
2 parents c1c905b + bf6ad3a commit bfaecd4

26 files changed

Lines changed: 4795 additions & 66 deletions

.github/workflows/ci-build.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# NOTE: This name appears in GitHub's Checks API and in workflow's status badge.
2+
name: ci-build
3+
4+
# Trigger the workflow when:
5+
on:
6+
# A push occurs to one of the matched branches.
7+
push:
8+
branches: [master]
9+
# Or when a pull request event occurs for a pull request against one of the
10+
# matched branches.
11+
pull_request:
12+
branches: [master]
13+
14+
jobs:
15+
build:
16+
# NOTE: This name appears in GitHub's Checks API.
17+
name: build
18+
runs-on: ubuntu-latest
19+
steps:
20+
- name: Checkout code
21+
uses: actions/checkout@v4
22+
- name: Set up Node.js 20
23+
uses: actions/setup-node@v4
24+
with:
25+
node-version: '20.x'
26+
cache: yarn
27+
- name: Install dependencies
28+
run: yarn install --frozen-lockfile
29+
- name: Build project
30+
run: yarn build
31+
- name: Build Storybook
32+
run: yarn build-storybook

.github/workflows/ci-test.yml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# NOTE: This name appears in GitHub's Checks API and in workflow's status badge.
2+
name: ci-test
3+
4+
# Trigger the workflow when:
5+
on:
6+
# A push occurs to one of the matched branches.
7+
push:
8+
branches: [master]
9+
# Or when a pull request event occurs for a pull request against one of the
10+
# matched branches.
11+
pull_request:
12+
branches: [master]
13+
14+
jobs:
15+
test:
16+
# NOTE: This name appears in GitHub's Checks API.
17+
name: test
18+
runs-on: ubuntu-latest
19+
steps:
20+
- name: Checkout code
21+
uses: actions/checkout@v4
22+
- name: Set up Node.js 20
23+
uses: actions/setup-node@v4
24+
with:
25+
node-version: '20.x'
26+
cache: yarn
27+
- name: Install dependencies
28+
run: yarn install --frozen-lockfile
29+
- name: Install Playwright
30+
run: npx playwright install --with-deps
31+
- name: Build project
32+
run: yarn build
33+
- name: Build Storybook
34+
run: yarn build-storybook --quiet
35+
- name: Serve Storybook and run tests
36+
run: |
37+
npx concurrently -k -s first -n "SB,TEST" -c "magenta,blue" \
38+
"npx http-server storybook-static --port 6006 --silent" \
39+
"npx wait-on tcp:127.0.0.1:6006 && yarn test-storybook"

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,6 @@ dist-ssr
2525

2626
# Eslint
2727
.eslintcache
28+
29+
*storybook.log
30+
storybook-static

.storybook/main.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import type { StorybookConfig } from '@storybook/react-vite'
2+
3+
const config: StorybookConfig = {
4+
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
5+
addons: [
6+
'@storybook/addon-vitest',
7+
'@storybook/addon-a11y',
8+
'@storybook/addon-designs',
9+
'@storybook/addon-themes',
10+
'@storybook/addon-docs',
11+
],
12+
framework: {
13+
name: '@storybook/react-vite',
14+
options: {},
15+
},
16+
core: {
17+
disableTelemetry: true,
18+
},
19+
typescript: {
20+
reactDocgen: 'react-docgen-typescript',
21+
},
22+
async viteFinal(config) {
23+
return {
24+
...config,
25+
plugins: [...(config.plugins || [])],
26+
}
27+
},
28+
}
29+
export default config

.storybook/preview-head.html

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<style>
2+
html,
3+
body {
4+
height: 100%;
5+
margin: 0;
6+
padding: 0;
7+
}
8+
</style>

.storybook/preview.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import type { Preview } from '@storybook/react-vite'
2+
import { withThemeByClassName } from '@storybook/addon-themes'
3+
// @ts-expect-error TS2307 - not a module
4+
import '../src/styles/global.css'
5+
6+
const preview: Preview = {
7+
parameters: {
8+
controls: {
9+
matchers: {
10+
color: /(background|color)$/i,
11+
date: /Date$/i,
12+
},
13+
},
14+
},
15+
decorators: [
16+
withThemeByClassName({
17+
themes: {
18+
light: '',
19+
dark: 'dark',
20+
},
21+
defaultTheme: 'dark',
22+
}),
23+
],
24+
}
25+
26+
export default preview

.storybook/vitest.setup.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { beforeAll } from 'vitest'
2+
import { setProjectAnnotations } from '@storybook/react-vite'
3+
import * as projectAnnotations from './preview'
4+
5+
// This is an important step to apply the right configuration when testing your stories.
6+
// More info at: https://storybook.js.org/docs/api/portable-stories/portable-stories-vitest#setprojectannotations
7+
const project = setProjectAnnotations([projectAnnotations])
8+
9+
beforeAll(project.beforeAll)

package.json

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,39 @@
1010
"build": "tsc && vite build",
1111
"prettier-check": "prettier --check . --ignore-path .gitignore",
1212
"prettier": "prettier --write . --ignore-path .gitignore",
13-
"eslint": "eslint . --cache --ext .js,.ts,.tsx --max-warnings 0"
13+
"eslint": "eslint . --cache --ext .js,.ts,.tsx --max-warnings 0",
14+
"storybook": "storybook dev -p 6006",
15+
"build-storybook": "storybook build",
16+
"test-storybook": "test-storybook"
1417
},
1518
"devDependencies": {
1619
"@eslint/js": "^9.26.0",
20+
"@storybook/addon-a11y": "^9.0.0-rc.2",
21+
"@storybook/addon-designs": "^10.0.0",
22+
"@storybook/addon-docs": "^9.0.0-rc.2",
23+
"@storybook/addon-themes": "^9.0.0-rc.2",
24+
"@storybook/addon-vitest": "9.0.0-rc.2",
25+
"@storybook/react-vite": "^9.0.0-rc.2",
26+
"@storybook/test-runner": "^0.22.0",
1727
"@types/node": "^22.15.3",
1828
"@types/react": "^19.1.2",
1929
"@vitejs/plugin-react": "^4.4.1",
30+
"@vitest/browser": "^3.1.3",
31+
"@vitest/coverage-v8": "^3.1.3",
2032
"eslint": "^9.26.0",
2133
"eslint-plugin-react-hooks": "^5.2.0",
2234
"eslint-plugin-react-refresh": "^0.4.20",
35+
"eslint-plugin-storybook": "^9.0.0-rc.2",
2336
"globals": "^16.0.0",
37+
"playwright": "^1.52.0",
2438
"prettier": "^3.5.3",
2539
"shadcn": "2.5.0",
40+
"storybook": "^9.0.0-rc.2",
2641
"typescript": "~5.7.2",
2742
"typescript-eslint": "^8.31.1",
2843
"vite": "^6.3.1",
29-
"vite-plugin-dts": "^4.5.3"
44+
"vite-plugin-dts": "^4.5.3",
45+
"vitest": "^3.1.3"
3046
},
3147
"dependencies": {
3248
"@hookform/resolvers": "^5.0.1",
@@ -77,5 +93,10 @@
7793
"tw-animate-css": "^1.2.9",
7894
"vaul": "^1.1.2",
7995
"zod": "^3.24.3"
96+
},
97+
"eslintConfig": {
98+
"extends": [
99+
"plugin:storybook/recommended"
100+
]
80101
}
81102
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import type { Meta, StoryObj } from '@storybook/react-vite'
2+
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion.tsx'
3+
import { expect } from 'storybook/test'
4+
5+
const meta = {
6+
title: 'Components/Accordion',
7+
component: Accordion,
8+
parameters: {
9+
layout: 'centered',
10+
design: {
11+
type: 'figma',
12+
url: 'https://www.figma.com/design/dSsI9L6NSpNCorbSdiYd1k/Oasis-Design-System---shadcn-ui---Default---December-2024?node-id=1-434&p=f&t=RSGCFmRgOgVUlGFP-0',
13+
},
14+
},
15+
argTypes: {
16+
type: {
17+
control: 'radio',
18+
options: ['single', 'multiple'],
19+
},
20+
},
21+
tags: ['autodocs'],
22+
} satisfies Meta<typeof Accordion>
23+
24+
export default meta
25+
type Story = StoryObj<typeof meta>
26+
27+
export const Default: Story = {
28+
args: {
29+
type: 'single',
30+
children: (
31+
<>
32+
<AccordionItem value="item-1">
33+
<AccordionTrigger>Accordion item #1</AccordionTrigger>
34+
<AccordionContent>Accordion content #1</AccordionContent>
35+
</AccordionItem>
36+
<AccordionItem value="item-2">
37+
<AccordionTrigger>Accordion item #2</AccordionTrigger>
38+
<AccordionContent>Accordion content #2</AccordionContent>
39+
</AccordionItem>
40+
<AccordionItem value="item-3">
41+
<AccordionTrigger>Accordion item #3</AccordionTrigger>
42+
<AccordionContent>Accordion content #3</AccordionContent>
43+
</AccordionItem>
44+
</>
45+
),
46+
},
47+
play: async ({ canvasElement }) => {
48+
const accordion = canvasElement.querySelector('[data-slot="accordion"][data-orientation="vertical"]')
49+
await expect(accordion).not.toBeNull()
50+
const closedItems = canvasElement.querySelectorAll('[data-state="closed"][data-slot="accordion-item"]')
51+
await expect(closedItems.length).toBe(3)
52+
},
53+
}
54+
55+
export const Disabled: Story = {
56+
args: {
57+
type: 'single',
58+
children: (
59+
<>
60+
<AccordionItem value="item-1">
61+
<AccordionTrigger>Available item</AccordionTrigger>
62+
<AccordionContent>This item is available for interaction.</AccordionContent>
63+
</AccordionItem>
64+
<AccordionItem value="item-2">
65+
<AccordionTrigger disabled>Disabled item</AccordionTrigger>
66+
<AccordionContent>
67+
This content won't be accessible because the trigger is disabled.
68+
</AccordionContent>
69+
</AccordionItem>
70+
</>
71+
),
72+
},
73+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import type { Meta, StoryObj } from '@storybook/react-vite'
2+
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert.tsx'
3+
import { InfoIcon } from 'lucide-react'
4+
import { expect, within } from 'storybook/test'
5+
6+
const meta: Meta<typeof Alert> = {
7+
title: 'Components/Alert',
8+
component: Alert,
9+
parameters: {
10+
layout: 'centered',
11+
design: {
12+
type: 'figma',
13+
url: 'https://www.figma.com/design/dSsI9L6NSpNCorbSdiYd1k/Oasis-Design-System---shadcn-ui---Default---December-2024?node-id=21-322&p=f&t=RSGCFmRgOgVUlGFP-0',
14+
},
15+
},
16+
tags: ['autodocs'],
17+
}
18+
19+
export default meta
20+
type Story = StoryObj<typeof meta>
21+
22+
export const Default: Story = {
23+
args: {
24+
children: (
25+
<>
26+
<InfoIcon />
27+
<AlertTitle>Information</AlertTitle>
28+
<AlertDescription>
29+
Alert description provides additional information about the alert.
30+
</AlertDescription>
31+
</>
32+
),
33+
variant: 'default',
34+
},
35+
play: async ({ canvasElement }) => {
36+
const canvas = within(canvasElement)
37+
const alert = canvas.getByRole('alert')
38+
await expect(alert).toBeInTheDocument()
39+
},
40+
}

0 commit comments

Comments
 (0)