@ossido-labs/ossido-router 0.1.2 → 0.1.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.
@@ -1,3 +1,4 @@
1
+ import { sanitizePathname } from "../utils/match-route.js";
1
2
  import { createContext, useContext } from "react";
2
3
 
3
4
  //#region src/components/RouterContext.tsx
@@ -13,7 +14,7 @@ function getInitialLocation(serverPayloadLocation) {
13
14
  };
14
15
  const { pathname, hash, href, search } = window.location;
15
16
  return {
16
- pathname,
17
+ pathname: sanitizePathname(pathname),
17
18
  hash,
18
19
  href,
19
20
  searchStr: search,
@@ -1 +1 @@
1
- {"version":3,"file":"RouterContext.js","names":[],"sources":["../../../src/components/RouterContext.tsx"],"sourcesContent":["import { createContext, useContext } from 'react';\n\nimport type { Router } from '../router';\nimport type { ServerInitialLocation } from '../types';\n\n/** How to reflect a committed navigation in the browser (history + scroll). */\nexport interface NavigationCommitOptions {\n history?: { type: 'pushState' | 'replaceState'; path: string };\n scroll?: boolean;\n /**\n * Override the app's `viewTransitions` config for this navigation: `true`\n * forces a view transition, `false` skips it. Defaults to the config value.\n */\n viewTransition?: boolean;\n}\n\nconst isServerSide = typeof window === 'undefined';\n\nexport interface ParsedLocation {\n href: string;\n pathname: string;\n search: Record<string, string>;\n searchStr: string;\n hash: string;\n}\n\nexport interface RouterContextValue {\n router: Router;\n location: ParsedLocation;\n /**\n * Incremented on every navigation (and on error retry / a manual\n * `refetchProps`). Combined with the\n * pathname it forms the data-resource key, so each navigation gets a fresh\n * resource (a refetch).\n *\n * Initialized to `0` identically on server and client and never changed\n * during the initial mount — otherwise the boundary would remount and flash\n * the loading fallback over server-rendered content (hydration mismatch).\n */\n navigationId: number;\n /**\n * Start a navigation to `loc`. Unless the destination has a `loading.tsx`,\n * its data is prefetched first and the navigation is only committed once the\n * data is ready — so the current page stays until then (no blank flash), even\n * across a layout change. `options` carries the browser history/scroll update\n * to apply at commit time.\n */\n updateLocation: (\n loc: ParsedLocation,\n options?: NavigationCommitOptions,\n ) => void;\n /**\n * Re-run the current route's data load (a refetch). Used by the error\n * boundary `reset` and by `useRouter().refetchProps`.\n */\n retry: () => void;\n}\n\nexport const RouterContext = createContext({} as RouterContextValue);\n\nexport function getInitialLocation(\n serverPayloadLocation: ServerInitialLocation,\n): ParsedLocation {\n if (isServerSide) {\n return {\n pathname: serverPayloadLocation.pathname || '',\n hash: '',\n href: serverPayloadLocation.href || '',\n searchStr: serverPayloadLocation.searchStr || '',\n search: Object.fromEntries(\n new URLSearchParams(serverPayloadLocation.searchStr),\n ),\n };\n }\n\n const { pathname, hash, href, search } = window.location;\n return {\n pathname,\n hash,\n href,\n searchStr: search,\n search: Object.fromEntries(new URLSearchParams(search)),\n };\n}\n\n/**\n * @warning THIS SHOULD NOT BE EXPOSED TO USERLAND\n */\nexport function useRouterContext(): RouterContextValue {\n return useContext(RouterContext);\n}\n"],"mappings":";;;AAgBA,MAAM,eAAe,OAAO,WAAW;AA0CvC,MAAa,gBAAgB,cAAc,CAAC,CAAuB;AAEnE,SAAgB,mBACd,uBACgB;CAChB,IAAI,cACF,OAAO;EACL,UAAU,sBAAsB,YAAY;EAC5C,MAAM;EACN,MAAM,sBAAsB,QAAQ;EACpC,WAAW,sBAAsB,aAAa;EAC9C,QAAQ,OAAO,YACb,IAAI,gBAAgB,sBAAsB,SAAS,CACrD;CACF;CAGF,MAAM,EAAE,UAAU,MAAM,MAAM,WAAW,OAAO;CAChD,OAAO;EACL;EACA;EACA;EACA,WAAW;EACX,QAAQ,OAAO,YAAY,IAAI,gBAAgB,MAAM,CAAC;CACxD;AACF;;;;AAKA,SAAgB,mBAAuC;CACrD,OAAO,WAAW,aAAa;AACjC"}
1
+ {"version":3,"file":"RouterContext.js","names":[],"sources":["../../../src/components/RouterContext.tsx"],"sourcesContent":["import { createContext, useContext } from 'react';\n\nimport type { Router } from '../router';\nimport type { ServerInitialLocation } from '../types';\nimport { sanitizePathname } from '../utils/match-route';\n\n/** How to reflect a committed navigation in the browser (history + scroll). */\nexport interface NavigationCommitOptions {\n history?: { type: 'pushState' | 'replaceState'; path: string };\n scroll?: boolean;\n /**\n * Override the app's `viewTransitions` config for this navigation: `true`\n * forces a view transition, `false` skips it. Defaults to the config value.\n */\n viewTransition?: boolean;\n}\n\nconst isServerSide = typeof window === 'undefined';\n\nexport interface ParsedLocation {\n href: string;\n pathname: string;\n search: Record<string, string>;\n searchStr: string;\n hash: string;\n}\n\nexport interface RouterContextValue {\n router: Router;\n location: ParsedLocation;\n /**\n * Incremented on every navigation (and on error retry / a manual\n * `refetchProps`). Combined with the\n * pathname it forms the data-resource key, so each navigation gets a fresh\n * resource (a refetch).\n *\n * Initialized to `0` identically on server and client and never changed\n * during the initial mount — otherwise the boundary would remount and flash\n * the loading fallback over server-rendered content (hydration mismatch).\n */\n navigationId: number;\n /**\n * Start a navigation to `loc`. Unless the destination has a `loading.tsx`,\n * its data is prefetched first and the navigation is only committed once the\n * data is ready — so the current page stays until then (no blank flash), even\n * across a layout change. `options` carries the browser history/scroll update\n * to apply at commit time.\n */\n updateLocation: (\n loc: ParsedLocation,\n options?: NavigationCommitOptions,\n ) => void;\n /**\n * Re-run the current route's data load (a refetch). Used by the error\n * boundary `reset` and by `useRouter().refetchProps`.\n */\n retry: () => void;\n}\n\nexport const RouterContext = createContext({} as RouterContextValue);\n\nexport function getInitialLocation(\n serverPayloadLocation: ServerInitialLocation,\n): ParsedLocation {\n if (isServerSide) {\n return {\n pathname: serverPayloadLocation.pathname || '',\n hash: '',\n href: serverPayloadLocation.href || '',\n searchStr: serverPayloadLocation.searchStr || '',\n search: Object.fromEntries(\n new URLSearchParams(serverPayloadLocation.searchStr),\n ),\n };\n }\n\n const { pathname, hash, href, search } = window.location;\n return {\n // Match the server, which renders with the sanitized pathname. Static\n // export serves directory URLs with a trailing slash (`/docs/x/`), so the\n // raw `window.location.pathname` would differ from the server's `/docs/x`\n // and break hydration for route-aware UI (e.g. active nav links).\n pathname: sanitizePathname(pathname),\n hash,\n href,\n searchStr: search,\n search: Object.fromEntries(new URLSearchParams(search)),\n };\n}\n\n/**\n * @warning THIS SHOULD NOT BE EXPOSED TO USERLAND\n */\nexport function useRouterContext(): RouterContextValue {\n return useContext(RouterContext);\n}\n"],"mappings":";;;;AAiBA,MAAM,eAAe,OAAO,WAAW;AA0CvC,MAAa,gBAAgB,cAAc,CAAC,CAAuB;AAEnE,SAAgB,mBACd,uBACgB;CAChB,IAAI,cACF,OAAO;EACL,UAAU,sBAAsB,YAAY;EAC5C,MAAM;EACN,MAAM,sBAAsB,QAAQ;EACpC,WAAW,sBAAsB,aAAa;EAC9C,QAAQ,OAAO,YACb,IAAI,gBAAgB,sBAAsB,SAAS,CACrD;CACF;CAGF,MAAM,EAAE,UAAU,MAAM,MAAM,WAAW,OAAO;CAChD,OAAO;EAKL,UAAU,iBAAiB,QAAQ;EACnC;EACA;EACA,WAAW;EACX,QAAQ,OAAO,YAAY,IAAI,gBAAgB,MAAM,CAAC;CACxD;AACF;;;;AAKA,SAAgB,mBAAuC;CACrD,OAAO,WAAW,aAAa;AACjC"}
@@ -1,7 +1,7 @@
1
1
  import { buildResourceKey, getOrCreateResource } from "../data/resourceCache.js";
2
+ import { matchRoute } from "../utils/match-route.js";
2
3
  import { RouterContext, getInitialLocation } from "./RouterContext.js";
3
4
  import { fromUrlToParsedLocation } from "../utils/from-url-to-parsed-location.js";
4
- import { matchRoute } from "../utils/match-route.js";
5
5
  import { VIEW_TRANSITIONS_ENABLED, runCommit } from "../utils/view-transition.js";
6
6
  import { useCallback, useEffect, useMemo, useState } from "react";
7
7
  import { jsx } from "react/jsx-runtime";
@@ -1,5 +1,5 @@
1
- import { useRouterContext } from "../components/RouterContext.js";
2
1
  import { matchRoute, sanitizePathname } from "../utils/match-route.js";
2
+ import { useRouterContext } from "../components/RouterContext.js";
3
3
 
4
4
  //#region src/hooks/useRoute.ts
5
5
  /**
@@ -1,9 +1,11 @@
1
+ import { sanitizePathname } from "./match-route.js";
2
+
1
3
  //#region src/utils/from-url-to-parsed-location.ts
2
4
  function fromUrlToParsedLocation(href) {
3
5
  const location = new URL(href, window.location.origin);
4
6
  return {
5
7
  href: location.href,
6
- pathname: location.pathname,
8
+ pathname: sanitizePathname(location.pathname),
7
9
  search: Object.fromEntries(location.searchParams),
8
10
  searchStr: location.search,
9
11
  hash: location.hash
@@ -1 +1 @@
1
- {"version":3,"file":"from-url-to-parsed-location.js","names":[],"sources":["../../../src/utils/from-url-to-parsed-location.ts"],"sourcesContent":["import type { ParsedLocation } from '../components/RouterContext';\n\nexport function fromUrlToParsedLocation(href: string): ParsedLocation {\n const location = new URL(href, window.location.origin);\n return {\n href: location.href,\n pathname: location.pathname,\n search: Object.fromEntries(location.searchParams),\n searchStr: location.search,\n hash: location.hash,\n };\n}\n"],"mappings":";AAEA,SAAgB,wBAAwB,MAA8B;CACpE,MAAM,WAAW,IAAI,IAAI,MAAM,OAAO,SAAS,MAAM;CACrD,OAAO;EACL,MAAM,SAAS;EACf,UAAU,SAAS;EACnB,QAAQ,OAAO,YAAY,SAAS,YAAY;EAChD,WAAW,SAAS;EACpB,MAAM,SAAS;CACjB;AACF"}
1
+ {"version":3,"file":"from-url-to-parsed-location.js","names":[],"sources":["../../../src/utils/from-url-to-parsed-location.ts"],"sourcesContent":["import type { ParsedLocation } from '../components/RouterContext';\nimport { sanitizePathname } from './match-route';\n\nexport function fromUrlToParsedLocation(href: string): ParsedLocation {\n const location = new URL(href, window.location.origin);\n return {\n href: location.href,\n // Canonical pathname (no trailing slash), matching the server payload so\n // `useRouter().pathname` is consistent across SSR, hydration, and navigation.\n pathname: sanitizePathname(location.pathname),\n search: Object.fromEntries(location.searchParams),\n searchStr: location.search,\n hash: location.hash,\n };\n}\n"],"mappings":";;;AAGA,SAAgB,wBAAwB,MAA8B;CACpE,MAAM,WAAW,IAAI,IAAI,MAAM,OAAO,SAAS,MAAM;CACrD,OAAO;EACL,MAAM,SAAS;EAGf,UAAU,iBAAiB,SAAS,QAAQ;EAC5C,QAAQ,OAAO,YAAY,SAAS,YAAY;EAChD,WAAW,SAAS;EACpB,MAAM,SAAS;CACjB;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ossido-labs/ossido-router",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -46,7 +46,7 @@
46
46
  },
47
47
  "dependencies": {
48
48
  "react-intersection-observer": "^9.13.0",
49
- "@ossido-labs/ossido-ui": "0.1.2"
49
+ "@ossido-labs/ossido-ui": "0.1.3"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@testing-library/react": "16.3.0",