@fluixi/core 1.0.0-alpha.100
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/LICENSE +21 -0
- package/README.md +334 -0
- package/dist/cdn/core.global.js +2 -0
- package/dist/cli/generate.cjs +5639 -0
- package/dist/cli/generate.d.ts +7 -0
- package/dist/cli/generate.d.ts.map +1 -0
- package/dist/cli/generate.js +2580 -0
- package/dist/cli/generate.mjs +5644 -0
- package/dist/cli/index.cjs +5639 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +2580 -0
- package/dist/cli/index.mjs +5644 -0
- package/dist/cli/run.cjs +64 -0
- package/dist/cli/run.d.ts +3 -0
- package/dist/cli/run.d.ts.map +1 -0
- package/dist/cli/run.js +62 -0
- package/dist/cli/run.mjs +40 -0
- package/dist/fluixi.d.ts +5 -0
- package/dist/src/cdn/chunk-RKBFEFZP.mjs +987 -0
- package/dist/src/cdn/core.cjs +1592 -0
- package/dist/src/cdn/core.d.ts +16 -0
- package/dist/src/cdn/core.d.ts.map +1 -0
- package/dist/src/cdn/core.js +15 -0
- package/dist/src/cdn/core.mjs +714 -0
- package/dist/src/cdn/router-V2THK27H.mjs +74 -0
- package/dist/src/index.cjs +1711 -0
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +11 -0
- package/dist/src/index.mjs +1833 -0
- package/dist/src/jsx-dev-runtime.cjs +26 -0
- package/dist/src/jsx-dev-runtime.d.ts +2 -0
- package/dist/src/jsx-dev-runtime.d.ts.map +1 -0
- package/dist/src/jsx-dev-runtime.js +1 -0
- package/dist/src/jsx-dev-runtime.mjs +24 -0
- package/dist/src/jsx-runtime.cjs +26 -0
- package/dist/src/jsx-runtime.d.ts +7 -0
- package/dist/src/jsx-runtime.d.ts.map +1 -0
- package/dist/src/jsx-runtime.js +8 -0
- package/dist/src/jsx-runtime.mjs +24 -0
- package/dist/src/lib/client/chunk-FDOPDB6Z.mjs +53 -0
- package/dist/src/lib/client/index.cjs +1210 -0
- package/dist/src/lib/client/index.d.ts +51 -0
- package/dist/src/lib/client/index.d.ts.map +1 -0
- package/dist/src/lib/client/index.js +174 -0
- package/dist/src/lib/client/index.mjs +293 -0
- package/dist/src/lib/client/router-4PTBPZLQ.mjs +891 -0
- package/dist/src/lib/context/context.cjs +81 -0
- package/dist/src/lib/context/context.d.ts +73 -0
- package/dist/src/lib/context/context.d.ts.map +1 -0
- package/dist/src/lib/context/context.js +93 -0
- package/dist/src/lib/context/context.mjs +64 -0
- package/dist/src/lib/context/index.cjs +83 -0
- package/dist/src/lib/context/index.d.ts +3 -0
- package/dist/src/lib/context/index.d.ts.map +1 -0
- package/dist/src/lib/context/index.js +1 -0
- package/dist/src/lib/context/index.mjs +64 -0
- package/dist/src/lib/control-flow.cjs +35 -0
- package/dist/src/lib/control-flow.d.ts +4 -0
- package/dist/src/lib/control-flow.d.ts.map +1 -0
- package/dist/src/lib/control-flow.js +1 -0
- package/dist/src/lib/control-flow.mjs +25 -0
- package/dist/src/lib/core.cjs +1710 -0
- package/dist/src/lib/core.d.ts +91 -0
- package/dist/src/lib/core.d.ts.map +1 -0
- package/dist/src/lib/core.js +158 -0
- package/dist/src/lib/core.mjs +1833 -0
- package/dist/src/lib/env/index.cjs +44 -0
- package/dist/src/lib/env/index.d.ts +26 -0
- package/dist/src/lib/env/index.d.ts.map +1 -0
- package/dist/src/lib/env/index.js +31 -0
- package/dist/src/lib/env/index.mjs +23 -0
- package/dist/src/lib/i18n/index.cjs +123 -0
- package/dist/src/lib/i18n/index.d.ts +110 -0
- package/dist/src/lib/i18n/index.d.ts.map +1 -0
- package/dist/src/lib/i18n/index.js +164 -0
- package/dist/src/lib/i18n/index.mjs +103 -0
- package/dist/src/lib/index.cjs +598 -0
- package/dist/src/lib/index.d.ts +81 -0
- package/dist/src/lib/index.d.ts.map +1 -0
- package/dist/src/lib/index.js +130 -0
- package/dist/src/lib/index.mjs +688 -0
- package/dist/src/lib/isomorphic.cjs +90 -0
- package/dist/src/lib/isomorphic.d.ts +114 -0
- package/dist/src/lib/isomorphic.d.ts.map +1 -0
- package/dist/src/lib/isomorphic.js +132 -0
- package/dist/src/lib/isomorphic.mjs +69 -0
- package/dist/src/lib/jsx-runtime/index.cjs +21 -0
- package/dist/src/lib/jsx-runtime/index.d.ts +13 -0
- package/dist/src/lib/jsx-runtime/index.d.ts.map +1 -0
- package/dist/src/lib/jsx-runtime/index.js +13 -0
- package/dist/src/lib/jsx-runtime/index.mjs +4 -0
- package/dist/src/lib/jsx-runtime/jsx-dev-runtime.cjs +21 -0
- package/dist/src/lib/jsx-runtime/jsx-dev-runtime.d.ts +2 -0
- package/dist/src/lib/jsx-runtime/jsx-dev-runtime.d.ts.map +1 -0
- package/dist/src/lib/jsx-runtime/jsx-dev-runtime.js +1 -0
- package/dist/src/lib/jsx-runtime/jsx-dev-runtime.mjs +4 -0
- package/dist/src/lib/plugins/fluixi-routes-plugin.cjs +302 -0
- package/dist/src/lib/plugins/fluixi-routes-plugin.d.ts +35 -0
- package/dist/src/lib/plugins/fluixi-routes-plugin.d.ts.map +1 -0
- package/dist/src/lib/plugins/fluixi-routes-plugin.js +118 -0
- package/dist/src/lib/plugins/fluixi-routes-plugin.mjs +271 -0
- package/dist/src/lib/plugins/index.cjs +311 -0
- package/dist/src/lib/plugins/index.d.ts +6 -0
- package/dist/src/lib/plugins/index.d.ts.map +1 -0
- package/dist/src/lib/plugins/index.js +7 -0
- package/dist/src/lib/plugins/index.mjs +279 -0
- package/dist/src/lib/plugins/route-codegen.cjs +73 -0
- package/dist/src/lib/plugins/route-codegen.d.ts +12 -0
- package/dist/src/lib/plugins/route-codegen.d.ts.map +1 -0
- package/dist/src/lib/plugins/route-codegen.js +80 -0
- package/dist/src/lib/plugins/route-codegen.mjs +52 -0
- package/dist/src/lib/plugins/route-scanner.cjs +189 -0
- package/dist/src/lib/plugins/route-scanner.d.ts +38 -0
- package/dist/src/lib/plugins/route-scanner.d.ts.map +1 -0
- package/dist/src/lib/plugins/route-scanner.js +215 -0
- package/dist/src/lib/plugins/route-scanner.mjs +158 -0
- package/dist/src/lib/plugins/vite.cjs +27 -0
- package/dist/src/lib/plugins/vite.d.ts +3 -0
- package/dist/src/lib/plugins/vite.d.ts.map +1 -0
- package/dist/src/lib/plugins/vite.js +1 -0
- package/dist/src/lib/plugins/vite.mjs +6 -0
- package/dist/src/lib/render/await.cjs +38 -0
- package/dist/src/lib/render/await.d.ts +26 -0
- package/dist/src/lib/render/await.d.ts.map +1 -0
- package/dist/src/lib/render/await.js +45 -0
- package/dist/src/lib/render/await.mjs +17 -0
- package/dist/src/lib/render/component.cjs +221 -0
- package/dist/src/lib/render/component.d.ts +296 -0
- package/dist/src/lib/render/component.d.ts.map +1 -0
- package/dist/src/lib/render/component.js +514 -0
- package/dist/src/lib/render/component.mjs +214 -0
- package/dist/src/lib/render/deferred.cjs +175 -0
- package/dist/src/lib/render/deferred.d.ts +36 -0
- package/dist/src/lib/render/deferred.d.ts.map +1 -0
- package/dist/src/lib/render/deferred.js +141 -0
- package/dist/src/lib/render/deferred.mjs +158 -0
- package/dist/src/lib/render/index.cjs +573 -0
- package/dist/src/lib/render/index.d.ts +98 -0
- package/dist/src/lib/render/index.d.ts.map +1 -0
- package/dist/src/lib/render/index.js +180 -0
- package/dist/src/lib/render/index.mjs +590 -0
- package/dist/src/lib/render/lazy.cjs +67 -0
- package/dist/src/lib/render/lazy.d.ts +49 -0
- package/dist/src/lib/render/lazy.d.ts.map +1 -0
- package/dist/src/lib/render/lazy.js +105 -0
- package/dist/src/lib/render/lazy.mjs +50 -0
- package/dist/src/lib/render/suspense.cjs +141 -0
- package/dist/src/lib/render/suspense.d.ts +65 -0
- package/dist/src/lib/render/suspense.d.ts.map +1 -0
- package/dist/src/lib/render/suspense.js +196 -0
- package/dist/src/lib/render/suspense.mjs +136 -0
- package/dist/src/lib/render/versions.cjs +35 -0
- package/dist/src/lib/render/versions.d.ts +2 -0
- package/dist/src/lib/render/versions.d.ts.map +1 -0
- package/dist/src/lib/render/versions.js +21 -0
- package/dist/src/lib/render/versions.mjs +14 -0
- package/dist/src/lib/router/data.cjs +228 -0
- package/dist/src/lib/router/data.d.ts +142 -0
- package/dist/src/lib/router/data.d.ts.map +1 -0
- package/dist/src/lib/router/data.js +258 -0
- package/dist/src/lib/router/data.mjs +214 -0
- package/dist/src/lib/router/index.cjs +921 -0
- package/dist/src/lib/router/index.d.ts +274 -0
- package/dist/src/lib/router/index.d.ts.map +1 -0
- package/dist/src/lib/router/index.js +904 -0
- package/dist/src/lib/router/index.mjs +938 -0
- package/dist/src/lib/router/scroll.cjs +79 -0
- package/dist/src/lib/router/scroll.d.ts +19 -0
- package/dist/src/lib/router/scroll.d.ts.map +1 -0
- package/dist/src/lib/router/scroll.js +68 -0
- package/dist/src/lib/router/scroll.mjs +58 -0
- package/dist/src/lib/router/transition.cjs +75 -0
- package/dist/src/lib/router/transition.d.ts +81 -0
- package/dist/src/lib/router/transition.d.ts.map +1 -0
- package/dist/src/lib/router/transition.js +136 -0
- package/dist/src/lib/router/transition.mjs +54 -0
- package/dist/src/lib/server/hydration.cjs +169 -0
- package/dist/src/lib/server/hydration.d.ts +198 -0
- package/dist/src/lib/server/hydration.d.ts.map +1 -0
- package/dist/src/lib/server/hydration.js +345 -0
- package/dist/src/lib/server/hydration.mjs +148 -0
- package/dist/src/lib/server/index.cjs +406 -0
- package/dist/src/lib/server/index.d.ts +115 -0
- package/dist/src/lib/server/index.d.ts.map +1 -0
- package/dist/src/lib/server/index.js +164 -0
- package/dist/src/lib/server/index.mjs +384 -0
- package/dist/src/lib/server/reactive.cjs +197 -0
- package/dist/src/lib/server/reactive.d.ts +239 -0
- package/dist/src/lib/server/reactive.d.ts.map +1 -0
- package/dist/src/lib/server/reactive.js +413 -0
- package/dist/src/lib/server/reactive.mjs +176 -0
- package/dist/src/lib/storage/cache.cjs +51 -0
- package/dist/src/lib/storage/cache.d.ts +18 -0
- package/dist/src/lib/storage/cache.d.ts.map +1 -0
- package/dist/src/lib/storage/cache.js +42 -0
- package/dist/src/lib/storage/cache.mjs +30 -0
- package/dist/src/lib/storage/index.cjs +246 -0
- package/dist/src/lib/storage/index.d.ts +83 -0
- package/dist/src/lib/storage/index.d.ts.map +1 -0
- package/dist/src/lib/storage/index.js +179 -0
- package/dist/src/lib/storage/index.mjs +231 -0
- package/dist/src/lib/storage/persisted.cjs +91 -0
- package/dist/src/lib/storage/persisted.d.ts +53 -0
- package/dist/src/lib/storage/persisted.d.ts.map +1 -0
- package/dist/src/lib/storage/persisted.js +75 -0
- package/dist/src/lib/storage/persisted.mjs +70 -0
- package/dist/src/lib/theme/color-scheme.cjs +281 -0
- package/dist/src/lib/theme/color-scheme.d.ts +61 -0
- package/dist/src/lib/theme/color-scheme.d.ts.map +1 -0
- package/dist/src/lib/theme/color-scheme.js +120 -0
- package/dist/src/lib/theme/color-scheme.mjs +265 -0
- package/dist/src/lib/theme/index.cjs +267 -0
- package/dist/src/lib/theme/index.d.ts +78 -0
- package/dist/src/lib/theme/index.d.ts.map +1 -0
- package/dist/src/lib/theme/index.js +135 -0
- package/dist/src/lib/theme/index.mjs +251 -0
- package/dist/src/lib/theme/provider.cjs +346 -0
- package/dist/src/lib/theme/provider.d.ts +34 -0
- package/dist/src/lib/theme/provider.d.ts.map +1 -0
- package/dist/src/lib/theme/provider.js +60 -0
- package/dist/src/lib/theme/provider.mjs +332 -0
- package/dist/src/lib/utils/index.cjs +209 -0
- package/dist/src/lib/utils/index.d.ts +286 -0
- package/dist/src/lib/utils/index.d.ts.map +1 -0
- package/dist/src/lib/utils/index.js +434 -0
- package/dist/src/lib/utils/index.mjs +188 -0
- package/dist/src/routes.cjs +37 -0
- package/dist/src/routes.d.ts +22 -0
- package/dist/src/routes.d.ts.map +1 -0
- package/dist/src/routes.js +20 -0
- package/dist/src/routes.mjs +17 -0
- package/dist/src/server.cjs +405 -0
- package/dist/src/server.d.ts +63 -0
- package/dist/src/server.d.ts.map +1 -0
- package/dist/src/server.js +62 -0
- package/dist/src/server.mjs +382 -0
- package/dist/src/utils.cjs +21 -0
- package/dist/src/utils.d.ts +10 -0
- package/dist/src/utils.d.ts.map +1 -0
- package/dist/src/utils.js +9 -0
- package/dist/src/utils.mjs +4 -0
- package/dist/src/version.generated.cjs +26 -0
- package/dist/src/version.generated.d.ts +3 -0
- package/dist/src/version.generated.d.ts.map +1 -0
- package/dist/src/version.generated.js +3 -0
- package/dist/src/version.generated.mjs +5 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -0
- package/package.json +164 -0
- package/src/index.ts +19 -0
- package/types/fluixi.d.ts +5 -0
- package/types/vinxi.d.ts +50 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @fluixi/core/plugins/route-scanner
|
|
3
|
+
*
|
|
4
|
+
* Scans a routes directory and builds a route tree following SolidStart conventions.
|
|
5
|
+
* Pure utility, no bundler dependency.
|
|
6
|
+
*/
|
|
7
|
+
export interface ScannedRoute {
|
|
8
|
+
/** Relative file path from routes dir: 'users/[id].tsx' */
|
|
9
|
+
filePath: string;
|
|
10
|
+
/** URL segment for this route: ':id', 'about', '' (index) */
|
|
11
|
+
urlSegment: string;
|
|
12
|
+
/** Full URL path: '/users/:id' */
|
|
13
|
+
urlPath: string;
|
|
14
|
+
/** Whether this is a layout file (layout.tsx) */
|
|
15
|
+
isLayout: boolean;
|
|
16
|
+
/** Whether this is an index file (index.tsx) */
|
|
17
|
+
isIndex: boolean;
|
|
18
|
+
/** Whether this has dynamic params ([id]) */
|
|
19
|
+
isDynamic: boolean;
|
|
20
|
+
/** Whether this is a catch-all ([...rest]) */
|
|
21
|
+
isCatchAll: boolean;
|
|
22
|
+
/** Whether the parent directory is a route group ((name)) */
|
|
23
|
+
isGroup: boolean;
|
|
24
|
+
/** Nested child routes */
|
|
25
|
+
children: ScannedRoute[];
|
|
26
|
+
parentUrlPath: string;
|
|
27
|
+
/** Whether this route file exports a `routeData` function */
|
|
28
|
+
hasRouteData: boolean;
|
|
29
|
+
}
|
|
30
|
+
export interface ScanOptions {
|
|
31
|
+
/** File extensions to include */
|
|
32
|
+
extensions?: string[];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Scan a routes directory and return a tree of ScannedRoute nodes.
|
|
36
|
+
*/
|
|
37
|
+
export declare function scanRoutes(routesDir: string, options?: ScanOptions): ScannedRoute[];
|
|
38
|
+
//# sourceMappingURL=route-scanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-scanner.d.ts","sourceRoot":"","sources":["../../../../src/lib/plugins/route-scanner.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,MAAM,WAAW,YAAY;IAC3B,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAC;IACnB,kCAAkC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,iDAAiD;IACjD,QAAQ,EAAE,OAAO,CAAC;IAClB,gDAAgD;IAChD,OAAO,EAAE,OAAO,CAAC;IACjB,6CAA6C;IAC7C,SAAS,EAAE,OAAO,CAAC;IACnB,8CAA8C;IAC9C,UAAU,EAAE,OAAO,CAAC;IACpB,6DAA6D;IAC7D,OAAO,EAAE,OAAO,CAAC;IACjB,0BAA0B;IAC1B,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,6DAA6D;IAC7D,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,iCAAiC;IACjC,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAQD;;GAEG;AACH,wBAAgB,UAAU,CACxB,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,WAAgB,GACxB,YAAY,EAAE,CAShB"}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @fluixi/core/plugins/route-scanner
|
|
3
|
+
*
|
|
4
|
+
* Scans a routes directory and builds a route tree following SolidStart conventions.
|
|
5
|
+
* Pure utility, no bundler dependency.
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from 'fs';
|
|
8
|
+
import * as path from 'path';
|
|
9
|
+
const DEFAULT_EXTENSIONS = ['.tsx', '.ts', '.jsx', '.js'];
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// SCANNING
|
|
12
|
+
// ============================================================================
|
|
13
|
+
/**
|
|
14
|
+
* Scan a routes directory and return a tree of ScannedRoute nodes.
|
|
15
|
+
*/
|
|
16
|
+
export function scanRoutes(routesDir, options = {}) {
|
|
17
|
+
const extensions = options.extensions ?? DEFAULT_EXTENSIONS;
|
|
18
|
+
const absDir = path.resolve(routesDir);
|
|
19
|
+
if (!fs.existsSync(absDir)) {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
return scanDirectory(absDir, absDir, '', extensions);
|
|
23
|
+
}
|
|
24
|
+
function scanDirectory(dir, rootDir, parentUrlPath, extensions) {
|
|
25
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
26
|
+
const routes = [];
|
|
27
|
+
const layoutRoute = null;
|
|
28
|
+
// Separate files and directories
|
|
29
|
+
const files = [];
|
|
30
|
+
const dirs = [];
|
|
31
|
+
for (const entry of entries) {
|
|
32
|
+
if (entry.isDirectory()) {
|
|
33
|
+
dirs.push(entry);
|
|
34
|
+
}
|
|
35
|
+
else if (entry.isFile() && hasValidExtension(entry.name, extensions)) {
|
|
36
|
+
files.push(entry);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// Find layout file first
|
|
40
|
+
let layout;
|
|
41
|
+
const nonLayoutFiles = [];
|
|
42
|
+
for (const file of files) {
|
|
43
|
+
const baseName = stripExtension(file.name);
|
|
44
|
+
if (baseName === 'layout') {
|
|
45
|
+
layout = buildFileRoute(file.name, dir, rootDir, parentUrlPath, true);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
nonLayoutFiles.push(file);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// Build routes for non-layout files
|
|
52
|
+
const fileRoutes = [];
|
|
53
|
+
for (const file of nonLayoutFiles) {
|
|
54
|
+
fileRoutes.push(buildFileRoute(file.name, dir, rootDir, parentUrlPath, false));
|
|
55
|
+
}
|
|
56
|
+
// Build routes for subdirectories
|
|
57
|
+
const dirRoutes = [];
|
|
58
|
+
for (const d of dirs) {
|
|
59
|
+
const dirName = d.name;
|
|
60
|
+
const isGroup = isRouteGroup(dirName);
|
|
61
|
+
const segment = isGroup ? '' : dirNameToSegment(dirName);
|
|
62
|
+
const childUrlPath = segment
|
|
63
|
+
? joinUrlPath(parentUrlPath, segment)
|
|
64
|
+
: parentUrlPath;
|
|
65
|
+
const children = scanDirectory(path.join(dir, dirName), rootDir, childUrlPath, extensions);
|
|
66
|
+
if (isGroup) {
|
|
67
|
+
// Route groups: children are flattened to parent level
|
|
68
|
+
dirRoutes.push(...children);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
// Regular directory: becomes a nested route
|
|
72
|
+
// If there's a DIRECT layout in the children (urlPath matches this dir's path),
|
|
73
|
+
// it becomes the parent route. We must not pick up layouts from deeper descendants
|
|
74
|
+
// (e.g. campaigns/[id]/workspace/layout.tsx must not be the layout for campaigns/).
|
|
75
|
+
const childLayout = children.find((c) => c.isLayout && c.urlPath === childUrlPath);
|
|
76
|
+
const childNonLayout = children.filter((c) => !c.isLayout || c.urlPath !== childUrlPath);
|
|
77
|
+
if (childLayout) {
|
|
78
|
+
// Preserve children from recursive scan, add any non-layout siblings
|
|
79
|
+
childLayout.children = [...childLayout.children, ...childNonLayout];
|
|
80
|
+
dirRoutes.push(childLayout);
|
|
81
|
+
}
|
|
82
|
+
else if (childNonLayout.length > 0) {
|
|
83
|
+
// No layout, just add children with their full paths
|
|
84
|
+
dirRoutes.push(...childNonLayout);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// Combine: if there's a layout at this level, nest everything under it
|
|
89
|
+
if (layout) {
|
|
90
|
+
layout.children = [...fileRoutes, ...dirRoutes];
|
|
91
|
+
routes.push(layout);
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
routes.push(...fileRoutes, ...dirRoutes);
|
|
95
|
+
}
|
|
96
|
+
// Sort: static routes first, then dynamic, then catch-all
|
|
97
|
+
return sortRoutes(routes);
|
|
98
|
+
}
|
|
99
|
+
// ============================================================================
|
|
100
|
+
// ROUTE BUILDING
|
|
101
|
+
// ============================================================================
|
|
102
|
+
function buildFileRoute(fileName, dir, rootDir, parentUrlPath, isLayout) {
|
|
103
|
+
const baseName = stripExtension(fileName);
|
|
104
|
+
const filePath = path.relative(rootDir, path.join(dir, fileName));
|
|
105
|
+
const isIndex = baseName === 'index';
|
|
106
|
+
const isCatchAll = baseName.startsWith('[...');
|
|
107
|
+
const isDynamic = !isCatchAll && baseName.startsWith('[') && baseName.endsWith(']');
|
|
108
|
+
let urlSegment;
|
|
109
|
+
if (isLayout) {
|
|
110
|
+
urlSegment = '';
|
|
111
|
+
}
|
|
112
|
+
else if (isIndex) {
|
|
113
|
+
urlSegment = '/';
|
|
114
|
+
}
|
|
115
|
+
else if (isCatchAll) {
|
|
116
|
+
// [...rest] -> *rest
|
|
117
|
+
const paramName = baseName.slice(4, -1); // remove '[...' and ']'
|
|
118
|
+
urlSegment = `*${paramName}`;
|
|
119
|
+
}
|
|
120
|
+
else if (isDynamic) {
|
|
121
|
+
// [id] -> :id
|
|
122
|
+
const paramName = baseName.slice(1, -1); // remove '[' and ']'
|
|
123
|
+
urlSegment = `:${paramName}`;
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
urlSegment = baseName;
|
|
127
|
+
}
|
|
128
|
+
const urlPath = isLayout
|
|
129
|
+
? parentUrlPath || '/'
|
|
130
|
+
: isIndex
|
|
131
|
+
? parentUrlPath || '/'
|
|
132
|
+
: joinUrlPath(parentUrlPath, urlSegment);
|
|
133
|
+
// Detect if the file exports a `routeData` function (static analysis at scan time)
|
|
134
|
+
const absoluteFilePath = path.join(dir, fileName);
|
|
135
|
+
let hasRouteData = false;
|
|
136
|
+
try {
|
|
137
|
+
const content = fs.readFileSync(absoluteFilePath, 'utf-8');
|
|
138
|
+
hasRouteData = /export\s+(const|function|async\s+function)\s+routeData\b/.test(content);
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
// If file can't be read, assume no routeData
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
filePath: filePath.replace(/\\/g, '/'), // normalize to forward slashes
|
|
145
|
+
urlSegment,
|
|
146
|
+
urlPath,
|
|
147
|
+
isLayout,
|
|
148
|
+
isIndex,
|
|
149
|
+
isDynamic,
|
|
150
|
+
isCatchAll,
|
|
151
|
+
isGroup: false,
|
|
152
|
+
children: [],
|
|
153
|
+
parentUrlPath,
|
|
154
|
+
hasRouteData,
|
|
155
|
+
rootDir,
|
|
156
|
+
dir
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
// ============================================================================
|
|
160
|
+
// UTILITIES
|
|
161
|
+
// ============================================================================
|
|
162
|
+
function hasValidExtension(fileName, extensions) {
|
|
163
|
+
return extensions.some((ext) => fileName.endsWith(ext));
|
|
164
|
+
}
|
|
165
|
+
function stripExtension(fileName) {
|
|
166
|
+
const lastDot = fileName.lastIndexOf('.');
|
|
167
|
+
return lastDot > 0 ? fileName.slice(0, lastDot) : fileName;
|
|
168
|
+
}
|
|
169
|
+
function isRouteGroup(dirName) {
|
|
170
|
+
return dirName.startsWith('(') && dirName.endsWith(')');
|
|
171
|
+
}
|
|
172
|
+
/** Convert a directory name to its URL segment, matching the same rules as file names. */
|
|
173
|
+
function dirNameToSegment(dirName) {
|
|
174
|
+
if (dirName.startsWith('[...') && dirName.endsWith(']')) {
|
|
175
|
+
return '*' + dirName.slice(4, -1); // [...rest] -> *rest
|
|
176
|
+
}
|
|
177
|
+
if (dirName.startsWith('[') && dirName.endsWith(']')) {
|
|
178
|
+
return ':' + dirName.slice(1, -1); // [id] -> :id
|
|
179
|
+
}
|
|
180
|
+
return dirName;
|
|
181
|
+
}
|
|
182
|
+
function joinUrlPath(parent, segment) {
|
|
183
|
+
const base = parent.endsWith('/') ? parent : parent + '/';
|
|
184
|
+
return base + segment;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Sort routes by specificity: static > dynamic > catch-all.
|
|
188
|
+
* Index routes come before non-index at the same level.
|
|
189
|
+
*/
|
|
190
|
+
function sortRoutes(routes) {
|
|
191
|
+
return routes.sort((a, b) => {
|
|
192
|
+
// Layouts first (they wrap children)
|
|
193
|
+
if (a.isLayout && !b.isLayout)
|
|
194
|
+
return -1;
|
|
195
|
+
if (!a.isLayout && b.isLayout)
|
|
196
|
+
return 1;
|
|
197
|
+
// Index routes before others
|
|
198
|
+
if (a.isIndex && !b.isIndex)
|
|
199
|
+
return -1;
|
|
200
|
+
if (!a.isIndex && b.isIndex)
|
|
201
|
+
return 1;
|
|
202
|
+
// Static before dynamic
|
|
203
|
+
if (!a.isDynamic && !a.isCatchAll && (b.isDynamic || b.isCatchAll))
|
|
204
|
+
return -1;
|
|
205
|
+
if ((a.isDynamic || a.isCatchAll) && !b.isDynamic && !b.isCatchAll)
|
|
206
|
+
return 1;
|
|
207
|
+
// Dynamic before catch-all
|
|
208
|
+
if (a.isDynamic && b.isCatchAll)
|
|
209
|
+
return -1;
|
|
210
|
+
if (a.isCatchAll && b.isDynamic)
|
|
211
|
+
return 1;
|
|
212
|
+
// Alphabetical fallback
|
|
213
|
+
return a.urlSegment.localeCompare(b.urlSegment);
|
|
214
|
+
});
|
|
215
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
// src/lib/plugins/route-scanner.ts
|
|
2
|
+
import * as fs from "fs";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
var DEFAULT_EXTENSIONS = [".tsx", ".ts", ".jsx", ".js"];
|
|
5
|
+
function scanRoutes(routesDir, options = {}) {
|
|
6
|
+
const extensions = options.extensions ?? DEFAULT_EXTENSIONS;
|
|
7
|
+
const absDir = path.resolve(routesDir);
|
|
8
|
+
if (!fs.existsSync(absDir)) {
|
|
9
|
+
return [];
|
|
10
|
+
}
|
|
11
|
+
return scanDirectory(absDir, absDir, "", extensions);
|
|
12
|
+
}
|
|
13
|
+
function scanDirectory(dir, rootDir, parentUrlPath, extensions) {
|
|
14
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
15
|
+
const routes = [];
|
|
16
|
+
const layoutRoute = null;
|
|
17
|
+
const files = [];
|
|
18
|
+
const dirs = [];
|
|
19
|
+
for (const entry of entries) {
|
|
20
|
+
if (entry.isDirectory()) {
|
|
21
|
+
dirs.push(entry);
|
|
22
|
+
} else if (entry.isFile() && hasValidExtension(entry.name, extensions)) {
|
|
23
|
+
files.push(entry);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
let layout;
|
|
27
|
+
const nonLayoutFiles = [];
|
|
28
|
+
for (const file of files) {
|
|
29
|
+
const baseName = stripExtension(file.name);
|
|
30
|
+
if (baseName === "layout") {
|
|
31
|
+
layout = buildFileRoute(file.name, dir, rootDir, parentUrlPath, true);
|
|
32
|
+
} else {
|
|
33
|
+
nonLayoutFiles.push(file);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const fileRoutes = [];
|
|
37
|
+
for (const file of nonLayoutFiles) {
|
|
38
|
+
fileRoutes.push(
|
|
39
|
+
buildFileRoute(file.name, dir, rootDir, parentUrlPath, false)
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
const dirRoutes = [];
|
|
43
|
+
for (const d of dirs) {
|
|
44
|
+
const dirName = d.name;
|
|
45
|
+
const isGroup = isRouteGroup(dirName);
|
|
46
|
+
const segment = isGroup ? "" : dirNameToSegment(dirName);
|
|
47
|
+
const childUrlPath = segment ? joinUrlPath(parentUrlPath, segment) : parentUrlPath;
|
|
48
|
+
const children = scanDirectory(
|
|
49
|
+
path.join(dir, dirName),
|
|
50
|
+
rootDir,
|
|
51
|
+
childUrlPath,
|
|
52
|
+
extensions
|
|
53
|
+
);
|
|
54
|
+
if (isGroup) {
|
|
55
|
+
dirRoutes.push(...children);
|
|
56
|
+
} else {
|
|
57
|
+
const childLayout = children.find((c) => c.isLayout && c.urlPath === childUrlPath);
|
|
58
|
+
const childNonLayout = children.filter((c) => !c.isLayout || c.urlPath !== childUrlPath);
|
|
59
|
+
if (childLayout) {
|
|
60
|
+
childLayout.children = [...childLayout.children, ...childNonLayout];
|
|
61
|
+
dirRoutes.push(childLayout);
|
|
62
|
+
} else if (childNonLayout.length > 0) {
|
|
63
|
+
dirRoutes.push(...childNonLayout);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (layout) {
|
|
68
|
+
layout.children = [...fileRoutes, ...dirRoutes];
|
|
69
|
+
routes.push(layout);
|
|
70
|
+
} else {
|
|
71
|
+
routes.push(...fileRoutes, ...dirRoutes);
|
|
72
|
+
}
|
|
73
|
+
return sortRoutes(routes);
|
|
74
|
+
}
|
|
75
|
+
function buildFileRoute(fileName, dir, rootDir, parentUrlPath, isLayout) {
|
|
76
|
+
const baseName = stripExtension(fileName);
|
|
77
|
+
const filePath = path.relative(rootDir, path.join(dir, fileName));
|
|
78
|
+
const isIndex = baseName === "index";
|
|
79
|
+
const isCatchAll = baseName.startsWith("[...");
|
|
80
|
+
const isDynamic = !isCatchAll && baseName.startsWith("[") && baseName.endsWith("]");
|
|
81
|
+
let urlSegment;
|
|
82
|
+
if (isLayout) {
|
|
83
|
+
urlSegment = "";
|
|
84
|
+
} else if (isIndex) {
|
|
85
|
+
urlSegment = "/";
|
|
86
|
+
} else if (isCatchAll) {
|
|
87
|
+
const paramName = baseName.slice(4, -1);
|
|
88
|
+
urlSegment = `*${paramName}`;
|
|
89
|
+
} else if (isDynamic) {
|
|
90
|
+
const paramName = baseName.slice(1, -1);
|
|
91
|
+
urlSegment = `:${paramName}`;
|
|
92
|
+
} else {
|
|
93
|
+
urlSegment = baseName;
|
|
94
|
+
}
|
|
95
|
+
const urlPath = isLayout ? parentUrlPath || "/" : isIndex ? parentUrlPath || "/" : joinUrlPath(parentUrlPath, urlSegment);
|
|
96
|
+
const absoluteFilePath = path.join(dir, fileName);
|
|
97
|
+
let hasRouteData = false;
|
|
98
|
+
try {
|
|
99
|
+
const content = fs.readFileSync(absoluteFilePath, "utf-8");
|
|
100
|
+
hasRouteData = /export\s+(const|function|async\s+function)\s+routeData\b/.test(content);
|
|
101
|
+
} catch {
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
filePath: filePath.replace(/\\/g, "/"),
|
|
105
|
+
// normalize to forward slashes
|
|
106
|
+
urlSegment,
|
|
107
|
+
urlPath,
|
|
108
|
+
isLayout,
|
|
109
|
+
isIndex,
|
|
110
|
+
isDynamic,
|
|
111
|
+
isCatchAll,
|
|
112
|
+
isGroup: false,
|
|
113
|
+
children: [],
|
|
114
|
+
parentUrlPath,
|
|
115
|
+
hasRouteData,
|
|
116
|
+
rootDir,
|
|
117
|
+
dir
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function hasValidExtension(fileName, extensions) {
|
|
121
|
+
return extensions.some((ext) => fileName.endsWith(ext));
|
|
122
|
+
}
|
|
123
|
+
function stripExtension(fileName) {
|
|
124
|
+
const lastDot = fileName.lastIndexOf(".");
|
|
125
|
+
return lastDot > 0 ? fileName.slice(0, lastDot) : fileName;
|
|
126
|
+
}
|
|
127
|
+
function isRouteGroup(dirName) {
|
|
128
|
+
return dirName.startsWith("(") && dirName.endsWith(")");
|
|
129
|
+
}
|
|
130
|
+
function dirNameToSegment(dirName) {
|
|
131
|
+
if (dirName.startsWith("[...") && dirName.endsWith("]")) {
|
|
132
|
+
return "*" + dirName.slice(4, -1);
|
|
133
|
+
}
|
|
134
|
+
if (dirName.startsWith("[") && dirName.endsWith("]")) {
|
|
135
|
+
return ":" + dirName.slice(1, -1);
|
|
136
|
+
}
|
|
137
|
+
return dirName;
|
|
138
|
+
}
|
|
139
|
+
function joinUrlPath(parent, segment) {
|
|
140
|
+
const base = parent.endsWith("/") ? parent : parent + "/";
|
|
141
|
+
return base + segment;
|
|
142
|
+
}
|
|
143
|
+
function sortRoutes(routes) {
|
|
144
|
+
return routes.sort((a, b) => {
|
|
145
|
+
if (a.isLayout && !b.isLayout) return -1;
|
|
146
|
+
if (!a.isLayout && b.isLayout) return 1;
|
|
147
|
+
if (a.isIndex && !b.isIndex) return -1;
|
|
148
|
+
if (!a.isIndex && b.isIndex) return 1;
|
|
149
|
+
if (!a.isDynamic && !a.isCatchAll && (b.isDynamic || b.isCatchAll)) return -1;
|
|
150
|
+
if ((a.isDynamic || a.isCatchAll) && !b.isDynamic && !b.isCatchAll) return 1;
|
|
151
|
+
if (a.isDynamic && b.isCatchAll) return -1;
|
|
152
|
+
if (a.isCatchAll && b.isDynamic) return 1;
|
|
153
|
+
return a.urlSegment.localeCompare(b.urlSegment);
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
export {
|
|
157
|
+
scanRoutes
|
|
158
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/lib/plugins/vite.ts
|
|
21
|
+
var vite_exports = {};
|
|
22
|
+
__export(vite_exports, {
|
|
23
|
+
createVitePlugin: () => import_vite_plugin.createVitePlugin,
|
|
24
|
+
fluixi: () => import_vite_plugin.fluixi
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(vite_exports);
|
|
27
|
+
var import_vite_plugin = require("@fluixi/vite-plugin");
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vite.d.ts","sourceRoot":"","sources":["../../../../src/lib/plugins/vite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,YAAY,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { fluixi, createVitePlugin } from '@fluixi/vite-plugin';
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/lib/render/await.ts
|
|
21
|
+
var await_exports = {};
|
|
22
|
+
__export(await_exports, {
|
|
23
|
+
Await: () => Await
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(await_exports);
|
|
26
|
+
var import_signal = require("@fluixi/reactive/signal");
|
|
27
|
+
function Await(props) {
|
|
28
|
+
const fetcher = () => {
|
|
29
|
+
const v = props.value;
|
|
30
|
+
return typeof v === "function" ? v() : v;
|
|
31
|
+
};
|
|
32
|
+
const [data] = (0, import_signal.createResource)(fetcher);
|
|
33
|
+
return () => {
|
|
34
|
+
if (data.loading) return props.fallback;
|
|
35
|
+
const child = props.children;
|
|
36
|
+
return typeof child === "function" ? child(data()) : child;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface AwaitProps<T> {
|
|
2
|
+
value: Promise<T> | (() => Promise<T>);
|
|
3
|
+
fallback?: unknown;
|
|
4
|
+
/** Render prop called with the resolved value (or plain children). */
|
|
5
|
+
children?: ((value: T) => unknown) | unknown;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Render the result of a promise, with a fallback while it is pending.
|
|
9
|
+
*
|
|
10
|
+
* `value` may be a promise or a function returning one. Pass a function when the promise
|
|
11
|
+
* should be created by the component rather than by whoever wrote the tag, which is what
|
|
12
|
+
* keeps a re-render from firing the request again.
|
|
13
|
+
*
|
|
14
|
+
* `children` is either a render prop called with the resolved value, or plain children
|
|
15
|
+
* that ignore it.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* html`
|
|
20
|
+
* <${Await} value=${() => fetchUser(id)} fallback=${html`<p>loading...</p>`}>
|
|
21
|
+
* ${(user) => html`<h1>${user.name}</h1>`}
|
|
22
|
+
* </${Await}>`;
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare function Await<T>(props: AwaitProps<T>): () => unknown;
|
|
26
|
+
//# sourceMappingURL=await.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"await.d.ts","sourceRoot":"","sources":["../../../../src/lib/render/await.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,GAAG,OAAO,CAAC;CAC9C;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,MAAM,OAAO,CAW5D"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `<Await value=${promise}>`: resolve a promise and render its value.
|
|
3
|
+
*
|
|
4
|
+
* A thin, Suspense-free helper for the common "await one promise" case:
|
|
5
|
+
*
|
|
6
|
+
* <Await value=${fetchUser(id)} fallback=${html`<p>loading...</p>`}>
|
|
7
|
+
* ${(user) => html`<span>${user.name}</span>`}
|
|
8
|
+
* </Await>
|
|
9
|
+
*
|
|
10
|
+
* `value` is a promise (or a function returning one). While pending it renders
|
|
11
|
+
* `fallback`; once resolved it calls the render-prop child with the value. The
|
|
12
|
+
* resource read is guarded by `.loading`, so it never throws/suspends.
|
|
13
|
+
*/
|
|
14
|
+
import { createResource } from '@fluixi/reactive/signal';
|
|
15
|
+
/**
|
|
16
|
+
* Render the result of a promise, with a fallback while it is pending.
|
|
17
|
+
*
|
|
18
|
+
* `value` may be a promise or a function returning one. Pass a function when the promise
|
|
19
|
+
* should be created by the component rather than by whoever wrote the tag, which is what
|
|
20
|
+
* keeps a re-render from firing the request again.
|
|
21
|
+
*
|
|
22
|
+
* `children` is either a render prop called with the resolved value, or plain children
|
|
23
|
+
* that ignore it.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* html`
|
|
28
|
+
* <${Await} value=${() => fetchUser(id)} fallback=${html`<p>loading...</p>`}>
|
|
29
|
+
* ${(user) => html`<h1>${user.name}</h1>`}
|
|
30
|
+
* </${Await}>`;
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export function Await(props) {
|
|
34
|
+
const fetcher = () => {
|
|
35
|
+
const v = props.value;
|
|
36
|
+
return typeof v === 'function' ? v() : v;
|
|
37
|
+
};
|
|
38
|
+
const [data] = createResource(fetcher);
|
|
39
|
+
return () => {
|
|
40
|
+
if (data.loading)
|
|
41
|
+
return props.fallback;
|
|
42
|
+
const child = props.children;
|
|
43
|
+
return typeof child === 'function' ? child(data()) : child;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// src/lib/render/await.ts
|
|
2
|
+
import { createResource } from "@fluixi/reactive/signal";
|
|
3
|
+
function Await(props) {
|
|
4
|
+
const fetcher = () => {
|
|
5
|
+
const v = props.value;
|
|
6
|
+
return typeof v === "function" ? v() : v;
|
|
7
|
+
};
|
|
8
|
+
const [data] = createResource(fetcher);
|
|
9
|
+
return () => {
|
|
10
|
+
if (data.loading) return props.fallback;
|
|
11
|
+
const child = props.children;
|
|
12
|
+
return typeof child === "function" ? child(data()) : child;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export {
|
|
16
|
+
Await
|
|
17
|
+
};
|