@alepha/react 0.6.2 → 0.6.4
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 +1 -28
- package/dist/index.browser.cjs +20 -23
- package/dist/index.browser.cjs.map +1 -0
- package/dist/index.browser.js +8 -7
- package/dist/index.browser.js.map +1 -0
- package/dist/index.cjs +234 -542
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +218 -682
- package/dist/index.js +219 -522
- package/dist/index.js.map +1 -0
- package/dist/{useAuth-B9ypF48n.cjs → useActive-BGtt_RNQ.cjs} +310 -475
- package/dist/useActive-BGtt_RNQ.cjs.map +1 -0
- package/dist/{useAuth-Ps01oe8e.js → useActive-QkvcaSmu.js} +309 -471
- package/dist/useActive-QkvcaSmu.js.map +1 -0
- package/package.json +12 -10
- package/src/components/Link.tsx +35 -0
- package/src/components/NestedView.tsx +36 -0
- package/src/contexts/RouterContext.ts +18 -0
- package/src/contexts/RouterLayerContext.ts +10 -0
- package/src/descriptors/$page.ts +143 -0
- package/src/errors/RedirectionError.ts +7 -0
- package/src/hooks/RouterHookApi.ts +156 -0
- package/src/hooks/useActive.ts +57 -0
- package/src/hooks/useClient.ts +6 -0
- package/src/hooks/useInject.ts +14 -0
- package/src/hooks/useQueryParams.ts +59 -0
- package/src/hooks/useRouter.ts +25 -0
- package/src/hooks/useRouterEvents.ts +43 -0
- package/src/hooks/useRouterState.ts +23 -0
- package/src/index.browser.ts +21 -0
- package/src/index.shared.ts +15 -0
- package/src/index.ts +48 -0
- package/src/providers/BrowserHeadProvider.ts +43 -0
- package/src/providers/BrowserRouterProvider.ts +146 -0
- package/src/providers/PageDescriptorProvider.ts +534 -0
- package/src/providers/ReactBrowserProvider.ts +223 -0
- package/src/providers/ReactServerProvider.ts +278 -0
- package/src/providers/ServerHeadProvider.ts +91 -0
|
@@ -1,41 +1,47 @@
|
|
|
1
|
-
import { __descriptor, KIND, NotImplementedError, EventEmitter, $logger, $inject, Alepha, $hook, t } from '@alepha/core';
|
|
2
1
|
import { jsx } from 'react/jsx-runtime';
|
|
3
2
|
import React, { createContext, useContext, useState, useEffect, createElement, useMemo } from 'react';
|
|
4
3
|
import { HttpClient } from '@alepha/server';
|
|
4
|
+
import { __descriptor, NotImplementedError, KIND, $logger, $inject, Alepha, EventEmitter, $hook, t } from '@alepha/core';
|
|
5
5
|
import { hydrateRoot, createRoot } from 'react-dom/client';
|
|
6
|
-
import {
|
|
6
|
+
import { RouterProvider } from '@alepha/router';
|
|
7
7
|
|
|
8
|
-
const KEY = "
|
|
9
|
-
const $
|
|
8
|
+
const KEY = "PAGE";
|
|
9
|
+
const $page = (options) => {
|
|
10
10
|
__descriptor(KEY);
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
if (options.children) {
|
|
12
|
+
for (const child of options.children) {
|
|
13
|
+
child.options.parent = {
|
|
14
|
+
options
|
|
15
|
+
};
|
|
16
16
|
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
17
|
+
}
|
|
18
|
+
if (options.parent) {
|
|
19
|
+
options.parent.options.children ??= [];
|
|
20
|
+
options.parent.options.children.push({
|
|
21
|
+
options
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
24
|
return {
|
|
25
|
-
[KIND]:
|
|
25
|
+
[KIND]: KEY,
|
|
26
26
|
options,
|
|
27
27
|
render: () => {
|
|
28
|
-
throw new NotImplementedError(
|
|
28
|
+
throw new NotImplementedError(KEY);
|
|
29
29
|
},
|
|
30
30
|
go: () => {
|
|
31
|
-
throw new NotImplementedError(
|
|
31
|
+
throw new NotImplementedError(KEY);
|
|
32
32
|
},
|
|
33
33
|
createAnchorProps: () => {
|
|
34
|
-
throw new NotImplementedError(
|
|
34
|
+
throw new NotImplementedError(KEY);
|
|
35
|
+
},
|
|
36
|
+
can: () => {
|
|
37
|
+
if (options.can) {
|
|
38
|
+
return options.can();
|
|
39
|
+
}
|
|
40
|
+
return true;
|
|
35
41
|
}
|
|
36
42
|
};
|
|
37
43
|
};
|
|
38
|
-
$page[KIND] =
|
|
44
|
+
$page[KIND] = KEY;
|
|
39
45
|
|
|
40
46
|
const RouterContext = createContext(
|
|
41
47
|
void 0
|
|
@@ -52,7 +58,7 @@ const NestedView = (props) => {
|
|
|
52
58
|
);
|
|
53
59
|
useEffect(() => {
|
|
54
60
|
if (app?.alepha.isBrowser()) {
|
|
55
|
-
return app?.
|
|
61
|
+
return app?.events.on("end", (state) => {
|
|
56
62
|
setView(state.layers[index]?.element);
|
|
57
63
|
});
|
|
58
64
|
}
|
|
@@ -67,159 +73,37 @@ class RedirectionError extends Error {
|
|
|
67
73
|
}
|
|
68
74
|
}
|
|
69
75
|
|
|
70
|
-
class
|
|
76
|
+
class PageDescriptorProvider {
|
|
71
77
|
log = $logger();
|
|
72
78
|
alepha = $inject(Alepha);
|
|
73
79
|
pages = [];
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
*
|
|
78
|
-
* @param name - Page name
|
|
79
|
-
* @return PageRoute
|
|
80
|
-
*/
|
|
80
|
+
getPages() {
|
|
81
|
+
return this.pages;
|
|
82
|
+
}
|
|
81
83
|
page(name) {
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
84
|
+
for (const page of this.pages) {
|
|
85
|
+
if (page.name === name) {
|
|
86
|
+
return page;
|
|
87
|
+
}
|
|
85
88
|
}
|
|
86
|
-
|
|
89
|
+
throw new Error(`Page ${name} not found`);
|
|
87
90
|
}
|
|
88
|
-
|
|
89
|
-
*
|
|
90
|
-
*/
|
|
91
|
-
root(state, context = {}) {
|
|
91
|
+
root(state, context = {}, events) {
|
|
92
92
|
return createElement(
|
|
93
93
|
RouterContext.Provider,
|
|
94
94
|
{
|
|
95
95
|
value: {
|
|
96
|
-
state,
|
|
97
|
-
router: this,
|
|
98
96
|
alepha: this.alepha,
|
|
99
|
-
|
|
97
|
+
state,
|
|
98
|
+
context,
|
|
99
|
+
events: events ?? new EventEmitter()
|
|
100
100
|
}
|
|
101
101
|
},
|
|
102
|
-
state.layers[0]?.element
|
|
102
|
+
createElement(NestedView, {}, state.layers[0]?.element)
|
|
103
103
|
);
|
|
104
104
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
* @param url
|
|
108
|
-
* @param options
|
|
109
|
-
*/
|
|
110
|
-
async render(url, options = {}) {
|
|
111
|
-
const [pathname, search = ""] = url.split("?");
|
|
112
|
-
const state = {
|
|
113
|
-
pathname,
|
|
114
|
-
search,
|
|
115
|
-
layers: [],
|
|
116
|
-
context: {}
|
|
117
|
-
};
|
|
118
|
-
await this.emit("begin", void 0);
|
|
119
|
-
try {
|
|
120
|
-
let layers = await this.match(url, options, state.context);
|
|
121
|
-
if (layers.length === 0) {
|
|
122
|
-
if (this.notFoundPageRoute) {
|
|
123
|
-
layers = await this.createLayers(url, this.notFoundPageRoute);
|
|
124
|
-
} else {
|
|
125
|
-
layers.push({
|
|
126
|
-
name: "not-found",
|
|
127
|
-
element: "Not Found",
|
|
128
|
-
index: 0,
|
|
129
|
-
path: "/"
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
state.layers = layers;
|
|
134
|
-
await this.emit("success", void 0);
|
|
135
|
-
} catch (e) {
|
|
136
|
-
if (e instanceof RedirectionError) {
|
|
137
|
-
return {
|
|
138
|
-
element: null,
|
|
139
|
-
layers: [],
|
|
140
|
-
redirect: typeof e.page === "string" ? e.page : this.href(e.page),
|
|
141
|
-
context: state.context
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
this.log.error(e);
|
|
145
|
-
state.layers = [
|
|
146
|
-
{
|
|
147
|
-
name: "error",
|
|
148
|
-
element: this.renderError(e),
|
|
149
|
-
index: 0,
|
|
150
|
-
path: "/"
|
|
151
|
-
}
|
|
152
|
-
];
|
|
153
|
-
await this.emit("error", e);
|
|
154
|
-
}
|
|
155
|
-
if (options.state) {
|
|
156
|
-
options.state.layers = state.layers;
|
|
157
|
-
options.state.pathname = state.pathname;
|
|
158
|
-
options.state.search = state.search;
|
|
159
|
-
options.state.context = state.context;
|
|
160
|
-
await this.emit("end", options.state);
|
|
161
|
-
return {
|
|
162
|
-
element: this.root(options.state, options.args),
|
|
163
|
-
layers: options.state.layers,
|
|
164
|
-
context: state.context
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
await this.emit("end", state);
|
|
168
|
-
return {
|
|
169
|
-
element: this.root(state, options.args),
|
|
170
|
-
layers: state.layers,
|
|
171
|
-
context: state.context
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
/**
|
|
175
|
-
*
|
|
176
|
-
* @param url
|
|
177
|
-
* @param options
|
|
178
|
-
* @param context
|
|
179
|
-
* @protected
|
|
180
|
-
*/
|
|
181
|
-
async match(url, options = {}, context = {}) {
|
|
182
|
-
const pages = this.pages;
|
|
183
|
-
const previous = options.previous;
|
|
184
|
-
const [pathname, search] = url.split("?");
|
|
185
|
-
for (const route of pages) {
|
|
186
|
-
if (route.children?.find((it) => !it.path || it.path === "/")) continue;
|
|
187
|
-
if (!route.match) continue;
|
|
188
|
-
const match2 = route.match.exec(pathname);
|
|
189
|
-
if (match2) {
|
|
190
|
-
const params = match2.params ?? {};
|
|
191
|
-
const query = {};
|
|
192
|
-
if (search) {
|
|
193
|
-
for (const [key, value] of new URLSearchParams(search).entries()) {
|
|
194
|
-
query[key] = String(value);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
return await this.createLayers(
|
|
198
|
-
url,
|
|
199
|
-
route,
|
|
200
|
-
params,
|
|
201
|
-
query,
|
|
202
|
-
previous,
|
|
203
|
-
options.args,
|
|
204
|
-
context
|
|
205
|
-
);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
return [];
|
|
209
|
-
}
|
|
210
|
-
/**
|
|
211
|
-
* Create layers for the given route.
|
|
212
|
-
*
|
|
213
|
-
* @param url
|
|
214
|
-
* @param route
|
|
215
|
-
* @param params
|
|
216
|
-
* @param query
|
|
217
|
-
* @param previous
|
|
218
|
-
* @param args
|
|
219
|
-
* @param renderContext
|
|
220
|
-
* @protected
|
|
221
|
-
*/
|
|
222
|
-
async createLayers(url, route, params = {}, query = {}, previous = [], args, renderContext) {
|
|
105
|
+
async createLayers(route, request) {
|
|
106
|
+
const { pathname, search } = request.url;
|
|
223
107
|
const layers = [];
|
|
224
108
|
let context = {};
|
|
225
109
|
const stack = [{ route }];
|
|
@@ -234,13 +118,13 @@ class Router extends EventEmitter {
|
|
|
234
118
|
const route2 = it.route;
|
|
235
119
|
const config = {};
|
|
236
120
|
try {
|
|
237
|
-
config.query = route2.schema?.query ? this.alepha.parse(route2.schema.query, query) : query;
|
|
121
|
+
config.query = route2.schema?.query ? this.alepha.parse(route2.schema.query, request.query) : request.query;
|
|
238
122
|
} catch (e) {
|
|
239
123
|
it.error = e;
|
|
240
124
|
break;
|
|
241
125
|
}
|
|
242
126
|
try {
|
|
243
|
-
config.params = route2.schema?.params ? this.alepha.parse(route2.schema.params, params) : params;
|
|
127
|
+
config.params = route2.schema?.params ? this.alepha.parse(route2.schema.params, request.params) : request.params;
|
|
244
128
|
} catch (e) {
|
|
245
129
|
it.error = e;
|
|
246
130
|
break;
|
|
@@ -251,14 +135,15 @@ class Router extends EventEmitter {
|
|
|
251
135
|
if (!route2.resolve) {
|
|
252
136
|
continue;
|
|
253
137
|
}
|
|
138
|
+
const previous = request.previous;
|
|
254
139
|
if (previous?.[i] && !forceRefresh && previous[i].name === route2.name) {
|
|
255
|
-
const
|
|
140
|
+
const url = (str) => str ? str.replace(/\/\/+/g, "/") : "/";
|
|
256
141
|
const prev = JSON.stringify({
|
|
257
|
-
part:
|
|
142
|
+
part: url(previous[i].part),
|
|
258
143
|
params: previous[i].config?.params ?? {}
|
|
259
144
|
});
|
|
260
145
|
const curr = JSON.stringify({
|
|
261
|
-
part:
|
|
146
|
+
part: url(route2.path),
|
|
262
147
|
params: config.params ?? {}
|
|
263
148
|
});
|
|
264
149
|
if (prev === curr) {
|
|
@@ -273,15 +158,14 @@ class Router extends EventEmitter {
|
|
|
273
158
|
forceRefresh = true;
|
|
274
159
|
}
|
|
275
160
|
try {
|
|
276
|
-
const props = await route2.resolve?.(
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
) ?? {};
|
|
161
|
+
const props = await route2.resolve?.({
|
|
162
|
+
...request,
|
|
163
|
+
// request
|
|
164
|
+
...config,
|
|
165
|
+
// params, query
|
|
166
|
+
...context
|
|
167
|
+
// previous props
|
|
168
|
+
}) ?? {};
|
|
285
169
|
it.props = {
|
|
286
170
|
...props
|
|
287
171
|
};
|
|
@@ -291,7 +175,13 @@ class Router extends EventEmitter {
|
|
|
291
175
|
};
|
|
292
176
|
} catch (e) {
|
|
293
177
|
if (e instanceof RedirectionError) {
|
|
294
|
-
|
|
178
|
+
return {
|
|
179
|
+
layers: [],
|
|
180
|
+
redirect: typeof e.page === "string" ? e.page : this.href(e.page),
|
|
181
|
+
head: request.head,
|
|
182
|
+
pathname,
|
|
183
|
+
search
|
|
184
|
+
};
|
|
295
185
|
}
|
|
296
186
|
this.log.error(e);
|
|
297
187
|
it.error = e;
|
|
@@ -302,25 +192,25 @@ class Router extends EventEmitter {
|
|
|
302
192
|
for (let i = 0; i < stack.length; i++) {
|
|
303
193
|
const it = stack[i];
|
|
304
194
|
const props = it.props ?? {};
|
|
305
|
-
const
|
|
306
|
-
for (const key of Object.keys(
|
|
307
|
-
|
|
195
|
+
const params = { ...it.config?.params };
|
|
196
|
+
for (const key of Object.keys(params)) {
|
|
197
|
+
params[key] = String(params[key]);
|
|
308
198
|
}
|
|
309
|
-
if (it.route.head &&
|
|
310
|
-
this.
|
|
199
|
+
if (it.route.head && !it.error) {
|
|
200
|
+
this.fillHead(it.route, request, {
|
|
311
201
|
...props,
|
|
312
202
|
...context
|
|
313
203
|
});
|
|
314
204
|
}
|
|
315
205
|
acc += "/";
|
|
316
|
-
acc += it.route.path ? compile(it.route.path)
|
|
206
|
+
acc += it.route.path ? this.compile(it.route.path, params) : "";
|
|
317
207
|
const path = acc.replace(/\/+/, "/");
|
|
318
208
|
if (it.error) {
|
|
319
209
|
const errorHandler = this.getErrorHandler(it.route);
|
|
320
210
|
const element = await (errorHandler ? errorHandler({
|
|
321
211
|
...it.config,
|
|
322
212
|
error: it.error,
|
|
323
|
-
url
|
|
213
|
+
url: ""
|
|
324
214
|
}) : this.renderError(it.error));
|
|
325
215
|
layers.push({
|
|
326
216
|
props,
|
|
@@ -348,13 +238,8 @@ class Router extends EventEmitter {
|
|
|
348
238
|
path
|
|
349
239
|
});
|
|
350
240
|
}
|
|
351
|
-
return layers;
|
|
241
|
+
return { layers, head: request.head, pathname, search };
|
|
352
242
|
}
|
|
353
|
-
/**
|
|
354
|
-
*
|
|
355
|
-
* @param route
|
|
356
|
-
* @protected
|
|
357
|
-
*/
|
|
358
243
|
getErrorHandler(route) {
|
|
359
244
|
if (route.errorHandler) return route.errorHandler;
|
|
360
245
|
let parent = route.parent;
|
|
@@ -363,12 +248,6 @@ class Router extends EventEmitter {
|
|
|
363
248
|
parent = parent.parent;
|
|
364
249
|
}
|
|
365
250
|
}
|
|
366
|
-
/**
|
|
367
|
-
*
|
|
368
|
-
* @param page
|
|
369
|
-
* @param props
|
|
370
|
-
* @protected
|
|
371
|
-
*/
|
|
372
251
|
async createElement(page, props) {
|
|
373
252
|
if (page.lazy) {
|
|
374
253
|
const component = await page.lazy();
|
|
@@ -379,65 +258,43 @@ class Router extends EventEmitter {
|
|
|
379
258
|
}
|
|
380
259
|
return void 0;
|
|
381
260
|
}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
*/
|
|
390
|
-
mergeRenderContext(page, ctx, props) {
|
|
391
|
-
if (page.head) {
|
|
261
|
+
fillHead(page, ctx, props) {
|
|
262
|
+
if (!page.head) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
ctx.head ??= {};
|
|
266
|
+
const head = typeof page.head === "function" ? page.head(props, ctx.head) : page.head;
|
|
267
|
+
if (head.title) {
|
|
392
268
|
ctx.head ??= {};
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
ctx.head.title = `${head.title}${ctx.head.titleSeparator}${ctx.head.title}`;
|
|
398
|
-
} else {
|
|
399
|
-
ctx.head.title = head.title;
|
|
400
|
-
}
|
|
401
|
-
ctx.head.titleSeparator = head.titleSeparator;
|
|
402
|
-
}
|
|
403
|
-
if (head.htmlAttributes) {
|
|
404
|
-
ctx.head.htmlAttributes = {
|
|
405
|
-
...ctx.head.htmlAttributes,
|
|
406
|
-
...head.htmlAttributes
|
|
407
|
-
};
|
|
408
|
-
}
|
|
409
|
-
if (head.bodyAttributes) {
|
|
410
|
-
ctx.head.bodyAttributes = {
|
|
411
|
-
...ctx.head.bodyAttributes,
|
|
412
|
-
...head.bodyAttributes
|
|
413
|
-
};
|
|
414
|
-
}
|
|
415
|
-
if (head.meta) {
|
|
416
|
-
ctx.head.meta = [...ctx.head.meta ?? [], ...head.meta ?? []];
|
|
269
|
+
if (ctx.head.titleSeparator) {
|
|
270
|
+
ctx.head.title = `${head.title}${ctx.head.titleSeparator}${ctx.head.title}`;
|
|
271
|
+
} else {
|
|
272
|
+
ctx.head.title = head.title;
|
|
417
273
|
}
|
|
274
|
+
ctx.head.titleSeparator = head.titleSeparator;
|
|
275
|
+
}
|
|
276
|
+
if (head.htmlAttributes) {
|
|
277
|
+
ctx.head.htmlAttributes = {
|
|
278
|
+
...ctx.head.htmlAttributes,
|
|
279
|
+
...head.htmlAttributes
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
if (head.bodyAttributes) {
|
|
283
|
+
ctx.head.bodyAttributes = {
|
|
284
|
+
...ctx.head.bodyAttributes,
|
|
285
|
+
...head.bodyAttributes
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
if (head.meta) {
|
|
289
|
+
ctx.head.meta = [...ctx.head.meta ?? [], ...head.meta ?? []];
|
|
418
290
|
}
|
|
419
291
|
}
|
|
420
|
-
/**
|
|
421
|
-
*
|
|
422
|
-
* @param e
|
|
423
|
-
* @protected
|
|
424
|
-
*/
|
|
425
292
|
renderError(e) {
|
|
426
293
|
return createElement("pre", { style: { overflow: "auto" } }, `${e.stack}`);
|
|
427
294
|
}
|
|
428
|
-
/**
|
|
429
|
-
* Render an empty view.
|
|
430
|
-
*
|
|
431
|
-
* @protected
|
|
432
|
-
*/
|
|
433
295
|
renderEmptyView() {
|
|
434
296
|
return createElement(NestedView, {});
|
|
435
297
|
}
|
|
436
|
-
/**
|
|
437
|
-
* Create a valid href for the given page.
|
|
438
|
-
* @param page
|
|
439
|
-
* @param params
|
|
440
|
-
*/
|
|
441
298
|
href(page, params = {}) {
|
|
442
299
|
const found = this.pages.find((it) => it.name === page.options.name);
|
|
443
300
|
if (!found) {
|
|
@@ -449,16 +306,15 @@ class Router extends EventEmitter {
|
|
|
449
306
|
url = `${parent.path ?? ""}/${url}`;
|
|
450
307
|
parent = parent.parent;
|
|
451
308
|
}
|
|
452
|
-
url = compile(url
|
|
309
|
+
url = this.compile(url, params);
|
|
453
310
|
return url.replace(/\/\/+/g, "/") || "/";
|
|
454
311
|
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
*/
|
|
312
|
+
compile(path, params = {}) {
|
|
313
|
+
for (const [key, value] of Object.entries(params)) {
|
|
314
|
+
path = path.replace(`:${key}`, value);
|
|
315
|
+
}
|
|
316
|
+
return path;
|
|
317
|
+
}
|
|
462
318
|
renderView(index, path, view = this.renderEmptyView()) {
|
|
463
319
|
return createElement(
|
|
464
320
|
RouterLayerContext.Provider,
|
|
@@ -471,23 +327,39 @@ class Router extends EventEmitter {
|
|
|
471
327
|
view
|
|
472
328
|
);
|
|
473
329
|
}
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
330
|
+
configure = $hook({
|
|
331
|
+
name: "configure",
|
|
332
|
+
handler: () => {
|
|
333
|
+
const pages = this.alepha.getDescriptorValues($page);
|
|
334
|
+
for (const { value, key } of pages) {
|
|
335
|
+
value.options.name ??= key;
|
|
336
|
+
if (value.options.parent) {
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
this.add(this.map(pages, value));
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
map(pages, target) {
|
|
344
|
+
const children = target.options.children ?? [];
|
|
345
|
+
for (const it of pages) {
|
|
346
|
+
if (it.value.options.parent === target) {
|
|
347
|
+
children.push(it.value);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
return {
|
|
351
|
+
...target.options,
|
|
352
|
+
parent: void 0,
|
|
353
|
+
children: children.map((it) => this.map(pages, it))
|
|
354
|
+
};
|
|
355
|
+
}
|
|
478
356
|
add(entry) {
|
|
479
357
|
if (this.alepha.isReady()) {
|
|
480
358
|
throw new Error("Router is already initialized");
|
|
481
359
|
}
|
|
482
|
-
if (entry.notFoundHandler) {
|
|
483
|
-
this.notFoundPageRoute = {
|
|
484
|
-
name: "not-found",
|
|
485
|
-
component: entry.notFoundHandler
|
|
486
|
-
};
|
|
487
|
-
}
|
|
488
360
|
entry.name ??= this.nextId();
|
|
489
361
|
const page = entry;
|
|
490
|
-
page.match = this.
|
|
362
|
+
page.match = this.createMatch(page);
|
|
491
363
|
this.pages.push(page);
|
|
492
364
|
if (page.children) {
|
|
493
365
|
for (const child of page.children) {
|
|
@@ -496,13 +368,7 @@ class Router extends EventEmitter {
|
|
|
496
368
|
}
|
|
497
369
|
}
|
|
498
370
|
}
|
|
499
|
-
|
|
500
|
-
* Create a match function for the given page.
|
|
501
|
-
*
|
|
502
|
-
* @param page
|
|
503
|
-
* @protected
|
|
504
|
-
*/
|
|
505
|
-
createMatchFunction(page) {
|
|
371
|
+
createMatch(page) {
|
|
506
372
|
let url = page.path ?? "/";
|
|
507
373
|
let target = page.parent;
|
|
508
374
|
while (target) {
|
|
@@ -510,76 +376,166 @@ class Router extends EventEmitter {
|
|
|
510
376
|
target = target.parent;
|
|
511
377
|
}
|
|
512
378
|
let path = url.replace(/\/\/+/g, "/");
|
|
513
|
-
if (path.endsWith("/")) {
|
|
379
|
+
if (path.endsWith("/") && path !== "/") {
|
|
514
380
|
path = path.slice(0, -1);
|
|
515
381
|
}
|
|
516
|
-
|
|
517
|
-
return {
|
|
518
|
-
exec: match(path.split("?")[0]),
|
|
519
|
-
path
|
|
520
|
-
};
|
|
521
|
-
}
|
|
522
|
-
return {
|
|
523
|
-
exec: match(path),
|
|
524
|
-
path
|
|
525
|
-
};
|
|
526
|
-
}
|
|
527
|
-
/**
|
|
528
|
-
*
|
|
529
|
-
*/
|
|
530
|
-
empty() {
|
|
531
|
-
return this.pages.length === 0;
|
|
382
|
+
return path;
|
|
532
383
|
}
|
|
533
|
-
/**
|
|
534
|
-
*
|
|
535
|
-
* @protected
|
|
536
|
-
*/
|
|
537
384
|
_next = 0;
|
|
538
|
-
/**
|
|
539
|
-
*
|
|
540
|
-
* @protected
|
|
541
|
-
*/
|
|
542
385
|
nextId() {
|
|
543
386
|
this._next += 1;
|
|
544
387
|
return `P${this._next}`;
|
|
545
388
|
}
|
|
546
389
|
}
|
|
390
|
+
const isPageRoute = (it) => {
|
|
391
|
+
return it && typeof it === "object" && typeof it.path === "string" && typeof it.page === "object";
|
|
392
|
+
};
|
|
547
393
|
|
|
548
|
-
class
|
|
394
|
+
class BrowserHeadProvider {
|
|
395
|
+
renderHead(document, head) {
|
|
396
|
+
if (head.title) {
|
|
397
|
+
document.title = head.title;
|
|
398
|
+
}
|
|
399
|
+
if (head.bodyAttributes) {
|
|
400
|
+
for (const [key, value] of Object.entries(head.bodyAttributes)) {
|
|
401
|
+
if (value) {
|
|
402
|
+
document.body.setAttribute(key, value);
|
|
403
|
+
} else {
|
|
404
|
+
document.body.removeAttribute(key);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
if (head.htmlAttributes) {
|
|
409
|
+
for (const [key, value] of Object.entries(head.htmlAttributes)) {
|
|
410
|
+
if (value) {
|
|
411
|
+
document.documentElement.setAttribute(key, value);
|
|
412
|
+
} else {
|
|
413
|
+
document.documentElement.removeAttribute(key);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
if (head.meta) {
|
|
418
|
+
for (const [key, value] of Object.entries(head.meta)) {
|
|
419
|
+
const meta = document.querySelector(`meta[name="${key}"]`);
|
|
420
|
+
if (meta) {
|
|
421
|
+
meta.setAttribute("content", value.content);
|
|
422
|
+
} else {
|
|
423
|
+
const newMeta = document.createElement("meta");
|
|
424
|
+
newMeta.setAttribute("name", key);
|
|
425
|
+
newMeta.setAttribute("content", value.content);
|
|
426
|
+
document.head.appendChild(newMeta);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
class BrowserRouterProvider extends RouterProvider {
|
|
434
|
+
log = $logger();
|
|
549
435
|
alepha = $inject(Alepha);
|
|
550
|
-
|
|
436
|
+
pageDescriptorProvider = $inject(PageDescriptorProvider);
|
|
437
|
+
events = new EventEmitter();
|
|
438
|
+
add(entry) {
|
|
439
|
+
this.pageDescriptorProvider.add(entry);
|
|
440
|
+
}
|
|
551
441
|
configure = $hook({
|
|
552
442
|
name: "configure",
|
|
553
|
-
handler: () => {
|
|
554
|
-
const
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
443
|
+
handler: async () => {
|
|
444
|
+
for (const page of this.pageDescriptorProvider.getPages()) {
|
|
445
|
+
if (page.component || page.lazy) {
|
|
446
|
+
this.push({
|
|
447
|
+
path: page.match,
|
|
448
|
+
page
|
|
449
|
+
});
|
|
559
450
|
}
|
|
560
|
-
this.router.add(this.map(pages, value));
|
|
561
451
|
}
|
|
562
452
|
}
|
|
563
453
|
});
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
454
|
+
async transition(url, options = {}) {
|
|
455
|
+
const { pathname, search } = url;
|
|
456
|
+
const state = {
|
|
457
|
+
pathname,
|
|
458
|
+
search,
|
|
459
|
+
layers: [],
|
|
460
|
+
head: {}
|
|
461
|
+
};
|
|
462
|
+
await this.events.emit("begin", void 0);
|
|
463
|
+
try {
|
|
464
|
+
const previous = options.previous;
|
|
465
|
+
const { route, params } = this.match(pathname);
|
|
466
|
+
const query = {};
|
|
467
|
+
if (search) {
|
|
468
|
+
for (const [key, value] of new URLSearchParams(search).entries()) {
|
|
469
|
+
query[key] = String(value);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
if (isPageRoute(route)) {
|
|
473
|
+
const result = await this.pageDescriptorProvider.createLayers(
|
|
474
|
+
route.page,
|
|
475
|
+
{
|
|
476
|
+
url,
|
|
477
|
+
params: params ?? {},
|
|
478
|
+
query,
|
|
479
|
+
previous,
|
|
480
|
+
...state,
|
|
481
|
+
head: state.head,
|
|
482
|
+
...options.context ?? {}
|
|
483
|
+
}
|
|
484
|
+
);
|
|
485
|
+
if (result.redirect) {
|
|
486
|
+
return {
|
|
487
|
+
element: null,
|
|
488
|
+
layers: [],
|
|
489
|
+
redirect: result.redirect,
|
|
490
|
+
head: state.head
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
state.layers = result.layers;
|
|
494
|
+
state.head = result.head;
|
|
495
|
+
}
|
|
496
|
+
if (state.layers.length === 0) {
|
|
497
|
+
state.layers.push({
|
|
498
|
+
name: "not-found",
|
|
499
|
+
element: "Not Found",
|
|
500
|
+
index: 0,
|
|
501
|
+
path: "/"
|
|
502
|
+
});
|
|
575
503
|
}
|
|
504
|
+
await this.events.emit("success", void 0);
|
|
505
|
+
} catch (e) {
|
|
506
|
+
this.log.error(e);
|
|
507
|
+
state.layers = [
|
|
508
|
+
{
|
|
509
|
+
name: "error",
|
|
510
|
+
element: this.pageDescriptorProvider.renderError(e),
|
|
511
|
+
index: 0,
|
|
512
|
+
path: "/"
|
|
513
|
+
}
|
|
514
|
+
];
|
|
515
|
+
await this.events.emit("error", e);
|
|
516
|
+
}
|
|
517
|
+
if (!options.state) {
|
|
518
|
+
await this.events.emit("end", state);
|
|
519
|
+
return {
|
|
520
|
+
element: this.root(state, options.context),
|
|
521
|
+
layers: state.layers,
|
|
522
|
+
head: state.head
|
|
523
|
+
};
|
|
576
524
|
}
|
|
525
|
+
options.state.layers = state.layers;
|
|
526
|
+
options.state.pathname = state.pathname;
|
|
527
|
+
options.state.search = state.search;
|
|
528
|
+
options.state.head = state.head;
|
|
529
|
+
await this.events.emit("end", options.state);
|
|
577
530
|
return {
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
531
|
+
element: this.root(state, options.context),
|
|
532
|
+
layers: options.state.layers,
|
|
533
|
+
head: state.head
|
|
581
534
|
};
|
|
582
535
|
}
|
|
536
|
+
root(state, context = {}) {
|
|
537
|
+
return this.pageDescriptorProvider.root(state, context, this.events);
|
|
538
|
+
}
|
|
583
539
|
}
|
|
584
540
|
|
|
585
541
|
const envSchema = t.object({
|
|
@@ -588,7 +544,9 @@ const envSchema = t.object({
|
|
|
588
544
|
class ReactBrowserProvider {
|
|
589
545
|
log = $logger();
|
|
590
546
|
client = $inject(HttpClient);
|
|
591
|
-
|
|
547
|
+
alepha = $inject(Alepha);
|
|
548
|
+
router = $inject(BrowserRouterProvider);
|
|
549
|
+
headProvider = $inject(BrowserHeadProvider);
|
|
592
550
|
env = $inject(envSchema);
|
|
593
551
|
root;
|
|
594
552
|
transitioning;
|
|
@@ -596,30 +554,17 @@ class ReactBrowserProvider {
|
|
|
596
554
|
layers: [],
|
|
597
555
|
pathname: "",
|
|
598
556
|
search: "",
|
|
599
|
-
|
|
557
|
+
head: {}
|
|
600
558
|
};
|
|
601
|
-
/**
|
|
602
|
-
*
|
|
603
|
-
*/
|
|
604
559
|
get document() {
|
|
605
560
|
return window.document;
|
|
606
561
|
}
|
|
607
|
-
/**
|
|
608
|
-
*
|
|
609
|
-
*/
|
|
610
562
|
get history() {
|
|
611
563
|
return window.history;
|
|
612
564
|
}
|
|
613
|
-
/**
|
|
614
|
-
*
|
|
615
|
-
*/
|
|
616
565
|
get url() {
|
|
617
566
|
return window.location.pathname + window.location.search;
|
|
618
567
|
}
|
|
619
|
-
/**
|
|
620
|
-
*
|
|
621
|
-
* @param props
|
|
622
|
-
*/
|
|
623
568
|
async invalidate(props) {
|
|
624
569
|
const previous = [];
|
|
625
570
|
if (props) {
|
|
@@ -660,66 +605,22 @@ class ReactBrowserProvider {
|
|
|
660
605
|
}
|
|
661
606
|
this.history.pushState({}, "", url);
|
|
662
607
|
}
|
|
663
|
-
/**
|
|
664
|
-
*
|
|
665
|
-
* @param options
|
|
666
|
-
* @protected
|
|
667
|
-
*/
|
|
668
608
|
async render(options = {}) {
|
|
669
609
|
const previous = options.previous ?? this.state.layers;
|
|
670
610
|
const url = options.url ?? this.url;
|
|
671
611
|
this.transitioning = { to: url };
|
|
672
|
-
const result = await this.router.
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
612
|
+
const result = await this.router.transition(
|
|
613
|
+
new URL(`http://localhost${url}`),
|
|
614
|
+
{
|
|
615
|
+
previous,
|
|
616
|
+
state: this.state
|
|
617
|
+
}
|
|
618
|
+
);
|
|
676
619
|
if (result.redirect) {
|
|
677
620
|
return await this.render({ url: result.redirect });
|
|
678
621
|
}
|
|
679
622
|
this.transitioning = void 0;
|
|
680
|
-
return { url,
|
|
681
|
-
}
|
|
682
|
-
/**
|
|
683
|
-
* Render the helmet context.
|
|
684
|
-
*
|
|
685
|
-
* @param ctx
|
|
686
|
-
* @protected
|
|
687
|
-
*/
|
|
688
|
-
renderHeadContext(ctx) {
|
|
689
|
-
if (ctx.title) {
|
|
690
|
-
this.document.title = ctx.title;
|
|
691
|
-
}
|
|
692
|
-
if (ctx.bodyAttributes) {
|
|
693
|
-
for (const [key, value] of Object.entries(ctx.bodyAttributes)) {
|
|
694
|
-
if (value) {
|
|
695
|
-
this.document.body.setAttribute(key, value);
|
|
696
|
-
} else {
|
|
697
|
-
this.document.body.removeAttribute(key);
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
if (ctx.htmlAttributes) {
|
|
702
|
-
for (const [key, value] of Object.entries(ctx.htmlAttributes)) {
|
|
703
|
-
if (value) {
|
|
704
|
-
this.document.documentElement.setAttribute(key, value);
|
|
705
|
-
} else {
|
|
706
|
-
this.document.documentElement.removeAttribute(key);
|
|
707
|
-
}
|
|
708
|
-
}
|
|
709
|
-
}
|
|
710
|
-
if (ctx.meta) {
|
|
711
|
-
for (const [key, value] of Object.entries(ctx.meta)) {
|
|
712
|
-
const meta = this.document.querySelector(`meta[name="${key}"]`);
|
|
713
|
-
if (meta) {
|
|
714
|
-
meta.setAttribute("content", value.content);
|
|
715
|
-
} else {
|
|
716
|
-
const newMeta = this.document.createElement("meta");
|
|
717
|
-
newMeta.setAttribute("name", key);
|
|
718
|
-
newMeta.setAttribute("content", value.content);
|
|
719
|
-
this.document.head.appendChild(newMeta);
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
}
|
|
623
|
+
return { url, head: result.head };
|
|
723
624
|
}
|
|
724
625
|
/**
|
|
725
626
|
* Get embedded layers from the server.
|
|
@@ -749,18 +650,6 @@ class ReactBrowserProvider {
|
|
|
749
650
|
this.document.body.prepend(div);
|
|
750
651
|
return div;
|
|
751
652
|
}
|
|
752
|
-
getUserFromCookies() {
|
|
753
|
-
const cookies = this.document.cookie.split("; ");
|
|
754
|
-
const userCookie = cookies.find((cookie) => cookie.startsWith("user="));
|
|
755
|
-
try {
|
|
756
|
-
if (userCookie) {
|
|
757
|
-
return JSON.parse(decodeURIComponent(userCookie.split("=")[1]));
|
|
758
|
-
}
|
|
759
|
-
} catch (error) {
|
|
760
|
-
this.log.warn(error, "Failed to parse user cookie");
|
|
761
|
-
}
|
|
762
|
-
return void 0;
|
|
763
|
-
}
|
|
764
653
|
// -------------------------------------------------------------------------------------------------------------------
|
|
765
654
|
/**
|
|
766
655
|
*
|
|
@@ -769,18 +658,21 @@ class ReactBrowserProvider {
|
|
|
769
658
|
ready = $hook({
|
|
770
659
|
name: "ready",
|
|
771
660
|
handler: async () => {
|
|
772
|
-
const
|
|
773
|
-
const previous =
|
|
774
|
-
if (
|
|
775
|
-
this.client.links =
|
|
776
|
-
}
|
|
777
|
-
const {
|
|
778
|
-
if (
|
|
779
|
-
this.
|
|
780
|
-
}
|
|
781
|
-
const
|
|
782
|
-
|
|
661
|
+
const hydration = this.getHydrationState();
|
|
662
|
+
const previous = hydration?.layers ?? [];
|
|
663
|
+
if (hydration?.links) {
|
|
664
|
+
this.client.links = hydration.links;
|
|
665
|
+
}
|
|
666
|
+
const { head } = await this.render({ previous });
|
|
667
|
+
if (head) {
|
|
668
|
+
this.headProvider.renderHead(this.document, head);
|
|
669
|
+
}
|
|
670
|
+
const context = {};
|
|
671
|
+
await this.alepha.emit("react:browser:render", {
|
|
672
|
+
context,
|
|
673
|
+
hydration
|
|
783
674
|
});
|
|
675
|
+
const element = this.router.root(this.state, context);
|
|
784
676
|
if (previous.length > 0) {
|
|
785
677
|
this.root = hydrateRoot(this.getRootElement(), element);
|
|
786
678
|
this.log.info("Hydrated root element");
|
|
@@ -792,50 +684,13 @@ class ReactBrowserProvider {
|
|
|
792
684
|
window.addEventListener("popstate", () => {
|
|
793
685
|
this.render();
|
|
794
686
|
});
|
|
795
|
-
this.router.on("end", ({
|
|
796
|
-
|
|
797
|
-
this.renderHeadContext(context2.head);
|
|
798
|
-
}
|
|
687
|
+
this.router.events.on("end", ({ head: head2 }) => {
|
|
688
|
+
this.headProvider.renderHead(this.document, head2);
|
|
799
689
|
});
|
|
800
690
|
}
|
|
801
691
|
});
|
|
802
692
|
}
|
|
803
693
|
|
|
804
|
-
class Auth {
|
|
805
|
-
alepha = $inject(Alepha);
|
|
806
|
-
log = $logger();
|
|
807
|
-
client = $inject(HttpClient);
|
|
808
|
-
slugs = {
|
|
809
|
-
login: "/api/_oauth/login",
|
|
810
|
-
logout: "/api/_oauth/logout"
|
|
811
|
-
};
|
|
812
|
-
start = $hook({
|
|
813
|
-
name: "start",
|
|
814
|
-
handler: async () => {
|
|
815
|
-
this.client.on("onError", (err) => {
|
|
816
|
-
if (err.statusCode === 401) {
|
|
817
|
-
this.login();
|
|
818
|
-
}
|
|
819
|
-
});
|
|
820
|
-
}
|
|
821
|
-
});
|
|
822
|
-
login = (provider) => {
|
|
823
|
-
if (this.alepha.isBrowser()) {
|
|
824
|
-
const browser = this.alepha.get(ReactBrowserProvider);
|
|
825
|
-
const redirect = browser.transitioning ? window.location.origin + browser.transitioning.to : window.location.href;
|
|
826
|
-
window.location.href = `${this.slugs.login}?redirect=${redirect}`;
|
|
827
|
-
if (browser.transitioning) {
|
|
828
|
-
throw new RedirectionError(browser.state.pathname);
|
|
829
|
-
}
|
|
830
|
-
return;
|
|
831
|
-
}
|
|
832
|
-
throw new RedirectionError(this.slugs.login);
|
|
833
|
-
};
|
|
834
|
-
logout = () => {
|
|
835
|
-
window.location.href = `${this.slugs.logout}?redirect=${encodeURIComponent(window.location.origin)}`;
|
|
836
|
-
};
|
|
837
|
-
}
|
|
838
|
-
|
|
839
694
|
class RouterHookApi {
|
|
840
695
|
constructor(state, layer, browser) {
|
|
841
696
|
this.state = state;
|
|
@@ -956,7 +811,7 @@ const useRouter = () => {
|
|
|
956
811
|
layer,
|
|
957
812
|
ctx.alepha.isBrowser() ? ctx.alepha.get(ReactBrowserProvider) : void 0
|
|
958
813
|
),
|
|
959
|
-
[
|
|
814
|
+
[layer]
|
|
960
815
|
);
|
|
961
816
|
};
|
|
962
817
|
|
|
@@ -968,7 +823,6 @@ const Link = (props) => {
|
|
|
968
823
|
}
|
|
969
824
|
const can = typeof props.to === "string" ? void 0 : props.to.options.can;
|
|
970
825
|
if (can && !can()) {
|
|
971
|
-
console.log("I cannot go to", to);
|
|
972
826
|
return null;
|
|
973
827
|
}
|
|
974
828
|
const name = typeof props.to === "string" ? void 0 : props.to.options.name;
|
|
@@ -1040,13 +894,13 @@ const useRouterEvents = (opts = {}) => {
|
|
|
1040
894
|
const onEnd = opts.onEnd;
|
|
1041
895
|
const onError = opts.onError;
|
|
1042
896
|
if (onBegin) {
|
|
1043
|
-
subs.push(ctx.
|
|
897
|
+
subs.push(ctx.events.on("begin", onBegin));
|
|
1044
898
|
}
|
|
1045
899
|
if (onEnd) {
|
|
1046
|
-
subs.push(ctx.
|
|
900
|
+
subs.push(ctx.events.on("end", onEnd));
|
|
1047
901
|
}
|
|
1048
902
|
if (onError) {
|
|
1049
|
-
subs.push(ctx.
|
|
903
|
+
subs.push(ctx.events.on("error", onError));
|
|
1050
904
|
}
|
|
1051
905
|
return () => {
|
|
1052
906
|
for (const sub of subs) {
|
|
@@ -1064,7 +918,7 @@ const useRouterState = () => {
|
|
|
1064
918
|
}
|
|
1065
919
|
const [state, setState] = useState(ctx.state);
|
|
1066
920
|
useEffect(
|
|
1067
|
-
() => ctx.
|
|
921
|
+
() => ctx.events.on("end", (it) => {
|
|
1068
922
|
setState({ ...it });
|
|
1069
923
|
}),
|
|
1070
924
|
[]
|
|
@@ -1088,7 +942,7 @@ const useActive = (path) => {
|
|
|
1088
942
|
const [isPending, setPending] = useState(false);
|
|
1089
943
|
const isActive = current === href;
|
|
1090
944
|
useEffect(
|
|
1091
|
-
() => ctx.
|
|
945
|
+
() => ctx.events.on("end", ({ pathname }) => setCurrent(pathname)),
|
|
1092
946
|
[]
|
|
1093
947
|
);
|
|
1094
948
|
return {
|
|
@@ -1111,21 +965,5 @@ const useActive = (path) => {
|
|
|
1111
965
|
};
|
|
1112
966
|
};
|
|
1113
967
|
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
if (!ctx) {
|
|
1117
|
-
throw new Error("useAuth must be used within a RouterContext");
|
|
1118
|
-
}
|
|
1119
|
-
const args = ctx.args ?? {};
|
|
1120
|
-
return {
|
|
1121
|
-
user: args.user,
|
|
1122
|
-
logout: () => {
|
|
1123
|
-
ctx.alepha.get(Auth).logout();
|
|
1124
|
-
},
|
|
1125
|
-
login: (provider) => {
|
|
1126
|
-
ctx.alepha.get(Auth).login();
|
|
1127
|
-
}
|
|
1128
|
-
};
|
|
1129
|
-
};
|
|
1130
|
-
|
|
1131
|
-
export { $auth as $, Auth as A, Link as L, NestedView as N, PageDescriptorProvider as P, Router as R, $page as a, RouterContext as b, RouterLayerContext as c, RouterHookApi as d, useClient as e, useQueryParams as f, useRouter as g, useRouterEvents as h, useRouterState as i, useActive as j, useAuth as k, ReactBrowserProvider as l, RedirectionError as m, pageDescriptorKey as p, useInject as u };
|
|
968
|
+
export { $page as $, BrowserRouterProvider as B, Link as L, NestedView as N, PageDescriptorProvider as P, RouterContext as R, RouterLayerContext as a, RouterHookApi as b, useClient as c, useQueryParams as d, useRouter as e, useRouterEvents as f, useRouterState as g, useActive as h, RedirectionError as i, isPageRoute as j, ReactBrowserProvider as k, useInject as u };
|
|
969
|
+
//# sourceMappingURL=useActive-QkvcaSmu.js.map
|