@inglorious/web 3.0.1 → 4.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/package.json +5 -4
- package/src/mount.js +12 -12
- package/src/router/index.js +59 -26
- package/types/router.d.ts +43 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inglorious/web",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "A new web framework that leverages the power of the Inglorious Store combined with the performance and simplicity of lit-html.",
|
|
5
5
|
"author": "IceOnFire <antony.mistretta@gmail.com> (https://ingloriouscoderz.it)",
|
|
6
6
|
"license": "MIT",
|
|
@@ -53,8 +53,8 @@
|
|
|
53
53
|
},
|
|
54
54
|
"files": [
|
|
55
55
|
"src",
|
|
56
|
-
"
|
|
57
|
-
"
|
|
56
|
+
"types",
|
|
57
|
+
"!src/**/*.test.js"
|
|
58
58
|
],
|
|
59
59
|
"publishConfig": {
|
|
60
60
|
"access": "public"
|
|
@@ -63,8 +63,9 @@
|
|
|
63
63
|
"**/*.css"
|
|
64
64
|
],
|
|
65
65
|
"dependencies": {
|
|
66
|
+
"@lit-labs/ssr-client": "^1.1.8",
|
|
66
67
|
"lit-html": "^3.3.1",
|
|
67
|
-
"@inglorious/store": "
|
|
68
|
+
"@inglorious/store": "9.0.0",
|
|
68
69
|
"@inglorious/utils": "3.7.1"
|
|
69
70
|
},
|
|
70
71
|
"devDependencies": {
|
package/src/mount.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { hydrate } from "@lit-labs/ssr-client"
|
|
1
2
|
import { html, render } from "lit-html"
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -11,20 +12,19 @@ export function mount(store, renderFn, element) {
|
|
|
11
12
|
const api = { ...store._api }
|
|
12
13
|
api.render = createRender(api)
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
let shouldHydrate = element.hasChildNodes()
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
const unsubscribe = store.subscribe(() => {
|
|
18
|
+
const template = renderFn(api)
|
|
19
|
+
|
|
20
|
+
if (shouldHydrate) {
|
|
21
|
+
hydrate(template, element)
|
|
22
|
+
shouldHydrate = false
|
|
23
|
+
} else {
|
|
24
|
+
render(template, element)
|
|
25
|
+
}
|
|
26
|
+
})
|
|
25
27
|
|
|
26
|
-
// const unsubscribe = store.subscribe(scheduleRender)
|
|
27
|
-
const unsubscribe = store.subscribe(() => render(renderFn(api), element))
|
|
28
28
|
store.notify("init")
|
|
29
29
|
|
|
30
30
|
return unsubscribe
|
package/src/router/index.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
const SKIP_FULL_MATCH_GROUP = 1 // .match() result at index 0 is the full string
|
|
8
8
|
const REMOVE_COLON_PREFIX = 1
|
|
9
9
|
|
|
10
|
+
const routeConfig = {}
|
|
10
11
|
let areListenersInitialized = false
|
|
11
12
|
|
|
12
13
|
/**
|
|
@@ -25,7 +26,7 @@ export const router = {
|
|
|
25
26
|
// Handle initial route
|
|
26
27
|
const { pathname, search } = window.location
|
|
27
28
|
const initialPath = pathname + search
|
|
28
|
-
const route = findRoute(
|
|
29
|
+
const route = findRoute(routeConfig, initialPath)
|
|
29
30
|
const entityId = entity.id
|
|
30
31
|
|
|
31
32
|
if (route) {
|
|
@@ -42,8 +43,7 @@ export const router = {
|
|
|
42
43
|
// Listen for browser back/forward
|
|
43
44
|
window.addEventListener("popstate", () => {
|
|
44
45
|
const path = window.location.pathname + window.location.search
|
|
45
|
-
const
|
|
46
|
-
const route = findRoute(routes, path)
|
|
46
|
+
const route = findRoute(routeConfig, path)
|
|
47
47
|
|
|
48
48
|
if (route) {
|
|
49
49
|
api.notify(`#${entityId}:routeSync`, {
|
|
@@ -83,18 +83,6 @@ export const router = {
|
|
|
83
83
|
})
|
|
84
84
|
},
|
|
85
85
|
|
|
86
|
-
create(entity) {
|
|
87
|
-
entity.routes ??= {}
|
|
88
|
-
},
|
|
89
|
-
|
|
90
|
-
routeAdd(entity, route) {
|
|
91
|
-
entity.routes[route.path] = route.entityType
|
|
92
|
-
},
|
|
93
|
-
|
|
94
|
-
routeRemove(entity, path) {
|
|
95
|
-
delete [entity.routes[path]]
|
|
96
|
-
},
|
|
97
|
-
|
|
98
86
|
/**
|
|
99
87
|
* Handles navigation to a new route.
|
|
100
88
|
* @param {RouterEntity} entity - The router entity.
|
|
@@ -122,9 +110,9 @@ export const router = {
|
|
|
122
110
|
}
|
|
123
111
|
|
|
124
112
|
// If "to" is already a final path (like "/users/1"), use it directly
|
|
125
|
-
// The router will match it against patterns in
|
|
113
|
+
// The router will match it against patterns in routeConfig
|
|
126
114
|
|
|
127
|
-
const route = findRoute(
|
|
115
|
+
const route = findRoute(routeConfig, path)
|
|
128
116
|
|
|
129
117
|
if (!route) {
|
|
130
118
|
console.warn(`No route matches path: ${path}`)
|
|
@@ -142,7 +130,7 @@ export const router = {
|
|
|
142
130
|
|
|
143
131
|
// Asynchronous navigation
|
|
144
132
|
if (typeof route.entityType === "function") {
|
|
145
|
-
entity.
|
|
133
|
+
entity.isLoading = true
|
|
146
134
|
entity.error = null
|
|
147
135
|
const entityId = entity.id
|
|
148
136
|
|
|
@@ -186,14 +174,16 @@ export const router = {
|
|
|
186
174
|
loadSuccess(entity, payload, api) {
|
|
187
175
|
const { module, route, path, replace, state } = payload
|
|
188
176
|
|
|
189
|
-
const [
|
|
177
|
+
const [typeName, type] = Object.entries(module).find(
|
|
178
|
+
([, type]) => type?.render,
|
|
179
|
+
)
|
|
190
180
|
|
|
191
|
-
api.
|
|
181
|
+
api.setType(typeName, type)
|
|
192
182
|
|
|
193
|
-
|
|
183
|
+
routeConfig[route.pattern] = typeName
|
|
194
184
|
|
|
195
185
|
// Complete the navigation
|
|
196
|
-
entity.
|
|
186
|
+
entity.isLoading = false
|
|
197
187
|
|
|
198
188
|
doNavigate(
|
|
199
189
|
entity,
|
|
@@ -211,7 +201,7 @@ export const router = {
|
|
|
211
201
|
const { error, path } = payload
|
|
212
202
|
console.error(`Failed to load route ${path}:`, error)
|
|
213
203
|
entity.path = path
|
|
214
|
-
entity.
|
|
204
|
+
entity.isLoading = false
|
|
215
205
|
entity.error = error
|
|
216
206
|
},
|
|
217
207
|
|
|
@@ -225,6 +215,49 @@ export const router = {
|
|
|
225
215
|
},
|
|
226
216
|
}
|
|
227
217
|
|
|
218
|
+
/**
|
|
219
|
+
* Retrieves the current route configuration.
|
|
220
|
+
* @returns {Record<string, string|function>} The current route configuration.
|
|
221
|
+
*/
|
|
222
|
+
export function getRoutes() {
|
|
223
|
+
return routeConfig
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Retrieves a single route configuration given its path.
|
|
228
|
+
* @param {string} path - The path of the route to retrieve.
|
|
229
|
+
* @returns {string|function|undefined} The route configuration or undefined if not found.
|
|
230
|
+
*/
|
|
231
|
+
export function getRoute(path) {
|
|
232
|
+
return routeConfig[path]
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Sets or updates routes in the route configuration.
|
|
237
|
+
* Can be used both during initialization and at any point to add or update routes dynamically.
|
|
238
|
+
* @param {Record<string, string|function>} routes - An object mapping route paths/patterns to entity type names or loader functions.
|
|
239
|
+
*/
|
|
240
|
+
export function setRoutes(routes) {
|
|
241
|
+
Object.assign(routeConfig, routes)
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Adds a single route to the route configuration.
|
|
246
|
+
* @param {string} path - The route path or pattern (e.g., "/users/:userId").
|
|
247
|
+
* @param {string|function} route - The entity type name or a function that dynamically loads it.
|
|
248
|
+
*/
|
|
249
|
+
export function addRoute(path, route) {
|
|
250
|
+
routeConfig[path] = route
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Removes a route from the route configuration.
|
|
255
|
+
* @param {string} path - The route path or pattern to remove.
|
|
256
|
+
*/
|
|
257
|
+
export function removeRoute(path) {
|
|
258
|
+
delete routeConfig[path]
|
|
259
|
+
}
|
|
260
|
+
|
|
228
261
|
/**
|
|
229
262
|
* Builds a URL path by substituting parameters into a route pattern.
|
|
230
263
|
* @param {string} pattern - The route pattern (e.g., "/users/:userId").
|
|
@@ -244,16 +277,16 @@ function buildPath(pattern, params = {}) {
|
|
|
244
277
|
/**
|
|
245
278
|
* Finds a matching route configuration for a given URL path.
|
|
246
279
|
* It supports parameterized routes and a fallback "*" route.
|
|
247
|
-
* @param {Record<string, string>}
|
|
280
|
+
* @param {Record<string, string>} routeConfig - The routes configuration map.
|
|
248
281
|
* @param {string} path - The URL path to match.
|
|
249
282
|
* @returns {{pattern: string, entityType: string, params: Record<string, string>, path: string}|null}
|
|
250
283
|
* The matched route object or null if no match is found.
|
|
251
284
|
*/
|
|
252
|
-
function findRoute(
|
|
285
|
+
function findRoute(routeConfig, path) {
|
|
253
286
|
const [pathname] = path.split("?")
|
|
254
287
|
let fallbackRoute = null
|
|
255
288
|
|
|
256
|
-
for (const [pattern, entityType] of Object.entries(
|
|
289
|
+
for (const [pattern, entityType] of Object.entries(routeConfig)) {
|
|
257
290
|
if (pattern === "*") {
|
|
258
291
|
fallbackRoute = { pattern, entityType, params: {}, path: pathname }
|
|
259
292
|
continue
|
package/types/router.d.ts
CHANGED
|
@@ -26,8 +26,6 @@ export type QueryParams = Record<string, string>
|
|
|
26
26
|
export interface RouterEntity {
|
|
27
27
|
/** A unique identifier for the router entity. */
|
|
28
28
|
id: string | number
|
|
29
|
-
/** The route configuration. */
|
|
30
|
-
routes: RoutesConfig
|
|
31
29
|
/** The current active path, without query string or hash. */
|
|
32
30
|
path?: string
|
|
33
31
|
/** The entity type of the current active route. */
|
|
@@ -38,6 +36,10 @@ export interface RouterEntity {
|
|
|
38
36
|
query?: QueryParams
|
|
39
37
|
/** The hash from the current URL. */
|
|
40
38
|
hash?: string
|
|
39
|
+
/** Whether a route is currently loading asynchronously. */
|
|
40
|
+
isLoading?: boolean
|
|
41
|
+
/** An error that occurred during route loading. */
|
|
42
|
+
error?: Error | null
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
/**
|
|
@@ -98,7 +100,7 @@ export interface RouterType {
|
|
|
98
100
|
entity: RouterEntity,
|
|
99
101
|
payload: string | number | NavigatePayload,
|
|
100
102
|
api: StoreApi,
|
|
101
|
-
): void
|
|
103
|
+
): void | Promise<void>
|
|
102
104
|
|
|
103
105
|
/**
|
|
104
106
|
* Synchronizes the router entity's state with data from a routing event,
|
|
@@ -128,3 +130,41 @@ export interface RouterType {
|
|
|
128
130
|
*/
|
|
129
131
|
loadError(entity: RouterEntity, payload: any): void
|
|
130
132
|
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Returns the current route configuration.
|
|
136
|
+
* @returns {Record<string, string|function>} The current route configuration.
|
|
137
|
+
*/
|
|
138
|
+
export function getRoutes(): Record<string, string | (() => Promise<any>)>
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Retrieves a single route configuration given its path.
|
|
142
|
+
* @param {string} path - The path of the route to retrieve.
|
|
143
|
+
* @returns {string|function|undefined} The route configuration or undefined if not found.
|
|
144
|
+
*/
|
|
145
|
+
export function getRoute(path: string): string | (() => Promise<any>)
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Sets or updates routes in the route configuration.
|
|
149
|
+
* Can be used both during initialization and at any point to add or update routes dynamically.
|
|
150
|
+
* @param routes An object mapping route paths/patterns to entity type names or loader functions.
|
|
151
|
+
*/
|
|
152
|
+
export function setRoutes(
|
|
153
|
+
routes: Record<string, string | (() => Promise<any>)>,
|
|
154
|
+
): void
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Adds a single route to the route configuration.
|
|
158
|
+
* @param path The route path or pattern (e.g., "/users/:userId").
|
|
159
|
+
* @param route The entity type name or a function that dynamically loads it.
|
|
160
|
+
*/
|
|
161
|
+
export function addRoute(
|
|
162
|
+
path: string,
|
|
163
|
+
route: string | (() => Promise<any>),
|
|
164
|
+
): void
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Removes a route from the route configuration.
|
|
168
|
+
* @param path The route path or pattern to remove.
|
|
169
|
+
*/
|
|
170
|
+
export function removeRoute(path: string): void
|