amateras 0.13.2 → 0.14.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/README.md +39 -38
- package/build/core.js +1 -1
- package/build/css-keyframes.js +1 -0
- package/build/css-property.js +1 -0
- package/build/css-variable.js +1 -0
- package/build/for.js +1 -1
- package/build/i18n.js +1 -1
- package/build/if.js +1 -1
- package/build/import-map.js +1 -1
- package/build/match.js +1 -1
- package/build/meta.js +1 -1
- package/build/prefetch.js +1 -1
- package/build/router.js +1 -1
- package/build/signal.js +1 -1
- package/build/store.js +1 -1
- package/build/ui.js +1 -1
- package/build/utils.js +1 -1
- package/build/widget.js +1 -1
- package/package.json +3 -2
- package/packages/core/src/index.ts +86 -31
- package/packages/core/src/lib/hmr.ts +4 -4
- package/packages/core/src/structure/ElementProto.ts +33 -11
- package/packages/core/src/structure/GlobalState.ts +13 -4
- package/packages/core/src/structure/NodeProto.ts +2 -4
- package/packages/core/src/structure/Proto.ts +37 -23
- package/packages/core/src/structure/TextProto.ts +1 -2
- package/packages/css/README.md +18 -15
- package/packages/css/src/ext/property.ts +2 -3
- package/packages/css/src/index.ts +1 -1
- package/packages/css/src/structure/$CSSProperty.ts +4 -0
- package/packages/css/src/structure/$CSSVariable.ts +1 -1
- package/packages/css/src/types.ts +5 -0
- package/packages/for/src/global.ts +12 -3
- package/packages/for/src/structure/For.ts +5 -3
- package/packages/i18n/README.md +16 -24
- package/packages/i18n/src/index.ts +26 -5
- package/packages/i18n/src/structure/I18n.ts +2 -4
- package/packages/i18n/src/structure/I18nSession.ts +4 -2
- package/packages/i18n/src/structure/I18nTranslation.ts +15 -26
- package/packages/idb/src/structure/$IDBStore.ts +2 -2
- package/packages/if/src/global.ts +15 -4
- package/packages/if/src/index.ts +18 -8
- package/packages/if/src/structure/Condition.ts +16 -13
- package/packages/if/src/structure/ConditionStatement.ts +9 -9
- package/packages/match/src/global.ts +9 -3
- package/packages/match/src/structure/Match.ts +1 -1
- package/packages/meta/src/index.ts +4 -5
- package/packages/prefetch/src/index.ts +30 -9
- package/packages/router/src/global.ts +17 -4
- package/packages/router/src/index.ts +25 -18
- package/packages/router/src/structure/Route.ts +2 -1
- package/packages/router/src/structure/RouteNode.ts +8 -6
- package/packages/router/src/structure/RouteSlot.ts +15 -2
- package/packages/router/src/structure/Router.ts +28 -19
- package/packages/router/src/structure/RouterConstructor.ts +5 -5
- package/packages/router/src/types.ts +2 -2
- package/packages/signal/README.md +28 -48
- package/packages/signal/src/index.ts +61 -38
- package/packages/signal/src/structure/Signal.ts +40 -7
- package/packages/store/src/structure/Store.ts +1 -1
- package/packages/ui/package.json +2 -1
- package/packages/ui/src/icon/check.svg.ts +1 -0
- package/packages/ui/src/icon/x.svg.ts +1 -0
- package/packages/ui/src/index.ts +9 -2
- package/packages/ui/src/lib/combobox_style.ts +20 -0
- package/packages/ui/src/lib/hover.ts +2 -0
- package/packages/ui/src/structure/Badge.ts +10 -1
- package/packages/ui/src/structure/Button.ts +54 -27
- package/packages/ui/src/structure/Card.ts +3 -4
- package/packages/ui/src/structure/Combobox/Combobox.ts +312 -0
- package/packages/ui/src/structure/Combobox/ComboboxChips.ts +178 -0
- package/packages/ui/src/structure/Combobox/ComboboxList.ts +209 -0
- package/packages/ui/src/structure/ContextMenu.ts +89 -0
- package/packages/ui/src/structure/Field.ts +109 -0
- package/packages/ui/src/structure/Input.ts +29 -0
- package/packages/ui/src/structure/Select/Select.ts +18 -8
- package/packages/ui/src/structure/Select/SelectContent.ts +6 -1
- package/packages/ui/src/structure/Select/SelectItem.ts +2 -1
- package/packages/ui/src/structure/Slideshow.ts +2 -2
- package/packages/ui/src/structure/Switch.ts +45 -0
- package/packages/ui/src/structure/Tabs.ts +3 -3
- package/packages/ui/src/structure/Toggle.ts +155 -0
- package/packages/ui/src/structure/Waterfall.ts +1 -1
- package/packages/ui/src/structure/WaterfallItem.ts +1 -1
- package/packages/utils/src/lib/utils.ts +30 -8
- package/packages/utils/src/structure/UID.ts +1 -1
- package/packages/widget/src/index.ts +29 -9
- package/packages/widget/src/structure/Widget.ts +7 -3
- package/packages/ui/src/structure/TextBlock.ts +0 -11
|
@@ -1,7 +1,16 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as _For from "#structure/For";
|
|
2
2
|
|
|
3
3
|
declare global {
|
|
4
|
-
export var For: typeof
|
|
4
|
+
export var For: typeof _For.For
|
|
5
|
+
// export function $<T>(For: typeof proto.For, signal: proto.ForList<T>, layout: proto.ForLayout<T>): proto.For<T>
|
|
5
6
|
|
|
6
|
-
export
|
|
7
|
+
export namespace $ {
|
|
8
|
+
export interface Overload<I> {
|
|
9
|
+
for: [
|
|
10
|
+
input: [typeof _For.For, _For.ForList<any>],
|
|
11
|
+
output: _For.For,
|
|
12
|
+
args: [layout: I[1] extends _For.ForList<infer T> ? _For.ForLayout<T> : never]
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
}
|
|
7
16
|
}
|
|
@@ -27,12 +27,14 @@ export class For<T = any> extends ProxyProto {
|
|
|
27
27
|
let nodes = this.toDOM();
|
|
28
28
|
let arr = _Array_from(parentNode.childNodes);
|
|
29
29
|
let currentPosition = arr.indexOf(thisNode);
|
|
30
|
+
let nextNode: Node | null = _null;
|
|
30
31
|
forEach(nodes, node => {
|
|
31
32
|
if (node !== thisNode) {
|
|
32
33
|
let currentNode = parentNode.childNodes[currentPosition];
|
|
33
34
|
if (currentNode !== node) {
|
|
34
|
-
|
|
35
|
-
parentNode.
|
|
35
|
+
if (!nodes.includes(currentNode as any)) nextNode = currentNode ?? _null;
|
|
36
|
+
else nextNode = parentNode.childNodes[currentPosition + 1] ?? _null;
|
|
37
|
+
parentNode.insertBefore(node, nextNode);
|
|
36
38
|
}
|
|
37
39
|
}
|
|
38
40
|
currentPosition++;
|
|
@@ -42,7 +44,7 @@ export class For<T = any> extends ProxyProto {
|
|
|
42
44
|
}
|
|
43
45
|
|
|
44
46
|
this.list$.subscribe(update);
|
|
45
|
-
this.
|
|
47
|
+
this.listen('dispose', () => this.list$.unsubscribe(update));
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
override build() {
|
package/packages/i18n/README.md
CHANGED
|
@@ -1,37 +1,33 @@
|
|
|
1
1
|
# amateras/i18n
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Import
|
|
4
4
|
```ts
|
|
5
5
|
import 'amateras';
|
|
6
6
|
import 'amateras/i18n';
|
|
7
|
+
```
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
## Usage
|
|
10
|
+
```ts
|
|
11
|
+
const i18n = $.i18n('en')
|
|
10
12
|
.add('en', {
|
|
11
13
|
homepage: {
|
|
12
14
|
_: 'Home',
|
|
13
15
|
hello: 'Hello, $name$!',
|
|
14
16
|
}
|
|
15
17
|
})
|
|
16
|
-
// set 'en' as locale language
|
|
17
|
-
.locale('en')
|
|
18
18
|
|
|
19
|
-
$(
|
|
20
|
-
$('h1'
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
// <text>Hello, Amateras!</text>
|
|
24
|
-
])
|
|
19
|
+
$('div', $$ => {
|
|
20
|
+
$('h1', $$ => $([ i18n.t('homepage') ]))
|
|
21
|
+
$('p', $$ => $([ i18n.t('homepage.hello', { name: 'Amateras' }) ]))
|
|
22
|
+
})
|
|
25
23
|
```
|
|
26
24
|
|
|
27
25
|
## Change Language
|
|
28
26
|
```ts
|
|
29
|
-
|
|
30
|
-
// all translation text will be updated
|
|
27
|
+
i18n.locale('zh');
|
|
31
28
|
```
|
|
32
29
|
|
|
33
30
|
## Import Dictionary Context
|
|
34
|
-
|
|
35
31
|
```ts
|
|
36
32
|
// ./i18n/en.ts
|
|
37
33
|
export default {
|
|
@@ -47,27 +43,23 @@ export default {
|
|
|
47
43
|
const $t = $.i18n()
|
|
48
44
|
.add('en', () => import('./i18n/en.ts'))
|
|
49
45
|
.add('zh', () => import('./i18n/zh.ts'))
|
|
50
|
-
// set 'zh' as locale language
|
|
51
|
-
// and fetch file automatically from path
|
|
52
|
-
.locale('zh');
|
|
53
46
|
```
|
|
54
47
|
|
|
55
|
-
## Directory Shortcut
|
|
56
|
-
|
|
48
|
+
## Translation Directory Shortcut
|
|
57
49
|
```ts
|
|
58
|
-
const
|
|
50
|
+
const i18n = $.i18n('en')
|
|
59
51
|
.add('en', {
|
|
60
52
|
page1: {
|
|
61
53
|
section2: {
|
|
62
54
|
button3: {
|
|
63
|
-
text: '
|
|
55
|
+
text: 'Deep Button Text'
|
|
64
56
|
}
|
|
65
57
|
}
|
|
66
58
|
}
|
|
67
59
|
})
|
|
68
60
|
|
|
69
|
-
const
|
|
61
|
+
const i18n_button = i18n.dir('page1.section2.button3');
|
|
70
62
|
|
|
71
|
-
|
|
72
|
-
|
|
63
|
+
i18n.t('page1.section2.button3.text') // Deep Button Text
|
|
64
|
+
i18n_button.t('text') // Deep Button Text
|
|
73
65
|
```
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { I18n } from "#structure/I18n";
|
|
2
2
|
import { I18nTranslation as _I18nTranslation, I18nTranslation } from "#structure/I18nTranslation";
|
|
3
|
-
import { _instanceof, _null, _Object_assign } from "@amateras/utils";
|
|
4
|
-
import { GlobalState } from "@amateras/core";
|
|
3
|
+
import { _instanceof, _null, _Object_assign, forEach } from "@amateras/utils";
|
|
4
|
+
import { GlobalState, Proto, ProxyProto } from "@amateras/core";
|
|
5
5
|
import type { I18nSession } from "#structure/I18nSession";
|
|
6
6
|
|
|
7
7
|
declare global {
|
|
@@ -13,7 +13,7 @@ declare global {
|
|
|
13
13
|
i18n: I18nTranslation
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
export interface ProtoEventMap {
|
|
16
|
+
export interface ProtoEventMap<P extends Proto> {
|
|
17
17
|
i18nupdate: [I18nTranslation]
|
|
18
18
|
}
|
|
19
19
|
}
|
|
@@ -31,10 +31,14 @@ declare module '@amateras/core' {
|
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
GlobalState.assign({
|
|
34
|
+
GlobalState.assign(() => ({
|
|
35
35
|
i18n: {
|
|
36
36
|
session: _null
|
|
37
37
|
}
|
|
38
|
+
}))
|
|
39
|
+
|
|
40
|
+
GlobalState.disposers.add(global => {
|
|
41
|
+
global.i18n.session = _null;
|
|
38
42
|
})
|
|
39
43
|
|
|
40
44
|
_Object_assign($, {
|
|
@@ -45,7 +49,24 @@ _Object_assign($, {
|
|
|
45
49
|
|
|
46
50
|
$.process.text.add(value => {
|
|
47
51
|
if (_instanceof(value, I18nTranslation)) {
|
|
48
|
-
|
|
52
|
+
const $proxy = new ProxyProto();
|
|
53
|
+
value.onupdate(result => {
|
|
54
|
+
$proxy.layout = () => $([ ...result ]);
|
|
55
|
+
forEach($proxy.protos, proto => proto.removeNode());
|
|
56
|
+
$proxy.build();
|
|
57
|
+
$proxy.node?.replaceWith(...$proxy.toDOM());
|
|
58
|
+
$proxy.dispatch('i18nupdate', [this], {bubbles: true})
|
|
59
|
+
})
|
|
60
|
+
value.update();
|
|
61
|
+
return $proxy;
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
$.process.attr.add((name, value, proto) => {
|
|
65
|
+
if (_instanceof(value, I18nTranslation)) {
|
|
66
|
+
value.onupdate((result) => {
|
|
67
|
+
proto.attr(name, result.join(''))
|
|
68
|
+
})
|
|
69
|
+
value.update();
|
|
49
70
|
}
|
|
50
71
|
})
|
|
51
72
|
|
|
@@ -10,13 +10,11 @@ export class I18n<D extends I18nDictionaryContext = {}> {
|
|
|
10
10
|
dictionaries = new Map<string, I18nDictionary>();
|
|
11
11
|
defaultLocale: string;
|
|
12
12
|
sessions = new Set<I18nSession>();
|
|
13
|
-
session = new I18nSession(this);
|
|
14
13
|
path = '';
|
|
15
14
|
static key = '__locale__';
|
|
16
15
|
constructor(defaultLocale: string) {
|
|
17
16
|
this.defaultLocale = defaultLocale;
|
|
18
17
|
this.#locale = defaultLocale;
|
|
19
|
-
this.sessions.add(this.session);
|
|
20
18
|
}
|
|
21
19
|
|
|
22
20
|
add(lang: string, dictionary: I18nDictionaryContext | I18nDictionaryContextImporter) {
|
|
@@ -75,11 +73,11 @@ export class I18n<D extends I18nDictionaryContext = {}> {
|
|
|
75
73
|
private getSession() {
|
|
76
74
|
let parentProto = Proto.proto;
|
|
77
75
|
if (parentProto) {
|
|
78
|
-
let session = parentProto.global.i18n.session ?? new I18nSession(this);
|
|
76
|
+
let session = parentProto.global.i18n.session ?? new I18nSession(this, parentProto.global);
|
|
79
77
|
parentProto.global.i18n.session = session;
|
|
80
78
|
return session;
|
|
81
79
|
}
|
|
82
|
-
else
|
|
80
|
+
else throw 'I18n.getSession(): session not found from Proto.proto'
|
|
83
81
|
}
|
|
84
82
|
|
|
85
83
|
private readStoreLocale() {
|
|
@@ -2,14 +2,16 @@ import { isUndefined, map } from "@amateras/utils";
|
|
|
2
2
|
import type { I18nTranslationResult } from "../types";
|
|
3
3
|
import type { I18n } from "./I18n";
|
|
4
4
|
import type { I18nTranslation, I18nTranslationOptions } from "./I18nTranslation";
|
|
5
|
-
import { onclient } from "@amateras/core";
|
|
5
|
+
import { GlobalState, onclient } from "@amateras/core";
|
|
6
6
|
|
|
7
7
|
export class I18nSession {
|
|
8
8
|
translations = new Set<I18nTranslation>()
|
|
9
9
|
i18n: I18n;
|
|
10
10
|
#locale: string;
|
|
11
|
-
|
|
11
|
+
global: GlobalState;
|
|
12
|
+
constructor(i18n: I18n, global: GlobalState) {
|
|
12
13
|
this.i18n = i18n;
|
|
14
|
+
this.global = global;
|
|
13
15
|
this.#locale = i18n.locale();
|
|
14
16
|
i18n.sessions.add(this);
|
|
15
17
|
}
|
|
@@ -1,45 +1,34 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { forEach } from "@amateras/utils";
|
|
1
|
+
import { forEach, map } from "@amateras/utils";
|
|
3
2
|
import type { I18nSession } from "./I18nSession";
|
|
4
3
|
|
|
5
|
-
export class I18nTranslation
|
|
4
|
+
export class I18nTranslation {
|
|
6
5
|
session: I18nSession;
|
|
7
6
|
key: string;
|
|
8
7
|
options: I18nTranslationOptions | undefined;
|
|
8
|
+
private updating = false;
|
|
9
|
+
private updaters: ((result: any[]) => void)[] = [];
|
|
9
10
|
constructor(session: I18nSession, key: string, options?: I18nTranslationOptions) {
|
|
10
|
-
super()
|
|
11
11
|
this.session = session;
|
|
12
12
|
this.key = key;
|
|
13
13
|
this.options = options;
|
|
14
|
-
session.translations.add(this);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
override dispose(): void {
|
|
18
|
-
super.dispose();
|
|
19
|
-
this.session.translations.delete(this)
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
override build(): this {
|
|
23
|
-
this.update();
|
|
24
|
-
return this;
|
|
14
|
+
this.session.translations.add(this);
|
|
25
15
|
}
|
|
26
16
|
|
|
27
17
|
async update() {
|
|
18
|
+
if (this.updating) return;
|
|
19
|
+
this.updating = true;
|
|
28
20
|
const request = this.session.fetch(this.key, this.options);
|
|
29
|
-
this.global.asyncTask(request);
|
|
21
|
+
this.session.global.asyncTask(request);
|
|
30
22
|
const {text, args} = await request;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
text.raw = text;
|
|
35
|
-
$(text as any, ...args);
|
|
36
|
-
}
|
|
37
|
-
forEach(this.protos, proto => proto.removeNode());
|
|
38
|
-
super.build();
|
|
39
|
-
this.node?.replaceWith(...this.toDOM());
|
|
40
|
-
this.dispatch('i18nupdate', this, {bubbles: true})
|
|
23
|
+
const arr = map(text, (str, index) => index < args.length ? [str, args[index]] : [str]).flat();
|
|
24
|
+
forEach(this.updaters, updaters => updaters(arr))
|
|
25
|
+
this.updating = false;
|
|
41
26
|
return this;
|
|
42
27
|
}
|
|
28
|
+
|
|
29
|
+
onupdate(handle: (result: any[]) => void) {
|
|
30
|
+
this.updaters.push(handle);
|
|
31
|
+
}
|
|
43
32
|
}
|
|
44
33
|
|
|
45
34
|
export type I18nTranslationOptions = {[key: string]: any}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _Object_assign } from "@amateras/utils";
|
|
2
2
|
import { $IDBIndex, type $IDBIndexConfig } from "./$IDBIndex";
|
|
3
3
|
import { $IDBRequest } from "#lib/$IDBRequest";
|
|
4
4
|
import { $IDBStoreBase } from "./$IDBStoreBase";
|
|
@@ -59,7 +59,7 @@ export interface $IDBStore<Config extends $IDBStoreConfig = any> {
|
|
|
59
59
|
count(query?: $IDBStoreKey<Config> | IDBKeyRange): Promise<number>;
|
|
60
60
|
|
|
61
61
|
/** {@link IDBObjectStore.get} */
|
|
62
|
-
get(query: $IDBStoreKey<Config> | IDBKeyRange): Promise<Config['schema']>
|
|
62
|
+
get(query: $IDBStoreKey<Config> | IDBKeyRange): Promise<Config['schema'] | undefined>
|
|
63
63
|
|
|
64
64
|
/** {@link IDBObjectStore.getAll} */
|
|
65
65
|
getAll(query?: $IDBStoreKey<Config> | IDBKeyRange): Promise<Config['schema'][]>
|
|
@@ -2,7 +2,7 @@ import type { Condition } from "#structure/Condition";
|
|
|
2
2
|
import * as _Else from "#structure/Else";
|
|
3
3
|
import * as _ElseIf from "#structure/ElseIf";
|
|
4
4
|
import * as _If from "#structure/If";
|
|
5
|
-
import type { Signal
|
|
5
|
+
import type { Signal } from "@amateras/signal";
|
|
6
6
|
import type { IfLayout } from ".";
|
|
7
7
|
|
|
8
8
|
declare global {
|
|
@@ -10,7 +10,18 @@ declare global {
|
|
|
10
10
|
export var Else: typeof _Else.Else
|
|
11
11
|
export var ElseIf: typeof _ElseIf.ElseIf
|
|
12
12
|
|
|
13
|
-
export
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
export namespace $ {
|
|
14
|
+
export interface Overload<I> {
|
|
15
|
+
if: [
|
|
16
|
+
input: [typeof _If.If | typeof _ElseIf.ElseIf, signal: OrArray<Signal>],
|
|
17
|
+
output: Condition,
|
|
18
|
+
args: [layout: I[1] extends OrArray<Signal> ? IfLayout<I[1]> : never]
|
|
19
|
+
]
|
|
20
|
+
else: [
|
|
21
|
+
input: [typeof _Else.Else],
|
|
22
|
+
output: Condition,
|
|
23
|
+
args: [layout: _Else.ElseLayout]
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
16
27
|
}
|
package/packages/if/src/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import './global';
|
|
2
2
|
import { If } from "#structure/If";
|
|
3
|
-
import { _instanceof, _null, isIncluded } from "@amateras/utils";
|
|
4
|
-
import { Signal, type SignalObject
|
|
3
|
+
import { _instanceof, _null, isArray, isIncluded } from "@amateras/utils";
|
|
4
|
+
import { Signal, type SignalObject } from '@amateras/signal';
|
|
5
5
|
import { ElseIf } from '#structure/ElseIf';
|
|
6
6
|
import { Else } from '#structure/Else';
|
|
7
7
|
import { Condition } from '#structure/Condition';
|
|
@@ -10,13 +10,24 @@ globalThis.If = If;
|
|
|
10
10
|
globalThis.Else = Else;
|
|
11
11
|
globalThis.ElseIf = ElseIf;
|
|
12
12
|
|
|
13
|
-
export type IfLayout<T> = (value: T extends
|
|
13
|
+
export type IfLayout<T> = (...value: T extends any[]
|
|
14
|
+
? ResolveArray<T>
|
|
15
|
+
: [ResolveSignal<T>]
|
|
16
|
+
) => void;
|
|
17
|
+
|
|
18
|
+
type ResolveArray<T> = T extends [infer A, ...infer Rest]
|
|
19
|
+
? [A] extends [Signal<any>]
|
|
20
|
+
? [ResolveSignal<A>, ...ResolveArray<Rest>]
|
|
21
|
+
: []
|
|
22
|
+
: [];
|
|
23
|
+
|
|
24
|
+
type ResolveSignal<T> = [T] extends [Signal<infer V>]
|
|
14
25
|
? V extends object
|
|
15
26
|
? SignalObject<V>
|
|
16
|
-
: V extends null
|
|
27
|
+
: V extends null
|
|
17
28
|
? never
|
|
18
29
|
: Signal<V>
|
|
19
|
-
:
|
|
30
|
+
: T;
|
|
20
31
|
|
|
21
32
|
/**This map store condition with parent Proto,
|
|
22
33
|
* all related Statement should be under same parent Proto.
|
|
@@ -39,10 +50,9 @@ $.process.craft.add((value, arg1, arg2) => {
|
|
|
39
50
|
// handle If/Else/ElseIf constructor
|
|
40
51
|
// add them into condition child statements
|
|
41
52
|
if (isIncluded(value, [If, Else, ElseIf])) {
|
|
42
|
-
let args: [Signal | null, () => void] = _instanceof(arg1, Signal) ? [arg1, arg2] : [_null, arg1];
|
|
53
|
+
let args: [Signal | Signal[] | null, () => void] = (_instanceof(arg1, Signal) || isArray(arg1)) ? [arg1, arg2] : [_null, arg1];
|
|
43
54
|
let statement = new value(...args);
|
|
44
|
-
condition.
|
|
45
|
-
condition.statements?.push(statement);
|
|
55
|
+
condition.append(statement);
|
|
46
56
|
}
|
|
47
57
|
else {
|
|
48
58
|
condition = _null;
|
|
@@ -5,13 +5,12 @@ import type { ConditionStatement } from "./ConditionStatement";
|
|
|
5
5
|
|
|
6
6
|
export class Condition extends ProxyProto {
|
|
7
7
|
static override [symbol_Statement] = true;
|
|
8
|
-
statements: ConditionStatement[] | null = _null;
|
|
9
8
|
declare layout: null;
|
|
10
9
|
statement: ConditionStatement | null = _null;
|
|
11
10
|
|
|
12
11
|
override build() {
|
|
13
12
|
// run base build method with empty protos
|
|
14
|
-
super.build(false);
|
|
13
|
+
super.build(false, false);
|
|
15
14
|
// set condition matched proto
|
|
16
15
|
this.validate()?.build();
|
|
17
16
|
// update function for Signal subscribe
|
|
@@ -20,32 +19,36 @@ export class Condition extends ProxyProto {
|
|
|
20
19
|
if (!matchProto?.builded) matchProto?.build();
|
|
21
20
|
if (this.statement === matchProto) return;
|
|
22
21
|
this.statement = matchProto ?? _null;
|
|
23
|
-
forEach(this.
|
|
22
|
+
forEach(this.protos, proto => !proto.visible && proto.removeNode());
|
|
24
23
|
this.node?.replaceWith(...this.toDOM());
|
|
25
24
|
this.parent?.mutate();
|
|
26
25
|
}
|
|
27
26
|
// build statements proto and subscribe expression signal
|
|
28
|
-
forEach(this.
|
|
29
|
-
proto.exp
|
|
30
|
-
|
|
31
|
-
proto.
|
|
32
|
-
|
|
27
|
+
forEach(this.protos, proto => {
|
|
28
|
+
forEach(proto.exps, exp$ => {
|
|
29
|
+
exp$?.subscribe(update);
|
|
30
|
+
proto.listen('dispose', () => {
|
|
31
|
+
exp$?.unsubscribe(update)
|
|
32
|
+
});
|
|
33
|
+
})
|
|
33
34
|
})
|
|
34
35
|
return this;
|
|
35
36
|
}
|
|
36
37
|
|
|
38
|
+
override get protos(): Set<ConditionStatement> {
|
|
39
|
+
return super.protos as Set<ConditionStatement>
|
|
40
|
+
}
|
|
41
|
+
|
|
37
42
|
override dispose(): void {
|
|
38
43
|
super.dispose();
|
|
39
|
-
forEach(this.statements, statement => statement.dispose());
|
|
40
44
|
this.statement = _null;
|
|
41
|
-
this.statements = _null;
|
|
42
45
|
}
|
|
43
46
|
|
|
44
47
|
validate() {
|
|
45
|
-
this.
|
|
46
|
-
|
|
48
|
+
forEach(this.protos, proto => proto.visible = false);
|
|
49
|
+
for (let proto of this.protos) {
|
|
47
50
|
if (proto.validate()) {
|
|
48
|
-
|
|
51
|
+
proto.visible = true;
|
|
49
52
|
return proto;
|
|
50
53
|
}
|
|
51
54
|
}
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
import { symbol_Statement } from "@amateras/core";
|
|
2
2
|
import { Proto } from "@amateras/core";
|
|
3
3
|
import type { Signal } from "@amateras/signal";
|
|
4
|
-
import { _null } from "@amateras/utils";
|
|
4
|
+
import { _null, toArray } from "@amateras/utils";
|
|
5
5
|
|
|
6
|
-
export type ConditionLayout = (value: Signal<any>
|
|
6
|
+
export type ConditionLayout = (...value: Signal<any>[]) => void;
|
|
7
7
|
|
|
8
8
|
export abstract class ConditionStatement extends Proto {
|
|
9
9
|
static override [symbol_Statement] = true;
|
|
10
|
-
|
|
11
|
-
constructor(expression: Signal<any
|
|
12
|
-
super(() => layout(this.
|
|
13
|
-
this.
|
|
10
|
+
exps: Signal<any>[] | null;
|
|
11
|
+
constructor(expression: OrArray<Signal<any>> | null, layout: ConditionLayout) {
|
|
12
|
+
super(() => layout(...this.exps ?? []));
|
|
13
|
+
this.exps = expression ? toArray(expression) : _null;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
override dispose(): void {
|
|
17
17
|
super.dispose();
|
|
18
|
-
this.
|
|
18
|
+
this.exps = _null;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
validate() {
|
|
22
|
-
if (!this.
|
|
23
|
-
return
|
|
22
|
+
if (!this.exps) return true;
|
|
23
|
+
return !this.exps.find(exp$ => !exp$.value)
|
|
24
24
|
}
|
|
25
25
|
}
|
|
@@ -8,7 +8,13 @@ declare global {
|
|
|
8
8
|
export var Case: typeof _Case.Case
|
|
9
9
|
export var Default: typeof _Default.Default
|
|
10
10
|
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
export namespace $ {
|
|
12
|
+
export interface Overload<I> {
|
|
13
|
+
match: [
|
|
14
|
+
input: [typeof _Match.Match, Signal],
|
|
15
|
+
output: I[1] extends Signal<infer T> ? _Match.Match<T> : never,
|
|
16
|
+
args: [layout: I[1] extends Signal<infer T> ? _Match.MatchLayout<T> : never]
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
}
|
|
14
20
|
}
|
|
@@ -51,7 +51,7 @@ export class Match<T = any> extends ProxyProto {
|
|
|
51
51
|
// build cases proto and subscribe expression signal
|
|
52
52
|
forEach(this.cases, proto => {
|
|
53
53
|
this.exp$.subscribe(update);
|
|
54
|
-
proto.
|
|
54
|
+
proto.listen('dispose', () => this.exp$.unsubscribe(update));
|
|
55
55
|
})
|
|
56
56
|
return this;
|
|
57
57
|
}
|
|
@@ -6,7 +6,7 @@ import type { MetaConfig } from "./types";
|
|
|
6
6
|
|
|
7
7
|
declare global {
|
|
8
8
|
export namespace $ {
|
|
9
|
-
function meta(config: MetaConfig): void
|
|
9
|
+
function meta(config: MetaConfig, parent?: Proto | null): void
|
|
10
10
|
|
|
11
11
|
export namespace meta {
|
|
12
12
|
function resolve(config: MetaConfig): void
|
|
@@ -22,11 +22,10 @@ declare module '@amateras/core' {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
_Object_assign($, {
|
|
25
|
-
meta(config: MetaConfig) {
|
|
25
|
+
meta(config: MetaConfig, parent = Proto.proto) {
|
|
26
26
|
if (onclient()) return;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
proto.global.meta = deepMerge(proto.global.meta ?? {}, config);
|
|
27
|
+
if (!parent) return;
|
|
28
|
+
parent.global.meta = deepMerge(parent.global.meta ?? {}, config);
|
|
30
29
|
},
|
|
31
30
|
})
|
|
32
31
|
|
|
@@ -5,7 +5,12 @@ import { _null, _Object_assign, isAsyncFunction, toURL } from "@amateras/utils";
|
|
|
5
5
|
|
|
6
6
|
declare global {
|
|
7
7
|
export namespace $ {
|
|
8
|
-
export function fetch<T, R>(url: string | URL, options?: RequestInit & FetchOptions<T, R
|
|
8
|
+
export function fetch<T, R>(url: string | URL, options?: RequestInit & FetchOptions<T, R>, proto?: Proto | null): Promise<FetchResult<T, R>>
|
|
9
|
+
|
|
10
|
+
export namespace fetch {
|
|
11
|
+
export let origin: string;
|
|
12
|
+
export let server: Bun.Server<undefined> | null
|
|
13
|
+
}
|
|
9
14
|
}
|
|
10
15
|
export var prefetch: {[key: string]: { expired: number, data: any }}
|
|
11
16
|
}
|
|
@@ -13,7 +18,8 @@ declare global {
|
|
|
13
18
|
declare module "@amateras/core" {
|
|
14
19
|
export interface GlobalState {
|
|
15
20
|
prefetch: {
|
|
16
|
-
caches: {[key: string]: { expired: number, data: any }}
|
|
21
|
+
caches: {[key: string]: { expired: number, data: any }};
|
|
22
|
+
req: null | Request
|
|
17
23
|
}
|
|
18
24
|
}
|
|
19
25
|
}
|
|
@@ -28,11 +34,12 @@ export type FetchResult<T, R> = {
|
|
|
28
34
|
result: R;
|
|
29
35
|
}
|
|
30
36
|
|
|
31
|
-
GlobalState.assign({
|
|
37
|
+
GlobalState.assign(() => ({
|
|
32
38
|
prefetch: {
|
|
33
|
-
caches: {}
|
|
39
|
+
caches: {},
|
|
40
|
+
req: null
|
|
34
41
|
}
|
|
35
|
-
})
|
|
42
|
+
}))
|
|
36
43
|
|
|
37
44
|
if (!globalThis.prefetch) globalThis.prefetch = {}
|
|
38
45
|
|
|
@@ -41,9 +48,8 @@ _Object_assign($, {
|
|
|
41
48
|
// 保证每次全局渲染都在抓取完毕之后:将 Promise 添加到 global.prefetch.fetches 让根原型能确保所有 fetch 运行结束
|
|
42
49
|
// 将已抓取的资料发送到客户端:从 record 函数回传的资料将会被记录在 global.prefetch.caches 当中,并且以抓取 URL 作为索引。
|
|
43
50
|
// 客户端不会用到过时的资料:每个发送到客户端的资料缓存都附上了过期时间
|
|
44
|
-
async fetch<T, R>(url: string | URL, options?: RequestInit & FetchOptions<T, R
|
|
45
|
-
url = toURL(url);
|
|
46
|
-
let proto = Proto.proto;
|
|
51
|
+
async fetch<T, R>(url: string | URL, options?: RequestInit & FetchOptions<T, R>, proto = Proto.proto) {
|
|
52
|
+
url = toURL(url, $.fetch.origin);
|
|
47
53
|
let cache = onclient() ? prefetch[url.href] : _null;
|
|
48
54
|
let then = options?.then;
|
|
49
55
|
let request = new Promise(async (resolve) => {
|
|
@@ -52,7 +58,17 @@ _Object_assign($, {
|
|
|
52
58
|
resolve({record: cache.data, result});
|
|
53
59
|
return ;
|
|
54
60
|
}
|
|
55
|
-
let
|
|
61
|
+
let { origin, server } = $.fetch;
|
|
62
|
+
let cookies = proto?.global.prefetch.req?.headers.get('cookie') || '';
|
|
63
|
+
let response = url.origin === origin && server
|
|
64
|
+
? await server.fetch(new Request(url, {
|
|
65
|
+
...options,
|
|
66
|
+
headers: {
|
|
67
|
+
...options?.headers,
|
|
68
|
+
'Cookie': cookies
|
|
69
|
+
}
|
|
70
|
+
}))
|
|
71
|
+
: await fetch(url, options);
|
|
56
72
|
let recordFn = options?.record;
|
|
57
73
|
if (recordFn) {
|
|
58
74
|
let record = isAsyncFunction(recordFn) ? await recordFn(response) : recordFn(response);
|
|
@@ -67,4 +83,9 @@ _Object_assign($, {
|
|
|
67
83
|
if (onserver()) proto?.global.asyncTask(request)
|
|
68
84
|
return request
|
|
69
85
|
}
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
_Object_assign($.fetch, {
|
|
89
|
+
origin: onclient() ? location.origin : 'http://localhost',
|
|
90
|
+
server: null
|
|
70
91
|
})
|