@alepha/react 0.13.6 → 0.13.7
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/auth/index.browser.js +5 -5
- package/dist/auth/index.browser.js.map +1 -1
- package/dist/auth/index.d.ts +3 -1
- package/dist/auth/index.js +5 -5
- package/dist/auth/index.js.map +1 -1
- package/dist/core/index.browser.js +385 -141
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +105 -89
- package/dist/core/index.js +387 -144
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js.map +1 -1
- package/dist/form/index.d.ts +14 -6
- package/dist/form/index.js +32 -12
- package/dist/form/index.js.map +1 -1
- package/dist/head/index.d.ts +1 -1
- package/dist/head/index.js +5 -1
- package/dist/head/index.js.map +1 -1
- package/dist/i18n/index.d.ts +3 -3
- package/dist/i18n/index.js +4 -3
- package/dist/i18n/index.js.map +1 -1
- package/dist/websocket/index.d.ts +20 -20
- package/package.json +6 -5
- package/src/auth/hooks/useAuth.ts +1 -0
- package/src/auth/services/ReactAuth.ts +6 -4
- package/src/core/components/ErrorViewer.tsx +378 -130
- package/src/core/components/NestedView.tsx +16 -11
- package/src/core/contexts/RouterLayerContext.ts +2 -0
- package/src/core/hooks/useAction.ts +4 -1
- package/src/core/primitives/$page.ts +15 -2
- package/src/core/providers/ReactPageProvider.ts +6 -7
- package/src/core/providers/ReactServerProvider.ts +2 -6
- package/src/form/services/FormModel.ts +81 -26
- package/src/head/index.ts +2 -1
- package/src/i18n/providers/I18nProvider.ts +4 -2
|
@@ -314,7 +314,11 @@ export class ReactPageProvider {
|
|
|
314
314
|
if (!it.error) {
|
|
315
315
|
try {
|
|
316
316
|
const element = await this.createElement(it.route, {
|
|
317
|
+
// default props attached to page
|
|
318
|
+
...(it.route.props ? it.route.props() : {}),
|
|
319
|
+
// resolved props
|
|
317
320
|
...props,
|
|
321
|
+
// context props (from previous layers)
|
|
318
322
|
...context,
|
|
319
323
|
});
|
|
320
324
|
|
|
@@ -380,12 +384,6 @@ export class ReactPageProvider {
|
|
|
380
384
|
return { state };
|
|
381
385
|
}
|
|
382
386
|
|
|
383
|
-
protected createRedirectionLayer(redirect: string): CreateLayersResult {
|
|
384
|
-
return {
|
|
385
|
-
redirect,
|
|
386
|
-
};
|
|
387
|
-
}
|
|
388
|
-
|
|
389
387
|
protected getErrorHandler(route: PageRoute): ErrorHandler | undefined {
|
|
390
388
|
if (route.errorHandler) return route.errorHandler;
|
|
391
389
|
let parent = route.parent;
|
|
@@ -431,7 +429,7 @@ export class ReactPageProvider {
|
|
|
431
429
|
): string {
|
|
432
430
|
const found = this.pages.find((it) => it.name === page.options.name);
|
|
433
431
|
if (!found) {
|
|
434
|
-
throw new
|
|
432
|
+
throw new AlephaError(`Page ${page.options.name} not found`);
|
|
435
433
|
}
|
|
436
434
|
|
|
437
435
|
let url = found.path ?? "";
|
|
@@ -475,6 +473,7 @@ export class ReactPageProvider {
|
|
|
475
473
|
value: {
|
|
476
474
|
index,
|
|
477
475
|
path,
|
|
476
|
+
onError: this.getErrorHandler(page) ?? ((error) => this.renderError(error)),
|
|
478
477
|
},
|
|
479
478
|
},
|
|
480
479
|
element,
|
|
@@ -39,17 +39,13 @@ import {
|
|
|
39
39
|
const envSchema = t.object({
|
|
40
40
|
REACT_SSR_ENABLED: t.optional(t.boolean()),
|
|
41
41
|
REACT_ROOT_ID: t.text({ default: "root" }), // TODO: move to ReactPageProvider.options?
|
|
42
|
-
REACT_SERVER_TEMPLATE: t.optional(
|
|
43
|
-
t.text({
|
|
44
|
-
size: "rich",
|
|
45
|
-
}),
|
|
46
|
-
),
|
|
47
42
|
});
|
|
48
43
|
|
|
49
44
|
declare module "alepha" {
|
|
50
45
|
interface Env extends Partial<Static<typeof envSchema>> {}
|
|
51
46
|
interface State {
|
|
52
47
|
"alepha.react.server.ssr"?: boolean;
|
|
48
|
+
"alepha.react.server.template"?: string;
|
|
53
49
|
}
|
|
54
50
|
}
|
|
55
51
|
|
|
@@ -171,7 +167,7 @@ export class ReactServerProvider {
|
|
|
171
167
|
|
|
172
168
|
public get template() {
|
|
173
169
|
return (
|
|
174
|
-
this.alepha.
|
|
170
|
+
this.alepha.store.get("alepha.react.server.template") ??
|
|
175
171
|
"<!DOCTYPE html><html lang='en'><head></head><body></body></html>"
|
|
176
172
|
);
|
|
177
173
|
}
|
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
Alepha,
|
|
4
|
-
type Static,
|
|
5
|
-
type TObject,
|
|
6
|
-
type TSchema,
|
|
7
|
-
t,
|
|
8
|
-
} from "alepha";
|
|
1
|
+
import type { TArray } from "alepha";
|
|
2
|
+
import { $inject, Alepha, type Static, t, type TObject, type TSchema, } from "alepha";
|
|
9
3
|
import { $logger } from "alepha/logger";
|
|
10
4
|
import type { ChangeEvent, InputHTMLAttributes } from "react";
|
|
11
5
|
|
|
@@ -221,17 +215,21 @@ export class FormModel<T extends TObject> {
|
|
|
221
215
|
if (!options.schema || !t.schema.isObject(schema)) {
|
|
222
216
|
return {};
|
|
223
217
|
}
|
|
218
|
+
|
|
224
219
|
if (prop in schema.properties) {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
}
|
|
220
|
+
|
|
221
|
+
// // it's a nested object, create another proxy
|
|
222
|
+
// if (t.schema.isObject(schema.properties[prop])) {
|
|
223
|
+
// return this.createProxyFromSchema(
|
|
224
|
+
// options,
|
|
225
|
+
// schema.properties[prop],
|
|
226
|
+
// {
|
|
227
|
+
// parent: parent ? `${parent}.${prop}` : prop,
|
|
228
|
+
// store: context.store,
|
|
229
|
+
// },
|
|
230
|
+
// );
|
|
231
|
+
// }
|
|
232
|
+
|
|
235
233
|
return this.createInputFromSchema<T>(
|
|
236
234
|
prop as keyof Static<T> & string,
|
|
237
235
|
options,
|
|
@@ -253,7 +251,7 @@ export class FormModel<T extends TObject> {
|
|
|
253
251
|
parent: string;
|
|
254
252
|
store: Record<string, any>;
|
|
255
253
|
},
|
|
256
|
-
):
|
|
254
|
+
): BaseInputField {
|
|
257
255
|
const parent = context.parent || "";
|
|
258
256
|
const field = schema.properties?.[name];
|
|
259
257
|
if (!field) {
|
|
@@ -268,7 +266,6 @@ export class FormModel<T extends TObject> {
|
|
|
268
266
|
}
|
|
269
267
|
|
|
270
268
|
const isRequired = schema.required?.includes(name) ?? false;
|
|
271
|
-
|
|
272
269
|
const key = parent ? `${parent}.${name}` : name;
|
|
273
270
|
const path = `/${key.replaceAll(".", "/")}`;
|
|
274
271
|
|
|
@@ -278,7 +275,7 @@ export class FormModel<T extends TObject> {
|
|
|
278
275
|
|
|
279
276
|
if (context.store[key] === typedValue) {
|
|
280
277
|
// no change, do not update
|
|
281
|
-
// return;
|
|
278
|
+
// return; <- disabled for now, as some inputs may need to sync even if value is same
|
|
282
279
|
}
|
|
283
280
|
|
|
284
281
|
context.store[key] = typedValue;
|
|
@@ -291,6 +288,8 @@ export class FormModel<T extends TObject> {
|
|
|
291
288
|
id: this.id,
|
|
292
289
|
path: path,
|
|
293
290
|
value: typedValue,
|
|
291
|
+
}, {
|
|
292
|
+
catch: true
|
|
294
293
|
});
|
|
295
294
|
|
|
296
295
|
if (sync) {
|
|
@@ -299,6 +298,7 @@ export class FormModel<T extends TObject> {
|
|
|
299
298
|
);
|
|
300
299
|
if (inputElement instanceof HTMLInputElement) {
|
|
301
300
|
if (t.schema.isBoolean(field)) {
|
|
301
|
+
inputElement.value = value;
|
|
302
302
|
inputElement.checked = Boolean(value);
|
|
303
303
|
} else {
|
|
304
304
|
inputElement.value = value;
|
|
@@ -324,7 +324,15 @@ export class FormModel<T extends TObject> {
|
|
|
324
324
|
}
|
|
325
325
|
|
|
326
326
|
if (t.schema.isBoolean(field)) {
|
|
327
|
-
|
|
327
|
+
if (event.target.value === "true") {
|
|
328
|
+
set(true, false);
|
|
329
|
+
} else if (event.target.value === "false") {
|
|
330
|
+
set(false, false);
|
|
331
|
+
} else if (event.target.value === "") {
|
|
332
|
+
set(undefined, false);
|
|
333
|
+
} else {
|
|
334
|
+
set(event.target.checked, false);
|
|
335
|
+
}
|
|
328
336
|
} else {
|
|
329
337
|
set(event.target.value, false);
|
|
330
338
|
}
|
|
@@ -391,6 +399,39 @@ export class FormModel<T extends TObject> {
|
|
|
391
399
|
Object.assign(attr, customAttr);
|
|
392
400
|
}
|
|
393
401
|
|
|
402
|
+
// if type = object, add items: { [key: string]: InputField }
|
|
403
|
+
if (t.schema.isObject(field)) {
|
|
404
|
+
return {
|
|
405
|
+
path,
|
|
406
|
+
props: attr,
|
|
407
|
+
schema: field,
|
|
408
|
+
set,
|
|
409
|
+
form: this,
|
|
410
|
+
required,
|
|
411
|
+
items: this.createProxyFromSchema(
|
|
412
|
+
options,
|
|
413
|
+
field,
|
|
414
|
+
{
|
|
415
|
+
parent: key,
|
|
416
|
+
store: context.store,
|
|
417
|
+
},
|
|
418
|
+
)
|
|
419
|
+
} as ObjectInputField<any>;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// if type = array, add items: InputField[]
|
|
423
|
+
if (t.schema.isArray(field)) {
|
|
424
|
+
return {
|
|
425
|
+
path,
|
|
426
|
+
props: attr,
|
|
427
|
+
schema: field,
|
|
428
|
+
set,
|
|
429
|
+
form: this,
|
|
430
|
+
required,
|
|
431
|
+
items: [], // <- will be populated dynamically in the UI
|
|
432
|
+
} as ArrayInputField<any>;
|
|
433
|
+
}
|
|
434
|
+
|
|
394
435
|
return {
|
|
395
436
|
path,
|
|
396
437
|
props: attr,
|
|
@@ -466,9 +507,7 @@ export class FormModel<T extends TObject> {
|
|
|
466
507
|
}
|
|
467
508
|
|
|
468
509
|
export type SchemaToInput<T extends TObject> = {
|
|
469
|
-
[K in keyof T["properties"]]: T["properties"][K]
|
|
470
|
-
? SchemaToInput<T["properties"][K]>
|
|
471
|
-
: InputField;
|
|
510
|
+
[K in keyof T["properties"]]: InputField<T["properties"][K]>;
|
|
472
511
|
};
|
|
473
512
|
|
|
474
513
|
export interface FormEventLike {
|
|
@@ -476,13 +515,29 @@ export interface FormEventLike {
|
|
|
476
515
|
stopPropagation?: () => void;
|
|
477
516
|
}
|
|
478
517
|
|
|
479
|
-
export
|
|
518
|
+
export type InputField<T extends TSchema> =
|
|
519
|
+
T extends TObject
|
|
520
|
+
? ObjectInputField<T>
|
|
521
|
+
: T extends TArray<infer U>
|
|
522
|
+
? ArrayInputField<U>
|
|
523
|
+
: BaseInputField;
|
|
524
|
+
|
|
525
|
+
export interface BaseInputField {
|
|
480
526
|
path: string;
|
|
481
527
|
required: boolean;
|
|
482
528
|
props: InputHTMLAttributesLike;
|
|
483
529
|
schema: TSchema;
|
|
484
530
|
set: (value: any) => void;
|
|
485
531
|
form: FormModel<any>;
|
|
532
|
+
items?: any;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
export interface ObjectInputField<T extends TObject> extends BaseInputField {
|
|
536
|
+
items: SchemaToInput<T>;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
export interface ArrayInputField<T extends TSchema> extends BaseInputField {
|
|
540
|
+
items: Array<InputField<T>>
|
|
486
541
|
}
|
|
487
542
|
|
|
488
543
|
export type InputHTMLAttributesLike = Pick<
|
package/src/head/index.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { $module } from "alepha";
|
|
|
8
8
|
import { $head } from "./primitives/$head.ts";
|
|
9
9
|
import type { Head } from "./interfaces/Head.ts";
|
|
10
10
|
import { ServerHeadProvider } from "./providers/ServerHeadProvider.ts";
|
|
11
|
+
import { HeadProvider } from "./providers/HeadProvider.ts";
|
|
11
12
|
|
|
12
13
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
13
14
|
|
|
@@ -43,5 +44,5 @@ declare module "@alepha/react" {
|
|
|
43
44
|
export const AlephaReactHead = $module({
|
|
44
45
|
name: "alepha.react.head",
|
|
45
46
|
primitives: [$head],
|
|
46
|
-
services: [AlephaReact, ServerHeadProvider],
|
|
47
|
+
services: [AlephaReact, ServerHeadProvider, HeadProvider],
|
|
47
48
|
});
|
|
@@ -15,6 +15,7 @@ export class I18nProvider<
|
|
|
15
15
|
protected cookie = $cookie({
|
|
16
16
|
name: "lang",
|
|
17
17
|
schema: t.text(),
|
|
18
|
+
ttl: [1, "year"]
|
|
18
19
|
});
|
|
19
20
|
|
|
20
21
|
public readonly registry: Array<{
|
|
@@ -170,7 +171,7 @@ export class I18nProvider<
|
|
|
170
171
|
options: I18nLocalizeOptions = {},
|
|
171
172
|
) => {
|
|
172
173
|
// Handle numbers
|
|
173
|
-
if (typeof value === "number") {
|
|
174
|
+
if (typeof value === "number" && !options.date) {
|
|
174
175
|
return new Intl.NumberFormat(this.lang, options.number).format(value);
|
|
175
176
|
}
|
|
176
177
|
|
|
@@ -178,7 +179,8 @@ export class I18nProvider<
|
|
|
178
179
|
if (
|
|
179
180
|
value instanceof Date ||
|
|
180
181
|
this.dateTimeProvider.isDateTime(value) ||
|
|
181
|
-
(typeof value === "string" && options.date)
|
|
182
|
+
(typeof value === "string" && options.date) ||
|
|
183
|
+
(typeof value === "number" && options.date)
|
|
182
184
|
) {
|
|
183
185
|
// convert to DateTime with locale applied
|
|
184
186
|
let dt = this.dateTimeProvider.of(value);
|