@weftui/router 0.26.2 → 0.26.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 +2 -0
- package/dist/client/index.js +6 -0
- package/docs/how-to/add-routing.md +10 -0
- package/docs/reference/router.md +4 -0
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -28,6 +28,8 @@ npm install @weftui/core @weftui/dom @weftui/router effect
|
|
|
28
28
|
| `RouterLive` (client) | History-backed `Router` layer; also provides the `AppRpcClientTag` seam. |
|
|
29
29
|
| `RouterServer` (server) | `RouterServer.render` / `RouterServer.toWebHandler` for SSR dispatch. |
|
|
30
30
|
|
|
31
|
+
Client-side navigation to a different path resets the window scroll to the top at commit; query-only navigations and browser back/forward preserve it (the latter via the browser's native `history.scrollRestoration`).
|
|
32
|
+
|
|
31
33
|
## Example
|
|
32
34
|
|
|
33
35
|
```typescript
|
package/dist/client/index.js
CHANGED
|
@@ -86,6 +86,10 @@ function RouterLive(def, options = {}) {
|
|
|
86
86
|
let committedScope;
|
|
87
87
|
let router;
|
|
88
88
|
const collectPreloads = (m) => m._tag !== "Matched" ? [] : [m.leaf.component, ...m.leaf.layoutChain.map((l) => l.component)].map(getPreload).filter((p) => p !== void 0);
|
|
89
|
+
const pathOf = (url) => {
|
|
90
|
+
const qIndex = url.indexOf("?");
|
|
91
|
+
return qIndex === -1 ? url : url.slice(0, qIndex);
|
|
92
|
+
};
|
|
89
93
|
const commitUrl = (normalized, replace) => Effect.sync(() => {
|
|
90
94
|
if (replace) window.history.replaceState(null, "", normalized);
|
|
91
95
|
else window.history.pushState(null, "", normalized);
|
|
@@ -137,8 +141,10 @@ function RouterLive(def, options = {}) {
|
|
|
137
141
|
url: normalized,
|
|
138
142
|
exit
|
|
139
143
|
});
|
|
144
|
+
const previousUrl = yield* SubscriptionRef.get(urlRef);
|
|
140
145
|
if (pushUrl) yield* commitUrl(normalized, replace);
|
|
141
146
|
yield* SubscriptionRef.set(urlRef, normalized);
|
|
147
|
+
if (pushUrl && pathOf(previousUrl) !== pathOf(normalized)) yield* Effect.sync(() => window.scrollTo(0, 0));
|
|
142
148
|
if (emitted) yield* SubscriptionRef.set(navRef, { _tag: "Idle" });
|
|
143
149
|
});
|
|
144
150
|
const navigate = (to, options) => commitTo(normalizeTo(to), true, options?.replace === true);
|
|
@@ -231,6 +231,16 @@ yield * patchQuery({ sort: "old" }); // merges into the current query
|
|
|
231
231
|
- **`navigate(ref, args)`** builds the URL via [`href`](#type-safe-links-with-href) (so it round-trips with the matcher) and pushes — or, with `{ replace: true }`, replaces — the History entry. `args` follows the same requiredness rules as `href`.
|
|
232
232
|
- **`setQuery` / `patchQuery`** keep the path, so the active leaf is never remounted — pair them with `Router.queryStream` for in-place reactive updates. They are a no-op when no route is matched.
|
|
233
233
|
|
|
234
|
+
### Scroll position on navigation
|
|
235
|
+
|
|
236
|
+
A client navigation whose **path** changes resets the window scroll to the top at commit — matching what a full page load would do, which a raw History `pushState`/`replaceState` otherwise doesn't. This applies uniformly to `Router.navigate`, clicking a link the [interceptor](#link-interception) handles, and the `push` / `replace` helpers.
|
|
237
|
+
|
|
238
|
+
- **Query-only navigations preserve scroll.** `setQuery` / `patchQuery` (and any navigation that keeps the same path) don't reset — the leaf stays mounted, so there's nothing to scroll away from.
|
|
239
|
+
- **Back/forward is untouched.** The router never resets scroll on `popstate`; the browser's native `history.scrollRestoration: "auto"` restores the offset the entry had when the user left it.
|
|
240
|
+
- **Hash navigation (`#section`) is unaffected** — it's browser-native, and the link interceptor already lets same-document/hash-only clicks fall through.
|
|
241
|
+
|
|
242
|
+
There's no opt-out; the behavior is hardwired.
|
|
243
|
+
|
|
234
244
|
## Server setup
|
|
235
245
|
|
|
236
246
|
On the server, `RouterServer` matches a request URL, builds a fixed-match `Router`, renders `RouterApp` to hydratable HTML inside a **document shell**, and reports a status (404 when no route matches or a page raises `RouterNotFound`).
|
package/docs/reference/router.md
CHANGED
|
@@ -258,6 +258,10 @@ yield * push("/users/1/posts?sort=new");
|
|
|
258
258
|
yield * patchQuery({ sort: "old" }); // keeps the current path + other query fields
|
|
259
259
|
```
|
|
260
260
|
|
|
261
|
+
### Scroll reset
|
|
262
|
+
|
|
263
|
+
Every client-committed navigation whose path differs from the previously committed path — `navigate`, `push`, `replace`, and the link interceptor — resets `window.scrollTo(0, 0)` synchronously at commit. Query-only navigations (`setQuery` / `patchQuery`, or any push/replace to the same path) preserve scroll. `popstate` (`back` / `forward`) never resets; the browser's own `history.scrollRestoration: "auto"` restores the prior offset for those entries. Server rendering is unaffected. Not configurable — there is no `NavigateOptions` field to opt out.
|
|
264
|
+
|
|
261
265
|
### `installLinkInterceptor`
|
|
262
266
|
|
|
263
267
|
```typescript
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weftui/router",
|
|
3
|
-
"version": "0.26.
|
|
3
|
+
"version": "0.26.3",
|
|
4
4
|
"description": "Universal nested router for Weft — one route tree, server and client, with type-safe params and href",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"effect",
|
|
@@ -44,10 +44,10 @@
|
|
|
44
44
|
"access": "public"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@effect/platform": "^0.96.
|
|
47
|
+
"@effect/platform": "^0.96.2",
|
|
48
48
|
"@effect/rpc": "^0.75.1",
|
|
49
|
-
"@weftui/
|
|
50
|
-
"@weftui/
|
|
49
|
+
"@weftui/core": "0.26.3",
|
|
50
|
+
"@weftui/dom": "0.26.3"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@types/jsdom": "^28.0.3",
|