amateras 0.3.0 → 0.4.0

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