@solidjs/router 0.9.1 → 0.10.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +325 -282
- package/dist/components.d.ts +7 -21
- package/dist/components.jsx +23 -30
- package/dist/data/action.d.ts +8 -0
- package/dist/data/action.js +113 -0
- package/dist/data/cache.d.ts +3 -0
- package/dist/data/cache.js +106 -0
- package/dist/data/createAsync.d.ts +5 -0
- package/dist/data/createAsync.js +8 -0
- package/dist/data/index.d.ts +3 -0
- package/dist/data/index.js +3 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +380 -120
- package/dist/index.jsx +2 -1
- package/dist/routing.d.ts +8 -9
- package/dist/routing.js +144 -71
- package/dist/types.d.ts +21 -19
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +1 -0
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isServer, delegateEvents, getRequestEvent, createComponent as createComponent$1, spread, mergeProps as mergeProps$1, template } from 'solid-js/web';
|
|
2
|
-
import { createSignal, onCleanup, getOwner, runWithOwner, createMemo, createContext, useContext, untrack, createRenderEffect,
|
|
2
|
+
import { createSignal, onCleanup, getOwner, runWithOwner, createMemo, createContext, useContext, untrack, createRenderEffect, on, startTransition, createComponent, resetErrorBoundaries, children, createRoot, Show, mergeProps, splitProps, createResource, sharedConfig, $TRACK } from 'solid-js';
|
|
3
|
+
import { createStore, reconcile } from 'solid-js/store';
|
|
3
4
|
|
|
4
5
|
function bindEvent(target, type, handler) {
|
|
5
6
|
target.addEventListener(type, handler);
|
|
@@ -201,6 +202,7 @@ function createBeforeLeave() {
|
|
|
201
202
|
|
|
202
203
|
const hasSchemeRegex = /^(?:[a-z0-9]+:)?\/\//i;
|
|
203
204
|
const trimPathRegex = /^\/+|(\/)\/+$/g;
|
|
205
|
+
const redirectStatusCodes = new Set([204, 301, 302, 303, 307, 308]);
|
|
204
206
|
function normalizePath(path, omitSlash = false) {
|
|
205
207
|
const s = path.replace(trimPathRegex, "$1");
|
|
206
208
|
return s ? omitSlash || /^[?#]/.test(s) ? s : "/" + s : "";
|
|
@@ -353,8 +355,7 @@ const MAX_REDIRECTS = 100;
|
|
|
353
355
|
const RouterContextObj = createContext();
|
|
354
356
|
const RouteContextObj = createContext();
|
|
355
357
|
const useRouter = () => invariant(useContext(RouterContextObj), "Make sure your app is wrapped in a <Router />");
|
|
356
|
-
|
|
357
|
-
const useRoute = () => TempRoute || useContext(RouteContextObj) || useRouter().base;
|
|
358
|
+
const useRoute = () => useContext(RouteContextObj) || useRouter().base;
|
|
358
359
|
const useResolvedPath = path => {
|
|
359
360
|
const route = useRoute();
|
|
360
361
|
return createMemo(() => route.resolvePath(path()));
|
|
@@ -380,7 +381,6 @@ const useMatch = (path, matchFilters) => {
|
|
|
380
381
|
});
|
|
381
382
|
};
|
|
382
383
|
const useParams = () => useRoute().params;
|
|
383
|
-
const useRouteData = () => useRoute().data;
|
|
384
384
|
const useSearchParams = () => {
|
|
385
385
|
const location = useLocation();
|
|
386
386
|
const navigate = useNavigate();
|
|
@@ -402,23 +402,17 @@ const useBeforeLeave = listener => {
|
|
|
402
402
|
});
|
|
403
403
|
onCleanup(s);
|
|
404
404
|
};
|
|
405
|
-
function createRoutes(routeDef, base = ""
|
|
405
|
+
function createRoutes(routeDef, base = "") {
|
|
406
406
|
const {
|
|
407
407
|
component,
|
|
408
|
-
|
|
408
|
+
load,
|
|
409
409
|
children
|
|
410
410
|
} = routeDef;
|
|
411
411
|
const isLeaf = !children || Array.isArray(children) && !children.length;
|
|
412
412
|
const shared = {
|
|
413
413
|
key: routeDef,
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
element
|
|
417
|
-
} = routeDef;
|
|
418
|
-
return element === undefined && fallback ? createComponent(fallback, {}) : element;
|
|
419
|
-
},
|
|
420
|
-
preload: routeDef.component ? component.preload : routeDef.preload,
|
|
421
|
-
data
|
|
414
|
+
component,
|
|
415
|
+
load
|
|
422
416
|
};
|
|
423
417
|
return asArray(routeDef.path).reduce((acc, path) => {
|
|
424
418
|
for (const originalPath of expandOptionals(path)) {
|
|
@@ -458,17 +452,18 @@ function createBranch(routes, index = 0) {
|
|
|
458
452
|
function asArray(value) {
|
|
459
453
|
return Array.isArray(value) ? value : [value];
|
|
460
454
|
}
|
|
461
|
-
function createBranches(routeDef, base = "",
|
|
455
|
+
function createBranches(routeDef, base = "", stack = [], branches = []) {
|
|
462
456
|
const routeDefs = asArray(routeDef);
|
|
463
457
|
for (let i = 0, len = routeDefs.length; i < len; i++) {
|
|
464
458
|
const def = routeDefs[i];
|
|
465
|
-
if (def && typeof def === "object"
|
|
466
|
-
|
|
459
|
+
if (def && typeof def === "object") {
|
|
460
|
+
if (!def.hasOwnProperty("path")) def.path = "";
|
|
461
|
+
const routes = createRoutes(def, base);
|
|
467
462
|
for (const route of routes) {
|
|
468
463
|
stack.push(route);
|
|
469
464
|
const isEmptyArray = Array.isArray(def.children) && def.children.length === 0;
|
|
470
465
|
if (def.children && !isEmptyArray) {
|
|
471
|
-
createBranches(def.children, route.pattern,
|
|
466
|
+
createBranches(def.children, route.pattern, stack, branches);
|
|
472
467
|
} else {
|
|
473
468
|
const branch = createBranch([...stack], branches.length);
|
|
474
469
|
branches.push(branch);
|
|
@@ -526,7 +521,15 @@ function createLocation(path, state) {
|
|
|
526
521
|
query: createMemoObject(on(search, () => extractSearchParams(url())))
|
|
527
522
|
};
|
|
528
523
|
}
|
|
529
|
-
|
|
524
|
+
const actions = new Map();
|
|
525
|
+
function registerAction(url, fn) {
|
|
526
|
+
actions.set(url, fn);
|
|
527
|
+
}
|
|
528
|
+
let intent;
|
|
529
|
+
function getIntent() {
|
|
530
|
+
return intent;
|
|
531
|
+
}
|
|
532
|
+
function createRouterContext(integration, getBranches, base = "") {
|
|
530
533
|
const {
|
|
531
534
|
signal: [source, setSource],
|
|
532
535
|
utils = {}
|
|
@@ -534,11 +537,8 @@ function createRouterContext(integration, base = "", data, out) {
|
|
|
534
537
|
const parsePath = utils.parsePath || (p => p);
|
|
535
538
|
const renderPath = utils.renderPath || (p => p);
|
|
536
539
|
const beforeLeave = utils.beforeLeave || createBeforeLeave();
|
|
540
|
+
let submissions = [];
|
|
537
541
|
const basePath = resolvePath("", base);
|
|
538
|
-
const output = isServer && out ? Object.assign(out, {
|
|
539
|
-
matches: [],
|
|
540
|
-
url: undefined
|
|
541
|
-
}) : undefined;
|
|
542
542
|
if (basePath === undefined) {
|
|
543
543
|
throw new Error(`${basePath} is not a valid base path`);
|
|
544
544
|
} else if (basePath && !source().value) {
|
|
@@ -570,19 +570,6 @@ function createRouterContext(integration, base = "", data, out) {
|
|
|
570
570
|
return resolvePath(basePath, to);
|
|
571
571
|
}
|
|
572
572
|
};
|
|
573
|
-
if (data) {
|
|
574
|
-
try {
|
|
575
|
-
TempRoute = baseRoute;
|
|
576
|
-
baseRoute.data = data({
|
|
577
|
-
data: undefined,
|
|
578
|
-
params: {},
|
|
579
|
-
location,
|
|
580
|
-
navigate: navigatorFactory(baseRoute)
|
|
581
|
-
});
|
|
582
|
-
} finally {
|
|
583
|
-
TempRoute = undefined;
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
573
|
function navigateFromRoute(route, to, options) {
|
|
587
574
|
// Untrack in case someone navigates in an effect - don't want to track `reference` or route paths
|
|
588
575
|
untrack(() => {
|
|
@@ -614,9 +601,6 @@ function createRouterContext(integration, base = "", data, out) {
|
|
|
614
601
|
const current = reference();
|
|
615
602
|
if (resolvedTo !== current || nextState !== state()) {
|
|
616
603
|
if (isServer) {
|
|
617
|
-
if (output) {
|
|
618
|
-
output.url = resolvedTo;
|
|
619
|
-
}
|
|
620
604
|
const e = getRequestEvent();
|
|
621
605
|
e && (e.response = Response.redirect(resolvedTo, 302));
|
|
622
606
|
setSource({
|
|
@@ -633,11 +617,13 @@ function createRouterContext(integration, base = "", data, out) {
|
|
|
633
617
|
state: state()
|
|
634
618
|
});
|
|
635
619
|
start(() => {
|
|
620
|
+
intent = "navigate";
|
|
636
621
|
setReference(resolvedTo);
|
|
637
622
|
setState(nextState);
|
|
638
623
|
resetErrorBoundaries();
|
|
639
624
|
}).then(() => {
|
|
640
625
|
if (referrers.length === len) {
|
|
626
|
+
intent = undefined;
|
|
641
627
|
navigateEnd({
|
|
642
628
|
value: resolvedTo,
|
|
643
629
|
state: nextState
|
|
@@ -675,23 +661,38 @@ function createRouterContext(integration, base = "", data, out) {
|
|
|
675
661
|
untrack(() => {
|
|
676
662
|
if (value !== reference()) {
|
|
677
663
|
start(() => {
|
|
664
|
+
intent = "native";
|
|
678
665
|
setReference(value);
|
|
679
666
|
setState(state);
|
|
667
|
+
}).then(() => {
|
|
668
|
+
intent = undefined;
|
|
680
669
|
});
|
|
681
670
|
}
|
|
682
671
|
});
|
|
683
672
|
});
|
|
684
673
|
if (!isServer) {
|
|
685
|
-
|
|
674
|
+
let preloadTimeout = {};
|
|
675
|
+
function isSvg(el) {
|
|
676
|
+
return el.namespaceURI === "http://www.w3.org/2000/svg";
|
|
677
|
+
}
|
|
678
|
+
function handleAnchor(evt) {
|
|
686
679
|
if (evt.defaultPrevented || evt.button !== 0 || evt.metaKey || evt.altKey || evt.ctrlKey || evt.shiftKey) return;
|
|
687
680
|
const a = evt.composedPath().find(el => el instanceof Node && el.nodeName.toUpperCase() === "A");
|
|
688
|
-
if (!a
|
|
689
|
-
const
|
|
690
|
-
|
|
681
|
+
if (!a) return;
|
|
682
|
+
const svg = isSvg(a);
|
|
683
|
+
const href = svg ? a.href.baseVal : a.href;
|
|
684
|
+
const target = svg ? a.target.baseVal : a.target;
|
|
685
|
+
if (target || !href && !a.hasAttribute("state")) return;
|
|
691
686
|
const rel = (a.getAttribute("rel") || "").split(/\s+/);
|
|
692
687
|
if (a.hasAttribute("download") || rel && rel.includes("external")) return;
|
|
693
|
-
const url = new URL(href);
|
|
688
|
+
const url = svg ? new URL(href, document.baseURI) : new URL(href);
|
|
694
689
|
if (url.origin !== window.location.origin || basePath && url.pathname && !url.pathname.toLowerCase().startsWith(basePath.toLowerCase())) return;
|
|
690
|
+
return [a, url];
|
|
691
|
+
}
|
|
692
|
+
function handleAnchorClick(evt) {
|
|
693
|
+
const res = handleAnchor(evt);
|
|
694
|
+
if (!res) return;
|
|
695
|
+
const [a, url] = res;
|
|
695
696
|
const to = parsePath(url.pathname + url.search + url.hash);
|
|
696
697
|
const state = a.getAttribute("state");
|
|
697
698
|
evt.preventDefault();
|
|
@@ -702,94 +703,166 @@ function createRouterContext(integration, base = "", data, out) {
|
|
|
702
703
|
state: state && JSON.parse(state)
|
|
703
704
|
});
|
|
704
705
|
}
|
|
706
|
+
function doPreload(a, path) {
|
|
707
|
+
const preload = a.getAttribute("preload") !== "false";
|
|
708
|
+
const matches = getRouteMatches(getBranches(), path);
|
|
709
|
+
const prevIntent = intent;
|
|
710
|
+
intent = "preload";
|
|
711
|
+
for (let match in matches) {
|
|
712
|
+
const {
|
|
713
|
+
route,
|
|
714
|
+
params
|
|
715
|
+
} = matches[match];
|
|
716
|
+
route.component && route.component.preload && route.component.preload();
|
|
717
|
+
preload && route.load && route.load({
|
|
718
|
+
params,
|
|
719
|
+
location
|
|
720
|
+
});
|
|
721
|
+
}
|
|
722
|
+
intent = prevIntent;
|
|
723
|
+
}
|
|
724
|
+
function handleAnchorPreload(evt) {
|
|
725
|
+
const res = handleAnchor(evt);
|
|
726
|
+
if (!res) return;
|
|
727
|
+
const [a, url] = res;
|
|
728
|
+
if (!preloadTimeout[url.pathname]) doPreload(a, url.pathname);
|
|
729
|
+
}
|
|
730
|
+
function handleAnchorIn(evt) {
|
|
731
|
+
const res = handleAnchor(evt);
|
|
732
|
+
if (!res) return;
|
|
733
|
+
const [a, url] = res;
|
|
734
|
+
if (preloadTimeout[url.pathname]) return;
|
|
735
|
+
preloadTimeout[url.pathname] = setTimeout(() => {
|
|
736
|
+
doPreload(a, url.pathname);
|
|
737
|
+
delete preloadTimeout[url.pathname];
|
|
738
|
+
}, 50);
|
|
739
|
+
}
|
|
740
|
+
function handleAnchorOut(evt) {
|
|
741
|
+
const res = handleAnchor(evt);
|
|
742
|
+
if (!res) return;
|
|
743
|
+
const [, url] = res;
|
|
744
|
+
if (preloadTimeout[url.pathname]) {
|
|
745
|
+
clearTimeout(preloadTimeout[url.pathname]);
|
|
746
|
+
delete preloadTimeout[url.pathname];
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
function handleFormSubmit(evt) {
|
|
750
|
+
let actionRef = evt.submitter && evt.submitter.getAttribute("formaction") || evt.target.action;
|
|
751
|
+
if (actionRef && actionRef.startsWith("action:")) {
|
|
752
|
+
const data = new FormData(evt.target);
|
|
753
|
+
actions.get(actionRef.slice(7))(data);
|
|
754
|
+
evt.preventDefault();
|
|
755
|
+
}
|
|
756
|
+
}
|
|
705
757
|
|
|
706
|
-
// ensure delegated
|
|
707
|
-
delegateEvents(["click"]);
|
|
758
|
+
// ensure delegated event run first
|
|
759
|
+
delegateEvents(["click", "submit"]);
|
|
708
760
|
document.addEventListener("click", handleAnchorClick);
|
|
709
|
-
|
|
761
|
+
document.addEventListener("mouseover", handleAnchorIn);
|
|
762
|
+
document.addEventListener("mouseout", handleAnchorOut);
|
|
763
|
+
document.addEventListener("focusin", handleAnchorPreload);
|
|
764
|
+
document.addEventListener("touchstart", handleAnchorPreload);
|
|
765
|
+
document.addEventListener("submit", handleFormSubmit);
|
|
766
|
+
onCleanup(() => {
|
|
767
|
+
document.removeEventListener("click", handleAnchorClick);
|
|
768
|
+
document.removeEventListener("mouseover", handleAnchorIn);
|
|
769
|
+
document.removeEventListener("mouseout", handleAnchorOut);
|
|
770
|
+
document.removeEventListener("focusin", handleAnchorPreload);
|
|
771
|
+
document.removeEventListener("touchstart", handleAnchorPreload);
|
|
772
|
+
document.removeEventListener("submit", handleFormSubmit);
|
|
773
|
+
});
|
|
774
|
+
} else {
|
|
775
|
+
function initFromFlash(params) {
|
|
776
|
+
let param = params.form ? JSON.parse(params.form) : null;
|
|
777
|
+
if (!param || !param.result) {
|
|
778
|
+
return [];
|
|
779
|
+
}
|
|
780
|
+
const input = new Map(param.entries);
|
|
781
|
+
return [{
|
|
782
|
+
url: param.url,
|
|
783
|
+
result: param.error ? new Error(param.result.message) : param.result,
|
|
784
|
+
input: input
|
|
785
|
+
}];
|
|
786
|
+
}
|
|
787
|
+
submissions = initFromFlash(location.query);
|
|
710
788
|
}
|
|
711
789
|
return {
|
|
712
790
|
base: baseRoute,
|
|
713
|
-
out: output,
|
|
714
791
|
location,
|
|
715
792
|
isRouting,
|
|
716
793
|
renderPath,
|
|
717
794
|
parsePath,
|
|
718
795
|
navigatorFactory,
|
|
719
|
-
beforeLeave
|
|
796
|
+
beforeLeave,
|
|
797
|
+
submissions: createSignal(submissions)
|
|
720
798
|
};
|
|
721
799
|
}
|
|
722
|
-
function createRouteContext(router, parent,
|
|
800
|
+
function createRouteContext(router, parent, outlet, match, params) {
|
|
723
801
|
const {
|
|
724
802
|
base,
|
|
725
|
-
location
|
|
726
|
-
navigatorFactory
|
|
803
|
+
location
|
|
727
804
|
} = router;
|
|
728
805
|
const {
|
|
729
806
|
pattern,
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
data
|
|
807
|
+
component,
|
|
808
|
+
load
|
|
733
809
|
} = match().route;
|
|
734
810
|
const path = createMemo(() => match().path);
|
|
735
|
-
preload && preload();
|
|
736
811
|
const route = {
|
|
737
812
|
parent,
|
|
738
813
|
pattern,
|
|
739
|
-
get child() {
|
|
740
|
-
return child();
|
|
741
|
-
},
|
|
742
814
|
path,
|
|
743
815
|
params,
|
|
744
|
-
|
|
745
|
-
|
|
816
|
+
outlet: () => component ? createComponent(component, {
|
|
817
|
+
params,
|
|
818
|
+
location,
|
|
819
|
+
get children() {
|
|
820
|
+
return outlet();
|
|
821
|
+
}
|
|
822
|
+
}) : outlet(),
|
|
746
823
|
resolvePath(to) {
|
|
747
824
|
return resolvePath(base.path(), to, path());
|
|
748
825
|
}
|
|
749
826
|
};
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
params,
|
|
756
|
-
location,
|
|
757
|
-
navigate: navigatorFactory(route)
|
|
758
|
-
});
|
|
759
|
-
} finally {
|
|
760
|
-
TempRoute = undefined;
|
|
761
|
-
}
|
|
762
|
-
}
|
|
827
|
+
component && component.preload && component.preload();
|
|
828
|
+
load && load({
|
|
829
|
+
params,
|
|
830
|
+
location
|
|
831
|
+
});
|
|
763
832
|
return route;
|
|
764
833
|
}
|
|
765
834
|
|
|
766
|
-
const _tmpl$ = /*#__PURE__*/template(`<a
|
|
835
|
+
const _tmpl$ = /*#__PURE__*/template(`<a></a>`, 2);
|
|
767
836
|
const Router = props => {
|
|
768
837
|
let e;
|
|
769
838
|
const {
|
|
770
839
|
source,
|
|
771
840
|
url,
|
|
772
|
-
base
|
|
773
|
-
data,
|
|
774
|
-
out
|
|
841
|
+
base
|
|
775
842
|
} = props;
|
|
776
843
|
const integration = source || (isServer ? staticIntegration({
|
|
777
844
|
value: url || (e = getRequestEvent()) && e.request.url || ""
|
|
778
845
|
}) : pathIntegration());
|
|
779
|
-
const
|
|
846
|
+
const routeDefs = children(() => props.root ? {
|
|
847
|
+
component: props.root,
|
|
848
|
+
children: props.children
|
|
849
|
+
} : props.children);
|
|
850
|
+
const branches = createMemo(() => createBranches(routeDefs(), props.base || ""));
|
|
851
|
+
const routerState = createRouterContext(integration, branches, base);
|
|
780
852
|
return createComponent$1(RouterContextObj.Provider, {
|
|
781
853
|
value: routerState,
|
|
782
854
|
get children() {
|
|
783
|
-
return
|
|
855
|
+
return createComponent$1(Routes, {
|
|
856
|
+
routerState: routerState,
|
|
857
|
+
get branches() {
|
|
858
|
+
return branches();
|
|
859
|
+
}
|
|
860
|
+
});
|
|
784
861
|
}
|
|
785
862
|
});
|
|
786
863
|
};
|
|
787
|
-
|
|
788
|
-
const
|
|
789
|
-
const parentRoute = useRoute();
|
|
790
|
-
const routeDefs = children(() => props.children);
|
|
791
|
-
const branches = createMemo(() => createBranches(routeDefs(), joinPaths(parentRoute.pattern, props.base || ""), Outlet));
|
|
792
|
-
const matches = createMemo(() => getRouteMatches(branches(), router.location.pathname));
|
|
864
|
+
function Routes(props) {
|
|
865
|
+
const matches = createMemo(() => getRouteMatches(props.branches, props.routerState.location.pathname));
|
|
793
866
|
const params = createMemoObject(() => {
|
|
794
867
|
const m = matches();
|
|
795
868
|
const params = {};
|
|
@@ -798,18 +871,6 @@ const Routes = props => {
|
|
|
798
871
|
}
|
|
799
872
|
return params;
|
|
800
873
|
});
|
|
801
|
-
if (router.out) {
|
|
802
|
-
router.out.matches.push(matches().map(({
|
|
803
|
-
route,
|
|
804
|
-
path,
|
|
805
|
-
params
|
|
806
|
-
}) => ({
|
|
807
|
-
originalPath: route.originalPath,
|
|
808
|
-
pattern: route.pattern,
|
|
809
|
-
path,
|
|
810
|
-
params
|
|
811
|
-
})));
|
|
812
|
-
}
|
|
813
874
|
const disposers = [];
|
|
814
875
|
let root;
|
|
815
876
|
const routeStates = createMemo(on(matches, (nextMatches, prevMatches, prev) => {
|
|
@@ -827,7 +888,7 @@ const Routes = props => {
|
|
|
827
888
|
}
|
|
828
889
|
createRoot(dispose => {
|
|
829
890
|
disposers[i] = dispose;
|
|
830
|
-
next[i] = createRouteContext(
|
|
891
|
+
next[i] = createRouteContext(props.routerState, next[i - 1] || props.routerState.base, createOutlet(() => routeStates()[i + 1]), () => matches()[i], params);
|
|
831
892
|
});
|
|
832
893
|
}
|
|
833
894
|
}
|
|
@@ -850,26 +911,11 @@ const Routes = props => {
|
|
|
850
911
|
}
|
|
851
912
|
})
|
|
852
913
|
});
|
|
853
|
-
}
|
|
854
|
-
const
|
|
855
|
-
return () => createComponent$1(
|
|
856
|
-
base: base,
|
|
857
|
-
children: routes
|
|
858
|
-
});
|
|
859
|
-
};
|
|
860
|
-
const Route = props => {
|
|
861
|
-
const childRoutes = children(() => props.children);
|
|
862
|
-
return mergeProps(props, {
|
|
863
|
-
get children() {
|
|
864
|
-
return childRoutes();
|
|
865
|
-
}
|
|
866
|
-
});
|
|
867
|
-
};
|
|
868
|
-
const Outlet = () => {
|
|
869
|
-
const route = useRoute();
|
|
870
|
-
return createComponent$1(Show, {
|
|
914
|
+
}
|
|
915
|
+
const createOutlet = child => {
|
|
916
|
+
return () => createComponent$1(Show, {
|
|
871
917
|
get when() {
|
|
872
|
-
return
|
|
918
|
+
return child();
|
|
873
919
|
},
|
|
874
920
|
keyed: true,
|
|
875
921
|
children: child => createComponent$1(RouteContextObj.Provider, {
|
|
@@ -880,6 +926,14 @@ const Outlet = () => {
|
|
|
880
926
|
})
|
|
881
927
|
});
|
|
882
928
|
};
|
|
929
|
+
const Route = props => {
|
|
930
|
+
const childRoutes = children(() => props.children);
|
|
931
|
+
return mergeProps(props, {
|
|
932
|
+
get children() {
|
|
933
|
+
return childRoutes();
|
|
934
|
+
}
|
|
935
|
+
});
|
|
936
|
+
};
|
|
883
937
|
function A(props) {
|
|
884
938
|
props = mergeProps({
|
|
885
939
|
inactiveClass: "inactive",
|
|
@@ -897,7 +951,7 @@ function A(props) {
|
|
|
897
951
|
return props.end ? path === loc : loc.startsWith(path);
|
|
898
952
|
});
|
|
899
953
|
return (() => {
|
|
900
|
-
const _el$ = _tmpl
|
|
954
|
+
const _el$ = _tmpl$.cloneNode(true);
|
|
901
955
|
spread(_el$, mergeProps$1(rest, {
|
|
902
956
|
get href() {
|
|
903
957
|
return href() || props.href;
|
|
@@ -940,4 +994,210 @@ function Navigate(props) {
|
|
|
940
994
|
return null;
|
|
941
995
|
}
|
|
942
996
|
|
|
943
|
-
|
|
997
|
+
/**
|
|
998
|
+
* This is mock of the eventual Solid 2.0 primitive. It is not fully featured.
|
|
999
|
+
*/
|
|
1000
|
+
function createAsync(fn) {
|
|
1001
|
+
const [resource] = createResource(() => fn(), v => v);
|
|
1002
|
+
return () => resource();
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
const LocationHeader = "Location";
|
|
1006
|
+
const PRELOAD_TIMEOUT = 5000;
|
|
1007
|
+
let cacheMap = new Map();
|
|
1008
|
+
function getCache() {
|
|
1009
|
+
if (!isServer) return cacheMap;
|
|
1010
|
+
const req = getRequestEvent() || sharedConfig.context;
|
|
1011
|
+
return req.routerCache || (req.routerCache = new Map());
|
|
1012
|
+
}
|
|
1013
|
+
function revalidate(key) {
|
|
1014
|
+
return startTransition(() => {
|
|
1015
|
+
const now = Date.now();
|
|
1016
|
+
for (let k of cacheMap.keys()) {
|
|
1017
|
+
if (key === undefined || k === key) {
|
|
1018
|
+
const set = cacheMap.get(k)[3];
|
|
1019
|
+
revalidateSignals(set, now);
|
|
1020
|
+
cacheMap.delete(k);
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
});
|
|
1024
|
+
}
|
|
1025
|
+
function revalidateSignals(set, time) {
|
|
1026
|
+
for (let s of set) s[1](time);
|
|
1027
|
+
}
|
|
1028
|
+
function cache(fn, name, options) {
|
|
1029
|
+
const [store, setStore] = createStore({});
|
|
1030
|
+
return (...args) => {
|
|
1031
|
+
const cache = getCache();
|
|
1032
|
+
const intent = getIntent();
|
|
1033
|
+
const owner = getOwner();
|
|
1034
|
+
const navigate = owner ? useNavigate() : undefined;
|
|
1035
|
+
const now = Date.now();
|
|
1036
|
+
const key = name + (args.length ? ":" + args.join(":") : "");
|
|
1037
|
+
let cached = cache.get(key);
|
|
1038
|
+
let version;
|
|
1039
|
+
if (owner) {
|
|
1040
|
+
version = createSignal(now, {
|
|
1041
|
+
equals: (p, v) => v - p < 50 // margin of error
|
|
1042
|
+
});
|
|
1043
|
+
|
|
1044
|
+
onCleanup(() => cached[3].delete(version));
|
|
1045
|
+
version[0](); // track it;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
if (cached && (isServer || intent === "native" || Date.now() - cached[0] < PRELOAD_TIMEOUT)) {
|
|
1049
|
+
version && cached[3].add(version);
|
|
1050
|
+
if (cached[2] === "preload" && intent !== "preload") {
|
|
1051
|
+
cached[0] = now;
|
|
1052
|
+
cached[1] = "then" in cached[1] ? cached[1].then(handleResponse) : handleResponse(cached[1]);
|
|
1053
|
+
cached[2] = intent;
|
|
1054
|
+
}
|
|
1055
|
+
if (!isServer && intent === "navigate") {
|
|
1056
|
+
startTransition(() => revalidateSignals(cached[3], cached[0])); // update version
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
return cached[1];
|
|
1060
|
+
}
|
|
1061
|
+
let res = fn(...args);
|
|
1062
|
+
if (intent !== "preload") {
|
|
1063
|
+
res = "then" in res ? res.then(handleResponse) : handleResponse(res);
|
|
1064
|
+
}
|
|
1065
|
+
if (cached) {
|
|
1066
|
+
cached[0] = now;
|
|
1067
|
+
cached[1] = res;
|
|
1068
|
+
cached[2] = intent;
|
|
1069
|
+
version && cached[3].add(version);
|
|
1070
|
+
if (!isServer && intent === "navigate") {
|
|
1071
|
+
startTransition(() => revalidateSignals(cached[3], cached[0])); // update version
|
|
1072
|
+
}
|
|
1073
|
+
} else cache.set(key, cached = [now, res, intent, new Set(version ? [version] : [])]);
|
|
1074
|
+
return res;
|
|
1075
|
+
function handleRedirect(response) {
|
|
1076
|
+
startTransition(() => {
|
|
1077
|
+
let url = response.headers.get(LocationHeader);
|
|
1078
|
+
if (url && url.startsWith("/")) {
|
|
1079
|
+
navigate(url, {
|
|
1080
|
+
replace: true
|
|
1081
|
+
});
|
|
1082
|
+
} else if (!isServer && url) {
|
|
1083
|
+
window.location.href = url;
|
|
1084
|
+
}
|
|
1085
|
+
});
|
|
1086
|
+
}
|
|
1087
|
+
function handleResponse(v) {
|
|
1088
|
+
if (v instanceof Response && redirectStatusCodes.has(v.status)) {
|
|
1089
|
+
if (navigate) isServer ? handleRedirect(v) : setTimeout(() => handleRedirect(v), 0);
|
|
1090
|
+
return;
|
|
1091
|
+
}
|
|
1092
|
+
setStore(key, reconcile(v, options));
|
|
1093
|
+
return store[key];
|
|
1094
|
+
}
|
|
1095
|
+
};
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
function useSubmissions(fn, filter) {
|
|
1099
|
+
const router = useRouter();
|
|
1100
|
+
const subs = createMemo(() => router.submissions[0]().filter(s => s.url === fn.toString() && (!filter || filter(s.input))));
|
|
1101
|
+
return new Proxy([], {
|
|
1102
|
+
get(_, property) {
|
|
1103
|
+
if (property === $TRACK) return subs();
|
|
1104
|
+
if (property === "pending") return subs().some(sub => !sub.result);
|
|
1105
|
+
return subs()[property];
|
|
1106
|
+
}
|
|
1107
|
+
});
|
|
1108
|
+
}
|
|
1109
|
+
function useSubmission(fn, filter) {
|
|
1110
|
+
const submissions = useSubmissions(fn, filter);
|
|
1111
|
+
return {
|
|
1112
|
+
get clear() {
|
|
1113
|
+
return submissions[0]?.clear;
|
|
1114
|
+
},
|
|
1115
|
+
get retry() {
|
|
1116
|
+
return submissions[0]?.retry;
|
|
1117
|
+
},
|
|
1118
|
+
get url() {
|
|
1119
|
+
return submissions[0]?.url;
|
|
1120
|
+
},
|
|
1121
|
+
get input() {
|
|
1122
|
+
return submissions[0]?.input;
|
|
1123
|
+
},
|
|
1124
|
+
get result() {
|
|
1125
|
+
return submissions[0]?.result;
|
|
1126
|
+
},
|
|
1127
|
+
get pending() {
|
|
1128
|
+
return submissions[0]?.pending;
|
|
1129
|
+
}
|
|
1130
|
+
};
|
|
1131
|
+
}
|
|
1132
|
+
function action(fn, name) {
|
|
1133
|
+
function mutate(variables) {
|
|
1134
|
+
const p = fn(variables);
|
|
1135
|
+
const [result, setResult] = createSignal();
|
|
1136
|
+
let submission;
|
|
1137
|
+
const router = this;
|
|
1138
|
+
router.submissions[1](s => [...s, submission = {
|
|
1139
|
+
input: variables,
|
|
1140
|
+
url,
|
|
1141
|
+
get result() {
|
|
1142
|
+
return result()?.data;
|
|
1143
|
+
},
|
|
1144
|
+
get pending() {
|
|
1145
|
+
return !result();
|
|
1146
|
+
},
|
|
1147
|
+
clear() {
|
|
1148
|
+
router.submissions[1](v => v.filter(i => i.input !== variables));
|
|
1149
|
+
},
|
|
1150
|
+
retry() {
|
|
1151
|
+
setResult(undefined);
|
|
1152
|
+
const p = fn(variables);
|
|
1153
|
+
p.then(async data => {
|
|
1154
|
+
const keys = handleResponse(data, router.navigatorFactory());
|
|
1155
|
+
await revalidate(keys);
|
|
1156
|
+
data ? setResult({
|
|
1157
|
+
data
|
|
1158
|
+
}) : submission.clear();
|
|
1159
|
+
return data;
|
|
1160
|
+
}).catch(error => {
|
|
1161
|
+
setResult({
|
|
1162
|
+
data: error
|
|
1163
|
+
});
|
|
1164
|
+
});
|
|
1165
|
+
return p;
|
|
1166
|
+
}
|
|
1167
|
+
}]);
|
|
1168
|
+
p.then(async data => {
|
|
1169
|
+
const keys = handleResponse(data, router.navigatorFactory());
|
|
1170
|
+
await revalidate(keys);
|
|
1171
|
+
data ? setResult({
|
|
1172
|
+
data
|
|
1173
|
+
}) : submission.clear();
|
|
1174
|
+
return data;
|
|
1175
|
+
}).catch(error => {
|
|
1176
|
+
setResult({
|
|
1177
|
+
data: error
|
|
1178
|
+
});
|
|
1179
|
+
});
|
|
1180
|
+
return p;
|
|
1181
|
+
}
|
|
1182
|
+
const url = fn.url || `action:${name}` || !isServer ? `action:${fn.name}` : "";
|
|
1183
|
+
mutate.toString = () => {
|
|
1184
|
+
if (!url) throw new Error("Client Actions need explicit names if server rendered");
|
|
1185
|
+
return url;
|
|
1186
|
+
};
|
|
1187
|
+
if (!isServer) registerAction(url, mutate);
|
|
1188
|
+
return mutate;
|
|
1189
|
+
}
|
|
1190
|
+
function handleResponse(response, navigate) {
|
|
1191
|
+
if (response instanceof Response && redirectStatusCodes.has(response.status)) {
|
|
1192
|
+
const locationUrl = response.headers.get("Location") || "/";
|
|
1193
|
+
if (locationUrl.startsWith("http")) {
|
|
1194
|
+
window.location.href = locationUrl;
|
|
1195
|
+
} else {
|
|
1196
|
+
navigate(locationUrl);
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
// return keys
|
|
1200
|
+
return;
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
export { A, A as Link, A as NavLink, Navigate, Route, Router, mergeSearchString as _mergeSearchString, action, cache, createAsync, createBeforeLeave, createIntegration, createMemoryHistory, hashIntegration, memoryIntegration, normalizeIntegration, pathIntegration, revalidate, staticIntegration, useBeforeLeave, useHref, useIsRouting, useLocation, useMatch, useNavigate, useParams, useResolvedPath, useSearchParams, useSubmission, useSubmissions };
|