amateras 0.3.0 → 0.4.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 +6 -4
- package/ext/css/README.md +19 -0
- package/ext/css/src/index.ts +347 -331
- package/ext/css/src/lib/colorAssign.ts +1 -1
- package/ext/css/src/structure/$CSSContainerRule.ts +13 -0
- package/ext/css/src/structure/$CSSRule.ts +1 -1
- package/ext/css/src/structure/$CSSStyleRule.ts +0 -7
- package/ext/css/src/structure/$CSSVariable.ts +3 -3
- package/ext/html/html.ts +1 -13
- package/ext/i18n/README.md +53 -0
- package/ext/i18n/package.json +10 -0
- package/ext/i18n/src/index.ts +54 -0
- package/ext/i18n/src/node/I18nText.ts +35 -0
- package/ext/i18n/src/structure/I18n.ts +40 -0
- package/ext/i18n/src/structure/I18nDictionary.ts +31 -0
- package/ext/markdown/index.ts +123 -0
- package/ext/router/index.ts +8 -1
- package/ext/router/node/Page.ts +1 -0
- package/ext/router/node/Route.ts +2 -1
- package/ext/router/node/Router.ts +33 -22
- package/ext/ssr/index.ts +4 -2
- package/ext/ui/lib/VirtualScroll.ts +24 -0
- package/ext/ui/node/Accordian.ts +97 -0
- package/ext/ui/node/Tabs.ts +114 -0
- package/ext/ui/node/Toast.ts +16 -0
- package/ext/ui/node/Waterfall.ts +73 -0
- package/ext/ui/package.json +11 -0
- package/package.json +4 -7
- package/src/core.ts +21 -8
- package/src/lib/assign.ts +8 -9
- package/src/lib/assignHelper.ts +1 -1
- package/src/lib/chain.ts +3 -0
- package/src/lib/debounce.ts +7 -0
- package/src/lib/env.ts +2 -0
- package/src/lib/native.ts +22 -35
- package/src/lib/randomId.ts +1 -1
- package/src/lib/sleep.ts +1 -1
- package/src/node/$Element.ts +182 -20
- package/src/node/$HTMLElement.ts +24 -0
- package/src/node/$Node.ts +75 -52
- package/src/node/$Virtual.ts +58 -0
- package/src/{node/node.ts → node.ts} +2 -5
|
@@ -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,114 @@
|
|
|
1
|
+
import { _instanceof, 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) this.childNodes.forEach(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,73 @@
|
|
|
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.render();
|
|
69
|
+
this.style({ height: px(getColumnByHeight(-1).h) });
|
|
70
|
+
this.dispatchEvent(new Event('layout'))
|
|
71
|
+
return this;
|
|
72
|
+
}
|
|
73
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "amateras",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Amateras is a DOM Utility library.",
|
|
5
5
|
"module": "index.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -25,7 +25,6 @@
|
|
|
25
25
|
"exports": {
|
|
26
26
|
".": "./src/index.ts",
|
|
27
27
|
"./core": "./src/core.ts",
|
|
28
|
-
"./node": "./src/node/node.ts",
|
|
29
28
|
"./node/*": "./src/node/*.ts",
|
|
30
29
|
"./lib/*": "./src/lib/*.ts",
|
|
31
30
|
"./structure/*": "./src/structure/*.ts",
|
|
@@ -35,12 +34,10 @@
|
|
|
35
34
|
"./css/colors": "./ext/css/src/lib/colors.ts",
|
|
36
35
|
"./css/color/*": "./ext/css/src/lib/colors/*.ts",
|
|
37
36
|
"./router": "./ext/router/index.ts",
|
|
38
|
-
"./ssr": "./ext/ssr/index.ts"
|
|
37
|
+
"./ssr": "./ext/ssr/index.ts",
|
|
38
|
+
"./i18n": "./ext/i18n/src/index.ts"
|
|
39
39
|
},
|
|
40
40
|
"workspaces": [
|
|
41
41
|
"./ext/*"
|
|
42
|
-
]
|
|
43
|
-
"peerDependencies": {
|
|
44
|
-
"@amateras/css": "./ext/css"
|
|
45
|
-
}
|
|
42
|
+
]
|
|
46
43
|
}
|
package/src/core.ts
CHANGED
|
@@ -1,27 +1,36 @@
|
|
|
1
1
|
import './global';
|
|
2
|
+
import './node';
|
|
2
3
|
import { Signal } from "#structure/Signal";
|
|
3
4
|
import { $Element, type $Event } from "#node/$Element";
|
|
4
5
|
import { $Node, type $NodeContentResolver, type $NodeContentTypes } from '#node/$Node';
|
|
5
|
-
import '#
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
6
|
+
import { _instanceof, isString, isFunction, _Object_assign, isObject, isNull, _Object_entries, _Object_defineProperty, forEach, isNumber, _Array_from, isUndefined } from '#lib/native';
|
|
7
|
+
import { $HTMLElement } from '#node/$HTMLElement';
|
|
8
|
+
import { _document } from '#lib/env';
|
|
8
9
|
|
|
9
10
|
const nodeNameMap: {[key: string]: Constructor<$Node>} = {}
|
|
11
|
+
const _stylesheet = new CSSStyleSheet();
|
|
10
12
|
|
|
11
13
|
export function $<F extends (...args: any[]) => $NodeContentResolver<$Node>, N extends number>(number: N, fn: F, ...args: Parameters<F>): Repeat<ReturnType<F>, N>;
|
|
12
14
|
export function $<F extends (...args: any[]) => $NodeContentResolver<$Node>>(fn: F, ...args: Parameters<F>): ReturnType<F>;
|
|
13
15
|
export function $<T extends Constructor<$Node>, P extends ConstructorParameters<T>, N extends number>(number: N, construct: T, ...args: P): Repeat<InstanceType<T>, N>;
|
|
14
16
|
export function $<T extends Constructor<$Node>, P extends ConstructorParameters<T>>(construct: T, ...args: P): InstanceType<T>;
|
|
17
|
+
export function $(nodes: NodeListOf<Node | ChildNode>): $Node[];
|
|
15
18
|
export function $<N extends $Node>($node: N, ...args: any[]): N;
|
|
19
|
+
export function $<N extends $Node>($node: N | null | undefined, ...args: any[]): N | null | undefined;
|
|
16
20
|
export function $<H extends HTMLElement>(element: H, ...args: any[]): $HTMLElement<H>;
|
|
21
|
+
export function $<H extends HTMLElement>(element: H | null | undefined, ...args: any[]): $HTMLElement<H> | null | undefined;
|
|
17
22
|
export function $<E extends Element>(element: E, ...args: any[]): $Element<E>;
|
|
23
|
+
export function $<E extends Element>(element: E | null | undefined, ...args: any[]): $Element<E> | null | undefined;
|
|
24
|
+
export function $<N extends Node | EventTarget>(node: N, ...args: any[]): $Node;
|
|
25
|
+
export function $<N extends Node | EventTarget>(node: N | null | undefined, ...args: any[]): $Node | null | undefined;
|
|
18
26
|
export function $<K extends TemplateStringsArray>(string: K, ...values: any[]): $NodeContentTypes[];
|
|
19
27
|
export function $<K extends keyof HTMLElementTagNameMap, N extends number>(number: N, tagname: K): Repeat<$HTMLElement<HTMLElementTagNameMap[K]>, N>;
|
|
20
28
|
export function $<K extends keyof HTMLElementTagNameMap>(tagname: K): $HTMLElement<HTMLElementTagNameMap[K]>;
|
|
21
|
-
export function $<Ev extends $Event<$Element, Event>>(event: Ev): Ev['
|
|
29
|
+
export function $<Ev extends $Event<$Element, Event>>(event: Ev): Ev['currentTarget']['$'];
|
|
22
30
|
export function $<N extends number>(number: N, tagname: string): Repeat<$HTMLElement<HTMLElement>, N>;
|
|
23
31
|
export function $(tagname: string): $HTMLElement<HTMLElement>
|
|
24
|
-
export function $(resolver: string | number | Element | $Node | Function | TemplateStringsArray | Event
|
|
32
|
+
export function $(resolver: string | number | null | undefined | Element | HTMLElement | $Node | Function | TemplateStringsArray | Event | NodeListOf<Node | ChildNode>, ...args: any[]) {
|
|
33
|
+
if (isNull(resolver) || isUndefined(resolver)) return null;
|
|
25
34
|
if (_instanceof(resolver, $Node)) return resolver;
|
|
26
35
|
if (isString(resolver) && nodeNameMap[resolver]) return new nodeNameMap[resolver](...args);
|
|
27
36
|
if (isFunction(resolver))
|
|
@@ -34,12 +43,16 @@ export function $(resolver: string | number | Element | $Node | Function | Templ
|
|
|
34
43
|
if (_instanceof(resolver, Node) && _instanceof(resolver.$, $Node)) return resolver.$;
|
|
35
44
|
if (_instanceof(resolver, Event)) return $(resolver.currentTarget as Element);
|
|
36
45
|
if (isNumber(resolver)) return _Array_from({length: resolver}).map(_ => $(args[0], ...args.slice(1)));
|
|
37
|
-
return new $
|
|
46
|
+
if (_instanceof(resolver, HTMLElement)) return new $HTMLElement(resolver);
|
|
47
|
+
if (_instanceof(resolver, Element)) return new $Element(resolver);
|
|
48
|
+
if (_instanceof(resolver, NodeList)) return _Array_from(resolver).map($)
|
|
49
|
+
return new $HTMLElement(resolver);
|
|
38
50
|
}
|
|
39
51
|
|
|
40
52
|
export namespace $ {
|
|
41
|
-
export const stylesheet =
|
|
42
|
-
_document.adoptedStyleSheets.push(
|
|
53
|
+
export const stylesheet = _stylesheet;
|
|
54
|
+
_document.adoptedStyleSheets.push(_stylesheet);
|
|
55
|
+
export const style = _stylesheet.insertRule.bind(_stylesheet);
|
|
43
56
|
type SignalProcess<T> = T extends Array<any> ? {} : T extends object ? { [key in keyof T as `${string & key}$`]: SignalFunction<T[key]> } : {};
|
|
44
57
|
export type SignalFunction<T> = {signal: Signal<T>, set: (newValue: T | ((oldValue: T) => T)) => SignalFunction<T>} & (() => T) & SignalProcess<T>;
|
|
45
58
|
export function signal<T>(value: T): SignalFunction<T>
|
package/src/lib/assign.ts
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import { Signal } from "../structure/Signal";
|
|
2
2
|
import { _instanceof, _Object_defineProperty, isUndefined } from "./native";
|
|
3
3
|
|
|
4
|
-
export
|
|
4
|
+
export const assign = (target: any, {set, get, fn}: {
|
|
5
5
|
set?: string[],
|
|
6
6
|
get?: string[],
|
|
7
7
|
fn?: string[]
|
|
8
|
-
}) {
|
|
8
|
+
}) => {
|
|
9
9
|
const [GET, SET, FN] = ['get', 'set', 'fn'] as const;
|
|
10
|
-
const filterAndMap = (type: 'get' | 'set' | 'fn', arr: string[] | undefined) =>
|
|
11
|
-
return arr?.map(prop => [type, prop]) ?? []
|
|
12
|
-
}
|
|
10
|
+
const filterAndMap = (type: 'get' | 'set' | 'fn', arr: string[] | undefined) => arr?.map(prop => [type, prop]) ?? []
|
|
13
11
|
const list = [...filterAndMap(GET, get), ...filterAndMap(SET, set), ...filterAndMap(FN, fn)] as [string, string][];
|
|
14
12
|
for (const [type, prop] of list) {
|
|
15
13
|
_Object_defineProperty(target.prototype, prop, {
|
|
@@ -19,17 +17,18 @@ export function assign(target: any, {set, get, fn}: {
|
|
|
19
17
|
writable: true,
|
|
20
18
|
...(type === SET ? {
|
|
21
19
|
// set
|
|
22
|
-
value
|
|
20
|
+
value(this, args: any) {
|
|
23
21
|
if (!arguments.length) return this.node[prop];
|
|
24
|
-
|
|
22
|
+
let set = (value: any) => !isUndefined(value) && (this.node[prop] = value);
|
|
25
23
|
if (_instanceof(args, Signal)) args = args.subscribe(set).value();
|
|
26
24
|
set(args)
|
|
27
25
|
return this;
|
|
28
26
|
}
|
|
29
27
|
} : {
|
|
30
28
|
// fn
|
|
31
|
-
value
|
|
32
|
-
|
|
29
|
+
value(this, ...args : any[]) {
|
|
30
|
+
let result = this.node[prop](...args)
|
|
31
|
+
return isUndefined(result) ? this : result;
|
|
33
32
|
}
|
|
34
33
|
})
|
|
35
34
|
}),
|
package/src/lib/assignHelper.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { $Node } from "#node/$Node";
|
|
|
2
2
|
import { assign } from "./assign";
|
|
3
3
|
import { _Object_entries, _Object_getOwnPropertyDescriptors } from "./native";
|
|
4
4
|
|
|
5
|
-
export
|
|
5
|
+
export const assignHelper = (object: Constructor<EventTarget>, target: Constructor<$Node>, tagname?: string) => {
|
|
6
6
|
const [set, get, fn] = [[], [], []] as [string[], string[], string[]]
|
|
7
7
|
// assign native object properties to target
|
|
8
8
|
for (const [prop, value] of _Object_entries(_Object_getOwnPropertyDescriptors(object.prototype))) {
|
package/src/lib/chain.ts
ADDED
package/src/lib/env.ts
ADDED
package/src/lib/native.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
// document
|
|
2
|
-
export const _document = document;
|
|
3
1
|
// Object
|
|
4
2
|
export const _Object_fromEntries = Object.fromEntries;
|
|
5
3
|
export const _Object_entries = Object.entries;
|
|
@@ -9,37 +7,26 @@ export const _Object_defineProperty = Object.defineProperty;
|
|
|
9
7
|
export const _Object_getOwnPropertyDescriptors = Object.getOwnPropertyDescriptors;
|
|
10
8
|
// Array
|
|
11
9
|
export const _Array_from = Array.from;
|
|
12
|
-
export
|
|
13
|
-
|
|
14
|
-
export
|
|
15
|
-
export
|
|
16
|
-
export
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
export
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
export function isString(target: any): target is string {
|
|
24
|
-
return _typeof(target, 'string');
|
|
25
|
-
}
|
|
26
|
-
export function isNumber(target: any): target is number {
|
|
27
|
-
return _typeof(target, 'number')
|
|
28
|
-
}
|
|
29
|
-
export function isObject(target: any): target is object {
|
|
30
|
-
return _typeof(target, 'object')
|
|
31
|
-
}
|
|
32
|
-
export function isFunction(target: any): target is Function {
|
|
33
|
-
return _typeof(target, 'function')
|
|
34
|
-
}
|
|
35
|
-
export function isUndefined(target: any): target is undefined {
|
|
36
|
-
return _typeof(target, 'undefined')
|
|
37
|
-
}
|
|
38
|
-
export function isNull(target: any): target is null {
|
|
39
|
-
return target === null;
|
|
40
|
-
}
|
|
41
|
-
export function _instanceof<T extends (abstract new (...args: any[]) => any)[]>(target: any, ...instance: T): target is InstanceType<T[number]> {
|
|
42
|
-
return !!instance.find(i => target instanceof i);
|
|
43
|
-
}
|
|
10
|
+
export const forEach: forEach = <T>(arr: any, fn: any, thisArgs?: any) => arr.forEach(fn, thisArgs);
|
|
11
|
+
// type check
|
|
12
|
+
export const _typeof = (target: any, type: 'string' | 'number' | 'object' | 'boolean' | 'function' | 'bigint' | 'symbol' | 'undefined') => typeof target === type;
|
|
13
|
+
export const equal = <T, V extends T>(target: T, ...args: V[]): target is V => !!args.find(a => a === target);
|
|
14
|
+
export const isString = (target: any): target is string => _typeof(target, 'string');
|
|
15
|
+
export const isNumber = (target: any): target is number => _typeof(target, 'number')
|
|
16
|
+
export const isObject = (target: any): target is object => _typeof(target, 'object')
|
|
17
|
+
export const isFunction = (target: any): target is Function => _typeof(target, 'function')
|
|
18
|
+
export const isUndefined = (target: any): target is undefined => _typeof(target, 'undefined')
|
|
19
|
+
export const isNull = (target: any): target is null => target === null;
|
|
20
|
+
export const _instanceof = <T extends (abstract new (...args: any[]) => any)[]>(target: any, ...instance: T): target is InstanceType<T[number]> => !!instance.find(i => target instanceof i);
|
|
44
21
|
// JSON
|
|
45
|
-
export const _JSON_stringify = JSON.stringify;
|
|
22
|
+
export const _JSON_stringify = JSON.stringify;
|
|
23
|
+
export const _JSON_parse = JSON.parse;
|
|
24
|
+
// String
|
|
25
|
+
export const startsWith = (target: string, ...str: string[]) => !!str.find(s => target.startsWith(s));
|
|
26
|
+
|
|
27
|
+
interface forEach {
|
|
28
|
+
<T>(arr: Array<T>, fn: (value: T, index: number, array: Array<T>) => any, thisArgs?: any): void;
|
|
29
|
+
<T>(set: Set<T>, fn: (value: T, index: number, set: Set<T>) => any, thisArgs?: any): void;
|
|
30
|
+
<K, V>(set: Map<K, V>, fn: (value: V, key: K, index: number, map: Map<K, V>) => any, thisArgs?: any): void;
|
|
31
|
+
<N extends Node>(set: NodeListOf<N>, fn: (value: N, index: number, parent: NodeListOf<N>) => any, thisArgs?: any): void;
|
|
32
|
+
}
|
package/src/lib/randomId.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { _Array_from } from "./native";
|
|
|
2
2
|
|
|
3
3
|
const LOWER = 'abcdefghijklmnopqrstuvwxyz';
|
|
4
4
|
const UPPER = LOWER.toUpperCase();
|
|
5
|
-
export
|
|
5
|
+
export const randomId = (options?: {length?: number, lettercase?: 'any' | 'lower' | 'upper'}): string => {
|
|
6
6
|
options = {length: 5, lettercase: 'any', ...options};
|
|
7
7
|
const char = options.lettercase === 'any' ? LOWER + UPPER : options.lettercase === 'lower' ? LOWER : UPPER;
|
|
8
8
|
return _Array_from({length: options.length as number}, (_, i) => {
|
package/src/lib/sleep.ts
CHANGED