@owlmeans/web-router 0.1.18-rc.50 → 0.1.18-rc.51

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
@@ -1,46 +1,149 @@
1
1
  # @owlmeans/web-router
2
2
 
3
- The default OwlMeans in-browser routing plugin for the OwlMeans context system. It depends on no
4
- third-party router — react-router is a separate opt-in plugin,
5
- [`@owlmeans/web-router-react-router`](../web-router-react-router).
6
-
7
- ## Overview
8
-
9
- - `makeWebRouterService()` — creates a router service backed by the OwlMeans browser router
10
- - `appendWebRouter(ctx)` — registers the web router service in the context
11
- - Provides `useParams`, `useLocation`, `useNavigate`, `outlet()`, `provider()` via the service
12
- - Used internally by `@owlmeans/web-client`'s `makeContext` — not typically used directly
3
+ The default OwlMeans in-browser routing plugin: standard URL routing over the browser History API,
4
+ a pure route matcher from `@owlmeans/router`, and a React provider, outlet and hooks — with no
5
+ third-party router. It registers itself as a `RouterPlugin` on the `@owlmeans/router` host, and
6
+ `@owlmeans/web-client` / `@owlmeans/web-panel` call `appendWebRouter` in their `makeContext`, so a
7
+ web app gets it without importing anything. An app imports it directly only for a custom context
8
+ setup or to reach the plugin's components and hooks outside the `context.router()` facade. To route
9
+ with react-router instead, add `@owlmeans/web-router-react-router` (higher priority, wins the
10
+ cascade); an SSR or React Native host is a plugin of its own.
13
11
 
14
12
  ## Installation
15
13
 
16
14
  ```bash
17
- bun add @owlmeans/web-router@^0.1.18-rc.50
15
+ bun add @owlmeans/web-router@^0.1.18-rc.51
18
16
  ```
19
17
 
18
+ `react` is a peer dependency.
19
+
20
+ ## Concepts
21
+
22
+ - **Router host** — the `RouterService` of `@owlmeans/router`, registered once per context
23
+ (`ensureRouterService`). Its facade (`provider`, `outlet`, `compile`, `useParams`, `useLocation`,
24
+ `useNavigate`, `useSearchParams`) delegates to the active plugin.
25
+ - **Browser plugin** — `makeBrowserRouterPlugin()`: alias `BROWSER_ROUTER`, priority 0, mode
26
+ `'browser'`, `match` always true — the universal browser fallback any higher-priority plugin
27
+ outranks.
28
+ - **Compile** — `compile(routes)` flattens and ranks the neutral `RouteObject[]`
29
+ (`{ index?, path?, children?, Component? }`) into matchable branches; synchronous.
30
+ - **Route chain** — `BrowserRouterProvider` re-matches on every history change and renders the chain
31
+ through `RouteChain`; each `<Outlet/>` renders the next-deeper match. A match without a
32
+ `Component` is a pass-through, as in react-router's implicit outlet.
33
+ - **Route syntax** — static segments, `:param`, nested routes and index routes; a static segment
34
+ outranks a `:param` sibling. No splat or optional segments.
35
+
20
36
  ## Usage
21
37
 
22
- This package is registered automatically when using `makeContext` from `@owlmeans/web-client`. Direct use is only needed for custom context setup:
38
+ ### Default wiring
39
+
40
+ Nothing to do with `@owlmeans/web-client` or `@owlmeans/web-panel`. A context assembled by hand
41
+ registers the plugin itself:
23
42
 
24
43
  ```typescript
25
44
  import { appendWebRouter } from '@owlmeans/web-router'
26
45
 
27
- appendWebRouter(context)
46
+ appendWebRouter(context) // ensures the router host, then registers the browser plugin
28
47
  ```
29
48
 
30
- ## API
49
+ ### Read the route in a component
50
+
51
+ Inside an OwlMeans app, reach the hooks through the facade so the active plugin answers:
52
+
53
+ ```tsx
54
+ import { useContext } from '@owlmeans/client'
55
+
56
+ export const UserScreen = () => {
57
+ const context = useContext()
58
+ const { id } = context.router().useParams<{ id: string }>()
59
+ const [query] = context.router().useSearchParams()
60
+ const navigate = context.router().useNavigate()
61
+
62
+ return (
63
+ <button onClick={() => navigate(`/users/${id}/edit`, { state: { from: query.get('tab') } })}>
64
+ edit
65
+ </button>
66
+ )
67
+ }
68
+ ```
31
69
 
32
- ### `makeWebRouterService(): RouterService`
70
+ `navigate(to, { replace?, state? })` takes a path string, a `{ pathname?, search?, hash? }`
71
+ object, or a number for history steps; an absolute `http…` string is a full-page navigation.
72
+ The setter returned by `useSearchParams` (`set(next, { replace?, state? })`) rewrites the search part
73
+ of the current path.
33
74
 
34
- Creates a router service with the OwlMeans browser router hooks and components.
75
+ ### Use the plugin standalone
35
76
 
36
- ### `appendWebRouter<C, T>(ctx): void`
77
+ The same components and hooks are exported directly — what the package's own browser harness does:
37
78
 
38
- Registers the web router service in the given context.
79
+ ```tsx
80
+ import { createRoot } from 'react-dom/client'
81
+ import type { RouteObject } from '@owlmeans/router'
82
+ import { makeBrowserRouterPlugin, Outlet, useParams } from '@owlmeans/web-router'
39
83
 
40
- ## Related Packages
84
+ const Layout = () => <main><Outlet /></main>
85
+ const Home = () => <p>home</p>
86
+ const User = () => <p>user {useParams().id}</p>
41
87
 
42
- - [`@owlmeans/router`](../router) — `RouterService` base interface
88
+ const routes: RouteObject[] = [
89
+ { path: '', Component: Layout, children: [
90
+ { index: true, Component: Home },
91
+ { path: 'users', children: [{ path: ':id', Component: User }] }, // component-less group passes through
92
+ ] },
93
+ ]
94
+
95
+ const plugin = makeBrowserRouterPlugin()
96
+ const Provider = plugin.provider()
97
+ createRoot(document.getElementById('root')!).render(<Provider router={plugin.compile(routes)} />)
98
+ ```
99
+
100
+ ### Switch to react-router
101
+
102
+ ```typescript
103
+ import { appendReactRouter } from '@owlmeans/web-router-react-router'
104
+
105
+ appendReactRouter(context) // priority 100 outranks the browser plugin
106
+ ```
107
+
108
+ ## API
109
+
110
+ | Symbol | Kind | Purpose |
111
+ |---|---|---|
112
+ | `appendWebRouter(ctx)` | function | `ensureRouterService(ctx)` + register the browser plugin; returns the context |
113
+ | `makeWebRouterService()` | function | back-compat: a new router host pre-loaded with the browser plugin |
114
+ | `makeBrowserRouterPlugin()` | function | the `RouterPlugin` itself |
115
+ | `BROWSER_ROUTER` | const | `'owlmeans-browser-router'` — the plugin alias |
116
+ | `BrowserRouterProvider` | component | `{ router: LibraryRouter }` — subscribes to history and renders the match chain |
117
+ | `Outlet` | component | renders the next-deeper match |
118
+ | `RouteChain` | component | `{ depth }` — renders the chain from a depth, skipping component-less matches |
119
+ | `useParams`, `useLocation`, `useNavigate`, `useSearchParams` | hooks | the plugin's hooks; throw outside the provider |
120
+ | `createBrowserHistory()` | function | `BrowserHistory` over `window.history` + `popstate`; an inert stub without `window` |
121
+ | `OwlLibraryRouter` | type | `{ routes, branches }` — what `compile` returns |
122
+ | `RouterState` | type | `{ location, matches, navigate }` — the provider's React context value |
123
+ | `BrowserHistory` | type | `location`, `push`, `replace`, `go`, `listen` |
124
+
125
+ ## Common pitfalls
126
+
127
+ - A hook used outside `BrowserRouterProvider` throws
128
+ `owlmeans-browser-router: router hook used outside of the router provider`.
129
+ - Calling the plugin's hooks directly bypasses the cascade; in an app, use `context.router().…` so a
130
+ switched plugin keeps working.
131
+ - Splat (`*`) and optional segments are not supported; declare explicit routes.
132
+ - `makeWebRouterService()` builds a separate host; prefer `appendWebRouter`, which reuses the
133
+ context's host.
134
+ - `noRouter` works on `<App>` only — `<PanelApp>` accepts the prop by type but still mounts the
135
+ router.
136
+
137
+ ## Related packages
138
+
139
+ - [`@owlmeans/router`](../router) — the router host, `RouterPlugin` contract and pure matcher
140
+ - [`@owlmeans/web-router-react-router`](../web-router-react-router) — opt-in react-router v7 plugin
141
+ - [`@owlmeans/client`](../client) — builds `RouteObject[]` from the entrypoint tree and exposes `context.router()`
43
142
  - [`@owlmeans/web-client`](../web-client) — calls `appendWebRouter` inside `makeContext`
143
+ - [`@owlmeans/web-panel`](../web-panel) — the panel layer, wired the same way
144
+
145
+ The `web-router` skill describes this plugin; the `router-plugins` skill covers the plugin contract,
146
+ cascade selection and authoring a new plugin.
44
147
 
45
148
  <!-- owlmeans:agent-guidance:start -->
46
149
  ## Agent guidance
@@ -50,7 +153,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
50
153
  your project's skill store (`.agents/skills/`):
51
154
 
52
155
  ```sh
53
- npx @owlmeans/agent-skills@^0.1.18-rc.51
156
+ npx @owlmeans/agent-skills@^0.1.18-rc.52
54
157
  ```
55
158
 
56
159
  The embedded files are version-matched to this package release. Do not edit them
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
3
  "package": "@owlmeans/web-router",
4
- "version": "0.1.18-rc.50",
5
- "generatedAt": "2026-10-06T11:45:57.681Z",
4
+ "version": "0.1.18-rc.51",
5
+ "generatedAt": "2026-10-08T21:27:54.319Z",
6
6
  "canonicalRepo": "https://github.com/owlmeans/common",
7
7
  "entries": [
8
8
  {
@@ -8,7 +8,7 @@ user-invocable: false
8
8
  # @owlmeans/web-router
9
9
 
10
10
  **Layer:** Web (React), build level L2
11
- **Install:** `"@owlmeans/web-router": "^0.1.18-rc.50"` in `dependencies`
11
+ **Install:** `"@owlmeans/web-router": "^0.1.18-rc.51"` in `dependencies`
12
12
 
13
13
  This package **is the default OwlMeans in-browser router** — a minimal, react-router-free
14
14
  implementation of standard URL routing over the browser History API. It registers itself as a
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owlmeans/web-router",
3
- "version": "0.1.18-rc.50",
3
+ "version": "0.1.18-rc.51",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -26,7 +26,7 @@
26
26
  },
27
27
  "devDependencies": {
28
28
  "@owlmeans/dep-config": "workspace:*",
29
- "@owlmeans/test-ui": "^0.1.18-rc.50",
29
+ "@owlmeans/test-ui": "^0.1.18-rc.51",
30
30
  "@types/node": "^26.6.4",
31
31
  "@types/react": "^19.3.0",
32
32
  "@vitejs/plugin-react": "^6.1.1",
@@ -39,7 +39,7 @@
39
39
  },
40
40
  "dependencies": {
41
41
  "@owlmeans/context": "^0.1.18-rc.34",
42
- "@owlmeans/router": "^0.1.18-rc.33"
42
+ "@owlmeans/router": "^0.1.18-rc.34"
43
43
  },
44
44
  "publishConfig": {
45
45
  "access": "public"