amateras 0.4.2 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/README.md +24 -25
  2. package/ext/html/node/$Anchor.ts +3 -3
  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 +28 -4
  8. package/ext/html/node/$Label.ts +12 -3
  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/I18nDictionary.ts +2 -2
  18. package/ext/i18n/src/structure/I18nTranslation.ts +35 -0
  19. package/ext/idb/README.md +127 -0
  20. package/ext/idb/package.json +13 -0
  21. package/ext/idb/src/core.ts +6 -0
  22. package/ext/idb/src/index.ts +17 -0
  23. package/ext/idb/src/lib/$IDBRequest.ts +8 -0
  24. package/ext/idb/src/structure/$IDB.ts +63 -0
  25. package/ext/idb/src/structure/$IDBCursor.ts +34 -0
  26. package/ext/idb/src/structure/$IDBIndex.ts +48 -0
  27. package/ext/idb/src/structure/$IDBStore.ts +103 -0
  28. package/ext/idb/src/structure/$IDBStoreBase.ts +30 -0
  29. package/ext/idb/src/structure/$IDBTransaction.ts +38 -0
  30. package/ext/idb/src/structure/builder/$IDBBuilder.ts +230 -0
  31. package/ext/idb/src/structure/builder/$IDBStoreBuilder.ts +100 -0
  32. package/ext/markdown/README.md +53 -0
  33. package/ext/markdown/package.json +15 -0
  34. package/ext/markdown/src/index.ts +3 -0
  35. package/ext/markdown/src/lib/type.ts +26 -0
  36. package/ext/markdown/src/lib/util.ts +21 -0
  37. package/ext/markdown/src/structure/Markdown.ts +54 -0
  38. package/ext/markdown/src/structure/MarkdownLexer.ts +111 -0
  39. package/ext/markdown/src/structure/MarkdownParser.ts +33 -0
  40. package/ext/markdown/src/syntax/alert.ts +46 -0
  41. package/ext/markdown/src/syntax/blockquote.ts +35 -0
  42. package/ext/markdown/src/syntax/bold.ts +11 -0
  43. package/ext/markdown/src/syntax/code.ts +11 -0
  44. package/ext/markdown/src/syntax/codeblock.ts +44 -0
  45. package/ext/markdown/src/syntax/heading.ts +14 -0
  46. package/ext/markdown/src/syntax/horizontalRule.ts +11 -0
  47. package/ext/markdown/src/syntax/image.ts +23 -0
  48. package/ext/markdown/src/syntax/italic.ts +11 -0
  49. package/ext/markdown/src/syntax/link.ts +46 -0
  50. package/ext/markdown/src/syntax/list.ts +121 -0
  51. package/ext/markdown/src/syntax/table.ts +67 -0
  52. package/ext/markdown/src/syntax/text.ts +19 -0
  53. package/ext/router/README.md +111 -17
  54. package/ext/router/package.json +10 -0
  55. package/ext/router/src/index.ts +69 -0
  56. package/ext/router/src/node/Page.ts +34 -0
  57. package/ext/router/src/node/Router.ts +191 -0
  58. package/ext/router/src/node/RouterAnchor.ts +24 -0
  59. package/ext/router/src/structure/PageBuilder.ts +24 -0
  60. package/ext/router/src/structure/Route.ts +105 -0
  61. package/ext/signal/README.md +93 -0
  62. package/ext/signal/package.json +9 -0
  63. package/ext/signal/src/index.ts +128 -0
  64. package/{src → ext/signal/src}/structure/Signal.ts +7 -11
  65. package/ext/ssr/index.ts +4 -4
  66. package/ext/ui/lib/VirtualScroll.ts +25 -0
  67. package/ext/ui/node/Accordian.ts +97 -0
  68. package/ext/ui/node/Form.ts +53 -0
  69. package/ext/ui/node/Grid.ts +0 -0
  70. package/ext/ui/node/Table.ts +43 -0
  71. package/ext/ui/node/Tabs.ts +114 -0
  72. package/ext/ui/node/Toast.ts +16 -0
  73. package/ext/ui/node/Waterfall.ts +72 -0
  74. package/ext/ui/package.json +11 -0
  75. package/package.json +9 -3
  76. package/src/core.ts +31 -59
  77. package/src/global.ts +12 -2
  78. package/src/index.ts +1 -2
  79. package/src/lib/assignProperties.ts +57 -0
  80. package/src/lib/native.ts +33 -11
  81. package/src/lib/sleep.ts +3 -1
  82. package/src/lib/toArray.ts +9 -0
  83. package/src/lib/trycatch.ts +17 -0
  84. package/src/lib/uppercase.ts +3 -0
  85. package/src/node/$Element.ts +7 -53
  86. package/src/node/$EventTarget.ts +45 -0
  87. package/src/node/$Node.ts +63 -55
  88. package/src/node/$Virtual.ts +65 -0
  89. package/src/node.ts +7 -6
  90. package/ext/i18n/src/node/I18nText.ts +0 -35
  91. package/ext/router/index.ts +0 -73
  92. package/ext/router/node/Page.ts +0 -27
  93. package/ext/router/node/Route.ts +0 -54
  94. package/ext/router/node/Router.ts +0 -149
  95. package/ext/router/node/RouterAnchor.ts +0 -8
  96. package/src/lib/assign.ts +0 -38
  97. package/src/lib/assignHelper.ts +0 -18
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,14 @@ 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>
19
+ type Ok<D> = [data: D, err: null];
20
+ type Err<E> = [data: null, err: E]
21
+ type Result<D, E> = Ok<D> | Err<E>
15
22
  type Repeat<T, N extends number, Acc extends T[] = []> =
16
23
  Acc['length'] extends N
17
24
  ? Acc
@@ -22,6 +29,9 @@ declare global {
22
29
  interface Node {
23
30
  readonly $: $Node
24
31
  }
32
+ interface EventTarget {
33
+ readonly $: $EventTarget
34
+ }
25
35
  interface Element {
26
36
  readonly $: $Element
27
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
@@ -1,5 +1,6 @@
1
1
  // Value
2
2
  export const _null = null;
3
+ export const _undefined = undefined;
3
4
  // Object
4
5
  export const _Object_fromEntries = Object.fromEntries;
5
6
  export const _Object_entries = Object.entries;
@@ -9,27 +10,48 @@ export const _Object_defineProperty = Object.defineProperty;
9
10
  export const _Object_getOwnPropertyDescriptors = Object.getOwnPropertyDescriptors;
10
11
  // Array
11
12
  export const _Array_from = Array.from;
12
- 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);
13
30
  // type check
14
31
  export const _typeof = (target: any, type: 'string' | 'number' | 'object' | 'boolean' | 'function' | 'bigint' | 'symbol' | 'undefined') => typeof target === type;
15
32
  export const equal = <T, V extends T>(target: T, ...args: V[]): target is V => !!args.find(a => a === target);
16
33
  export const isString = (target: any): target is string => _typeof(target, 'string');
17
- export const isNumber = (target: any): target is number => _typeof(target, 'number')
18
- export const isObject = (target: any): target is object => _typeof(target, 'object')
19
- export const isFunction = (target: any): target is Function => _typeof(target, 'function')
34
+ export const isBoolean = (target: any): target is boolean => _typeof(target, 'boolean');
35
+ export const isNumber = (target: any): target is number => _typeof(target, 'number');
36
+ export const isObject = (target: any): target is object => _typeof(target, 'object');
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)
20
39
  export const isUndefined = (target: any): target is undefined => target === undefined;
21
40
  export const isNull = (target: any): target is null => target === _null;
41
+ export const isArray = Array.isArray;
22
42
  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);
23
43
  // JSON
24
44
  export const _JSON_stringify = JSON.stringify;
25
45
  export const _JSON_parse = JSON.parse;
26
46
  // String
27
47
  export const startsWith = (target: string, ...str: string[]) => !!str.find(s => target.startsWith(s));
48
+ // String & Array
49
+ interface slice {
50
+ (target: string, start?: number, end?: number): string;
51
+ <T>(target: Array<T>, start?: number, end?: number): T[];
52
+ }
53
+ export const slice: slice = (target: any, start?: number, end?: number) => target.slice(start, end);
28
54
  // Function
29
- export const _bind = (target: Function, obj: Object) => target.bind(obj);
30
- interface forEach {
31
- <T>(arr: Array<T>, fn: (value: T, index: number, array: Array<T>) => any, thisArgs?: any): void;
32
- <T>(set: Set<T>, fn: (value: T, index: number, set: Set<T>) => any, thisArgs?: any): void;
33
- <K, V>(set: Map<K, V>, fn: (value: V, key: K, index: number, map: Map<K, V>) => any, thisArgs?: any): void;
34
- <N extends Node>(set: NodeListOf<N>, fn: (value: N, index: number, parent: NodeListOf<N>) => any, thisArgs?: any): void;
35
- }
55
+ export const _bind = <T extends Function>(target: T, obj: Object): T => target.bind(obj);
56
+ // Promise
57
+ export const _Promise = Promise;
package/src/lib/sleep.ts CHANGED
@@ -1 +1,3 @@
1
- export const sleep = async (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
1
+ import { _Promise } from "./native";
2
+
3
+ export const sleep = async (ms: number) => new _Promise(resolve => setTimeout(resolve, ms));
@@ -0,0 +1,9 @@
1
+ import { _instanceof, _Object_assign } from "./native";
2
+
3
+ export const toArray = <T>(item: OrArray<T>): T[] => _instanceof(item, Array) ? item : [item];
4
+
5
+ declare module '#core' {
6
+ export namespace $ {
7
+ export function toArray<T>(item: OrArray<T>): T[];
8
+ }
9
+ }
@@ -0,0 +1,17 @@
1
+ import { _instanceof, _JSON_stringify, _null, _Object_assign } from "./native";
2
+
3
+ export const trycatch = <D>(callback: () => D): Result<D, Error> => {
4
+ try {
5
+ return [callback(), _null];
6
+ } catch (err) {
7
+ return [_null, _instanceof(err, Error) ? err : new Error(_JSON_stringify(err))];
8
+ }
9
+ }
10
+
11
+ _Object_assign($, {trycatch})
12
+
13
+ declare module '#core' {
14
+ export namespace $ {
15
+ export function trycatch <D>(callback: () => D): Result<D, Error>
16
+ }
17
+ }
@@ -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}): this;
17
- attr(resolver?: {[key: string]: string | number | boolean | Signal<any> | null} | 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
  }
@@ -39,27 +37,11 @@ export class $Element<Ele extends Element = Element, EvMap = ElementEventMap> ex
39
37
  return this;
40
38
  }
41
39
 
42
- on<K extends keyof EvMap, Ev extends EvMap[K]>(type: K, listener: $EventListener<this, Ev> | $EventListenerObject<this, Ev>, options?: boolean | AddEventListenerOptions) {
43
- return this.addEventListener(type as string, listener as any, options);
44
- }
45
-
46
- off<K extends keyof EvMap, Ev extends EvMap[K]>(type: K, listener: $EventListener<this, Ev> | $EventListenerObject<this, Ev>, options?: boolean | EventListenerOptions) {
47
- return this.removeEventListener(type as string, listener as any, options);
48
- }
49
-
50
- once<K extends keyof EvMap, Ev extends EvMap[K]>(type: K, listener: $EventListener<this, Ev> | $EventListenerObject<this, Ev>, options?: boolean | AddEventListenerOptions) {
51
- return this.on(type, listener, {once: true})
52
- }
53
-
54
40
  toString() {
55
41
  return this.outerHTML();
56
42
  }
57
43
  }
58
44
 
59
- export type $Event<E extends $Element, Ev = any> = Ev & {currentTarget: {$: E}};
60
- export type $EventListener<E extends $Element, Ev> = (event: $Event<E, Ev>) => void;
61
- export type $EventListenerObject<E extends $Element, Ev> = { handleEvent(object: $Event<E, Ev>): void; }
62
-
63
45
  function createNode(nodeName: string) {
64
46
  return !_document
65
47
  //@ts-expect-error
@@ -67,7 +49,7 @@ function createNode(nodeName: string) {
67
49
  : _document.createElement(nodeName);
68
50
  }
69
51
 
70
- export interface $Element<Ele extends Element, EvMap> {
52
+ export interface $Element<Ele extends Element, EvMap = ElementEventMap> {
71
53
  /** {@link Element.attributes} */
72
54
  readonly attributes: NamedNodeMap;
73
55
  /** {@link Element.clientHeight} */
@@ -207,20 +189,6 @@ export interface $Element<Ele extends Element, EvMap> {
207
189
  animate(keyframes: Keyframe[] | PropertyIndexedKeyframes | null, options?: number | KeyframeAnimationOptions): Animation;
208
190
  /** {@link Element.getAnimations} */
209
191
  getAnimations(options?: GetAnimationsOptions): Animation[];
210
- /** {@link Element.append} */
211
- append(...nodes: (Node | string)[]): this;
212
- /** {@link Element.prepend} */
213
- prepend(...nodes: (Node | string)[]): this;
214
- /** {@link Element.querySelector} */
215
- querySelector<K extends keyof HTMLElementTagNameMap>(selectors: K): HTMLElementTagNameMap[K] | null;
216
- querySelector<K extends keyof SVGElementTagNameMap>(selectors: K): SVGElementTagNameMap[K] | null;
217
- querySelector<K extends keyof MathMLElementTagNameMap>(selectors: K): MathMLElementTagNameMap[K] | null;
218
- /** {@link Element.querySelectorAll} */
219
- querySelectorAll<K extends keyof HTMLElementTagNameMap>(selectors: K): NodeListOf<HTMLElementTagNameMap[K]>;
220
- querySelectorAll<K extends keyof SVGElementTagNameMap>(selectors: K): NodeListOf<SVGElementTagNameMap[K]>;
221
- querySelectorAll<K extends keyof MathMLElementTagNameMap>(selectors: K): NodeListOf<MathMLElementTagNameMap[K]>;
222
- /** {@link Element.replaceChildren} */
223
- replaceChildren(...nodes: (Node | string)[]): this;
224
192
 
225
193
  /** {@link Element.classList} */
226
194
  classList(): DOMTokenList;
@@ -383,18 +351,4 @@ export interface $Element<Ele extends Element, EvMap> {
383
351
  /** {@link ARIAMixin.role} */
384
352
  role(): string | null;
385
353
  role(role: $Parameter<string | null>): this;
386
- addEventListener<K extends keyof EvMap, Ev extends EvMap[K]>(type: K, listener: $EventListener<this, Ev> | $EventListenerObject<this, Ev>, options?: boolean | AddEventListenerOptions): this;
387
- addEventListener(type: string, listener: $EventListener<this, Event> | $EventListenerObject<this, Event>, options?: boolean | AddEventListenerOptions): this;
388
- removeEventListener<K extends keyof EvMap, Ev extends EvMap[K]>(type: K, listener: $EventListener<this, Ev> | $EventListenerObject<this, Ev>, options?: boolean | EventListenerOptions): this;
389
- removeEventListener(type: string, listener: $EventListener<this, Event> | $EventListenerObject<this, Event>, options?: boolean | EventListenerOptions): this;
390
-
391
-
392
- on(type: string, listener: $EventListener<this, Event> | $EventListenerObject<this, Event>, options?: boolean | AddEventListenerOptions): this;
393
- on<K extends keyof EvMap, Ev extends EvMap[K]>(type: K, listener: $EventListener<this, Ev> | $EventListenerObject<this, Ev>, options?: boolean | AddEventListenerOptions): this;
394
-
395
- off(type: string, listener: $EventListener<this, Event> | $EventListenerObject<this, Event>, options?: boolean | EventListenerOptions): this;
396
- off<K extends keyof EvMap, Ev extends EvMap[K]>(type: K, listener: $EventListener<this, Ev> | $EventListenerObject<this, Ev>, options?: boolean | EventListenerOptions): this;
397
-
398
- once(type: string, listener: $EventListener<this, Event> | $EventListenerObject<this, Event>, options?: boolean | AddEventListenerOptions): this;
399
- once<K extends keyof EvMap, Ev extends EvMap[K]>(type: K, listener: $EventListener<this, Ev> | $EventListenerObject<this, Ev>, options?: boolean | AddEventListenerOptions): this;
400
354
  }
@@ -0,0 +1,45 @@
1
+ import { isBoolean } from "#lib/native";
2
+
3
+ export class $EventTarget<EvMap = {}> {
4
+ node: EventTarget;
5
+ constructor(node: EventTarget) {
6
+ this.node = node;
7
+ if (node !== window) (node as Mutable<EventTarget>).$ = this;
8
+ }
9
+
10
+ on(type: string, listener: $EventListener<this, Event> | $EventListenerObject<this, Event>, options?: boolean | AddEventListenerOptions): this {
11
+ return this.addEventListener(type, listener, options);
12
+ }
13
+
14
+ off(type: string, listener: $EventListener<this, Event> | $EventListenerObject<this, Event>, options?: boolean | EventListenerOptions): this {
15
+ return this.removeEventListener(type, listener, options);
16
+ }
17
+
18
+ once(type: string, listener: $EventListener<this, Event> | $EventListenerObject<this, Event>, options?: boolean | AddEventListenerOptions): this {
19
+ return this.on(type, listener, { once: true, ...(isBoolean(options) ? {capture: options} : options ?? {}) })
20
+ }
21
+ }
22
+
23
+ export type $Event<E extends $EventTarget, Ev = any> = Ev & {currentTarget: {$: E}};
24
+ export type $EventListener<E extends $EventTarget, Ev> = (event: $Event<E, Ev>) => void;
25
+ export type $EventListenerObject<E extends $EventTarget, Ev> = { handleEvent(object: $Event<E, Ev>): void; }
26
+
27
+ export interface $EventTarget<EvMap = {}> {
28
+ /** {@link EventTarget.addEventListener} */
29
+ addEventListener<K extends keyof EvMap, Ev extends EvMap[K]>(type: K, listener: $EventListener<this, Ev> | $EventListenerObject<this, Ev>, options?: boolean | AddEventListenerOptions): this;
30
+ addEventListener(type: string, listener: $EventListener<this, Event> | $EventListenerObject<this, Event>, options?: boolean | AddEventListenerOptions): this;
31
+ /** {@link EventTarget.removeEventListener} */
32
+ removeEventListener<K extends keyof EvMap, Ev extends EvMap[K]>(type: K, listener: $EventListener<this, Ev> | $EventListenerObject<this, Ev>, options?: boolean | EventListenerOptions): this;
33
+ removeEventListener(type: string, listener: $EventListener<this, Event> | $EventListenerObject<this, Event>, options?: boolean | EventListenerOptions): this;
34
+ /** {@link EventTarget.dispatchEvent} */
35
+ dispatchEvent(event: Event): boolean;
36
+
37
+ on<K extends keyof EvMap, Ev extends EvMap[K]>(type: K, listener: $EventListener<this, Ev> | $EventListenerObject<this, Ev>, options?: boolean | AddEventListenerOptions): this;
38
+ on(type: string, listener: $EventListener<this, Event> | $EventListenerObject<this, Event>, options?: boolean | AddEventListenerOptions): this;
39
+
40
+ off<K extends keyof EvMap, Ev extends EvMap[K]>(type: K, listener: $EventListener<this, Ev> | $EventListenerObject<this, Ev>, options?: boolean | EventListenerOptions): this;
41
+ off(type: string, listener: $EventListener<this, Event> | $EventListenerObject<this, Event>, options?: boolean | EventListenerOptions): this;
42
+
43
+ once<K extends keyof EvMap, Ev extends EvMap[K]>(type: K, listener: $EventListener<this, Ev> | $EventListenerObject<this, Ev>, options?: boolean | AddEventListenerOptions): this;
44
+ once(type: string, listener: $EventListener<this, Event> | $EventListenerObject<this, Event>, options?: boolean | AddEventListenerOptions): this;
45
+ }
package/src/node/$Node.ts CHANGED
@@ -1,14 +1,15 @@
1
1
  import { chain } from "#lib/chain";
2
2
  import { _document } from "#lib/env";
3
- import { _Array_from, _instanceof, _JSON_stringify, _null, forEach, isFunction, isNull, isObject, isUndefined } from "#lib/native";
4
- import { Signal } from "#structure/Signal";
3
+ import { _Array_from, _instanceof, _JSON_stringify, _null, _Promise, forEach, isFunction, isNull, isUndefined } from "#lib/native";
4
+ import { toArray } from "#lib/toArray";
5
+ import { $EventTarget } from "./$EventTarget";
5
6
 
6
- export class $Node {
7
- node: Node & ChildNode;
7
+ export class $Node<EvMap = {}> extends $EventTarget<EvMap> {
8
+ declare node: Node & ChildNode & ParentNode;
9
+ static processors = new Set<$NodeContentProcessor>();
10
+ static setters = new Set<$NodeSetterHandler>();
8
11
  constructor(node: Node & ChildNode) {
9
- this.node = node;
10
- //@ts-expect-error
11
- this.node.$ = this;
12
+ super(node);
12
13
  }
13
14
 
14
15
  content(children: $NodeContentResolver<this>) {
@@ -20,7 +21,10 @@ export class $Node {
20
21
 
21
22
  insert(resolver: $NodeContentResolver<this>, position = -1) {
22
23
  // process nodes
23
- forEach($.toArray(resolver), resolve_child => forEach($Node.process(this, resolve_child), $node => $Node.append(this, $node, position)));
24
+ forEach(toArray(resolver), resolve_child => forEach($Node.process(this, resolve_child), $node => {
25
+ $Node.append(this, $node, position);
26
+ if (position >= 0) position++;
27
+ }));
24
28
  return this;
25
29
  }
26
30
 
@@ -33,7 +37,7 @@ export class $Node {
33
37
  replace($node: $NodeContentResolver<$Node>) {
34
38
  if ($node)
35
39
  this.replaceWith(
36
- ...$.toArray($Node.process(this, $node)).filter($node => $node).map($node => $node?.node) as Node[]
40
+ ...toArray($Node.process(this, $node)).filter($node => $node).map($node => $node?.node) as Node[]
37
41
  )
38
42
  return this;
39
43
  }
@@ -58,37 +62,18 @@ export class $Node {
58
62
  }
59
63
 
60
64
  static process<T extends $Node>($node: T, content: $NodeContentResolver<any>): Array<$Node | undefined | null> {
65
+ for (const processor of this.processors) {
66
+ const result = processor($node, content);
67
+ if (result) return result;
68
+ }
61
69
  if (isUndefined(content) || isNull(content) || _instanceof(content, $Node)) return [content];
62
70
  // is Promise
63
- if (_instanceof(content, Promise)) return [$('async').await(content, ($async, $child) => $async.replace($child as any))];
71
+ if (_instanceof(content, _Promise)) return [$('async').await(content, ($async, $child) => $async.replace($child as any))];
64
72
  // is SignalFunction or ContentHandler
65
73
  if (isFunction(content)) {
66
- const signal = (content as any).signal;
67
- if (_instanceof(signal, Signal)) {
68
- const resolver = (content as $.SignalFunction<any>)();
69
- if (_instanceof(resolver, $Node)) {
70
- // handler signal $Node result
71
- let node = resolver;
72
- const set = (value: any) => {
73
- node.replace(value);
74
- node = value;
75
- }
76
- signal.subscribe(set);
77
- return [resolver];
78
- } else {
79
- // handler signal other type result
80
- const $text = _document ? new $Text() : $('signal').attr({ type: typeof signal.value() });
81
- const set = (value: any) => $text.textContent(isObject(value) ? _JSON_stringify(value) : value);
82
- if (_instanceof($text, $Text)) $text.signals.add(signal);
83
- signal.subscribe(set);
84
- set(resolver);
85
- return [$text];
86
- }
87
- } else {
88
- const _content = content($node) as $NodeContentResolver<$Node>;
89
- if (_instanceof(_content, Promise)) return this.process($node, _content as any);
90
- else return $.toArray(_content).map(content => this.process($node, content)).flat();
91
- }
74
+ const _content = content($node) as $NodeContentResolver<$Node>;
75
+ if (_instanceof(_content, _Promise)) return this.process($node, _content as any);
76
+ else return toArray(_content).map(content => this.process($node, content)).flat();
92
77
  }
93
78
  // is nested array
94
79
  if (_instanceof(content, Array)) return content.map(c => this.process($node, c)).flat();
@@ -109,17 +94,18 @@ export class $Node {
109
94
  }
110
95
 
111
96
  export class $Text extends $Node {
112
- signals = new Set<Signal<any>>();
113
97
  constructor(textContent?: string) {
114
98
  super(new Text(textContent));
115
99
  }
116
100
  }
117
101
 
102
+ export type $NodeSetterHandler = (value: any, set: (value: any) => void) => any;
103
+ export type $NodeContentProcessor = <N extends $Node>($node: N, content: $NodeContentResolver<N>) => Array<$Node | undefined | null> | void | undefined;
118
104
  export type $NodeContentHandler<T extends $Node> = ($node: T) => OrPromise<$NodeContentResolver<T>>;
119
- export type $NodeContentTypes = $Node | string | number | boolean | $.SignalFunction<any> | null | undefined;
105
+ export type $NodeContentTypes = $Node | string | number | boolean | $.$NodeContentTypeExtends | null | undefined;
120
106
  export type $NodeContentResolver<T extends $Node> = OrPromise<$NodeContentTypes | $NodeContentHandler<T> | $NodeContentResolver<T>[]>;
121
107
 
122
- export interface $Node {
108
+ export interface $Node<EvMap = {}> extends $EventTarget<EvMap> {
123
109
  /** {@link Node.baseURI} */
124
110
  readonly baseURI: string;
125
111
  /** {@link Node.childNodes} */
@@ -144,13 +130,21 @@ export interface $Node {
144
130
  readonly parentNode?: ParentNode | null;
145
131
  /** {@link Node.previousSibling} */
146
132
  readonly previousSibling?: ChildNode | null;
133
+ /** {@link ParentNode.childElementCount} */
134
+ readonly childElementCount: number;
135
+ /** {@link ParentNode.children} */
136
+ readonly children: HTMLCollection;
137
+ /** {@link ParentNode.firstElementChild} */
138
+ readonly firstElementChild: Element | null;
139
+ /** {@link ParentNode.lastElementChild} */
140
+ readonly lastElementChild: Element | null;
147
141
 
148
142
  /** {@link Node.appendChild} */
149
143
  appendChild<T extends Node>(node: T): T;
150
144
  /** {@link Node.cloneNode} */
151
145
  cloneNode(subtree?: boolean): Node;
152
146
  /** {@link Node.compareDocumentPosition} */
153
- compareDocumentPosition(other: Node): number;
147
+ compareDocumentPosition(other: $EventTarget | Node): number;
154
148
  /** {@link Node.getRootNode} */
155
149
  getRootNode(options?: GetRootNodeOptions): Node;
156
150
  /** {@link Node.hasChildNodes} */
@@ -160,9 +154,9 @@ export interface $Node {
160
154
  /** {@link Node.isDefaultNamespace} */
161
155
  isDefaultNamespace(namespace: string | null): boolean;
162
156
  /** {@link Node.isEqualNode} */
163
- isEqualNode(otherNode: Node | null): boolean;
157
+ isEqualNode(otherNode: $EventTarget | Node | null): boolean;
164
158
  /** {@link Node.isSameNode} */
165
- isSameNode(otherNode: Node | null): boolean;
159
+ isSameNode(otherNode: $EventTarget | Node | null): boolean;
166
160
  /** {@link Node.lookupNamespaceURI} */
167
161
  lookupNamespaceURI(prefix: string | null): string | null;
168
162
  /** {@link Node.lookupPrefix} */
@@ -173,20 +167,34 @@ export interface $Node {
173
167
  removeChild<T extends Node>(child: T): T;
174
168
  /** {@link Node.replaceChild} */
175
169
  replaceChild<T extends Node>(node: Node, child: T): T;
176
- /** {@link Node.replaceChild} */
177
- after(...nodes: (Node | string)[]): this;
178
- /** {@link Node.replaceChild} */
179
- before(...nodes: (Node | string)[]): this;
180
- /** {@link Node.replaceChild} */
170
+ /** {@link Node.contains} */
171
+ contains(other: $EventTarget | Node | null | undefined): boolean;
172
+
173
+ /** {@link ChildNode.after} */
174
+ after(...nodes: ($EventTarget | Node | string)[]): this;
175
+ /** {@link ChildNode.before} */
176
+ before(...nodes: ($EventTarget | Node | string)[]): this;
177
+ /** {@link ChildNode.remove} */
181
178
  remove(): this;
182
- /** {@link Node.replaceChild} */
183
- replaceWith(...nodes: (Node | string)[]): this;
184
- /** {@link EventTarget.addEventListener} */
185
- addEventListener(type: string, callback: EventListenerOrEventListenerObject | null, options?: AddEventListenerOptions | boolean): void;
186
- /** {@link EventTarget.removeEventListener} */
187
- removeEventListener(type: string, callback: EventListenerOrEventListenerObject | null, options?: EventListenerOptions | boolean): void;
188
- /** {@link EventTarget.dispatchEvent} */
189
- dispatchEvent(event: Event): boolean;
179
+ /** {@link ChildNode.replaceWith} */
180
+ replaceWith(...nodes: ($EventTarget | Node | string)[]): this;
181
+ /** {@link ParentNode.append} */
182
+ append(...nodes: ($EventTarget | Node | string)[]): this;
183
+ /** {@link ParentNode.prepend} */
184
+ prepend(...nodes: ($EventTarget | Node | string)[]): this;
185
+ /** {@link ParentNode.querySelector} */
186
+ querySelector<K extends keyof HTMLElementTagNameMap>(selectors: K): HTMLElementTagNameMap[K] | null;
187
+ querySelector<K extends keyof SVGElementTagNameMap>(selectors: K): SVGElementTagNameMap[K] | null;
188
+ querySelector<K extends keyof MathMLElementTagNameMap>(selectors: K): MathMLElementTagNameMap[K] | null;
189
+ querySelector<E extends Element = Element>(selectors: string): E | null;
190
+ /** {@link ParentNode.querySelectorAll} */
191
+ querySelectorAll<K extends keyof HTMLElementTagNameMap>(selectors: K): NodeListOf<HTMLElementTagNameMap[K]>;
192
+ querySelectorAll<K extends keyof SVGElementTagNameMap>(selectors: K): NodeListOf<SVGElementTagNameMap[K]>;
193
+ querySelectorAll<K extends keyof MathMLElementTagNameMap>(selectors: K): NodeListOf<MathMLElementTagNameMap[K]>;
194
+ querySelectorAll<K extends keyof HTMLElementDeprecatedTagNameMap>(selectors: K): NodeListOf<HTMLElementDeprecatedTagNameMap[K]>;
195
+ querySelectorAll<E extends Element = Element>(selectors: string): NodeListOf<E>;
196
+ /** {@link ParentNode.replaceChildren} */
197
+ replaceChildren(...nodes: ($EventTarget | Node | string)[]): this;
190
198
 
191
199
  /** {@link Node.nodeValue} */
192
200
  nodeValue(nodeValue: $Parameter<string | null>): this;
@@ -0,0 +1,65 @@
1
+ import { chain } from "#lib/chain";
2
+ import { forEach, _Array_from, _instanceof, _null } from "#lib/native";
3
+ import { toArray } from "#lib/toArray";
4
+ import { $HTMLElement } from "#node/$HTMLElement";
5
+ import { $Node, type $NodeContentResolver } from "#node/$Node";
6
+
7
+ export class $Virtual<Ele extends HTMLElement = HTMLElement, EvMap = HTMLElementEventMap> extends $HTMLElement<Ele, EvMap> {
8
+ nodes = new Set<$Node>();
9
+ hiddenNodes = new Set<$Node>();
10
+ constructor(resolver: string | Ele) {
11
+ super(resolver);
12
+ }
13
+
14
+ content(children: $NodeContentResolver<this>) {
15
+ return chain(this, _null, _null, children, children => {
16
+ this.nodes.clear();
17
+ forEach(this.childNodes, node => node.remove());
18
+ this.insert(children);
19
+ })
20
+ }
21
+
22
+ insert(resolver: $NodeContentResolver<this>, position = -1) {
23
+ // process nodes
24
+ forEach(toArray(resolver), resolve_child => {
25
+ forEach($Node.process(this, resolve_child), $node => {
26
+ $Virtual.append(this, $node, position)
27
+ if (position >= 0) position++;
28
+ })
29
+ });
30
+ return this;
31
+ }
32
+
33
+ hide($node?: $Node | null) {
34
+ if ($node && this.nodes.has($node)) this.hiddenNodes.add($node);
35
+ return this;
36
+ }
37
+
38
+ show($node?: $Node | null) {
39
+ if ($node) this.hiddenNodes.delete($node);
40
+ return this;
41
+ }
42
+
43
+ render() {
44
+ // remove hidden node
45
+ forEach(this.childNodes, node => this.hiddenNodes.has($(node)) && node.remove());
46
+ // add visible node with position
47
+ forEach(this.nodes, ($node, i) => {
48
+ if (
49
+ !this.hiddenNodes.has($node) // node is not hidden
50
+ && !$node.inDOM() // node is not in dom tree
51
+ && $(this.childNodes).at(i) !== $node // node not matched at position
52
+ ) $Node.append(this, $node, i);
53
+ })
54
+ return this;
55
+ }
56
+
57
+ static append($node: $Virtual, child: $Node | undefined | null, position: number) {
58
+ if (child) {
59
+ const childList = _Array_from($node.nodes);
60
+ if (!childList.at(position)) childList.push(child);
61
+ else childList.splice(position >= 0 ? position : childList.length + 1 + position, 0, child);
62
+ $node.nodes = new Set(childList);
63
+ }
64
+ }
65
+ }
package/src/node.ts CHANGED
@@ -1,10 +1,11 @@
1
1
  import { $HTMLElement } from '#node/$HTMLElement';
2
- import { assignHelper } from '#lib/assignHelper';
2
+ import { assignProperties } from '#lib/assignProperties';
3
3
  import { $Element } from '#node/$Element';
4
4
  import { $Node, $Text } from '#node/$Node';
5
+ import { $EventTarget } from '#node/$EventTarget';
5
6
 
6
- assignHelper(EventTarget, $Node);
7
- assignHelper(Node, $Node);
8
- assignHelper(Text, $Text);
9
- assignHelper(Element, $Element);
10
- assignHelper(HTMLElement, $HTMLElement);
7
+ assignProperties(EventTarget, $EventTarget);
8
+ assignProperties(Node, $Node);
9
+ assignProperties(Text, $Text);
10
+ assignProperties(Element, $Element);
11
+ assignProperties(HTMLElement, $HTMLElement);