@flight-framework/cli 0.0.8 → 0.0.9
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/package.json
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
+
import { useRouter } from './context/RouterContext';
|
|
2
|
+
|
|
1
3
|
export default function App() {
|
|
4
|
+
const { path } = useRouter();
|
|
5
|
+
|
|
2
6
|
return (
|
|
3
7
|
<main>
|
|
4
|
-
<h1>Flight
|
|
8
|
+
<h1>Welcome to Flight</h1>
|
|
9
|
+
<p>Current path: {path}</p>
|
|
5
10
|
<p>Edit <code>src/App.tsx</code> to get started.</p>
|
|
6
11
|
</main>
|
|
7
12
|
);
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { createContext, useState, useEffect, useContext, type ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
interface RouterContextValue {
|
|
4
|
+
path: string;
|
|
5
|
+
navigate: (to: string) => void;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Router Context for SSR-safe path sharing
|
|
10
|
+
* - Server: receives URL from request
|
|
11
|
+
* - Client: syncs with browser location
|
|
12
|
+
*/
|
|
13
|
+
const RouterContext = createContext<RouterContextValue>({
|
|
14
|
+
path: '/',
|
|
15
|
+
navigate: () => { },
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export function useRouter() {
|
|
19
|
+
return useContext(RouterContext);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface RouterProviderProps {
|
|
23
|
+
children: ReactNode;
|
|
24
|
+
initialPath?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Router Provider - wraps app to provide current path
|
|
29
|
+
*
|
|
30
|
+
* Usage:
|
|
31
|
+
* - Server: <RouterProvider initialPath={url}><App /></RouterProvider>
|
|
32
|
+
* - Client: <RouterProvider><App /></RouterProvider>
|
|
33
|
+
*/
|
|
34
|
+
export function RouterProvider({ children, initialPath = '/' }: RouterProviderProps) {
|
|
35
|
+
const isClient = typeof window !== 'undefined';
|
|
36
|
+
|
|
37
|
+
const [path, setPath] = useState(
|
|
38
|
+
isClient ? window.location.pathname : initialPath
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const navigate = (to: string) => {
|
|
42
|
+
if (isClient) {
|
|
43
|
+
window.history.pushState({}, '', to);
|
|
44
|
+
setPath(to);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
if (!isClient) return;
|
|
50
|
+
|
|
51
|
+
const handlePopState = () => setPath(window.location.pathname);
|
|
52
|
+
window.addEventListener('popstate', handlePopState);
|
|
53
|
+
return () => window.removeEventListener('popstate', handlePopState);
|
|
54
|
+
}, [isClient]);
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<RouterContext.Provider value={{ path, navigate }}>
|
|
58
|
+
{children}
|
|
59
|
+
</RouterContext.Provider>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export default RouterProvider;
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
import { hydrateRoot, createRoot } from 'react-dom/client';
|
|
2
|
+
import { RouterProvider } from './context/RouterContext';
|
|
2
3
|
import App from './App';
|
|
3
4
|
import './styles/global.css';
|
|
4
5
|
|
|
5
6
|
const root = document.getElementById('root')!;
|
|
6
7
|
|
|
8
|
+
const app = (
|
|
9
|
+
<RouterProvider>
|
|
10
|
+
<App />
|
|
11
|
+
</RouterProvider>
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
// Hydrate SSR content or render client-only
|
|
7
15
|
if (root.innerHTML.trim()) {
|
|
8
|
-
hydrateRoot(root,
|
|
16
|
+
hydrateRoot(root, app);
|
|
9
17
|
} else {
|
|
10
|
-
createRoot(root).render(
|
|
18
|
+
createRoot(root).render(app);
|
|
11
19
|
}
|
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
import { renderToString } from 'react-dom/server';
|
|
2
|
+
import { RouterProvider } from './context/RouterContext';
|
|
2
3
|
import App from './App';
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Server-side render function
|
|
7
|
+
* Called by Flight for each page request
|
|
8
|
+
*
|
|
9
|
+
* @param url - Request URL path (e.g., '/about', '/products/123')
|
|
10
|
+
*/
|
|
11
|
+
export function render(url: string): string {
|
|
12
|
+
return renderToString(
|
|
13
|
+
<RouterProvider initialPath={url}>
|
|
14
|
+
<App />
|
|
15
|
+
</RouterProvider>
|
|
16
|
+
);
|
|
6
17
|
}
|