application.ts 1.0.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 +358 -0
- package/dist/app/App.d.ts +124 -0
- package/dist/app/App.js +326 -0
- package/dist/app/App.js.map +1 -0
- package/dist/app/AppView.d.ts +143 -0
- package/dist/app/AppView.js +264 -0
- package/dist/app/AppView.js.map +1 -0
- package/dist/app/types.d.ts +67 -0
- package/dist/app/types.js +2 -0
- package/dist/app/types.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/navigation/route.d.ts +34 -0
- package/dist/navigation/route.js +68 -0
- package/dist/navigation/route.js.map +1 -0
- package/dist/navigation/router.d.ts +92 -0
- package/dist/navigation/router.js +246 -0
- package/dist/navigation/router.js.map +1 -0
- package/dist/navigation/types.d.ts +63 -0
- package/dist/navigation/types.js +9 -0
- package/dist/navigation/types.js.map +1 -0
- package/package.json +68 -0
- package/src/app/App.ts +391 -0
- package/src/app/AppView.ts +333 -0
- package/src/app/types.ts +78 -0
- package/src/index.ts +28 -0
- package/src/navigation/route.ts +87 -0
- package/src/navigation/router.ts +284 -0
- package/src/navigation/types.ts +73 -0
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { Route } from './route';
|
|
2
|
+
import { NavigationEvents } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Router class for managing navigation and route mapping
|
|
5
|
+
* Emits events for Application.ts to handle view rendering via StackView
|
|
6
|
+
*/
|
|
7
|
+
export class Router extends EventTarget {
|
|
8
|
+
constructor() {
|
|
9
|
+
super();
|
|
10
|
+
this.routes = new Map();
|
|
11
|
+
this.isInitialized = false;
|
|
12
|
+
this.basePath = '';
|
|
13
|
+
this._currentPath = '/';
|
|
14
|
+
this._currentParams = {};
|
|
15
|
+
// Listen for popstate events (browser back/forward)
|
|
16
|
+
window.addEventListener('popstate', () => {
|
|
17
|
+
this.handleRouteChange();
|
|
18
|
+
});
|
|
19
|
+
// Intercept link clicks for client-side navigation
|
|
20
|
+
document.addEventListener('click', (e) => {
|
|
21
|
+
const target = e.target;
|
|
22
|
+
const link = target.closest('a[href]');
|
|
23
|
+
if (link && link.href.startsWith(window.location.origin) && !link.hasAttribute('target')) {
|
|
24
|
+
e.preventDefault();
|
|
25
|
+
this.navigate(link.pathname);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Map a route path to a handler (view identifier)
|
|
31
|
+
* @param path - The route path (e.g., '/', '/user/:id')
|
|
32
|
+
* @param handler - The view identifier/handler
|
|
33
|
+
* @param options - Optional route configuration
|
|
34
|
+
* @returns The router instance for chaining
|
|
35
|
+
*/
|
|
36
|
+
map(path, handler, options) {
|
|
37
|
+
const route = new Route(path, options);
|
|
38
|
+
this.routes.set(path, { route, handler });
|
|
39
|
+
return this;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Set the 404 not found handler
|
|
43
|
+
* @param handler - The view identifier to use for 404
|
|
44
|
+
* @returns The router instance for chaining
|
|
45
|
+
*/
|
|
46
|
+
notFound(handler) {
|
|
47
|
+
this.notFoundHandler = handler;
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Set the base path for all routes
|
|
52
|
+
* @param base - Base path (e.g., '/basic', '/app')
|
|
53
|
+
* @returns The router instance for chaining
|
|
54
|
+
*/
|
|
55
|
+
setBasePath(base) {
|
|
56
|
+
// Normalize: ensure starts with / and no trailing /
|
|
57
|
+
this.basePath = base.replace(/\/$/, '').replace(/^(?!\/)/, '/');
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Get the current base path
|
|
62
|
+
*/
|
|
63
|
+
getBasePath() {
|
|
64
|
+
return this.basePath;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Initialize the router and handle the current path
|
|
68
|
+
*/
|
|
69
|
+
start() {
|
|
70
|
+
if (this.isInitialized) {
|
|
71
|
+
console.warn('Router is already initialized');
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
// Auto-detect base path from <base> tag if not set
|
|
75
|
+
if (!this.basePath) {
|
|
76
|
+
const baseTag = document.querySelector('base[href]');
|
|
77
|
+
if (baseTag) {
|
|
78
|
+
const baseHref = baseTag.getAttribute('href') || '';
|
|
79
|
+
// Extract path from href (could be full URL or relative path)
|
|
80
|
+
try {
|
|
81
|
+
const url = new URL(baseHref, window.location.origin);
|
|
82
|
+
this.basePath = url.pathname.replace(/\/$/, '');
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
this.basePath = baseHref.replace(/\/$/, '');
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
this.isInitialized = true;
|
|
90
|
+
this.handleRouteChange();
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Navigate to a specific path
|
|
94
|
+
* @param path - The path to navigate to (relative to basePath)
|
|
95
|
+
* @param replaceState - If true, replaces current history entry instead of pushing
|
|
96
|
+
*/
|
|
97
|
+
async navigate(path, replaceState = false) {
|
|
98
|
+
// Strip basePath if present to get route path
|
|
99
|
+
const routePath = this.stripBasePath(path);
|
|
100
|
+
// Find matching route
|
|
101
|
+
const match = this.findRoute(routePath);
|
|
102
|
+
if (!match) {
|
|
103
|
+
this.emitNotFound(routePath);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const { route, handler, params } = match;
|
|
107
|
+
// Check route guard
|
|
108
|
+
const guardResult = await route.canEnter(params);
|
|
109
|
+
if (guardResult === false) {
|
|
110
|
+
// Navigation denied
|
|
111
|
+
console.warn(`Navigation to ${path} was denied by route guard`);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (typeof guardResult === 'string') {
|
|
115
|
+
// Redirect to another path
|
|
116
|
+
await this.navigate(guardResult, replaceState);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
// Add basePath to create full URL
|
|
120
|
+
const fullPath = this.addBasePath(routePath);
|
|
121
|
+
// Update browser history
|
|
122
|
+
if (replaceState) {
|
|
123
|
+
window.history.replaceState({ path: fullPath }, '', fullPath);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
window.history.pushState({ path: fullPath }, '', fullPath);
|
|
127
|
+
}
|
|
128
|
+
// Emit navigation event for Application.ts to handle
|
|
129
|
+
this.emitNavigation(routePath, params, handler, route.options.meta);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Get the current path (route pattern)
|
|
133
|
+
*/
|
|
134
|
+
get currentPath() {
|
|
135
|
+
return this._currentPath;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Get the current route parameters
|
|
139
|
+
*/
|
|
140
|
+
get currentParams() {
|
|
141
|
+
return this._currentParams;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Get the current route metadata
|
|
145
|
+
*/
|
|
146
|
+
get currentMeta() {
|
|
147
|
+
return this._currentMeta;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Find a route that matches the given path
|
|
151
|
+
*/
|
|
152
|
+
findRoute(path) {
|
|
153
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
154
|
+
for (const [_, { route, handler }] of this.routes) {
|
|
155
|
+
const params = route.match(path);
|
|
156
|
+
if (params !== null) {
|
|
157
|
+
return { route, handler, params };
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Handle route change (from popstate or initial load)
|
|
164
|
+
*/
|
|
165
|
+
async handleRouteChange() {
|
|
166
|
+
const routePath = this.stripBasePath(window.location.pathname);
|
|
167
|
+
await this.navigate(routePath, true);
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Strip base path from a full path
|
|
171
|
+
*/
|
|
172
|
+
stripBasePath(fullPath) {
|
|
173
|
+
if (!this.basePath) {
|
|
174
|
+
return fullPath;
|
|
175
|
+
}
|
|
176
|
+
if (fullPath.startsWith(this.basePath)) {
|
|
177
|
+
const stripped = fullPath.slice(this.basePath.length);
|
|
178
|
+
return stripped || '/';
|
|
179
|
+
}
|
|
180
|
+
return fullPath;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Add base path to a route path
|
|
184
|
+
*/
|
|
185
|
+
addBasePath(routePath) {
|
|
186
|
+
if (!this.basePath) {
|
|
187
|
+
return routePath;
|
|
188
|
+
}
|
|
189
|
+
// Ensure route path starts with /
|
|
190
|
+
const normalizedPath = routePath.startsWith('/') ? routePath : '/' + routePath;
|
|
191
|
+
return this.basePath + normalizedPath;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Emit navigation event
|
|
195
|
+
*/
|
|
196
|
+
emitNavigation(path, params, handler, meta) {
|
|
197
|
+
// Store current navigation state
|
|
198
|
+
this._currentPath = path;
|
|
199
|
+
this._currentParams = params;
|
|
200
|
+
this._currentMeta = meta;
|
|
201
|
+
const detail = {
|
|
202
|
+
path,
|
|
203
|
+
params,
|
|
204
|
+
handler,
|
|
205
|
+
meta
|
|
206
|
+
};
|
|
207
|
+
this.dispatchEvent(new CustomEvent(NavigationEvents.NAVIGATE, { detail }));
|
|
208
|
+
window.dispatchEvent(new CustomEvent(NavigationEvents.NAVIGATE, { detail }));
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Emit not found event
|
|
212
|
+
*/
|
|
213
|
+
emitNotFound(path) {
|
|
214
|
+
if (this.notFoundHandler) {
|
|
215
|
+
// Store current navigation state
|
|
216
|
+
this._currentPath = path;
|
|
217
|
+
this._currentParams = {};
|
|
218
|
+
this._currentMeta = undefined;
|
|
219
|
+
const detail = {
|
|
220
|
+
path,
|
|
221
|
+
params: {},
|
|
222
|
+
handler: this.notFoundHandler
|
|
223
|
+
};
|
|
224
|
+
this.dispatchEvent(new CustomEvent(NavigationEvents.NOT_FOUND, { detail }));
|
|
225
|
+
window.dispatchEvent(new CustomEvent(NavigationEvents.NOT_FOUND, { detail }));
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
console.error(`404: No route found for ${path} and no notFound handler configured`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Generate a URL for a route with parameters
|
|
233
|
+
* @param path - The route path pattern
|
|
234
|
+
* @param params - Parameters to inject
|
|
235
|
+
* @returns The generated URL (with basePath) or null if route not found
|
|
236
|
+
*/
|
|
237
|
+
generateUrl(path, params = {}) {
|
|
238
|
+
const routeEntry = this.routes.get(path);
|
|
239
|
+
if (!routeEntry) {
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
const routePath = routeEntry.route.generate(params);
|
|
243
|
+
return this.addBasePath(routePath);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
//# sourceMappingURL=router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/navigation/router.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route parameters extracted from URL path
|
|
3
|
+
*/
|
|
4
|
+
export type RouteParams = Record<string, string>;
|
|
5
|
+
/**
|
|
6
|
+
* Navigation guard function that can prevent navigation
|
|
7
|
+
* @returns true to allow navigation, false to prevent, or string path to redirect
|
|
8
|
+
*/
|
|
9
|
+
export type RouteGuard = (params: RouteParams) => boolean | string | Promise<boolean | string>;
|
|
10
|
+
/**
|
|
11
|
+
* Route configuration options
|
|
12
|
+
*/
|
|
13
|
+
export interface RouteOptions {
|
|
14
|
+
/**
|
|
15
|
+
* Guard function to check if navigation is allowed
|
|
16
|
+
*/
|
|
17
|
+
canEnter?: RouteGuard;
|
|
18
|
+
/**
|
|
19
|
+
* Additional metadata for the route
|
|
20
|
+
*/
|
|
21
|
+
meta?: Record<string, any>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Route handler - reference to view class constructor or string identifier
|
|
25
|
+
*/
|
|
26
|
+
export type RouteHandler<T = any> = (new () => T) | string;
|
|
27
|
+
/**
|
|
28
|
+
* Route definition
|
|
29
|
+
*/
|
|
30
|
+
export interface RouteDefinition {
|
|
31
|
+
path: string;
|
|
32
|
+
handler: RouteHandler;
|
|
33
|
+
options?: RouteOptions;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Navigation event detail
|
|
37
|
+
*/
|
|
38
|
+
export interface NavigationEventDetail {
|
|
39
|
+
/**
|
|
40
|
+
* The path being navigated to
|
|
41
|
+
*/
|
|
42
|
+
path: string;
|
|
43
|
+
/**
|
|
44
|
+
* Route parameters extracted from the path
|
|
45
|
+
*/
|
|
46
|
+
params: RouteParams;
|
|
47
|
+
/**
|
|
48
|
+
* The route handler (view identifier)
|
|
49
|
+
*/
|
|
50
|
+
handler: RouteHandler;
|
|
51
|
+
/**
|
|
52
|
+
* Route metadata
|
|
53
|
+
*/
|
|
54
|
+
meta?: Record<string, any>;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Navigation events
|
|
58
|
+
*/
|
|
59
|
+
export declare const NavigationEvents: {
|
|
60
|
+
readonly BEFORE_NAVIGATE: "navigation:before";
|
|
61
|
+
readonly NAVIGATE: "navigation:navigate";
|
|
62
|
+
readonly NOT_FOUND: "navigation:notfound";
|
|
63
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/navigation/types.ts"],"names":[],"mappings":"AAiEA;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC5B,eAAe,EAAE,mBAAmB;IACpC,QAAQ,EAAE,qBAAqB;IAC/B,SAAS,EAAE,qBAAqB;CAC1B,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "application.ts",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Simplified Web SPA app framework with vanilla JavaScript and CSS",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/index.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"src/",
|
|
9
|
+
"dist/",
|
|
10
|
+
"README.md",
|
|
11
|
+
"LICENSE"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"dev": "vite",
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"build:examples": "vite build",
|
|
17
|
+
"preview": "vite preview",
|
|
18
|
+
"typecheck": "tsc --noEmit",
|
|
19
|
+
"lint": "eslint src/**/*.ts",
|
|
20
|
+
"lint:fix": "eslint src/**/*.ts --fix",
|
|
21
|
+
"example": "npm run build && vite examples --open",
|
|
22
|
+
"example:build": "npm run build && vite build --config vite.config.ts"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"spa",
|
|
26
|
+
"framework",
|
|
27
|
+
"typescript",
|
|
28
|
+
"vanilla",
|
|
29
|
+
"lightweight",
|
|
30
|
+
"template",
|
|
31
|
+
"routing",
|
|
32
|
+
"stackview"
|
|
33
|
+
],
|
|
34
|
+
"author": "Xoboto Contributors",
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"stackview.ts": "^1.0.1",
|
|
38
|
+
"template.ts": "^2.0.0"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@typescript-eslint/eslint-plugin": "^8.18.0",
|
|
42
|
+
"@typescript-eslint/parser": "^8.18.0",
|
|
43
|
+
"@types/node": "^22.0.0",
|
|
44
|
+
"typescript": "^5.9.3",
|
|
45
|
+
"vite": "^7.2.4",
|
|
46
|
+
"eslint": "^8.57.0"
|
|
47
|
+
},
|
|
48
|
+
"eslintConfig": {
|
|
49
|
+
"extends": [
|
|
50
|
+
"eslint:recommended",
|
|
51
|
+
"plugin:@typescript-eslint/recommended"
|
|
52
|
+
],
|
|
53
|
+
"parser": "@typescript-eslint/parser",
|
|
54
|
+
"plugins": [
|
|
55
|
+
"@typescript-eslint"
|
|
56
|
+
],
|
|
57
|
+
"parserOptions": {
|
|
58
|
+
"ecmaVersion": 2020,
|
|
59
|
+
"sourceType": "module"
|
|
60
|
+
},
|
|
61
|
+
"rules": {
|
|
62
|
+
"@typescript-eslint/no-unused-vars": "warn",
|
|
63
|
+
"@typescript-eslint/no-explicit-any": "off",
|
|
64
|
+
"@typescript-eslint/explicit-function-return-type": "warn",
|
|
65
|
+
"prefer-spread": "off"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|