UNPKG

rasengan

Version:

The modern React Framework

166 lines (165 loc) 5.26 kB
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; }