@storybook/tanstack-react 0.0.0-pr-34403-sha-53a142e3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json ADDED
@@ -0,0 +1,111 @@
1
+ {
2
+ "name": "@storybook/tanstack-react",
3
+ "version": "0.0.0-pr-34403-sha-53a142e3",
4
+ "description": "Storybook for TanStack (React, Vite): Router + Query ready Storybook framework",
5
+ "keywords": [
6
+ "storybook",
7
+ "storybook-framework",
8
+ "tanstack",
9
+ "tanstack-router",
10
+ "tanstack-query",
11
+ "react",
12
+ "vite",
13
+ "component",
14
+ "components"
15
+ ],
16
+ "homepage": "https://github.com/storybookjs/storybook/tree/next/code/frameworks/tanstack-react",
17
+ "bugs": {
18
+ "url": "https://github.com/storybookjs/storybook/issues"
19
+ },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "https://github.com/storybookjs/storybook.git",
23
+ "directory": "code/frameworks/tanstack-react"
24
+ },
25
+ "funding": {
26
+ "type": "opencollective",
27
+ "url": "https://opencollective.com/storybook"
28
+ },
29
+ "license": "MIT",
30
+ "type": "module",
31
+ "exports": {
32
+ ".": {
33
+ "types": "./dist/index.d.ts",
34
+ "code": "./src/index.ts",
35
+ "default": "./dist/index.js"
36
+ },
37
+ "./node": {
38
+ "types": "./dist/node/index.d.ts",
39
+ "code": "./src/node/index.ts",
40
+ "default": "./dist/node/index.js"
41
+ },
42
+ "./package.json": "./package.json",
43
+ "./preset": {
44
+ "types": "./dist/preset.d.ts",
45
+ "code": "./src/preset.ts",
46
+ "default": "./dist/preset.js"
47
+ },
48
+ "./preview": {
49
+ "types": "./dist/preview.d.ts",
50
+ "code": "./src/preview.tsx",
51
+ "default": "./dist/preview.js"
52
+ },
53
+ "./react-router": {
54
+ "types": "./dist/export-mocks/react-router.d.ts",
55
+ "code": "./src/export-mocks/react-router.ts",
56
+ "default": "./dist/export-mocks/react-router.js"
57
+ },
58
+ "./start": {
59
+ "types": "./dist/export-mocks/start.d.ts",
60
+ "code": "./src/export-mocks/start.ts",
61
+ "default": "./dist/export-mocks/start.js"
62
+ }
63
+ },
64
+ "files": [
65
+ "dist/**/*",
66
+ "template/**/*",
67
+ "README.md",
68
+ "*.js",
69
+ "*.d.ts",
70
+ "!src/**/*"
71
+ ],
72
+ "dependencies": {
73
+ "@storybook/builder-vite": "0.0.0-pr-34403-sha-53a142e3",
74
+ "@storybook/react": "0.0.0-pr-34403-sha-53a142e3",
75
+ "@storybook/react-vite": "0.0.0-pr-34403-sha-53a142e3"
76
+ },
77
+ "devDependencies": {
78
+ "@tanstack/react-router": "^1.168.10",
79
+ "@tanstack/react-start": "^1.167.16",
80
+ "@tanstack/router-core": "^1.168.9",
81
+ "@tanstack/start-client-core": "^1.167.9",
82
+ "@types/node": "^22.19.1",
83
+ "prop-types": "^15.7.2",
84
+ "typescript": "^5.9.3",
85
+ "vite": "^7.0.4"
86
+ },
87
+ "peerDependencies": {
88
+ "@tanstack/react-router": "^1.168.10",
89
+ "@tanstack/react-start": "^1.167.16",
90
+ "@tanstack/router-core": "^1.168.9",
91
+ "@tanstack/start-client-core": "^1.167.9",
92
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
93
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
94
+ "storybook": "^0.0.0-pr-34403-sha-53a142e3",
95
+ "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
96
+ },
97
+ "peerDependenciesMeta": {
98
+ "@tanstack/react-router": {
99
+ "optional": false
100
+ },
101
+ "@tanstack/react-start": {
102
+ "optional": true
103
+ },
104
+ "@tanstack/start-client-core": {
105
+ "optional": true
106
+ }
107
+ },
108
+ "publishConfig": {
109
+ "access": "public"
110
+ }
111
+ }
@@ -0,0 +1,54 @@
1
+ import type { Meta, StoryObj } from '@storybook/tanstack-react';
2
+
3
+ import { fn } from 'storybook/test';
4
+
5
+ import { Button } from './Button';
6
+
7
+ // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
8
+ const meta = {
9
+ title: 'Example/Button',
10
+ component: Button,
11
+ parameters: {
12
+ // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
13
+ layout: 'centered',
14
+ },
15
+ // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
16
+ tags: ['autodocs'],
17
+ // More on argTypes: https://storybook.js.org/docs/api/argtypes
18
+ argTypes: {
19
+ backgroundColor: { control: 'color' },
20
+ },
21
+ // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#story-args
22
+ args: { onClick: fn() },
23
+ } satisfies Meta<typeof Button>;
24
+
25
+ export default meta;
26
+ type Story = StoryObj<typeof meta>;
27
+
28
+ // More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
29
+ export const Primary: Story = {
30
+ args: {
31
+ primary: true,
32
+ label: 'Button',
33
+ },
34
+ };
35
+
36
+ export const Secondary: Story = {
37
+ args: {
38
+ label: 'Button',
39
+ },
40
+ };
41
+
42
+ export const Large: Story = {
43
+ args: {
44
+ size: 'large',
45
+ label: 'Button',
46
+ },
47
+ };
48
+
49
+ export const Small: Story = {
50
+ args: {
51
+ size: 'small',
52
+ label: 'Button',
53
+ },
54
+ };
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+
3
+ export interface ButtonProps {
4
+ /** Is this the principal call to action on the page? */
5
+ primary?: boolean;
6
+ /** What background color to use */
7
+ backgroundColor?: string;
8
+ /** How large should the button be? */
9
+ size?: 'small' | 'medium' | 'large';
10
+ /** Button contents */
11
+ label: string;
12
+ /** Optional click handler */
13
+ onClick?: () => void;
14
+ }
15
+
16
+ /** Primary UI component for user interaction */
17
+ export const Button = ({
18
+ primary = false,
19
+ size = 'medium',
20
+ backgroundColor,
21
+ label,
22
+ ...props
23
+ }: ButtonProps) => {
24
+ const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';
25
+ return (
26
+ <button
27
+ type="button"
28
+ className={['storybook-button', `storybook-button--${size}`, mode].join(' ')}
29
+ style={{ backgroundColor }}
30
+ {...props}
31
+ >
32
+ {label}
33
+ </button>
34
+ );
35
+ };
@@ -0,0 +1,34 @@
1
+ import type { Meta, StoryObj } from '@storybook/tanstack-react';
2
+
3
+ import { fn } from 'storybook/test';
4
+
5
+ import { Header } from './Header';
6
+
7
+ const meta = {
8
+ title: 'Example/Header',
9
+ component: Header,
10
+ // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
11
+ tags: ['autodocs'],
12
+ parameters: {
13
+ // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout
14
+ layout: 'fullscreen',
15
+ },
16
+ args: {
17
+ onLogin: fn(),
18
+ onLogout: fn(),
19
+ onCreateAccount: fn(),
20
+ },
21
+ } satisfies Meta<typeof Header>;
22
+
23
+ export default meta;
24
+ type Story = StoryObj<typeof meta>;
25
+
26
+ export const LoggedIn: Story = {
27
+ args: {
28
+ user: {
29
+ name: 'Jane Doe',
30
+ },
31
+ },
32
+ };
33
+
34
+ export const LoggedOut: Story = {};
@@ -0,0 +1,55 @@
1
+ import React from 'react';
2
+
3
+ import { Button } from './Button';
4
+
5
+ type User = {
6
+ name: string;
7
+ };
8
+
9
+ export interface HeaderProps {
10
+ user?: User;
11
+ onLogin?: () => void;
12
+ onLogout?: () => void;
13
+ onCreateAccount?: () => void;
14
+ }
15
+
16
+ export const Header = ({ user, onLogin, onLogout, onCreateAccount }: HeaderProps) => (
17
+ <header>
18
+ <div className="storybook-header">
19
+ <div>
20
+ <svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
21
+ <g fill="none" fillRule="evenodd">
22
+ <path
23
+ d="M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z"
24
+ fill="#FFF"
25
+ />
26
+ <path
27
+ d="M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z"
28
+ fill="#555AB9"
29
+ />
30
+ <path
31
+ d="M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z"
32
+ fill="#91BAF8"
33
+ />
34
+ </g>
35
+ </svg>
36
+ <h1>Acme</h1>
37
+ </div>
38
+ <div>
39
+ {user ? (
40
+ <>
41
+ <span className="welcome">
42
+ Welcome, <b>{user.name}</b>!
43
+ </span>
44
+ <Button size="small" onClick={onLogout} label="Log out" />
45
+ </>
46
+ ) : (
47
+ <>
48
+ <Button size="small" onClick={onLogin} label="Log in" />
49
+ <Button primary size="small" onClick={onCreateAccount} label="Sign up" />
50
+ </>
51
+ )}
52
+ </div>
53
+ </div>
54
+ </header>
55
+ );
@@ -0,0 +1,33 @@
1
+ import type { Meta, StoryObj } from '@storybook/tanstack-react';
2
+
3
+ import { expect, userEvent, within } from 'storybook/test';
4
+
5
+ import { Route } from './Page';
6
+
7
+ const meta = {
8
+ title: 'Example/Page',
9
+ component: Route,
10
+ parameters: {
11
+ // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout
12
+ layout: 'fullscreen',
13
+ },
14
+ } satisfies Meta<typeof Route>;
15
+
16
+ export default meta;
17
+ type Story = StoryObj<typeof meta>;
18
+
19
+ export const LoggedOut: Story = {};
20
+
21
+ // More on component testing: https://storybook.js.org/docs/writing-tests/interaction-testing
22
+ export const LoggedIn: Story = {
23
+ play: async ({ canvasElement }) => {
24
+ const canvas = within(canvasElement);
25
+ const loginButton = canvas.getByRole('button', { name: /Log in/i });
26
+ await expect(loginButton).toBeInTheDocument();
27
+ await userEvent.click(loginButton);
28
+ await expect(loginButton).not.toBeInTheDocument();
29
+
30
+ const logoutButton = canvas.getByRole('button', { name: /Log out/i });
31
+ await expect(logoutButton).toBeInTheDocument();
32
+ },
33
+ };
@@ -0,0 +1,159 @@
1
+ import React from 'react';
2
+
3
+ import { Link, useLoaderData, useRouterState, createFileRoute } from '@tanstack/react-router';
4
+
5
+ import { Header } from './Header';
6
+
7
+ type User = {
8
+ name: string;
9
+ };
10
+
11
+ declare module '@tanstack/react-router' {
12
+ interface FileRoutesByPath {
13
+ '/storybook': {};
14
+ }
15
+ }
16
+
17
+ export const Route = createFileRoute('/storybook')({
18
+ loader: async () => {
19
+ return {
20
+ featuredItems: [
21
+ { id: 1, title: 'Item 1', description: 'This is the first item.' },
22
+ { id: 2, title: 'Item 2', description: 'This is the second item.' },
23
+ { id: 3, title: 'Item 3', description: 'This is the third item.' },
24
+ ],
25
+ };
26
+ },
27
+ component: () => <Page />,
28
+ });
29
+
30
+ export type PageLoaderData = {
31
+ featuredItems: Array<{ id: number; title: string; description: string }>;
32
+ };
33
+
34
+ const Page: React.FC = () => {
35
+ const [user, setUser] = React.useState<User>();
36
+ const { featuredItems } = useLoaderData({ strict: false }) as PageLoaderData;
37
+
38
+ return (
39
+ <article>
40
+ <Header
41
+ user={user}
42
+ onLogin={() => setUser({ name: 'Jane Doe' })}
43
+ onLogout={() => setUser(undefined)}
44
+ onCreateAccount={() => setUser({ name: 'Jane Doe' })}
45
+ />
46
+
47
+ <section className="storybook-page">
48
+ <h2>TanStack Router in Storybook</h2>
49
+
50
+ <CurrentRoute />
51
+
52
+ {featuredItems?.length > 0 && (
53
+ <>
54
+ <h3>Loaded via route loader</h3>
55
+ <ul
56
+ style={{ listStyle: 'none', padding: 0, display: 'flex', gap: 12, flexWrap: 'wrap' }}
57
+ >
58
+ {featuredItems.map((item) => (
59
+ <li
60
+ key={item.id}
61
+ style={{
62
+ padding: '12px 16px',
63
+ background: '#f6f9fc',
64
+ border: '1px solid #e0e6ef',
65
+ borderRadius: 8,
66
+ minWidth: 180,
67
+ }}
68
+ >
69
+ <strong>{item.title}</strong>
70
+ <p style={{ margin: '4px 0 0', fontSize: 13, color: '#666' }}>
71
+ {item.description}
72
+ </p>
73
+ </li>
74
+ ))}
75
+ </ul>
76
+ </>
77
+ )}
78
+
79
+ <CurrentRoute />
80
+
81
+ <p>
82
+ Every story is wrapped in a TanStack Router provider automatically. Click the links below
83
+ and check the <strong>Actions</strong> panel to see the <code>onNavigate</code> spy
84
+ capture each navigation attempt.
85
+ </p>
86
+
87
+ <nav
88
+ style={{
89
+ display: 'flex',
90
+ gap: 8,
91
+ flexWrap: 'wrap',
92
+ marginBottom: 24,
93
+ }}
94
+ >
95
+ <Link
96
+ to="/"
97
+ className="storybook-button storybook-button--small storybook-button--secondary"
98
+ >
99
+ Home
100
+ </Link>
101
+ <Link
102
+ to="/about"
103
+ className="storybook-button storybook-button--small storybook-button--secondary"
104
+ >
105
+ About
106
+ </Link>
107
+ <Link
108
+ to="/settings"
109
+ search={{ tab: 'profile' }}
110
+ className="storybook-button storybook-button--small storybook-button--secondary"
111
+ >
112
+ Settings
113
+ </Link>
114
+ </nav>
115
+
116
+ <p>
117
+ The current route display above reads from <code>useRouterState()</code> — a real TanStack
118
+ Router hook running inside Storybook's mock router. Use the{' '}
119
+ <code>tanstack.router.path</code> story parameter to set the initial route.
120
+ </p>
121
+
122
+ <div className="tip-wrapper">
123
+ <span className="tip">Tip</span> Each navigation is intercepted and logged as an action.
124
+ No page actually changes — this lets you test routing behavior in isolation.
125
+ </div>
126
+ </section>
127
+ </article>
128
+ );
129
+ };
130
+ function CurrentRoute() {
131
+ const { location } = useRouterState();
132
+
133
+ return (
134
+ <div
135
+ style={{
136
+ padding: '12px 16px',
137
+ background: '#f6f9fc',
138
+ border: '1px solid #e0e6ef',
139
+ borderRadius: 8,
140
+ fontFamily: 'monospace',
141
+ fontSize: 13,
142
+ marginBottom: 24,
143
+ display: 'flex',
144
+ gap: 12,
145
+ alignItems: 'center',
146
+ flexWrap: 'wrap',
147
+ }}
148
+ >
149
+ <span style={{ fontWeight: 600, color: '#333' }}>Current route:</span>
150
+ <code style={{ color: '#029cfd' }}>{location.pathname}</code>
151
+ {location.searchStr && (
152
+ <>
153
+ <span style={{ color: '#666' }}>search:</span>
154
+ <code style={{ color: '#66bf3c' }}>{location.searchStr}</code>
155
+ </>
156
+ )}
157
+ </div>
158
+ );
159
+ }