@real-router/vue 0.0.1

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 ADDED
@@ -0,0 +1,430 @@
1
+ # @real-router/vue
2
+
3
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](../../LICENSE)
4
+
5
+ > Vue 3 integration for [Real-Router](https://github.com/greydragon888/real-router) — composables, components, and context providers.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @real-router/vue @real-router/core @real-router/browser-plugin
11
+ ```
12
+
13
+ **Peer dependency:** `vue` >= 3.3.0
14
+
15
+ ## Quick Start
16
+
17
+ ```typescript
18
+ import { createRouter } from "@real-router/core";
19
+ import { browserPluginFactory } from "@real-router/browser-plugin";
20
+ import { RouterProvider, RouteView, Link } from "@real-router/vue";
21
+ import { defineComponent, h } from "vue";
22
+
23
+ const router = createRouter([
24
+ { name: "home", path: "/" },
25
+ {
26
+ name: "users",
27
+ path: "/users",
28
+ children: [{ name: "profile", path: "/:id" }],
29
+ },
30
+ ]);
31
+
32
+ router.usePlugin(browserPluginFactory());
33
+ router.start();
34
+
35
+ const App = defineComponent({
36
+ setup() {
37
+ return () =>
38
+ h(
39
+ RouterProvider,
40
+ { router },
41
+ {
42
+ default: () => [
43
+ h("nav", [
44
+ h(Link, { routeName: "home" }, { default: () => "Home" }),
45
+ h(Link, { routeName: "users" }, { default: () => "Users" }),
46
+ ]),
47
+ h(
48
+ RouteView,
49
+ { nodeName: "" },
50
+ {
51
+ default: () => [
52
+ h(
53
+ RouteView.Match,
54
+ { segment: "home" },
55
+ { default: () => h(HomePage) },
56
+ ),
57
+ h(
58
+ RouteView.Match,
59
+ { segment: "users" },
60
+ { default: () => h(UsersPage) },
61
+ ),
62
+ h(RouteView.NotFound, null, {
63
+ default: () => h(NotFoundPage),
64
+ }),
65
+ ],
66
+ },
67
+ ),
68
+ ],
69
+ },
70
+ );
71
+ },
72
+ });
73
+ ```
74
+
75
+ Or with Vue SFC templates (the composables and components work in `.vue` files too):
76
+
77
+ ```vue
78
+ <template>
79
+ <RouterProvider :router="router">
80
+ <nav>
81
+ <Link routeName="home">Home</Link>
82
+ <Link routeName="users">Users</Link>
83
+ </nav>
84
+ <RouteView nodeName="">
85
+ <RouteView.Match segment="home">
86
+ <HomePage />
87
+ </RouteView.Match>
88
+ <RouteView.Match segment="users">
89
+ <UsersPage />
90
+ </RouteView.Match>
91
+ <RouteView.NotFound>
92
+ <NotFoundPage />
93
+ </RouteView.NotFound>
94
+ </RouteView>
95
+ </RouterProvider>
96
+ </template>
97
+ ```
98
+
99
+ ## Plugin Installation (Alternative)
100
+
101
+ Use `createRouterPlugin` for the standard `app.use()` pattern instead of `<RouterProvider>`:
102
+
103
+ ```typescript
104
+ import { createApp } from "vue";
105
+ import { createRouterPlugin } from "@real-router/vue";
106
+
107
+ const app = createApp(App);
108
+ app.use(createRouterPlugin(router));
109
+ ```
110
+
111
+ All composables (`useRouter`, `useRoute`, etc.) and the `v-link` directive work identically — `app.provide()` resolves the same way as component-level `provide()`. `<RouterProvider>` remains available for advanced cases (multiple routers, scoped routing, testing).
112
+
113
+ ## Composables
114
+
115
+ Route state composables return `ShallowRef` values. Read `.value` in script, or use them directly in templates where Vue auto-unwraps refs.
116
+
117
+ | Composable | Returns | Reactive? |
118
+ | ----------------------- | ------------------------------------------------------------- | ---------------------------------------- |
119
+ | `useRouter()` | `Router` | Never |
120
+ | `useNavigator()` | `Navigator` | Never (stable ref, safe to use directly) |
121
+ | `useRoute()` | `{ navigator, route: ShallowRef, previousRoute: ShallowRef }` | route/previousRoute on every navigation |
122
+ | `useRouteNode(name)` | `{ navigator, route: ShallowRef, previousRoute: ShallowRef }` | Only when node activates/deactivates |
123
+ | `useRouteUtils()` | `RouteUtils` | Never |
124
+ | `useRouterTransition()` | `ShallowRef<RouterTransitionSnapshot>` | On transition start/end |
125
+
126
+ ```typescript
127
+ // useRouteNode — updates only when "users.*" changes
128
+ const UsersLayout = defineComponent({
129
+ setup() {
130
+ const { route } = useRouteNode("users");
131
+
132
+ return () => {
133
+ if (!route.value) return null;
134
+
135
+ switch (route.value.name) {
136
+ case "users":
137
+ return h(UsersList);
138
+ case "users.profile":
139
+ return h(UserProfile, { id: route.value.params.id });
140
+ default:
141
+ return null;
142
+ }
143
+ };
144
+ },
145
+ });
146
+
147
+ // useNavigator — stable reference, never reactive
148
+ const BackButton = defineComponent({
149
+ setup() {
150
+ const navigator = useNavigator();
151
+ return () =>
152
+ h("button", { onClick: () => navigator.navigate("home") }, "Back");
153
+ },
154
+ });
155
+
156
+ // useRouterTransition — progress bars, loading states
157
+ const GlobalProgress = defineComponent({
158
+ setup() {
159
+ const transition = useRouterTransition();
160
+ return () =>
161
+ transition.value.isTransitioning
162
+ ? h("div", { class: "progress-bar" })
163
+ : null;
164
+ },
165
+ });
166
+ ```
167
+
168
+ ## Components
169
+
170
+ ### `<Link>`
171
+
172
+ Navigation link with automatic active state detection. Uses `computed()` for href and class — only the DOM attributes update when active state changes.
173
+
174
+ ```typescript
175
+ h(
176
+ Link,
177
+ {
178
+ routeName: "users.profile",
179
+ routeParams: { id: "123" },
180
+ activeClassName: "active", // default: "active"
181
+ activeStrict: false, // default: false (ancestor match)
182
+ ignoreQueryParams: true, // default: true
183
+ routeOptions: { replace: true },
184
+ },
185
+ { default: () => "View Profile" },
186
+ );
187
+ ```
188
+
189
+ In a template:
190
+
191
+ ```vue
192
+ <Link
193
+ routeName="users.profile"
194
+ :routeParams="{ id: '123' }"
195
+ activeClassName="active"
196
+ :activeStrict="false"
197
+ :ignoreQueryParams="true"
198
+ :routeOptions="{ replace: true }"
199
+ >
200
+ View Profile
201
+ </Link>
202
+ ```
203
+
204
+ ### `<RouteView>`
205
+
206
+ Declarative route matching. Renders the first matching `<RouteView.Match>` child.
207
+
208
+ ```typescript
209
+ h(
210
+ RouteView,
211
+ { nodeName: "" },
212
+ {
213
+ default: () => [
214
+ h(RouteView.Match, { segment: "users" }, { default: () => h(UsersPage) }),
215
+ h(
216
+ RouteView.Match,
217
+ { segment: "settings" },
218
+ { default: () => h(SettingsPage) },
219
+ ),
220
+ h(RouteView.NotFound, null, { default: () => h(NotFoundPage) }),
221
+ ],
222
+ },
223
+ );
224
+ ```
225
+
226
+ `RouteView.Match` accepts an optional `exact` prop for strict segment matching:
227
+
228
+ ```typescript
229
+ h(
230
+ RouteView.Match,
231
+ { segment: "users", exact: true },
232
+ { default: () => h(UsersIndex) },
233
+ );
234
+ // Only matches "users" exactly, not "users.profile"
235
+ ```
236
+
237
+ **`keepAlive` prop:** Vue's native `<KeepAlive>` preserves component state across navigations. Each segment gets a dedicated wrapper component so `<KeepAlive>` can track them independently.
238
+
239
+ ```typescript
240
+ h(
241
+ RouteView,
242
+ { nodeName: "", keepAlive: true },
243
+ {
244
+ default: () => [
245
+ h(RouteView.Match, { segment: "users" }, { default: () => h(UsersPage) }),
246
+ // UsersPage stays alive when navigating to settings and back
247
+ ],
248
+ },
249
+ );
250
+ ```
251
+
252
+ **Lazy loading with `fallback`:** Pass a `fallback` prop (`VNode | (() => VNode)`) to wrap the matched content in Vue's `<Suspense>`. This lets you show a loading state while a `defineAsyncComponent` chunk is fetching. Works with both `keepAlive` and non-`keepAlive` modes.
253
+
254
+ ```typescript
255
+ import { defineAsyncComponent, h } from "vue";
256
+
257
+ const LazyDashboard = defineAsyncComponent(() => import("./Dashboard.vue"));
258
+
259
+ h(
260
+ RouteView,
261
+ { nodeName: "" },
262
+ {
263
+ default: () => [
264
+ h(
265
+ RouteView.Match,
266
+ { segment: "dashboard", fallback: h(Spinner) },
267
+ { default: () => h(LazyDashboard) },
268
+ ),
269
+ ],
270
+ },
271
+ );
272
+ ```
273
+
274
+ In a template:
275
+
276
+ ```vue
277
+ <script setup>
278
+ import { defineAsyncComponent } from "vue";
279
+ const LazyDashboard = defineAsyncComponent(() => import("./Dashboard.vue"));
280
+ </script>
281
+
282
+ <RouteView nodeName="">
283
+ <RouteView.Match segment="dashboard" :fallback="SpinnerComponent">
284
+ <LazyDashboard />
285
+ </RouteView.Match>
286
+ </RouteView>
287
+ ```
288
+
289
+ Without `fallback`, no `<Suspense>` boundary is added. The prop is optional.
290
+
291
+ ## Directives
292
+
293
+ ### `v-link`
294
+
295
+ Low-level directive for adding navigation to any element. Automatically handles click events, keyboard navigation (Enter key), and cursor styling.
296
+
297
+ ```typescript
298
+ import { vLink } from "@real-router/vue";
299
+
300
+ h("a", {
301
+ "v-link": { name: "users.profile", params: { id: "123" } },
302
+ });
303
+
304
+ h("button", {
305
+ "v-link": { name: "home" },
306
+ });
307
+
308
+ h("div", {
309
+ "v-link": {
310
+ name: "settings",
311
+ params: {},
312
+ options: { replace: true },
313
+ },
314
+ role: "link",
315
+ tabindex: "0",
316
+ });
317
+ ```
318
+
319
+ In a template:
320
+
321
+ ```vue
322
+ <a v-link="{ name: 'users.profile', params: { id: '123' } }">
323
+ User Profile
324
+ </a>
325
+
326
+ <button v-link="{ name: 'home' }">
327
+ Go Home
328
+ </button>
329
+
330
+ <div v-link="{ name: 'settings' }" role="link" tabindex="0">
331
+ Settings
332
+ </div>
333
+ ```
334
+
335
+ **Value:**
336
+
337
+ | Property | Type | Default | Description |
338
+ | --------- | -------- | ------- | ---------------------------------- |
339
+ | `name` | `string` | — | Target route name |
340
+ | `params` | `Params` | `{}` | Route parameters |
341
+ | `options` | `object` | `{}` | Navigation options (replace, etc.) |
342
+
343
+ The directive automatically sets `cursor: pointer` and adds `role="link"` + `tabindex="0"` to non-interactive elements for accessibility.
344
+
345
+ ## Vue-Specific Patterns
346
+
347
+ ### Refs, Not Plain Values
348
+
349
+ Unlike the React and Preact adapters, `useRoute()` and `useRouteNode()` return `ShallowRef` values. Read `.value` in script:
350
+
351
+ ```typescript
352
+ // React/Preact
353
+ const { route } = useRoute();
354
+ console.log(route?.name);
355
+
356
+ // Vue
357
+ const { route } = useRoute();
358
+ console.log(route.value?.name); // .value in script
359
+
360
+ // In template — Vue auto-unwraps
361
+ // <div>{{ route?.name }}</div>
362
+ ```
363
+
364
+ ### Watching Route Changes
365
+
366
+ Use Vue's `watch` to react to route changes in script:
367
+
368
+ ```typescript
369
+ const { route } = useRouteNode("users");
370
+
371
+ watch(route, (newRoute) => {
372
+ if (newRoute) {
373
+ document.title = `Users — ${newRoute.params.id ?? "list"}`;
374
+ }
375
+ });
376
+ ```
377
+
378
+ ### No .vue SFC Required
379
+
380
+ All components are plain `.ts` files using `defineComponent` + `h()`. You can use them in `.vue` SFC templates or in render functions — both work.
381
+
382
+ ## Accessibility
383
+
384
+ Enable screen reader announcements for route changes:
385
+
386
+ ```typescript
387
+ h(
388
+ RouterProvider,
389
+ { router, announceNavigation: true },
390
+ {
391
+ default: () => [
392
+ /* Your app */
393
+ ],
394
+ },
395
+ );
396
+ ```
397
+
398
+ Or in a template:
399
+
400
+ ```vue
401
+ <RouterProvider :router="router" :announceNavigation="true">
402
+ <!-- Your app -->
403
+ </RouterProvider>
404
+ ```
405
+
406
+ When enabled, a visually hidden `aria-live` region announces each navigation. Focus moves to the first `<h1>` on the new page. See [Accessibility guide](https://github.com/greydragon888/real-router/wiki/Accessibility) for details.
407
+
408
+ ## Documentation
409
+
410
+ Full documentation: [Wiki](https://github.com/greydragon888/real-router/wiki)
411
+
412
+ - [RouterProvider](https://github.com/greydragon888/real-router/wiki/RouterProvider) · [RouteView](https://github.com/greydragon888/real-router/wiki/RouteView) · [Link](https://github.com/greydragon888/real-router/wiki/Link)
413
+ - [useRouter](https://github.com/greydragon888/real-router/wiki/useRouter) · [useRoute](https://github.com/greydragon888/real-router/wiki/useRoute) · [useRouteNode](https://github.com/greydragon888/real-router/wiki/useRouteNode) · [useNavigator](https://github.com/greydragon888/real-router/wiki/useNavigator) · [useRouteUtils](https://github.com/greydragon888/real-router/wiki/useRouteUtils) · [useRouterTransition](https://github.com/greydragon888/real-router/wiki/useRouterTransition)
414
+
415
+ ## Related Packages
416
+
417
+ | Package | Description |
418
+ | ---------------------------------------------------------------------------------------- | ------------------------------------ |
419
+ | [@real-router/core](https://www.npmjs.com/package/@real-router/core) | Core router (required dependency) |
420
+ | [@real-router/browser-plugin](https://www.npmjs.com/package/@real-router/browser-plugin) | Browser History API integration |
421
+ | [@real-router/sources](https://www.npmjs.com/package/@real-router/sources) | Subscription layer (used internally) |
422
+ | [@real-router/route-utils](https://www.npmjs.com/package/@real-router/route-utils) | Route tree queries (`useRouteUtils`) |
423
+
424
+ ## Contributing
425
+
426
+ See [contributing guidelines](../../CONTRIBUTING.md) for development setup and PR process.
427
+
428
+ ## License
429
+
430
+ [MIT](../../LICENSE) © [Oleg Ivanov](https://github.com/greydragon888)
@@ -0,0 +1,244 @@
1
+ import * as vue from 'vue';
2
+ import { VNode, PropType, Directive, ShallowRef, Plugin, InjectionKey } from 'vue';
3
+ import { Params, NavigationOptions, Router, Navigator, State } from '@real-router/core';
4
+ export { Navigator } from '@real-router/core';
5
+ import { RouteUtils } from '@real-router/route-utils';
6
+ import { RouterTransitionSnapshot } from '@real-router/sources';
7
+ export { RouterTransitionSnapshot } from '@real-router/sources';
8
+
9
+ interface RouteViewProps {
10
+ readonly nodeName: string;
11
+ readonly keepAlive?: boolean;
12
+ }
13
+ interface MatchProps {
14
+ readonly segment: string;
15
+ readonly exact?: boolean;
16
+ readonly fallback?: VNode | (() => VNode);
17
+ }
18
+ type NotFoundProps = Record<string, never>;
19
+
20
+ declare const RouteView: {
21
+ new (...args: any[]): vue.CreateComponentPublicInstanceWithMixins<Readonly<vue.ExtractPropTypes<{
22
+ nodeName: {
23
+ type: StringConstructor;
24
+ required: true;
25
+ };
26
+ keepAlive: {
27
+ type: BooleanConstructor;
28
+ default: boolean;
29
+ };
30
+ }>> & Readonly<{}>, () => VNode | null, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, vue.PublicProps, {
31
+ keepAlive: boolean;
32
+ }, true, {}, {}, vue.GlobalComponents, vue.GlobalDirectives, string, {}, any, vue.ComponentProvideOptions, {
33
+ P: {};
34
+ B: {};
35
+ D: {};
36
+ C: {};
37
+ M: {};
38
+ Defaults: {};
39
+ }, Readonly<vue.ExtractPropTypes<{
40
+ nodeName: {
41
+ type: StringConstructor;
42
+ required: true;
43
+ };
44
+ keepAlive: {
45
+ type: BooleanConstructor;
46
+ default: boolean;
47
+ };
48
+ }>> & Readonly<{}>, () => VNode | null, {}, {}, {}, {
49
+ keepAlive: boolean;
50
+ }>;
51
+ __isFragment?: never;
52
+ __isTeleport?: never;
53
+ __isSuspense?: never;
54
+ } & vue.ComponentOptionsBase<Readonly<vue.ExtractPropTypes<{
55
+ nodeName: {
56
+ type: StringConstructor;
57
+ required: true;
58
+ };
59
+ keepAlive: {
60
+ type: BooleanConstructor;
61
+ default: boolean;
62
+ };
63
+ }>> & Readonly<{}>, () => VNode | null, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, {
64
+ keepAlive: boolean;
65
+ }, {}, string, {}, vue.GlobalComponents, vue.GlobalDirectives, string, vue.ComponentProvideOptions> & vue.VNodeProps & vue.AllowedComponentProps & vue.ComponentCustomProps & {
66
+ Match: vue.DefineComponent<vue.ExtractPropTypes<{
67
+ segment: {
68
+ type: vue.PropType<string>;
69
+ required: true;
70
+ };
71
+ exact: {
72
+ type: BooleanConstructor;
73
+ default: boolean;
74
+ };
75
+ fallback: {
76
+ type: vue.PropType<VNode | (() => VNode)>;
77
+ default: undefined;
78
+ };
79
+ }>, {}, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<vue.ExtractPropTypes<{
80
+ segment: {
81
+ type: vue.PropType<string>;
82
+ required: true;
83
+ };
84
+ exact: {
85
+ type: BooleanConstructor;
86
+ default: boolean;
87
+ };
88
+ fallback: {
89
+ type: vue.PropType<VNode | (() => VNode)>;
90
+ default: undefined;
91
+ };
92
+ }>> & Readonly<{}>, {
93
+ exact: boolean;
94
+ fallback: VNode<vue.RendererNode, vue.RendererElement, {
95
+ [key: string]: any;
96
+ }> | (() => VNode);
97
+ }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
98
+ NotFound: vue.DefineComponent<{}, {}, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
99
+ };
100
+
101
+ declare const Link: vue.DefineComponent<vue.ExtractPropTypes<{
102
+ routeName: {
103
+ type: StringConstructor;
104
+ required: true;
105
+ };
106
+ routeParams: {
107
+ type: PropType<Params>;
108
+ default: () => Readonly<{}>;
109
+ };
110
+ routeOptions: {
111
+ type: PropType<NavigationOptions>;
112
+ default: () => Readonly<{}>;
113
+ };
114
+ class: {
115
+ type: StringConstructor;
116
+ default: undefined;
117
+ };
118
+ activeClassName: {
119
+ type: StringConstructor;
120
+ default: string;
121
+ };
122
+ activeStrict: {
123
+ type: BooleanConstructor;
124
+ default: boolean;
125
+ };
126
+ ignoreQueryParams: {
127
+ type: BooleanConstructor;
128
+ default: boolean;
129
+ };
130
+ target: {
131
+ type: StringConstructor;
132
+ default: undefined;
133
+ };
134
+ }>, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
135
+ [key: string]: any;
136
+ }>, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<vue.ExtractPropTypes<{
137
+ routeName: {
138
+ type: StringConstructor;
139
+ required: true;
140
+ };
141
+ routeParams: {
142
+ type: PropType<Params>;
143
+ default: () => Readonly<{}>;
144
+ };
145
+ routeOptions: {
146
+ type: PropType<NavigationOptions>;
147
+ default: () => Readonly<{}>;
148
+ };
149
+ class: {
150
+ type: StringConstructor;
151
+ default: undefined;
152
+ };
153
+ activeClassName: {
154
+ type: StringConstructor;
155
+ default: string;
156
+ };
157
+ activeStrict: {
158
+ type: BooleanConstructor;
159
+ default: boolean;
160
+ };
161
+ ignoreQueryParams: {
162
+ type: BooleanConstructor;
163
+ default: boolean;
164
+ };
165
+ target: {
166
+ type: StringConstructor;
167
+ default: undefined;
168
+ };
169
+ }>> & Readonly<{}>, {
170
+ class: string;
171
+ ignoreQueryParams: boolean;
172
+ routeParams: Params;
173
+ routeOptions: NavigationOptions;
174
+ activeClassName: string;
175
+ activeStrict: boolean;
176
+ target: string;
177
+ }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
178
+
179
+ interface LinkDirectiveValue {
180
+ name: string;
181
+ params?: Params;
182
+ options?: NavigationOptions;
183
+ }
184
+ declare const vLink: Directive<HTMLElement, LinkDirectiveValue>;
185
+
186
+ declare const useRouter: () => Router;
187
+
188
+ declare const useNavigator: () => Navigator;
189
+
190
+ declare const useRouteUtils: () => RouteUtils;
191
+
192
+ interface RouteContext {
193
+ navigator: Navigator;
194
+ route: ShallowRef<State | undefined>;
195
+ previousRoute: ShallowRef<State | undefined>;
196
+ }
197
+ interface LinkProps<P extends Params = Params> {
198
+ routeName: string;
199
+ routeParams?: P;
200
+ routeOptions?: NavigationOptions;
201
+ class?: string;
202
+ activeClassName?: string;
203
+ activeStrict?: boolean;
204
+ ignoreQueryParams?: boolean;
205
+ target?: string;
206
+ }
207
+
208
+ declare const useRoute: () => RouteContext;
209
+
210
+ declare function useRouteNode(nodeName: string): RouteContext;
211
+
212
+ declare function useRouterTransition(): ShallowRef<RouterTransitionSnapshot>;
213
+
214
+ declare function createRouterPlugin(router: Router): Plugin<[]>;
215
+
216
+ declare const RouterProvider: vue.DefineComponent<vue.ExtractPropTypes<{
217
+ router: {
218
+ type: PropType<Router>;
219
+ required: true;
220
+ };
221
+ announceNavigation: {
222
+ type: BooleanConstructor;
223
+ default: boolean;
224
+ };
225
+ }>, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
226
+ [key: string]: any;
227
+ }>[] | undefined, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<vue.ExtractPropTypes<{
228
+ router: {
229
+ type: PropType<Router>;
230
+ required: true;
231
+ };
232
+ announceNavigation: {
233
+ type: BooleanConstructor;
234
+ default: boolean;
235
+ };
236
+ }>> & Readonly<{}>, {
237
+ announceNavigation: boolean;
238
+ }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
239
+
240
+ declare const RouterKey: InjectionKey<Router>;
241
+ declare const NavigatorKey: InjectionKey<Navigator>;
242
+ declare const RouteKey: InjectionKey<RouteContext>;
243
+
244
+ export { Link, type LinkDirectiveValue, type LinkProps, NavigatorKey, RouteKey, RouteView, type MatchProps as RouteViewMatchProps, type NotFoundProps as RouteViewNotFoundProps, type RouteViewProps, RouterKey, RouterProvider, createRouterPlugin, useNavigator, useRoute, useRouteNode, useRouteUtils, useRouter, useRouterTransition, vLink };
@@ -0,0 +1 @@
1
+ var e=require("vue"),t=require("@real-router/core"),r=require("@real-router/route-utils"),o=require("@real-router/sources"),n=require("dom-utils"),u=require("@real-router/core/api");function a(){return null}var s=e.defineComponent({name:"RouteView.Match",props:{segment:{type:String,required:!0},exact:{type:Boolean,default:!1},fallback:{type:[Object,Function],default:void 0}},render:a}),i=e.defineComponent({name:"RouteView.NotFound",render:a});function c(e,t,o){return o?e===t:r.startsWithSegment(e,t)}function l(t){if(Array.isArray(t)){const r=[];for(const o of t)Array.isArray(o)?r.push(...l(o)):e.isVNode(o)&&r.push(o);return r}return e.isVNode(t)?[t]:[]}function p(t,r){const o=l(t);for(const t of o)t.type===s||t.type===i?r.push(t):t.type===e.Fragment&&p(t.children,r)}function d(t){const r=e.shallowRef(t.getSnapshot()),o=t.subscribe(()=>{r.value=t.getSnapshot()});return e.onScopeDispose(o),r}var f=Symbol("RouterKey"),v=Symbol("NavigatorKey"),m=Symbol("RouteKey"),g=()=>{const t=e.inject(f);if(!t)throw new Error("useRouter must be used within a RouterProvider");return t};function y(r){const n=g(),u=d(o.createRouteNodeSource(n,r)),a=t.getNavigator(n),s=e.shallowRef(u.value.route),i=e.shallowRef(u.value.previousRoute);return e.watch(u,e=>{s.value=e.route,i.value=e.previousRoute},{flush:"sync"}),{navigator:a,route:s,previousRoute:i}}function R(e){const t=e.children;return t?.default?.()??null}function h(t,r){if(void 0===r)return t;const o="function"==typeof r?r():r;return e.h(e.Suspense,{},{default:()=>t,fallback:()=>o})}var N=e.defineComponent({name:"RouteView",props:{nodeName:{type:String,required:!0},keepAlive:{type:Boolean,default:!1}},setup(r,{slots:o}){const n=y(r.nodeName),u=new Map;return()=>{const a=n.route.value;if(!a)return null;const l=[];p(o.default?.(),l);const{rendered:d,fallback:f}=function(e,r,o){let n,u=null,a=!1;const s=[];for(const t of e){if(t.type===i){u=t.children;continue}const e=t.props,l=e?.segment??"";!a&&c(r,o?`${o}.${l}`:l,e?.exact??!1)&&(a=!0,n=e?.fallback,s.push(t))}if(!a&&r===t.UNKNOWN_ROUTE&&null!==u){const t=e.filter(e=>e.type===i).at(-1);t&&s.push(t)}return{rendered:s,activeMatchFound:a,fallback:n}}(l,a.name,r.nodeName);if(0===d.length)return null;const v=d[0];if(!r.keepAlive){if(v.type===s||v.type===i){const t=R(v);return t?h(e.h(e.Fragment,t),f):null}return null}const m=v.props,g=m?.segment??"__not-found__",y=function(t,r){const o=t.get(r);if(o)return o;const n=e.markRaw(e.defineComponent({name:`KeepAlive-${r}`,setup:(e,t)=>()=>t.slots.default?.()}));return t.set(r,n),n}(u,g),N=R(v)??[];return h(e.h(e.KeepAlive,null,{default:()=>e.h(y,{key:g},{default:()=>N})}),f)}}}),w=Object.assign(N,{Match:s,NotFound:i}),b=Object.freeze({}),k=Object.freeze({}),S=e.defineComponent({name:"Link",props:{routeName:{type:String,required:!0},routeParams:{type:Object,default:()=>b},routeOptions:{type:Object,default:()=>k},class:{type:String,default:void 0},activeClassName:{type:String,default:"active"},activeStrict:{type:Boolean,default:!1},ignoreQueryParams:{type:Boolean,default:!0},target:{type:String,default:void 0}},setup(t,{slots:r,attrs:u}){const a=g(),s=function(e,t,r=!1,n=!0){const u=g();return d(o.createActiveRouteSource(u,e,t,{strict:r,ignoreQueryParams:n}))}(t.routeName,t.routeParams,t.activeStrict,t.ignoreQueryParams),i=e.computed(()=>n.buildHref(a,t.routeName,t.routeParams)),c=e.computed(()=>n.buildActiveClassName(s.value,t.activeClassName,t.class)),l=e=>{u.onClick&&"function"==typeof u.onClick&&(u.onClick(e),e.defaultPrevented)||n.shouldNavigate(e)&&"_blank"!==t.target&&(e.preventDefault(),a.navigate(t.routeName,t.routeParams,t.routeOptions).catch(()=>{}))};return()=>e.h("a",{...u,href:i.value,class:c.value,target:t.target,onClick:l},r.default?.())}}),P=null;function x(e){P=e}function A(){if(!P)throw new Error("v-link directive requires a RouterProvider ancestor. Make sure RouterProvider is mounted.");return P}var C=new WeakMap,q=new WeakMap;function E(e,t,r){const o=function(e,t){return r=>{n.shouldNavigate(r)&&(r.preventDefault(),e.navigate(t.name,t.params??{},t.options??{}).catch(()=>{}))}}(t,r),u=function(e,t,r){return o=>{"Enter"!==o.key||r instanceof HTMLButtonElement||e.navigate(t.name,t.params??{},t.options??{}).catch(()=>{})}}(t,r,e);e.addEventListener("click",o),e.addEventListener("keydown",u),C.set(e,o),q.set(e,u)}function O(e){const t=C.get(e),r=q.get(e);t&&e.removeEventListener("click",t),r&&e.removeEventListener("keydown",r),C.delete(e),q.delete(e)}var j={mounted(e,t){const r=A();n.applyLinkA11y(e),e.style.cursor="pointer",E(e,r,t.value)},updated(e,t){const r=A();O(e),E(e,r,t.value)},beforeUnmount(e){O(e)}},K=e.defineComponent({name:"RouterProvider",props:{router:{type:Object,required:!0},announceNavigation:{type:Boolean,default:!1}},setup(r,{slots:u}){e.onMounted(()=>{if(!r.announceNavigation)return;const t=n.createRouteAnnouncer(r.router);e.onUnmounted(()=>{t.destroy()})});const a=t.getNavigator(r.router);x(r.router);const s=o.createRouteSource(r.router),i=s.getSnapshot(),c=e.shallowRef(i.route),l=e.shallowRef(i.previousRoute),p=s.subscribe(()=>{const e=s.getSnapshot();c.value=e.route,l.value=e.previousRoute});return e.onScopeDispose(p),e.provide(f,r.router),e.provide(v,a),e.provide(m,{navigator:a,route:c,previousRoute:l}),()=>u.default?.()}});exports.Link=S,exports.NavigatorKey=v,exports.RouteKey=m,exports.RouteView=w,exports.RouterKey=f,exports.RouterProvider=K,exports.createRouterPlugin=function(r){return{install(n){const u=t.getNavigator(r);x(r);const a=o.createRouteSource(r),s=a.getSnapshot(),i=e.shallowRef(s.route),c=e.shallowRef(s.previousRoute);a.subscribe(()=>{const e=a.getSnapshot();i.value=e.route,c.value=e.previousRoute}),n.provide(f,r),n.provide(v,u),n.provide(m,{navigator:u,route:i,previousRoute:c})}}},exports.useNavigator=()=>{const t=e.inject(v);if(!t)throw new Error("useNavigator must be used within a RouterProvider");return t},exports.useRoute=()=>{const t=e.inject(m);if(!t)throw new Error("useRoute must be used within a RouterProvider");return t},exports.useRouteNode=y,exports.useRouteUtils=()=>{const e=g();return r.getRouteUtils(u.getPluginApi(e).getTree())},exports.useRouter=g,exports.useRouterTransition=function(){const e=g();return d(o.createTransitionSource(e))},exports.vLink=j;//# sourceMappingURL=index.js.map