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.
Files changed (81) hide show
  1. package/README.md +23 -26
  2. package/ext/html/node/$Anchor.ts +2 -2
  3. package/ext/html/node/$Canvas.ts +2 -2
  4. package/ext/html/node/$Dialog.ts +2 -2
  5. package/ext/html/node/$Form.ts +2 -2
  6. package/ext/html/node/$Image.ts +2 -2
  7. package/ext/html/node/$Input.ts +2 -2
  8. package/ext/html/node/$Label.ts +2 -2
  9. package/ext/html/node/$Media.ts +2 -2
  10. package/ext/html/node/$OptGroup.ts +2 -2
  11. package/ext/html/node/$Option.ts +2 -2
  12. package/ext/html/node/$Select.ts +2 -2
  13. package/ext/html/node/$TextArea.ts +2 -2
  14. package/ext/i18n/README.md +20 -0
  15. package/ext/i18n/src/index.ts +106 -12
  16. package/ext/i18n/src/structure/I18n.ts +12 -8
  17. package/ext/i18n/src/structure/I18nTranslation.ts +35 -0
  18. package/ext/idb/src/structure/builder/$IDBBuilder.ts +8 -8
  19. package/ext/markdown/README.md +53 -0
  20. package/ext/markdown/package.json +7 -0
  21. package/ext/markdown/src/index.ts +3 -0
  22. package/ext/markdown/src/lib/type.ts +26 -0
  23. package/ext/markdown/src/lib/util.ts +21 -0
  24. package/ext/markdown/src/structure/Markdown.ts +54 -0
  25. package/ext/markdown/src/structure/MarkdownLexer.ts +111 -0
  26. package/ext/markdown/src/structure/MarkdownParser.ts +33 -0
  27. package/ext/markdown/src/syntax/alert.ts +46 -0
  28. package/ext/markdown/src/syntax/blockquote.ts +35 -0
  29. package/ext/markdown/src/syntax/bold.ts +11 -0
  30. package/ext/markdown/src/syntax/code.ts +11 -0
  31. package/ext/markdown/src/syntax/codeblock.ts +44 -0
  32. package/ext/markdown/src/syntax/heading.ts +14 -0
  33. package/ext/markdown/src/syntax/horizontalRule.ts +11 -0
  34. package/ext/markdown/src/syntax/image.ts +23 -0
  35. package/ext/markdown/src/syntax/italic.ts +11 -0
  36. package/ext/markdown/src/syntax/link.ts +46 -0
  37. package/ext/markdown/src/syntax/list.ts +121 -0
  38. package/ext/markdown/src/syntax/table.ts +67 -0
  39. package/ext/markdown/src/syntax/text.ts +19 -0
  40. package/ext/router/README.md +111 -17
  41. package/ext/router/package.json +10 -0
  42. package/ext/router/src/index.ts +69 -0
  43. package/ext/router/src/node/Page.ts +34 -0
  44. package/ext/router/src/node/Router.ts +191 -0
  45. package/ext/router/{node → src/node}/RouterAnchor.ts +13 -2
  46. package/ext/router/src/structure/PageBuilder.ts +24 -0
  47. package/ext/router/src/structure/Route.ts +105 -0
  48. package/ext/signal/README.md +93 -0
  49. package/ext/signal/package.json +9 -0
  50. package/ext/signal/src/index.ts +128 -0
  51. package/{src → ext/signal/src}/structure/Signal.ts +6 -10
  52. package/ext/ssr/index.ts +4 -4
  53. package/ext/ui/lib/VirtualScroll.ts +25 -0
  54. package/ext/ui/node/Accordian.ts +97 -0
  55. package/ext/ui/node/Form.ts +53 -0
  56. package/ext/ui/node/Grid.ts +0 -0
  57. package/ext/ui/node/Table.ts +43 -0
  58. package/ext/ui/node/Tabs.ts +114 -0
  59. package/ext/ui/node/Toast.ts +16 -0
  60. package/ext/ui/node/Waterfall.ts +72 -0
  61. package/ext/ui/package.json +11 -0
  62. package/package.json +6 -3
  63. package/src/core.ts +30 -60
  64. package/src/global.ts +9 -2
  65. package/src/index.ts +1 -2
  66. package/src/lib/assignProperties.ts +57 -0
  67. package/src/lib/native.ts +25 -8
  68. package/src/lib/uppercase.ts +3 -0
  69. package/src/node/$Element.ts +7 -41
  70. package/src/node/$EventTarget.ts +45 -0
  71. package/src/node/$Node.ts +60 -65
  72. package/src/node/$Virtual.ts +65 -0
  73. package/src/node.ts +7 -6
  74. package/ext/i18n/src/node/I18nText.ts +0 -35
  75. package/ext/markdown/index.ts +0 -121
  76. package/ext/router/index.ts +0 -73
  77. package/ext/router/node/Page.ts +0 -27
  78. package/ext/router/node/Route.ts +0 -54
  79. package/ext/router/node/Router.ts +0 -149
  80. package/src/lib/assign.ts +0 -38
  81. 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
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "@amateras/ui",
3
+ "peerDependencies": {
4
+ "amateras": "../../"
5
+ },
6
+ "exports": {
7
+ "./waterfall": "./node/Waterfall.ts",
8
+ "./tabs": "./node/Tabs.ts",
9
+ "./virtual-scroll": "./lib/VirtualScroll.ts"
10
+ }
11
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "amateras",
3
- "version": "0.5.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 { Signal } from "#structure/Signal";
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 { toArray } from '#lib/toArray';
8
+ import { $EventTarget, type $Event } from '#node/$EventTarget';
10
9
 
11
- const nodeNameMap: {[key: string]: Constructor<$Node>} = {}
10
+ const nodeNameMap: {[key: string]: Constructor<$EventTarget>} = {}
12
11
  const _stylesheet = new CSSStyleSheet();
13
12
 
14
- export function $<F extends (...args: any[]) => $NodeContentResolver<$Node>, N extends number>(number: N, fn: F, ...args: Parameters<F>): Repeat<ReturnType<F>, N>;
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 $<N extends Node | EventTarget>(node: N, ...args: any[]): $Node;
26
- export function $<N extends Node | EventTarget>(node: N | null | undefined, ...args: any[]): $Node | null | undefined;
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 $(tagname: string): $HTMLElement<HTMLElement>
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, NodeList)) return _Array_from(resolver).map($)
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
- type SignalProcess<T> = T extends Array<any> ? {} : T extends object ? { [key in keyof T as `${string & key}$`]: SignalFunction<T[key]> } : {};
59
- export type SignalFunction<T> = {signal: Signal<T>, set: (newValue: T | ((oldValue: T) => T)) => SignalFunction<T>} & (() => T) & SignalProcess<T>;
60
- export const signal = <T>(value: T): SignalFunction<T> => {
61
- const signal = new Signal<T>(value);
62
- const signalFn = function () { return signal.value(); }
63
- _Object_assign(signalFn, {
64
- signal,
65
- set(newValue: T) { return signal.value(newValue), signalFn; }
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
- type assign = {
100
- (resolver: [nodeName: string, $node: Constructor<$Node>][]): $;
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 { Signal } from '#structure/Signal';
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 $Parameter<T> = T | undefined | Signal<T> | Signal<T | undefined>
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
@@ -1,3 +1,2 @@
1
1
  import '#core';
2
- export * from '#core';
3
- export * from '#structure/Signal';
2
+ export * from '#core';
@@ -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
- export const forEach: forEach = <T>(arr: any, fn: any, thisArgs?: any) => arr.forEach(fn, thisArgs);
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
- // Function
32
- export const _bind = (target: Function, obj: Object) => target.bind(obj);
33
- interface forEach {
34
- <T>(arr: Array<T>, fn: (value: T, index: number, array: Array<T>) => any, thisArgs?: any): void;
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;
@@ -0,0 +1,3 @@
1
+ import { slice } from "./native";
2
+
3
+ export const uppercase = (str: string, start?: number, end?: number) => `${slice(str, 0, start)}${slice(str, start, end).toUpperCase()}${end ? slice(str, end) : ''}`
@@ -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 | Signal<any> | null | undefined}): this;
17
- attr(resolver?: {[key: string]: string | number | boolean | Signal<any> | null | undefined} | string) {
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
- const set = (value: any) => !isUndefined(value) && isNull(value) ? this.removeAttribute(key) : this.setAttribute(key, `${value}`)
22
- if (_instanceof(value, Signal)) value = value.subscribe(set).value();
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
  }