@real-router/solid 0.10.0 → 0.11.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 CHANGED
@@ -372,7 +372,7 @@ Opt-in preservation of scroll position across navigations:
372
372
  </RouterProvider>
373
373
  ```
374
374
 
375
- Restores scroll on back/forward, scrolls to top (or `#hash`) on push. Three modes: `"restore"` (default), `"top"`, `"manual"`. Custom containers via `scrollContainer: () => HTMLElement | null`. Options are read once on mount — changing the prop at runtime does not reconfigure the utility (Solid `onMount` is non-reactive). See [Scroll Restoration guide](https://github.com/greydragon888/real-router/wiki/Scroll-Restoration) for details.
375
+ Restores scroll on back/forward, scrolls to top (or `#hash`) on push. Three modes: `"restore"` (default), `"top"`, `"native"`. Custom containers via `scrollContainer: () => HTMLElement | null`. Options are read once on mount — changing the prop at runtime does not reconfigure the utility (Solid `onMount` is non-reactive). See [Scroll Restoration guide](https://github.com/greydragon888/real-router/wiki/Scroll-Restoration) for details.
376
376
 
377
377
  ## View Transitions
378
378
 
@@ -273,11 +273,32 @@ interface UseRouteEnterOptions {
273
273
  */
274
274
  declare function useRouteEnter(handler: RouteEnterHandler, options?: UseRouteEnterOptions): void;
275
275
 
276
- type ScrollRestorationMode = "restore" | "top" | "manual";
276
+ type ScrollRestorationMode = "restore" | "top" | "native";
277
277
  interface ScrollRestorationOptions {
278
278
  mode?: ScrollRestorationMode | undefined;
279
279
  anchorScrolling?: boolean | undefined;
280
280
  scrollContainer?: (() => HTMLElement | null) | undefined;
281
+ /**
282
+ * Scroll behavior passed to `scrollTo({ behavior })` and
283
+ * `scrollIntoView({ behavior })`.
284
+ *
285
+ * - `"auto"` (default) — browser-defined, usually instant.
286
+ * - `"instant"` — explicit instant jump (no animation).
287
+ * - `"smooth"` — animated transition. Note: smooth restore on back/traverse
288
+ * can feel disorienting if the user expects to land at the saved position
289
+ * immediately. Recommended for `mode: "top"` or anchor scroll only.
290
+ *
291
+ * See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/ScrollToOptions/behavior).
292
+ */
293
+ behavior?: ScrollBehavior | undefined;
294
+ /**
295
+ * sessionStorage key used to persist saved scroll positions. Default:
296
+ * `"real-router:scroll"`. Override only when multiple independent
297
+ * `RouterProvider` instances share the same document and you need to
298
+ * isolate their scroll stores (e.g. micro-frontends, embedded widgets,
299
+ * or testing). For a single app with one provider the default is fine.
300
+ */
301
+ storageKey?: string | undefined;
281
302
  }
282
303
 
283
304
  interface RouteProviderProps {
package/dist/cjs/index.js CHANGED
@@ -336,7 +336,7 @@ function manageFocus(h1) {
336
336
  });
337
337
  }
338
338
 
339
- const STORAGE_KEY = "real-router:scroll";
339
+ const DEFAULT_STORAGE_KEY = "real-router:scroll";
340
340
  const NOOP_INSTANCE$1 = Object.freeze({
341
341
  destroy: () => {
342
342
  /* no-op */
@@ -348,14 +348,36 @@ function createScrollRestoration(router, options) {
348
348
  }
349
349
  const mode = options?.mode ?? "restore";
350
350
 
351
- // mode "manual" = utility does nothing. Don't flip history.scrollRestoration,
352
- // don't subscribe, don't register pagehide — leave the browser's native
353
- // auto-restore intact for the app to override if it wants to.
354
- if (mode === "manual") {
351
+ // mode "native" = utility does nothing. Don't flip history.scrollRestoration,
352
+ // don't subscribe, don't register pagehide — `history.scrollRestoration`
353
+ // stays at the browser default ("auto") so the browser handles scroll
354
+ // restore natively. (Note: this is the OPPOSITE of `history.scrollRestoration
355
+ // === "manual"` — utility's "native" leaves the DOM property at "auto" so
356
+ // the browser is in charge.)
357
+ if (mode === "native") {
355
358
  return NOOP_INSTANCE$1;
356
359
  }
357
360
  const anchorEnabled = options?.anchorScrolling ?? true;
358
361
  const getContainer = options?.scrollContainer;
362
+ const behavior = options?.behavior ?? "auto";
363
+ const storageKey = options?.storageKey ?? DEFAULT_STORAGE_KEY;
364
+ const loadStore = () => {
365
+ try {
366
+ const raw = sessionStorage.getItem(storageKey);
367
+ return raw ? JSON.parse(raw) : {};
368
+ } catch {
369
+ return {};
370
+ }
371
+ };
372
+ const putPos = (key, pos) => {
373
+ try {
374
+ const store = loadStore();
375
+ store[key] = pos;
376
+ sessionStorage.setItem(storageKey, JSON.stringify(store));
377
+ } catch {
378
+ // Ignore quota / security errors.
379
+ }
380
+ };
359
381
  const prevScrollRestoration = history.scrollRestoration;
360
382
  try {
361
383
  history.scrollRestoration = "manual";
@@ -373,9 +395,17 @@ function createScrollRestoration(router, options) {
373
395
  const writePos = top => {
374
396
  const element = getContainer?.();
375
397
  if (element) {
376
- element.scrollTop = top;
398
+ element.scrollTo({
399
+ top,
400
+ left: 0,
401
+ behavior
402
+ });
377
403
  } else {
378
- globalThis.scrollTo(0, top);
404
+ globalThis.scrollTo({
405
+ top,
406
+ left: 0,
407
+ behavior
408
+ });
379
409
  }
380
410
  };
381
411
  const scrollToHashOrTop = route => {
@@ -389,7 +419,9 @@ function createScrollRestoration(router, options) {
389
419
  // eslint-disable-next-line unicorn/prefer-query-selector -- ids may contain CSS-unsafe chars
390
420
  const element = document.getElementById(ctxHash);
391
421
  if (element) {
392
- element.scrollIntoView();
422
+ element.scrollIntoView({
423
+ behavior
424
+ });
393
425
  return;
394
426
  }
395
427
  }
@@ -413,7 +445,9 @@ function createScrollRestoration(router, options) {
413
445
  // eslint-disable-next-line unicorn/prefer-query-selector -- ids may contain CSS-unsafe chars
414
446
  const element = document.getElementById(id);
415
447
  if (element) {
416
- element.scrollIntoView();
448
+ element.scrollIntoView({
449
+ behavior
450
+ });
417
451
  return;
418
452
  }
419
453
  }
@@ -479,23 +513,6 @@ function createScrollRestoration(router, options) {
479
513
  function keyOf(state) {
480
514
  return `${state.name}:${canonicalJson(state.params)}`;
481
515
  }
482
- function loadStore() {
483
- try {
484
- const raw = sessionStorage.getItem(STORAGE_KEY);
485
- return raw ? JSON.parse(raw) : {};
486
- } catch {
487
- return {};
488
- }
489
- }
490
- function putPos(key, pos) {
491
- try {
492
- const store = loadStore();
493
- store[key] = pos;
494
- sessionStorage.setItem(STORAGE_KEY, JSON.stringify(store));
495
- } catch {
496
- // Ignore quota / security errors.
497
- }
498
- }
499
516
  function canonicalJson(value) {
500
517
  return JSON.stringify(value, canonicalReplacer);
501
518
  }
@@ -273,11 +273,32 @@ interface UseRouteEnterOptions {
273
273
  */
274
274
  declare function useRouteEnter(handler: RouteEnterHandler, options?: UseRouteEnterOptions): void;
275
275
 
276
- type ScrollRestorationMode = "restore" | "top" | "manual";
276
+ type ScrollRestorationMode = "restore" | "top" | "native";
277
277
  interface ScrollRestorationOptions {
278
278
  mode?: ScrollRestorationMode | undefined;
279
279
  anchorScrolling?: boolean | undefined;
280
280
  scrollContainer?: (() => HTMLElement | null) | undefined;
281
+ /**
282
+ * Scroll behavior passed to `scrollTo({ behavior })` and
283
+ * `scrollIntoView({ behavior })`.
284
+ *
285
+ * - `"auto"` (default) — browser-defined, usually instant.
286
+ * - `"instant"` — explicit instant jump (no animation).
287
+ * - `"smooth"` — animated transition. Note: smooth restore on back/traverse
288
+ * can feel disorienting if the user expects to land at the saved position
289
+ * immediately. Recommended for `mode: "top"` or anchor scroll only.
290
+ *
291
+ * See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/ScrollToOptions/behavior).
292
+ */
293
+ behavior?: ScrollBehavior | undefined;
294
+ /**
295
+ * sessionStorage key used to persist saved scroll positions. Default:
296
+ * `"real-router:scroll"`. Override only when multiple independent
297
+ * `RouterProvider` instances share the same document and you need to
298
+ * isolate their scroll stores (e.g. micro-frontends, embedded widgets,
299
+ * or testing). For a single app with one provider the default is fine.
300
+ */
301
+ storageKey?: string | undefined;
281
302
  }
282
303
 
283
304
  interface RouteProviderProps {
@@ -334,7 +334,7 @@ function manageFocus(h1) {
334
334
  });
335
335
  }
336
336
 
337
- const STORAGE_KEY = "real-router:scroll";
337
+ const DEFAULT_STORAGE_KEY = "real-router:scroll";
338
338
  const NOOP_INSTANCE$1 = Object.freeze({
339
339
  destroy: () => {
340
340
  /* no-op */
@@ -346,14 +346,36 @@ function createScrollRestoration(router, options) {
346
346
  }
347
347
  const mode = options?.mode ?? "restore";
348
348
 
349
- // mode "manual" = utility does nothing. Don't flip history.scrollRestoration,
350
- // don't subscribe, don't register pagehide — leave the browser's native
351
- // auto-restore intact for the app to override if it wants to.
352
- if (mode === "manual") {
349
+ // mode "native" = utility does nothing. Don't flip history.scrollRestoration,
350
+ // don't subscribe, don't register pagehide — `history.scrollRestoration`
351
+ // stays at the browser default ("auto") so the browser handles scroll
352
+ // restore natively. (Note: this is the OPPOSITE of `history.scrollRestoration
353
+ // === "manual"` — utility's "native" leaves the DOM property at "auto" so
354
+ // the browser is in charge.)
355
+ if (mode === "native") {
353
356
  return NOOP_INSTANCE$1;
354
357
  }
355
358
  const anchorEnabled = options?.anchorScrolling ?? true;
356
359
  const getContainer = options?.scrollContainer;
360
+ const behavior = options?.behavior ?? "auto";
361
+ const storageKey = options?.storageKey ?? DEFAULT_STORAGE_KEY;
362
+ const loadStore = () => {
363
+ try {
364
+ const raw = sessionStorage.getItem(storageKey);
365
+ return raw ? JSON.parse(raw) : {};
366
+ } catch {
367
+ return {};
368
+ }
369
+ };
370
+ const putPos = (key, pos) => {
371
+ try {
372
+ const store = loadStore();
373
+ store[key] = pos;
374
+ sessionStorage.setItem(storageKey, JSON.stringify(store));
375
+ } catch {
376
+ // Ignore quota / security errors.
377
+ }
378
+ };
357
379
  const prevScrollRestoration = history.scrollRestoration;
358
380
  try {
359
381
  history.scrollRestoration = "manual";
@@ -371,9 +393,17 @@ function createScrollRestoration(router, options) {
371
393
  const writePos = top => {
372
394
  const element = getContainer?.();
373
395
  if (element) {
374
- element.scrollTop = top;
396
+ element.scrollTo({
397
+ top,
398
+ left: 0,
399
+ behavior
400
+ });
375
401
  } else {
376
- globalThis.scrollTo(0, top);
402
+ globalThis.scrollTo({
403
+ top,
404
+ left: 0,
405
+ behavior
406
+ });
377
407
  }
378
408
  };
379
409
  const scrollToHashOrTop = route => {
@@ -387,7 +417,9 @@ function createScrollRestoration(router, options) {
387
417
  // eslint-disable-next-line unicorn/prefer-query-selector -- ids may contain CSS-unsafe chars
388
418
  const element = document.getElementById(ctxHash);
389
419
  if (element) {
390
- element.scrollIntoView();
420
+ element.scrollIntoView({
421
+ behavior
422
+ });
391
423
  return;
392
424
  }
393
425
  }
@@ -411,7 +443,9 @@ function createScrollRestoration(router, options) {
411
443
  // eslint-disable-next-line unicorn/prefer-query-selector -- ids may contain CSS-unsafe chars
412
444
  const element = document.getElementById(id);
413
445
  if (element) {
414
- element.scrollIntoView();
446
+ element.scrollIntoView({
447
+ behavior
448
+ });
415
449
  return;
416
450
  }
417
451
  }
@@ -477,23 +511,6 @@ function createScrollRestoration(router, options) {
477
511
  function keyOf(state) {
478
512
  return `${state.name}:${canonicalJson(state.params)}`;
479
513
  }
480
- function loadStore() {
481
- try {
482
- const raw = sessionStorage.getItem(STORAGE_KEY);
483
- return raw ? JSON.parse(raw) : {};
484
- } catch {
485
- return {};
486
- }
487
- }
488
- function putPos(key, pos) {
489
- try {
490
- const store = loadStore();
491
- store[key] = pos;
492
- sessionStorage.setItem(STORAGE_KEY, JSON.stringify(store));
493
- } catch {
494
- // Ignore quota / security errors.
495
- }
496
- }
497
514
  function canonicalJson(value) {
498
515
  return JSON.stringify(value, canonicalReplacer);
499
516
  }
@@ -1,9 +1,30 @@
1
1
  import type { Router } from "@real-router/core";
2
- export type ScrollRestorationMode = "restore" | "top" | "manual";
2
+ export type ScrollRestorationMode = "restore" | "top" | "native";
3
3
  export interface ScrollRestorationOptions {
4
4
  mode?: ScrollRestorationMode | undefined;
5
5
  anchorScrolling?: boolean | undefined;
6
6
  scrollContainer?: (() => HTMLElement | null) | undefined;
7
+ /**
8
+ * Scroll behavior passed to `scrollTo({ behavior })` and
9
+ * `scrollIntoView({ behavior })`.
10
+ *
11
+ * - `"auto"` (default) — browser-defined, usually instant.
12
+ * - `"instant"` — explicit instant jump (no animation).
13
+ * - `"smooth"` — animated transition. Note: smooth restore on back/traverse
14
+ * can feel disorienting if the user expects to land at the saved position
15
+ * immediately. Recommended for `mode: "top"` or anchor scroll only.
16
+ *
17
+ * See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/ScrollToOptions/behavior).
18
+ */
19
+ behavior?: ScrollBehavior | undefined;
20
+ /**
21
+ * sessionStorage key used to persist saved scroll positions. Default:
22
+ * `"real-router:scroll"`. Override only when multiple independent
23
+ * `RouterProvider` instances share the same document and you need to
24
+ * isolate their scroll stores (e.g. micro-frontends, embedded widgets,
25
+ * or testing). For a single app with one provider the default is fine.
26
+ */
27
+ storageKey?: string | undefined;
7
28
  }
8
29
  export declare function createScrollRestoration(router: Router, options?: ScrollRestorationOptions): {
9
30
  destroy: () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"scroll-restore.d.ts","sourceRoot":"","sources":["../../../src/dom-utils/scroll-restore.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAS,MAAM,mBAAmB,CAAC;AAUvD,MAAM,MAAM,qBAAqB,GAAG,SAAS,GAAG,KAAK,GAAG,QAAQ,CAAC;AAEjE,MAAM,WAAW,wBAAwB;IACvC,IAAI,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IACzC,eAAe,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACtC,eAAe,CAAC,EAAE,CAAC,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,SAAS,CAAC;CAC1D;AAOD,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,wBAAwB,GACjC;IAAE,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE,CAwKzB"}
1
+ {"version":3,"file":"scroll-restore.d.ts","sourceRoot":"","sources":["../../../src/dom-utils/scroll-restore.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAS,MAAM,mBAAmB,CAAC;AAUvD,MAAM,MAAM,qBAAqB,GAAG,SAAS,GAAG,KAAK,GAAG,QAAQ,CAAC;AAEjE,MAAM,WAAW,wBAAwB;IACvC,IAAI,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IACzC,eAAe,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACtC,eAAe,CAAC,EAAE,CAAC,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,SAAS,CAAC;IACzD;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IACtC;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC;AAOD,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,wBAAwB,GACjC;IAAE,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE,CAkMzB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@real-router/solid",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "type": "commonjs",
5
5
  "description": "Solid.js integration for Real-Router",
6
6
  "main": "./dist/cjs/index.js",