amateras 0.5.0 → 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 +23 -26
- package/ext/html/node/$Anchor.ts +2 -2
- 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 +2 -2
- package/ext/html/node/$Label.ts +2 -2
- 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/I18nTranslation.ts +35 -0
- package/ext/idb/src/structure/builder/$IDBBuilder.ts +8 -8
- package/ext/markdown/README.md +53 -0
- package/ext/markdown/package.json +7 -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/{node → src/node}/RouterAnchor.ts +13 -2
- 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 +6 -10
- 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 +6 -3
- package/src/core.ts +30 -60
- package/src/global.ts +9 -2
- package/src/index.ts +1 -2
- package/src/lib/assignProperties.ts +57 -0
- package/src/lib/native.ts +25 -8
- package/src/lib/uppercase.ts +3 -0
- package/src/node/$Element.ts +7 -41
- package/src/node/$EventTarget.ts +45 -0
- package/src/node/$Node.ts +60 -65
- package/src/node/$Virtual.ts +65 -0
- package/src/node.ts +7 -6
- package/ext/i18n/src/node/I18nText.ts +0 -35
- package/ext/markdown/index.ts +0 -121
- 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/src/lib/assign.ts +0 -38
- package/src/lib/assignHelper.ts +0 -18
|
@@ -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,12 +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
38
|
"./i18n": "./ext/i18n/src/index.ts",
|
|
39
39
|
"./idb": "./ext/idb/src/index.ts",
|
|
40
40
|
"./idb/core": "./ext/idb/src/core.ts",
|
|
41
|
-
"./markdown": "./ext/markdown/index.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"
|
|
42
45
|
},
|
|
43
46
|
"workspaces": [
|
|
44
47
|
"./ext/*"
|
package/src/core.ts
CHANGED
|
@@ -1,20 +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';
|
|
9
|
-
import {
|
|
8
|
+
import { $EventTarget, type $Event } from '#node/$EventTarget';
|
|
10
9
|
|
|
11
|
-
const nodeNameMap: {[key: string]: Constructor<$
|
|
10
|
+
const nodeNameMap: {[key: string]: Constructor<$EventTarget>} = {}
|
|
12
11
|
const _stylesheet = new CSSStyleSheet();
|
|
13
12
|
|
|
14
|
-
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>
|
|
15
16
|
export function $<F extends (...args: any[]) => $NodeContentResolver<$Node>>(fn: F, ...args: Parameters<F>): ReturnType<F>;
|
|
16
17
|
export function $<T extends Constructor<$Node>, P extends ConstructorParameters<T>, N extends number>(number: N, construct: T, ...args: P): Repeat<InstanceType<T>, N>;
|
|
17
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[];
|
|
18
21
|
export function $(nodes: NodeListOf<Node | ChildNode>): $Node[];
|
|
19
22
|
export function $<N extends $Node>($node: N, ...args: any[]): N;
|
|
20
23
|
export function $<N extends $Node>($node: N | null | undefined, ...args: any[]): N | null | undefined;
|
|
@@ -22,14 +25,17 @@ export function $<H extends HTMLElement>(element: H, ...args: any[]): $HTMLEleme
|
|
|
22
25
|
export function $<H extends HTMLElement>(element: H | null | undefined, ...args: any[]): $HTMLElement<H> | null | undefined;
|
|
23
26
|
export function $<E extends Element>(element: E, ...args: any[]): $Element<E>;
|
|
24
27
|
export function $<E extends Element>(element: E | null | undefined, ...args: any[]): $Element<E> | null | undefined;
|
|
25
|
-
export function $<
|
|
26
|
-
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;
|
|
27
34
|
export function $<K extends TemplateStringsArray>(string: K, ...values: any[]): $NodeContentTypes[];
|
|
28
|
-
export function $<K extends keyof HTMLElementTagNameMap, N extends number>(number: N, tagname: K): Repeat<$HTMLElement<HTMLElementTagNameMap[K]>, N>;
|
|
29
|
-
export function $<K extends keyof HTMLElementTagNameMap>(tagname: K): $HTMLElement<HTMLElementTagNameMap[K]>;
|
|
30
35
|
export function $<Ev extends $Event<$Element, Event>>(event: Ev): Ev['currentTarget']['$'];
|
|
31
36
|
export function $<N extends number>(number: N, tagname: string): Repeat<$HTMLElement<HTMLElement>, N>;
|
|
32
|
-
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>;
|
|
33
39
|
export function $(resolver: string | number | null | undefined | Element | HTMLElement | $Node | Function | TemplateStringsArray | Event | NodeListOf<Node | ChildNode>, ...args: any[]) {
|
|
34
40
|
if (isNull(resolver) || isUndefined(resolver)) return null;
|
|
35
41
|
if (_instanceof(resolver, $Node)) return resolver;
|
|
@@ -47,62 +53,27 @@ export function $(resolver: string | number | null | undefined | Element | HTMLE
|
|
|
47
53
|
if (_instanceof(resolver, HTMLElement)) return new $HTMLElement(resolver);
|
|
48
54
|
if (_instanceof(resolver, Element)) return new $Element(resolver);
|
|
49
55
|
if (_instanceof(resolver, Node)) return new $Node(resolver as any);
|
|
50
|
-
if (_instanceof(resolver,
|
|
56
|
+
if (_instanceof(resolver, EventTarget)) return new $EventTarget(resolver as any);
|
|
57
|
+
if (_instanceof(resolver, NodeList)) return _Array_from(resolver).map($);
|
|
51
58
|
return new $HTMLElement(resolver);
|
|
52
59
|
}
|
|
53
60
|
|
|
54
61
|
export namespace $ {
|
|
62
|
+
// css
|
|
55
63
|
export const stylesheet = _stylesheet;
|
|
56
64
|
_document.adoptedStyleSheets.push(_stylesheet);
|
|
57
65
|
export const style = _bind(_stylesheet.insertRule, _stylesheet);
|
|
58
|
-
|
|
59
|
-
export
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
})
|
|
67
|
-
if (isObject(value) && !isNull(value)) {
|
|
68
|
-
for (const [key, val] of _Object_entries(value)) {
|
|
69
|
-
const val$ = $.signal(val);
|
|
70
|
-
val$.signal.subscribe(newValue => { value[key as keyof typeof value] = newValue; signal.emit() });
|
|
71
|
-
_Object_defineProperty(signalFn, `${key}$`, {value: val$});
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
return signalFn as unknown as SignalFunction<T>
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export type ComputeFunction<T> = ({(): T}) & { signal: Signal<T> };
|
|
78
|
-
export const compute = <T>(process: () => T): ComputeFunction<T> => {
|
|
79
|
-
let subscribed = false;
|
|
80
|
-
const signalFn: SignalFunction<any> = signal(_null);
|
|
81
|
-
const computeFn = () => {
|
|
82
|
-
if (!subscribed) return signalFn.set(subscribe())();
|
|
83
|
-
else return signalFn.set(process())();
|
|
84
|
-
}
|
|
85
|
-
const subscribe = () => {
|
|
86
|
-
const signalHandler = (signal: Signal<any>) => {
|
|
87
|
-
signal.subscribe(() => signalFn.set(process()))
|
|
88
|
-
}
|
|
89
|
-
Signal.listeners.add(signalHandler);
|
|
90
|
-
const result = process();
|
|
91
|
-
Signal.listeners.delete(signalHandler);
|
|
92
|
-
subscribed = true;
|
|
93
|
-
return result;
|
|
94
|
-
}
|
|
95
|
-
_Object_assign(computeFn, { signal: signalFn.signal });
|
|
96
|
-
return computeFn as ComputeFunction<T>
|
|
97
|
-
}
|
|
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>]
|
|
98
74
|
|
|
99
|
-
|
|
100
|
-
(resolver
|
|
101
|
-
(nodeName: string, $node: Constructor<$Node>): $;
|
|
102
|
-
}
|
|
103
|
-
export const assign: assign = (resolver: string | [nodeName: string, $node: Constructor<$Node>][], $node?: Constructor<$Node>) => {
|
|
104
|
-
if (isString(resolver)) $node && (nodeNameMap[resolver] = $node);
|
|
105
|
-
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);
|
|
106
77
|
return $;
|
|
107
78
|
}
|
|
108
79
|
|
|
@@ -110,5 +81,4 @@ export namespace $ {
|
|
|
110
81
|
}
|
|
111
82
|
|
|
112
83
|
export type $ = typeof $;
|
|
113
|
-
globalThis.$ = $;
|
|
114
|
-
_Object_assign($, {toArray})
|
|
84
|
+
globalThis.$ = $;
|
package/src/global.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { $Element } from '#node/$Element';
|
|
2
2
|
import type { $Node } from '#node/$Node';
|
|
3
3
|
import * as core from '#core';
|
|
4
|
-
import type {
|
|
4
|
+
import type { $EventTarget } from '#node/$EventTarget';
|
|
5
5
|
|
|
6
6
|
declare global {
|
|
7
7
|
export import $ = core.$;
|
|
@@ -11,7 +11,11 @@ declare global {
|
|
|
11
11
|
type OrPromise<T> = T | Promise<T>;
|
|
12
12
|
type OrNullish<T> = T | Nullish;
|
|
13
13
|
type Constructor<T> = { new (...args: any[]): T }
|
|
14
|
-
type
|
|
14
|
+
type Mutable<T> = {
|
|
15
|
+
-readonly [P in keyof T]: T[P];
|
|
16
|
+
}
|
|
17
|
+
type AsyncFunction<T> = () => Promise<T>;
|
|
18
|
+
type $Parameter<T> = T | undefined | $.$NodeParameterExtends<T>
|
|
15
19
|
type Ok<D> = [data: D, err: null];
|
|
16
20
|
type Err<E> = [data: null, err: E]
|
|
17
21
|
type Result<D, E> = Ok<D> | Err<E>
|
|
@@ -25,6 +29,9 @@ declare global {
|
|
|
25
29
|
interface Node {
|
|
26
30
|
readonly $: $Node
|
|
27
31
|
}
|
|
32
|
+
interface EventTarget {
|
|
33
|
+
readonly $: $EventTarget
|
|
34
|
+
}
|
|
28
35
|
interface Element {
|
|
29
36
|
readonly $: $Element
|
|
30
37
|
}
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { $EventTarget } from "#node/$EventTarget";
|
|
2
|
+
import { $Node } from "#node/$Node";
|
|
3
|
+
import { _instanceof, _null, _Object_defineProperty, _Object_entries, _Object_getOwnPropertyDescriptors, forEach, isUndefined } from "./native";
|
|
4
|
+
|
|
5
|
+
const assigner = (target: any, {set, get, fn}: {
|
|
6
|
+
set?: string[],
|
|
7
|
+
get?: string[],
|
|
8
|
+
fn?: string[]
|
|
9
|
+
}) => {
|
|
10
|
+
const [GET, SET, FN] = ['get', 'set', 'fn'] as const;
|
|
11
|
+
const filterAndMap = (type: 'get' | 'set' | 'fn', arr: string[] | undefined) => arr?.map(prop => [type, prop]) ?? []
|
|
12
|
+
const list = [...filterAndMap(GET, get), ...filterAndMap(SET, set), ...filterAndMap(FN, fn)] as [string, string][];
|
|
13
|
+
forEach(list, ([type, prop]) =>
|
|
14
|
+
_Object_defineProperty(target.prototype, prop, {
|
|
15
|
+
...(type === GET ? {
|
|
16
|
+
get() { return this.node[prop as any] }
|
|
17
|
+
} : {
|
|
18
|
+
writable: true,
|
|
19
|
+
...(type === SET ? {
|
|
20
|
+
// set
|
|
21
|
+
value(this, args: any) {
|
|
22
|
+
if (!arguments.length) return this.node[prop];
|
|
23
|
+
let set = (value: any) => !isUndefined(value) && (this.node[prop] = value);
|
|
24
|
+
for (const setter of $Node.setters) {
|
|
25
|
+
const result = setter(args, set);
|
|
26
|
+
if (!isUndefined(result)) return set(result), this;
|
|
27
|
+
}
|
|
28
|
+
set(args)
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
} : {
|
|
32
|
+
// fn
|
|
33
|
+
value(this, ...args : any[]) {
|
|
34
|
+
let result = this.node[prop](...args.map(value => _instanceof(value, $Node) ? value.node : value ?? _null))
|
|
35
|
+
return isUndefined(result) ? this : result;
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
}),
|
|
39
|
+
|
|
40
|
+
})
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const assignProperties = (object: Constructor<EventTarget>, target: Constructor<$EventTarget>, tagname?: string) => {
|
|
45
|
+
const [set, get, fn] = [[], [], []] as [string[], string[], string[]]
|
|
46
|
+
// assign native object properties to target
|
|
47
|
+
forEach(_Object_entries(_Object_getOwnPropertyDescriptors(object.prototype)), ([prop, value]) => {
|
|
48
|
+
if (!(prop in target.prototype)) {
|
|
49
|
+
if (value.get && !value.set) get.push(prop);
|
|
50
|
+
else if (value.value) fn.push(prop);
|
|
51
|
+
else if (value.get && value.set) set.push(prop);
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
assigner(target, {set, get, fn})
|
|
55
|
+
// register tagname
|
|
56
|
+
if (tagname) $.assign([tagname, target])
|
|
57
|
+
}
|
package/src/lib/native.ts
CHANGED
|
@@ -10,7 +10,23 @@ export const _Object_defineProperty = Object.defineProperty;
|
|
|
10
10
|
export const _Object_getOwnPropertyDescriptors = Object.getOwnPropertyDescriptors;
|
|
11
11
|
// Array
|
|
12
12
|
export const _Array_from = Array.from;
|
|
13
|
-
|
|
13
|
+
interface forEach {
|
|
14
|
+
<T>(arr: Array<T>, fn: (value: T, index: number, array: Array<T>) => Promise<void>): Promise<void>;
|
|
15
|
+
<T>(arr: Array<T>, fn: (value: T, index: number, array: Array<T>) => void): void;
|
|
16
|
+
<T>(set: Set<T>, fn: (value: T, index: number, set: Set<T>) => Promise<void>): void;
|
|
17
|
+
<T>(set: Set<T>, fn: (value: T, index: number, set: Set<T>) => void): void;
|
|
18
|
+
<K, V>(map: Map<K, V>, fn: (value: [K, V], index: number, map: Map<K, V>) => Promise<void>): void;
|
|
19
|
+
<K, V>(map: Map<K, V>, fn: (value: [K, V], index: number, map: Map<K, V>) => void): void;
|
|
20
|
+
<N extends Node>(set: NodeListOf<N>, fn: (value: N, index: number, parent: NodeListOf<N>) => Promise<void>): void;
|
|
21
|
+
<N extends Node>(set: NodeListOf<N>, fn: (value: N, index: number, parent: NodeListOf<N>) => void): void;
|
|
22
|
+
}
|
|
23
|
+
export const forEach: forEach = async (arr: any, fn: any) => {
|
|
24
|
+
let i = 0;
|
|
25
|
+
let isAsync = isAsyncFunction(fn);
|
|
26
|
+
let handle = async () => { for (let item of arr) { isAsync ? await fn(item, i, arr) : fn(item, i, arr); i++; } }
|
|
27
|
+
return isAsync ? new _Promise<void>(resolve => handle().then(resolve)) : handle();
|
|
28
|
+
};
|
|
29
|
+
// export const forEach: forEach = (arr: any, fn: any) => arr.forEach(fn);
|
|
14
30
|
// type check
|
|
15
31
|
export const _typeof = (target: any, type: 'string' | 'number' | 'object' | 'boolean' | 'function' | 'bigint' | 'symbol' | 'undefined') => typeof target === type;
|
|
16
32
|
export const equal = <T, V extends T>(target: T, ...args: V[]): target is V => !!args.find(a => a === target);
|
|
@@ -19,6 +35,7 @@ export const isBoolean = (target: any): target is boolean => _typeof(target, 'bo
|
|
|
19
35
|
export const isNumber = (target: any): target is number => _typeof(target, 'number');
|
|
20
36
|
export const isObject = (target: any): target is object => _typeof(target, 'object');
|
|
21
37
|
export const isFunction = (target: any): target is Function => _typeof(target, 'function');
|
|
38
|
+
export const isAsyncFunction = (target: any): target is AsyncFunction<Awaited<ReturnType<typeof target>>> => _instanceof(target, (async () => 0).constructor as any)
|
|
22
39
|
export const isUndefined = (target: any): target is undefined => target === undefined;
|
|
23
40
|
export const isNull = (target: any): target is null => target === _null;
|
|
24
41
|
export const isArray = Array.isArray;
|
|
@@ -28,13 +45,13 @@ export const _JSON_stringify = JSON.stringify;
|
|
|
28
45
|
export const _JSON_parse = JSON.parse;
|
|
29
46
|
// String
|
|
30
47
|
export const startsWith = (target: string, ...str: string[]) => !!str.find(s => target.startsWith(s));
|
|
31
|
-
//
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
<T>(
|
|
35
|
-
<T>(set: Set<T>, fn: (value: T, index: number, set: Set<T>) => any, thisArgs?: any): void;
|
|
36
|
-
<K, V>(set: Map<K, V>, fn: (value: V, key: K, index: number, map: Map<K, V>) => any, thisArgs?: any): void;
|
|
37
|
-
<N extends Node>(set: NodeListOf<N>, fn: (value: N, index: number, parent: NodeListOf<N>) => any, thisArgs?: any): void;
|
|
48
|
+
// String & Array
|
|
49
|
+
interface slice {
|
|
50
|
+
(target: string, start?: number, end?: number): string;
|
|
51
|
+
<T>(target: Array<T>, start?: number, end?: number): T[];
|
|
38
52
|
}
|
|
53
|
+
export const slice: slice = (target: any, start?: number, end?: number) => target.slice(start, end);
|
|
54
|
+
// Function
|
|
55
|
+
export const _bind = <T extends Function>(target: T, obj: Object): T => target.bind(obj);
|
|
39
56
|
// Promise
|
|
40
57
|
export const _Promise = Promise;
|
package/src/node/$Element.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { Signal } from "#structure/Signal";
|
|
2
|
-
import { $Node } from "#node/$Node";
|
|
3
1
|
import { _Array_from, _instanceof, _Object_assign, _Object_entries, _Object_fromEntries, isNull, isString, isUndefined } from "#lib/native";
|
|
4
2
|
import { _document } from "#lib/env";
|
|
3
|
+
import { $Node } from "./$Node";
|
|
5
4
|
|
|
6
|
-
export class $Element<Ele extends Element = Element, EvMap = ElementEventMap> extends $Node {
|
|
5
|
+
export class $Element<Ele extends Element = Element, EvMap = ElementEventMap> extends $Node<EvMap> {
|
|
7
6
|
declare node: Ele
|
|
8
7
|
constructor(resolver: Ele | string) {
|
|
9
8
|
super(_instanceof(resolver, Element) ? resolver : createNode(resolver) as unknown as Ele)
|
|
@@ -13,14 +12,13 @@ export class $Element<Ele extends Element = Element, EvMap = ElementEventMap> ex
|
|
|
13
12
|
|
|
14
13
|
attr(): {[key: string]: string};
|
|
15
14
|
attr(key: string): string | null;
|
|
16
|
-
attr(obj: {[key: string]: string | number | boolean |
|
|
17
|
-
attr(resolver?: {[key: string]: string | number | boolean |
|
|
15
|
+
attr(obj: {[key: string]: string | number | boolean | null | undefined}): this;
|
|
16
|
+
attr(resolver?: {[key: string]: string | number | boolean | null | undefined} | string) {
|
|
18
17
|
if (!arguments.length) return _Object_fromEntries(_Array_from(this.attributes).map(attr => [attr.name, attr.value]));
|
|
19
18
|
if (isString(resolver)) return this.getAttribute(resolver);
|
|
20
19
|
if (resolver) for (let [key, value] of _Object_entries(resolver)) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
set(value);
|
|
20
|
+
if (!isUndefined(value) && isNull(value)) this.removeAttribute(key);
|
|
21
|
+
else this.setAttribute(key, `${value}`);
|
|
24
22
|
}
|
|
25
23
|
return this;
|
|
26
24
|
}
|
|
@@ -44,10 +42,6 @@ export class $Element<Ele extends Element = Element, EvMap = ElementEventMap> ex
|
|
|
44
42
|
}
|
|
45
43
|
}
|
|
46
44
|
|
|
47
|
-
export type $Event<E extends $Element, Ev = any> = Ev & {currentTarget: {$: E}};
|
|
48
|
-
export type $EventListener<E extends $Element, Ev> = (event: $Event<E, Ev>) => void;
|
|
49
|
-
export type $EventListenerObject<E extends $Element, Ev> = { handleEvent(object: $Event<E, Ev>): void; }
|
|
50
|
-
|
|
51
45
|
function createNode(nodeName: string) {
|
|
52
46
|
return !_document
|
|
53
47
|
//@ts-expect-error
|
|
@@ -55,7 +49,7 @@ function createNode(nodeName: string) {
|
|
|
55
49
|
: _document.createElement(nodeName);
|
|
56
50
|
}
|
|
57
51
|
|
|
58
|
-
export interface $Element<Ele extends Element, EvMap> {
|
|
52
|
+
export interface $Element<Ele extends Element, EvMap = ElementEventMap> {
|
|
59
53
|
/** {@link Element.attributes} */
|
|
60
54
|
readonly attributes: NamedNodeMap;
|
|
61
55
|
/** {@link Element.clientHeight} */
|
|
@@ -195,20 +189,6 @@ export interface $Element<Ele extends Element, EvMap> {
|
|
|
195
189
|
animate(keyframes: Keyframe[] | PropertyIndexedKeyframes | null, options?: number | KeyframeAnimationOptions): Animation;
|
|
196
190
|
/** {@link Element.getAnimations} */
|
|
197
191
|
getAnimations(options?: GetAnimationsOptions): Animation[];
|
|
198
|
-
/** {@link Element.append} */
|
|
199
|
-
append(...nodes: (Node | string)[]): this;
|
|
200
|
-
/** {@link Element.prepend} */
|
|
201
|
-
prepend(...nodes: (Node | string)[]): this;
|
|
202
|
-
/** {@link Element.querySelector} */
|
|
203
|
-
querySelector<K extends keyof HTMLElementTagNameMap>(selectors: K): HTMLElementTagNameMap[K] | null;
|
|
204
|
-
querySelector<K extends keyof SVGElementTagNameMap>(selectors: K): SVGElementTagNameMap[K] | null;
|
|
205
|
-
querySelector<K extends keyof MathMLElementTagNameMap>(selectors: K): MathMLElementTagNameMap[K] | null;
|
|
206
|
-
/** {@link Element.querySelectorAll} */
|
|
207
|
-
querySelectorAll<K extends keyof HTMLElementTagNameMap>(selectors: K): NodeListOf<HTMLElementTagNameMap[K]>;
|
|
208
|
-
querySelectorAll<K extends keyof SVGElementTagNameMap>(selectors: K): NodeListOf<SVGElementTagNameMap[K]>;
|
|
209
|
-
querySelectorAll<K extends keyof MathMLElementTagNameMap>(selectors: K): NodeListOf<MathMLElementTagNameMap[K]>;
|
|
210
|
-
/** {@link Element.replaceChildren} */
|
|
211
|
-
replaceChildren(...nodes: (Node | string)[]): this;
|
|
212
192
|
|
|
213
193
|
/** {@link Element.classList} */
|
|
214
194
|
classList(): DOMTokenList;
|
|
@@ -371,18 +351,4 @@ export interface $Element<Ele extends Element, EvMap> {
|
|
|
371
351
|
/** {@link ARIAMixin.role} */
|
|
372
352
|
role(): string | null;
|
|
373
353
|
role(role: $Parameter<string | null>): this;
|
|
374
|
-
addEventListener<K extends keyof EvMap, Ev extends EvMap[K]>(type: K, listener: $EventListener<this, Ev> | $EventListenerObject<this, Ev>, options?: boolean | AddEventListenerOptions): this;
|
|
375
|
-
addEventListener(type: string, listener: $EventListener<this, Event> | $EventListenerObject<this, Event>, options?: boolean | AddEventListenerOptions): this;
|
|
376
|
-
removeEventListener<K extends keyof EvMap, Ev extends EvMap[K]>(type: K, listener: $EventListener<this, Ev> | $EventListenerObject<this, Ev>, options?: boolean | EventListenerOptions): this;
|
|
377
|
-
removeEventListener(type: string, listener: $EventListener<this, Event> | $EventListenerObject<this, Event>, options?: boolean | EventListenerOptions): this;
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
on(type: string, listener: $EventListener<this, Event> | $EventListenerObject<this, Event>, options?: boolean | AddEventListenerOptions): this;
|
|
381
|
-
on<K extends keyof EvMap, Ev extends EvMap[K]>(type: K, listener: $EventListener<this, Ev> | $EventListenerObject<this, Ev>, options?: boolean | AddEventListenerOptions): this;
|
|
382
|
-
|
|
383
|
-
off(type: string, listener: $EventListener<this, Event> | $EventListenerObject<this, Event>, options?: boolean | EventListenerOptions): this;
|
|
384
|
-
off<K extends keyof EvMap, Ev extends EvMap[K]>(type: K, listener: $EventListener<this, Ev> | $EventListenerObject<this, Ev>, options?: boolean | EventListenerOptions): this;
|
|
385
|
-
|
|
386
|
-
once(type: string, listener: $EventListener<this, Event> | $EventListenerObject<this, Event>, options?: boolean | AddEventListenerOptions): this;
|
|
387
|
-
once<K extends keyof EvMap, Ev extends EvMap[K]>(type: K, listener: $EventListener<this, Ev> | $EventListenerObject<this, Ev>, options?: boolean | AddEventListenerOptions): this;
|
|
388
354
|
}
|