@solidjs/router 0.9.0 → 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/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, createComponent, on, startTransition, resetErrorBoundaries, children, createRoot, Show, mergeProps, splitProps } from 'solid-js';
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
- let TempRoute;
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 = "", fallback) {
405
+ function createRoutes(routeDef, base = "") {
406
406
  const {
407
407
  component,
408
- data,
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
- element: component ? () => createComponent(component, {}) : () => {
415
- const {
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 = "", fallback, stack = [], branches = []) {
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" && def.hasOwnProperty("path")) {
466
- const routes = createRoutes(def, base, fallback);
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, fallback, stack, branches);
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
- function createRouterContext(integration, base = "", data, out) {
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
- function handleAnchorClick(evt) {
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 || !a.hasAttribute("link")) return;
689
- const href = a.href;
690
- if (a.target || !href && !a.hasAttribute("state")) return;
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 events run first
707
- delegateEvents(["click"]);
758
+ // ensure delegated event run first
759
+ delegateEvents(["click", "submit"]);
708
760
  document.addEventListener("click", handleAnchorClick);
709
- onCleanup(() => document.removeEventListener("click", handleAnchorClick));
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, child, match, params) {
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
- element: outlet,
731
- preload,
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
- data: parent.data,
745
- outlet,
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
- if (data) {
751
- try {
752
- TempRoute = route;
753
- route.data = data({
754
- data: parent.data,
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 link>`);
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 routerState = createRouterContext(integration, base, data, out);
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 props.children;
855
+ return createComponent$1(Routes, {
856
+ routerState: routerState,
857
+ get branches() {
858
+ return branches();
859
+ }
860
+ });
784
861
  }
785
862
  });
786
863
  };
787
- const Routes = props => {
788
- const router = useRouter();
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(router, next[i - 1] || parentRoute, () => routeStates()[i + 1], () => matches()[i], params);
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 useRoutes = (routes, base) => {
855
- return () => createComponent$1(Routes, {
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 route.child;
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
- export { A, A as Link, A as NavLink, Navigate, Outlet, Route, Router, Routes, mergeSearchString as _mergeSearchString, createBeforeLeave, createIntegration, createMemoryHistory, hashIntegration, memoryIntegration, normalizeIntegration, pathIntegration, staticIntegration, useBeforeLeave, useHref, useIsRouting, useLocation, useMatch, useNavigate, useParams, useResolvedPath, useRouteData, useRoutes, useSearchParams };
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 };