@iyulab/router 0.1.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/LICENSE +21 -0
- package/README.md +240 -0
- package/dist/main.cjs.js +32729 -0
- package/dist/main.d.ts +382 -0
- package/dist/main.es.js +32731 -0
- package/dist/main.umd.js +32729 -0
- package/package.json +52 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 iyulab
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
# @iyulab/router
|
|
2
|
+
|
|
3
|
+
A modern client-side router for web applications with support for Lit and React components.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🚀 Modern URLPattern-based routing
|
|
8
|
+
- 🔧 Support for both Lit and React components
|
|
9
|
+
- 📱 Client-side navigation with history management
|
|
10
|
+
- 🎯 Nested routing support
|
|
11
|
+
- ⚡ Async data loading with loaders
|
|
12
|
+
- 🔗 Smart link component with external link detection
|
|
13
|
+
- 📊 Route progress tracking
|
|
14
|
+
- 🎨 Flexible outlet system for component rendering
|
|
15
|
+
- 🌐 Global route information access via `window.route`
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @iyulab/router
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
### Basic Setup
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import { Router } from '@iyulab/router';
|
|
29
|
+
|
|
30
|
+
const router = new Router({
|
|
31
|
+
root: document.getElementById('app')!,
|
|
32
|
+
basepath: '/app',
|
|
33
|
+
routes: [
|
|
34
|
+
{
|
|
35
|
+
path: '/',
|
|
36
|
+
element: 'home-page'
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
path: '/user/:id',
|
|
40
|
+
component: UserComponent,
|
|
41
|
+
loader: async (routeInfo) => {
|
|
42
|
+
const response = await fetch(`/api/user/${routeInfo.params.id}`);
|
|
43
|
+
return response.json();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
],
|
|
47
|
+
notfound: 'not-found-page'
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Connect the router
|
|
51
|
+
router.connect();
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Using with Lit Components
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import { LitElement, html } from 'lit';
|
|
58
|
+
import { customElement } from 'lit/decorators.js';
|
|
59
|
+
import { UOutlet, ULink } from '@iyulab/router';
|
|
60
|
+
|
|
61
|
+
@customElement('app-root')
|
|
62
|
+
export class AppRoot extends LitElement {
|
|
63
|
+
render() {
|
|
64
|
+
return html`
|
|
65
|
+
<nav>
|
|
66
|
+
<u-link href="/">Home</u-link>
|
|
67
|
+
<u-link href="/about">About</u-link>
|
|
68
|
+
<u-link href="/user/123">User</u-link>
|
|
69
|
+
</nav>
|
|
70
|
+
<main>
|
|
71
|
+
<u-outlet></u-outlet>
|
|
72
|
+
</main>
|
|
73
|
+
`;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Using with React Components
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
import React from 'react';
|
|
82
|
+
import { Outlet, Link } from '@iyulab/router';
|
|
83
|
+
|
|
84
|
+
export function AppRoot() {
|
|
85
|
+
return (
|
|
86
|
+
<div>
|
|
87
|
+
<nav>
|
|
88
|
+
<Link href="/">Home</Link>
|
|
89
|
+
<Link href="/about">About</Link>
|
|
90
|
+
<Link href="/user/123">User</Link>
|
|
91
|
+
</nav>
|
|
92
|
+
<main>
|
|
93
|
+
<Outlet />
|
|
94
|
+
</main>
|
|
95
|
+
</div>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Nested Routes
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
const routes = [
|
|
104
|
+
{
|
|
105
|
+
path: '/dashboard',
|
|
106
|
+
element: 'dashboard-layout',
|
|
107
|
+
children: [
|
|
108
|
+
{
|
|
109
|
+
index: true,
|
|
110
|
+
element: 'dashboard-home'
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
path: 'settings',
|
|
114
|
+
element: 'dashboard-settings'
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
path: 'profile',
|
|
118
|
+
component: ProfileComponent
|
|
119
|
+
}
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
];
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Route Information Access
|
|
126
|
+
|
|
127
|
+
You can access current route information globally via `window.route`:
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
// In any component or script
|
|
131
|
+
console.log('Current path:', window.route.pathname);
|
|
132
|
+
console.log('Route params:', window.route.params);
|
|
133
|
+
console.log('Query params:', window.route.search);
|
|
134
|
+
console.log('Route data:', window.route.data);
|
|
135
|
+
|
|
136
|
+
// For Lit components
|
|
137
|
+
import { LitElement, html } from 'lit';
|
|
138
|
+
import { customElement } from 'lit/decorators.js';
|
|
139
|
+
|
|
140
|
+
@customElement('my-component')
|
|
141
|
+
export class MyComponent extends LitElement {
|
|
142
|
+
connectedCallback() {
|
|
143
|
+
super.connectedCallback();
|
|
144
|
+
// Listen for route changes
|
|
145
|
+
document.addEventListener('route-change', this.onRouteChange);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
disconnectedCallback() {
|
|
149
|
+
document.removeEventListener('route-change', this.onRouteChange);
|
|
150
|
+
super.disconnectedCallback();
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
private onRouteChange = () => {
|
|
154
|
+
this.requestUpdate(); // Trigger re-render when route changes
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
render() {
|
|
158
|
+
return html`
|
|
159
|
+
<div>Current path: ${window.route?.pathname}</div>
|
|
160
|
+
<div>Params: ${JSON.stringify(window.route?.params)}</div>
|
|
161
|
+
`;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// For React components
|
|
166
|
+
import React, { useState, useEffect } from 'react';
|
|
167
|
+
|
|
168
|
+
export function MyReactComponent() {
|
|
169
|
+
const [routeInfo, setRouteInfo] = useState(window.route);
|
|
170
|
+
|
|
171
|
+
useEffect(() => {
|
|
172
|
+
const handleRouteChange = () => {
|
|
173
|
+
setRouteInfo(window.route);
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
document.addEventListener('route-change', handleRouteChange);
|
|
177
|
+
return () => document.removeEventListener('route-change', handleRouteChange);
|
|
178
|
+
}, []);
|
|
179
|
+
|
|
180
|
+
return (
|
|
181
|
+
<div>
|
|
182
|
+
<div>Current path: {routeInfo?.pathname}</div>
|
|
183
|
+
<div>Params: {JSON.stringify(routeInfo?.params)}</div>
|
|
184
|
+
</div>
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## API Reference
|
|
190
|
+
|
|
191
|
+
### Router
|
|
192
|
+
|
|
193
|
+
#### Constructor Options
|
|
194
|
+
|
|
195
|
+
- `root`: HTMLElement - The root element where the router will render components
|
|
196
|
+
- `basepath`: string - The base path for the router (optional, defaults to '/')
|
|
197
|
+
- `routes`: Route[] - Array of route configurations
|
|
198
|
+
- `notfound`: LitElement class or string - Component to render when no route matches
|
|
199
|
+
|
|
200
|
+
#### Methods
|
|
201
|
+
|
|
202
|
+
- `connect()`: Connect the router and start listening to navigation events
|
|
203
|
+
- `disconnect()`: Disconnect the router and stop listening to events
|
|
204
|
+
- `go(href: string)`: Navigate to a specific path
|
|
205
|
+
- `goBase()`: Navigate to the base path
|
|
206
|
+
|
|
207
|
+
### Route Configuration
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
type Route = {
|
|
211
|
+
path?: string; // URL pattern (URLPattern syntax)
|
|
212
|
+
index?: boolean; // Index route (matches parent path exactly)
|
|
213
|
+
element?: typeof LitElement | string; // Lit element to render
|
|
214
|
+
component?: ComponentType; // React component to render
|
|
215
|
+
loader?: (routeInfo: RouteInfo) => Promise<any>; // Data loader function
|
|
216
|
+
title?: string; // Page title
|
|
217
|
+
children?: Route[]; // Nested routes
|
|
218
|
+
force?: boolean; // Force re-render on navigation
|
|
219
|
+
};
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Components
|
|
223
|
+
|
|
224
|
+
- `UOutlet` / `Outlet`: Outlet component for rendering route components
|
|
225
|
+
- `ULink` / `Link`: Smart link component with client-side navigation
|
|
226
|
+
|
|
227
|
+
### Global Route Access
|
|
228
|
+
|
|
229
|
+
- `window.route`: Global access to current route information (RouteInfo object)
|
|
230
|
+
|
|
231
|
+
## Events
|
|
232
|
+
|
|
233
|
+
The router dispatches the following events:
|
|
234
|
+
|
|
235
|
+
- `route-change`: Fired when the route changes (detail contains RouteInfo)
|
|
236
|
+
- `route-progress`: Fired during navigation with progress value (0-1)
|
|
237
|
+
|
|
238
|
+
## License
|
|
239
|
+
|
|
240
|
+
MIT
|