svelte-navigator-lite 0.1.0 → 0.1.2
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/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/router.svelte.d.ts +29 -0
- package/dist/router.svelte.js +200 -0
- package/package.json +1 -2
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export declare const page: import("svelte/store").Readable<{
|
|
2
|
+
url: URL;
|
|
3
|
+
}>;
|
|
4
|
+
export declare function goto(path: string, { replaceState }?: {
|
|
5
|
+
replaceState?: boolean | undefined;
|
|
6
|
+
}): Promise<void>;
|
|
7
|
+
export type Route = {
|
|
8
|
+
rootPath: string;
|
|
9
|
+
segments: ({
|
|
10
|
+
name?: string;
|
|
11
|
+
enforceVal?: string;
|
|
12
|
+
})[];
|
|
13
|
+
searchParams?: string[];
|
|
14
|
+
routeGuards?: RouteGuard[];
|
|
15
|
+
};
|
|
16
|
+
export type RouteGuard = {
|
|
17
|
+
fn: () => boolean;
|
|
18
|
+
redirectTo: string;
|
|
19
|
+
};
|
|
20
|
+
export type RouteList = Record<string, Route>;
|
|
21
|
+
export type Router = ReturnType<typeof _createRouter>;
|
|
22
|
+
export declare function _createRouter(RouteList?: RouteList): {
|
|
23
|
+
readonly route: string;
|
|
24
|
+
readonly params: Record<string, string>;
|
|
25
|
+
navigate(route: string, params?: Record<string, string>): Promise<void>;
|
|
26
|
+
registerRoute(name: string, route: Route): void;
|
|
27
|
+
};
|
|
28
|
+
export declare let router: Router;
|
|
29
|
+
export declare function createRouter(RouteList: RouteList, defaultRoute: string): void;
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { readable } from 'svelte/store';
|
|
2
|
+
/**
|
|
3
|
+
* Minimal replacement for SvelteKit's `page` store.
|
|
4
|
+
* Emits `{ url: URL }` and updates on history navigation.
|
|
5
|
+
*/
|
|
6
|
+
function createPageStore() {
|
|
7
|
+
if (typeof window === 'undefined') {
|
|
8
|
+
return readable({ url: new URL('http://localhost/') }, () => { });
|
|
9
|
+
}
|
|
10
|
+
const getValue = () => ({ url: new URL(window.location.href) });
|
|
11
|
+
return readable(getValue(), (set) => {
|
|
12
|
+
const update = () => set(getValue());
|
|
13
|
+
window.addEventListener('popstate', update);
|
|
14
|
+
window.addEventListener('hashchange', update);
|
|
15
|
+
return () => {
|
|
16
|
+
window.removeEventListener('popstate', update);
|
|
17
|
+
window.removeEventListener('hashchange', update);
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
export const page = createPageStore();
|
|
22
|
+
export async function goto(path, { replaceState = false } = {}) {
|
|
23
|
+
if (typeof window === 'undefined')
|
|
24
|
+
return;
|
|
25
|
+
// 1. Create a URL object based on the current origin to "clean" the input
|
|
26
|
+
// This prevents 'http://login' from being treated as a new domain
|
|
27
|
+
const url = new URL(path, window.location.origin);
|
|
28
|
+
// 2. Ensure we only take the pathname and search params
|
|
29
|
+
const cleanPath = url.pathname + url.search + url.hash;
|
|
30
|
+
const push = replaceState
|
|
31
|
+
? history.replaceState.bind(history)
|
|
32
|
+
: history.pushState.bind(history);
|
|
33
|
+
// 3. Use the cleaned path
|
|
34
|
+
push({}, '', cleanPath);
|
|
35
|
+
window.dispatchEvent(new PopStateEvent('popstate'));
|
|
36
|
+
}
|
|
37
|
+
export function _createRouter(RouteList = {}) {
|
|
38
|
+
let state = $state({
|
|
39
|
+
current: '',
|
|
40
|
+
params: {},
|
|
41
|
+
});
|
|
42
|
+
let routes = {};
|
|
43
|
+
function parseUrl(url) {
|
|
44
|
+
const path = new URL(url).pathname.slice(1);
|
|
45
|
+
const segments = path.split('/').filter(Boolean);
|
|
46
|
+
for (const [routeName, route] of Object.entries(routes)) {
|
|
47
|
+
if (route.rootPath !== segments[0])
|
|
48
|
+
continue;
|
|
49
|
+
let params = {};
|
|
50
|
+
let match = true;
|
|
51
|
+
// Check segments
|
|
52
|
+
for (let i = 0; i < route.segments.length; i++) {
|
|
53
|
+
const routeSegment = route.segments[i];
|
|
54
|
+
const urlSegment = segments[i + 1];
|
|
55
|
+
if (routeSegment.enforceVal) {
|
|
56
|
+
if (urlSegment !== routeSegment.enforceVal) {
|
|
57
|
+
match = false;
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else if (routeSegment.name) {
|
|
62
|
+
if (!urlSegment) {
|
|
63
|
+
match = false;
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
params[routeSegment.name] = urlSegment;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (match) {
|
|
70
|
+
state.current = routeName;
|
|
71
|
+
state.params = params;
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Fallback to cal route
|
|
76
|
+
state.current = 'cal';
|
|
77
|
+
state.params = {};
|
|
78
|
+
// if (segments[0] === 'login') {
|
|
79
|
+
// state.current = 'login';
|
|
80
|
+
// state.params = {};
|
|
81
|
+
// } else if (segments[0] === 'signup') {
|
|
82
|
+
// state.current = 'signup';
|
|
83
|
+
// state.params = {};
|
|
84
|
+
// } else if (segments[0] === 'signup' && new URLSearchParams(new URL(url).search).get('redirect')) {
|
|
85
|
+
// state.current = 'signup';
|
|
86
|
+
// state.params = { redirect: new URLSearchParams(new URL(url).search).get('redirect')! };
|
|
87
|
+
// } else if (segments[0] === 'verify-email') {
|
|
88
|
+
// state.current = 'verify-email';
|
|
89
|
+
// state.params = {};
|
|
90
|
+
// } else if (segments[0] === 'cal' && segments.length === 4) {
|
|
91
|
+
// state.current = 'cal-date';
|
|
92
|
+
// state.params = { mm: segments[1], dd: segments[2], yyyy: segments[3] };
|
|
93
|
+
// } else if (segments[0] === 'cal' && segments.length === 1) {
|
|
94
|
+
// state.current = 'cal';
|
|
95
|
+
// state.params = {};
|
|
96
|
+
// } else if (segments[0] === 'event' && segments[1] && segments[2] === 'edit') {
|
|
97
|
+
// state.current = 'edit';
|
|
98
|
+
// state.params = { eventId: segments[1] };
|
|
99
|
+
// } else if (segments[0] === 'event' && segments[1]) {
|
|
100
|
+
// state.current = 'event';
|
|
101
|
+
// state.params = { eventId: segments[1] };
|
|
102
|
+
// } else if (segments[0] === 'settings') {
|
|
103
|
+
// state.current = 'settings';
|
|
104
|
+
// state.params = {};
|
|
105
|
+
// } else if (segments[0] === 'forgot-password') {
|
|
106
|
+
// state.current = 'forgot-password';
|
|
107
|
+
// state.params = {};
|
|
108
|
+
// } else if (segments[0] === 'password-reset' && new URLSearchParams(new URL(url).search).get('token')) {
|
|
109
|
+
// state.current = 'password-reset';
|
|
110
|
+
// state.params = { token: new URLSearchParams(new URL(url).search).get('token')! };
|
|
111
|
+
// } else if (segments[0] === 'groups') {
|
|
112
|
+
// state.current = 'groups';
|
|
113
|
+
// state.params = {};
|
|
114
|
+
// } else if (segments[0] === 'create') {
|
|
115
|
+
// state.current = 'create';
|
|
116
|
+
// state.params = {};
|
|
117
|
+
// } else if (segments[0] === 'calendar' && segments[1] === 'create') {
|
|
118
|
+
// state.current = 'create-calendar';
|
|
119
|
+
// state.params = {};
|
|
120
|
+
// } else if (segments[0] === 'calendar' && segments[1] && segments[2] === 'edit') {
|
|
121
|
+
// state.current = 'edit-calendar';
|
|
122
|
+
// state.params = { calendarId: segments[1] };
|
|
123
|
+
// } else if (segments[0] === 'cal' && segments[1] === 'public' && segments[2]) {
|
|
124
|
+
// state.current = 'public-calendar';
|
|
125
|
+
// state.params = { calendarId: segments[2] };
|
|
126
|
+
// } else {
|
|
127
|
+
// state.current = 'cal';
|
|
128
|
+
// state.params = {};
|
|
129
|
+
// }
|
|
130
|
+
}
|
|
131
|
+
page.subscribe((p) => parseUrl(p.url.toString()));
|
|
132
|
+
return {
|
|
133
|
+
get route() {
|
|
134
|
+
return state.current;
|
|
135
|
+
;
|
|
136
|
+
},
|
|
137
|
+
get params() {
|
|
138
|
+
return state.params;
|
|
139
|
+
},
|
|
140
|
+
async navigate(route, params) {
|
|
141
|
+
let path = routes[route].rootPath;
|
|
142
|
+
for (const guard of routes[route].routeGuards || []) {
|
|
143
|
+
if (guard.fn()) {
|
|
144
|
+
await this.navigate(guard.redirectTo);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
for (const segment of routes[route].segments) {
|
|
149
|
+
if (segment.enforceVal) {
|
|
150
|
+
path += `/${segment.enforceVal}`;
|
|
151
|
+
}
|
|
152
|
+
else if (segment.name) {
|
|
153
|
+
if (!params || !params[segment.name]) {
|
|
154
|
+
throw new Error(`Missing parameter ${segment.name} for route ${route}`);
|
|
155
|
+
}
|
|
156
|
+
path += `/${params[segment.name]}`;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (routes[route].searchParams) {
|
|
160
|
+
const searchParams = new URLSearchParams();
|
|
161
|
+
for (const param of routes[route].searchParams) {
|
|
162
|
+
if (params && params[param]) {
|
|
163
|
+
searchParams.set(param, params[param]);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
path += `?${searchParams.toString()}`;
|
|
167
|
+
}
|
|
168
|
+
// if (route === 'cal-date' && params) {
|
|
169
|
+
// path = `/cal/${params.mm}/${params.dd}/${params.yyyy}`;
|
|
170
|
+
// } else if (route === 'event' && params) {
|
|
171
|
+
// path = `/event/${params.eventId}`;
|
|
172
|
+
// } else if (route === 'edit' && params) {
|
|
173
|
+
// path = `/event/${params.eventId}/edit`;
|
|
174
|
+
// } else if (route === 'create-calendar') {
|
|
175
|
+
// path = '/calendar/create';
|
|
176
|
+
// } else if (route === 'edit-calendar' && params) {
|
|
177
|
+
// path = `/calendar/${params.calendarId}/edit`;
|
|
178
|
+
// } else if (route === 'public-calendar' && params) {
|
|
179
|
+
// path = `/cal/public/${params.calendarId}`;
|
|
180
|
+
// } else if (route === 'password-reset' && params) {
|
|
181
|
+
// path = '/password-reset?token=' + params.token;
|
|
182
|
+
// } else if (route === 'cal') {
|
|
183
|
+
// path = '/cal';
|
|
184
|
+
// } else {
|
|
185
|
+
// path = `/${route}`;
|
|
186
|
+
// }
|
|
187
|
+
await goto(path);
|
|
188
|
+
},
|
|
189
|
+
registerRoute(name, route) {
|
|
190
|
+
routes[name] = route;
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
export let router = _createRouter();
|
|
195
|
+
export function createRouter(RouteList, defaultRoute) {
|
|
196
|
+
for (const [name, route] of Object.entries(RouteList)) {
|
|
197
|
+
router.registerRoute(name, route);
|
|
198
|
+
}
|
|
199
|
+
router.navigate(defaultRoute);
|
|
200
|
+
}
|
package/package.json
CHANGED