@solidjs/router 0.14.1 → 0.14.3

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 CHANGED
@@ -495,11 +495,19 @@ This is light wrapper over `createResource` that aims to serve as stand-in for a
495
495
  const user = createAsync((currentValue) => getUser(params.id))
496
496
  ```
497
497
 
498
+ It also preserves `latest` field from `createResource`. Note that it will be removed in the future.
499
+
500
+ ```jsx
501
+ const user = createAsync((currentValue) => getUser(params.id))
502
+ return <h1>{user.latest.name}</h1>;
503
+ ```
504
+
498
505
  Using `cache` in `createResource` directly won't work properly as the fetcher is not reactive and it won't invalidate properly.
499
506
 
500
507
  ### `createAsyncStore`
501
508
 
502
509
  Similar to `createAsync` except it uses a deeply reactive store. Perfect for applying fine-grained changes to large model data that updates.
510
+ It also supports `latest` field which will be removed in the future.
503
511
 
504
512
  ```jsx
505
513
  const todos = createAsyncStore(() => getTodos());
@@ -727,7 +735,7 @@ This is the main Router component for the browser.
727
735
  | base | string | Base url to use for matching routes |
728
736
  | actionBase | string | Root url for server actions, default: `/_server` |
729
737
  | preload | boolean | Enables/disables preloads globally, default: `true` |
730
- | explicitLinks | boolean | Disables all anchors being intercepted and instead requires `<A>`. default: `false` |
738
+ | explicitLinks | boolean | Disables all anchors being intercepted and instead requires `<A>`. Default: `false`. (To disable interception for a specific link, set `target` to any value, e.g. `<a target="_self">`.) |
731
739
 
732
740
  ### `<A>`
733
741
 
@@ -1,27 +1,32 @@
1
+ import { type ReconcileOptions } from "solid-js/store";
1
2
  /**
2
- * This is mock of the eventual Solid 2.0 primitive. It is not fully featured.
3
+ * As `createAsync` and `createAsyncStore` are wrappers for `createResource`,
4
+ * this type allows to support `latest` field for these primitives.
5
+ * It will be removed in the future.
3
6
  */
4
- import { type Accessor } from "solid-js";
5
- import { type ReconcileOptions } from "solid-js/store";
7
+ export type AccessorWithLatest<T> = {
8
+ (): T;
9
+ latest: T;
10
+ };
6
11
  export declare function createAsync<T>(fn: (prev: T) => Promise<T>, options: {
7
12
  name?: string;
8
13
  initialValue: T;
9
14
  deferStream?: boolean;
10
- }): Accessor<T>;
15
+ }): AccessorWithLatest<T>;
11
16
  export declare function createAsync<T>(fn: (prev: T | undefined) => Promise<T>, options?: {
12
17
  name?: string;
13
18
  initialValue?: T;
14
19
  deferStream?: boolean;
15
- }): Accessor<T | undefined>;
20
+ }): AccessorWithLatest<T | undefined>;
16
21
  export declare function createAsyncStore<T>(fn: (prev: T) => Promise<T>, options: {
17
22
  name?: string;
18
23
  initialValue: T;
19
24
  deferStream?: boolean;
20
25
  reconcile?: ReconcileOptions;
21
- }): Accessor<T>;
26
+ }): AccessorWithLatest<T>;
22
27
  export declare function createAsyncStore<T>(fn: (prev: T | undefined) => Promise<T>, options?: {
23
28
  name?: string;
24
29
  initialValue?: T;
25
30
  deferStream?: boolean;
26
31
  reconcile?: ReconcileOptions;
27
- }): Accessor<T | undefined>;
32
+ }): AccessorWithLatest<T | undefined>;
@@ -8,7 +8,13 @@ export function createAsync(fn, options) {
8
8
  let resource;
9
9
  let prev = () => !resource || resource.state === "unresolved" ? undefined : resource.latest;
10
10
  [resource] = createResource(() => subFetch(fn, untrack(prev)), v => v, options);
11
- return () => resource();
11
+ const resultAccessor = (() => resource());
12
+ Object.defineProperty(resultAccessor, 'latest', {
13
+ get() {
14
+ return resource.latest;
15
+ }
16
+ });
17
+ return resultAccessor;
12
18
  }
13
19
  export function createAsyncStore(fn, options = {}) {
14
20
  let resource;
@@ -17,17 +23,23 @@ export function createAsyncStore(fn, options = {}) {
17
23
  ...options,
18
24
  storage: (init) => createDeepSignal(init, options.reconcile)
19
25
  });
20
- return () => resource();
26
+ const resultAccessor = (() => resource());
27
+ Object.defineProperty(resultAccessor, 'latest', {
28
+ get() {
29
+ return resource.latest;
30
+ }
31
+ });
32
+ return resultAccessor;
21
33
  }
22
34
  function createDeepSignal(value, options) {
23
35
  const [store, setStore] = createStore({
24
- value
36
+ value: structuredClone(value)
25
37
  });
26
38
  return [
27
39
  () => store.value,
28
40
  (v) => {
29
41
  typeof v === "function" && (v = v());
30
- setStore("value", reconcile(v, options));
42
+ setStore("value", reconcile(structuredClone(v), options));
31
43
  return store.value;
32
44
  }
33
45
  ];
@@ -1,4 +1,4 @@
1
- export { createAsync, createAsyncStore } from "./createAsync.js";
1
+ export { createAsync, createAsyncStore, type AccessorWithLatest } from "./createAsync.js";
2
2
  export { action, useSubmission, useSubmissions, useAction, type Action } from "./action.js";
3
3
  export { cache, revalidate, type CachedFunction } from "./cache.js";
4
4
  export { redirect, reload, json } from "./response.js";
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { isServer, getRequestEvent, createComponent as createComponent$1, memo, delegateEvents, spread, mergeProps as mergeProps$1, template } from 'solid-js/web';
2
- import { getOwner, runWithOwner, createMemo, createContext, onCleanup, useContext, untrack, createSignal, createRenderEffect, on, startTransition, resetErrorBoundaries, batch, createComponent, children, mergeProps, Show, createRoot, getListener, sharedConfig, $TRACK, splitProps, createResource } from 'solid-js';
2
+ import { getOwner, runWithOwner, createMemo, createContext, onCleanup, useContext, untrack, createSignal, createRenderEffect, on, startTransition, resetErrorBoundaries, batch, createComponent, children, mergeProps, Show, createRoot, sharedConfig, getListener, $TRACK, splitProps, createResource } from 'solid-js';
3
3
  import { createStore, reconcile, unwrap } from 'solid-js/store';
4
4
 
5
5
  function createBeforeLeave() {
@@ -263,7 +263,7 @@ const useSearchParams = () => {
263
263
  const location = useLocation();
264
264
  const navigate = useNavigate();
265
265
  const setSearchParams = (params, options) => {
266
- const searchString = untrack(() => location.pathname + mergeSearchString(location.search, params) + location.hash);
266
+ const searchString = untrack(() => mergeSearchString(location.search, params) + location.hash);
267
267
  navigate(searchString, {
268
268
  scroll: false,
269
269
  resolve: false,
@@ -520,6 +520,7 @@ function createRouterContext(integration, branches, getContext, options = {}) {
520
520
  }
521
521
  return;
522
522
  }
523
+ const queryOnly = !to || to[0] === "?";
523
524
  const {
524
525
  replace,
525
526
  resolve,
@@ -527,11 +528,12 @@ function createRouterContext(integration, branches, getContext, options = {}) {
527
528
  state: nextState
528
529
  } = {
529
530
  replace: false,
530
- resolve: true,
531
+ resolve: !queryOnly,
531
532
  scroll: true,
532
533
  ...options
533
534
  };
534
- const resolvedTo = resolve ? route.resolvePath(to) : resolvePath("", to);
535
+ let s;
536
+ const resolvedTo = resolve ? route.resolvePath(to) : resolvePath(queryOnly && (s = source().value) && s.split("?")[0] || "", to);
535
537
  if (resolvedTo === undefined) {
536
538
  throw new Error(`Path '${to}' is not a routable path`);
537
539
  } else if (referrers.length >= MAX_REDIRECTS) {
@@ -840,6 +842,7 @@ function createRouter(config) {
840
842
  equals: (a, b) => a.value === b.value && a.state === b.state
841
843
  }), undefined, next => {
842
844
  !ignore && config.set(next);
845
+ if (sharedConfig.registry && !sharedConfig.done) sharedConfig.done = true;
843
846
  return next;
844
847
  });
845
848
  config.init && onCleanup(config.init((value = config.get()) => {
@@ -872,9 +875,8 @@ function getPath(url) {
872
875
  }
873
876
  function StaticRouter(props) {
874
877
  let e;
875
- const url = props.url || (e = getRequestEvent()) && getPath(e.request.url) || "";
876
878
  const obj = {
877
- value: props.transformUrl ? props.transformUrl(url) : url
879
+ value: props.url || (e = getRequestEvent()) && getPath(e.request.url) || ""
878
880
  };
879
881
  return createRouterComponent({
880
882
  signal: [() => obj, next => Object.assign(obj, next)]
@@ -1315,7 +1317,7 @@ function Router(props) {
1315
1317
  const getSource = () => {
1316
1318
  const url = window.location.pathname.replace(/^\/+/, "/") + window.location.search;
1317
1319
  return {
1318
- value: props.transformUrl ? props.transformUrl(url) + window.location.hash : url + window.location.hash,
1320
+ value: url + window.location.hash,
1319
1321
  state: window.history.state
1320
1322
  };
1321
1323
  };
@@ -1521,11 +1523,24 @@ function Navigate(props) {
1521
1523
  /**
1522
1524
  * This is mock of the eventual Solid 2.0 primitive. It is not fully featured.
1523
1525
  */
1526
+
1527
+ /**
1528
+ * As `createAsync` and `createAsyncStore` are wrappers for `createResource`,
1529
+ * this type allows to support `latest` field for these primitives.
1530
+ * It will be removed in the future.
1531
+ */
1532
+
1524
1533
  function createAsync(fn, options) {
1525
1534
  let resource;
1526
1535
  let prev = () => !resource || resource.state === "unresolved" ? undefined : resource.latest;
1527
1536
  [resource] = createResource(() => subFetch(fn, untrack(prev)), v => v, options);
1528
- return () => resource();
1537
+ const resultAccessor = () => resource();
1538
+ Object.defineProperty(resultAccessor, 'latest', {
1539
+ get() {
1540
+ return resource.latest;
1541
+ }
1542
+ });
1543
+ return resultAccessor;
1529
1544
  }
1530
1545
  function createAsyncStore(fn, options = {}) {
1531
1546
  let resource;
@@ -1534,15 +1549,21 @@ function createAsyncStore(fn, options = {}) {
1534
1549
  ...options,
1535
1550
  storage: init => createDeepSignal(init, options.reconcile)
1536
1551
  });
1537
- return () => resource();
1552
+ const resultAccessor = () => resource();
1553
+ Object.defineProperty(resultAccessor, 'latest', {
1554
+ get() {
1555
+ return resource.latest;
1556
+ }
1557
+ });
1558
+ return resultAccessor;
1538
1559
  }
1539
1560
  function createDeepSignal(value, options) {
1540
1561
  const [store, setStore] = createStore({
1541
- value
1562
+ value: structuredClone(value)
1542
1563
  });
1543
1564
  return [() => store.value, v => {
1544
1565
  typeof v === "function" && (v = v());
1545
- setStore("value", reconcile(v, options));
1566
+ setStore("value", reconcile(structuredClone(v), options));
1546
1567
  return store.value;
1547
1568
  }];
1548
1569
  }
@@ -9,7 +9,7 @@ export function Router(props) {
9
9
  const getSource = () => {
10
10
  const url = window.location.pathname.replace(/^\/+/, "/") + window.location.search;
11
11
  return {
12
- value: props.transformUrl ? props.transformUrl(url) + window.location.hash : url + window.location.hash,
12
+ value: url + window.location.hash,
13
13
  state: window.history.state
14
14
  };
15
15
  };
@@ -6,9 +6,8 @@ function getPath(url) {
6
6
  }
7
7
  export function StaticRouter(props) {
8
8
  let e;
9
- const url = props.url || ((e = getRequestEvent()) && getPath(e.request.url)) || "";
10
9
  const obj = {
11
- value: props.transformUrl ? props.transformUrl(url) : url,
10
+ value: props.url || ((e = getRequestEvent()) && getPath(e.request.url)) || "",
12
11
  };
13
12
  return createRouterComponent({
14
13
  signal: [() => obj, next => Object.assign(obj, next)]
@@ -1,4 +1,4 @@
1
- import { createSignal, onCleanup } from "solid-js";
1
+ import { createSignal, onCleanup, sharedConfig } from "solid-js";
2
2
  import { createRouterComponent } from "./components.jsx";
3
3
  function intercept([value, setValue], get, set) {
4
4
  return [get ? () => get(value()) : value, set ? (v) => setValue(set(v)) : setValue];
@@ -22,6 +22,8 @@ export function createRouter(config) {
22
22
  equals: (a, b) => a.value === b.value && a.state === b.state
23
23
  }), undefined, next => {
24
24
  !ignore && config.set(next);
25
+ if (sharedConfig.registry && !sharedConfig.done)
26
+ sharedConfig.done = true;
25
27
  return next;
26
28
  });
27
29
  config.init &&
package/dist/routing.js CHANGED
@@ -41,7 +41,7 @@ export const useSearchParams = () => {
41
41
  const location = useLocation();
42
42
  const navigate = useNavigate();
43
43
  const setSearchParams = (params, options) => {
44
- const searchString = untrack(() => location.pathname + mergeSearchString(location.search, params) + location.hash);
44
+ const searchString = untrack(() => mergeSearchString(location.search, params) + location.hash);
45
45
  navigate(searchString, {
46
46
  scroll: false,
47
47
  resolve: false,
@@ -295,13 +295,17 @@ export function createRouterContext(integration, branches, getContext, options =
295
295
  }
296
296
  return;
297
297
  }
298
+ const queryOnly = !to || to[0] === "?";
298
299
  const { replace, resolve, scroll, state: nextState } = {
299
300
  replace: false,
300
- resolve: true,
301
+ resolve: !queryOnly,
301
302
  scroll: true,
302
303
  ...options
303
304
  };
304
- const resolvedTo = resolve ? route.resolvePath(to) : resolvePath("", to);
305
+ let s;
306
+ const resolvedTo = resolve
307
+ ? route.resolvePath(to)
308
+ : resolvePath((queryOnly && (s = source().value) && s.split("?")[0]) || "", to);
305
309
  if (resolvedTo === undefined) {
306
310
  throw new Error(`Path '${to}' is not a routable path`);
307
311
  }
package/dist/types.d.ts CHANGED
@@ -49,6 +49,7 @@ export interface LocationChange<S = unknown> {
49
49
  replace?: boolean;
50
50
  scroll?: boolean;
51
51
  state?: S;
52
+ rawPath?: string;
52
53
  }
53
54
  export interface RouterIntegration {
54
55
  signal: Signal<LocationChange>;
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "Ryan Turnquist"
7
7
  ],
8
8
  "license": "MIT",
9
- "version": "0.14.1",
9
+ "version": "0.14.3",
10
10
  "homepage": "https://github.com/solidjs/solid-router#readme",
11
11
  "repository": {
12
12
  "type": "git",