import { ComponentType } from 'react'; import { PreviewAddon, InferTypes, AddonTypes } from 'storybook/internal/csf'; import { CompatibleString, ProjectAnnotations, Args, DecoratorFunction, ArgsStoryFn, Parameters as Parameters$1, ComponentAnnotations, Renderer, StoryAnnotations } from 'storybook/internal/types'; import { Register, AnyRoute, FileRoutesByPath } from '@tanstack/react-router'; import { Decorator, ReactTypes, ReactPreview, ReactMeta, ReactRenderer, Meta as Meta$1, StoryObj as StoryObj$1 } from '@storybook/react'; export * from '@storybook/react'; import { RoutesByPath, RouteOptions, ResolveParams, AnyContext } from '@tanstack/router-core'; import { BuilderOptions } from '@storybook/builder-vite'; import { StorybookConfig as StorybookConfig$1 } from '@storybook/react-vite'; /** Convert a union type to an intersection type. Inspired by [this Stack Overflow answer](https://stackoverflow.com/a/50375286/2172153). @example ``` import type {UnionToIntersection} from 'type-fest'; type Union = {the(): void} | {great(arg: string): void} | {escape: boolean}; type Intersection = UnionToIntersection; //=> {the(): void} & {great(arg: string): void} & {escape: boolean} ``` @category Type */ type UnionToIntersection = ( // `extends unknown` is always going to be the case and is used to convert the // `Union` into a [distributive conditional // type](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types). Union extends unknown // The union type is used as the only argument to a function since the union // of function arguments is an intersection. ? (distributedUnion: Union) => void // This won't happen. : never // Infer the `Intersection` type since TypeScript represents the positional // arguments of unions of functions as an intersection of the union. ) extends ((mergedIntersection: infer Intersection) => void) // The `& Union` is to ensure result of `UnionToIntersection` is always assignable to `A | B` ? Intersection & Union : never; /** 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. @example ``` import type {Simplify} from 'type-fest'; type PositionProps = { top: number; left: number; }; type SizeProps = { width: number; height: number; }; // In your editor, hovering over `Props` will show a flattened object with all the properties. type Props = Simplify; ``` 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`. 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. 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 = ...`. Then `value` will be assignable to the `fn` argument. Or the `value` can be cast as `Simplify` if you can't re-declare the `value`. @example ``` import type {Simplify} from 'type-fest'; interface SomeInterface { foo: number; bar?: string; baz: number | undefined; } type SomeType = { foo: number; bar?: string; baz: number | undefined; }; const literal = {foo: 123, bar: 'hello', baz: 456}; const someType: SomeType = literal; const someInterface: SomeInterface = literal; declare function fn(object: Record): void; fn(literal); // Good: literal object type is sealed fn(someType); // Good: type is sealed // @ts-expect-error fn(someInterface); // Error: Index signature for type 'string' is missing in type 'someInterface'. Because `interface` can be re-opened fn(someInterface as Simplify); // Good: transform an `interface` into a `type` ``` @link https://github.com/microsoft/TypeScript/issues/15300 @see {@link SimplifyDeep} @category Object */ type Simplify = {[KeyType in keyof T]: T[KeyType]} & {}; /** Omit any index signatures from the given object type, leaving only explicitly defined properties. This is the counterpart of `PickIndexSignature`. Use-cases: - Remove overly permissive signatures from third-party types. This type was taken from this [StackOverflow answer](https://stackoverflow.com/a/68261113/420747). It relies on the fact that an empty object (`{}`) is assignable to an object with just an index signature, like `Record`, but not to an object with explicitly defined keys, like `Record<'foo' | 'bar', unknown>`. (The actual value type, `unknown`, is irrelevant and could be any type. Only the key type matters.) ``` const indexed: Record = {}; // Allowed // @ts-expect-error const keyed: Record<'foo', unknown> = {}; // Error // TS2739: Type '{}' is missing the following properties from type 'Record<"foo" | "bar", unknown>': foo, bar ``` 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: ``` type Indexed = {} extends Record ? '✅ `{}` is assignable to `Record`' : '❌ `{}` is NOT assignable to `Record`'; type IndexedResult = Indexed; //=> '✅ `{}` is assignable to `Record`' type Keyed = {} extends Record<'foo' | 'bar', unknown> ? '✅ `{}` is assignable to `Record<\'foo\' | \'bar\', unknown>`' : '❌ `{}` is NOT assignable to `Record<\'foo\' | \'bar\', unknown>`'; type KeyedResult = Keyed; //=> '❌ `{}` is NOT assignable to `Record<\'foo\' | \'bar\', unknown>`' ``` 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`... ``` type OmitIndexSignature = { [KeyType in keyof ObjectType // Map each key of `ObjectType`... ]: ObjectType[KeyType]; // ...to its original value, i.e. `OmitIndexSignature == Foo`. }; ``` ...whether an empty object (`{}`) would be assignable to an object with that `KeyType` (`Record`)... ``` type OmitIndexSignature = { [KeyType in keyof ObjectType // Is `{}` assignable to `Record`? as {} extends Record ? never // ✅ `{}` is assignable to `Record` : KeyType // ❌ `{}` is NOT assignable to `Record` ]: ObjectType[KeyType]; }; ``` 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. @example ``` import type {OmitIndexSignature} from 'type-fest'; type Example = { // These index signatures will be removed. [x: string]: any; [x: number]: any; [x: symbol]: any; [x: `head-${string}`]: string; [x: `${string}-tail`]: string; [x: `head-${string}-tail`]: string; [x: `${bigint}`]: string; [x: `embedded-${number}`]: string; // These explicitly defined keys will remain. foo: 'bar'; qux?: 'baz'; }; type ExampleWithoutIndexSignatures = OmitIndexSignature; //=> {foo: 'bar'; qux?: 'baz'} ``` @see {@link PickIndexSignature} @category Object */ type OmitIndexSignature = { [KeyType in keyof ObjectType as {} extends Record ? never : KeyType]: ObjectType[KeyType]; }; /** Union of every registered full path (e.g. `'/' | '/admin/users' | '/$libraryId/$version'`). */ type RegisteredFullPath = keyof Register['router']['routesByPath']; type IsAppRouteTree = TRoute extends Register['router']['routeTree'] ? true : false; type IsRoute = T extends AnyRoute ? true : T extends FileRoutesByPath[keyof FileRoutesByPath] ? true : false; type ExtractAllPathsFromFileRoutes = TRoute['path']; type StoryRoutePath = TRoute extends FileRoutesByPath[keyof FileRoutesByPath] ? ExtractAllPathsFromFileRoutes : keyof FileRoutesByPath | `/${string}`; type StoryRouteSearch = IsAppRouteTree extends true ? Record : TRoute extends FileRoutesByPath[keyof FileRoutesByPath] ? TRoute['preLoaderRoute'] extends { types: { allSearch: infer A; }; } ? A : never : Record; type StoryRouteFileOptions = IsRoute extends true ? TRoute extends { options: infer O; } ? Pick> : Pick, 'loader' | 'beforeLoad' | 'validateSearch' | 'loaderDeps' | 'context' | 'params' | 'head' | 'search' | 'parseParams' | 'context'> : Pick, 'loader' | 'beforeLoad' | 'validateSearch' | 'loaderDeps' | 'context' | 'params' | 'head' | 'search' | 'parseParams' | 'context'>; type CreateStoryRouteOptions = StoryRouteFileOptions & { path?: StoryRoutePath; }; type StoryRouteOptions = CreateStoryRouteOptions | (TRoute extends AnyRoute ? TRoute : AnyRoute); /** * Per-route override options for use inside `RouteTreeOverrides`. * Users can override `loader`, `beforeLoad`, etc. for a specific route. */ interface RouteOverrideOptions { /** Override the route's loader function. */ loader?: TRoute extends FileRoutesByPath[keyof FileRoutesByPath]['preLoaderRoute'] ? TRoute['options']['loader'] | ((ctx: unknown) => Promise | unknown) : (ctx: unknown) => Promise | unknown; /** Override the route's beforeLoad function. */ beforeLoad?: TRoute extends FileRoutesByPath[keyof FileRoutesByPath]['preLoaderRoute'] ? TRoute['options']['beforeLoad'] | ((ctx: unknown) => Promise | void) : (ctx: unknown) => Promise | void; /** Override the route's search params validation. */ validateSearch?: TRoute extends FileRoutesByPath[keyof FileRoutesByPath]['preLoaderRoute'] ? TRoute['options']['validateSearch'] | ((search: unknown) => Promise | void) : (search: unknown) => Promise | void; /** Override the route's loader dependencies. */ loaderDeps?: TRoute extends FileRoutesByPath[keyof FileRoutesByPath]['preLoaderRoute'] ? TRoute['options']['loaderDeps'] | string[] : string[]; /** Override the route's context function. */ context?: TRoute extends FileRoutesByPath[keyof FileRoutesByPath]['preLoaderRoute'] ? TRoute['options']['context'] | ((ctx: unknown) => Promise | unknown) : (ctx: unknown) => Promise | unknown; } /** * A map of route overrides keyed by route ID. * Each entry can override `loader`, `beforeLoad`, etc. for that route. * * @example * ```ts * routeOverrides: { * '/_authed': { beforeLoad: () => {} }, * '/demo/form/simple/$id': { * loader: async () => ({ name: 'Mock User' }), * }, * } * ``` */ type RouteTreeOverrides = Partial<{ [routePath in keyof FileRoutesByPath]: RouteOverrideOptions | undefined; }>; interface RouterParameters : RegisteredFullPath = TRoute extends AnyRoute ? keyof RoutesByPath : keyof FileRoutesByPath> { route?: StoryRouteOptions; /** * Path to resolve the story route against. * Constrained to known registered paths in route tree mode, but can be any string in app route mode (since the user may be passing a custom `route` that doesn't exist in the registered tree). */ path?: Path; /** URL params to interpolate into the path (e.g. `{ id: '42' }` for `/$id`). */ params?: ResolveParams; /** Search/query params to append to the URL (e.g. `{ tab: 'details' }`). */ query?: Partial>; /** * Override options for specific routes in the app route tree (route tree mode only). * * Each key is a route ID (e.g. `'/about'`, `'__root__'`, `'/demo/form/simple/$id'`). * Values can override `loader`, `beforeLoad`, etc. for that route. * * @example * ```ts * routeOverrides: { * '/_authed': { beforeLoad: () => {} }, * '/demo/form/simple/$id': { * loader: async () => ({ name: 'Mock User' }), * }, * } * ``` */ routeOverrides?: RouteTreeOverrides; context?: Record; /** * */ useRouterContext?: ({ storyContext }: { storyContext: Parameters[1]; }) => AnyContext; } type FrameworkName = CompatibleString<'@storybook/tanstack-react'>; type BuilderName = CompatibleString<'@storybook/builder-vite'>; type FrameworkOptions = { /** Builder options passed through to @storybook/builder-vite. */ builder?: BuilderOptions; }; type StorybookConfigFramework = { framework: FrameworkName | { name: FrameworkName; options: FrameworkOptions; }; core?: StorybookConfig$1['core'] & { builder?: BuilderName | { name: BuilderName; options: BuilderOptions; }; }; }; /** The interface for Storybook configuration in `main.ts` files. */ type StorybookConfig = Omit & StorybookConfigFramework; /** Path constraint mirroring `RouterParameters`'s second generic. */ type DefaultStoryPath = TRoute extends AnyRoute ? keyof RoutesByPath : RegisteredFullPath; interface TanStackPreviewOptions = DefaultStoryPath> { /** Router configuration for stories */ router?: RouterParameters; } interface TanStackParameters = DefaultStoryPath> { /** TanStack framework configuration (router integration). */ tanstack?: TanStackPreviewOptions; } interface TanStackTypes = DefaultStoryPath> { parameters: TanStackParameters; } /** Extracts and unions all args types from an array of decorators. */ type DecoratorsArgs = UnionToIntersection ? TArgs : unknown>; type InferCombinedTypes = ReactTypes & T & { args: Simplify>>>; }; type Preview = ProjectAnnotations>; declare function definePreview = DefaultStoryPath, Addons extends PreviewAddon[] = []>(preview: { addons?: Addons; route?: TRoute; } & ProjectAnnotations, TPath> & InferTypes>): TanStackPreview, TRoute>; /** * Metadata to configure stories for a component or a TanStack Route. * * When `TCmpOrArgs` is a TanStack Route, the `component` field accepts the * Route object directly and TanStack parameters (params, query, loader, etc.) * are inferred from the route's types. */ type Meta = IsRoute extends true ? Omit, 'component'> & Partial> : Meta$1; /** * When the meta's `component` is a TanStack Route, the story inherits * TanStack parameter types for type-safe params/query/loader configuration. */ type StoryObj = [TMetaOrCmpOrArgs] extends [ { component?: infer Component; } ] ? IsRoute extends true ? StoryAnnotations> & Partial> : StoryObj$1 & Partial : IsRoute extends true ? StoryAnnotations> & Partial> : StoryObj$1 & Partial; interface TanStackPreview extends ReactPreview & T> { type(): TanStackPreview; meta = DefaultStoryPath, TArgs extends Args = Args, Decorators extends DecoratorFunction & T, any> = DecoratorFunction & T, any>, TMetaArgs extends Partial & T)['args']> = Partial & T)['args']>>(meta: { render?: ArgsStoryFn & T, TArgs & (TanStackTypes & T)['args']>; component?: ComponentType; decorators?: Decorators | Decorators[]; args?: TMetaArgs; parameters?: TanStackParameters & Parameters$1 & (ReactTypes & T)['parameters']; } & Omit & T, TArgs>, 'decorators' | 'component' | 'args' | 'render' | 'parameters'>): ReactMeta & T, TArgs, Decorators>, Omit & T, TArgs, Decorators>>, 'args'> & { args: Partial extends TMetaArgs ? {} : TMetaArgs; }>; meta = DefaultStoryPath, TArgs extends Args = Args, Decorators extends DecoratorFunction & T, any> = DecoratorFunction & T, any>, TMetaArgs extends Partial & T)['args']> = Partial & T)['args']>>(meta: { render?: ArgsStoryFn & T, TArgs & (TanStackTypes & T)['args']>; component?: ComponentType; decorators?: Decorators | Decorators[]; args?: TMetaArgs; parameters?: TanStackParameters & Parameters$1 & (ReactTypes & T)['parameters']; } & Omit & T, TArgs>, 'decorators' | 'component' | 'args' | 'render' | 'parameters'>): ReactMeta & T, TArgs, Decorators>, Omit & T, TArgs, Decorators>>, 'args'> & { args: Partial extends TMetaArgs ? {} : TMetaArgs; }>; } export { type CreateStoryRouteOptions, type DefaultStoryPath, 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 };