UNPKG

solid-router

Version:
165 lines (141 loc) 3.86 kB
import { createComponent, ssr, getHydrationKey, ssrSpread, escape } from 'solid-js/dom'; import { createMemoryHistory } from 'history'; import { createSignal, onCleanup, createContext, useContext, createMemo, suspend, sample, createEffect } from 'solid-js'; import { match } from 'path-to-regexp'; const _ck$ = ["children"]; const HistoryContext = createContext(); function ContextProvider(props) { const history = props.history; const [locationSignal, setLocationSignal] = createSignal(history.location); const locationHandler = history.listen(location => { setLocationSignal(location); }); onCleanup(() => { locationHandler(); }); return createComponent(HistoryContext.Provider, { value: { history, locationSignal }, children: () => props.children }, _ck$); } const _ck$$1 = ["children", "history"]; function ServerContextProvider(props) { return createComponent(ContextProvider, { history: () => createMemoryHistory(props.options), children: () => props.children }, _ck$$1); } function getArrayOf(array) { if (Array.isArray(array)) { return array; } if (!!array) { return [array]; } return []; } const RouteContext = createContext(); function useLocationSignal() { const { locationSignal } = useContext(HistoryContext); return locationSignal; } function useRouteMatchSignal(routeOrPath) { const locationSignal = useLocationSignal(); let route; if (typeof routeOrPath === 'string') { route = { path: routeOrPath, options: {} }; } else { route = routeOrPath; } if (!route.path) { route.path = '*'; } const matcher = match(route.path, route.options); return () => { const pathname = locationSignal().pathname; return matcher(pathname); }; } const _ck$$2 = ["children"]; function Router(props) { const routes = getArrayOf(props.children); const routeMatchSignals = routes.map(useRouteMatchSignal); const useFallback = ('fallback' in props); const evalConditions = createMemo(() => { return routeMatchSignals.reduce((result, matcher, index) => { if (result.index === -1) { const match = matcher(); if (match) { return { index, params: match.params }; } } return result; }, { index: -1, params: {} }); }); return suspend(createMemo(() => { const { index, params } = evalConditions(); return sample(() => createComponent(RouteContext.Provider, { value: params, children: () => index < 0 ? useFallback && props.fallback : routes[index].children }, _ck$$2)); })); } function Route(props) { return props; } function useHistory() { const { history } = useContext(HistoryContext); return history; } function Link(props) { const history = useHistory(); return ssr`<a _hk="${getHydrationKey()}" ${ssrSpread(props, false, false)}></a>`; } function Redirect(props) { const history = useHistory(); createEffect(() => { history.push(props.href); }); return props.children; } function NavLink({ href, activeClass = '', className = '', children, options, ...props }) { const history = useHistory(); const routeMatchSignal = useRouteMatchSignal({ path: href, options }); return createMemo(() => { const isMatched = !!routeMatchSignal(); return sample(() => ssr`<a _hk="${getHydrationKey()}" class="${isMatched ? `${className} ${activeClass}` : className}" href="${href}" ${ssrSpread(props, false, true)}>${escape(children)}</a>`); }); } function useParams() { return useContext(RouteContext); } export { ServerContextProvider as ContextProvider, Link, NavLink, Redirect, Route, Router, useHistory, useLocationSignal, useParams, useRouteMatchSignal as useRouteMatchSignalCreator };