@storybook/tanstack-react 0.0.0 → 10.4.0-alpha.18
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-73EPJ7AY.js +230 -0
- package/dist/export-mocks/react-router.d.ts +344 -0
- package/dist/export-mocks/react-router.js +79 -0
- package/dist/export-mocks/start-storage-context.d.ts +16 -0
- package/dist/export-mocks/start-storage-context.js +33 -0
- package/dist/export-mocks/start.d.ts +120 -0
- package/dist/export-mocks/start.js +334 -0
- package/dist/index.d.ts +438 -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 +9 -0
- package/dist/preset.js +403 -0
- package/dist/preview.d.ts +111 -0
- package/dist/preview.js +13 -0
- package/package.json +108 -5
- package/template/cli/ts/Button.stories.ts +54 -0
- package/template/cli/ts/Button.tsx +36 -0
- package/template/cli/ts/Header.stories.ts +34 -0
- package/template/cli/ts/Header.tsx +56 -0
- package/template/cli/ts/Page.stories.ts +41 -0
- package/template/cli/ts/Page.tsx +79 -0
package/dist/preset.js
ADDED
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
import CJS_COMPAT_NODE_URL_846xwv5762j from 'node:url';
|
|
2
|
+
import CJS_COMPAT_NODE_PATH_846xwv5762j from 'node:path';
|
|
3
|
+
import CJS_COMPAT_NODE_MODULE_846xwv5762j from "node:module";
|
|
4
|
+
|
|
5
|
+
var __filename = CJS_COMPAT_NODE_URL_846xwv5762j.fileURLToPath(import.meta.url);
|
|
6
|
+
var __dirname = CJS_COMPAT_NODE_PATH_846xwv5762j.dirname(__filename);
|
|
7
|
+
var require = CJS_COMPAT_NODE_MODULE_846xwv5762j.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
|
+
|
|
16
|
+
// ../../../node_modules/pathe/dist/shared/pathe.ff20891b.mjs
|
|
17
|
+
var _DRIVE_LETTER_START_RE = /^[A-Za-z]:\//;
|
|
18
|
+
function normalizeWindowsPath(input = "") {
|
|
19
|
+
return input && input.replace(/\\/g, "/").replace(_DRIVE_LETTER_START_RE, (r) => r.toUpperCase());
|
|
20
|
+
}
|
|
21
|
+
var _IS_ABSOLUTE_RE = /^[/\\](?![/\\])|^[/\\]{2}(?!\.)|^[A-Za-z]:[/\\]/, _DRIVE_LETTER_RE = /^[A-Za-z]:$/;
|
|
22
|
+
var isAbsolute = function(p) {
|
|
23
|
+
return _IS_ABSOLUTE_RE.test(p);
|
|
24
|
+
};
|
|
25
|
+
var dirname = function(p) {
|
|
26
|
+
let segments = normalizeWindowsPath(p).replace(/\/$/, "").split("/").slice(0, -1);
|
|
27
|
+
return segments.length === 1 && _DRIVE_LETTER_RE.test(segments[0]) && (segments[0] += "/"), segments.join("/") || (isAbsolute(p) ? "/" : ".");
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// src/preset.ts
|
|
31
|
+
import { viteFinal as reactViteFinal } from "@storybook/react-vite/preset";
|
|
32
|
+
|
|
33
|
+
// src/plugins/server-code-elimination.ts
|
|
34
|
+
import { transformSync, types as t } from "storybook/internal/babel";
|
|
35
|
+
var SERVER_FN_RE = /\bcreateServerFn\b/, MIDDLEWARE_RE = /\bcreateMiddleware\b/, ISOMORPHIC_FN_RE = /\bcreateIsomorphicFn\b/, SERVER_ONLY_FN_RE = /\bcreateServerOnlyFn\b/, CLIENT_ONLY_FN_RE = /\bcreateClientOnlyFn\b/, ROUTE_FACTORY_RE = /\b(createFileRoute|createRootRoute|createRootRouteWithContext|createRoute)\b/, ROUTE_FACTORIES = /* @__PURE__ */ new Set([
|
|
36
|
+
"createFileRoute",
|
|
37
|
+
"createRootRoute",
|
|
38
|
+
"createRootRouteWithContext",
|
|
39
|
+
"createRoute"
|
|
40
|
+
]), ANY_PATTERN_RE = /\b(createServerFn|createMiddleware|createIsomorphicFn|createServerOnlyFn|createClientOnlyFn|createFileRoute|createRootRoute|createRootRouteWithContext|createRoute)\b/;
|
|
41
|
+
function serverCodeEliminationPlugin(options = {}) {
|
|
42
|
+
let excludeFiles = options.excludeFiles ?? [];
|
|
43
|
+
return {
|
|
44
|
+
name: "storybook:tanstack-react:server-code-elimination",
|
|
45
|
+
enforce: "pre",
|
|
46
|
+
transform: {
|
|
47
|
+
// we can fully rely on transform.filter
|
|
48
|
+
// and not worry about the handler since tanstack start users are Vite > 8 only
|
|
49
|
+
filter: {
|
|
50
|
+
id: {
|
|
51
|
+
include: [/\.tsx?$/],
|
|
52
|
+
exclude: [/node_modules/]
|
|
53
|
+
},
|
|
54
|
+
code: ANY_PATTERN_RE
|
|
55
|
+
},
|
|
56
|
+
async handler(code, id) {
|
|
57
|
+
if (!/\.[mc]?[jt]sx?$/.test(id) || excludeFiles.some((excluded) => id.includes(excluded)) || !ANY_PATTERN_RE.test(code))
|
|
58
|
+
return null;
|
|
59
|
+
let state = { code, modified: !1, needsFnImport: !1 }, result = transformSync(code, {
|
|
60
|
+
filename: id,
|
|
61
|
+
sourceType: "module",
|
|
62
|
+
parserOpts: {
|
|
63
|
+
plugins: ["typescript", "jsx"]
|
|
64
|
+
},
|
|
65
|
+
plugins: [() => serverCodeElimination(state)],
|
|
66
|
+
sourceMaps: !0,
|
|
67
|
+
configFile: !1,
|
|
68
|
+
babelrc: !1
|
|
69
|
+
});
|
|
70
|
+
return !state.modified || !result?.code ? null : {
|
|
71
|
+
code: result.code,
|
|
72
|
+
map: result.map
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function serverCodeElimination(state) {
|
|
79
|
+
function sbFnCall() {
|
|
80
|
+
return state.needsFnImport = !0, buildFnCall();
|
|
81
|
+
}
|
|
82
|
+
function sbFnCallWithImpl(impl) {
|
|
83
|
+
return state.needsFnImport = !0, buildFnCallWithImpl(impl);
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
visitor: {
|
|
87
|
+
Program(programPath) {
|
|
88
|
+
let tanstackImports = collectTanstackImports(programPath.node.body), resolves = (name, factory) => resolvesToFactory(tanstackImports, name, factory);
|
|
89
|
+
programPath.traverse({
|
|
90
|
+
CallExpression(path2) {
|
|
91
|
+
let node = path2.node;
|
|
92
|
+
if (ROUTE_FACTORY_RE.test(state.code)) {
|
|
93
|
+
let routeOptionsArg = getRouteFactoryOptionsArg(node, tanstackImports);
|
|
94
|
+
routeOptionsArg && stripServerOption(routeOptionsArg) && (state.modified = !0);
|
|
95
|
+
}
|
|
96
|
+
if (t.isIdentifier(node.callee) && resolves(node.callee.name, "createServerOnlyFn") && SERVER_ONLY_FN_RE.test(state.code)) {
|
|
97
|
+
path2.replaceWith(sbFnCall()), state.modified = !0;
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (t.isIdentifier(node.callee) && resolves(node.callee.name, "createClientOnlyFn") && CLIENT_ONLY_FN_RE.test(state.code)) {
|
|
101
|
+
let innerFn = node.arguments[0];
|
|
102
|
+
innerFn && t.isExpression(innerFn) && (path2.replaceWith(sbFnCallWithImpl(innerFn)), state.modified = !0);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
let methodName = getMethodName(node);
|
|
106
|
+
if (!methodName)
|
|
107
|
+
return;
|
|
108
|
+
let root = findChainRoot(node);
|
|
109
|
+
if (root) {
|
|
110
|
+
if (methodName === "handler" && resolves(root.rootName, "createServerFn") && SERVER_FN_RE.test(state.code)) {
|
|
111
|
+
let handlerArg = node.arguments[0];
|
|
112
|
+
if (handlerArg) {
|
|
113
|
+
if (t.isIdentifier(handlerArg)) {
|
|
114
|
+
let binding = path2.scope.getBinding(handlerArg.name);
|
|
115
|
+
binding && binding.referencePaths.length === 1 && binding.path.remove();
|
|
116
|
+
}
|
|
117
|
+
node.arguments[0] = sbFnCall();
|
|
118
|
+
}
|
|
119
|
+
state.modified = !0;
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (resolves(root.rootName, "createMiddleware") && MIDDLEWARE_RE.test(state.code)) {
|
|
123
|
+
(methodName === "server" || methodName === "inputValidator") && t.isMemberExpression(path2.node.callee) && (path2.replaceWith(path2.node.callee.object), state.modified = !0);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (resolves(root.rootName, "createIsomorphicFn") && ISOMORPHIC_FN_RE.test(state.code)) {
|
|
127
|
+
if (methodName === "client") {
|
|
128
|
+
let innerFn = node.arguments[0];
|
|
129
|
+
innerFn && t.isExpression(innerFn) && (path2.replaceWith(sbFnCallWithImpl(innerFn)), state.modified = !0);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (methodName === "server") {
|
|
133
|
+
let parent = path2.parent;
|
|
134
|
+
(!t.isMemberExpression(parent) || !t.isCallExpression(path2.parentPath?.parent)) && (path2.replaceWith(sbFnCall()), state.modified = !0);
|
|
135
|
+
}
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}), state.modified && (state.needsFnImport && programPath.node.body.unshift(buildFnImport()), eliminateDeadImports(programPath));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
function buildFnImport() {
|
|
146
|
+
return t.importDeclaration(
|
|
147
|
+
[t.importSpecifier(t.identifier("__sb_fn"), t.identifier("fn"))],
|
|
148
|
+
t.stringLiteral("storybook/test")
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
function buildFnCall() {
|
|
152
|
+
return t.callExpression(t.identifier("__sb_fn"), []);
|
|
153
|
+
}
|
|
154
|
+
function buildFnCallWithImpl(impl) {
|
|
155
|
+
return t.callExpression(t.identifier("__sb_fn"), [impl]);
|
|
156
|
+
}
|
|
157
|
+
function collectTanstackImports(body) {
|
|
158
|
+
let imports = /* @__PURE__ */ new Map();
|
|
159
|
+
for (let node of body) {
|
|
160
|
+
if (!t.isImportDeclaration(node))
|
|
161
|
+
continue;
|
|
162
|
+
let src = node.source.value;
|
|
163
|
+
if (!(!src.includes("@tanstack/") && !src.includes("export-mocks") && !src.includes("@storybook/tanstack-react"))) {
|
|
164
|
+
for (let spec of node.specifiers)
|
|
165
|
+
if (t.isImportSpecifier(spec)) {
|
|
166
|
+
let importedName = t.isIdentifier(spec.imported) ? spec.imported.name : spec.imported.value;
|
|
167
|
+
imports.set(spec.local.name, importedName);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return imports;
|
|
172
|
+
}
|
|
173
|
+
function resolvesToFactory(imports, name, factoryName) {
|
|
174
|
+
return name === factoryName || imports.get(name) === factoryName;
|
|
175
|
+
}
|
|
176
|
+
function findChainRoot(node) {
|
|
177
|
+
let current = node;
|
|
178
|
+
for (; ; ) {
|
|
179
|
+
let callee = current.callee;
|
|
180
|
+
if (t.isIdentifier(callee))
|
|
181
|
+
return { rootCall: current, rootName: callee.name };
|
|
182
|
+
if (t.isMemberExpression(callee) && t.isCallExpression(callee.object)) {
|
|
183
|
+
current = callee.object;
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
function getMethodName(node) {
|
|
190
|
+
return t.isMemberExpression(node.callee) && t.isIdentifier(node.callee.property) ? node.callee.property.name : null;
|
|
191
|
+
}
|
|
192
|
+
function getRouteFactoryOptionsArg(node, imports) {
|
|
193
|
+
if (!getRouteFactoryName(node, imports))
|
|
194
|
+
return null;
|
|
195
|
+
let optionsArg = node.arguments[0];
|
|
196
|
+
return t.isObjectExpression(optionsArg) ? optionsArg : null;
|
|
197
|
+
}
|
|
198
|
+
function getRouteFactoryName(node, imports) {
|
|
199
|
+
if (t.isIdentifier(node.callee)) {
|
|
200
|
+
let resolved = imports.get(node.callee.name) ?? node.callee.name;
|
|
201
|
+
return ROUTE_FACTORIES.has(resolved) ? resolved : null;
|
|
202
|
+
}
|
|
203
|
+
if (t.isCallExpression(node.callee) && t.isIdentifier(node.callee.callee)) {
|
|
204
|
+
let calleeName = node.callee.callee.name, resolved = imports.get(calleeName) ?? calleeName;
|
|
205
|
+
return ROUTE_FACTORIES.has(resolved) ? resolved : null;
|
|
206
|
+
}
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
function stripServerOption(options) {
|
|
210
|
+
let initialLength = options.properties.length;
|
|
211
|
+
return options.properties = options.properties.filter((prop) => {
|
|
212
|
+
if (!t.isObjectProperty(prop) || prop.computed)
|
|
213
|
+
return !0;
|
|
214
|
+
let key = prop.key;
|
|
215
|
+
return (t.isIdentifier(key) ? key.name : void 0) !== "server";
|
|
216
|
+
}), options.properties.length !== initialLength;
|
|
217
|
+
}
|
|
218
|
+
function eliminateDeadImports(programPath) {
|
|
219
|
+
let referencedIdentifiers = /* @__PURE__ */ new Set();
|
|
220
|
+
programPath.traverse({
|
|
221
|
+
enter(path2) {
|
|
222
|
+
let { node } = path2;
|
|
223
|
+
!t.isIdentifier(node) || path2.isBindingIdentifier() || path2.findParent((p) => p.isImportDeclaration()) || referencedIdentifiers.add(node.name);
|
|
224
|
+
}
|
|
225
|
+
}), programPath.traverse({
|
|
226
|
+
ImportDeclaration(path2) {
|
|
227
|
+
let specifiers = path2.node.specifiers.filter(
|
|
228
|
+
(spec) => referencedIdentifiers.has(spec.local.name)
|
|
229
|
+
);
|
|
230
|
+
specifiers.length === 0 ? path2.remove() : specifiers.length !== path2.node.specifiers.length && (path2.node.specifiers = specifiers);
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// src/plugins/server-only-stub.ts
|
|
236
|
+
import { babelParse as parse2, types as t2 } from "storybook/internal/babel";
|
|
237
|
+
var SERVER_FILE_RE = /\.server\.(?:[mc]?[jt]sx?)$/;
|
|
238
|
+
function serverOnlyStubPlugin(options = {}) {
|
|
239
|
+
let patterns = [SERVER_FILE_RE, ...options.extraPatterns ?? []];
|
|
240
|
+
return {
|
|
241
|
+
name: "storybook:tanstack-react:server-only-stub",
|
|
242
|
+
enforce: "pre",
|
|
243
|
+
transform: {
|
|
244
|
+
filter: {
|
|
245
|
+
id: {
|
|
246
|
+
// The `id` filter is matched against the full resolved id, so the
|
|
247
|
+
// pattern matches both `src/utils/foo.server.ts` and any other
|
|
248
|
+
// `.server.*` file. We additionally re-check inside the handler in
|
|
249
|
+
// case Vite ever changes how filters are applied.
|
|
250
|
+
include: patterns,
|
|
251
|
+
exclude: [/node_modules/]
|
|
252
|
+
}
|
|
253
|
+
},
|
|
254
|
+
handler(code, id) {
|
|
255
|
+
if (!patterns.some((re) => re.test(id)))
|
|
256
|
+
return null;
|
|
257
|
+
let exports = collectExports(code, id);
|
|
258
|
+
return {
|
|
259
|
+
code: buildStubCode(exports, id),
|
|
260
|
+
map: { mappings: "" }
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
function collectExports(code, id) {
|
|
267
|
+
let named = /* @__PURE__ */ new Set(), hasDefault = !1, ast;
|
|
268
|
+
try {
|
|
269
|
+
ast = parse2(code);
|
|
270
|
+
} catch {
|
|
271
|
+
return { named, hasDefault };
|
|
272
|
+
}
|
|
273
|
+
for (let node of ast.program.body) {
|
|
274
|
+
if (t2.isExportDefaultDeclaration(node)) {
|
|
275
|
+
hasDefault = !0;
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
if (!t2.isExportAllDeclaration(node) && t2.isExportNamedDeclaration(node)) {
|
|
279
|
+
let decl = node.declaration;
|
|
280
|
+
if (decl)
|
|
281
|
+
if (t2.isVariableDeclaration(decl))
|
|
282
|
+
for (let declarator of decl.declarations)
|
|
283
|
+
t2.isIdentifier(declarator.id) && named.add(declarator.id.name);
|
|
284
|
+
else (t2.isFunctionDeclaration(decl) || t2.isClassDeclaration(decl)) && decl.id?.name && named.add(decl.id.name);
|
|
285
|
+
for (let spec of node.specifiers)
|
|
286
|
+
if (t2.isExportSpecifier(spec)) {
|
|
287
|
+
let exportedName = t2.isIdentifier(spec.exported) ? spec.exported.name : spec.exported.value;
|
|
288
|
+
exportedName !== "default" ? named.add(exportedName) : hasDefault = !0;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return { named, hasDefault };
|
|
293
|
+
}
|
|
294
|
+
function buildStubCode(exports, id) {
|
|
295
|
+
let label = JSON.stringify(id), namedExports = [...exports.named].map((name) => `export const ${name} = __sb_serverOnly(${JSON.stringify(name)});`).join(`
|
|
296
|
+
`), defaultExport = exports.hasDefault ? "export default __sb_serverOnly('default');" : "";
|
|
297
|
+
return `import { fn as __sb_fn } from 'storybook/test';
|
|
298
|
+
function __sb_serverOnly(name) {
|
|
299
|
+
return __sb_fn(() => {
|
|
300
|
+
throw new Error(
|
|
301
|
+
\`[storybook] Tried to call server-only export "\${name}" from \${${label}} in the browser.\`
|
|
302
|
+
);
|
|
303
|
+
}).mockName(name);
|
|
304
|
+
}
|
|
305
|
+
${namedExports}
|
|
306
|
+
${defaultExport}`.trim();
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// src/plugins/module-interception.ts
|
|
310
|
+
var INTERCEPTED_PATTERNS = ["virtual:cloudflare", "server-entry", "worker-entry"], START_SERVER_MODULES = [
|
|
311
|
+
"@tanstack/react-start",
|
|
312
|
+
"@tanstack/react-start/server",
|
|
313
|
+
"@tanstack/react-start-server",
|
|
314
|
+
"@tanstack/start-server-core"
|
|
315
|
+
];
|
|
316
|
+
function moduleInterceptionPlugin({
|
|
317
|
+
startMockPath,
|
|
318
|
+
startStorageContextMockPath,
|
|
319
|
+
routerMockPath
|
|
320
|
+
}) {
|
|
321
|
+
return {
|
|
322
|
+
name: "storybook:tanstack-react:module-interception",
|
|
323
|
+
enforce: "pre",
|
|
324
|
+
resolveId: {
|
|
325
|
+
order: "pre",
|
|
326
|
+
handler(id, importer) {
|
|
327
|
+
if ((id === "@tanstack/react-router" || id.startsWith("@tanstack/react-router/")) && importer && !importer.includes("export-mocks"))
|
|
328
|
+
return routerMockPath;
|
|
329
|
+
if (START_SERVER_MODULES.includes(id) || id === "@tanstack/react-start")
|
|
330
|
+
return startMockPath;
|
|
331
|
+
if (id === "@tanstack/start-storage-context")
|
|
332
|
+
return startStorageContextMockPath;
|
|
333
|
+
for (let pattern of INTERCEPTED_PATTERNS)
|
|
334
|
+
if (id.includes(pattern))
|
|
335
|
+
return startMockPath;
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
338
|
+
},
|
|
339
|
+
config() {
|
|
340
|
+
return {
|
|
341
|
+
optimizeDeps: {
|
|
342
|
+
exclude: [
|
|
343
|
+
"@storybook/react",
|
|
344
|
+
"@storybook/react/entry-preview",
|
|
345
|
+
"@storybook/react/entry-preview-argtypes",
|
|
346
|
+
"@storybook/react/entry-preview-docs",
|
|
347
|
+
"@storybook/tanstack-react",
|
|
348
|
+
"@tanstack/react-start",
|
|
349
|
+
"@tanstack/react-start/server",
|
|
350
|
+
"@tanstack/react-start-server",
|
|
351
|
+
"@tanstack/start-server-core"
|
|
352
|
+
]
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// src/preset.ts
|
|
360
|
+
var core = async (config, options) => {
|
|
361
|
+
let framework = await options.presets.apply("framework");
|
|
362
|
+
return {
|
|
363
|
+
...config,
|
|
364
|
+
builder: {
|
|
365
|
+
name: fileURLToPath(import.meta.resolve("@storybook/builder-vite")),
|
|
366
|
+
options: typeof framework == "string" ? {} : framework.options.builder || {}
|
|
367
|
+
},
|
|
368
|
+
renderer: fileURLToPath(import.meta.resolve("@storybook/react/preset"))
|
|
369
|
+
};
|
|
370
|
+
}, previewAnnotations = (entry = []) => [
|
|
371
|
+
...entry,
|
|
372
|
+
fileURLToPath(import.meta.resolve("@storybook/tanstack-react/preview"))
|
|
373
|
+
], optimizeViteDeps = [
|
|
374
|
+
"@tanstack/react-store",
|
|
375
|
+
"@tanstack/react-router > @tanstack/react-store",
|
|
376
|
+
"use-sync-external-store/shim/with-selector"
|
|
377
|
+
], viteFinal = async (config, options) => {
|
|
378
|
+
let reactConfig = await reactViteFinal(config, options), isTanStackStartPlugin = (p) => {
|
|
379
|
+
if (Array.isArray(p))
|
|
380
|
+
return p.some(isTanStackStartPlugin);
|
|
381
|
+
let pluginRecord = p;
|
|
382
|
+
return typeof p == "object" && p !== null && "name" in pluginRecord && typeof pluginRecord.name == "string" && (pluginRecord.name.startsWith("tanstack-start") || pluginRecord.name.includes("rsc:"));
|
|
383
|
+
}, startMockPath = fileURLToPath(import.meta.resolve("./export-mocks/start.js")), startStorageContextMockPath = fileURLToPath(
|
|
384
|
+
import.meta.resolve("./export-mocks/start-storage-context.js")
|
|
385
|
+
), routerMockPath = fileURLToPath(
|
|
386
|
+
import.meta.resolve("@storybook/tanstack-react/react-router")
|
|
387
|
+
), plugins = [
|
|
388
|
+
...(reactConfig.plugins ?? []).filter((p) => !isTanStackStartPlugin(p)),
|
|
389
|
+
serverCodeEliminationPlugin({ excludeFiles: [dirname(startMockPath)] }),
|
|
390
|
+
serverOnlyStubPlugin(),
|
|
391
|
+
moduleInterceptionPlugin({ startMockPath, startStorageContextMockPath, routerMockPath })
|
|
392
|
+
];
|
|
393
|
+
return {
|
|
394
|
+
...reactConfig,
|
|
395
|
+
plugins
|
|
396
|
+
};
|
|
397
|
+
};
|
|
398
|
+
export {
|
|
399
|
+
core,
|
|
400
|
+
optimizeViteDeps,
|
|
401
|
+
previewAnnotations,
|
|
402
|
+
viteFinal
|
|
403
|
+
};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { LoaderFunction, Renderer, DecoratorFunction } from 'storybook/internal/types';
|
|
2
|
+
import { applyDecorators as applyDecorators$1 } from '@storybook/react/entry-preview-docs';
|
|
3
|
+
import { Register, AnyRoute, FileRoutesByPath } from '@tanstack/react-router';
|
|
4
|
+
import { RoutesByPath, RouteOptions, ResolveParams, AnyContext } from '@tanstack/router-core';
|
|
5
|
+
import { Decorator } from '@storybook/react';
|
|
6
|
+
|
|
7
|
+
/** Union of every registered full path (e.g. `'/' | '/admin/users' | '/$libraryId/$version'`). */
|
|
8
|
+
type RegisteredFullPath = keyof Register['router']['routesByPath'];
|
|
9
|
+
type IsAppRouteTree<TRoute> = TRoute extends Register['router']['routeTree'] ? true : false;
|
|
10
|
+
type IsRoute<T> = T extends AnyRoute ? true : T extends FileRoutesByPath[keyof FileRoutesByPath] ? true : false;
|
|
11
|
+
type ExtractAllPathsFromFileRoutes<TRoute extends FileRoutesByPath[keyof FileRoutesByPath]['preLoaderRoute'] | AnyRoute> = TRoute['path'];
|
|
12
|
+
type StoryRoutePath<TRoute = undefined> = TRoute extends FileRoutesByPath[keyof FileRoutesByPath] ? ExtractAllPathsFromFileRoutes<TRoute> : keyof FileRoutesByPath | `/${string}`;
|
|
13
|
+
type StoryRouteSearch<TRoute> = IsAppRouteTree<TRoute> extends true ? Record<string, unknown> : TRoute extends FileRoutesByPath[keyof FileRoutesByPath] ? TRoute['preLoaderRoute'] extends {
|
|
14
|
+
types: {
|
|
15
|
+
allSearch: infer A;
|
|
16
|
+
};
|
|
17
|
+
} ? A : never : Record<string, unknown>;
|
|
18
|
+
type StoryRouteFileOptions<TRoute = undefined> = IsRoute<TRoute> extends true ? TRoute extends {
|
|
19
|
+
options: infer O;
|
|
20
|
+
} ? 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'>;
|
|
21
|
+
type CreateStoryRouteOptions<TRoute = undefined> = StoryRouteFileOptions<TRoute> & {
|
|
22
|
+
path?: StoryRoutePath<TRoute>;
|
|
23
|
+
};
|
|
24
|
+
type StoryRouteOptions<TRoute = undefined> = CreateStoryRouteOptions<TRoute> | (TRoute extends AnyRoute ? TRoute : AnyRoute);
|
|
25
|
+
/**
|
|
26
|
+
* Per-route override options for use inside `RouteTreeOverrides`.
|
|
27
|
+
* Users can override `loader`, `beforeLoad`, etc. for a specific route.
|
|
28
|
+
*/
|
|
29
|
+
interface RouteOverrideOptions<TRoute extends FileRoutesByPath[keyof FileRoutesByPath]['preLoaderRoute'] | undefined = undefined> {
|
|
30
|
+
/** Override the route's loader function. */
|
|
31
|
+
loader?: TRoute extends FileRoutesByPath[keyof FileRoutesByPath]['preLoaderRoute'] ? TRoute['options']['loader'] | ((ctx: unknown) => Promise<unknown> | unknown) : (ctx: unknown) => Promise<unknown> | unknown;
|
|
32
|
+
/** Override the route's beforeLoad function. */
|
|
33
|
+
beforeLoad?: TRoute extends FileRoutesByPath[keyof FileRoutesByPath]['preLoaderRoute'] ? TRoute['options']['beforeLoad'] | ((ctx: unknown) => Promise<void> | void) : (ctx: unknown) => Promise<void> | void;
|
|
34
|
+
/** Override the route's search params validation. */
|
|
35
|
+
validateSearch?: TRoute extends FileRoutesByPath[keyof FileRoutesByPath]['preLoaderRoute'] ? TRoute['options']['validateSearch'] | ((search: unknown) => Promise<void> | void) : (search: unknown) => Promise<void> | void;
|
|
36
|
+
/** Override the route's loader dependencies. */
|
|
37
|
+
loaderDeps?: TRoute extends FileRoutesByPath[keyof FileRoutesByPath]['preLoaderRoute'] ? TRoute['options']['loaderDeps'] | string[] : string[];
|
|
38
|
+
/** Override the route's context function. */
|
|
39
|
+
context?: TRoute extends FileRoutesByPath[keyof FileRoutesByPath]['preLoaderRoute'] ? TRoute['options']['context'] | ((ctx: unknown) => Promise<unknown> | unknown) : (ctx: unknown) => Promise<unknown> | unknown;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* A map of route overrides keyed by route ID.
|
|
43
|
+
* Each entry can override `loader`, `beforeLoad`, etc. for that route.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* routeOverrides: {
|
|
48
|
+
* '/_authed': { beforeLoad: () => {} },
|
|
49
|
+
* '/demo/form/simple/$id': {
|
|
50
|
+
* loader: async () => ({ name: 'Mock User' }),
|
|
51
|
+
* },
|
|
52
|
+
* }
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
type RouteTreeOverrides = Partial<{
|
|
56
|
+
[routePath in keyof FileRoutesByPath]: RouteOverrideOptions<FileRoutesByPath[routePath]['preLoaderRoute']> | undefined;
|
|
57
|
+
}>;
|
|
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?: ({ storyContext }: {
|
|
91
|
+
storyContext: Parameters<Decorator>[1];
|
|
92
|
+
}) => AnyContext;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** Path constraint mirroring `RouterParameters`'s second generic. */
|
|
96
|
+
type DefaultStoryPath<TRoute> = TRoute extends AnyRoute ? keyof RoutesByPath<TRoute> : RegisteredFullPath;
|
|
97
|
+
interface TanStackPreviewOptions<TRoute = undefined, Path extends DefaultStoryPath<TRoute> = DefaultStoryPath<TRoute>> {
|
|
98
|
+
/** Router configuration for stories */
|
|
99
|
+
router?: RouterParameters<TRoute, Path>;
|
|
100
|
+
}
|
|
101
|
+
interface TanStackParameters<TRoute = undefined, Path extends DefaultStoryPath<TRoute> = DefaultStoryPath<TRoute>> {
|
|
102
|
+
/** TanStack framework configuration (router integration). */
|
|
103
|
+
tanstack?: TanStackPreviewOptions<TRoute, Path>;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
declare const loaders: LoaderFunction<Renderer>[];
|
|
107
|
+
declare const applyDecorators: (storyFn: Parameters<typeof applyDecorators$1>[0], allDecorators: DecoratorFunction[]) => any;
|
|
108
|
+
declare const parameters: TanStackParameters;
|
|
109
|
+
declare const optimizeDeps: string[];
|
|
110
|
+
|
|
111
|
+
export { applyDecorators, loaders, optimizeDeps, parameters };
|
package/dist/preview.js
ADDED
package/package.json
CHANGED
|
@@ -1,9 +1,112 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@storybook/tanstack-react",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "",
|
|
5
|
-
"keywords": [
|
|
3
|
+
"version": "10.4.0-alpha.18",
|
|
4
|
+
"description": "Storybook for TanStack (React, Vite): Router and Start ready Storybook framework",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"storybook",
|
|
7
|
+
"storybook-framework",
|
|
8
|
+
"tanstack",
|
|
9
|
+
"tanstack-router",
|
|
10
|
+
"tanstack-start",
|
|
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
|
+
},
|
|
6
29
|
"license": "MIT",
|
|
7
|
-
"
|
|
8
|
-
"
|
|
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
|
+
"./start-storage-context": {
|
|
64
|
+
"types": "./dist/export-mocks/start-storage-context.d.ts",
|
|
65
|
+
"code": "./src/export-mocks/start-storage-context.ts",
|
|
66
|
+
"default": "./dist/export-mocks/start-storage-context.js"
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
"files": [
|
|
70
|
+
"dist/**/*",
|
|
71
|
+
"template/**/*",
|
|
72
|
+
"README.md",
|
|
73
|
+
"*.js",
|
|
74
|
+
"*.d.ts",
|
|
75
|
+
"!src/**/*"
|
|
76
|
+
],
|
|
77
|
+
"dependencies": {
|
|
78
|
+
"@storybook/builder-vite": "10.4.0-alpha.18",
|
|
79
|
+
"@storybook/react": "10.4.0-alpha.18",
|
|
80
|
+
"@storybook/react-vite": "10.4.0-alpha.18"
|
|
81
|
+
},
|
|
82
|
+
"devDependencies": {
|
|
83
|
+
"@tanstack/react-router": "^1.168.10",
|
|
84
|
+
"@tanstack/react-start": "^1.167.16",
|
|
85
|
+
"@tanstack/router-core": "^1.168.9",
|
|
86
|
+
"@tanstack/start-client-core": "^1.167.9",
|
|
87
|
+
"@types/node": "^22.19.1",
|
|
88
|
+
"typescript": "^5.9.3",
|
|
89
|
+
"vite": "^7.0.4"
|
|
90
|
+
},
|
|
91
|
+
"peerDependencies": {
|
|
92
|
+
"@tanstack/react-router": "^1.168.10",
|
|
93
|
+
"@tanstack/react-start": "^1.167.16",
|
|
94
|
+
"@tanstack/router-core": "^1.168.9",
|
|
95
|
+
"@tanstack/start-client-core": "^1.167.9",
|
|
96
|
+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
|
97
|
+
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
|
98
|
+
"storybook": "^10.4.0-alpha.18",
|
|
99
|
+
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
|
|
100
|
+
},
|
|
101
|
+
"peerDependenciesMeta": {
|
|
102
|
+
"@tanstack/react-start": {
|
|
103
|
+
"optional": true
|
|
104
|
+
},
|
|
105
|
+
"@tanstack/start-client-core": {
|
|
106
|
+
"optional": true
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
"publishConfig": {
|
|
110
|
+
"access": "public"
|
|
111
|
+
}
|
|
9
112
|
}
|