UNPKG

solid-router

Version:
202 lines (166 loc) 4.38 kB
import { createComponent, spread, template, delegateEvents, insert } from 'solid-js/dom'; import { createBrowserHistory } 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 BrowserContextProvider(props) { return createComponent(ContextProvider, { history: () => createBrowserHistory(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; } const _tmpl$ = template(`<a></a>`, 2); function Link(props) { const history = useHistory(); function handleClick(e) { e.preventDefault(); history.push(props.href); } return (() => { const _el$ = _tmpl$.cloneNode(true); _el$.__click = handleClick; spread(_el$, props, false, false); return _el$; })(); } delegateEvents(["click"]); function Redirect(props) { const history = useHistory(); createEffect(() => { history.push(props.href); }); return props.children; } const _tmpl$$1 = template(`<a></a>`, 2); function NavLink({ href, activeClass = '', className = '', children, options, ...props }) { const history = useHistory(); const routeMatchSignal = useRouteMatchSignal({ path: href, options }); function handleClick(e) { e.preventDefault(); history.push(href); } return createMemo(() => { const isMatched = !!routeMatchSignal(); return sample(() => (() => { const _el$ = _tmpl$$1.cloneNode(true); _el$.__click = handleClick; _el$.className = isMatched ? `${className} ${activeClass}` : className; _el$.setAttribute("href", href); spread(_el$, props, false, true); insert(_el$, children); return _el$; })()); }); } delegateEvents(["click"]); function useParams() { return useContext(RouteContext); } export { BrowserContextProvider as ContextProvider, Link, NavLink, Redirect, Route, Router, useHistory, useLocationSignal, useParams, useRouteMatchSignal as useRouteMatchSignalCreator };