@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/README.md +7 -0
- package/dist/_browser-chunks/chunk-4BE7D4DS.js +9 -0
- package/dist/_browser-chunks/chunk-4CKCBIXI.js +7 -0
- package/dist/_browser-chunks/chunk-LJRZDJ5L.js +113 -0
- package/dist/export-mocks/react-router.d.ts +349 -0
- package/dist/export-mocks/react-router.js +90 -0
- package/dist/export-mocks/start.d.ts +18 -0
- package/dist/export-mocks/start.js +37 -0
- package/dist/index.d.ts +408 -0
- package/dist/index.js +17 -0
- package/dist/node/index.d.ts +28 -0
- package/dist/node/index.js +19 -0
- package/dist/preset.d.ts +8 -0
- package/dist/preset.js +74 -0
- package/dist/preview.d.ts +69 -0
- package/dist/preview.js +11 -0
- package/package.json +111 -0
- package/template/cli/ts/Button.stories.ts +54 -0
- package/template/cli/ts/Button.tsx +35 -0
- package/template/cli/ts/Header.stories.ts +34 -0
- package/template/cli/ts/Header.tsx +55 -0
- package/template/cli/ts/Page.stories.ts +33 -0
- package/template/cli/ts/Page.tsx +159 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
import { ComponentType } from 'react';
|
|
2
|
+
import { PreviewAddon, InferTypes, AddonTypes } from 'storybook/internal/csf';
|
|
3
|
+
import { CompatibleString, ProjectAnnotations, Args, DecoratorFunction, ArgsStoryFn, ComponentAnnotations, Renderer, StoryAnnotations } from 'storybook/internal/types';
|
|
4
|
+
import { AnyRoute, FileRoutesByPath } from '@tanstack/react-router';
|
|
5
|
+
import { ReactTypes, ReactPreview, ReactMeta, ReactRenderer, Meta as Meta$1, StoryObj as StoryObj$1 } from '@storybook/react';
|
|
6
|
+
export * from '@storybook/react';
|
|
7
|
+
import { BuilderOptions } from '@storybook/builder-vite';
|
|
8
|
+
import { StorybookConfig as StorybookConfig$1 } from '@storybook/react-vite';
|
|
9
|
+
import { RouteOptions } from '@tanstack/router-core';
|
|
10
|
+
|
|
11
|
+
declare global {
|
|
12
|
+
interface SymbolConstructor {
|
|
13
|
+
readonly observable: symbol;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
@see Simplify
|
|
19
|
+
*/
|
|
20
|
+
interface SimplifyOptions {
|
|
21
|
+
/**
|
|
22
|
+
Do the simplification recursively.
|
|
23
|
+
|
|
24
|
+
@default false
|
|
25
|
+
*/
|
|
26
|
+
deep?: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Flatten a type without worrying about the result.
|
|
30
|
+
type Flatten<
|
|
31
|
+
AnyType,
|
|
32
|
+
Options extends SimplifyOptions = {},
|
|
33
|
+
> = Options['deep'] extends true
|
|
34
|
+
? {[KeyType in keyof AnyType]: Simplify<AnyType[KeyType], Options>}
|
|
35
|
+
: {[KeyType in keyof AnyType]: AnyType[KeyType]};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
Useful to flatten the type output to improve type hints shown in editors. And also to transform an interface into a type to aide with assignability.
|
|
39
|
+
|
|
40
|
+
@example
|
|
41
|
+
```
|
|
42
|
+
import type {Simplify} from 'type-fest';
|
|
43
|
+
|
|
44
|
+
type PositionProps = {
|
|
45
|
+
top: number;
|
|
46
|
+
left: number;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
type SizeProps = {
|
|
50
|
+
width: number;
|
|
51
|
+
height: number;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// In your editor, hovering over `Props` will show a flattened object with all the properties.
|
|
55
|
+
type Props = Simplify<PositionProps & SizeProps>;
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Sometimes it is desired to pass a value as a function argument that has a different type. At first inspection it may seem assignable, and then you discover it is not because the `value`'s type definition was defined as an interface. In the following example, `fn` requires an argument of type `Record<string, unknown>`. If the value is defined as a literal, then it is assignable. And if the `value` is defined as type using the `Simplify` utility the value is assignable. But if the `value` is defined as an interface, it is not assignable because the interface is not sealed and elsewhere a non-string property could be added to the interface.
|
|
59
|
+
|
|
60
|
+
If the type definition must be an interface (perhaps it was defined in a third-party npm package), then the `value` can be defined as `const value: Simplify<SomeInterface> = ...`. Then `value` will be assignable to the `fn` argument. Or the `value` can be cast as `Simplify<SomeInterface>` if you can't re-declare the `value`.
|
|
61
|
+
|
|
62
|
+
@example
|
|
63
|
+
```
|
|
64
|
+
import type {Simplify} from 'type-fest';
|
|
65
|
+
|
|
66
|
+
interface SomeInterface {
|
|
67
|
+
foo: number;
|
|
68
|
+
bar?: string;
|
|
69
|
+
baz: number | undefined;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
type SomeType = {
|
|
73
|
+
foo: number;
|
|
74
|
+
bar?: string;
|
|
75
|
+
baz: number | undefined;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const literal = {foo: 123, bar: 'hello', baz: 456};
|
|
79
|
+
const someType: SomeType = literal;
|
|
80
|
+
const someInterface: SomeInterface = literal;
|
|
81
|
+
|
|
82
|
+
function fn(object: Record<string, unknown>): void {}
|
|
83
|
+
|
|
84
|
+
fn(literal); // Good: literal object type is sealed
|
|
85
|
+
fn(someType); // Good: type is sealed
|
|
86
|
+
fn(someInterface); // Error: Index signature for type 'string' is missing in type 'someInterface'. Because `interface` can be re-opened
|
|
87
|
+
fn(someInterface as Simplify<SomeInterface>); // Good: transform an `interface` into a `type`
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
@link https://github.com/microsoft/TypeScript/issues/15300
|
|
91
|
+
|
|
92
|
+
@category Object
|
|
93
|
+
*/
|
|
94
|
+
type Simplify<
|
|
95
|
+
AnyType,
|
|
96
|
+
Options extends SimplifyOptions = {},
|
|
97
|
+
> = Flatten<AnyType> extends AnyType
|
|
98
|
+
? Flatten<AnyType, Options>
|
|
99
|
+
: AnyType;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
Remove any index signatures from the given object type, so that only explicitly defined properties remain.
|
|
103
|
+
|
|
104
|
+
Use-cases:
|
|
105
|
+
- Remove overly permissive signatures from third-party types.
|
|
106
|
+
|
|
107
|
+
This type was taken from this [StackOverflow answer](https://stackoverflow.com/a/68261113/420747).
|
|
108
|
+
|
|
109
|
+
It relies on the fact that an empty object (`{}`) is assignable to an object with just an index signature, like `Record<string, unknown>`, but not to an object with explicitly defined keys, like `Record<'foo' | 'bar', unknown>`.
|
|
110
|
+
|
|
111
|
+
(The actual value type, `unknown`, is irrelevant and could be any type. Only the key type matters.)
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
const indexed: Record<string, unknown> = {}; // Allowed
|
|
115
|
+
|
|
116
|
+
const keyed: Record<'foo', unknown> = {}; // Error
|
|
117
|
+
// => TS2739: Type '{}' is missing the following properties from type 'Record<"foo" | "bar", unknown>': foo, bar
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Instead of causing a type error like the above, you can also use a [conditional type](https://www.typescriptlang.org/docs/handbook/2/conditional-types.html) to test whether a type is assignable to another:
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
type Indexed = {} extends Record<string, unknown>
|
|
124
|
+
? '✅ `{}` is assignable to `Record<string, unknown>`'
|
|
125
|
+
: '❌ `{}` is NOT assignable to `Record<string, unknown>`';
|
|
126
|
+
// => '✅ `{}` is assignable to `Record<string, unknown>`'
|
|
127
|
+
|
|
128
|
+
type Keyed = {} extends Record<'foo' | 'bar', unknown>
|
|
129
|
+
? "✅ `{}` is assignable to `Record<'foo' | 'bar', unknown>`"
|
|
130
|
+
: "❌ `{}` is NOT assignable to `Record<'foo' | 'bar', unknown>`";
|
|
131
|
+
// => "❌ `{}` is NOT assignable to `Record<'foo' | 'bar', unknown>`"
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Using a [mapped type](https://www.typescriptlang.org/docs/handbook/2/mapped-types.html#further-exploration), you can then check for each `KeyType` of `ObjectType`...
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
import type {RemoveIndexSignature} from 'type-fest';
|
|
138
|
+
|
|
139
|
+
type RemoveIndexSignature<ObjectType> = {
|
|
140
|
+
[KeyType in keyof ObjectType // Map each key of `ObjectType`...
|
|
141
|
+
]: ObjectType[KeyType]; // ...to its original value, i.e. `RemoveIndexSignature<Foo> == Foo`.
|
|
142
|
+
};
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
...whether an empty object (`{}`) would be assignable to an object with that `KeyType` (`Record<KeyType, unknown>`)...
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
import type {RemoveIndexSignature} from 'type-fest';
|
|
149
|
+
|
|
150
|
+
type RemoveIndexSignature<ObjectType> = {
|
|
151
|
+
[KeyType in keyof ObjectType
|
|
152
|
+
// Is `{}` assignable to `Record<KeyType, unknown>`?
|
|
153
|
+
as {} extends Record<KeyType, unknown>
|
|
154
|
+
? ... // ✅ `{}` is assignable to `Record<KeyType, unknown>`
|
|
155
|
+
: ... // ❌ `{}` is NOT assignable to `Record<KeyType, unknown>`
|
|
156
|
+
]: ObjectType[KeyType];
|
|
157
|
+
};
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
If `{}` is assignable, it means that `KeyType` is an index signature and we want to remove it. If it is not assignable, `KeyType` is a "real" key and we want to keep it.
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
import type {RemoveIndexSignature} from 'type-fest';
|
|
164
|
+
|
|
165
|
+
type RemoveIndexSignature<ObjectType> = {
|
|
166
|
+
[KeyType in keyof ObjectType
|
|
167
|
+
as {} extends Record<KeyType, unknown>
|
|
168
|
+
? never // => Remove this `KeyType`.
|
|
169
|
+
: KeyType // => Keep this `KeyType` as it is.
|
|
170
|
+
]: ObjectType[KeyType];
|
|
171
|
+
};
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
@example
|
|
175
|
+
```
|
|
176
|
+
import type {RemoveIndexSignature} from 'type-fest';
|
|
177
|
+
|
|
178
|
+
interface Example {
|
|
179
|
+
// These index signatures will be removed.
|
|
180
|
+
[x: string]: any
|
|
181
|
+
[x: number]: any
|
|
182
|
+
[x: symbol]: any
|
|
183
|
+
[x: `head-${string}`]: string
|
|
184
|
+
[x: `${string}-tail`]: string
|
|
185
|
+
[x: `head-${string}-tail`]: string
|
|
186
|
+
[x: `${bigint}`]: string
|
|
187
|
+
[x: `embedded-${number}`]: string
|
|
188
|
+
|
|
189
|
+
// These explicitly defined keys will remain.
|
|
190
|
+
foo: 'bar';
|
|
191
|
+
qux?: 'baz';
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
type ExampleWithoutIndexSignatures = RemoveIndexSignature<Example>;
|
|
195
|
+
// => { foo: 'bar'; qux?: 'baz' | undefined; }
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
@category Object
|
|
199
|
+
*/
|
|
200
|
+
type RemoveIndexSignature<ObjectType> = {
|
|
201
|
+
[KeyType in keyof ObjectType as {} extends Record<KeyType, unknown>
|
|
202
|
+
? never
|
|
203
|
+
: KeyType]: ObjectType[KeyType];
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
Convert a union type to an intersection type using [distributive conditional types](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types).
|
|
208
|
+
|
|
209
|
+
Inspired by [this Stack Overflow answer](https://stackoverflow.com/a/50375286/2172153).
|
|
210
|
+
|
|
211
|
+
@example
|
|
212
|
+
```
|
|
213
|
+
import type {UnionToIntersection} from 'type-fest';
|
|
214
|
+
|
|
215
|
+
type Union = {the(): void} | {great(arg: string): void} | {escape: boolean};
|
|
216
|
+
|
|
217
|
+
type Intersection = UnionToIntersection<Union>;
|
|
218
|
+
//=> {the(): void; great(arg: string): void; escape: boolean};
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
A more applicable example which could make its way into your library code follows.
|
|
222
|
+
|
|
223
|
+
@example
|
|
224
|
+
```
|
|
225
|
+
import type {UnionToIntersection} from 'type-fest';
|
|
226
|
+
|
|
227
|
+
class CommandOne {
|
|
228
|
+
commands: {
|
|
229
|
+
a1: () => undefined,
|
|
230
|
+
b1: () => undefined,
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
class CommandTwo {
|
|
235
|
+
commands: {
|
|
236
|
+
a2: (argA: string) => undefined,
|
|
237
|
+
b2: (argB: string) => undefined,
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const union = [new CommandOne(), new CommandTwo()].map(instance => instance.commands);
|
|
242
|
+
type Union = typeof union;
|
|
243
|
+
//=> {a1(): void; b1(): void} | {a2(argA: string): void; b2(argB: string): void}
|
|
244
|
+
|
|
245
|
+
type Intersection = UnionToIntersection<Union>;
|
|
246
|
+
//=> {a1(): void; b1(): void; a2(argA: string): void; b2(argB: string): void}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
@category Type
|
|
250
|
+
*/
|
|
251
|
+
type UnionToIntersection<Union> = (
|
|
252
|
+
// `extends unknown` is always going to be the case and is used to convert the
|
|
253
|
+
// `Union` into a [distributive conditional
|
|
254
|
+
// type](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types).
|
|
255
|
+
Union extends unknown
|
|
256
|
+
// The union type is used as the only argument to a function since the union
|
|
257
|
+
// of function arguments is an intersection.
|
|
258
|
+
? (distributedUnion: Union) => void
|
|
259
|
+
// This won't happen.
|
|
260
|
+
: never
|
|
261
|
+
// Infer the `Intersection` type since TypeScript represents the positional
|
|
262
|
+
// arguments of unions of functions as an intersection of the union.
|
|
263
|
+
) extends ((mergedIntersection: infer Intersection) => void)
|
|
264
|
+
? Intersection
|
|
265
|
+
: never;
|
|
266
|
+
|
|
267
|
+
type IsRoute<T> = T extends AnyRoute ? true : T extends FileRoutesByPath[keyof FileRoutesByPath] ? true : false;
|
|
268
|
+
type StoryRoutePathForRoute<TRoute> = TRoute extends {
|
|
269
|
+
path: infer P;
|
|
270
|
+
} ? unknown extends P ? keyof FileRoutesByPath | (string & {}) : P extends '/' ? `/${string}` : P extends string ? P | `${P}/${string}` : keyof FileRoutesByPath | (string & {}) : keyof FileRoutesByPath | (string & {});
|
|
271
|
+
type StoryRoutePath<TRoute = undefined> = IsRoute<TRoute> extends true ? StoryRoutePathForRoute<TRoute> : keyof FileRoutesByPath | (string & {});
|
|
272
|
+
type StoryRouteParams<TRoute> = IsRoute<TRoute> extends true ? TRoute extends {
|
|
273
|
+
types: {
|
|
274
|
+
allParams: infer P;
|
|
275
|
+
};
|
|
276
|
+
} ? unknown extends P ? Record<string, string> : P : Record<string, string> : Record<string, string>;
|
|
277
|
+
type StoryRouteSearch<TRoute> = IsRoute<TRoute> extends true ? TRoute extends {
|
|
278
|
+
types: {
|
|
279
|
+
fullSearchSchema: infer S;
|
|
280
|
+
};
|
|
281
|
+
} ? unknown extends S ? Record<string, unknown> : S : Record<string, unknown> : Record<string, unknown>;
|
|
282
|
+
type StoryRouteFileOptions<TRoute = undefined> = IsRoute<TRoute> extends true ? TRoute extends {
|
|
283
|
+
options: infer O;
|
|
284
|
+
} ? Pick<O, Extract<keyof O, 'loader' | 'beforeLoad' | 'validateSearch' | 'loaderDeps' | 'context' | 'params' | 'head' | 'search' | 'parseParams' | 'context'>> : Pick<RouteOptions<unknown>, 'loader' | 'beforeLoad' | 'validateSearch' | 'loaderDeps' | 'context' | 'params' | 'head' | 'search' | 'parseParams' | 'context'> : Pick<RouteOptions<unknown>, 'loader' | 'beforeLoad' | 'validateSearch' | 'loaderDeps' | 'context' | 'params' | 'head' | 'search' | 'parseParams' | 'context'>;
|
|
285
|
+
type CreateStoryRouteOptions<TRoute = undefined> = StoryRouteFileOptions<TRoute> & {
|
|
286
|
+
path?: StoryRoutePath<TRoute>;
|
|
287
|
+
};
|
|
288
|
+
type StoryRouteOptions<TRoute = undefined> = CreateStoryRouteOptions<TRoute> | AnyRoute;
|
|
289
|
+
/**
|
|
290
|
+
* Extracts a single route option type directly from the route's options,
|
|
291
|
+
* avoiding indexing into deferred conditional types (which causes DTS errors).
|
|
292
|
+
*/
|
|
293
|
+
type RouteOption<TRoute, K extends string> = IsRoute<TRoute> extends true ? TRoute extends {
|
|
294
|
+
options: Record<K, infer V>;
|
|
295
|
+
} ? V : undefined : K extends keyof RouteOptions<unknown> ? RouteOptions<unknown>[K] : undefined;
|
|
296
|
+
interface RouterParameters<TRoute = undefined> {
|
|
297
|
+
/** A route object or route options to use for this story. */
|
|
298
|
+
route?: StoryRouteOptions<TRoute>;
|
|
299
|
+
/** The initial URL path to render. */
|
|
300
|
+
path?: StoryRoutePath<TRoute>;
|
|
301
|
+
/** URL params to interpolate into the path (e.g. `{ id: '42' }` for `/$id`). */
|
|
302
|
+
params?: StoryRouteParams<TRoute>;
|
|
303
|
+
/** Search/query params to append to the URL (e.g. `{ tab: 'details' }`). */
|
|
304
|
+
query?: Partial<StoryRouteSearch<TRoute>>;
|
|
305
|
+
/** Override the route's loader function. */
|
|
306
|
+
loader?: RouteOption<TRoute, 'loader'>;
|
|
307
|
+
/** Override the route's beforeLoad function. */
|
|
308
|
+
beforeLoad?: RouteOption<TRoute, 'beforeLoad'>;
|
|
309
|
+
/** Override the route's search params validation. */
|
|
310
|
+
validateSearch?: RouteOption<TRoute, 'validateSearch'>;
|
|
311
|
+
/** Override the route's loader dependencies. */
|
|
312
|
+
loaderDeps?: RouteOption<TRoute, 'loaderDeps'>;
|
|
313
|
+
/** Override the route's context. */
|
|
314
|
+
context?: Record<string, unknown>;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
type FrameworkName = CompatibleString<'@storybook/tanstack-react'>;
|
|
318
|
+
type BuilderName = CompatibleString<'@storybook/builder-vite'>;
|
|
319
|
+
type FrameworkOptions = {
|
|
320
|
+
/** Builder options passed through to @storybook/builder-vite. */
|
|
321
|
+
builder?: BuilderOptions;
|
|
322
|
+
};
|
|
323
|
+
type StorybookConfigFramework = {
|
|
324
|
+
framework: FrameworkName | {
|
|
325
|
+
name: FrameworkName;
|
|
326
|
+
options: FrameworkOptions;
|
|
327
|
+
};
|
|
328
|
+
core?: StorybookConfig$1['core'] & {
|
|
329
|
+
builder?: BuilderName | {
|
|
330
|
+
name: BuilderName;
|
|
331
|
+
options: BuilderOptions;
|
|
332
|
+
};
|
|
333
|
+
};
|
|
334
|
+
};
|
|
335
|
+
/** The interface for Storybook configuration in `main.ts` files. */
|
|
336
|
+
type StorybookConfig = Omit<StorybookConfig$1, keyof StorybookConfigFramework> & StorybookConfigFramework;
|
|
337
|
+
interface TanStackPreviewOptions<TRoute = undefined> {
|
|
338
|
+
/** Router configuration for stories */
|
|
339
|
+
router?: RouterParameters<TRoute>;
|
|
340
|
+
}
|
|
341
|
+
interface TanStackParameters<TRoute = undefined> {
|
|
342
|
+
/** TanStack framework configuration (router integration). */
|
|
343
|
+
tanstack?: TanStackPreviewOptions<TRoute>;
|
|
344
|
+
}
|
|
345
|
+
interface TanStackTypes<TRoute = undefined> {
|
|
346
|
+
parameters: TanStackParameters<TRoute>;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/** Extracts and unions all args types from an array of decorators. */
|
|
350
|
+
type DecoratorsArgs<TRenderer extends Renderer, Decorators> = UnionToIntersection<Decorators extends DecoratorFunction<TRenderer, infer TArgs> ? TArgs : unknown>;
|
|
351
|
+
type InferCombinedTypes<T, TArgs, Decorators> = ReactTypes & T & {
|
|
352
|
+
args: Simplify<TArgs & Simplify<RemoveIndexSignature<DecoratorsArgs<ReactTypes & T, Decorators>>>>;
|
|
353
|
+
};
|
|
354
|
+
type Preview<TRoute extends AnyRoute | undefined = undefined> = ProjectAnnotations<ReactTypes & TanStackTypes<TRoute>>;
|
|
355
|
+
declare function definePreview<TRoute extends AnyRoute | undefined = undefined, Addons extends PreviewAddon<never>[] = []>(preview: {
|
|
356
|
+
addons?: Addons;
|
|
357
|
+
route?: TRoute;
|
|
358
|
+
} & ProjectAnnotations<ReactTypes & TanStackTypes<NoInfer<TRoute>> & InferTypes<Addons>>): TanStackPreview<InferTypes<Addons>, TRoute>;
|
|
359
|
+
/**
|
|
360
|
+
* Metadata to configure stories for a component or a TanStack Route.
|
|
361
|
+
*
|
|
362
|
+
* When `TCmpOrArgs` is a TanStack Route, the `component` field accepts the
|
|
363
|
+
* Route object directly and TanStack parameters (params, query, loader, etc.)
|
|
364
|
+
* are inferred from the route's types.
|
|
365
|
+
*/
|
|
366
|
+
type Meta<TCmpOrArgs = Args> = IsRoute<TCmpOrArgs> extends true ? Omit<ComponentAnnotations<ReactRenderer, Args>, 'component'> & Partial<TanStackTypes<TCmpOrArgs>> & {
|
|
367
|
+
component?: TCmpOrArgs;
|
|
368
|
+
} : Meta$1<TCmpOrArgs>;
|
|
369
|
+
/**
|
|
370
|
+
* When the meta's `component` is a TanStack Route, the story inherits
|
|
371
|
+
* TanStack parameter types for type-safe params/query/loader configuration.
|
|
372
|
+
*/
|
|
373
|
+
type StoryObj<TMetaOrCmpOrArgs = unknown> = [TMetaOrCmpOrArgs] extends [
|
|
374
|
+
{
|
|
375
|
+
component?: infer Component;
|
|
376
|
+
}
|
|
377
|
+
] ? IsRoute<Component> extends true ? StoryAnnotations<ReactRenderer, Args, Partial<Args>> & Partial<TanStackTypes<Component>> : StoryObj$1<TMetaOrCmpOrArgs> & Partial<TanStackTypes> : IsRoute<TMetaOrCmpOrArgs> extends true ? StoryAnnotations<ReactRenderer, Args, Partial<Args>> & Partial<TanStackTypes<TMetaOrCmpOrArgs>> : StoryObj$1<TMetaOrCmpOrArgs> & Partial<TanStackTypes>;
|
|
378
|
+
interface TanStackPreview<T extends AddonTypes, TRoute extends AnyRoute | undefined = undefined> extends ReactPreview<TanStackTypes<TRoute> & T> {
|
|
379
|
+
type<R>(): TanStackPreview<T & R, TRoute>;
|
|
380
|
+
meta<TMetaRoute extends AnyRoute, TArgs extends Args, Decorators extends DecoratorFunction<ReactTypes & TanStackTypes<TMetaRoute> & T, any>, TMetaArgs extends Partial<TArgs & (TanStackTypes<TMetaRoute> & T)['args']>>(meta: {
|
|
381
|
+
render?: ArgsStoryFn<ReactTypes & TanStackTypes<TMetaRoute> & T, TArgs & (TanStackTypes<TMetaRoute> & T)['args']>;
|
|
382
|
+
component?: ComponentType<TArgs>;
|
|
383
|
+
/** Provide a route to enable type-safe params/query/loader inference for this meta. */
|
|
384
|
+
route: TMetaRoute;
|
|
385
|
+
decorators?: Decorators | Decorators[];
|
|
386
|
+
args?: TMetaArgs;
|
|
387
|
+
} & Omit<ComponentAnnotations<ReactTypes & TanStackTypes<TMetaRoute> & T, TArgs>, 'decorators' | 'component' | 'args' | 'render'>): ReactMeta<InferCombinedTypes<TanStackTypes<TMetaRoute> & T, TArgs, Decorators>, Omit<ComponentAnnotations<InferCombinedTypes<TanStackTypes<TMetaRoute> & T, TArgs, Decorators>>, 'args'> & {
|
|
388
|
+
args: Partial<TArgs> extends TMetaArgs ? {} : TMetaArgs;
|
|
389
|
+
}>;
|
|
390
|
+
meta<TMetaRoute extends AnyRoute | FileRoutesByPath[keyof FileRoutesByPath], TArgs extends Args, Decorators extends DecoratorFunction<ReactTypes & TanStackTypes<TMetaRoute> & T, any>, TMetaArgs extends Partial<TArgs & (TanStackTypes<TMetaRoute> & T)['args']>>(meta: {
|
|
391
|
+
render?: ArgsStoryFn<ReactTypes & TanStackTypes<TMetaRoute> & T, TArgs & (TanStackTypes<TMetaRoute> & T)['args']>;
|
|
392
|
+
component: TMetaRoute;
|
|
393
|
+
decorators?: Decorators | Decorators[];
|
|
394
|
+
args?: TMetaArgs;
|
|
395
|
+
} & Omit<ComponentAnnotations<ReactTypes & TanStackTypes<TMetaRoute> & T, TArgs>, 'decorators' | 'component' | 'args' | 'render'>): ReactMeta<InferCombinedTypes<TanStackTypes<TMetaRoute> & T, TArgs, Decorators>, Omit<ComponentAnnotations<InferCombinedTypes<TanStackTypes<TMetaRoute> & T, TArgs, Decorators>>, 'args'> & {
|
|
396
|
+
args: Partial<TArgs> extends TMetaArgs ? {} : TMetaArgs;
|
|
397
|
+
}>;
|
|
398
|
+
meta<TArgs extends Args, Decorators extends DecoratorFunction<ReactTypes & TanStackTypes<TRoute> & T, any>, TMetaArgs extends Partial<TArgs & (TanStackTypes<TRoute> & T)['args']>>(meta: {
|
|
399
|
+
render?: ArgsStoryFn<ReactTypes & TanStackTypes<TRoute> & T, TArgs & (TanStackTypes<TRoute> & T)['args']>;
|
|
400
|
+
component?: ComponentType<TArgs>;
|
|
401
|
+
decorators?: Decorators | Decorators[];
|
|
402
|
+
args?: TMetaArgs;
|
|
403
|
+
} & Omit<ComponentAnnotations<ReactTypes & TanStackTypes<TRoute> & T, TArgs>, 'decorators' | 'component' | 'args' | 'render'>): ReactMeta<InferCombinedTypes<TanStackTypes<TRoute> & T, TArgs, Decorators>, Omit<ComponentAnnotations<InferCombinedTypes<TanStackTypes<TRoute> & T, TArgs, Decorators>>, 'args'> & {
|
|
404
|
+
args: Partial<TArgs> extends TMetaArgs ? {} : TMetaArgs;
|
|
405
|
+
}>;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
export { type CreateStoryRouteOptions, type FrameworkOptions, type IsRoute, type Meta, type Preview, type RouterParameters, type StoryObj, type StoryRouteFileOptions, type StoryRouteOptions, type StorybookConfig, type TanStackParameters, type TanStackPreviewOptions, type TanStackTypes, definePreview };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
preview_exports
|
|
3
|
+
} from "./_browser-chunks/chunk-LJRZDJ5L.js";
|
|
4
|
+
import "./_browser-chunks/chunk-4BE7D4DS.js";
|
|
5
|
+
|
|
6
|
+
// src/index.ts
|
|
7
|
+
import { __definePreview } from "@storybook/react";
|
|
8
|
+
export * from "@storybook/react";
|
|
9
|
+
function definePreview(preview) {
|
|
10
|
+
return __definePreview({
|
|
11
|
+
...preview,
|
|
12
|
+
addons: [preview_exports, ...preview.addons ?? []]
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
export {
|
|
16
|
+
definePreview
|
|
17
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { CompatibleString } from 'storybook/internal/types';
|
|
2
|
+
import { BuilderOptions } from '@storybook/builder-vite';
|
|
3
|
+
import { StorybookConfig as StorybookConfig$1 } from '@storybook/react-vite';
|
|
4
|
+
|
|
5
|
+
type FrameworkName = CompatibleString<'@storybook/tanstack-react'>;
|
|
6
|
+
type BuilderName = CompatibleString<'@storybook/builder-vite'>;
|
|
7
|
+
type FrameworkOptions = {
|
|
8
|
+
/** Builder options passed through to @storybook/builder-vite. */
|
|
9
|
+
builder?: BuilderOptions;
|
|
10
|
+
};
|
|
11
|
+
type StorybookConfigFramework = {
|
|
12
|
+
framework: FrameworkName | {
|
|
13
|
+
name: FrameworkName;
|
|
14
|
+
options: FrameworkOptions;
|
|
15
|
+
};
|
|
16
|
+
core?: StorybookConfig$1['core'] & {
|
|
17
|
+
builder?: BuilderName | {
|
|
18
|
+
name: BuilderName;
|
|
19
|
+
options: BuilderOptions;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
/** The interface for Storybook configuration in `main.ts` files. */
|
|
24
|
+
type StorybookConfig = Omit<StorybookConfig$1, keyof StorybookConfigFramework> & StorybookConfigFramework;
|
|
25
|
+
|
|
26
|
+
declare function defineMain(config: StorybookConfig): StorybookConfig;
|
|
27
|
+
|
|
28
|
+
export { type StorybookConfig, defineMain };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import CJS_COMPAT_NODE_URL_2tdt6g07j5u from 'node:url';
|
|
2
|
+
import CJS_COMPAT_NODE_PATH_2tdt6g07j5u from 'node:path';
|
|
3
|
+
import CJS_COMPAT_NODE_MODULE_2tdt6g07j5u from "node:module";
|
|
4
|
+
|
|
5
|
+
var __filename = CJS_COMPAT_NODE_URL_2tdt6g07j5u.fileURLToPath(import.meta.url);
|
|
6
|
+
var __dirname = CJS_COMPAT_NODE_PATH_2tdt6g07j5u.dirname(__filename);
|
|
7
|
+
var require = CJS_COMPAT_NODE_MODULE_2tdt6g07j5u.createRequire(import.meta.url);
|
|
8
|
+
|
|
9
|
+
// ------------------------------------------------------------
|
|
10
|
+
// end of CJS compatibility banner, injected by Storybook's esbuild configuration
|
|
11
|
+
// ------------------------------------------------------------
|
|
12
|
+
|
|
13
|
+
// src/node/index.ts
|
|
14
|
+
function defineMain(config) {
|
|
15
|
+
return config;
|
|
16
|
+
}
|
|
17
|
+
export {
|
|
18
|
+
defineMain
|
|
19
|
+
};
|
package/dist/preset.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { PresetProperty } from 'storybook/internal/types';
|
|
2
|
+
import { StorybookConfigVite } from '@storybook/builder-vite';
|
|
3
|
+
|
|
4
|
+
declare const core: PresetProperty<'core'>;
|
|
5
|
+
declare const previewAnnotations: PresetProperty<'previewAnnotations'>;
|
|
6
|
+
declare const viteFinal: StorybookConfigVite['viteFinal'];
|
|
7
|
+
|
|
8
|
+
export { core, previewAnnotations, viteFinal };
|
package/dist/preset.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import CJS_COMPAT_NODE_URL_2tdt6g07j5u from 'node:url';
|
|
2
|
+
import CJS_COMPAT_NODE_PATH_2tdt6g07j5u from 'node:path';
|
|
3
|
+
import CJS_COMPAT_NODE_MODULE_2tdt6g07j5u from "node:module";
|
|
4
|
+
|
|
5
|
+
var __filename = CJS_COMPAT_NODE_URL_2tdt6g07j5u.fileURLToPath(import.meta.url);
|
|
6
|
+
var __dirname = CJS_COMPAT_NODE_PATH_2tdt6g07j5u.dirname(__filename);
|
|
7
|
+
var require = CJS_COMPAT_NODE_MODULE_2tdt6g07j5u.createRequire(import.meta.url);
|
|
8
|
+
|
|
9
|
+
// ------------------------------------------------------------
|
|
10
|
+
// end of CJS compatibility banner, injected by Storybook's esbuild configuration
|
|
11
|
+
// ------------------------------------------------------------
|
|
12
|
+
|
|
13
|
+
// src/preset.ts
|
|
14
|
+
import { fileURLToPath } from "node:url";
|
|
15
|
+
import { viteFinal as reactViteFinal } from "@storybook/react-vite/preset";
|
|
16
|
+
var INTERCEPTED_PATTERNS = ["virtual:cloudflare", "server-entry", "worker-entry"], INTERCEPTED_MODULES = ["@tanstack/react-start", "@tanstack/start-server-core"], core = async (config, options) => {
|
|
17
|
+
let framework = await options.presets.apply("framework");
|
|
18
|
+
return {
|
|
19
|
+
...config,
|
|
20
|
+
builder: {
|
|
21
|
+
name: fileURLToPath(import.meta.resolve("@storybook/builder-vite")),
|
|
22
|
+
options: typeof framework == "string" ? {} : framework.options.builder || {}
|
|
23
|
+
},
|
|
24
|
+
renderer: fileURLToPath(import.meta.resolve("@storybook/react/preset"))
|
|
25
|
+
};
|
|
26
|
+
}, previewAnnotations = (entry = []) => [
|
|
27
|
+
...entry,
|
|
28
|
+
fileURLToPath(import.meta.resolve("@storybook/tanstack-react/preview"))
|
|
29
|
+
], viteFinal = async (config, options) => {
|
|
30
|
+
let reactConfig = await reactViteFinal(config, options), isTanStackStartPlugin = (p) => {
|
|
31
|
+
if (Array.isArray(p))
|
|
32
|
+
return p.some(isTanStackStartPlugin);
|
|
33
|
+
let pluginRecord = p;
|
|
34
|
+
return typeof p == "object" && p !== null && "name" in pluginRecord && typeof pluginRecord.name == "string" && pluginRecord.name.startsWith("tanstack-start");
|
|
35
|
+
}, stubPath = fileURLToPath(import.meta.resolve("./export-mocks/start.js")), routerMockPath = fileURLToPath(
|
|
36
|
+
import.meta.resolve("@storybook/tanstack-react/react-router")
|
|
37
|
+
), plugins = [
|
|
38
|
+
...(reactConfig.plugins ?? []).filter((p) => !isTanStackStartPlugin(p)),
|
|
39
|
+
{
|
|
40
|
+
name: "tanstack-start-plugin-remover",
|
|
41
|
+
enforce: "pre",
|
|
42
|
+
resolveId: {
|
|
43
|
+
order: "pre",
|
|
44
|
+
handler(id, importer) {
|
|
45
|
+
if ((id === "@tanstack/react-router" || id.startsWith("@tanstack/react-router/")) && importer && !importer.includes("export-mocks"))
|
|
46
|
+
return routerMockPath;
|
|
47
|
+
for (let mod of INTERCEPTED_MODULES)
|
|
48
|
+
if (id === mod || id.startsWith(`${mod}/`))
|
|
49
|
+
return stubPath;
|
|
50
|
+
for (let pattern of INTERCEPTED_PATTERNS)
|
|
51
|
+
if (id.includes(pattern))
|
|
52
|
+
return stubPath;
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
config() {
|
|
57
|
+
return {
|
|
58
|
+
optimizeDeps: {
|
|
59
|
+
exclude: ["@storybook/tanstack-react"]
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
];
|
|
65
|
+
return {
|
|
66
|
+
...reactConfig,
|
|
67
|
+
plugins
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
export {
|
|
71
|
+
core,
|
|
72
|
+
previewAnnotations,
|
|
73
|
+
viteFinal
|
|
74
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Decorator } from '@storybook/react';
|
|
2
|
+
import { LoaderFunction, Renderer } from 'storybook/internal/types';
|
|
3
|
+
import { AnyRoute, FileRoutesByPath } from '@tanstack/react-router';
|
|
4
|
+
import { RouteOptions } from '@tanstack/router-core';
|
|
5
|
+
|
|
6
|
+
type IsRoute<T> = T extends AnyRoute ? true : T extends FileRoutesByPath[keyof FileRoutesByPath] ? true : false;
|
|
7
|
+
type StoryRoutePathForRoute<TRoute> = TRoute extends {
|
|
8
|
+
path: infer P;
|
|
9
|
+
} ? unknown extends P ? keyof FileRoutesByPath | (string & {}) : P extends '/' ? `/${string}` : P extends string ? P | `${P}/${string}` : keyof FileRoutesByPath | (string & {}) : keyof FileRoutesByPath | (string & {});
|
|
10
|
+
type StoryRoutePath<TRoute = undefined> = IsRoute<TRoute> extends true ? StoryRoutePathForRoute<TRoute> : keyof FileRoutesByPath | (string & {});
|
|
11
|
+
type StoryRouteParams<TRoute> = IsRoute<TRoute> extends true ? TRoute extends {
|
|
12
|
+
types: {
|
|
13
|
+
allParams: infer P;
|
|
14
|
+
};
|
|
15
|
+
} ? unknown extends P ? Record<string, string> : P : Record<string, string> : Record<string, string>;
|
|
16
|
+
type StoryRouteSearch<TRoute> = IsRoute<TRoute> extends true ? TRoute extends {
|
|
17
|
+
types: {
|
|
18
|
+
fullSearchSchema: infer S;
|
|
19
|
+
};
|
|
20
|
+
} ? unknown extends S ? Record<string, unknown> : S : Record<string, unknown> : Record<string, unknown>;
|
|
21
|
+
type StoryRouteFileOptions<TRoute = undefined> = IsRoute<TRoute> extends true ? TRoute extends {
|
|
22
|
+
options: infer O;
|
|
23
|
+
} ? Pick<O, Extract<keyof O, 'loader' | 'beforeLoad' | 'validateSearch' | 'loaderDeps' | 'context' | 'params' | 'head' | 'search' | 'parseParams' | 'context'>> : Pick<RouteOptions<unknown>, 'loader' | 'beforeLoad' | 'validateSearch' | 'loaderDeps' | 'context' | 'params' | 'head' | 'search' | 'parseParams' | 'context'> : Pick<RouteOptions<unknown>, 'loader' | 'beforeLoad' | 'validateSearch' | 'loaderDeps' | 'context' | 'params' | 'head' | 'search' | 'parseParams' | 'context'>;
|
|
24
|
+
type CreateStoryRouteOptions<TRoute = undefined> = StoryRouteFileOptions<TRoute> & {
|
|
25
|
+
path?: StoryRoutePath<TRoute>;
|
|
26
|
+
};
|
|
27
|
+
type StoryRouteOptions<TRoute = undefined> = CreateStoryRouteOptions<TRoute> | AnyRoute;
|
|
28
|
+
/**
|
|
29
|
+
* Extracts a single route option type directly from the route's options,
|
|
30
|
+
* avoiding indexing into deferred conditional types (which causes DTS errors).
|
|
31
|
+
*/
|
|
32
|
+
type RouteOption<TRoute, K extends string> = IsRoute<TRoute> extends true ? TRoute extends {
|
|
33
|
+
options: Record<K, infer V>;
|
|
34
|
+
} ? V : undefined : K extends keyof RouteOptions<unknown> ? RouteOptions<unknown>[K] : undefined;
|
|
35
|
+
interface RouterParameters<TRoute = undefined> {
|
|
36
|
+
/** A route object or route options to use for this story. */
|
|
37
|
+
route?: StoryRouteOptions<TRoute>;
|
|
38
|
+
/** The initial URL path to render. */
|
|
39
|
+
path?: StoryRoutePath<TRoute>;
|
|
40
|
+
/** URL params to interpolate into the path (e.g. `{ id: '42' }` for `/$id`). */
|
|
41
|
+
params?: StoryRouteParams<TRoute>;
|
|
42
|
+
/** Search/query params to append to the URL (e.g. `{ tab: 'details' }`). */
|
|
43
|
+
query?: Partial<StoryRouteSearch<TRoute>>;
|
|
44
|
+
/** Override the route's loader function. */
|
|
45
|
+
loader?: RouteOption<TRoute, 'loader'>;
|
|
46
|
+
/** Override the route's beforeLoad function. */
|
|
47
|
+
beforeLoad?: RouteOption<TRoute, 'beforeLoad'>;
|
|
48
|
+
/** Override the route's search params validation. */
|
|
49
|
+
validateSearch?: RouteOption<TRoute, 'validateSearch'>;
|
|
50
|
+
/** Override the route's loader dependencies. */
|
|
51
|
+
loaderDeps?: RouteOption<TRoute, 'loaderDeps'>;
|
|
52
|
+
/** Override the route's context. */
|
|
53
|
+
context?: Record<string, unknown>;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
interface TanStackPreviewOptions<TRoute = undefined> {
|
|
57
|
+
/** Router configuration for stories */
|
|
58
|
+
router?: RouterParameters<TRoute>;
|
|
59
|
+
}
|
|
60
|
+
interface TanStackParameters<TRoute = undefined> {
|
|
61
|
+
/** TanStack framework configuration (router integration). */
|
|
62
|
+
tanstack?: TanStackPreviewOptions<TRoute>;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
declare const loaders: LoaderFunction<Renderer>[];
|
|
66
|
+
declare const decorators: Decorator[];
|
|
67
|
+
declare const parameters: TanStackParameters;
|
|
68
|
+
|
|
69
|
+
export { decorators, loaders, parameters };
|