amateras 0.2.0 → 0.3.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 +19 -3
- package/ext/css/src/index.ts +102 -45
- package/ext/css/src/lib/colorAssign.ts +6 -0
- package/ext/css/src/lib/colors/amber.ts +25 -0
- package/ext/css/src/lib/colors/blackwhite.ts +13 -0
- package/ext/css/src/lib/colors/blue.ts +25 -0
- package/ext/css/src/lib/colors/cyan.ts +25 -0
- package/ext/css/src/lib/colors/emerald.ts +25 -0
- package/ext/css/src/lib/colors/fuchsia.ts +25 -0
- package/ext/css/src/lib/colors/gray.ts +25 -0
- package/ext/css/src/lib/colors/green.ts +25 -0
- package/ext/css/src/lib/colors/indigo.ts +25 -0
- package/ext/css/src/lib/colors/lime.ts +25 -0
- package/ext/css/src/lib/colors/neutral.ts +25 -0
- package/ext/css/src/lib/colors/orange.ts +25 -0
- package/ext/css/src/lib/colors/pink.ts +25 -0
- package/ext/css/src/lib/colors/purple.ts +25 -0
- package/ext/css/src/lib/colors/red.ts +25 -0
- package/ext/css/src/lib/colors/rose.ts +25 -0
- package/ext/css/src/lib/colors/sky.ts +25 -0
- package/ext/css/src/lib/colors/slate.ts +25 -0
- package/ext/css/src/lib/colors/stone.ts +25 -0
- package/ext/css/src/lib/colors/teal.ts +25 -0
- package/ext/css/src/lib/colors/violet.ts +25 -0
- package/ext/css/src/lib/colors/yellow.ts +25 -0
- package/ext/css/src/lib/colors/zinc.ts +25 -0
- package/ext/css/src/lib/colors.ts +23 -0
- package/ext/css/src/structure/$CSSKeyframesRule.ts +1 -5
- package/ext/css/src/structure/$CSSMediaRule.ts +3 -23
- package/ext/css/src/structure/$CSSRule.ts +6 -18
- package/ext/css/src/structure/$CSSStyleRule.ts +10 -12
- package/ext/html/node/$Anchor.ts +31 -1
- package/ext/html/node/$Image.ts +54 -1
- package/ext/html/node/$Input.ts +154 -1
- package/ext/html/node/$OptGroup.ts +8 -1
- package/ext/html/node/$Option.ts +25 -1
- package/ext/html/node/$Select.ts +61 -1
- package/ext/router/index.ts +6 -4
- package/ext/router/node/Route.ts +2 -2
- package/ext/router/node/Router.ts +49 -15
- package/ext/router/node/RouterAnchor.ts +1 -1
- package/ext/ssr/index.ts +4 -4
- package/package.json +3 -1
- package/src/core.ts +19 -15
- package/src/global.ts +4 -0
- package/src/lib/assign.ts +4 -3
- package/src/lib/assignHelper.ts +1 -1
- package/src/lib/native.ts +14 -3
- package/src/node/$Element.ts +128 -24
- package/src/node/$HTMLElement.ts +70 -1
- package/src/node/$Node.ts +101 -30
- package/src/node/node.ts +2 -1
- package/src/structure/Signal.ts +3 -3
- package/ext/css/src/structure/$CSSKeyframeRule.ts +0 -14
package/ext/html/node/$Option.ts
CHANGED
|
@@ -7,7 +7,31 @@ export class $Option extends $HTMLElement<HTMLOptionElement> {
|
|
|
7
7
|
}
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
export interface $Option extends $HTMLElement<HTMLOptionElement> {
|
|
10
|
+
export interface $Option extends $HTMLElement<HTMLOptionElement> {
|
|
11
|
+
/** {@link HTMLOptionElement.form} */
|
|
12
|
+
readonly form: HTMLFormElement | null;
|
|
13
|
+
/** {@link HTMLOptionElement.index} */
|
|
14
|
+
readonly index: number;
|
|
15
|
+
|
|
16
|
+
/** {@link HTMLOptionElement.defaultSelected} */
|
|
17
|
+
defaultSelected(defaultSelected: $Parameter<boolean>): this;
|
|
18
|
+
defaultSelected(): boolean;
|
|
19
|
+
/** {@link HTMLOptionElement.disabled} */
|
|
20
|
+
disabled(disabled: $Parameter<boolean>): this;
|
|
21
|
+
disabled(): boolean;
|
|
22
|
+
/** {@link HTMLOptionElement.label} */
|
|
23
|
+
label(label: $Parameter<string>): this;
|
|
24
|
+
label(): string;
|
|
25
|
+
/** {@link HTMLOptionElement.selected} */
|
|
26
|
+
selected(selected: $Parameter<boolean>): this;
|
|
27
|
+
selected(): boolean;
|
|
28
|
+
/** {@link HTMLOptionElement.text} */
|
|
29
|
+
text(text: $Parameter<string>): this;
|
|
30
|
+
text(): string;
|
|
31
|
+
/** {@link HTMLOptionElement.value} */
|
|
32
|
+
value(value: $Parameter<string>): this;
|
|
33
|
+
value(): string;
|
|
34
|
+
}
|
|
11
35
|
|
|
12
36
|
assignHelper(HTMLOptionElement, $Option, 'option');
|
|
13
37
|
|
package/ext/html/node/$Select.ts
CHANGED
|
@@ -7,7 +7,67 @@ export class $Select extends $HTMLElement<HTMLSelectElement> {
|
|
|
7
7
|
}
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
export interface $Select extends $HTMLElement<HTMLSelectElement> {
|
|
10
|
+
export interface $Select extends $HTMLElement<HTMLSelectElement> {
|
|
11
|
+
/** {@link HTMLSelectElement.form} */
|
|
12
|
+
readonly form: HTMLFormElement | null;
|
|
13
|
+
/** {@link HTMLSelectElement.labels} */
|
|
14
|
+
readonly labels: NodeListOf<HTMLLabelElement>;
|
|
15
|
+
/** {@link HTMLSelectElement.options} */
|
|
16
|
+
readonly options: HTMLOptionsCollection;
|
|
17
|
+
/** {@link HTMLSelectElement.selectedOptions} */
|
|
18
|
+
readonly selectedOptions: HTMLCollectionOf<HTMLOptionElement>;
|
|
19
|
+
/** {@link HTMLSelectElement.type} */
|
|
20
|
+
readonly type: "select-one" | "select-multiple";
|
|
21
|
+
/** {@link HTMLSelectElement.validationMessage} */
|
|
22
|
+
readonly validationMessage: string;
|
|
23
|
+
/** {@link HTMLSelectElement.validity} */
|
|
24
|
+
readonly validity: ValidityState;
|
|
25
|
+
/** {@link HTMLSelectElement.willValidate} */
|
|
26
|
+
readonly willValidate: boolean;
|
|
27
|
+
|
|
28
|
+
/** {@link HTMLSelectElement.autocomplete} */
|
|
29
|
+
autocomplete(autocomplete: $Parameter<AutoFill>): this;
|
|
30
|
+
autocomplete(): AutoFill;
|
|
31
|
+
/** {@link HTMLSelectElement.disabled} */
|
|
32
|
+
disabled(disabled: $Parameter<boolean>): this;
|
|
33
|
+
disabled(): boolean;
|
|
34
|
+
/** {@link HTMLSelectElement.length} */
|
|
35
|
+
length(length: $Parameter<number>): this;
|
|
36
|
+
length(): number;
|
|
37
|
+
/** {@link HTMLSelectElement.multiple} */
|
|
38
|
+
multiple(multiple: $Parameter<boolean>): this;
|
|
39
|
+
multiple(): boolean;
|
|
40
|
+
/** {@link HTMLSelectElement.name} */
|
|
41
|
+
name(name: $Parameter<string>): this;
|
|
42
|
+
name(): string;
|
|
43
|
+
/** {@link HTMLSelectElement.required} */
|
|
44
|
+
required(required: $Parameter<boolean>): this;
|
|
45
|
+
required(): boolean;
|
|
46
|
+
/** {@link HTMLSelectElement.selectedIndex} */
|
|
47
|
+
selectedIndex(selectedIndex: $Parameter<number>): this;
|
|
48
|
+
selectedIndex(): number;
|
|
49
|
+
/** {@link HTMLSelectElement.size} */
|
|
50
|
+
size(size: $Parameter<number>): this;
|
|
51
|
+
size(): number;
|
|
52
|
+
/** {@link HTMLSelectElement.value} */
|
|
53
|
+
value(value: $Parameter<string>): this;
|
|
54
|
+
value(): string;
|
|
55
|
+
|
|
56
|
+
/** {@link HTMLSelectElement.add} */
|
|
57
|
+
add(element: HTMLOptionElement | HTMLOptGroupElement, before?: HTMLElement | number | null): this;
|
|
58
|
+
/** {@link HTMLSelectElement.checkValidity} */
|
|
59
|
+
checkValidity(): boolean;
|
|
60
|
+
/** {@link HTMLSelectElement.item} */
|
|
61
|
+
item(index: number): HTMLOptionElement | null;
|
|
62
|
+
/** {@link HTMLSelectElement.namedItem} */
|
|
63
|
+
namedItem(name: string): HTMLOptionElement | null;
|
|
64
|
+
/** {@link HTMLSelectElement.reportValidity} */
|
|
65
|
+
reportValidity(): boolean;
|
|
66
|
+
/** {@link HTMLSelectElement.setCustomValidity} */
|
|
67
|
+
setCustomValidity(error: string): this;
|
|
68
|
+
/** {@link HTMLSelectElement.showPicker} */
|
|
69
|
+
showPicker(): this;
|
|
70
|
+
}
|
|
11
71
|
|
|
12
72
|
assignHelper(HTMLSelectElement, $Select, 'select');
|
|
13
73
|
|
package/ext/router/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { AnchorTarget } from "#html/$Anchor";
|
|
2
|
+
import { _Object_assign, forEach } from "#lib/native";
|
|
2
3
|
import type { $NodeContentResolver } from "#node/$Node";
|
|
3
4
|
import type { Page } from "./node/Page";
|
|
4
5
|
import { Route } from "./node/Route";
|
|
@@ -7,13 +8,14 @@ import { RouterAnchor } from "./node/RouterAnchor";
|
|
|
7
8
|
export * from "./node/Route";
|
|
8
9
|
export * from "./node/Router";
|
|
9
10
|
export * from "./node/Page";
|
|
11
|
+
export * from "./node/RouterAnchor";
|
|
10
12
|
|
|
11
13
|
declare module 'amateras/core' {
|
|
12
14
|
export function $<P extends string>(nodeName: 'route', path: P, builder: RouteBuilder<Route<P>, RouteDataResolver<P>>): Route<P>;
|
|
13
15
|
export function $(nodeName: 'router', page?: Page<any>): Router;
|
|
14
16
|
export function $(nodeName: 'ra'): RouterAnchor;
|
|
15
17
|
export namespace $ {
|
|
16
|
-
export function open(url: string | URL | Nullish): typeof Router;
|
|
18
|
+
export function open(url: string | URL | Nullish, target: AnchorTarget): typeof Router;
|
|
17
19
|
export function replace(url: string | URL | Nullish): typeof Router;
|
|
18
20
|
export function back(): typeof Router;
|
|
19
21
|
export function forward(): typeof Router;
|
|
@@ -27,10 +29,10 @@ _Object_assign($, {
|
|
|
27
29
|
forward: Router.forward.bind(Router)
|
|
28
30
|
});
|
|
29
31
|
// define styles
|
|
30
|
-
[
|
|
32
|
+
forEach([
|
|
31
33
|
`router{display:block}`,
|
|
32
34
|
`page{display:block}`
|
|
33
|
-
]
|
|
35
|
+
], rule => $.stylesheet.insertRule(rule));
|
|
34
36
|
// assign nodes
|
|
35
37
|
$.assign([
|
|
36
38
|
['router', Router],
|
package/ext/router/node/Route.ts
CHANGED
|
@@ -34,8 +34,8 @@ export class Route<Path extends string = string> extends BaseRouteNode<Path> {
|
|
|
34
34
|
super(path, builder, 'route');
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
async build(data: {params: any, query: any} = {params: {}, query: {}}) {
|
|
38
|
-
|
|
37
|
+
async build(data: {params: any, query: any} = {params: {}, query: {}}, page?: Page) {
|
|
38
|
+
page = page ?? new Page(this, data);
|
|
39
39
|
page.params = data.params;
|
|
40
40
|
let resolver: any = this.builder(page);
|
|
41
41
|
if (_instanceof(resolver, Promise)) {
|
|
@@ -1,32 +1,55 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { AnchorTarget } from "#html/$Anchor";
|
|
2
|
+
import { _Array_from, _document, _instanceof, _Object_fromEntries, forEach } from "#lib/native";
|
|
2
3
|
import { Page } from "./Page";
|
|
3
4
|
import { BaseRouteNode, Route } from "./Route";
|
|
4
5
|
|
|
6
|
+
// history index
|
|
7
|
+
let index = 0;
|
|
5
8
|
const _location = location;
|
|
6
9
|
const {origin} = _location;
|
|
7
10
|
const _history = history;
|
|
8
|
-
const
|
|
9
|
-
_instanceof(path, URL) ? path : new URL(path.startsWith(origin) ? path : origin + path);
|
|
11
|
+
const documentElement = _document.documentElement;
|
|
10
12
|
const [PUSH, REPLACE] = [1, 2] as const;
|
|
11
|
-
const
|
|
13
|
+
const [FORWARD, BACK] = ['forward', 'back'] as const;
|
|
14
|
+
|
|
15
|
+
// disable browser scroll restoration
|
|
16
|
+
_history.scrollRestoration = 'manual';
|
|
17
|
+
|
|
18
|
+
/** convert path string to URL object */
|
|
19
|
+
const toURL = (path: string | URL) =>
|
|
20
|
+
_instanceof(path, URL) ? path : path.startsWith('http') ? new URL(path) : new URL(path.startsWith(origin) ? path : origin + path);
|
|
21
|
+
|
|
22
|
+
/** handle history state with push and replace state. */
|
|
23
|
+
const historyHandler = async (path: string | URL | Nullish, mode: 1 | 2, target?: AnchorTarget) => {
|
|
12
24
|
if (!path) return;
|
|
13
25
|
const url = toURL(path);
|
|
14
|
-
if (url.
|
|
15
|
-
|
|
16
|
-
|
|
26
|
+
if (url.href === _location.href) return;
|
|
27
|
+
if (target && target !== '_self') return open(url, target);
|
|
28
|
+
if (url.origin !== origin) return open(url, target);
|
|
29
|
+
_history.replaceState({
|
|
30
|
+
index: index,
|
|
31
|
+
x: documentElement.scrollLeft,
|
|
32
|
+
y: documentElement.scrollTop
|
|
33
|
+
}, '', _location.href);
|
|
34
|
+
if (mode === PUSH) index += 1;
|
|
35
|
+
Router.direction = FORWARD;
|
|
36
|
+
history[mode === PUSH ? 'pushState' : 'replaceState']({index}, '' , url)
|
|
37
|
+
for (let router of Router.routers) router.routes.size && await router.resolve(path)
|
|
17
38
|
}
|
|
39
|
+
|
|
18
40
|
export class Router extends BaseRouteNode<''> {
|
|
19
41
|
static pageRouters = new Map<Page, Router>();
|
|
20
42
|
static routers = new Set<Router>();
|
|
21
43
|
pageMap = new Map<string, Page>();
|
|
44
|
+
static direction: 'back' | 'forward' = FORWARD;
|
|
22
45
|
constructor(page?: Page) {
|
|
23
46
|
super('', () => [], 'router')
|
|
24
47
|
Router.routers.add(this);
|
|
25
48
|
if (page) Router.pageRouters.set(page, this);
|
|
26
49
|
}
|
|
27
50
|
|
|
28
|
-
static open(path: string | URL | Nullish) {
|
|
29
|
-
historyHandler(path, PUSH);
|
|
51
|
+
static open(path: string | URL | Nullish, target?: AnchorTarget) {
|
|
52
|
+
historyHandler(path, PUSH, target);
|
|
30
53
|
return this;
|
|
31
54
|
}
|
|
32
55
|
|
|
@@ -46,7 +69,7 @@ export class Router extends BaseRouteNode<''> {
|
|
|
46
69
|
}
|
|
47
70
|
|
|
48
71
|
async resolve(path: string | URL) {
|
|
49
|
-
const {pathname, searchParams, hash} = toURL(path);
|
|
72
|
+
const {pathname, searchParams, hash, href} = toURL(path);
|
|
50
73
|
const routeData = { params: {} as {[key: string]: string}, query: _Object_fromEntries(searchParams) }
|
|
51
74
|
const split = (p: string) => p.replaceAll(/\/+/g, '/').split('/').map(path => `/${path}`);
|
|
52
75
|
|
|
@@ -83,20 +106,31 @@ export class Router extends BaseRouteNode<''> {
|
|
|
83
106
|
// build pages
|
|
84
107
|
let prevPage: null | Page = null, prevRoute: BaseRouteNode<any> = this;
|
|
85
108
|
for (const [route, pathId] of targetRoutes) {
|
|
86
|
-
const page =
|
|
87
|
-
|
|
109
|
+
const page = this.pageMap.get(pathId) ?? new Page(route ?? prevRoute.routes.get('404') ?? new Route('404', () => null), routeData);
|
|
110
|
+
await route?.build(routeData, page);
|
|
88
111
|
_document && (_document.title = page.pageTitle() ?? _document.title);
|
|
89
112
|
this.pageMap.set(pathId, page);
|
|
90
|
-
|
|
91
|
-
|
|
113
|
+
|
|
114
|
+
if (href === _location.href) {
|
|
115
|
+
if (prevPage) Router.pageRouters.get(prevPage)?.content(page);
|
|
116
|
+
else this.content(page);
|
|
117
|
+
}
|
|
92
118
|
prevPage = page;
|
|
93
119
|
if (route) prevRoute = route;
|
|
94
120
|
}
|
|
121
|
+
let { x, y } = _history.state ?? {x: 0, y: 0};
|
|
122
|
+
scrollTo(x, y);
|
|
95
123
|
return this;
|
|
96
124
|
}
|
|
97
125
|
|
|
98
126
|
listen() {
|
|
99
|
-
const resolve = () =>
|
|
127
|
+
const resolve = () => {
|
|
128
|
+
const stateIndex = _history.state?.index ?? 0;
|
|
129
|
+
if (index > stateIndex) Router.direction = BACK;
|
|
130
|
+
if (index < stateIndex) Router.direction = FORWARD;
|
|
131
|
+
index = stateIndex;
|
|
132
|
+
this.resolve(_location.href);
|
|
133
|
+
}
|
|
100
134
|
addEventListener('popstate', resolve);
|
|
101
135
|
resolve();
|
|
102
136
|
return this;
|
|
@@ -3,6 +3,6 @@ import { $Anchor } from "#html/$Anchor";
|
|
|
3
3
|
export class RouterAnchor extends $Anchor {
|
|
4
4
|
constructor() {
|
|
5
5
|
super();
|
|
6
|
-
this.on('click', e => { e.preventDefault(); $.open(this.href()) })
|
|
6
|
+
this.on('click', e => { e.preventDefault(); $.open(this.href(), this.target()) })
|
|
7
7
|
}
|
|
8
8
|
}
|
package/ext/ssr/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import './env';
|
|
2
2
|
import 'amateras';
|
|
3
|
-
import { _Array_from, _instanceof, _Object_assign, _Object_defineProperty } from "amateras/lib/native";
|
|
3
|
+
import { _Array_from, _document, _instanceof, _Object_assign, _Object_defineProperty, forEach } from "amateras/lib/native";
|
|
4
4
|
import { $Element, $Node, $Text } from "amateras/node";
|
|
5
5
|
import { BROWSER, NODE } from 'esm-env';
|
|
6
6
|
|
|
@@ -24,7 +24,7 @@ export function onclient<T>(cb: () => T): T | undefined {
|
|
|
24
24
|
_Object_assign($, {
|
|
25
25
|
mount(id: string, $node: $Element) {
|
|
26
26
|
if (!BROWSER) return;
|
|
27
|
-
const node =
|
|
27
|
+
const node = _document.querySelector(`#${id}`);
|
|
28
28
|
if (!node) throw 'Target node of mounting not found';
|
|
29
29
|
getData(node, $node);
|
|
30
30
|
node.replaceWith($node.node);
|
|
@@ -32,12 +32,12 @@ _Object_assign($, {
|
|
|
32
32
|
function getData(node: Node, $node: $Node) {
|
|
33
33
|
if (node.nodeName === 'SIGNAL' && _instanceof(node, Element) && _instanceof($node, $Text)) {
|
|
34
34
|
const type = $(node).attr()['type'];
|
|
35
|
-
return $node.signals
|
|
35
|
+
return forEach($node.signals, signal => signal.value(type === 'number' ? Number(node.textContent) : type === 'boolean' ? node.textContent == 'true' ? true : false : node.textContent));
|
|
36
36
|
}
|
|
37
37
|
if (_instanceof(node, Text)) return $node.textContent(node.textContent);
|
|
38
38
|
if (_instanceof(node, Element) && _instanceof($node, $Element)) $node.attr($(node).attr());
|
|
39
39
|
const arr = _Array_from($node.childNodes);
|
|
40
|
-
node.childNodes
|
|
40
|
+
forEach(node.childNodes, (_node, i) => {
|
|
41
41
|
const targetChildNode = arr.at(i);
|
|
42
42
|
if (!targetChildNode) throw 'Target DOM tree not matched';
|
|
43
43
|
getData(_node, targetChildNode.$)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "amateras",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Amateras is a DOM Utility library.",
|
|
5
5
|
"module": "index.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -32,6 +32,8 @@
|
|
|
32
32
|
"./html": "./ext/html/html.ts",
|
|
33
33
|
"./html/*": "./ext/html/node/*.ts",
|
|
34
34
|
"./css": "./ext/css/src/index.ts",
|
|
35
|
+
"./css/colors": "./ext/css/src/lib/colors.ts",
|
|
36
|
+
"./css/color/*": "./ext/css/src/lib/colors/*.ts",
|
|
35
37
|
"./router": "./ext/router/index.ts",
|
|
36
38
|
"./ssr": "./ext/ssr/index.ts"
|
|
37
39
|
},
|
package/src/core.ts
CHANGED
|
@@ -1,41 +1,45 @@
|
|
|
1
1
|
import './global';
|
|
2
2
|
import { Signal } from "#structure/Signal";
|
|
3
3
|
import { $Element, type $Event } from "#node/$Element";
|
|
4
|
-
import { $Node, type $NodeContentTypes } from '#node/$Node';
|
|
4
|
+
import { $Node, type $NodeContentResolver, type $NodeContentTypes } from '#node/$Node';
|
|
5
5
|
import '#node/node';
|
|
6
|
-
import { _instanceof, isString, isFunction, _Object_assign, isObject, isNull, _Object_entries, _Object_defineProperty } from '#lib/native';
|
|
6
|
+
import { _instanceof, isString, isFunction, _Object_assign, isObject, isNull, _Object_entries, _Object_defineProperty, forEach, isNumber, _Array_from, _document } from '#lib/native';
|
|
7
7
|
import type { $HTMLElement } from '#node/$HTMLElement';
|
|
8
8
|
|
|
9
9
|
const nodeNameMap: {[key: string]: Constructor<$Node>} = {}
|
|
10
10
|
|
|
11
|
-
export function $<F extends (...args: any[]) => $Node>(fn: F, ...args: Parameters<F>): ReturnType<F>;
|
|
12
|
-
export function $<
|
|
13
|
-
export function $<
|
|
11
|
+
export function $<F extends (...args: any[]) => $NodeContentResolver<$Node>, N extends number>(number: N, fn: F, ...args: Parameters<F>): Repeat<ReturnType<F>, N>;
|
|
12
|
+
export function $<F extends (...args: any[]) => $NodeContentResolver<$Node>>(fn: F, ...args: Parameters<F>): ReturnType<F>;
|
|
13
|
+
export function $<T extends Constructor<$Node>, P extends ConstructorParameters<T>, N extends number>(number: N, construct: T, ...args: P): Repeat<InstanceType<T>, N>;
|
|
14
|
+
export function $<T extends Constructor<$Node>, P extends ConstructorParameters<T>>(construct: T, ...args: P): InstanceType<T>;
|
|
14
15
|
export function $<N extends $Node>($node: N, ...args: any[]): N;
|
|
16
|
+
export function $<H extends HTMLElement>(element: H, ...args: any[]): $HTMLElement<H>;
|
|
15
17
|
export function $<E extends Element>(element: E, ...args: any[]): $Element<E>;
|
|
16
18
|
export function $<K extends TemplateStringsArray>(string: K, ...values: any[]): $NodeContentTypes[];
|
|
19
|
+
export function $<K extends keyof HTMLElementTagNameMap, N extends number>(number: N, tagname: K): Repeat<$HTMLElement<HTMLElementTagNameMap[K]>, N>;
|
|
17
20
|
export function $<K extends keyof HTMLElementTagNameMap>(tagname: K): $HTMLElement<HTMLElementTagNameMap[K]>;
|
|
18
|
-
export function $<
|
|
19
|
-
export function $<
|
|
21
|
+
export function $<Ev extends $Event<$Element, Event>>(event: Ev): Ev['target']['$'];
|
|
22
|
+
export function $<N extends number>(number: N, tagname: string): Repeat<$HTMLElement<HTMLElement>, N>;
|
|
20
23
|
export function $(tagname: string): $HTMLElement<HTMLElement>
|
|
21
|
-
export function $(resolver: string | Element | $Node | Function | TemplateStringsArray | Event, ...args: any[]) {
|
|
24
|
+
export function $(resolver: string | number | Element | $Node | Function | TemplateStringsArray | Event, ...args: any[]) {
|
|
22
25
|
if (_instanceof(resolver, $Node)) return resolver;
|
|
23
26
|
if (isString(resolver) && nodeNameMap[resolver]) return new nodeNameMap[resolver](...args);
|
|
24
27
|
if (isFunction(resolver))
|
|
25
|
-
if (resolver.prototype?.constructor) return resolver.prototype.constructor(...args);
|
|
28
|
+
if (resolver.prototype?.constructor) return new resolver.prototype.constructor(...args);
|
|
26
29
|
else return resolver(...args);
|
|
27
30
|
if (resolver instanceof Array) {
|
|
28
31
|
const iterate = args.values();
|
|
29
32
|
return resolver.map(str => [str ?? undefined, iterate.next().value]).flat().filter(item => item);
|
|
30
33
|
}
|
|
31
34
|
if (_instanceof(resolver, Node) && _instanceof(resolver.$, $Node)) return resolver.$;
|
|
32
|
-
if (_instanceof(resolver, Event)) return $(resolver.currentTarget as Element)
|
|
35
|
+
if (_instanceof(resolver, Event)) return $(resolver.currentTarget as Element);
|
|
36
|
+
if (isNumber(resolver)) return _Array_from({length: resolver}).map(_ => $(args[0], ...args.slice(1)));
|
|
33
37
|
return new $Element(resolver);
|
|
34
38
|
}
|
|
35
39
|
|
|
36
40
|
export namespace $ {
|
|
37
41
|
export const stylesheet = new CSSStyleSheet();
|
|
38
|
-
|
|
42
|
+
_document.adoptedStyleSheets.push(stylesheet);
|
|
39
43
|
type SignalProcess<T> = T extends Array<any> ? {} : T extends object ? { [key in keyof T as `${string & key}$`]: SignalFunction<T[key]> } : {};
|
|
40
44
|
export type SignalFunction<T> = {signal: Signal<T>, set: (newValue: T | ((oldValue: T) => T)) => SignalFunction<T>} & (() => T) & SignalProcess<T>;
|
|
41
45
|
export function signal<T>(value: T): SignalFunction<T>
|
|
@@ -59,7 +63,7 @@ export namespace $ {
|
|
|
59
63
|
export type ComputeFunction<T> = ({(): T}) & { signal: Signal<T> };
|
|
60
64
|
export function compute<T>(process: () => T) {
|
|
61
65
|
let subscribed = false;
|
|
62
|
-
const signalFn: SignalFunction<any> =
|
|
66
|
+
const signalFn: SignalFunction<any> = signal(null);
|
|
63
67
|
function computeFn() {
|
|
64
68
|
if (!subscribed) return signalFn.set(subscribe())();
|
|
65
69
|
else return signalFn.set(process())();
|
|
@@ -74,7 +78,7 @@ export namespace $ {
|
|
|
74
78
|
subscribed = true;
|
|
75
79
|
return result;
|
|
76
80
|
}
|
|
77
|
-
|
|
81
|
+
_Object_assign(computeFn, { signal: signalFn.signal });
|
|
78
82
|
return computeFn as ComputeFunction<T>
|
|
79
83
|
}
|
|
80
84
|
|
|
@@ -82,11 +86,11 @@ export namespace $ {
|
|
|
82
86
|
export function assign(nodeName: string, $node: Constructor<$Node>): void;
|
|
83
87
|
export function assign(resolver: string | [nodeName: string, $node: Constructor<$Node>][], $node?: Constructor<$Node>) {
|
|
84
88
|
if (isString(resolver)) $node && (nodeNameMap[resolver] = $node);
|
|
85
|
-
else
|
|
89
|
+
else forEach(resolver, ([nodeName, $node]) => nodeNameMap[nodeName] = $node);
|
|
86
90
|
return $;
|
|
87
91
|
}
|
|
88
92
|
|
|
89
|
-
export function
|
|
93
|
+
export function toArray<T>(item: OrArray<T>): T[] {
|
|
90
94
|
return _instanceof(item, Array) ? item : [item];
|
|
91
95
|
}
|
|
92
96
|
|
package/src/global.ts
CHANGED
|
@@ -12,6 +12,10 @@ declare global {
|
|
|
12
12
|
type OrNullish<T> = T | Nullish;
|
|
13
13
|
type Constructor<T> = { new (...args: any[]): T }
|
|
14
14
|
type $Parameter<T> = T | undefined | Signal<T> | Signal<T | undefined>
|
|
15
|
+
type Repeat<T, N extends number, Acc extends T[] = []> =
|
|
16
|
+
Acc['length'] extends N
|
|
17
|
+
? Acc
|
|
18
|
+
: Repeat<T, N, [...Acc, T]>;
|
|
15
19
|
type Prettify<T> = {
|
|
16
20
|
[K in keyof T]: T[K];
|
|
17
21
|
} & {};
|
package/src/lib/assign.ts
CHANGED
|
@@ -6,17 +6,18 @@ export function assign(target: any, {set, get, fn}: {
|
|
|
6
6
|
get?: string[],
|
|
7
7
|
fn?: string[]
|
|
8
8
|
}) {
|
|
9
|
+
const [GET, SET, FN] = ['get', 'set', 'fn'] as const;
|
|
9
10
|
const filterAndMap = (type: 'get' | 'set' | 'fn', arr: string[] | undefined) => {
|
|
10
11
|
return arr?.map(prop => [type, prop]) ?? []
|
|
11
12
|
}
|
|
12
|
-
const list = [...filterAndMap(
|
|
13
|
+
const list = [...filterAndMap(GET, get), ...filterAndMap(SET, set), ...filterAndMap(FN, fn)] as [string, string][];
|
|
13
14
|
for (const [type, prop] of list) {
|
|
14
15
|
_Object_defineProperty(target.prototype, prop, {
|
|
15
|
-
...(type ===
|
|
16
|
+
...(type === GET ? {
|
|
16
17
|
get() { return this.node[prop as any] }
|
|
17
18
|
} : {
|
|
18
19
|
writable: true,
|
|
19
|
-
...(type ===
|
|
20
|
+
...(type === SET ? {
|
|
20
21
|
// set
|
|
21
22
|
value: function (this, args: any) {
|
|
22
23
|
if (!arguments.length) return this.node[prop];
|
package/src/lib/assignHelper.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { assign } from "./assign";
|
|
|
3
3
|
import { _Object_entries, _Object_getOwnPropertyDescriptors } from "./native";
|
|
4
4
|
|
|
5
5
|
export function assignHelper(object: Constructor<Node>, target: Constructor<$Node>, tagname?: string) {
|
|
6
|
-
const
|
|
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))) {
|
|
9
9
|
if (prop in target.prototype) continue;
|
package/src/lib/native.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// document
|
|
2
|
+
export const _document = document;
|
|
1
3
|
// Object
|
|
2
4
|
export const _Object_fromEntries = Object.fromEntries;
|
|
3
5
|
export const _Object_entries = Object.entries;
|
|
@@ -7,6 +9,13 @@ export const _Object_defineProperty = Object.defineProperty;
|
|
|
7
9
|
export const _Object_getOwnPropertyDescriptors = Object.getOwnPropertyDescriptors;
|
|
8
10
|
// Array
|
|
9
11
|
export const _Array_from = Array.from;
|
|
12
|
+
export function forEach<N extends Node>(set: NodeListOf<N>, fn: (value: N, index: number, parent: NodeListOf<N>) => any, thisArgs?: any): void;
|
|
13
|
+
export function forEach<K, V>(set: Map<K, V>, fn: (value: V, key: K, index: number, map: Map<K, V>) => any, thisArgs?: any): void;
|
|
14
|
+
export function forEach<T>(set: Set<T>, fn: (value: T, index: number, set: Set<T>) => any, thisArgs?: any): void;
|
|
15
|
+
export function forEach<T>(arr: Array<T>, fn: (value: T, index: number, array: Array<T>) => any, thisArgs?: any): void;
|
|
16
|
+
export function forEach<T>(arr: any, fn: any, thisArgs?: any) {
|
|
17
|
+
arr.forEach(fn, thisArgs)
|
|
18
|
+
}
|
|
10
19
|
// typeof
|
|
11
20
|
export function _typeof(target: any, type: 'string' | 'number' | 'object' | 'boolean' | 'function' | 'bigint' | 'symbol' | 'undefined') {
|
|
12
21
|
return typeof target === type;
|
|
@@ -29,6 +38,8 @@ export function isUndefined(target: any): target is undefined {
|
|
|
29
38
|
export function isNull(target: any): target is null {
|
|
30
39
|
return target === null;
|
|
31
40
|
}
|
|
32
|
-
export function _instanceof<T
|
|
33
|
-
return target instanceof
|
|
34
|
-
}
|
|
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
|
+
}
|
|
44
|
+
// JSON
|
|
45
|
+
export const _JSON_stringify = JSON.stringify;
|