@storybook/tanstack-react 10.6.0-alpha.0 → 10.6.0-alpha.2

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.
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  normalizeFileRoutePath
3
- } from "./chunk-XKNIZ3MM.js";
3
+ } from "./chunk-LTDGLEVR.js";
4
4
  import {
5
5
  __export
6
6
  } from "./chunk-4BE7D4DS.js";
@@ -28,7 +28,12 @@ import {
28
28
  } from "@tanstack/react-router";
29
29
 
30
30
  // src/routing/duplicate-tree.ts
31
- import { createRoute, RootRoute, createRootRouteWithContext } from "@tanstack/react-router";
31
+ import {
32
+ createRoute,
33
+ RootRoute,
34
+ createRootRouteWithContext,
35
+ joinPaths
36
+ } from "@tanstack/react-router";
32
37
  var MAX_PARENT_WALK = 50;
33
38
  function findRootRoute(route) {
34
39
  let current = route;
@@ -50,9 +55,9 @@ function initSourceTree(route, counter) {
50
55
  initSourceTree(child, counter);
51
56
  }
52
57
  function cloneChild(oldRoute, parent, overrides, byId) {
53
- let options = oldRoute.options ?? {}, { id: _id, getParentRoute: _g, ...rest } = options, override = getOverrideFor(overrides, oldRoute.id), cloned = createRoute({
54
- ...rest,
55
- ...override,
58
+ let options = oldRoute.options ?? {}, { id: originalId, getParentRoute: _g, ...rest } = options, override = getOverrideFor(overrides, oldRoute.id), merged = { ...rest, ...override }, cloned = createRoute({
59
+ ...!merged.path && originalId != null ? { id: originalId } : {},
60
+ ...merged,
56
61
  getParentRoute: () => parent
57
62
  });
58
63
  byId.set(oldRoute.id, cloned);
@@ -67,7 +72,12 @@ function cloneChild(oldRoute, parent, overrides, byId) {
67
72
  }
68
73
  function duplicateRouteTree(rootRoute, { overrides } = {}) {
69
74
  initSourceTree(rootRoute, { i: 0 });
70
- let byId = /* @__PURE__ */ new Map(), rootOptions = rootRoute.options ?? {}, rootOverride = getOverrideFor(overrides, "__root__"), { id: _rootId, getParentRoute: _rootGetParent, ...restRoot } = rootOptions, newRoot = createRootRouteWithContext()({
75
+ let byId = /* @__PURE__ */ new Map(), rootOptions = rootRoute.options ?? {}, rootOverride = getOverrideFor(overrides, "__root__"), {
76
+ id: _rootId,
77
+ getParentRoute: _rootGetParent,
78
+ shellComponent: _rootShell,
79
+ ...restRoot
80
+ } = rootOptions, newRoot = createRootRouteWithContext()({
71
81
  ...restRoot,
72
82
  ...rootOverride
73
83
  });
@@ -81,6 +91,16 @@ function duplicateRouteTree(rootRoute, { overrides } = {}) {
81
91
  }
82
92
  return { root: newRoot, byId };
83
93
  }
94
+ function mountPathFor(route) {
95
+ let segments = [], current = route;
96
+ for (let i = 0; i < MAX_PARENT_WALK && current; i += 1) {
97
+ let routePath = current.options?.path;
98
+ routePath && routePath !== "/" && segments.unshift(routePath);
99
+ let getParent = current.options?.getParentRoute;
100
+ current = typeof getParent == "function" ? getParent() : void 0;
101
+ }
102
+ return joinPaths(["/", ...segments]);
103
+ }
84
104
  function resolveStoryLeaf(tree, { path, boundRouteId }) {
85
105
  let { root, byId } = tree;
86
106
  if (path) {
@@ -134,7 +154,7 @@ function createStoryRouter({
134
154
  context,
135
155
  routerContext
136
156
  }) {
137
- let routerParameters = context.parameters.tanstack?.router ?? {}, { tree, leaf } = resolveTree(Story, context), routeTree = tree.root, inferredPath = routerParameters?.path || leaf.fullPath || (leaf.id ? normalizeFileRoutePath(leaf.id) : void 0) || routeTree.children?.[0]?.fullPath || "/", resolvedPath = interpolatePath({
157
+ let routerParameters = context.parameters.tanstack?.router ?? {}, { tree, leaf } = resolveTree(Story, context), routeTree = tree.root, inferredPath = routerParameters?.path || leaf.fullPath || (leaf.id ? normalizeFileRoutePath(leaf.id) : void 0) || mountPathFor(leaf), resolvedPath = interpolatePath({
138
158
  path: inferredPath,
139
159
  params: routerParameters?.params ?? {}
140
160
  }).interpolatedPath, search = routerParameters?.query ? defaultStringifySearch(routerParameters.query) : "";
@@ -154,6 +174,24 @@ function createStoryRouter({
154
174
  context: routerContext
155
175
  });
156
176
  }
177
+ function ensureMatchableLeaf(tree, leaf) {
178
+ if (!(leaf !== tree.root && !leaf.options?.path && leaf.options?.id != null))
179
+ return leaf;
180
+ let existingIndexChild = (leaf.children ?? []).find(
181
+ (child) => child.options?.path === "/"
182
+ );
183
+ if (existingIndexChild)
184
+ return existingIndexChild;
185
+ let syntheticLeaf = createRoute2({
186
+ path: "/",
187
+ component: () => null,
188
+ getParentRoute: () => leaf
189
+ });
190
+ return leaf.addChildren([
191
+ ...leaf.children ?? [],
192
+ syntheticLeaf
193
+ ]), syntheticLeaf;
194
+ }
157
195
  function injectStoryComponent(leaf, Story, overrides, leafId) {
158
196
  let userOverride = overrides?.[leafId];
159
197
  userOverride && "component" in userOverride && userOverride.component !== void 0 || leaf.update({ component: () => React.createElement(Story, null) });
@@ -165,7 +203,9 @@ function resolveTree(Story, context) {
165
203
  path: routerParameters.path,
166
204
  boundRouteId: resolvedRoute && resolvedRoute !== rootRoute ? resolvedRoute.id : void 0
167
205
  });
168
- return injectStoryComponent(leaf, Story, routeOverrides, leaf.id), { tree, leaf };
206
+ injectStoryComponent(leaf, Story, routeOverrides, leaf.id);
207
+ let renderLeaf = ensureMatchableLeaf(tree, leaf);
208
+ return { tree, leaf: renderLeaf };
169
209
  }
170
210
  if (isRoute(routerParameterRoute)) {
171
211
  let syntheticRoot2 = createRootRoute(
@@ -173,7 +213,9 @@ function resolveTree(Story, context) {
173
213
  );
174
214
  routerParameterRoute.update({ getParentRoute: () => syntheticRoot2 }), syntheticRoot2.addChildren([routerParameterRoute]);
175
215
  let tree = duplicateRouteTree(syntheticRoot2, { overrides: routeOverrides }), leaf = tree.byId.get(routerParameterRoute.id) ?? tree.root;
176
- return injectStoryComponent(leaf, Story, routeOverrides, leaf.id), { tree, leaf };
216
+ injectStoryComponent(leaf, Story, routeOverrides, leaf.id);
217
+ let renderLeaf = ensureMatchableLeaf(tree, leaf);
218
+ return { tree, leaf: renderLeaf };
177
219
  }
178
220
  let plainOptions = routerParameterRoute ?? {}, {
179
221
  path: plainRoutePath,
@@ -13,7 +13,15 @@ function removeUnderscores(s) {
13
13
  function normalizeFileRoutePath(path) {
14
14
  return removeGroups(removeUnderscores(removeLayoutSegments(path)) ?? "") || "/";
15
15
  }
16
+ function isPathlessSegment(segment) {
17
+ return segment.startsWith("_") || segment.startsWith("(") && segment.endsWith(")");
18
+ }
19
+ function isPathlessFileRouteId(id) {
20
+ let segments = id.split("/").filter(Boolean), lastSegment = segments[segments.length - 1];
21
+ return lastSegment != null && isPathlessSegment(lastSegment);
22
+ }
16
23
 
17
24
  export {
18
- normalizeFileRoutePath
25
+ normalizeFileRoutePath,
26
+ isPathlessFileRouteId
19
27
  };
@@ -0,0 +1,131 @@
1
+ import { CompatibleString } from "storybook/internal/types";
2
+ import { AnyRoute, FileRoutesByPath, Register } from "@tanstack/react-router";
3
+ import { Decorator } from "@storybook/react";
4
+ import { AnyContext, ResolveParams, RouteOptions, RoutesByPath } from "@tanstack/router-core";
5
+ import { BuilderOptions } from "@storybook/builder-vite";
6
+ import { StorybookConfig } from "@storybook/react-vite";
7
+
8
+ //#region code/frameworks/tanstack-react/.dts-emit/code/frameworks/tanstack-react/src/routing/types.d.ts
9
+ /** Union of every registered full path (e.g. `'/' | '/admin/users' | '/$libraryId/$version'`). */
10
+ type RegisteredFullPath = keyof Register['router']['routesByPath'];
11
+ type IsAppRouteTree<TRoute> = TRoute extends Register['router']['routeTree'] ? true : false;
12
+ type IsRoute<T> = T extends AnyRoute ? true : T extends FileRoutesByPath[keyof FileRoutesByPath] ? true : false;
13
+ type ExtractAllPathsFromFileRoutes<TRoute extends FileRoutesByPath[keyof FileRoutesByPath]['preLoaderRoute'] | AnyRoute> = TRoute['path'];
14
+ type StoryRoutePath<TRoute = undefined> = TRoute extends FileRoutesByPath[keyof FileRoutesByPath] ? ExtractAllPathsFromFileRoutes<TRoute> : keyof FileRoutesByPath | `/${string}`;
15
+ type StoryRouteSearch<TRoute> = IsAppRouteTree<TRoute> extends true ? Record<string, unknown> : TRoute extends FileRoutesByPath[keyof FileRoutesByPath] ? TRoute['preLoaderRoute'] extends {
16
+ types: {
17
+ allSearch: infer A;
18
+ };
19
+ } ? A : never : Record<string, unknown>;
20
+ type StoryRouteFileOptions<TRoute = undefined> = IsRoute<TRoute> extends true ? TRoute extends {
21
+ options: infer O;
22
+ } ? 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'>;
23
+ type CreateStoryRouteOptions<TRoute = undefined> = StoryRouteFileOptions<TRoute> & {
24
+ path?: StoryRoutePath<TRoute>;
25
+ };
26
+ type StoryRouteOptions<TRoute = undefined> = CreateStoryRouteOptions<TRoute> | (TRoute extends AnyRoute ? TRoute : AnyRoute);
27
+ /**
28
+ * Per-route override options for use inside `RouteTreeOverrides`.
29
+ * Users can override `loader`, `beforeLoad`, etc. for a specific route.
30
+ */
31
+ interface RouteOverrideOptions<TRoute extends FileRoutesByPath[keyof FileRoutesByPath]['preLoaderRoute'] | undefined = undefined> {
32
+ /** Override the route's loader function. */
33
+ loader?: TRoute extends FileRoutesByPath[keyof FileRoutesByPath]['preLoaderRoute'] ? TRoute['options']['loader'] | ((ctx: unknown) => Promise<unknown> | unknown) : (ctx: unknown) => Promise<unknown> | unknown;
34
+ /** Override the route's beforeLoad function. */
35
+ beforeLoad?: TRoute extends FileRoutesByPath[keyof FileRoutesByPath]['preLoaderRoute'] ? TRoute['options']['beforeLoad'] | ((ctx: unknown) => Promise<void> | void) : (ctx: unknown) => Promise<void> | void;
36
+ /** Override the route's search params validation. */
37
+ validateSearch?: TRoute extends FileRoutesByPath[keyof FileRoutesByPath]['preLoaderRoute'] ? TRoute['options']['validateSearch'] | ((search: unknown) => Promise<void> | void) : (search: unknown) => Promise<void> | void;
38
+ /** Override the route's loader dependencies. */
39
+ loaderDeps?: TRoute extends FileRoutesByPath[keyof FileRoutesByPath]['preLoaderRoute'] ? TRoute['options']['loaderDeps'] | string[] : string[];
40
+ /** Override the route's context function. */
41
+ context?: TRoute extends FileRoutesByPath[keyof FileRoutesByPath]['preLoaderRoute'] ? TRoute['options']['context'] | ((ctx: unknown) => Promise<unknown> | unknown) : (ctx: unknown) => Promise<unknown> | unknown;
42
+ }
43
+ /**
44
+ * A map of route overrides keyed by route ID.
45
+ * Each entry can override `loader`, `beforeLoad`, etc. for that route.
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * routeOverrides: {
50
+ * '/_authed': { beforeLoad: () => {} },
51
+ * '/demo/form/simple/$id': {
52
+ * loader: async () => ({ name: 'Mock User' }),
53
+ * },
54
+ * }
55
+ * ```
56
+ */
57
+ type RouteTreeOverrides = Partial<{ [routePath in keyof FileRoutesByPath]: RouteOverrideOptions<FileRoutesByPath[routePath]['preLoaderRoute']> | undefined }>;
58
+ interface RouterParameters<TRoute = undefined, Path extends (TRoute extends AnyRoute ? keyof RoutesByPath<TRoute> : RegisteredFullPath) = (TRoute extends AnyRoute ? keyof RoutesByPath<TRoute> : keyof FileRoutesByPath)> {
59
+ route?: StoryRouteOptions<TRoute>;
60
+ /**
61
+ * Path to resolve the story route against.
62
+ * 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).
63
+ */
64
+ path?: Path;
65
+ /** URL params to interpolate into the path (e.g. `{ id: '42' }` for `/$id`). */
66
+ params?: ResolveParams<Path>;
67
+ /** Search/query params to append to the URL (e.g. `{ tab: 'details' }`). */
68
+ query?: Partial<StoryRouteSearch<TRoute>>;
69
+ /**
70
+ * Override options for specific routes in the app route tree (route tree mode only).
71
+ *
72
+ * Each key is a route ID (e.g. `'/about'`, `'__root__'`, `'/demo/form/simple/$id'`).
73
+ * Values can override `loader`, `beforeLoad`, etc. for that route.
74
+ *
75
+ * @example
76
+ * ```ts
77
+ * routeOverrides: {
78
+ * '/_authed': { beforeLoad: () => {} },
79
+ * '/demo/form/simple/$id': {
80
+ * loader: async () => ({ name: 'Mock User' }),
81
+ * },
82
+ * }
83
+ * ```
84
+ */
85
+ routeOverrides?: RouteTreeOverrides;
86
+ context?: Record<string, unknown>;
87
+ /**
88
+ *
89
+ */
90
+ useRouterContext?: ({
91
+ storyContext
92
+ }: {
93
+ storyContext: Parameters<Decorator>[1];
94
+ }) => AnyContext;
95
+ }
96
+ //#endregion
97
+ //#region code/frameworks/tanstack-react/.dts-emit/code/frameworks/tanstack-react/src/types.d.ts
98
+ type FrameworkName = CompatibleString<'@storybook/tanstack-react'>;
99
+ type BuilderName = CompatibleString<'@storybook/builder-vite'>;
100
+ type FrameworkOptions = {
101
+ /** Builder options passed through to @storybook/builder-vite. */builder?: BuilderOptions;
102
+ };
103
+ type StorybookConfigFramework = {
104
+ framework: FrameworkName | {
105
+ name: FrameworkName;
106
+ options: FrameworkOptions;
107
+ };
108
+ core?: StorybookConfig['core'] & {
109
+ builder?: BuilderName | {
110
+ name: BuilderName;
111
+ options: BuilderOptions;
112
+ };
113
+ };
114
+ };
115
+ /** The interface for Storybook configuration in `main.ts` files. */
116
+ type StorybookConfig$1 = Omit<StorybookConfig, keyof StorybookConfigFramework> & StorybookConfigFramework;
117
+ /** Path constraint mirroring `RouterParameters`'s second generic. */
118
+ type DefaultStoryPath<TRoute> = TRoute extends AnyRoute ? keyof RoutesByPath<TRoute> : RegisteredFullPath;
119
+ interface TanStackPreviewOptions<TRoute = undefined, Path extends DefaultStoryPath<TRoute> = DefaultStoryPath<TRoute>> {
120
+ /** Router configuration for stories */
121
+ router?: RouterParameters<TRoute, Path>;
122
+ }
123
+ interface TanStackParameters<TRoute = undefined, Path extends DefaultStoryPath<TRoute> = DefaultStoryPath<TRoute>> {
124
+ /** TanStack framework configuration (router integration). */
125
+ tanstack?: TanStackPreviewOptions<TRoute, Path>;
126
+ }
127
+ interface TanStackTypes<TRoute = undefined, Path extends DefaultStoryPath<TRoute> = DefaultStoryPath<TRoute>> {
128
+ parameters: TanStackParameters<TRoute, Path>;
129
+ }
130
+ //#endregion
131
+ export { TanStackPreviewOptions as a, IsRoute as c, StoryRouteOptions as d, TanStackParameters as i, RouterParameters as l, FrameworkOptions as n, TanStackTypes as o, StorybookConfig$1 as r, CreateStoryRouteOptions as s, DefaultStoryPath as t, StoryRouteFileOptions as u };