@storybook/tanstack-react 10.6.0-alpha.3 → 10.6.0-alpha.5
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/dist/_browser-chunks/{chunk-XY6TESST.js → chunk-HRV4LMK3.js} +71 -26
- package/dist/{chunk-CT6Edisg.d.ts → chunk-B0pqNVvJ.d.ts} +5 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/node/index.d.ts +1 -1
- package/dist/node/index.js +6 -6
- package/dist/preset.js +12 -11
- package/dist/preview.d.ts +4 -3
- package/dist/preview.js +3 -1
- package/package.json +5 -5
- package/template/stories/LoaderContextInjection.stories.tsx +45 -0
- package/template/stories/RouterContextInjection.stories.tsx +45 -0
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
var preview_exports = {};
|
|
10
10
|
__export(preview_exports, {
|
|
11
11
|
applyDecorators: () => applyDecorators,
|
|
12
|
+
beforeEach: () => beforeEach,
|
|
12
13
|
loaders: () => loaders,
|
|
13
14
|
optimizeDeps: () => optimizeDeps,
|
|
14
15
|
parameters: () => parameters
|
|
@@ -16,22 +17,23 @@ __export(preview_exports, {
|
|
|
16
17
|
import { applyDecorators as reactApplyDecorators } from "@storybook/react/entry-preview-docs";
|
|
17
18
|
|
|
18
19
|
// src/routing/decorator.tsx
|
|
19
|
-
import React from "react";
|
|
20
20
|
import {
|
|
21
21
|
createMemoryHistory,
|
|
22
22
|
createRootRoute,
|
|
23
23
|
createRoute as createRoute2,
|
|
24
24
|
createRouter,
|
|
25
|
-
|
|
26
|
-
interpolatePath,
|
|
27
|
-
|
|
25
|
+
defaultStringifySearch,
|
|
26
|
+
interpolatePath as interpolatePath2,
|
|
27
|
+
RouterProvider
|
|
28
28
|
} from "@tanstack/react-router";
|
|
29
|
+
import React from "react";
|
|
29
30
|
|
|
30
31
|
// src/routing/duplicate-tree.ts
|
|
31
32
|
import {
|
|
32
33
|
createRoute,
|
|
33
34
|
RootRoute,
|
|
34
35
|
createRootRouteWithContext,
|
|
36
|
+
interpolatePath,
|
|
35
37
|
joinPaths
|
|
36
38
|
} from "@tanstack/react-router";
|
|
37
39
|
var MAX_PARENT_WALK = 50;
|
|
@@ -54,13 +56,18 @@ function initSourceTree(route, counter) {
|
|
|
54
56
|
for (let child of children)
|
|
55
57
|
initSourceTree(child, counter);
|
|
56
58
|
}
|
|
59
|
+
function layoutIdFor(id) {
|
|
60
|
+
return id.length > 1 && id.endsWith("/") ? id.slice(0, -1) : id;
|
|
61
|
+
}
|
|
57
62
|
function cloneChild(oldRoute, parent, overrides, byId) {
|
|
58
|
-
let options = oldRoute.options ?? {}, { id: originalId, getParentRoute: _g, ...rest } = options, override = getOverrideFor(overrides, oldRoute.id), merged = { ...rest, ...
|
|
59
|
-
...!merged.path &&
|
|
63
|
+
let options = oldRoute.options ?? {}, { id: originalId, getParentRoute: _g, ...rest } = options, override = getOverrideFor(overrides, oldRoute.id), { id: overrideId, ...overrideRest } = override, merged = { ...rest, ...overrideRest }, explicitId = "id" in override ? overrideId : originalId, cloned = createRoute({
|
|
64
|
+
...!merged.path && explicitId != null ? { id: layoutIdFor(explicitId) } : {},
|
|
60
65
|
...merged,
|
|
61
66
|
getParentRoute: () => parent
|
|
62
67
|
});
|
|
63
|
-
|
|
68
|
+
merged.path && explicitId != null && cloned.update({ id: explicitId });
|
|
69
|
+
let lazyFn = oldRoute.lazyFn;
|
|
70
|
+
lazyFn && cloned.lazy(lazyFn), byId.set(oldRoute.id, cloned);
|
|
64
71
|
let children = oldRoute.children;
|
|
65
72
|
if (children?.length) {
|
|
66
73
|
let clonedChildren = children.map(
|
|
@@ -80,8 +87,8 @@ function duplicateRouteTree(rootRoute, { overrides } = {}) {
|
|
|
80
87
|
} = rootOptions, newRoot = createRootRouteWithContext()({
|
|
81
88
|
...restRoot,
|
|
82
89
|
...rootOverride
|
|
83
|
-
});
|
|
84
|
-
byId.set("__root__", newRoot);
|
|
90
|
+
}), rootLazyFn = rootRoute.lazyFn;
|
|
91
|
+
rootLazyFn && newRoot.lazy(rootLazyFn), byId.set("__root__", newRoot);
|
|
85
92
|
let children = rootRoute.children;
|
|
86
93
|
if (children?.length) {
|
|
87
94
|
let clonedChildren = children.map(
|
|
@@ -106,13 +113,27 @@ function originalRouteId(tree, route) {
|
|
|
106
113
|
if (cloned === route)
|
|
107
114
|
return id;
|
|
108
115
|
}
|
|
109
|
-
function resolveStoryLeaf(tree, {
|
|
116
|
+
function resolveStoryLeaf(tree, {
|
|
117
|
+
path,
|
|
118
|
+
boundRouteId,
|
|
119
|
+
params
|
|
120
|
+
}) {
|
|
110
121
|
let { root, byId } = tree;
|
|
111
122
|
if (path) {
|
|
112
|
-
let
|
|
123
|
+
let bound = boundRouteId ? byId.get(boundRouteId) : void 0;
|
|
124
|
+
if (bound) {
|
|
125
|
+
let boundCandidate = mountPathFor(bound), boundInterpolated = params ? interpolatePath({ path: boundCandidate, params }).interpolatedPath : boundCandidate;
|
|
126
|
+
if (boundCandidate === path || boundInterpolated === path)
|
|
127
|
+
return bound;
|
|
128
|
+
}
|
|
129
|
+
let bestMatch, bestLiteral = !1, bestMatchLength = -1;
|
|
113
130
|
for (let route of byId.values()) {
|
|
114
|
-
|
|
115
|
-
|
|
131
|
+
if (route === root)
|
|
132
|
+
continue;
|
|
133
|
+
let candidate = mountPathFor(route), isLiteral = candidate === path, interpolated = params ? interpolatePath({ path: candidate, params }).interpolatedPath : candidate;
|
|
134
|
+
if (!isLiteral && interpolated !== path)
|
|
135
|
+
continue;
|
|
136
|
+
(isLiteral === bestLiteral ? candidate.length > bestMatchLength : isLiteral) && (bestMatch = route, bestLiteral = isLiteral, bestMatchLength = candidate.length);
|
|
116
137
|
}
|
|
117
138
|
if (bestMatch)
|
|
118
139
|
return bestMatch;
|
|
@@ -138,17 +159,15 @@ var StoryContext = React.createContext({ Story: () => null }), StoryFromContext
|
|
|
138
159
|
return React.createElement(Story, null);
|
|
139
160
|
}, tanstackRouteDecorator = (Story, context) => React.createElement(TanStackRouterStory, { Story, context });
|
|
140
161
|
function TanStackRouterStory({ Story, context }) {
|
|
141
|
-
let routerContext = context.parameters.tanstack?.router?.useRouterContext?.({
|
|
162
|
+
let router = context.tanstackRouter, routerContext = context.parameters.tanstack?.router?.useRouterContext?.({
|
|
142
163
|
storyContext: context
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
...routerContext
|
|
151
|
-
}),
|
|
164
|
+
});
|
|
165
|
+
if (!router)
|
|
166
|
+
throw new Error(
|
|
167
|
+
"No story router found on the story context: the `routerBeforeEach` hook of @storybook/tanstack-react did not run before rendering. Note that portable stories are not supported by this framework."
|
|
168
|
+
);
|
|
169
|
+
let providerContext = React.useMemo(
|
|
170
|
+
() => routerContext,
|
|
152
171
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
153
172
|
[context.id, routerContext]
|
|
154
173
|
);
|
|
@@ -159,7 +178,7 @@ function createStoryRouter({
|
|
|
159
178
|
context,
|
|
160
179
|
routerContext
|
|
161
180
|
}) {
|
|
162
|
-
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 =
|
|
181
|
+
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 = interpolatePath2({
|
|
163
182
|
path: inferredPath,
|
|
164
183
|
params: routerParameters?.params ?? {}
|
|
165
184
|
}).interpolatedPath, search = routerParameters?.query ? defaultStringifySearch(routerParameters.query) : "";
|
|
@@ -206,7 +225,8 @@ function resolveTree(Story, context) {
|
|
|
206
225
|
if (rootRoute) {
|
|
207
226
|
let tree = duplicateRouteTree(rootRoute, { overrides: routeOverrides }), leaf = resolveStoryLeaf(tree, {
|
|
208
227
|
path: routerParameters.path,
|
|
209
|
-
boundRouteId: resolvedRoute && resolvedRoute !== rootRoute ? resolvedRoute.id : void 0
|
|
228
|
+
boundRouteId: resolvedRoute && resolvedRoute !== rootRoute ? resolvedRoute.id : void 0,
|
|
229
|
+
params: routerParameters.params
|
|
210
230
|
});
|
|
211
231
|
injectStoryComponent(leaf, Story, routeOverrides, originalRouteId(tree, leaf) ?? leaf.id);
|
|
212
232
|
let renderLeaf = ensureMatchableLeaf(tree, leaf);
|
|
@@ -247,6 +267,30 @@ function resolveTree(Story, context) {
|
|
|
247
267
|
};
|
|
248
268
|
}
|
|
249
269
|
|
|
270
|
+
// src/routing/before-each.ts
|
|
271
|
+
var storyRouters = /* @__PURE__ */ new Map(), routerBeforeEach = async (context) => {
|
|
272
|
+
let cached = storyRouters.get(context.id);
|
|
273
|
+
if (cached) {
|
|
274
|
+
context.tanstackRouter = cached;
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
let storyContext = context, parameterContext = (context.parameters.tanstack?.router ?? {}).context, routerContext = typeof parameterContext == "function" ? parameterContext({ storyContext }) : parameterContext, router = createStoryRouter({
|
|
278
|
+
Story: StoryFromContext,
|
|
279
|
+
context: storyContext,
|
|
280
|
+
routerContext
|
|
281
|
+
}), load = router.load();
|
|
282
|
+
if (context.abortSignal && !context.abortSignal.aborted ? (load.catch(() => {
|
|
283
|
+
}), await Promise.race([
|
|
284
|
+
load,
|
|
285
|
+
new Promise(
|
|
286
|
+
(resolve) => context.abortSignal.addEventListener("abort", () => resolve(), { once: !0 })
|
|
287
|
+
)
|
|
288
|
+
])) : await load, !context.abortSignal?.aborted)
|
|
289
|
+
return storyRouters.set(context.id, router), context.tanstackRouter = router, () => {
|
|
290
|
+
storyRouters.delete(context.id);
|
|
291
|
+
};
|
|
292
|
+
};
|
|
293
|
+
|
|
250
294
|
// src/routing/loader.ts
|
|
251
295
|
import { RootRoute as RootRoute3 } from "@tanstack/react-router";
|
|
252
296
|
function getComponentFromRoute(route) {
|
|
@@ -267,7 +311,7 @@ var routeComponentLoader = (context) => {
|
|
|
267
311
|
};
|
|
268
312
|
|
|
269
313
|
// src/preview.tsx
|
|
270
|
-
var loaders = [routeComponentLoader], applyDecorators = (storyFn, allDecorators) => (
|
|
314
|
+
var loaders = [routeComponentLoader], beforeEach = [routerBeforeEach], applyDecorators = (storyFn, allDecorators) => (
|
|
271
315
|
// reorder decorators so `jsxDecorator` is innermost, and `tanstackRouteDecorator` is just outside it
|
|
272
316
|
// There is an issue if `tanstackRouteDecorator` is innermost. All stories crashes due to a bug with the jsxDecorator.
|
|
273
317
|
reactApplyDecorators(storyFn, [
|
|
@@ -284,6 +328,7 @@ var loaders = [routeComponentLoader], applyDecorators = (storyFn, allDecorators)
|
|
|
284
328
|
|
|
285
329
|
export {
|
|
286
330
|
loaders,
|
|
331
|
+
beforeEach,
|
|
287
332
|
applyDecorators,
|
|
288
333
|
parameters,
|
|
289
334
|
optimizeDeps,
|
|
@@ -86,10 +86,11 @@ interface RouterParameters<TRoute = undefined, Path extends (TRoute extends AnyR
|
|
|
86
86
|
* ```
|
|
87
87
|
*/
|
|
88
88
|
routeOverrides?: RouteTreeOverrides;
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
89
|
+
/** Object or factory; the factory runs before initial router load outside React, so loader and beforeLoad can read its values. */
|
|
90
|
+
context?: Record<string, unknown> | ((options: {
|
|
91
|
+
storyContext: Parameters<Decorator>[1];
|
|
92
|
+
}) => Record<string, unknown>);
|
|
93
|
+
/** React hook render context reaches components, not the initial loader or beforeLoad; use the context factory for loader-visible values. */
|
|
93
94
|
useRouterContext?: ({
|
|
94
95
|
storyContext
|
|
95
96
|
}: {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as TanStackPreviewOptions, c as IsRoute, d as StoryRouteOptions, i as TanStackParameters, l as RouterParameters, n as FrameworkOptions, o as TanStackTypes, r as StorybookConfig, s as CreateStoryRouteOptions, t as DefaultStoryPath, u as StoryRouteFileOptions } from "./chunk-
|
|
1
|
+
import { a as TanStackPreviewOptions, c as IsRoute, d as StoryRouteOptions, i as TanStackParameters, l as RouterParameters, n as FrameworkOptions, o as TanStackTypes, r as StorybookConfig, s as CreateStoryRouteOptions, t as DefaultStoryPath, u as StoryRouteFileOptions } from "./chunk-B0pqNVvJ.js";
|
|
2
2
|
import { ComponentType } from "react";
|
|
3
3
|
import { AddonTypes, InferTypes, PreviewAddon } from "storybook/internal/csf";
|
|
4
4
|
import { Args, ArgsStoryFn, ComponentAnnotations, DecoratorFunction, Parameters, ProjectAnnotations, Renderer, StoryAnnotations } from "storybook/internal/types";
|
package/dist/index.js
CHANGED
package/dist/node/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as StorybookConfig } from "../chunk-
|
|
1
|
+
import { r as StorybookConfig } from "../chunk-B0pqNVvJ.js";
|
|
2
2
|
|
|
3
3
|
//#region code/frameworks/tanstack-react/.dts-emit/code/frameworks/tanstack-react/src/node/index.d.ts
|
|
4
4
|
declare function defineMain(config: StorybookConfig): StorybookConfig;
|
package/dist/node/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
1
|
+
import CJS_COMPAT_NODE_URL_zvu6fwxyfs from 'node:url';
|
|
2
|
+
import CJS_COMPAT_NODE_PATH_zvu6fwxyfs from 'node:path';
|
|
3
|
+
import CJS_COMPAT_NODE_MODULE_zvu6fwxyfs from "node:module";
|
|
4
4
|
|
|
5
|
-
var __filename =
|
|
6
|
-
var __dirname =
|
|
7
|
-
var require =
|
|
5
|
+
var __filename = CJS_COMPAT_NODE_URL_zvu6fwxyfs.fileURLToPath(import.meta.url);
|
|
6
|
+
var __dirname = CJS_COMPAT_NODE_PATH_zvu6fwxyfs.dirname(__filename);
|
|
7
|
+
var require = CJS_COMPAT_NODE_MODULE_zvu6fwxyfs.createRequire(import.meta.url);
|
|
8
8
|
|
|
9
9
|
// ------------------------------------------------------------
|
|
10
10
|
// end of CJS compatibility banner, injected by Storybook's esbuild configuration
|
package/dist/preset.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
1
|
+
import CJS_COMPAT_NODE_URL_zvu6fwxyfs from 'node:url';
|
|
2
|
+
import CJS_COMPAT_NODE_PATH_zvu6fwxyfs from 'node:path';
|
|
3
|
+
import CJS_COMPAT_NODE_MODULE_zvu6fwxyfs from "node:module";
|
|
4
4
|
|
|
5
|
-
var __filename =
|
|
6
|
-
var __dirname =
|
|
7
|
-
var require =
|
|
5
|
+
var __filename = CJS_COMPAT_NODE_URL_zvu6fwxyfs.fileURLToPath(import.meta.url);
|
|
6
|
+
var __dirname = CJS_COMPAT_NODE_PATH_zvu6fwxyfs.dirname(__filename);
|
|
7
|
+
var require = CJS_COMPAT_NODE_MODULE_zvu6fwxyfs.createRequire(import.meta.url);
|
|
8
8
|
|
|
9
9
|
// ------------------------------------------------------------
|
|
10
10
|
// end of CJS compatibility banner, injected by Storybook's esbuild configuration
|
|
@@ -360,16 +360,17 @@ function moduleInterceptionPlugin({
|
|
|
360
360
|
enforce: "pre",
|
|
361
361
|
resolveId: {
|
|
362
362
|
order: "pre",
|
|
363
|
-
handler(id, importer) {
|
|
363
|
+
async handler(id, importer) {
|
|
364
|
+
let resolveMock = async (mockPath) => await this.resolve(mockPath, importer, { skipSelf: !0 }) ?? mockPath;
|
|
364
365
|
if ((id === "@tanstack/react-router" || id.startsWith("@tanstack/react-router/")) && importer && !importer.includes("export-mocks"))
|
|
365
|
-
return routerMockPath;
|
|
366
|
+
return resolveMock(routerMockPath);
|
|
366
367
|
if (START_SERVER_MODULES.includes(id) || id === "@tanstack/react-start")
|
|
367
|
-
return startMockPath;
|
|
368
|
+
return resolveMock(startMockPath);
|
|
368
369
|
if (id === "@tanstack/start-storage-context")
|
|
369
|
-
return startStorageContextMockPath;
|
|
370
|
+
return resolveMock(startStorageContextMockPath);
|
|
370
371
|
for (let pattern of INTERCEPTED_PATTERNS)
|
|
371
372
|
if (id.includes(pattern))
|
|
372
|
-
return startMockPath;
|
|
373
|
+
return resolveMock(startMockPath);
|
|
373
374
|
return null;
|
|
374
375
|
}
|
|
375
376
|
},
|
package/dist/preview.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { i as TanStackParameters } from "./chunk-
|
|
2
|
-
import { DecoratorFunction, LoaderFunction, Renderer } from "storybook/internal/types";
|
|
1
|
+
import { i as TanStackParameters } from "./chunk-B0pqNVvJ.js";
|
|
2
|
+
import { BeforeEach, DecoratorFunction, LoaderFunction, Renderer } from "storybook/internal/types";
|
|
3
3
|
import { applyDecorators as applyDecorators$1 } from "@storybook/react/entry-preview-docs";
|
|
4
4
|
|
|
5
5
|
//#region code/frameworks/tanstack-react/.dts-emit/code/frameworks/tanstack-react/src/preview.d.ts
|
|
6
6
|
declare const loaders: LoaderFunction<Renderer>[];
|
|
7
|
+
declare const beforeEach: BeforeEach<Renderer>[];
|
|
7
8
|
declare const applyDecorators: (storyFn: Parameters<typeof applyDecorators$1>[0], allDecorators: DecoratorFunction[]) => any;
|
|
8
9
|
declare const parameters: TanStackParameters;
|
|
9
10
|
declare const optimizeDeps: string[];
|
|
10
11
|
//#endregion
|
|
11
|
-
export { applyDecorators, loaders, optimizeDeps, parameters };
|
|
12
|
+
export { applyDecorators, beforeEach, loaders, optimizeDeps, parameters };
|
package/dist/preview.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
applyDecorators,
|
|
3
|
+
beforeEach,
|
|
3
4
|
loaders,
|
|
4
5
|
optimizeDeps,
|
|
5
6
|
parameters
|
|
6
|
-
} from "./_browser-chunks/chunk-
|
|
7
|
+
} from "./_browser-chunks/chunk-HRV4LMK3.js";
|
|
7
8
|
import "./_browser-chunks/chunk-LTDGLEVR.js";
|
|
8
9
|
import "./_browser-chunks/chunk-4BE7D4DS.js";
|
|
9
10
|
export {
|
|
10
11
|
applyDecorators,
|
|
12
|
+
beforeEach,
|
|
11
13
|
loaders,
|
|
12
14
|
optimizeDeps,
|
|
13
15
|
parameters
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@storybook/tanstack-react",
|
|
3
|
-
"version": "10.6.0-alpha.
|
|
3
|
+
"version": "10.6.0-alpha.5",
|
|
4
4
|
"description": "Storybook for TanStack (React, Vite): Router and Start ready Storybook framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"storybook",
|
|
@@ -75,9 +75,9 @@
|
|
|
75
75
|
"!src/**/*"
|
|
76
76
|
],
|
|
77
77
|
"dependencies": {
|
|
78
|
-
"@storybook/builder-vite": "10.6.0-alpha.
|
|
79
|
-
"@storybook/react": "10.6.0-alpha.
|
|
80
|
-
"@storybook/react-vite": "10.6.0-alpha.
|
|
78
|
+
"@storybook/builder-vite": "10.6.0-alpha.5",
|
|
79
|
+
"@storybook/react": "10.6.0-alpha.5",
|
|
80
|
+
"@storybook/react-vite": "10.6.0-alpha.5"
|
|
81
81
|
},
|
|
82
82
|
"devDependencies": {
|
|
83
83
|
"@tanstack/react-router": "^1.168.10",
|
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
"@tanstack/start-client-core": "^1.167.9",
|
|
96
96
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
|
97
97
|
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
|
98
|
-
"storybook": "^10.6.0-alpha.
|
|
98
|
+
"storybook": "^10.6.0-alpha.5",
|
|
99
99
|
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
|
|
100
100
|
},
|
|
101
101
|
"peerDependenciesMeta": {
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import type { Meta, StoryObj } from '@storybook/tanstack-react';
|
|
4
|
+
|
|
5
|
+
import { expect, within } from 'storybook/test';
|
|
6
|
+
|
|
7
|
+
const loaderCalls: unknown[] = [];
|
|
8
|
+
|
|
9
|
+
function LoaderContextViewer() {
|
|
10
|
+
return <p data-testid="loader-context">{String(loaderCalls[0] ?? 'missing')}</p>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const meta = {
|
|
14
|
+
component: LoaderContextViewer,
|
|
15
|
+
parameters: {
|
|
16
|
+
tanstack: {
|
|
17
|
+
router: {
|
|
18
|
+
context: () => {
|
|
19
|
+
loaderCalls.length = 0;
|
|
20
|
+
return { injected: 'from-factory' };
|
|
21
|
+
},
|
|
22
|
+
route: {
|
|
23
|
+
loader: ({ context }: { context: unknown }) => {
|
|
24
|
+
loaderCalls.push((context as any)?.injected ?? null);
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
} satisfies Meta<typeof LoaderContextViewer>;
|
|
31
|
+
|
|
32
|
+
export default meta;
|
|
33
|
+
|
|
34
|
+
type Story = StoryObj<typeof meta>;
|
|
35
|
+
|
|
36
|
+
/** Factory router context is visible to the route loader before render. */
|
|
37
|
+
export const FactoryValuesReachLoader: Story = {
|
|
38
|
+
play: async ({ canvasElement }) => {
|
|
39
|
+
const canvas = within(canvasElement);
|
|
40
|
+
await expect(canvas.getByTestId('loader-context')).toHaveTextContent('from-factory');
|
|
41
|
+
|
|
42
|
+
await expect(loaderCalls.length).toBeGreaterThan(0);
|
|
43
|
+
await expect(loaderCalls.every((call) => call === 'from-factory')).toBe(true);
|
|
44
|
+
},
|
|
45
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import type { Meta, StoryObj } from '@storybook/tanstack-react';
|
|
4
|
+
|
|
5
|
+
import { useRouter } from '@tanstack/react-router';
|
|
6
|
+
import { expect, within } from 'storybook/test';
|
|
7
|
+
|
|
8
|
+
const InjectedContext = React.createContext('missing-provider');
|
|
9
|
+
|
|
10
|
+
function RouterContextViewer() {
|
|
11
|
+
const router = useRouter();
|
|
12
|
+
const injected = (router.options.context as { injected?: string } | undefined)?.injected;
|
|
13
|
+
return <p data-testid="injected-router-context">{injected ?? 'missing-context'}</p>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const meta = {
|
|
17
|
+
component: RouterContextViewer,
|
|
18
|
+
decorators: [
|
|
19
|
+
(Story) => (
|
|
20
|
+
<InjectedContext.Provider value="from-react-hook">
|
|
21
|
+
<Story />
|
|
22
|
+
</InjectedContext.Provider>
|
|
23
|
+
),
|
|
24
|
+
],
|
|
25
|
+
parameters: {
|
|
26
|
+
tanstack: {
|
|
27
|
+
router: {
|
|
28
|
+
useRouterContext: () => ({ injected: React.useContext(InjectedContext) }),
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
} satisfies Meta<typeof RouterContextViewer>;
|
|
33
|
+
|
|
34
|
+
export default meta;
|
|
35
|
+
|
|
36
|
+
type Story = StoryObj<typeof meta>;
|
|
37
|
+
|
|
38
|
+
/** Hook-derived values read from a decorator's React provider must reach the story's router. */
|
|
39
|
+
export const HookValuesReachRouter: Story = {
|
|
40
|
+
play: async ({ canvasElement }) => {
|
|
41
|
+
await expect(within(canvasElement).getByTestId('injected-router-context')).toHaveTextContent(
|
|
42
|
+
'from-react-hook'
|
|
43
|
+
);
|
|
44
|
+
},
|
|
45
|
+
};
|