amateras 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/README.md +25 -7
  2. package/ext/css/README.md +19 -0
  3. package/ext/css/src/index.ts +395 -322
  4. package/ext/css/src/lib/colorAssign.ts +6 -0
  5. package/ext/css/src/lib/colors/amber.ts +25 -0
  6. package/ext/css/src/lib/colors/blackwhite.ts +13 -0
  7. package/ext/css/src/lib/colors/blue.ts +25 -0
  8. package/ext/css/src/lib/colors/cyan.ts +25 -0
  9. package/ext/css/src/lib/colors/emerald.ts +25 -0
  10. package/ext/css/src/lib/colors/fuchsia.ts +25 -0
  11. package/ext/css/src/lib/colors/gray.ts +25 -0
  12. package/ext/css/src/lib/colors/green.ts +25 -0
  13. package/ext/css/src/lib/colors/indigo.ts +25 -0
  14. package/ext/css/src/lib/colors/lime.ts +25 -0
  15. package/ext/css/src/lib/colors/neutral.ts +25 -0
  16. package/ext/css/src/lib/colors/orange.ts +25 -0
  17. package/ext/css/src/lib/colors/pink.ts +25 -0
  18. package/ext/css/src/lib/colors/purple.ts +25 -0
  19. package/ext/css/src/lib/colors/red.ts +25 -0
  20. package/ext/css/src/lib/colors/rose.ts +25 -0
  21. package/ext/css/src/lib/colors/sky.ts +25 -0
  22. package/ext/css/src/lib/colors/slate.ts +25 -0
  23. package/ext/css/src/lib/colors/stone.ts +25 -0
  24. package/ext/css/src/lib/colors/teal.ts +25 -0
  25. package/ext/css/src/lib/colors/violet.ts +25 -0
  26. package/ext/css/src/lib/colors/yellow.ts +25 -0
  27. package/ext/css/src/lib/colors/zinc.ts +25 -0
  28. package/ext/css/src/lib/colors.ts +23 -0
  29. package/ext/css/src/structure/$CSSContainerRule.ts +13 -0
  30. package/ext/css/src/structure/$CSSKeyframesRule.ts +1 -5
  31. package/ext/css/src/structure/$CSSMediaRule.ts +3 -23
  32. package/ext/css/src/structure/$CSSRule.ts +6 -18
  33. package/ext/css/src/structure/$CSSStyleRule.ts +5 -14
  34. package/ext/css/src/structure/$CSSVariable.ts +3 -3
  35. package/ext/html/html.ts +1 -13
  36. package/ext/html/node/$Anchor.ts +31 -1
  37. package/ext/html/node/$Image.ts +54 -1
  38. package/ext/html/node/$Input.ts +154 -1
  39. package/ext/html/node/$OptGroup.ts +8 -1
  40. package/ext/html/node/$Option.ts +25 -1
  41. package/ext/html/node/$Select.ts +61 -1
  42. package/ext/i18n/README.md +53 -0
  43. package/ext/i18n/package.json +10 -0
  44. package/ext/i18n/src/index.ts +54 -0
  45. package/ext/i18n/src/node/I18nText.ts +35 -0
  46. package/ext/i18n/src/structure/I18n.ts +40 -0
  47. package/ext/i18n/src/structure/I18nDictionary.ts +31 -0
  48. package/ext/markdown/index.ts +123 -0
  49. package/ext/router/index.ts +13 -4
  50. package/ext/router/node/Page.ts +1 -0
  51. package/ext/router/node/Route.ts +4 -3
  52. package/ext/router/node/Router.ts +62 -17
  53. package/ext/router/node/RouterAnchor.ts +1 -1
  54. package/ext/ssr/index.ts +7 -5
  55. package/ext/ui/lib/VirtualScroll.ts +24 -0
  56. package/ext/ui/node/Accordian.ts +97 -0
  57. package/ext/ui/node/Tabs.ts +114 -0
  58. package/ext/ui/node/Toast.ts +16 -0
  59. package/ext/ui/node/Waterfall.ts +73 -0
  60. package/ext/ui/package.json +11 -0
  61. package/package.json +6 -7
  62. package/src/core.ts +36 -19
  63. package/src/global.ts +4 -0
  64. package/src/lib/assign.ts +12 -12
  65. package/src/lib/assignHelper.ts +2 -2
  66. package/src/lib/chain.ts +3 -0
  67. package/src/lib/debounce.ts +7 -0
  68. package/src/lib/env.ts +2 -0
  69. package/src/lib/native.ts +22 -24
  70. package/src/lib/randomId.ts +1 -1
  71. package/src/lib/sleep.ts +1 -1
  72. package/src/node/$Element.ts +301 -35
  73. package/src/node/$HTMLElement.ts +94 -1
  74. package/src/node/$Node.ts +148 -54
  75. package/src/node/$Virtual.ts +58 -0
  76. package/src/{node/node.ts → node.ts} +2 -4
  77. package/src/structure/Signal.ts +3 -3
  78. package/ext/css/src/structure/$CSSKeyframeRule.ts +0 -14
@@ -0,0 +1,114 @@
1
+ import { _instanceof, isUndefined } from "amateras/lib/native";
2
+ import { $HTMLElement } from "amateras/node/$HTMLElement";
3
+ import type { $Node } from "amateras/node/$Node";
4
+
5
+ $.style('tabs,tabs-container,tabs-list,tabs-content{display: block}')
6
+
7
+ export class Tabs extends $HTMLElement {
8
+ #value: null | string = null;
9
+ currentContent: null | TabsContent = null;
10
+ $container: null | TabsContainer = null;
11
+ $list: null | TabsList = null;
12
+ constructor() {
13
+ super('tabs');
14
+ }
15
+
16
+ value(): string | null;
17
+ value(value: string | undefined): this;
18
+ value(value?: string) {
19
+ return chain(this, arguments, () => this.#value, value, value => {
20
+ this.#value = value;
21
+ this.$container?.content(this.$container.contentMap.get(value));
22
+ this.$list?.check();
23
+ })
24
+ }
25
+ }
26
+
27
+ export class TabsContainer extends $HTMLElement {
28
+ $tabs?: Tabs;
29
+ contentMap = new Map<string, TabsContent>();
30
+ constructor($tabs?: Tabs) {
31
+ super('tabs-container');
32
+ this.$tabs = $tabs;
33
+ }
34
+
35
+ mounted($parent: $Node) {
36
+ if (_instanceof($parent, Tabs)) this.$tabs = $parent;
37
+ if (this.$tabs) {
38
+ this.$tabs.$container = this;
39
+ this.content(this.contentMap.get(this.$tabs.value() ?? ''))
40
+ }
41
+ return this;
42
+ }
43
+ }
44
+
45
+ export class TabsContent extends $HTMLElement {
46
+ #value: string;
47
+ $container: null | TabsContainer = null;
48
+ constructor(value: string) {
49
+ super('tabs-content');
50
+ this.#value = value
51
+ }
52
+
53
+ value(): string;
54
+ value(value: string): this;
55
+ value(value?: string) {
56
+ return chain(this, arguments, () => this.#value, value, value => {
57
+ this.#value = value;
58
+ this.$container?.contentMap.set(value, this).delete(this.#value ?? '')
59
+ })
60
+ }
61
+
62
+ mounted($parent: $Node) {
63
+ if (!_instanceof($parent, TabsContainer)) return this;
64
+ if ($parent && this.#value) {
65
+ this.$container = $parent;
66
+ $parent.contentMap.set(this.#value, this);
67
+ }
68
+ return this;
69
+ }
70
+ }
71
+
72
+ export class TabsList extends $HTMLElement {
73
+ $tabs?: null | Tabs = null;
74
+ triggers = new Map<string, TabsTrigger>();
75
+ constructor($tabs?: Tabs) {
76
+ super('tabs-list');
77
+ this.$tabs = $tabs;
78
+ this.on('click', _ => this.check())
79
+ }
80
+
81
+ check() {
82
+ this.triggers.forEach($trigger => $trigger.attr({selected: $trigger.value() === this.$tabs?.value() ? '' : null}))
83
+ return this;
84
+ }
85
+
86
+ mounted($parent: $Node): this {
87
+ if (_instanceof($parent, Tabs)) this.$tabs = $parent, $parent.$list = this;
88
+ if (this.$tabs) this.childNodes.forEach(child => $(child).is(TabsTrigger)?.use($child => {
89
+ this.triggers.set($child.value(), $child);
90
+ $child.$tabs = this.$tabs;
91
+ }));
92
+ return this;
93
+ }
94
+ }
95
+
96
+ export class TabsTrigger extends $HTMLElement {
97
+ #value: string;
98
+ $tabs?: null | Tabs = null;
99
+ constructor(value: string) {
100
+ super('tabs-trigger');
101
+ this.#value = value;
102
+ this.on('click', _ => this.$tabs?.value(this.#value ?? undefined))
103
+ }
104
+
105
+ value(): string;
106
+ value(value: string): this;
107
+ value(value?: string) {
108
+ return chain(this, arguments, () => this.#value, value, value => this.#value = value)
109
+ }
110
+ }
111
+
112
+ function chain<T, R, V>(_this: T, args: IArguments, get: () => R, value: V, set: (value: Exclude<V, undefined>) => any) {
113
+ return !args.length ? get() : isUndefined(value) ? _this : (set(value as any), _this);
114
+ }
@@ -0,0 +1,16 @@
1
+ import { _document } from "../../../src/lib/env";
2
+ import { $HTMLElement } from "../../../src/node/$HTMLElement";
3
+
4
+ $.style('toast{position:absolute}')
5
+
6
+ export class Toast extends $HTMLElement {
7
+ constructor() {
8
+ super('toast');
9
+ }
10
+
11
+ popup(duration = 3000) {
12
+ $(_document.body).insert(this);
13
+ setTimeout(() => this.remove(), duration)
14
+ return this;
15
+ }
16
+ }
@@ -0,0 +1,73 @@
1
+ import { _Array_from, _instanceof, equal, forEach, isNumber } from "amateras/lib/native";
2
+ import { $HTMLElement } from "amateras/node/$HTMLElement";
3
+ import { $Element } from "amateras/node/$Element";
4
+ import { $Virtual } from "amateras/node/$Virtual";
5
+
6
+ const getRect = (el: $Element) => el.getBoundingClientRect();
7
+ const px = (value: number) => `${value}px`;
8
+ $.style(`waterfall { display: block; position: relative }`)
9
+
10
+ export class Waterfall extends $Virtual {
11
+ #column = 1;
12
+ #gap = 0;
13
+ #width = 0;
14
+ constructor() {
15
+ super('waterfall');
16
+ new ResizeObserver(_ => this.inDOM() && this.#width !== getRect(this).width && (this.dispatchEvent(new Event('resize', {cancelable: true})) && this.layout())).observe(this.node);
17
+ }
18
+
19
+ column(): number;
20
+ column(column: $Parameter<number>): this;
21
+ column(column?: $Parameter<number>) {
22
+ if (!arguments.length) return this.#column;
23
+ if (isNumber(column)) this.#column = column;
24
+ return this;
25
+ }
26
+
27
+ gap(): number;
28
+ gap(gap: $Parameter<number>): this;
29
+ gap(gap?: $Parameter<number>) {
30
+ if (!arguments.length) return this.#gap;
31
+ if (isNumber(gap)) this.#gap = gap;
32
+ return this;
33
+ }
34
+
35
+ layout() {
36
+ const items = _Array_from(this.nodes).map(item => item);
37
+ const { width } = getRect(this);
38
+ this.#width = width;
39
+ const columnCount = this.#column;
40
+ const gap = this.#gap;
41
+ const columnWidth = ((width - ((columnCount - 1) * gap)) / columnCount);
42
+ const columns = _Array_from({length: columnCount}).map((_, i) => ({ i, h: 0, x: i * (columnWidth + gap) }))
43
+ const getColumnByHeight = (i: number) => columns.sort((a, b) => a.h - b.h ? a.h - b.h : a.i - b.i).at(i) as typeof columns[number];
44
+ forEach(items, item => {
45
+ if (!_instanceof(item, $HTMLElement)) return;
46
+ item.attr();
47
+ const { height, width } = item.attr();
48
+ const shortestSection = getColumnByHeight(0);
49
+ item.style({
50
+ position: 'absolute',
51
+ top: px(shortestSection.h),
52
+ left: px(shortestSection.x),
53
+ width: px(columnWidth),
54
+ });
55
+ if (width && height) {
56
+ // get ratio from attributes and calculate item's height
57
+ let itemHeight = columnWidth / (+width / +height);
58
+ item.style({ height: px(itemHeight) })
59
+ shortestSection.h += +itemHeight + gap;
60
+ } else {
61
+ item.style({ visibility: 'hidden', height: '' })
62
+ if (this.hiddenNodes.has(item)) this.show(item).render().hide(item);
63
+ let itemHeight = getRect(item).height;
64
+ item.style({visibility: '', height: px(itemHeight)})
65
+ shortestSection.h += +itemHeight + gap;
66
+ }
67
+ })
68
+ this.render();
69
+ this.style({ height: px(getColumnByHeight(-1).h) });
70
+ this.dispatchEvent(new Event('layout'))
71
+ return this;
72
+ }
73
+ }
@@ -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.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Amateras is a DOM Utility library.",
5
5
  "module": "index.ts",
6
6
  "type": "module",
@@ -25,20 +25,19 @@
25
25
  "exports": {
26
26
  ".": "./src/index.ts",
27
27
  "./core": "./src/core.ts",
28
- "./node": "./src/node/node.ts",
29
28
  "./node/*": "./src/node/*.ts",
30
29
  "./lib/*": "./src/lib/*.ts",
31
30
  "./structure/*": "./src/structure/*.ts",
32
31
  "./html": "./ext/html/html.ts",
33
32
  "./html/*": "./ext/html/node/*.ts",
34
33
  "./css": "./ext/css/src/index.ts",
34
+ "./css/colors": "./ext/css/src/lib/colors.ts",
35
+ "./css/color/*": "./ext/css/src/lib/colors/*.ts",
35
36
  "./router": "./ext/router/index.ts",
36
- "./ssr": "./ext/ssr/index.ts"
37
+ "./ssr": "./ext/ssr/index.ts",
38
+ "./i18n": "./ext/i18n/src/index.ts"
37
39
  },
38
40
  "workspaces": [
39
41
  "./ext/*"
40
- ],
41
- "peerDependencies": {
42
- "@amateras/css": "./ext/css"
43
- }
42
+ ]
44
43
  }
package/src/core.ts CHANGED
@@ -1,41 +1,58 @@
1
1
  import './global';
2
+ import './node';
2
3
  import { Signal } from "#structure/Signal";
3
4
  import { $Element, type $Event } from "#node/$Element";
4
- import { $Node, type $NodeContentTypes } from '#node/$Node';
5
- import '#node/node';
6
- import { _instanceof, isString, isFunction, _Object_assign, isObject, isNull, _Object_entries, _Object_defineProperty } from '#lib/native';
7
- import type { $HTMLElement } from '#node/$HTMLElement';
5
+ import { $Node, type $NodeContentResolver, type $NodeContentTypes } from '#node/$Node';
6
+ import { _instanceof, isString, isFunction, _Object_assign, isObject, isNull, _Object_entries, _Object_defineProperty, forEach, isNumber, _Array_from, isUndefined } from '#lib/native';
7
+ import { $HTMLElement } from '#node/$HTMLElement';
8
+ import { _document } from '#lib/env';
8
9
 
9
10
  const nodeNameMap: {[key: string]: Constructor<$Node>} = {}
11
+ const _stylesheet = new CSSStyleSheet();
10
12
 
11
- export function $<F extends (...args: any[]) => $Node>(fn: F, ...args: Parameters<F>): ReturnType<F>;
12
- export function $<C extends $NodeContentTypes | undefined | void, F extends () => C, P extends Parameters<F>>(fn: F, ...args: any[]): C;
13
- export function $<N extends $Node, T extends Constructor<N>, P extends ConstructorParameters<T>>(construct: T, ...args: P): N;
13
+ export function $<F extends (...args: any[]) => $NodeContentResolver<$Node>, N extends number>(number: N, fn: F, ...args: Parameters<F>): Repeat<ReturnType<F>, N>;
14
+ export function $<F extends (...args: any[]) => $NodeContentResolver<$Node>>(fn: F, ...args: Parameters<F>): ReturnType<F>;
15
+ export function $<T extends Constructor<$Node>, P extends ConstructorParameters<T>, N extends number>(number: N, construct: T, ...args: P): Repeat<InstanceType<T>, N>;
16
+ export function $<T extends Constructor<$Node>, P extends ConstructorParameters<T>>(construct: T, ...args: P): InstanceType<T>;
17
+ export function $(nodes: NodeListOf<Node | ChildNode>): $Node[];
14
18
  export function $<N extends $Node>($node: N, ...args: any[]): N;
19
+ export function $<N extends $Node>($node: N | null | undefined, ...args: any[]): N | null | undefined;
20
+ export function $<H extends HTMLElement>(element: H, ...args: any[]): $HTMLElement<H>;
21
+ export function $<H extends HTMLElement>(element: H | null | undefined, ...args: any[]): $HTMLElement<H> | null | undefined;
15
22
  export function $<E extends Element>(element: E, ...args: any[]): $Element<E>;
23
+ export function $<E extends Element>(element: E | null | undefined, ...args: any[]): $Element<E> | null | undefined;
24
+ export function $<N extends Node | EventTarget>(node: N, ...args: any[]): $Node;
25
+ export function $<N extends Node | EventTarget>(node: N | null | undefined, ...args: any[]): $Node | null | undefined;
16
26
  export function $<K extends TemplateStringsArray>(string: K, ...values: any[]): $NodeContentTypes[];
27
+ export function $<K extends keyof HTMLElementTagNameMap, N extends number>(number: N, tagname: K): Repeat<$HTMLElement<HTMLElementTagNameMap[K]>, N>;
17
28
  export function $<K extends keyof HTMLElementTagNameMap>(tagname: K): $HTMLElement<HTMLElementTagNameMap[K]>;
18
- export function $<H extends HTMLElement>(tagname: $Event<H>): $HTMLElement<H>;
19
- export function $<E extends Element>(tagname: $Event<E>): $Element<E>;
29
+ export function $<Ev extends $Event<$Element, Event>>(event: Ev): Ev['currentTarget']['$'];
30
+ export function $<N extends number>(number: N, tagname: string): Repeat<$HTMLElement<HTMLElement>, N>;
20
31
  export function $(tagname: string): $HTMLElement<HTMLElement>
21
- export function $(resolver: string | Element | $Node | Function | TemplateStringsArray | Event, ...args: any[]) {
32
+ export function $(resolver: string | number | null | undefined | Element | HTMLElement | $Node | Function | TemplateStringsArray | Event | NodeListOf<Node | ChildNode>, ...args: any[]) {
33
+ if (isNull(resolver) || isUndefined(resolver)) return null;
22
34
  if (_instanceof(resolver, $Node)) return resolver;
23
35
  if (isString(resolver) && nodeNameMap[resolver]) return new nodeNameMap[resolver](...args);
24
36
  if (isFunction(resolver))
25
- if (resolver.prototype?.constructor) return resolver.prototype.constructor(...args);
37
+ if (resolver.prototype?.constructor) return new resolver.prototype.constructor(...args);
26
38
  else return resolver(...args);
27
39
  if (resolver instanceof Array) {
28
40
  const iterate = args.values();
29
41
  return resolver.map(str => [str ?? undefined, iterate.next().value]).flat().filter(item => item);
30
42
  }
31
43
  if (_instanceof(resolver, Node) && _instanceof(resolver.$, $Node)) return resolver.$;
32
- if (_instanceof(resolver, Event)) return $(resolver.currentTarget as Element)
33
- return new $Element(resolver);
44
+ if (_instanceof(resolver, Event)) return $(resolver.currentTarget as Element);
45
+ if (isNumber(resolver)) return _Array_from({length: resolver}).map(_ => $(args[0], ...args.slice(1)));
46
+ if (_instanceof(resolver, HTMLElement)) return new $HTMLElement(resolver);
47
+ if (_instanceof(resolver, Element)) return new $Element(resolver);
48
+ if (_instanceof(resolver, NodeList)) return _Array_from(resolver).map($)
49
+ return new $HTMLElement(resolver);
34
50
  }
35
51
 
36
52
  export namespace $ {
37
- export const stylesheet = new CSSStyleSheet();
38
- document?.adoptedStyleSheets.push(stylesheet);
53
+ export const stylesheet = _stylesheet;
54
+ _document.adoptedStyleSheets.push(_stylesheet);
55
+ export const style = _stylesheet.insertRule.bind(_stylesheet);
39
56
  type SignalProcess<T> = T extends Array<any> ? {} : T extends object ? { [key in keyof T as `${string & key}$`]: SignalFunction<T[key]> } : {};
40
57
  export type SignalFunction<T> = {signal: Signal<T>, set: (newValue: T | ((oldValue: T) => T)) => SignalFunction<T>} & (() => T) & SignalProcess<T>;
41
58
  export function signal<T>(value: T): SignalFunction<T>
@@ -59,7 +76,7 @@ export namespace $ {
59
76
  export type ComputeFunction<T> = ({(): T}) & { signal: Signal<T> };
60
77
  export function compute<T>(process: () => T) {
61
78
  let subscribed = false;
62
- const signalFn: SignalFunction<any> = $.signal(null);
79
+ const signalFn: SignalFunction<any> = signal(null);
63
80
  function computeFn() {
64
81
  if (!subscribed) return signalFn.set(subscribe())();
65
82
  else return signalFn.set(process())();
@@ -74,7 +91,7 @@ export namespace $ {
74
91
  subscribed = true;
75
92
  return result;
76
93
  }
77
- _Object_defineProperty(computeFn, 'signal', { value: signalFn.signal });
94
+ _Object_assign(computeFn, { signal: signalFn.signal });
78
95
  return computeFn as ComputeFunction<T>
79
96
  }
80
97
 
@@ -82,11 +99,11 @@ export namespace $ {
82
99
  export function assign(nodeName: string, $node: Constructor<$Node>): void;
83
100
  export function assign(resolver: string | [nodeName: string, $node: Constructor<$Node>][], $node?: Constructor<$Node>) {
84
101
  if (isString(resolver)) $node && (nodeNameMap[resolver] = $node);
85
- else resolver.forEach(([nodeName, $node]) => nodeNameMap[nodeName] = $node);
102
+ else forEach(resolver, ([nodeName, $node]) => nodeNameMap[nodeName] = $node);
86
103
  return $;
87
104
  }
88
105
 
89
- export function orArrayResolver<T>(item: OrArray<T>): T[] {
106
+ export function toArray<T>(item: OrArray<T>): T[] {
90
107
  return _instanceof(item, Array) ? item : [item];
91
108
  }
92
109
 
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
@@ -1,34 +1,34 @@
1
1
  import { Signal } from "../structure/Signal";
2
2
  import { _instanceof, _Object_defineProperty, isUndefined } from "./native";
3
3
 
4
- export function assign(target: any, {set, get, fn}: {
4
+ export const assign = (target: any, {set, get, fn}: {
5
5
  set?: string[],
6
6
  get?: string[],
7
7
  fn?: string[]
8
- }) {
9
- const filterAndMap = (type: 'get' | 'set' | 'fn', arr: string[] | undefined) => {
10
- return arr?.map(prop => [type, prop]) ?? []
11
- }
12
- const list = [...filterAndMap('get', get), ...filterAndMap('set', set), ...filterAndMap('fn', fn)] as [string, string][];
8
+ }) => {
9
+ const [GET, SET, FN] = ['get', 'set', 'fn'] as const;
10
+ const filterAndMap = (type: 'get' | 'set' | 'fn', arr: string[] | undefined) => arr?.map(prop => [type, prop]) ?? []
11
+ const list = [...filterAndMap(GET, get), ...filterAndMap(SET, set), ...filterAndMap(FN, fn)] as [string, string][];
13
12
  for (const [type, prop] of list) {
14
13
  _Object_defineProperty(target.prototype, prop, {
15
- ...(type === 'get' ? {
14
+ ...(type === GET ? {
16
15
  get() { return this.node[prop as any] }
17
16
  } : {
18
17
  writable: true,
19
- ...(type === 'set' ? {
18
+ ...(type === SET ? {
20
19
  // set
21
- value: function (this, args: any) {
20
+ value(this, args: any) {
22
21
  if (!arguments.length) return this.node[prop];
23
- const set = (value: any) => !isUndefined(value) && (this.node[prop] = value);
22
+ let set = (value: any) => !isUndefined(value) && (this.node[prop] = value);
24
23
  if (_instanceof(args, Signal)) args = args.subscribe(set).value();
25
24
  set(args)
26
25
  return this;
27
26
  }
28
27
  } : {
29
28
  // fn
30
- value: function (this, ...args : any[]) {
31
- return this.node[prop](...args) ?? this;
29
+ value(this, ...args : any[]) {
30
+ let result = this.node[prop](...args)
31
+ return isUndefined(result) ? this : result;
32
32
  }
33
33
  })
34
34
  }),
@@ -2,8 +2,8 @@ import type { $Node } from "#node/$Node";
2
2
  import { assign } from "./assign";
3
3
  import { _Object_entries, _Object_getOwnPropertyDescriptors } from "./native";
4
4
 
5
- export function assignHelper(object: Constructor<Node>, target: Constructor<$Node>, tagname?: string) {
6
- const {set, get, fn} = { set: [] as string[], get: [] as string[], fn: [] as string[] }
5
+ export const assignHelper = (object: Constructor<EventTarget>, target: Constructor<$Node>, tagname?: string) => {
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;
@@ -0,0 +1,3 @@
1
+ import { isUndefined } from "./native";
2
+
3
+ export const chain = <T, R, V>(_this: T, args: IArguments, get: () => R, value: V, set: (value: Exclude<V, undefined>) => any) => !args.length ? get() : isUndefined(value) ? _this : (set(value as any), _this);
@@ -0,0 +1,7 @@
1
+ export const debounce = () => {
2
+ let timer: ReturnType<typeof setTimeout>;
3
+ return (fn: Function, timeout: number) => {
4
+ if (timer) clearTimeout(timer);
5
+ timer = setTimeout(fn, timeout);
6
+ }
7
+ }
package/src/lib/env.ts ADDED
@@ -0,0 +1,2 @@
1
+ // window and document
2
+ export const _document = document;
package/src/lib/native.ts CHANGED
@@ -7,28 +7,26 @@ export const _Object_defineProperty = Object.defineProperty;
7
7
  export const _Object_getOwnPropertyDescriptors = Object.getOwnPropertyDescriptors;
8
8
  // Array
9
9
  export const _Array_from = Array.from;
10
- // typeof
11
- export function _typeof(target: any, type: 'string' | 'number' | 'object' | 'boolean' | 'function' | 'bigint' | 'symbol' | 'undefined') {
12
- return typeof target === type;
13
- }
14
- export function isString(target: any): target is string {
15
- return _typeof(target, 'string');
16
- }
17
- export function isNumber(target: any): target is number {
18
- return _typeof(target, 'number')
19
- }
20
- export function isObject(target: any): target is object {
21
- return _typeof(target, 'object')
22
- }
23
- export function isFunction(target: any): target is Function {
24
- return _typeof(target, 'function')
25
- }
26
- export function isUndefined(target: any): target is undefined {
27
- return _typeof(target, 'undefined')
28
- }
29
- export function isNull(target: any): target is null {
30
- return target === null;
31
- }
32
- export function _instanceof<T>(target: any, instance: abstract new (...args: any[]) => T): target is T {
33
- return target instanceof instance;
10
+ export const forEach: forEach = <T>(arr: any, fn: any, thisArgs?: any) => arr.forEach(fn, thisArgs);
11
+ // type check
12
+ export const _typeof = (target: any, type: 'string' | 'number' | 'object' | 'boolean' | 'function' | 'bigint' | 'symbol' | 'undefined') => typeof target === type;
13
+ export const equal = <T, V extends T>(target: T, ...args: V[]): target is V => !!args.find(a => a === target);
14
+ export const isString = (target: any): target is string => _typeof(target, 'string');
15
+ export const isNumber = (target: any): target is number => _typeof(target, 'number')
16
+ export const isObject = (target: any): target is object => _typeof(target, 'object')
17
+ export const isFunction = (target: any): target is Function => _typeof(target, 'function')
18
+ export const isUndefined = (target: any): target is undefined => _typeof(target, 'undefined')
19
+ export const isNull = (target: any): target is null => target === null;
20
+ export const _instanceof = <T extends (abstract new (...args: any[]) => any)[]>(target: any, ...instance: T): target is InstanceType<T[number]> => !!instance.find(i => target instanceof i);
21
+ // JSON
22
+ export const _JSON_stringify = JSON.stringify;
23
+ export const _JSON_parse = JSON.parse;
24
+ // String
25
+ export const startsWith = (target: string, ...str: string[]) => !!str.find(s => target.startsWith(s));
26
+
27
+ interface forEach {
28
+ <T>(arr: Array<T>, fn: (value: T, index: number, array: Array<T>) => any, thisArgs?: any): void;
29
+ <T>(set: Set<T>, fn: (value: T, index: number, set: Set<T>) => any, thisArgs?: any): void;
30
+ <K, V>(set: Map<K, V>, fn: (value: V, key: K, index: number, map: Map<K, V>) => any, thisArgs?: any): void;
31
+ <N extends Node>(set: NodeListOf<N>, fn: (value: N, index: number, parent: NodeListOf<N>) => any, thisArgs?: any): void;
34
32
  }
@@ -2,7 +2,7 @@ import { _Array_from } from "./native";
2
2
 
3
3
  const LOWER = 'abcdefghijklmnopqrstuvwxyz';
4
4
  const UPPER = LOWER.toUpperCase();
5
- export function randomId(options?: {length?: number, lettercase?: 'any' | 'lower' | 'upper'}): string {
5
+ export const randomId = (options?: {length?: number, lettercase?: 'any' | 'lower' | 'upper'}): string => {
6
6
  options = {length: 5, lettercase: 'any', ...options};
7
7
  const char = options.lettercase === 'any' ? LOWER + UPPER : options.lettercase === 'lower' ? LOWER : UPPER;
8
8
  return _Array_from({length: options.length as number}, (_, i) => {
package/src/lib/sleep.ts CHANGED
@@ -1,3 +1,3 @@
1
- export async function sleep(ms: number) {
1
+ export const sleep = async (ms: number) => {
2
2
  return new Promise(resolve => setTimeout(resolve, ms))
3
3
  }