amateras 0.4.2 → 0.6.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 +24 -25
- package/ext/html/node/$Anchor.ts +3 -3
- package/ext/html/node/$Canvas.ts +2 -2
- package/ext/html/node/$Dialog.ts +2 -2
- package/ext/html/node/$Form.ts +2 -2
- package/ext/html/node/$Image.ts +2 -2
- package/ext/html/node/$Input.ts +28 -4
- package/ext/html/node/$Label.ts +12 -3
- package/ext/html/node/$Media.ts +2 -2
- package/ext/html/node/$OptGroup.ts +2 -2
- package/ext/html/node/$Option.ts +2 -2
- package/ext/html/node/$Select.ts +2 -2
- package/ext/html/node/$TextArea.ts +2 -2
- package/ext/i18n/README.md +20 -0
- package/ext/i18n/src/index.ts +106 -12
- package/ext/i18n/src/structure/I18n.ts +12 -8
- package/ext/i18n/src/structure/I18nDictionary.ts +2 -2
- package/ext/i18n/src/structure/I18nTranslation.ts +35 -0
- package/ext/idb/README.md +127 -0
- package/ext/idb/package.json +13 -0
- package/ext/idb/src/core.ts +6 -0
- package/ext/idb/src/index.ts +17 -0
- package/ext/idb/src/lib/$IDBRequest.ts +8 -0
- package/ext/idb/src/structure/$IDB.ts +63 -0
- package/ext/idb/src/structure/$IDBCursor.ts +34 -0
- package/ext/idb/src/structure/$IDBIndex.ts +48 -0
- package/ext/idb/src/structure/$IDBStore.ts +103 -0
- package/ext/idb/src/structure/$IDBStoreBase.ts +30 -0
- package/ext/idb/src/structure/$IDBTransaction.ts +38 -0
- package/ext/idb/src/structure/builder/$IDBBuilder.ts +230 -0
- package/ext/idb/src/structure/builder/$IDBStoreBuilder.ts +100 -0
- package/ext/markdown/README.md +53 -0
- package/ext/markdown/package.json +15 -0
- package/ext/markdown/src/index.ts +3 -0
- package/ext/markdown/src/lib/type.ts +26 -0
- package/ext/markdown/src/lib/util.ts +21 -0
- package/ext/markdown/src/structure/Markdown.ts +54 -0
- package/ext/markdown/src/structure/MarkdownLexer.ts +111 -0
- package/ext/markdown/src/structure/MarkdownParser.ts +33 -0
- package/ext/markdown/src/syntax/alert.ts +46 -0
- package/ext/markdown/src/syntax/blockquote.ts +35 -0
- package/ext/markdown/src/syntax/bold.ts +11 -0
- package/ext/markdown/src/syntax/code.ts +11 -0
- package/ext/markdown/src/syntax/codeblock.ts +44 -0
- package/ext/markdown/src/syntax/heading.ts +14 -0
- package/ext/markdown/src/syntax/horizontalRule.ts +11 -0
- package/ext/markdown/src/syntax/image.ts +23 -0
- package/ext/markdown/src/syntax/italic.ts +11 -0
- package/ext/markdown/src/syntax/link.ts +46 -0
- package/ext/markdown/src/syntax/list.ts +121 -0
- package/ext/markdown/src/syntax/table.ts +67 -0
- package/ext/markdown/src/syntax/text.ts +19 -0
- package/ext/router/README.md +111 -17
- package/ext/router/package.json +10 -0
- package/ext/router/src/index.ts +69 -0
- package/ext/router/src/node/Page.ts +34 -0
- package/ext/router/src/node/Router.ts +191 -0
- package/ext/router/src/node/RouterAnchor.ts +24 -0
- package/ext/router/src/structure/PageBuilder.ts +24 -0
- package/ext/router/src/structure/Route.ts +105 -0
- package/ext/signal/README.md +93 -0
- package/ext/signal/package.json +9 -0
- package/ext/signal/src/index.ts +128 -0
- package/{src → ext/signal/src}/structure/Signal.ts +7 -11
- package/ext/ssr/index.ts +4 -4
- package/ext/ui/lib/VirtualScroll.ts +25 -0
- package/ext/ui/node/Accordian.ts +97 -0
- package/ext/ui/node/Form.ts +53 -0
- package/ext/ui/node/Grid.ts +0 -0
- package/ext/ui/node/Table.ts +43 -0
- package/ext/ui/node/Tabs.ts +114 -0
- package/ext/ui/node/Toast.ts +16 -0
- package/ext/ui/node/Waterfall.ts +72 -0
- package/ext/ui/package.json +11 -0
- package/package.json +9 -3
- package/src/core.ts +31 -59
- package/src/global.ts +12 -2
- package/src/index.ts +1 -2
- package/src/lib/assignProperties.ts +57 -0
- package/src/lib/native.ts +33 -11
- package/src/lib/sleep.ts +3 -1
- package/src/lib/toArray.ts +9 -0
- package/src/lib/trycatch.ts +17 -0
- package/src/lib/uppercase.ts +3 -0
- package/src/node/$Element.ts +7 -53
- package/src/node/$EventTarget.ts +45 -0
- package/src/node/$Node.ts +63 -55
- package/src/node/$Virtual.ts +65 -0
- package/src/node.ts +7 -6
- package/ext/i18n/src/node/I18nText.ts +0 -35
- package/ext/router/index.ts +0 -73
- package/ext/router/node/Page.ts +0 -27
- package/ext/router/node/Route.ts +0 -54
- package/ext/router/node/Router.ts +0 -149
- package/ext/router/node/RouterAnchor.ts +0 -8
- package/src/lib/assign.ts +0 -38
- package/src/lib/assignHelper.ts +0 -18
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { _instanceof, forEach, isUndefined } from "
|
|
1
|
+
import { _instanceof, forEach, isFunction, isUndefined } from "amateras/lib/native";
|
|
2
2
|
|
|
3
3
|
export class Signal<T> {
|
|
4
4
|
#value: T;
|
|
5
|
-
subscribers = new Set<(value: T) => void>();
|
|
6
|
-
static listeners = new Set<(signal: Signal<any>) => void>();
|
|
5
|
+
#subscribers = new Set<(value: T) => void>();
|
|
7
6
|
constructor(value: T) {
|
|
8
7
|
this.#value = value;
|
|
9
8
|
}
|
|
@@ -12,11 +11,8 @@ export class Signal<T> {
|
|
|
12
11
|
value(newValue: T): this;
|
|
13
12
|
value(callback: (oldValue: T) => T): this;
|
|
14
13
|
value(resolver?: T | ((oldValue: T) => T)) {
|
|
15
|
-
if (!arguments.length)
|
|
16
|
-
|
|
17
|
-
return this.#value;
|
|
18
|
-
}
|
|
19
|
-
if (_instanceof(resolver, Function)) this.value(resolver(this.#value));
|
|
14
|
+
if (!arguments.length) return this.#value;
|
|
15
|
+
if (isFunction(resolver)) this.value(resolver(this.#value));
|
|
20
16
|
else if (!isUndefined(resolver)) {
|
|
21
17
|
this.#value = resolver;
|
|
22
18
|
this.emit();
|
|
@@ -25,17 +21,17 @@ export class Signal<T> {
|
|
|
25
21
|
}
|
|
26
22
|
|
|
27
23
|
emit() {
|
|
28
|
-
forEach(this
|
|
24
|
+
forEach(this.#subscribers, subs => subs(this.#value))
|
|
29
25
|
return this;
|
|
30
26
|
}
|
|
31
27
|
|
|
32
28
|
subscribe(callback: (value: T) => void) {
|
|
33
|
-
this
|
|
29
|
+
this.#subscribers.add(callback);
|
|
34
30
|
return this;
|
|
35
31
|
}
|
|
36
32
|
|
|
37
33
|
unsubscribe(callback: (value: T) => void) {
|
|
38
|
-
this
|
|
34
|
+
this.#subscribers.delete(callback);
|
|
39
35
|
return this;
|
|
40
36
|
}
|
|
41
37
|
|
package/ext/ssr/index.ts
CHANGED
|
@@ -32,10 +32,10 @@ _Object_assign($, {
|
|
|
32
32
|
node.replaceWith($node.node);
|
|
33
33
|
|
|
34
34
|
function getData(node: Node, $node: $Node) {
|
|
35
|
-
if (node.nodeName === 'SIGNAL' && _instanceof(node, Element) && _instanceof($node, $Text)) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
35
|
+
// if (node.nodeName === 'SIGNAL' && _instanceof(node, Element) && _instanceof($node, $Text)) {
|
|
36
|
+
// const type = $(node).attr()['type'];
|
|
37
|
+
// return forEach($node.signals, signal => signal.value(type === 'number' ? Number(node.textContent) : type === 'boolean' ? node.textContent == 'true' ? true : false : node.textContent));
|
|
38
|
+
// }
|
|
39
39
|
if (_instanceof(node, Text)) return $node.textContent(node.textContent);
|
|
40
40
|
if (_instanceof(node, Element) && _instanceof($node, $Element)) $node.attr($(node).attr());
|
|
41
41
|
const arr = _Array_from($node.childNodes);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { _Array_from, _instanceof, forEach } from "amateras/lib/native";
|
|
2
|
+
import type { $Virtual } from "amateras/node/$Virtual";
|
|
3
|
+
import { $HTMLElement } from "amateras/node/$HTMLElement";
|
|
4
|
+
import { _document } from "amateras/lib/env";
|
|
5
|
+
import type { $Node } from "amateras/node/$Node";
|
|
6
|
+
|
|
7
|
+
export const VirtualScroll = ($parent: $Virtual, scroller: $Node = $(_document)) => {
|
|
8
|
+
scroller.on('scroll', () => render($parent), true);
|
|
9
|
+
$parent.on('layout', () => render($parent));
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const render = ($parent: $Virtual) => {
|
|
13
|
+
const number = parseInt;
|
|
14
|
+
const parentRect = $parent.getBoundingClientRect();
|
|
15
|
+
const children = _Array_from($parent.nodes);
|
|
16
|
+
forEach(children, $child => {
|
|
17
|
+
if (!_instanceof($child, $HTMLElement)) return;
|
|
18
|
+
const { top, height } = $child.style();
|
|
19
|
+
const topPos = parentRect.top + number(top);
|
|
20
|
+
const bottomPos = topPos + number(height);
|
|
21
|
+
if (bottomPos < 0 || topPos > outerHeight + 200) $parent.hide($child);
|
|
22
|
+
else $parent.show($child);
|
|
23
|
+
})
|
|
24
|
+
$parent.render();
|
|
25
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { _Array_from, _instanceof, forEach, isNull } from "amateras/lib/native";
|
|
2
|
+
import { $HTMLElement } from "amateras/node/$HTMLElement";
|
|
3
|
+
import type { $Node, $NodeContentResolver } from "amateras/node/$Node";
|
|
4
|
+
import { chain } from "../../../src/lib/chain";
|
|
5
|
+
|
|
6
|
+
const [ACCORDIAN, ACCORDIAN_ITEM, ACCORDIAN_TRIGGER, ACCORDIAN_CONTENT, ACCORDIAN_CONTAINER] = ['accordian', 'accordian-item', 'accordian-trigger', 'accordian-content', 'accordian-container'] as const;
|
|
7
|
+
forEach([
|
|
8
|
+
`${ACCORDIAN},${ACCORDIAN_ITEM},${ACCORDIAN_TRIGGER}{display:block}`,
|
|
9
|
+
`${ACCORDIAN_CONTENT}{display:grid;grid-template-rows:0fr}`,
|
|
10
|
+
`${ACCORDIAN_CONTENT}[opened]{grid-template-rows:1fr}`,
|
|
11
|
+
`${ACCORDIAN_CONTAINER}{overflow:hidden}`,
|
|
12
|
+
], $.style)
|
|
13
|
+
|
|
14
|
+
export class Accordian extends $HTMLElement {
|
|
15
|
+
#autoclose = false;
|
|
16
|
+
constructor() {
|
|
17
|
+
super(ACCORDIAN);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
autoclose(): boolean;
|
|
21
|
+
autoclose(autoclose: boolean): this;
|
|
22
|
+
autoclose(autoclose?: boolean) {
|
|
23
|
+
return chain(this, arguments, () => this.#autoclose, autoclose, autoclose => this.#autoclose = autoclose);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
get items() {
|
|
27
|
+
return _Array_from($(this.childNodes)).filter($child => _instanceof($child, AccordianItem))
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export class AccordianItem extends $HTMLElement {
|
|
32
|
+
$content: null | AccordianContent = null;
|
|
33
|
+
$trigger: null | AccordianTrigger = null;
|
|
34
|
+
$root: null | Accordian = null;
|
|
35
|
+
constructor() {
|
|
36
|
+
super(ACCORDIAN_ITEM);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
mounted($parent: $Node): this {
|
|
40
|
+
if (_instanceof($parent, Accordian)) this.$root = $parent;
|
|
41
|
+
forEach($(this.childNodes), $c => {
|
|
42
|
+
if (_instanceof($c, AccordianTrigger)) this.$trigger = $c;
|
|
43
|
+
if (_instanceof($c, AccordianContent)) this.$content = $c;
|
|
44
|
+
})
|
|
45
|
+
return this;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export class AccordianTrigger extends $HTMLElement {
|
|
50
|
+
$item: null | AccordianItem = null;
|
|
51
|
+
constructor() {
|
|
52
|
+
super(ACCORDIAN_TRIGGER);
|
|
53
|
+
this.on('click', _ => {
|
|
54
|
+
const $item = this.$item;
|
|
55
|
+
const $root = $item?.$root;
|
|
56
|
+
this.$item?.$content?.use($content => isNull($content.attr('opened')) ? $content.open() : $content.close());
|
|
57
|
+
$root?.autoclose() && $root.items.forEach($i => $i !== $item && $i.$content?.close())
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
mounted($parent: $Node): this {
|
|
62
|
+
if (_instanceof($parent, AccordianItem)) this.$item = $parent;
|
|
63
|
+
return this;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export class AccordianContent extends $HTMLElement {
|
|
68
|
+
$container = $(AccordianContainer);
|
|
69
|
+
constructor() {
|
|
70
|
+
super(ACCORDIAN_CONTENT);
|
|
71
|
+
super.insert(this.$container);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
content(children: $NodeContentResolver<AccordianContainer>): this {
|
|
75
|
+
this.$container.content(children);
|
|
76
|
+
return this;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
insert(resolver: $NodeContentResolver<AccordianContainer>, position?: number): this {
|
|
80
|
+
this.$container.insert(resolver, position);
|
|
81
|
+
return this;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
open() {
|
|
85
|
+
return this.attr({opened: ''})
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
close() {
|
|
89
|
+
return this.attr({opened: null});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export class AccordianContainer extends $HTMLElement {
|
|
94
|
+
constructor() {
|
|
95
|
+
super(ACCORDIAN_CONTAINER);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { $Form } from 'amateras/html/$Form';
|
|
2
|
+
import { $HTMLElement } from 'amateras/node/$HTMLElement';
|
|
3
|
+
import { $Label } from 'amateras/html/$Label';
|
|
4
|
+
import { $Input } from 'amateras/html/$Input';
|
|
5
|
+
import type { $Node } from '../../../src/node/$Node';
|
|
6
|
+
import { _instanceof, _undefined } from '../../../src/lib/native';
|
|
7
|
+
|
|
8
|
+
export class Form extends $Form {
|
|
9
|
+
constructor() {
|
|
10
|
+
super();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
get data() {
|
|
14
|
+
return Object.fromEntries(new FormData(this.node).entries());
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export class FormField extends $HTMLElement {
|
|
19
|
+
constructor() {
|
|
20
|
+
super('form-field');
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class FormItem extends $HTMLElement {
|
|
25
|
+
constructor(name?: string) {
|
|
26
|
+
super('form-item');
|
|
27
|
+
this.attr({ name });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export class Label extends $Label {
|
|
32
|
+
constructor() {
|
|
33
|
+
super();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
mounted($parent: $Node): void {
|
|
37
|
+
if (_instanceof($parent, FormItem))
|
|
38
|
+
this.htmlFor($parent.attr('name') ?? _undefined);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export class Input extends $Input {
|
|
43
|
+
constructor() {
|
|
44
|
+
super();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
mounted($parent: $Node): void {
|
|
48
|
+
if (_instanceof($parent, FormItem)) {
|
|
49
|
+
const name = $parent.attr('name') ?? _undefined;
|
|
50
|
+
this.id(name).name(name);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { $HTMLElement } from "../../../src/node/$HTMLElement";
|
|
2
|
+
|
|
3
|
+
export class Table extends $HTMLElement {
|
|
4
|
+
constructor() {
|
|
5
|
+
super('table');
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class TableHeader extends $HTMLElement {
|
|
10
|
+
constructor() {
|
|
11
|
+
super('thead')
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class TableBody extends $HTMLElement {
|
|
16
|
+
constructor() {
|
|
17
|
+
super('tbody')
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class TableRow extends $HTMLElement {
|
|
22
|
+
constructor() {
|
|
23
|
+
super('tr')
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export class TableHead extends $HTMLElement {
|
|
28
|
+
constructor() {
|
|
29
|
+
super('th')
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export class TableCell extends $HTMLElement {
|
|
34
|
+
constructor() {
|
|
35
|
+
super('td')
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export class TableFooter extends $HTMLElement {
|
|
40
|
+
constructor() {
|
|
41
|
+
super('tfoot')
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { _Array_from, _instanceof, forEach, isUndefined } from "amateras/lib/native";
|
|
2
|
+
import { $HTMLElement } from "amateras/node/$HTMLElement";
|
|
3
|
+
import type { $Node } from "amateras/node/$Node";
|
|
4
|
+
|
|
5
|
+
$.style('tabs,tabs-container,tabs-list,tabs-content{display: block}')
|
|
6
|
+
|
|
7
|
+
export class Tabs extends $HTMLElement {
|
|
8
|
+
#value: null | string = null;
|
|
9
|
+
currentContent: null | TabsContent = null;
|
|
10
|
+
$container: null | TabsContainer = null;
|
|
11
|
+
$list: null | TabsList = null;
|
|
12
|
+
constructor() {
|
|
13
|
+
super('tabs');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
value(): string | null;
|
|
17
|
+
value(value: string | undefined): this;
|
|
18
|
+
value(value?: string) {
|
|
19
|
+
return chain(this, arguments, () => this.#value, value, value => {
|
|
20
|
+
this.#value = value;
|
|
21
|
+
this.$container?.content(this.$container.contentMap.get(value));
|
|
22
|
+
this.$list?.check();
|
|
23
|
+
})
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export class TabsContainer extends $HTMLElement {
|
|
28
|
+
$tabs?: Tabs;
|
|
29
|
+
contentMap = new Map<string, TabsContent>();
|
|
30
|
+
constructor($tabs?: Tabs) {
|
|
31
|
+
super('tabs-container');
|
|
32
|
+
this.$tabs = $tabs;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
mounted($parent: $Node) {
|
|
36
|
+
if (_instanceof($parent, Tabs)) this.$tabs = $parent;
|
|
37
|
+
if (this.$tabs) {
|
|
38
|
+
this.$tabs.$container = this;
|
|
39
|
+
this.content(this.contentMap.get(this.$tabs.value() ?? ''))
|
|
40
|
+
}
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export class TabsContent extends $HTMLElement {
|
|
46
|
+
#value: string;
|
|
47
|
+
$container: null | TabsContainer = null;
|
|
48
|
+
constructor(value: string) {
|
|
49
|
+
super('tabs-content');
|
|
50
|
+
this.#value = value
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
value(): string;
|
|
54
|
+
value(value: string): this;
|
|
55
|
+
value(value?: string) {
|
|
56
|
+
return chain(this, arguments, () => this.#value, value, value => {
|
|
57
|
+
this.#value = value;
|
|
58
|
+
this.$container?.contentMap.set(value, this).delete(this.#value ?? '')
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
mounted($parent: $Node) {
|
|
63
|
+
if (!_instanceof($parent, TabsContainer)) return this;
|
|
64
|
+
if ($parent && this.#value) {
|
|
65
|
+
this.$container = $parent;
|
|
66
|
+
$parent.contentMap.set(this.#value, this);
|
|
67
|
+
}
|
|
68
|
+
return this;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export class TabsList extends $HTMLElement {
|
|
73
|
+
$tabs?: null | Tabs = null;
|
|
74
|
+
triggers = new Map<string, TabsTrigger>();
|
|
75
|
+
constructor($tabs?: Tabs) {
|
|
76
|
+
super('tabs-list');
|
|
77
|
+
this.$tabs = $tabs;
|
|
78
|
+
this.on('click', _ => this.check())
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
check() {
|
|
82
|
+
this.triggers.forEach($trigger => $trigger.attr({selected: $trigger.value() === this.$tabs?.value() ? '' : null}))
|
|
83
|
+
return this;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
mounted($parent: $Node): this {
|
|
87
|
+
if (_instanceof($parent, Tabs)) this.$tabs = $parent, $parent.$list = this;
|
|
88
|
+
if (this.$tabs) forEach(_Array_from(this.childNodes), child => $(child).is(TabsTrigger)?.use($child => {
|
|
89
|
+
this.triggers.set($child.value(), $child);
|
|
90
|
+
$child.$tabs = this.$tabs;
|
|
91
|
+
}));
|
|
92
|
+
return this;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export class TabsTrigger extends $HTMLElement {
|
|
97
|
+
#value: string;
|
|
98
|
+
$tabs?: null | Tabs = null;
|
|
99
|
+
constructor(value: string) {
|
|
100
|
+
super('tabs-trigger');
|
|
101
|
+
this.#value = value;
|
|
102
|
+
this.on('click', _ => this.$tabs?.value(this.#value ?? undefined))
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
value(): string;
|
|
106
|
+
value(value: string): this;
|
|
107
|
+
value(value?: string) {
|
|
108
|
+
return chain(this, arguments, () => this.#value, value, value => this.#value = value)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function chain<T, R, V>(_this: T, args: IArguments, get: () => R, value: V, set: (value: Exclude<V, undefined>) => any) {
|
|
113
|
+
return !args.length ? get() : isUndefined(value) ? _this : (set(value as any), _this);
|
|
114
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { _document } from "../../../src/lib/env";
|
|
2
|
+
import { $HTMLElement } from "../../../src/node/$HTMLElement";
|
|
3
|
+
|
|
4
|
+
$.style('toast{position:absolute}')
|
|
5
|
+
|
|
6
|
+
export class Toast extends $HTMLElement {
|
|
7
|
+
constructor() {
|
|
8
|
+
super('toast');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
popup(duration = 3000) {
|
|
12
|
+
$(_document.body).insert(this);
|
|
13
|
+
setTimeout(() => this.remove(), duration)
|
|
14
|
+
return this;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { _Array_from, _instanceof, equal, forEach, isNumber } from "amateras/lib/native";
|
|
2
|
+
import { $HTMLElement } from "amateras/node/$HTMLElement";
|
|
3
|
+
import { $Element } from "amateras/node/$Element";
|
|
4
|
+
import { $Virtual } from "amateras/node/$Virtual";
|
|
5
|
+
|
|
6
|
+
const getRect = (el: $Element) => el.getBoundingClientRect();
|
|
7
|
+
const px = (value: number) => `${value}px`;
|
|
8
|
+
$.style(`waterfall { display: block; position: relative }`)
|
|
9
|
+
|
|
10
|
+
export class Waterfall extends $Virtual {
|
|
11
|
+
#column = 1;
|
|
12
|
+
#gap = 0;
|
|
13
|
+
#width = 0;
|
|
14
|
+
constructor() {
|
|
15
|
+
super('waterfall');
|
|
16
|
+
new ResizeObserver(_ => this.inDOM() && this.#width !== getRect(this).width && (this.dispatchEvent(new Event('resize', {cancelable: true})) && this.layout())).observe(this.node);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
column(): number;
|
|
20
|
+
column(column: $Parameter<number>): this;
|
|
21
|
+
column(column?: $Parameter<number>) {
|
|
22
|
+
if (!arguments.length) return this.#column;
|
|
23
|
+
if (isNumber(column)) this.#column = column;
|
|
24
|
+
return this;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
gap(): number;
|
|
28
|
+
gap(gap: $Parameter<number>): this;
|
|
29
|
+
gap(gap?: $Parameter<number>) {
|
|
30
|
+
if (!arguments.length) return this.#gap;
|
|
31
|
+
if (isNumber(gap)) this.#gap = gap;
|
|
32
|
+
return this;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
layout() {
|
|
36
|
+
const items = _Array_from(this.nodes).map(item => item);
|
|
37
|
+
const { width } = getRect(this);
|
|
38
|
+
this.#width = width;
|
|
39
|
+
const columnCount = this.#column;
|
|
40
|
+
const gap = this.#gap;
|
|
41
|
+
const columnWidth = ((width - ((columnCount - 1) * gap)) / columnCount);
|
|
42
|
+
const columns = _Array_from({length: columnCount}).map((_, i) => ({ i, h: 0, x: i * (columnWidth + gap) }))
|
|
43
|
+
const getColumnByHeight = (i: number) => columns.sort((a, b) => a.h - b.h ? a.h - b.h : a.i - b.i).at(i) as typeof columns[number];
|
|
44
|
+
forEach(items, item => {
|
|
45
|
+
if (!_instanceof(item, $HTMLElement)) return;
|
|
46
|
+
item.attr();
|
|
47
|
+
const { height, width } = item.attr();
|
|
48
|
+
const shortestSection = getColumnByHeight(0);
|
|
49
|
+
item.style({
|
|
50
|
+
position: 'absolute',
|
|
51
|
+
top: px(shortestSection.h),
|
|
52
|
+
left: px(shortestSection.x),
|
|
53
|
+
width: px(columnWidth),
|
|
54
|
+
});
|
|
55
|
+
if (width && height) {
|
|
56
|
+
// get ratio from attributes and calculate item's height
|
|
57
|
+
let itemHeight = columnWidth / (+width / +height);
|
|
58
|
+
item.style({ height: px(itemHeight) })
|
|
59
|
+
shortestSection.h += +itemHeight + gap;
|
|
60
|
+
} else {
|
|
61
|
+
item.style({ visibility: 'hidden', height: '' })
|
|
62
|
+
if (this.hiddenNodes.has(item)) this.show(item).render().hide(item);
|
|
63
|
+
let itemHeight = getRect(item).height;
|
|
64
|
+
item.style({visibility: '', height: px(itemHeight)})
|
|
65
|
+
shortestSection.h += +itemHeight + gap;
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
this.style({ height: px(getColumnByHeight(-1).h) });
|
|
69
|
+
this.dispatchEvent(new Event('layout'))
|
|
70
|
+
return this;
|
|
71
|
+
}
|
|
72
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "amateras",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Amateras is a DOM Utility library.",
|
|
5
5
|
"module": "index.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -33,9 +33,15 @@
|
|
|
33
33
|
"./css": "./ext/css/src/index.ts",
|
|
34
34
|
"./css/colors": "./ext/css/src/lib/colors.ts",
|
|
35
35
|
"./css/color/*": "./ext/css/src/lib/colors/*.ts",
|
|
36
|
-
"./router": "./ext/router/index.ts",
|
|
36
|
+
"./router": "./ext/router/src/index.ts",
|
|
37
37
|
"./ssr": "./ext/ssr/index.ts",
|
|
38
|
-
"./i18n": "./ext/i18n/src/index.ts"
|
|
38
|
+
"./i18n": "./ext/i18n/src/index.ts",
|
|
39
|
+
"./idb": "./ext/idb/src/index.ts",
|
|
40
|
+
"./idb/core": "./ext/idb/src/core.ts",
|
|
41
|
+
"./markdown": "./ext/markdown/src/index.ts",
|
|
42
|
+
"./markdown/syntax/*": "./ext/markdown/src/syntax/*.ts",
|
|
43
|
+
"./signal": "./ext/signal/src/index.ts",
|
|
44
|
+
"./ui/*": "./ext/ui/*.ts"
|
|
39
45
|
},
|
|
40
46
|
"workspaces": [
|
|
41
47
|
"./ext/*"
|
package/src/core.ts
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
import './global';
|
|
2
2
|
import './node';
|
|
3
|
-
import {
|
|
4
|
-
import { $Element, type $Event } from "#node/$Element";
|
|
3
|
+
import { $Element } from "#node/$Element";
|
|
5
4
|
import { $Node, type $NodeContentResolver, type $NodeContentTypes } from '#node/$Node';
|
|
6
5
|
import { _instanceof, isString, isFunction, _Object_assign, isObject, isNull, _Object_entries, _Object_defineProperty, forEach, isNumber, _Array_from, isUndefined, _bind, _null } from '#lib/native';
|
|
7
6
|
import { $HTMLElement } from '#node/$HTMLElement';
|
|
8
7
|
import { _document } from '#lib/env';
|
|
8
|
+
import { $EventTarget, type $Event } from '#node/$EventTarget';
|
|
9
9
|
|
|
10
|
-
const nodeNameMap: {[key: string]: Constructor<$
|
|
10
|
+
const nodeNameMap: {[key: string]: Constructor<$EventTarget>} = {}
|
|
11
11
|
const _stylesheet = new CSSStyleSheet();
|
|
12
12
|
|
|
13
|
-
export function $<
|
|
13
|
+
export function $<K extends keyof $.$NodeMap, T extends $.$NodeMap[K]>(tagname: K, ...args: ConstructorParameters<T>): InstanceType<T>;
|
|
14
|
+
export function $<K extends keyof HTMLElementTagNameMap>(tagname: K): $HTMLElement<HTMLElementTagNameMap[K]>;
|
|
15
|
+
export function $(tagname: string): $HTMLElement<HTMLElement>
|
|
14
16
|
export function $<F extends (...args: any[]) => $NodeContentResolver<$Node>>(fn: F, ...args: Parameters<F>): ReturnType<F>;
|
|
15
17
|
export function $<T extends Constructor<$Node>, P extends ConstructorParameters<T>, N extends number>(number: N, construct: T, ...args: P): Repeat<InstanceType<T>, N>;
|
|
16
18
|
export function $<T extends Constructor<$Node>, P extends ConstructorParameters<T>>(construct: T, ...args: P): InstanceType<T>;
|
|
19
|
+
export function $(nodes: NodeListOf<HTMLElement>): $HTMLElement[];
|
|
20
|
+
export function $(nodes: NodeListOf<Element>): $Element[];
|
|
17
21
|
export function $(nodes: NodeListOf<Node | ChildNode>): $Node[];
|
|
18
22
|
export function $<N extends $Node>($node: N, ...args: any[]): N;
|
|
19
23
|
export function $<N extends $Node>($node: N | null | undefined, ...args: any[]): N | null | undefined;
|
|
@@ -21,14 +25,17 @@ export function $<H extends HTMLElement>(element: H, ...args: any[]): $HTMLEleme
|
|
|
21
25
|
export function $<H extends HTMLElement>(element: H | null | undefined, ...args: any[]): $HTMLElement<H> | null | undefined;
|
|
22
26
|
export function $<E extends Element>(element: E, ...args: any[]): $Element<E>;
|
|
23
27
|
export function $<E extends Element>(element: E | null | undefined, ...args: any[]): $Element<E> | null | undefined;
|
|
24
|
-
export function $<
|
|
25
|
-
export function $<N extends Node
|
|
28
|
+
export function $<D extends Document>(node: D): $Node<DocumentEventMap>;
|
|
29
|
+
export function $<N extends Node>(node: N, ...args: any[]): $Node;
|
|
30
|
+
export function $<N extends Node>(node: N | null | undefined, ...args: any[]): $Node | null | undefined;
|
|
31
|
+
export function $<W extends Window>(node: W): $EventTarget<WindowEventMap>;
|
|
32
|
+
export function $<E extends EventTarget>(node: E, ...args: any[]): $EventTarget;
|
|
33
|
+
export function $<E extends EventTarget>(node: E | null | undefined, ...args: any[]): $EventTarget | null | undefined;
|
|
26
34
|
export function $<K extends TemplateStringsArray>(string: K, ...values: any[]): $NodeContentTypes[];
|
|
27
|
-
export function $<K extends keyof HTMLElementTagNameMap, N extends number>(number: N, tagname: K): Repeat<$HTMLElement<HTMLElementTagNameMap[K]>, N>;
|
|
28
|
-
export function $<K extends keyof HTMLElementTagNameMap>(tagname: K): $HTMLElement<HTMLElementTagNameMap[K]>;
|
|
29
35
|
export function $<Ev extends $Event<$Element, Event>>(event: Ev): Ev['currentTarget']['$'];
|
|
30
36
|
export function $<N extends number>(number: N, tagname: string): Repeat<$HTMLElement<HTMLElement>, N>;
|
|
31
|
-
export function
|
|
37
|
+
export function $<N extends number, K extends keyof HTMLElementTagNameMap>(number: N, tagname: K): Repeat<$HTMLElement<HTMLElementTagNameMap[K]>, N>;
|
|
38
|
+
export function $<N extends number, F extends (...args: any[]) => $NodeContentResolver<$Node>>(number: N, fn: F, ...args: Parameters<F>): Repeat<ReturnType<F>, N>;
|
|
32
39
|
export function $(resolver: string | number | null | undefined | Element | HTMLElement | $Node | Function | TemplateStringsArray | Event | NodeListOf<Node | ChildNode>, ...args: any[]) {
|
|
33
40
|
if (isNull(resolver) || isUndefined(resolver)) return null;
|
|
34
41
|
if (_instanceof(resolver, $Node)) return resolver;
|
|
@@ -45,68 +52,33 @@ export function $(resolver: string | number | null | undefined | Element | HTMLE
|
|
|
45
52
|
if (isNumber(resolver)) return _Array_from({length: resolver}).map(_ => $(args[0], ...args.slice(1)));
|
|
46
53
|
if (_instanceof(resolver, HTMLElement)) return new $HTMLElement(resolver);
|
|
47
54
|
if (_instanceof(resolver, Element)) return new $Element(resolver);
|
|
48
|
-
if (_instanceof(resolver,
|
|
55
|
+
if (_instanceof(resolver, Node)) return new $Node(resolver as any);
|
|
56
|
+
if (_instanceof(resolver, EventTarget)) return new $EventTarget(resolver as any);
|
|
57
|
+
if (_instanceof(resolver, NodeList)) return _Array_from(resolver).map($);
|
|
49
58
|
return new $HTMLElement(resolver);
|
|
50
59
|
}
|
|
51
60
|
|
|
52
61
|
export namespace $ {
|
|
62
|
+
// css
|
|
53
63
|
export const stylesheet = _stylesheet;
|
|
54
64
|
_document.adoptedStyleSheets.push(_stylesheet);
|
|
55
65
|
export const style = _bind(_stylesheet.insertRule, _stylesheet);
|
|
56
|
-
|
|
57
|
-
export
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
})
|
|
65
|
-
if (isObject(value) && !isNull(value)) {
|
|
66
|
-
for (const [key, val] of _Object_entries(value)) {
|
|
67
|
-
const val$ = $.signal(val);
|
|
68
|
-
val$.signal.subscribe(newValue => { value[key as keyof typeof value] = newValue; signal.emit() });
|
|
69
|
-
_Object_defineProperty(signalFn, `${key}$`, {value: val$});
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
return signalFn as unknown as SignalFunction<T>
|
|
73
|
-
}
|
|
66
|
+
// node map
|
|
67
|
+
export interface $NodeMap {}
|
|
68
|
+
// node content amp
|
|
69
|
+
export interface $NodeContentMap {}
|
|
70
|
+
export type $NodeContentTypeExtends = $NodeContentMap[keyof $NodeContentMap]
|
|
71
|
+
// attr value map
|
|
72
|
+
export interface $NodeParameterMap<T> {}
|
|
73
|
+
export type $NodeParameterExtends<T> = $NodeParameterMap<T>[keyof $NodeParameterMap<T>]
|
|
74
74
|
|
|
75
|
-
export
|
|
76
|
-
|
|
77
|
-
let subscribed = false;
|
|
78
|
-
const signalFn: SignalFunction<any> = signal(_null);
|
|
79
|
-
const computeFn = () => {
|
|
80
|
-
if (!subscribed) return signalFn.set(subscribe())();
|
|
81
|
-
else return signalFn.set(process())();
|
|
82
|
-
}
|
|
83
|
-
const subscribe = () => {
|
|
84
|
-
const signalHandler = (signal: Signal<any>) => {
|
|
85
|
-
signal.subscribe(() => signalFn.set(process()))
|
|
86
|
-
}
|
|
87
|
-
Signal.listeners.add(signalHandler);
|
|
88
|
-
const result = process();
|
|
89
|
-
Signal.listeners.delete(signalHandler);
|
|
90
|
-
subscribed = true;
|
|
91
|
-
return result;
|
|
92
|
-
}
|
|
93
|
-
_Object_assign(computeFn, { signal: signalFn.signal });
|
|
94
|
-
return computeFn as ComputeFunction<T>
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
type assign = {
|
|
98
|
-
(resolver: [nodeName: string, $node: Constructor<$Node>][]): $;
|
|
99
|
-
(nodeName: string, $node: Constructor<$Node>): $;
|
|
100
|
-
}
|
|
101
|
-
export const assign: assign = (resolver: string | [nodeName: string, $node: Constructor<$Node>][], $node?: Constructor<$Node>) => {
|
|
102
|
-
if (isString(resolver)) $node && (nodeNameMap[resolver] = $node);
|
|
103
|
-
else forEach(resolver, ([nodeName, $node]) => nodeNameMap[nodeName] = $node);
|
|
75
|
+
export const assign = (...resolver: [nodeName: string, $node: Constructor<$EventTarget>][]) => {
|
|
76
|
+
forEach(resolver, ([nodeName, $node]) => nodeNameMap[nodeName] = $node);
|
|
104
77
|
return $;
|
|
105
78
|
}
|
|
106
79
|
|
|
107
|
-
export const toArray = <T>(item: OrArray<T>): T[] => _instanceof(item, Array) ? item : [item];
|
|
108
|
-
|
|
109
80
|
export const span = (content: string) => $('span').content(content);
|
|
110
81
|
}
|
|
82
|
+
|
|
111
83
|
export type $ = typeof $;
|
|
112
84
|
globalThis.$ = $;
|