rasengan
Version:
The modern React Framework
166 lines (165 loc) • 5.26 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { isRouteErrorResponse, Link, useLocation, useParams, useRouteError, } from 'react-router';
import { useEffect, useRef } from 'react';
import { errorStore } from '../error-overlay/error-store.js';
// Extract the environment variables
const extractEnv = () => {
try {
const env = import.meta.env;
// If not env, use process.env on the server only
if (!env) {
const serverEnv = process.env;
return {
DEV: serverEnv.NODE_ENV === 'development',
PROD: serverEnv.NODE_ENV === 'production',
TEST: serverEnv.NODE_ENV === 'test',
};
}
return {
DEV: env.DEV,
PROD: env.PROD,
TEST: env.TEST,
};
}
catch (error) {
console.error(error);
return {
DEV: false,
PROD: true,
TEST: false,
};
}
};
/**
* Error boundary component that will be displayed if an error occurs during a routing
* @returns
*/
export function ErrorBoundary() {
const { DEV } = extractEnv();
let error = useRouteError();
if (!DEV)
return (_jsx("section", { style: {
position: 'fixed',
top: 0,
left: 0,
right: 0,
bottom: 0,
zIndex: 100,
display: 'flex',
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
height: '100vh',
width: '100vw',
gap: 10,
backgroundColor: '#fff',
}, children: _jsx("p", { style: {
fontSize: '18px',
}, children: "Application Error" }) }));
useEffect(() => {
if (!DEV)
return;
const err = error instanceof Error
? error
: isRouteErrorResponse(error)
? new Error(`${error.status} ${error.statusText}: ${error.data}`)
: new Error(String(error));
errorStore.addError(err, 'route');
}, [error, DEV]);
return null;
}
/**
* Page component that defines title and description to a page
*/
export const RasenganPageComponent = ({ page: Page, data, }) => {
// Get the page props
const props = data.props ?? {};
// get params
const params = useParams();
const pageProps = {
...props,
params,
};
return _jsx(Page, { ...pageProps });
};
/**
* Component that will be displayed when a page is not found
* @returns React.ReactNode
*/
export const NotFoundPageComponent = () => {
return (_jsxs("section", { style: {
display: 'flex',
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
height: '100vh',
width: '100vw',
gap: 10,
}, children: [_jsx("h1", { style: {
fontSize: '18px',
fontWeight: 'normal',
}, children: "404" }), _jsx("span", { style: {
height: '20px',
borderRightWidth: '1px',
borderRightStyle: 'solid',
borderRightColor: '#ccc',
} }), _jsx("p", { style: {
fontSize: '18px',
}, children: "Page not found" })] }));
};
/**
* Custom Link Component
* @param props
* @returns React.ReactNode
*/
export const CustomLink = (props) => {
const { to, children, ...rest } = props;
if (typeof to === 'string') {
const splitted = to.split('#');
if (splitted.length > 1)
return (_jsx("a", { href: to, ...rest, children: children }));
}
return (_jsx(Link, { to: to, ...rest, children: children }));
};
// Store scroll positions globally (per location.key)
const scrollPositions = {};
/**
* Scroll restoration component
* @param {Props} props
* @returns
*/
export function ScrollRestoration({ alwaysToTop = false, target }) {
const location = useLocation();
const pathnameRef = useRef(location.pathname);
useEffect(() => {
if (typeof window === 'undefined')
return;
const prevPathname = pathnameRef.current;
const el = target?.current; // easier to reference
if (alwaysToTop) {
if (el) {
el.scrollTo(0, 0);
}
else {
window.scrollTo(0, 0);
}
pathnameRef.current = location.pathname;
return;
}
// Save scroll position of the previous page
if (prevPathname) {
scrollPositions[prevPathname] = el ? el.scrollTop : window.scrollY;
}
// Restore scroll position of the new page (default to 0 if not stored)
const storedY = scrollPositions[location.pathname] ?? 0;
if (el) {
el.scrollTo(0, storedY);
}
else {
window.scrollTo(0, storedY);
}
// Update ref
pathnameRef.current = location.pathname;
}, [location.pathname, target?.current]); // depend on target.current
return null;
}