vista-core-js 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ErrorOverlay.d.ts +7 -0
- package/dist/ErrorOverlay.js +68 -0
- package/dist/app.d.ts +21 -0
- package/dist/app.js +119 -0
- package/dist/client/link.d.ts +23 -0
- package/dist/client/link.js +42 -0
- package/dist/client.d.ts +2 -0
- package/dist/client.js +290 -0
- package/dist/components/PixelBlast.d.ts +28 -0
- package/dist/components/PixelBlast.js +584 -0
- package/dist/entry-client.d.ts +1 -0
- package/dist/entry-client.js +56 -0
- package/dist/entry-server.d.ts +9 -0
- package/dist/entry-server.js +33 -0
- package/dist/error-overlay.d.ts +1 -0
- package/dist/error-overlay.js +166 -0
- package/dist/font/google/index.d.ts +1923 -0
- package/dist/font/google/index.js +1948 -0
- package/dist/image/get-img-props.d.ts +20 -0
- package/dist/image/get-img-props.js +46 -0
- package/dist/image/image-config.d.ts +20 -0
- package/dist/image/image-config.js +17 -0
- package/dist/image/image-loader.d.ts +7 -0
- package/dist/image/image-loader.js +10 -0
- package/dist/image/index.d.ts +12 -0
- package/dist/image/index.js +12 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +4 -0
- package/dist/plugin.d.ts +5 -0
- package/dist/plugin.js +88 -0
- package/dist/router.d.ts +18 -0
- package/dist/router.js +55 -0
- package/package.json +47 -0
- package/src/ErrorOverlay.tsx +194 -0
- package/src/app.tsx +138 -0
- package/src/assets/vista.gif +0 -0
- package/src/client/link.tsx +85 -0
- package/src/client.tsx +368 -0
- package/src/entry-client.tsx +70 -0
- package/src/entry-server.tsx +58 -0
- package/src/error-overlay.ts +187 -0
- package/src/font/google/index.d.ts +19011 -0
- package/src/font/google/index.ts +1968 -0
- package/src/font/types.d.ts +13 -0
- package/src/image/get-img-props.ts +100 -0
- package/src/image/image-config.ts +22 -0
- package/src/image/image-loader.ts +23 -0
- package/src/image/index.tsx +21 -0
- package/src/index.ts +7 -0
- package/src/plugin.ts +100 -0
- package/src/router-loader.ts +51 -0
- package/src/router.tsx +80 -0
- package/tsconfig.json +23 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
const VSCodeColors = {
|
|
3
|
+
bg: '#1e1e1e',
|
|
4
|
+
sidebar: '#252526',
|
|
5
|
+
activityBar: '#333333',
|
|
6
|
+
statusBar: '#007acc',
|
|
7
|
+
titleBar: '#3c3c3c',
|
|
8
|
+
text: '#d4d4d4',
|
|
9
|
+
red: '#f14c4c',
|
|
10
|
+
yellow: '#cca700',
|
|
11
|
+
green: '#238636',
|
|
12
|
+
terminalBg: '#1e1e1e',
|
|
13
|
+
editorBg: '#1e1e1e',
|
|
14
|
+
lineNo: '#858585',
|
|
15
|
+
};
|
|
16
|
+
export const ErrorOverlay = ({ error, onClose }) => {
|
|
17
|
+
if (!error)
|
|
18
|
+
return null;
|
|
19
|
+
const isBuildError = error.type === 'error' || error.plugin; // Vite error shape
|
|
20
|
+
const message = error.message || 'Unknown Error';
|
|
21
|
+
const file = error.id || error.file || error.filename || 'Unknown File';
|
|
22
|
+
const frame = error.frame || '';
|
|
23
|
+
const stack = error.stack || '';
|
|
24
|
+
// Parse location if available
|
|
25
|
+
const loc = error.loc ? `${error.loc.line}:${error.loc.column}` : '';
|
|
26
|
+
return (_jsxs("div", { style: {
|
|
27
|
+
position: 'fixed',
|
|
28
|
+
top: 0,
|
|
29
|
+
left: 0,
|
|
30
|
+
width: '100vw',
|
|
31
|
+
height: '100vh',
|
|
32
|
+
zIndex: 99999,
|
|
33
|
+
backgroundColor: 'rgba(0, 0, 0, 0.6)',
|
|
34
|
+
backdropFilter: 'blur(8px)',
|
|
35
|
+
display: 'flex',
|
|
36
|
+
alignItems: 'center',
|
|
37
|
+
justifyContent: 'center',
|
|
38
|
+
fontFamily: "'Segoe UI', Tahoma, Geneva, Verdana, sans-serif",
|
|
39
|
+
}, children: [_jsxs("div", { style: {
|
|
40
|
+
width: '85vw',
|
|
41
|
+
maxWidth: '1000px',
|
|
42
|
+
height: '80vh',
|
|
43
|
+
backgroundColor: VSCodeColors.bg,
|
|
44
|
+
borderRadius: '10px',
|
|
45
|
+
boxShadow: '0 20px 50px rgba(0,0,0,0.5)',
|
|
46
|
+
overflow: 'hidden',
|
|
47
|
+
display: 'flex',
|
|
48
|
+
flexDirection: 'column',
|
|
49
|
+
border: '1px solid #454545',
|
|
50
|
+
animation: 'vista-slide-up 0.3s ease-out',
|
|
51
|
+
}, children: [_jsxs("div", { style: {
|
|
52
|
+
height: '35px',
|
|
53
|
+
backgroundColor: VSCodeColors.titleBar,
|
|
54
|
+
display: 'flex',
|
|
55
|
+
alignItems: 'center',
|
|
56
|
+
padding: '0 15px',
|
|
57
|
+
borderBottom: '1px solid #333',
|
|
58
|
+
}, children: [_jsxs("div", { style: { display: 'flex', gap: '8px', marginRight: '20px' }, children: [_jsx("div", { onClick: onClose, style: { width: '12px', height: '12px', borderRadius: '50%', backgroundColor: '#ff5f56', cursor: 'pointer' } }), _jsx("div", { style: { width: '12px', height: '12px', borderRadius: '50%', backgroundColor: '#ffbd2e' } }), _jsx("div", { style: { width: '12px', height: '12px', borderRadius: '50%', backgroundColor: '#27c93f' } })] }), _jsxs("div", { style: { color: '#ccc', fontSize: '13px', flex: 1, textAlign: 'center', opacity: 0.8 }, children: [file.split('/').pop(), " ", loc ? `— ${loc}` : ''] })] }), _jsxs("div", { style: { display: 'flex', flex: 1, overflow: 'hidden' }, children: [_jsxs("div", { style: { width: '50px', backgroundColor: VSCodeColors.activityBar, display: 'flex', flexDirection: 'column', alignItems: 'center', paddingTop: '15px' }, children: [_jsx("div", { style: { marginBottom: '20px', opacity: 0.6, cursor: 'pointer' }, title: "Explorer", children: _jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "#d4d4d4", strokeWidth: "1.5", children: [_jsx("path", { d: "M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z" }), _jsx("polyline", { points: "13 2 13 9 20 9" })] }) }), _jsx("div", { style: { marginBottom: '20px', opacity: 0.6, cursor: 'pointer' }, title: "Search", children: _jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "#d4d4d4", strokeWidth: "1.5", children: [_jsx("circle", { cx: "11", cy: "11", r: "8" }), _jsx("line", { x1: "21", y1: "21", x2: "16.65", y2: "16.65" })] }) }), _jsx("div", { style: { marginBottom: '20px', opacity: 1, borderLeft: '2px solid white', paddingLeft: '11px', cursor: 'pointer' }, title: "Run and Debug", children: _jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "#d4d4d4", strokeWidth: "1.5", children: [_jsx("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" }), _jsx("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" })] }) })] }), _jsxs("div", { className: "vista-sidebar", style: { width: '200px', backgroundColor: VSCodeColors.sidebar, fontSize: '13px', color: VSCodeColors.text, padding: '10px', borderRight: '1px solid #333' }, children: [_jsx("div", { style: { fontSize: '11px', fontWeight: 'bold', marginBottom: '10px', opacity: 0.7, textTransform: 'uppercase' }, children: "Open Editors" }), _jsxs("div", { style: { padding: '5px 10px', backgroundColor: '#37373d', borderRadius: '3px', cursor: 'pointer', display: 'flex', alignItems: 'center' }, children: [_jsx("span", { style: { marginRight: '8px', display: 'flex', alignItems: 'center' }, children: _jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "#61dafb", strokeWidth: "2", children: [_jsx("circle", { cx: "12", cy: "12", r: "10" }), _jsx("line", { x1: "12", y1: "8", x2: "12", y2: "12" }), _jsx("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })] }) }), file.split('/').pop()] })] }), _jsxs("div", { style: { flex: 1, display: 'flex', flexDirection: 'column', backgroundColor: VSCodeColors.editorBg }, children: [_jsx("div", { style: { height: '35px', backgroundColor: VSCodeColors.bg, display: 'flex', alignItems: 'center', borderBottom: '1px solid #333' }, children: _jsxs("div", { style: { padding: '0 15px', height: '100%', backgroundColor: '#1e1e1e', borderTop: '2px solid #e11c1c', color: '#fff', fontSize: '13px', display: 'flex', alignItems: 'center', gap: '8px' }, children: [_jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "#61dafb", strokeWidth: "2", children: [_jsx("circle", { cx: "12", cy: "12", r: "10" }), _jsx("line", { x1: "12", y1: "8", x2: "12", y2: "12" }), _jsx("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })] }), file.split('/').pop(), _jsx("span", { style: { marginLeft: '10px', cursor: 'pointer', opacity: 0.7 }, children: _jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [_jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), _jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }) })] }) }), _jsxs("div", { style: { flex: 2, padding: '20px', overflow: 'auto', fontFamily: "'Fira Code', 'Consolas', monospace", fontSize: '14px', lineHeight: '1.5', color: '#d4d4d4' }, children: [isBuildError && (_jsx("div", { style: { color: '#f14c4c', marginBottom: '15px', fontWeight: 'bold' }, children: message })), frame ? (_jsx("pre", { style: { margin: 0, whiteSpace: 'pre-wrap', fontFamily: 'inherit' }, children: frame })) : (_jsxs("div", { style: { color: '#d4d4d4' }, children: [_jsx("div", { style: { color: '#666', marginBottom: '20px' }, children: "// Source code not available for runtime execution error." }), _jsx("pre", { style: { margin: 0, color: '#9cdcfe', whiteSpace: 'pre-wrap' }, children: stack })] }))] }), _jsxs("div", { style: { flex: 1, backgroundColor: '#1e1e1e', borderTop: '1px solid #444', display: 'flex', flexDirection: 'column' }, children: [_jsxs("div", { style: { display: 'flex', padding: '5px 15px', borderBottom: '1px solid #333', fontSize: '11px', color: '#ccc', gap: '15px' }, children: [_jsx("span", { style: { textDecoration: 'underline', cursor: 'pointer' }, children: "PROBLEMS" }), _jsx("span", { style: { opacity: 0.5, cursor: 'pointer' }, children: "OUTPUT" }), _jsx("span", { style: { opacity: 0.5, cursor: 'pointer' }, children: "DEBUG CONSOLE" }), _jsx("span", { style: { opacity: 0.5, cursor: 'pointer' }, children: "TERMINAL" })] }), _jsxs("div", { style: { padding: '15px', overflow: 'auto', fontFamily: 'monospace', fontSize: '13px', color: '#f14c4c' }, children: [_jsx("div", { style: { color: '#d4d4d4', marginBottom: '5px' }, children: "$ npm run dev" }), _jsxs("div", { children: ["> Error: ", message] })] })] })] })] }), _jsxs("div", { style: { height: '22px', backgroundColor: '#e11c1c', display: 'flex', alignItems: 'center', padding: '0 10px', fontSize: '12px', color: 'white', justifyContent: 'space-between' }, children: [_jsxs("div", { style: { display: 'flex', gap: '15px', alignItems: 'center' }, children: [_jsxs("span", { style: { display: 'flex', alignItems: 'center', gap: '5px' }, children: [_jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "currentColor", children: [_jsx("circle", { cx: "12", cy: "12", r: "10" }), _jsx("line", { x1: "15", y1: "9", x2: "9", y2: "15" }), _jsx("line", { x1: "9", y1: "9", x2: "15", y2: "15" })] }), "1 Error"] }), _jsxs("span", { style: { display: 'flex', alignItems: 'center', gap: '5px' }, children: [_jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [_jsx("path", { d: "M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" }), _jsx("line", { x1: "12", y1: "9", x2: "12", y2: "13" }), _jsx("line", { x1: "12", y1: "17", x2: "12.01", y2: "17" })] }), "0 Warnings"] })] }), _jsxs("div", { children: ["Ln ", error.loc?.line || 0, ", Col ", error.loc?.column || 0] })] })] }), _jsx("style", { children: `
|
|
59
|
+
.vista-sidebar { display: none; }
|
|
60
|
+
@media (min-width: 768px) {
|
|
61
|
+
.vista-sidebar { display: block; }
|
|
62
|
+
}
|
|
63
|
+
@keyframes vista-slide-up {
|
|
64
|
+
from { opacity: 0; transform: translateY(20px) scale(0.95); }
|
|
65
|
+
to { opacity: 1; transform: translateY(0) scale(1); }
|
|
66
|
+
}
|
|
67
|
+
` })] }));
|
|
68
|
+
};
|
package/dist/app.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export declare function loadRoute(path: string): Promise<React.ComponentType<any> | null>;
|
|
3
|
+
export declare function loadRootLayout(): Promise<{
|
|
4
|
+
Component: React.ComponentType<any>;
|
|
5
|
+
metadata: any;
|
|
6
|
+
} | {
|
|
7
|
+
Component: null;
|
|
8
|
+
metadata: {};
|
|
9
|
+
}>;
|
|
10
|
+
export type VistaAsset = {
|
|
11
|
+
type: 'style' | 'script' | 'preamble';
|
|
12
|
+
src?: string;
|
|
13
|
+
content?: string;
|
|
14
|
+
key?: string;
|
|
15
|
+
};
|
|
16
|
+
export default function App({ initialComponent, initialRootLayout, metadata, assets }: {
|
|
17
|
+
initialComponent?: React.ComponentType<any>;
|
|
18
|
+
initialRootLayout?: React.ComponentType<any>;
|
|
19
|
+
metadata?: any;
|
|
20
|
+
assets?: VistaAsset[];
|
|
21
|
+
}): import("react/jsx-runtime").JSX.Element;
|
package/dist/app.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React, { Suspense } from 'react';
|
|
3
|
+
import { useRouter } from './router.js';
|
|
4
|
+
// Lazy load all pages and layouts at module level so they can be accessed by loadRoute
|
|
5
|
+
// Note: Vite treats absolute paths in glob as relative to the project root
|
|
6
|
+
// Lazy load all pages and layouts at module level so they can be accessed by loadRoute
|
|
7
|
+
// Note: Vite treats absolute paths in glob as relative to the project root
|
|
8
|
+
// FIX: Use eager: true to solve HMR instability with lazy boundaries
|
|
9
|
+
// FIX: Use eager: true to solve HMR instability with lazy boundaries
|
|
10
|
+
const pages = import.meta.glob('/app/**/index.tsx', { eager: true });
|
|
11
|
+
const layouts = import.meta.glob('/app/**/layout.tsx', { eager: true });
|
|
12
|
+
const rootLayout = import.meta.glob('/app/layout.tsx', { eager: true });
|
|
13
|
+
// Helper to resolve route path to file key
|
|
14
|
+
function getPageKey(path) {
|
|
15
|
+
const cleanPath = path === '/' ? '/' : path.replace(/\/$/, '');
|
|
16
|
+
return `/app${cleanPath === '/' ? '' : cleanPath}/index.tsx`;
|
|
17
|
+
}
|
|
18
|
+
// Exported loader for entry-client to preload the initial route
|
|
19
|
+
export async function loadRoute(path) {
|
|
20
|
+
const pageKey = getPageKey(path);
|
|
21
|
+
if (pages[pageKey]) {
|
|
22
|
+
try {
|
|
23
|
+
// Eager: pages[pageKey] is the module itself
|
|
24
|
+
const mod = pages[pageKey];
|
|
25
|
+
return mod.default;
|
|
26
|
+
}
|
|
27
|
+
catch (e) {
|
|
28
|
+
console.error(`Failed to load route: ${path}`, e);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
// Exported loader for entry-client/server to preload the root layout and metadata
|
|
34
|
+
export async function loadRootLayout() {
|
|
35
|
+
const rootLayoutKey = '/app/layout.tsx';
|
|
36
|
+
if (rootLayout[rootLayoutKey]) {
|
|
37
|
+
try {
|
|
38
|
+
// Eager: rootLayout[rootLayoutKey] is the module itself
|
|
39
|
+
const mod = rootLayout[rootLayoutKey];
|
|
40
|
+
return {
|
|
41
|
+
Component: mod.default,
|
|
42
|
+
metadata: mod.metadata || {}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
catch (e) {
|
|
46
|
+
console.error('Failed to load root layout', e);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return { Component: null, metadata: {} };
|
|
50
|
+
}
|
|
51
|
+
function VistaHead({ assets, metadata }) {
|
|
52
|
+
// Serialize assets for client hydration
|
|
53
|
+
const serializedAssets = JSON.stringify(assets || []);
|
|
54
|
+
// With hydrateRoot(document) and React 19, we can just render the tags.
|
|
55
|
+
// React handles the hoisting for stylesheets if we hint them, or just standard placement.
|
|
56
|
+
// Since we are hydrating the full document, and RootLayout contains <head>,
|
|
57
|
+
// these tags will be rendered where they are (in body/root children).
|
|
58
|
+
// React 19 "Hoistable" Resources: <title>, <meta>, <link rel=stylesheet>.
|
|
59
|
+
// They will be hoisted to <head> automatically.
|
|
60
|
+
return (_jsxs(_Fragment, { children: [metadata?.title && _jsx("title", { children: metadata.title }), metadata?.description && _jsx("meta", { name: "description", content: metadata.description }), assets?.map((asset, index) => {
|
|
61
|
+
if (asset.type === 'style' && asset.src) {
|
|
62
|
+
// Precedence="default" opts into React 19 Resource Loading/Hoisting
|
|
63
|
+
/* @ts-ignore: React 19 prop */
|
|
64
|
+
return _jsx("link", { rel: "stylesheet", href: asset.src, precedence: "default" }, asset.key || asset.src);
|
|
65
|
+
}
|
|
66
|
+
if (asset.type === 'script' && asset.src) {
|
|
67
|
+
return _jsx("script", { type: "module", src: asset.src }, asset.key || asset.src);
|
|
68
|
+
}
|
|
69
|
+
if (asset.type === 'preamble' && asset.content) {
|
|
70
|
+
return (_jsx("script", { type: "module", dangerouslySetInnerHTML: { __html: asset.content } }, "preamble"));
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}), _jsx("script", { id: "vista-assets", dangerouslySetInnerHTML: {
|
|
74
|
+
__html: `window.__VISTA_ASSETS__ = ${serializedAssets};`
|
|
75
|
+
} })] }));
|
|
76
|
+
}
|
|
77
|
+
export default function App({ initialComponent, initialRootLayout, metadata, assets }) {
|
|
78
|
+
const { path } = useRouter();
|
|
79
|
+
const pageKey = getPageKey(path);
|
|
80
|
+
if (!pages[pageKey]) {
|
|
81
|
+
return _jsxs("div", { children: ["404 Not Found: ", pageKey] });
|
|
82
|
+
}
|
|
83
|
+
// --- Page Logic ---
|
|
84
|
+
// --- Page Logic ---
|
|
85
|
+
const isInitialRender = React.useRef(!!initialComponent);
|
|
86
|
+
const [useInitial, setUseInitial] = React.useState(!!initialComponent);
|
|
87
|
+
const [initialPath] = React.useState(path); // FIX: Hook must be at top level
|
|
88
|
+
React.useEffect(() => {
|
|
89
|
+
// Switch to dynamic component (HMR-capable) after hydration
|
|
90
|
+
if (useInitial) {
|
|
91
|
+
setUseInitial(false);
|
|
92
|
+
isInitialRender.current = false;
|
|
93
|
+
}
|
|
94
|
+
}, []);
|
|
95
|
+
let PageComponent;
|
|
96
|
+
// Use initial component only if we are on the same path and fresh from hydration
|
|
97
|
+
if (useInitial && initialComponent && path === initialPath) {
|
|
98
|
+
PageComponent = initialComponent;
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
// Eager: Direct access
|
|
102
|
+
PageComponent = pages[pageKey].default;
|
|
103
|
+
}
|
|
104
|
+
// --- Layout Logic ---
|
|
105
|
+
let RootLayoutComponent = initialRootLayout;
|
|
106
|
+
if (!RootLayoutComponent) {
|
|
107
|
+
const rootLayoutKey = '/app/layout.tsx';
|
|
108
|
+
if (rootLayout[rootLayoutKey]) {
|
|
109
|
+
// Eager
|
|
110
|
+
RootLayoutComponent = rootLayout[rootLayoutKey].default;
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
RootLayoutComponent = React.Fragment;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return (
|
|
117
|
+
/* @ts-ignore */
|
|
118
|
+
_jsxs(RootLayoutComponent, { children: [_jsx(VistaHead, { metadata: metadata, assets: assets }), _jsx(Suspense, { fallback: null, children: _jsx(PageComponent, {}, path) })] }));
|
|
119
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React, { AnchorHTMLAttributes } from 'react';
|
|
2
|
+
type Url = string | {
|
|
3
|
+
href: string;
|
|
4
|
+
query?: any;
|
|
5
|
+
hash?: string;
|
|
6
|
+
};
|
|
7
|
+
export interface LinkProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> {
|
|
8
|
+
href: Url;
|
|
9
|
+
as?: Url;
|
|
10
|
+
replace?: boolean;
|
|
11
|
+
scroll?: boolean;
|
|
12
|
+
shallow?: boolean;
|
|
13
|
+
passHref?: boolean;
|
|
14
|
+
prefetch?: boolean | 'auto' | null;
|
|
15
|
+
locale?: string | false;
|
|
16
|
+
legacyBehavior?: boolean;
|
|
17
|
+
onNavigate?: () => void;
|
|
18
|
+
}
|
|
19
|
+
export declare const Link: React.ForwardRefExoticComponent<LinkProps & React.RefAttributes<HTMLAnchorElement>>;
|
|
20
|
+
export declare const useLinkStatus: () => {
|
|
21
|
+
pending: boolean;
|
|
22
|
+
};
|
|
23
|
+
export default Link;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { useRouter } from '../router';
|
|
4
|
+
// Simple normalization for href (string or object)
|
|
5
|
+
const formatUrl = (url) => {
|
|
6
|
+
if (typeof url === 'string')
|
|
7
|
+
return url;
|
|
8
|
+
if (typeof url === 'object' && url !== null) {
|
|
9
|
+
// Very basic support just for demo
|
|
10
|
+
return (url.href || '') + (url.hash || '');
|
|
11
|
+
}
|
|
12
|
+
return '';
|
|
13
|
+
};
|
|
14
|
+
export const Link = React.forwardRef(({ href, as, replace, scroll, shallow, passHref, prefetch, legacyBehavior, children, onClick, ...props }, ref) => {
|
|
15
|
+
const { push, replace: replaceRoute } = useRouter();
|
|
16
|
+
const targetPath = formatUrl(as || href);
|
|
17
|
+
const handleClick = (e) => {
|
|
18
|
+
if (onClick)
|
|
19
|
+
onClick(e);
|
|
20
|
+
// Standard link behavior checks
|
|
21
|
+
if (e.defaultPrevented)
|
|
22
|
+
return;
|
|
23
|
+
if (e.button !== 0)
|
|
24
|
+
return; // ignore right clicks
|
|
25
|
+
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey)
|
|
26
|
+
return; // ignore open in new tab
|
|
27
|
+
if (!href)
|
|
28
|
+
return;
|
|
29
|
+
e.preventDefault();
|
|
30
|
+
if (replace) {
|
|
31
|
+
replaceRoute(targetPath);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
push(targetPath);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
return (_jsx("a", { href: targetPath, onClick: handleClick, ref: ref, ...props, children: children }));
|
|
38
|
+
});
|
|
39
|
+
export const useLinkStatus = () => {
|
|
40
|
+
return { pending: false }; // Mock implementation
|
|
41
|
+
};
|
|
42
|
+
export default Link;
|
package/dist/client.d.ts
ADDED
package/dist/client.js
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import React, { useState, useEffect } from 'react';
|
|
3
|
+
import ReactDOM from 'react-dom/client';
|
|
4
|
+
import { RouterProvider, useRouter } from './router.js';
|
|
5
|
+
import { ErrorOverlay } from './ErrorOverlay';
|
|
6
|
+
// --- Error Management ---
|
|
7
|
+
function VistaErrorManager({ children, initialError }) {
|
|
8
|
+
const [error, setError] = useState(initialError || null);
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
// 1. Listen for Vite HMR/Build Errors
|
|
11
|
+
if (import.meta.hot) {
|
|
12
|
+
import.meta.hot.on('vite:error', (payloade) => {
|
|
13
|
+
// Vite sends an object like { err: { message, stack, plugin, id, frame, loc } }
|
|
14
|
+
// OR sometimes just the error object directly depending on version/context.
|
|
15
|
+
console.log('[Vista] Received vite:error payload:', payloade);
|
|
16
|
+
const err = payloade.err || payloade;
|
|
17
|
+
setError({
|
|
18
|
+
message: err.message,
|
|
19
|
+
stack: err.stack,
|
|
20
|
+
id: err.id, // Vite uses 'id' for filename often
|
|
21
|
+
frame: err.frame,
|
|
22
|
+
plugin: err.plugin,
|
|
23
|
+
loc: err.loc,
|
|
24
|
+
type: 'build',
|
|
25
|
+
// Fallbacks for Overlay keys
|
|
26
|
+
filename: err.id || err.file || 'Build Error',
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
import.meta.hot.on('vite:beforeUpdate', () => {
|
|
30
|
+
setError(null); // Clear error on new update
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
// 2. Listen for Unhandled Promise Rejections
|
|
34
|
+
const handleRejection = (event) => {
|
|
35
|
+
// Ignore dynamic import errors if we likely have a build error
|
|
36
|
+
if (event.reason?.message?.includes('Failed to fetch dynamically imported module')) {
|
|
37
|
+
console.log('[Vista] Ignoring dynamic import error (likely causing a build error)');
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
setError((prev) => {
|
|
41
|
+
// specific check: don't overwrite build errors with runtime noise
|
|
42
|
+
if (prev && prev.type === 'build')
|
|
43
|
+
return prev;
|
|
44
|
+
return {
|
|
45
|
+
message: event.reason?.message || 'Unhandled Promise Rejection',
|
|
46
|
+
stack: event.reason?.stack || '',
|
|
47
|
+
filename: 'Runtime Error',
|
|
48
|
+
loc: { line: 0, column: 0 },
|
|
49
|
+
type: 'runtime'
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
// 3. Listen for Global Errors
|
|
54
|
+
const handleError = (event) => {
|
|
55
|
+
setError((prev) => {
|
|
56
|
+
if (prev && prev.type === 'build')
|
|
57
|
+
return prev;
|
|
58
|
+
return {
|
|
59
|
+
message: event.error?.message || event.message || 'Unknown Error',
|
|
60
|
+
stack: event.error?.stack || '',
|
|
61
|
+
filename: 'Runtime Error',
|
|
62
|
+
loc: { line: event.lineno || 0, column: event.colno || 0 },
|
|
63
|
+
type: 'runtime'
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
window.addEventListener('unhandledrejection', handleRejection);
|
|
68
|
+
window.addEventListener('error', handleError);
|
|
69
|
+
return () => {
|
|
70
|
+
window.removeEventListener('unhandledrejection', handleRejection);
|
|
71
|
+
window.removeEventListener('error', handleError);
|
|
72
|
+
};
|
|
73
|
+
}, []);
|
|
74
|
+
const handleBoundaryError = (err) => {
|
|
75
|
+
// Logic to ignore cascade errors
|
|
76
|
+
if (error && error.type === 'build')
|
|
77
|
+
return;
|
|
78
|
+
if (err.message && err.message.includes('Failed to fetch dynamically imported module'))
|
|
79
|
+
return;
|
|
80
|
+
setError({
|
|
81
|
+
message: err.message,
|
|
82
|
+
stack: err.stack,
|
|
83
|
+
loc: { line: 0, column: 0 },
|
|
84
|
+
filename: 'Runtime Error',
|
|
85
|
+
type: 'runtime'
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
if (error) {
|
|
89
|
+
return _jsx(ErrorOverlay, { error: error, onClose: () => setError(null) });
|
|
90
|
+
}
|
|
91
|
+
return (_jsx(ErrorBoundary, { onError: handleBoundaryError, children: children }));
|
|
92
|
+
}
|
|
93
|
+
// ... existing ErrorBoundary ...
|
|
94
|
+
// ... existing AppContent ...
|
|
95
|
+
// ... existing App ...
|
|
96
|
+
// Export a mount function that accepts the glob results
|
|
97
|
+
export function mount(modules) {
|
|
98
|
+
console.log('[Vista] Mount called with modules:', Object.keys(modules));
|
|
99
|
+
const root = document.getElementById('root');
|
|
100
|
+
if (root) {
|
|
101
|
+
console.log('[Vista] Root element found, rendering...');
|
|
102
|
+
ReactDOM.createRoot(root).render(_jsx(VistaErrorManager, { children: _jsx(App, { modules: modules }) }));
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
console.error('[Vista] FATAL: Root element #root not found in DOM');
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Export a mountError function for when module loading fails
|
|
109
|
+
export function mountError(error) {
|
|
110
|
+
const root = document.getElementById('root');
|
|
111
|
+
if (root) {
|
|
112
|
+
// Mount just the ErrorManager to catch and display the Vite error
|
|
113
|
+
ReactDOM.createRoot(root).render(_jsx(VistaErrorManager, { initialError: error, children: _jsx("div", { style: { padding: '20px', fontFamily: 'sans-serif', color: '#666' }, children: "Initializing error overlay..." }) }));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
class ErrorBoundary extends React.Component {
|
|
117
|
+
constructor(props) {
|
|
118
|
+
super(props);
|
|
119
|
+
this.state = { hasError: false };
|
|
120
|
+
}
|
|
121
|
+
static getDerivedStateFromError(error) {
|
|
122
|
+
return { hasError: true };
|
|
123
|
+
}
|
|
124
|
+
componentDidCatch(error, errorInfo) {
|
|
125
|
+
this.props.onError({
|
|
126
|
+
message: error.message,
|
|
127
|
+
stack: error.stack,
|
|
128
|
+
loc: { line: 0, column: 0 },
|
|
129
|
+
filename: 'Runtime Error'
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
render() {
|
|
133
|
+
if (this.state.hasError) {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
return this.props.children;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// --- App Logic ---
|
|
140
|
+
function AppContent({ modules }) {
|
|
141
|
+
const { path: currentPath } = useRouter();
|
|
142
|
+
// 1. Find the matching page component
|
|
143
|
+
let PageComponent = () => _jsx("div", { className: "p-10 text-xl", children: "404 Not Found" });
|
|
144
|
+
// 2. Build the Layout Tree
|
|
145
|
+
// ... (Logic to build layoutPaths is same) ...
|
|
146
|
+
// Refactored Async Logic
|
|
147
|
+
const [componentTree, setComponentTree] = React.useState(null);
|
|
148
|
+
const [pageError, setPageError] = React.useState(null);
|
|
149
|
+
React.useEffect(() => {
|
|
150
|
+
let isMounted = true;
|
|
151
|
+
setPageError(null);
|
|
152
|
+
const loadRoute = async () => {
|
|
153
|
+
try {
|
|
154
|
+
// --- 1. Route Matching Engine ---
|
|
155
|
+
let pageLoader = null;
|
|
156
|
+
let matchedRoutePath = '';
|
|
157
|
+
let routeParams = {};
|
|
158
|
+
// Normalize current path: remove trailing slash (unless root)
|
|
159
|
+
let normalizedPath = currentPath;
|
|
160
|
+
if (normalizedPath.length > 1 && normalizedPath.endsWith('/')) {
|
|
161
|
+
normalizedPath = normalizedPath.slice(0, -1);
|
|
162
|
+
}
|
|
163
|
+
// Helper: Convert file path to route regex
|
|
164
|
+
// e.g. "/app/users/[id]/index.tsx" -> "^/users/([^/]+)$"
|
|
165
|
+
// e.g. "/app/index.tsx" -> "^/$"
|
|
166
|
+
const createRouteMatcher = (filePath) => {
|
|
167
|
+
// Remove prefix: handle "/", "./", or no slash before "app"
|
|
168
|
+
let cleanPath = filePath
|
|
169
|
+
.replace(/^(\.?\/)?app\//, '') // Remove app/ prefix (robust)
|
|
170
|
+
.replace(/\/index\.tsx$/, '') // Remove /index.tsx (nested)
|
|
171
|
+
.replace(/^index\.tsx$/, '') // Remove index.tsx (root)
|
|
172
|
+
.replace(/\.tsx$/, ''); // Remove .tsx (if any)
|
|
173
|
+
if (cleanPath === '')
|
|
174
|
+
cleanPath = '/';
|
|
175
|
+
// Split into segments
|
|
176
|
+
const segments = cleanPath.split('/').filter(Boolean);
|
|
177
|
+
const paramNames = [];
|
|
178
|
+
// Console log for debug
|
|
179
|
+
// console.log(`[Router Debug] File: ${filePath} -> Clean: ${cleanPath}`);
|
|
180
|
+
const pathPattern = segments.map(seg => {
|
|
181
|
+
if (seg.startsWith('[') && seg.endsWith(']')) {
|
|
182
|
+
const paramName = seg.slice(1, -1);
|
|
183
|
+
paramNames.push(paramName);
|
|
184
|
+
return '([^/]+)'; // Match any non-slash char
|
|
185
|
+
}
|
|
186
|
+
return seg; // Static segment
|
|
187
|
+
}).join('/');
|
|
188
|
+
// Generate Regex: Ensure it starts with ^/ and ends with $
|
|
189
|
+
// cleanPath modules like 'about' become '^/about$'
|
|
190
|
+
// root '' becomes '^/$'
|
|
191
|
+
const regexString = pathPattern ? `^/${pathPattern}$` : '^/$';
|
|
192
|
+
return {
|
|
193
|
+
regex: new RegExp(regexString),
|
|
194
|
+
paramNames,
|
|
195
|
+
originalPath: cleanPath
|
|
196
|
+
};
|
|
197
|
+
};
|
|
198
|
+
// Iterate all modules to find a match
|
|
199
|
+
// Note: In a real framework, you'd cache the route table.
|
|
200
|
+
// console.log('[Vista Router] Current Path (Normalized):', normalizedPath);
|
|
201
|
+
// console.log('[Vista Router] Modules Found:', Object.keys(modules));
|
|
202
|
+
for (const path in modules) {
|
|
203
|
+
// Only care about pages (index.tsx)
|
|
204
|
+
if (!path.endsWith('/index.tsx'))
|
|
205
|
+
continue;
|
|
206
|
+
const { regex, paramNames } = createRouteMatcher(path);
|
|
207
|
+
const match = normalizedPath.match(regex);
|
|
208
|
+
// console.log(`[Vista Router] Checking ${path} -> Regex: ${regex} -> Match: ${match ? 'YES' : 'NO'}`);
|
|
209
|
+
if (match) {
|
|
210
|
+
pageLoader = modules[path];
|
|
211
|
+
matchedRoutePath = path;
|
|
212
|
+
// Extract params
|
|
213
|
+
match.slice(1).forEach((val, index) => {
|
|
214
|
+
routeParams[paramNames[index]] = decodeURIComponent(val);
|
|
215
|
+
});
|
|
216
|
+
break; // Found first match (TODO: strict sorting Order)
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (!pageLoader) {
|
|
220
|
+
if (isMounted)
|
|
221
|
+
setComponentTree(_jsx("div", { className: "p-10 text-xl", children: "404 Not Found" }));
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
// --- 2. Load Page & Layouts ---
|
|
225
|
+
const pageModule = await pageLoader();
|
|
226
|
+
let PageComponent = pageModule.default;
|
|
227
|
+
// Load Layouts: Climb up the directory tree from the page path
|
|
228
|
+
// e.g. /app/users/[id]/index.tsx
|
|
229
|
+
// Check: /app/users/[id]/layout.tsx
|
|
230
|
+
// Check: /app/users/layout.tsx
|
|
231
|
+
// Check: /app/layout.tsx
|
|
232
|
+
const layoutLoaders = [];
|
|
233
|
+
const dirSegments = matchedRoutePath.split('/').slice(0, -1); // remove index.tsx
|
|
234
|
+
// Construct potential layout paths from root down to leaf
|
|
235
|
+
// But we want to load them all.
|
|
236
|
+
// Actually, let's just create the list of all parent directories and check for layout.tsx
|
|
237
|
+
let currentDir = ''; // starts empty
|
|
238
|
+
const possibleLayouts = [];
|
|
239
|
+
// We know everything starts with /app
|
|
240
|
+
// dirSegments looks like ['', 'app', 'users', '[id]']
|
|
241
|
+
for (const segment of dirSegments) {
|
|
242
|
+
if (!segment)
|
|
243
|
+
continue;
|
|
244
|
+
currentDir += `/${segment}`;
|
|
245
|
+
const layoutPath = `${currentDir}/layout.tsx`;
|
|
246
|
+
if (modules[layoutPath]) {
|
|
247
|
+
possibleLayouts.push(layoutPath);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
// Execute layout loaders
|
|
251
|
+
const layoutModules = await Promise.all(possibleLayouts.map(path => modules[path]()));
|
|
252
|
+
if (!isMounted)
|
|
253
|
+
return;
|
|
254
|
+
// Handle Metadata
|
|
255
|
+
let meta = pageModule.metadata || {};
|
|
256
|
+
layoutModules.forEach(mod => {
|
|
257
|
+
if (mod.metadata)
|
|
258
|
+
meta = { ...meta, ...mod.metadata };
|
|
259
|
+
});
|
|
260
|
+
if (meta.title)
|
|
261
|
+
document.title = meta.title;
|
|
262
|
+
// Build Tree: Wrap Page with Layouts (Inner -> Outer? NO. Outer wraps Inner.)
|
|
263
|
+
// layoutModules is [AppLayout, UsersLayout, UserIdLayout]
|
|
264
|
+
// We want <AppLayout><UsersLayout><UserIdLayout><Page /></...></...></...>
|
|
265
|
+
let Content = _jsx(PageComponent, { params: routeParams }); // Pass params to page!
|
|
266
|
+
// Reverse iterate to wrap from inside out
|
|
267
|
+
for (let i = layoutModules.length - 1; i >= 0; i--) {
|
|
268
|
+
const LayoutComponent = layoutModules[i].default;
|
|
269
|
+
Content = _jsx(LayoutComponent, { params: routeParams, children: Content });
|
|
270
|
+
}
|
|
271
|
+
setComponentTree(Content);
|
|
272
|
+
}
|
|
273
|
+
catch (err) {
|
|
274
|
+
console.error('[Vista] Failed to load route:', err);
|
|
275
|
+
if (isMounted)
|
|
276
|
+
setPageError(err);
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
loadRoute();
|
|
280
|
+
return () => { isMounted = false; };
|
|
281
|
+
}, [currentPath, modules]);
|
|
282
|
+
if (pageError) {
|
|
283
|
+
// Propagate to ErrorManager
|
|
284
|
+
throw pageError;
|
|
285
|
+
}
|
|
286
|
+
return componentTree;
|
|
287
|
+
}
|
|
288
|
+
function App({ modules }) {
|
|
289
|
+
return (_jsx(React.StrictMode, { children: _jsx(RouterProvider, { children: _jsx(AppContent, { modules: modules }) }) }));
|
|
290
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
type PixelBlastVariant = 'square' | 'circle' | 'triangle' | 'diamond';
|
|
3
|
+
export type PixelBlastProps = {
|
|
4
|
+
variant?: PixelBlastVariant;
|
|
5
|
+
pixelSize?: number;
|
|
6
|
+
color?: string;
|
|
7
|
+
className?: string;
|
|
8
|
+
style?: React.CSSProperties;
|
|
9
|
+
antialias?: boolean;
|
|
10
|
+
patternScale?: number;
|
|
11
|
+
patternDensity?: number;
|
|
12
|
+
liquid?: boolean;
|
|
13
|
+
liquidStrength?: number;
|
|
14
|
+
liquidRadius?: number;
|
|
15
|
+
pixelSizeJitter?: number;
|
|
16
|
+
enableRipples?: boolean;
|
|
17
|
+
rippleIntensityScale?: number;
|
|
18
|
+
rippleThickness?: number;
|
|
19
|
+
rippleSpeed?: number;
|
|
20
|
+
liquidWobbleSpeed?: number;
|
|
21
|
+
autoPauseOffscreen?: boolean;
|
|
22
|
+
speed?: number;
|
|
23
|
+
transparent?: boolean;
|
|
24
|
+
edgeFade?: number;
|
|
25
|
+
noiseAmount?: number;
|
|
26
|
+
};
|
|
27
|
+
declare const PixelBlast: React.FC<PixelBlastProps>;
|
|
28
|
+
export default PixelBlast;
|