solid-router
Version:
A declarative router for solid-js
206 lines (168 loc) • 4.58 kB
JavaScript
import { createComponent, getNextElement, spread, runHydrationEvents, 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$ = getNextElement(_tmpl$);
_el$.__click = handleClick;
spread(_el$, props, false, false);
runHydrationEvents(_el$.getAttribute("_hk"));
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$ = getNextElement(_tmpl$$1);
_el$.__click = handleClick;
_el$.className = isMatched ? `${className} ${activeClass}` : className;
_el$.setAttribute("href", href);
spread(_el$, props, false, true);
insert(_el$, children, undefined, Array.prototype.slice.call(_el$.childNodes, 0));
runHydrationEvents(_el$.getAttribute("_hk"));
return _el$;
})());
});
}
delegateEvents(["click"]);
function useParams() {
return useContext(RouteContext);
}
export { BrowserContextProvider as ContextProvider, Link, NavLink, Redirect, Route, Router, useHistory, useLocationSignal, useParams, useRouteMatchSignal as useRouteMatchSignalCreator };