@ossy/router-react 1.40.2 → 1.40.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 +42 -4
- package/build/index.js +1 -1
- package/build/types/router-react.d.ts +26 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -8,19 +8,20 @@ The components that want to trigger a navigation only need to be aware of the pa
|
|
|
8
8
|
|
|
9
9
|
Loading of appropriate data is still the responsibility of the component.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Route changes use full navigation (`window.location`). Query-string state on the **same pathname** can be updated client-side via `useSearchParams()` without remounting the page tree.
|
|
12
12
|
|
|
13
13
|
## Features
|
|
14
14
|
- Easy to use
|
|
15
15
|
- Supports single language websites
|
|
16
16
|
- Supports multi language websites with localized paths
|
|
17
17
|
- Supports prerendering (API is only hooks based ATM, API that works for server components is comming)
|
|
18
|
+
- Client-side search param updates on the current page (`useSearchParams`) via `history.pushState`
|
|
18
19
|
|
|
19
20
|
## Roadmap
|
|
20
21
|
- [ ] API that works on server components (non hooks API)
|
|
21
|
-
- [
|
|
22
|
-
- [
|
|
23
|
-
- [
|
|
22
|
+
- [x] Trigger navigation programmatically on the client (`router.navigate()`)
|
|
23
|
+
- [x] Update search params without full navigation (`useSearchParams().set` / `.delete`)
|
|
24
|
+
- [x] Redirects (page `redirect` field)
|
|
24
25
|
|
|
25
26
|
## Table of Contents
|
|
26
27
|
|
|
@@ -39,6 +40,7 @@ This Router is aimed towards websites that want to prerender as much as possible
|
|
|
39
40
|
- [Switching language (same page)](#switching-language-same-page)
|
|
40
41
|
- [Navigating back](#navigating-back)
|
|
41
42
|
- [Redirects](#redirects)
|
|
43
|
+
- [Search params (same page)](#search-params-same-page)
|
|
42
44
|
|
|
43
45
|
## What problem does this package solve?
|
|
44
46
|
When creating links in your app it's not uncommon to hard code the path you want to navigate to.
|
|
@@ -293,6 +295,42 @@ const pages = [
|
|
|
293
295
|
]
|
|
294
296
|
```
|
|
295
297
|
|
|
298
|
+
### Search params (same page)
|
|
299
|
+
|
|
300
|
+
Read and update the query string on the **current pathname** without a full navigation. Use `useSearchParams()` when you only care about query state (storage folders, selected resource `?r=`, auth tokens). Use `useRouter().searchParams` for the same values when you already depend on the full router object.
|
|
301
|
+
|
|
302
|
+
```tsx
|
|
303
|
+
import { useSearchParams, useRouter } from '@ossy/router-react'
|
|
304
|
+
|
|
305
|
+
function StorageBrowser () {
|
|
306
|
+
const searchParams = useSearchParams()
|
|
307
|
+
const location = searchParams.location ?? '/'
|
|
308
|
+
|
|
309
|
+
const openFolder = (path: string) => {
|
|
310
|
+
searchParams.set('location', path.endsWith('/') ? path : `${path}/`)
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const clearSelection = () => {
|
|
314
|
+
searchParams.delete('r')
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return (
|
|
318
|
+
<div>
|
|
319
|
+
<p>Current folder: {location}</p>
|
|
320
|
+
<button type="button" onClick={() => openFolder('/docs/')}>Open docs</button>
|
|
321
|
+
<button type="button" onClick={clearSelection}>Clear selection</button>
|
|
322
|
+
</div>
|
|
323
|
+
)
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
- `set(name, value)` — updates the query via `pushState` and re-renders subscribers. Empty values remove the key.
|
|
328
|
+
- `delete(name)` — removes a query key.
|
|
329
|
+
- Browser back/forward syncs via `popstate`.
|
|
330
|
+
- SSR: pass `url` on `<Router url={requestUrl} />` so the initial query matches the request; on the client, `window.location.search` is followed after hydration.
|
|
331
|
+
|
|
332
|
+
`router.href` reflects the URL at mount; it is not updated on query-only changes. Read query keys from `useSearchParams()` or `router.searchParams`.
|
|
333
|
+
|
|
296
334
|
## Why not open source?
|
|
297
335
|
|
|
298
336
|
TLDR: It might be in the future.
|
package/build/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import n,{createContext as e,useMemo as t,useState as o,useEffect as i,useCallback as r,useContext as a}from"react";import{Router as u,isCatchAllRoutePath as l}from"@ossy/router";var d=function(){return d=Object.assign||function(n){for(var e,t=1,o=arguments.length;t<o;t++)for(var i in e=arguments[t])Object.prototype.hasOwnProperty.call(e,i)&&(n[i]=e[i]);return n},d.apply(this,arguments)};"function"==typeof SuppressedError&&SuppressedError;var c=e({href:"",pages:[],language:void 0,defaultLanguage:void 0,supportedLanguages:[],params:{},navigate:function(){},getHref:function(){return""},back:function(){}}),f=e({set:function(){},delete:function(){}}),s=function(){return a(f)},v=function(){var n=a(c),e=a(f);return t(function(){return d(d({},n),{searchParams:e})},[n,e])},p=function(e){var a,s,v,p,w=e.url,g=e.pages,h=void 0===g?[]:g,m=e.defaultLanguage,y=void 0===m?void 0:m,L=e.supportedLanguages,E=void 0===L?[]:L,P=e.children;if(w){var b=w.match(/([^?#]*)(\?[^#]*)?(#.*)?/);a=w,s=(null==b?void 0:b[1])||"",v=(null==b?void 0:b[3])||"",p=(null==b?void 0:b[2])||""}else{if("undefined"==typeof window)return n.createElement(n.Fragment,null);a=window.location.href,s=window.location.pathname,v=window.location.hash,p=(null==v?void 0:v.includes("?"))?v.split("?")[1]:window.location.search}var S=E.length>1&&!!y,k=s.split("/")[1]||"",R=E.includes(k)?k:y,O=t(function(){return u.of({pages:h,defaultLanguage:y,supportedLanguages:E})},[h,y,E]),U=t(function(){return O.getParamsFromUrl(a)},[O,a]),j=o(function(){return"undefined"==typeof window?p:window.location.search}),F=j[0],H=j[1];i(function(){if("undefined"!=typeof window){var n=function(){return H(window.location.search)};return window.addEventListener("popstate",n),function(){return window.removeEventListener("popstate",n)}}},[]);var x="undefined"==typeof window&&w?p:F,B=new URLSearchParams(x.replace(/^\?/,"")),N=r(function(n){if("undefined"!=typeof window){var e=new URLSearchParams(window.location.search);n(e);var t=e.toString(),o=t?"".concat(window.location.pathname,"?").concat(t):window.location.pathname;window.history.pushState({},"",o),H(window.location.search)}},[]),q=r(function(n,e){N(function(t){null==e||""===e?t.delete(n):t.set(n,e)})},[N]),z=r(function(n){N(function(e){e.delete(n)})},[N]),A=O.getPageByUrl(a);A||(S&&"/"===s&&"undefined"!=typeof window&&(window.location.href="/"+y),A=S?h.find(function(n){var e,t=n.path,o=null!==(e=null==t?void 0:t[R])&&void 0!==e?e:null==t?void 0:t[y];return l(o)}):h.find(function(n){return l(n.path)})),A||console.warn("[RouterReact] No active page found for",s);var C=r(function(n){var e,t,o,i,r,a,u={};if("string"==typeof n?(t=n,u=U,o=R):(a=n).id||void 0===a.language?(t=(null==n?void 0:n.id)||(null==A?void 0:A.id)||"",u=(null==n?void 0:n.params)||U,o=(null==n?void 0:n.language)||R):(t=null!==(e=null==A?void 0:A.id)&&void 0!==e?e:"",u=U,o=n.language),t.includes("#")){var l=t.split("#");if(t=l[0],(i=l[1]).includes("?")){var d=t.split("?");i=d[0],r=d[1]}}else if(t.includes("?")){var c=t.split("?");t=c[0],r=c[1]}var f=O.getPathname({id:t.replace("@",""),params:u,language:o});return i&&(f=f+"#"+i),r&&(f=f+"?"+r),null!=f?f:""},[O,R,U,A]),D=r(function(n){if("undefined"!=typeof window&&n)if("@back"!==n){var e=C(n);e&&(window.location.href=e)}else window.history.back()},[C]),G=r(function(){"undefined"!=typeof window&&window.history.back()},[]),I=t(function(){var n=Object.fromEntries(B.entries());return d(d({},n),{set:q,delete:z})},[F,q,z]),J=t(function(){return{href:a,pages:h,language:R,defaultLanguage:y,supportedLanguages:E,params:U,navigate:D,getHref:C,back:G}},[a,h,R,y,E,U,D,C,G]);(null==A?void 0:A.redirect)&&D({id:A.redirect});var K=t(function(){var n,e;return null!==(n=null==A?void 0:A.element)&&void 0!==n?n:null===(e=null==A?void 0:A.render)||void 0===e?void 0:e.call(A)},[A]);return A?n.createElement(c.Provider,{value:J},n.createElement(f.Provider,{value:I},P||K)):n.createElement(n.Fragment,null)};export{p as Router,c as RouterContext,f as SearchParamsContext,v as useRouter,s as useSearchParams};
|
|
@@ -1,14 +1,37 @@
|
|
|
1
1
|
import React, { PropsWithChildren } from 'react';
|
|
2
2
|
import { MultiLanguagePage, RouterOptions, SingleLanguagePage } from '@ossy/router';
|
|
3
|
-
export
|
|
3
|
+
export interface RouterSearchParams {
|
|
4
|
+
set: (name: string, value: string) => void;
|
|
5
|
+
delete: (name: string) => void;
|
|
6
|
+
}
|
|
7
|
+
type RouterNavigationContextValue = {
|
|
8
|
+
href: string;
|
|
4
9
|
pages: RouterPage[];
|
|
10
|
+
language: string | undefined;
|
|
5
11
|
defaultLanguage: string | undefined;
|
|
6
12
|
supportedLanguages: string[];
|
|
7
|
-
|
|
13
|
+
params: Record<string, string>;
|
|
14
|
+
navigate: (navigationRequest: string | '@back' | GetHrefRequest | GetHrefOfActivePageByLanguageRequest) => void;
|
|
15
|
+
getHref: (getHrefRequest: string | GetHrefRequest | GetHrefOfActivePageByLanguageRequest) => string;
|
|
16
|
+
back: () => void;
|
|
17
|
+
};
|
|
18
|
+
export declare const RouterContext: React.Context<RouterNavigationContextValue>;
|
|
19
|
+
export type RouterSearchParamsState = RouterSearchParams & Record<string, string | undefined>;
|
|
20
|
+
export declare const SearchParamsContext: React.Context<RouterSearchParamsState>;
|
|
21
|
+
/** Query string state — updates on pushState/popstate without remounting the page tree. */
|
|
22
|
+
export declare const useSearchParams: () => RouterSearchParamsState;
|
|
23
|
+
/** Navigation + route params. Stable across query-only URL changes when used without `searchParams`. */
|
|
8
24
|
export declare const useRouter: () => {
|
|
25
|
+
searchParams: RouterSearchParamsState;
|
|
26
|
+
href: string;
|
|
9
27
|
pages: RouterPage[];
|
|
28
|
+
language: string | undefined;
|
|
10
29
|
defaultLanguage: string | undefined;
|
|
11
30
|
supportedLanguages: string[];
|
|
31
|
+
params: Record<string, string>;
|
|
32
|
+
navigate: (navigationRequest: string | "@back" | GetHrefRequest | GetHrefOfActivePageByLanguageRequest) => void;
|
|
33
|
+
getHref: (getHrefRequest: string | GetHrefRequest | GetHrefOfActivePageByLanguageRequest) => string;
|
|
34
|
+
back: () => void;
|
|
12
35
|
};
|
|
13
36
|
export declare const Router: <T extends RouterPage>({ url, pages, defaultLanguage, supportedLanguages, children, }: PropsWithChildren<RouterProps<T>>) => React.JSX.Element;
|
|
14
37
|
export interface RouterProps<T extends RouterPage> extends RouterOptions<T> {
|
|
@@ -49,3 +72,4 @@ export interface GetHrefRequest {
|
|
|
49
72
|
export interface GetHrefOfActivePageByLanguageRequest {
|
|
50
73
|
language: string;
|
|
51
74
|
}
|
|
75
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ossy/router-react",
|
|
3
|
-
"version": "1.40.
|
|
3
|
+
"version": "1.40.3",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/ossy-se/packages.git"
|
|
@@ -65,5 +65,5 @@
|
|
|
65
65
|
"/build",
|
|
66
66
|
"README.md"
|
|
67
67
|
],
|
|
68
|
-
"gitHead": "
|
|
68
|
+
"gitHead": "a0d89185a17f8de8ce328c3a648c108ff1d61d8f"
|
|
69
69
|
}
|