Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
fd4caf0b4a | |||
18bbc4922a |
242
$index.ts
242
$index.ts
@ -1,242 +0,0 @@
|
|||||||
import { $State, $StateArgument, $StateOption } from "./index";
|
|
||||||
import { $Node } from "./lib/node/$Node"
|
|
||||||
import { $Document } from "./lib/node/$Document"
|
|
||||||
import { $Anchor } from "./lib/node/$Anchor";
|
|
||||||
import { $Button } from "./lib/node/$Button";
|
|
||||||
import { $Form } from "./lib/node/$Form";
|
|
||||||
import { $Input } from "./lib/node/$Input";
|
|
||||||
import { $Container } from "./lib/node/$Container";
|
|
||||||
import { $Element } from "./lib/node/$Element";
|
|
||||||
import { $Label } from "./lib/node/$Label";
|
|
||||||
import { $Image } from "./lib/node/$Image";
|
|
||||||
import { $Canvas } from "./lib/node/$Canvas";
|
|
||||||
import { $Dialog } from "./lib/node/$Dialog";
|
|
||||||
import { $View } from "./lib/node/$View";
|
|
||||||
import { $Select } from "./lib/node/$Select";
|
|
||||||
import { $Option } from "./lib/node/$Option";
|
|
||||||
import { $OptGroup } from "./lib/node/$OptGroup";
|
|
||||||
import { $Textarea } from "./lib/node/$Textarea";
|
|
||||||
import { $Util } from "./lib/$Util";
|
|
||||||
import { $HTMLElement } from "./lib/node/$HTMLElement";
|
|
||||||
import { $Async } from "./lib/node/$Async";
|
|
||||||
|
|
||||||
export type $ = typeof $;
|
|
||||||
export function $<E extends $Element = $Element>(query: `::${string}`): E[];
|
|
||||||
export function $<E extends $Element = $Element>(query: `:${string}`): E | null;
|
|
||||||
export function $(element: null): null;
|
|
||||||
export function $<K extends keyof $.TagNameTypeMap>(resolver: K): $.TagNameTypeMap[K];
|
|
||||||
export function $<K extends string>(resolver: K): $Container;
|
|
||||||
export function $<H extends HTMLElement>(htmlElement: H): $.$HTMLElementMap<H>;
|
|
||||||
export function $<H extends Element>(element: H): $Element;
|
|
||||||
export function $<N extends $Node>(node: N): N;
|
|
||||||
export function $<H extends EventTarget>(element: H): $Element;
|
|
||||||
export function $(element: null | HTMLElement | EventTarget): $Element | null;
|
|
||||||
export function $(element: undefined): undefined;
|
|
||||||
export function $(resolver: any) {
|
|
||||||
if (typeof resolver === 'undefined') return resolver;
|
|
||||||
if (resolver === null) return resolver;
|
|
||||||
if (resolver instanceof $Node) return resolver;
|
|
||||||
if (typeof resolver === 'string') {
|
|
||||||
if (resolver.startsWith('::')) return Array.from(document.querySelectorAll(resolver.replace(/^::/, ''))).map(dom => $(dom));
|
|
||||||
else if (resolver.startsWith(':')) return $(document.querySelector(resolver.replace(/^:/, '')));
|
|
||||||
else if (resolver in $.TagNameElementMap) {
|
|
||||||
const instance = $.TagNameElementMap[resolver as keyof $.TagNameElementMap]
|
|
||||||
if (instance === $HTMLElement) return new $HTMLElement(resolver);
|
|
||||||
if (instance === $Container) return new $Container(resolver);
|
|
||||||
//@ts-expect-error
|
|
||||||
return new instance();
|
|
||||||
} else return new $Container(resolver);
|
|
||||||
}
|
|
||||||
if (resolver instanceof Node) {
|
|
||||||
if (resolver.$) return resolver.$;
|
|
||||||
else return $Util.from(resolver);
|
|
||||||
}
|
|
||||||
throw `$: NOT SUPPORT TARGET ELEMENT TYPE ('${resolver}')`
|
|
||||||
}
|
|
||||||
export namespace $ {
|
|
||||||
export let anchorHandler: null | (($a: $Anchor, e: Event) => void) = null;
|
|
||||||
export let anchorPreventDefault: boolean = false;
|
|
||||||
export const TagNameElementMap = {
|
|
||||||
'document': $Document,
|
|
||||||
'body': $Container,
|
|
||||||
'a': $Anchor,
|
|
||||||
'p': $Container,
|
|
||||||
'pre': $Container,
|
|
||||||
'code': $Container,
|
|
||||||
'blockquote': $Container,
|
|
||||||
'strong': $Container,
|
|
||||||
'h1': $Container,
|
|
||||||
'h2': $Container,
|
|
||||||
'h3': $Container,
|
|
||||||
'h4': $Container,
|
|
||||||
'h5': $Container,
|
|
||||||
'h6': $Container,
|
|
||||||
'div': $Container,
|
|
||||||
'ol': $Container,
|
|
||||||
'ul': $Container,
|
|
||||||
'dl': $Container,
|
|
||||||
'li': $Container,
|
|
||||||
'input': $Input,
|
|
||||||
'label': $Label,
|
|
||||||
'button': $Button,
|
|
||||||
'form': $Form,
|
|
||||||
'img': $Image,
|
|
||||||
'dialog': $Dialog,
|
|
||||||
'canvas': $Canvas,
|
|
||||||
'view': $View,
|
|
||||||
'select': $Select,
|
|
||||||
'option': $Option,
|
|
||||||
'optgroup': $OptGroup,
|
|
||||||
'textarea': $Textarea,
|
|
||||||
'async': $Async,
|
|
||||||
}
|
|
||||||
export type TagNameElementMapType = typeof TagNameElementMap;
|
|
||||||
export interface TagNameElementMap extends TagNameElementMapType {}
|
|
||||||
export type TagNameTypeMap = {
|
|
||||||
[key in keyof $.TagNameElementMap]: InstanceType<$.TagNameElementMap[key]>;
|
|
||||||
};
|
|
||||||
export type ContainerTypeTagName = Exclude<keyof TagNameTypeMap, 'input'>;
|
|
||||||
export type SelfTypeTagName = 'input';
|
|
||||||
|
|
||||||
export type $HTMLElementMap<H extends HTMLElement> =
|
|
||||||
H extends HTMLLabelElement ? $Label
|
|
||||||
: H extends HTMLInputElement ? $Input
|
|
||||||
: H extends HTMLAnchorElement ? $Anchor
|
|
||||||
: H extends HTMLButtonElement ? $Button
|
|
||||||
: H extends HTMLFormElement ? $Form
|
|
||||||
: H extends HTMLImageElement ? $Image
|
|
||||||
: H extends HTMLFormElement ? $Form
|
|
||||||
: H extends HTMLCanvasElement ? $Canvas
|
|
||||||
: H extends HTMLDialogElement ? $Dialog
|
|
||||||
: H extends HTMLSelectElement ? $Select
|
|
||||||
: H extends HTMLOptionElement ? $Option
|
|
||||||
: H extends HTMLOptGroupElement ? $OptGroup
|
|
||||||
: H extends HTMLTextAreaElement ? $Textarea
|
|
||||||
: $Container<H>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A helper for fluent method design. Return the `instance` object when arguments length not equal 0. Otherwise, return the `value`.
|
|
||||||
* @param instance The object to return when arguments length not equal 0.
|
|
||||||
* @param args The method `arguments`.
|
|
||||||
* @param value The value to return when arguments length equal 0.
|
|
||||||
* @param action The action to execute when arguments length not equal 0.
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export function fluent<T, A, V>(instance: T, args: IArguments, value: () => V, action: (...args: any[]) => void) {
|
|
||||||
if (!args.length) return value();
|
|
||||||
action();
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function orArrayResolve<T>(multable: OrArray<T>) {
|
|
||||||
if (multable instanceof Array) return multable;
|
|
||||||
else return [multable];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function mixin(target: any, constructors: OrArray<any>) { return $Util.mixin(target, constructors) }
|
|
||||||
/**
|
|
||||||
* A helper for undefined able value and $State.set() which apply value to target.
|
|
||||||
* @param object Target object.
|
|
||||||
* @param key The key of target object.
|
|
||||||
* @param value Value of target property or parameter of method(Using Tuple to apply parameter).
|
|
||||||
* @param methodKey Variant key name when apply value on $State.set()
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export function set<O, K extends keyof O>(
|
|
||||||
object: O,
|
|
||||||
key: K,
|
|
||||||
value: O[K] extends (...args: any) => any
|
|
||||||
? (undefined | $StateArgument<Parameters<O[K]>>)
|
|
||||||
: (undefined | $StateArgument<O[K]>),
|
|
||||||
methodKey?: string) {
|
|
||||||
if (value === undefined) return;
|
|
||||||
if (value instanceof $State && object instanceof Node) {
|
|
||||||
value.use(object.$, methodKey ?? key as any);
|
|
||||||
if (object[key] instanceof Function) (object[key] as Function)(value)
|
|
||||||
else object[key] = value.value;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (object[key] instanceof Function) (object[key] as Function)(value);
|
|
||||||
else object[key] = value as any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function state<T>(value: T, options?: $StateOption<T>) {
|
|
||||||
return new $State<T>(value, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function resize(object: Blob, size: number): Promise<string> {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.onload = (e) => {
|
|
||||||
const $img = $('img');
|
|
||||||
$img.once('load', e => {
|
|
||||||
const $canvas = $('canvas');
|
|
||||||
const context = $canvas.getContext('2d');
|
|
||||||
const ratio = $img.height() / $img.width();
|
|
||||||
const [w, h] = [
|
|
||||||
ratio > 1 ? size / ratio : size,
|
|
||||||
ratio > 1 ? size : size * ratio,
|
|
||||||
]
|
|
||||||
$canvas.height(h).width(w);
|
|
||||||
context?.drawImage($img.dom, 0, 0, w, h);
|
|
||||||
resolve($canvas.toDataURL(object.type))
|
|
||||||
})
|
|
||||||
if (!e.target) throw "$.resize(): e.target is null";
|
|
||||||
$img.src(e.target.result as string);
|
|
||||||
}
|
|
||||||
reader.readAsDataURL(object);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function rem(amount: number = 1) {
|
|
||||||
return parseInt(getComputedStyle(document.documentElement).fontSize) * amount
|
|
||||||
}
|
|
||||||
|
|
||||||
export function html(html: string) {
|
|
||||||
const body = new DOMParser().parseFromString(html, 'text/html').body;
|
|
||||||
return Array.from(body.children).map(child => $(child))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**Build multiple element in once. */
|
|
||||||
export function builder<F extends BuildNodeFunction, R extends ReturnType<F>>(bulder: F, params: [...Parameters<F>][], callback?: BuilderSelfFunction<R>): R[]
|
|
||||||
export function builder<F extends BuildNodeFunction, R extends ReturnType<F>>(bulder: [F, ...Parameters<F>], size: number, callback?: BuilderSelfFunction<R>): R[]
|
|
||||||
export function builder<F extends BuildNodeFunction, R extends ReturnType<F>>(bulder: [F, ...Parameters<F>], options: ($Node | string | BuilderSelfFunction<R>)[]): R[]
|
|
||||||
export function builder<K extends $.SelfTypeTagName>(tagname: K, size: number, callback?: BuilderSelfFunction<$.TagNameTypeMap[K]>): $.TagNameTypeMap[K][]
|
|
||||||
export function builder<K extends $.SelfTypeTagName>(tagname: K, callback: BuilderSelfFunction<$.TagNameTypeMap[K]>[]): $.TagNameTypeMap[K][]
|
|
||||||
export function builder<K extends $.ContainerTypeTagName>(tagname: K, size: number, callback?: BuilderSelfFunction<$.TagNameTypeMap[K]>): $.TagNameTypeMap[K][]
|
|
||||||
export function builder<K extends $.ContainerTypeTagName>(tagname: K, options: ($Node | string | BuilderSelfFunction<$.TagNameTypeMap[K]>)[]): $.TagNameTypeMap[K][]
|
|
||||||
export function builder(tagname: any, resolver: any, callback?: BuilderSelfFunction<any>) {
|
|
||||||
if (typeof resolver === 'number') {
|
|
||||||
return Array(resolver).fill('').map(v => {
|
|
||||||
const ele = isTuppleBuilder(tagname) ? tagname[0](...tagname.slice(1) as []) : $(tagname);
|
|
||||||
if (callback) callback(ele);
|
|
||||||
return ele
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const eleArray = [];
|
|
||||||
for (const item of resolver) {
|
|
||||||
const ele = tagname instanceof Function ? tagname(...item) // tagname is function, item is params
|
|
||||||
: isTuppleBuilder(tagname) ? tagname[0](...tagname.slice(1) as [])
|
|
||||||
: $(tagname);
|
|
||||||
if (item instanceof Function) { item(ele) }
|
|
||||||
else if (item instanceof $Node || typeof item === 'string') { ele.content(item) }
|
|
||||||
eleArray.push(ele);
|
|
||||||
}
|
|
||||||
return eleArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isTuppleBuilder(target: any): target is [BuildNodeFunction, ...any] {
|
|
||||||
if (target instanceof Array && target[0] instanceof Function) return true;
|
|
||||||
else return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function registerTagName(string: string, node: {new(...args: undefined[]): $Node}) {
|
|
||||||
Object.assign($.TagNameElementMap, {[string]: node});
|
|
||||||
return $.TagNameElementMap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
type BuildNodeFunction = (...args: any[]) => $Node;
|
|
||||||
type BuilderSelfFunction<K extends $Node> = (self: K) => void;
|
|
||||||
globalThis.$ = $;
|
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,3 +0,0 @@
|
|||||||
.npmignore
|
|
||||||
bun.lockb
|
|
||||||
node_modules
|
|
44
README.md
44
README.md
@ -1,44 +0,0 @@
|
|||||||
# ElexisJS
|
|
||||||
TypeScript First Web Framework, for Humans.
|
|
||||||
> ElexisJS is still in beta test now, some breaking changes might happen very often.
|
|
||||||
|
|
||||||
## What does ElexisJS bring to developer?
|
|
||||||
1. Write website with Native JavaScript syntax and full TypeScript development experiance, no more HTML or JSX.
|
|
||||||
2. For fluent method lovers.
|
|
||||||
3. Easy to import or create extensions to extend more functional.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
1. Install from npm
|
|
||||||
```
|
|
||||||
npm i elexis
|
|
||||||
```
|
|
||||||
2. Import to your project main entry js/ts file.
|
|
||||||
```ts
|
|
||||||
import 'elexis';
|
|
||||||
```
|
|
||||||
3. Use web packaging tools like [Vite](https://vitejs.dev/) to compile your project.
|
|
||||||
|
|
||||||
## How to Create Element
|
|
||||||
Using the simple $ function to create any element with node name.
|
|
||||||
```ts
|
|
||||||
$('a');
|
|
||||||
```
|
|
||||||
> This is not jQuery selector! It looks like same but it actually create `<a>` element, not selecting them.
|
|
||||||
|
|
||||||
## Fluent method
|
|
||||||
Create and modify element in one line.
|
|
||||||
```ts
|
|
||||||
$('h1').class('title').css({color: 'red'})
|
|
||||||
```
|
|
||||||
|
|
||||||
## Build your first "Hello, world!" ElexisJS project
|
|
||||||
Let's try this in your entry file:
|
|
||||||
```ts
|
|
||||||
$(document.body).content([
|
|
||||||
$('h1').class('title').content('Hello, world!')
|
|
||||||
])
|
|
||||||
```
|
|
||||||
|
|
||||||
## Extensions
|
|
||||||
1. [@elexis/router](https://github.com/elexisjs/router): Router for Single Page App.
|
|
||||||
2. [@elexis/layout](https://github.com/elexisjs/layout): Build waterfall/justified layout with automatic compute content size and position.
|
|
BIN
icon_dark.png
Normal file
BIN
icon_dark.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 57 KiB |
BIN
icon_light.png
Normal file
BIN
icon_light.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 70 KiB |
50
index.ts
50
index.ts
@ -1,50 +0,0 @@
|
|||||||
declare global {
|
|
||||||
var $: import('./$index').$;
|
|
||||||
interface Array<T> {
|
|
||||||
detype<F extends undefined | null, O>(...types: F[]): Array<Exclude<T, F>>
|
|
||||||
}
|
|
||||||
type OrMatrix<T> = T | OrMatrix<T>[];
|
|
||||||
type OrArray<T> = T | T[];
|
|
||||||
type OrPromise<T> = T | Promise<T>;
|
|
||||||
type Mutable<T> = {
|
|
||||||
-readonly [k in keyof T]: T[k];
|
|
||||||
};
|
|
||||||
type Types = 'string' | 'number' | 'boolean' | 'object' | 'symbol' | 'bigint' | 'function' | 'undefined'
|
|
||||||
type Autocapitalize = 'none' | 'off' | 'sentences' | 'on' | 'words' | 'characters';
|
|
||||||
type SelectionDirection = "forward" | "backward" | "none";
|
|
||||||
type InputType = "button" | "checkbox" | "color" | "date" | "datetime-local" | "email" | "file" | "hidden" | "image" | "month" | "number" | "password" | "radio" | "range" | "reset" | "search" | "submit" | "tel" | "text" | "time" | "url" | "week";
|
|
||||||
type InputMode = "" | "none" | "text" | "decimal" | "numeric" | "tel" | "search" | "email" | "url";
|
|
||||||
type ButtonType = "submit" | "reset" | "button" | "menu";
|
|
||||||
type TextDirection = 'ltr' | 'rtl' | 'auto' | '';
|
|
||||||
type ImageDecoding = "async" | "sync" | "auto";
|
|
||||||
type ImageLoading = "eager" | "lazy";
|
|
||||||
type ConstructorType<T> = { new (...args: any[]): T }
|
|
||||||
interface Node {
|
|
||||||
$: import('./lib/node/$Node').$Node;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Array.prototype.detype = function <T extends undefined | null, O>(this: O[], ...types: T[]) {
|
|
||||||
return this.filter(item => {
|
|
||||||
if (!types.length) return item !== undefined;
|
|
||||||
else for (const type of types) if (typeof item !== typeof type) return false; else return true
|
|
||||||
}) as Exclude<O, T>[];
|
|
||||||
}
|
|
||||||
export * from "./$index";
|
|
||||||
export * from "./lib/node/$Node";
|
|
||||||
export * from "./lib/node/$Anchor";
|
|
||||||
export * from "./lib/node/$Element";
|
|
||||||
export * from "./lib/$NodeManager";
|
|
||||||
export * from "./lib/node/$Text";
|
|
||||||
export * from "./lib/node/$Container";
|
|
||||||
export * from "./lib/node/$Button";
|
|
||||||
export * from "./lib/node/$Form";
|
|
||||||
export * from "./lib/$EventManager";
|
|
||||||
export * from "./lib/$State";
|
|
||||||
export * from "./lib/node/$View";
|
|
||||||
export * from "./lib/node/$Select";
|
|
||||||
export * from "./lib/node/$Option";
|
|
||||||
export * from "./lib/node/$OptGroup";
|
|
||||||
export * from "./lib/node/$Textarea";
|
|
||||||
export * from "./lib/node/$Image";
|
|
||||||
export * from "./lib/node/$Async";
|
|
||||||
export * from "./lib/node/$Document";
|
|
@ -1,65 +0,0 @@
|
|||||||
export abstract class $EventMethod<EM> {
|
|
||||||
abstract events: $EventManager<EM>;
|
|
||||||
//@ts-expect-error
|
|
||||||
on<K extends keyof EM>(type: K, callback: (...args: EM[K]) => any) { this.events.on(type, callback); return this }
|
|
||||||
//@ts-expect-error
|
|
||||||
off<K extends keyof EM>(type: K, callback: (...args: EM[K]) => any) { this.events.off(type, callback); return this }
|
|
||||||
//@ts-expect-error
|
|
||||||
once<K extends keyof EM>(type: K, callback: (...args: EM[K]) => any) { this.events.once(type, callback); return this }
|
|
||||||
}
|
|
||||||
export class $EventManager<EM> {
|
|
||||||
private eventMap = new Map<string, $Event>();
|
|
||||||
register(...names: string[]) {
|
|
||||||
names.forEach(name => {
|
|
||||||
const event = new $Event(name);
|
|
||||||
this.eventMap.set(event.name, event);
|
|
||||||
})
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
delete(name: string) { this.eventMap.delete(name); return this }
|
|
||||||
//@ts-expect-error
|
|
||||||
fire<K extends keyof EM>(type: K, ...args: EM[K]) {
|
|
||||||
const event = this.get(type)
|
|
||||||
//@ts-expect-error
|
|
||||||
if (event instanceof $Event) event.fire(...args);
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
//@ts-expect-error
|
|
||||||
on<K extends keyof EM>(type: K, callback: (...args: EM[K]) => any) {
|
|
||||||
this.get(type).add(callback);
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
//@ts-expect-error
|
|
||||||
off<K extends keyof EM>(type: K, callback: (...args: EM[K]) => any) {
|
|
||||||
this.get(type).delete(callback);
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
//@ts-expect-error
|
|
||||||
once<K extends keyof EM>(type: K, callback: (...args: EM[K]) => any) {
|
|
||||||
//@ts-expect-error
|
|
||||||
const onceFn = (...args: EM[K]) => {
|
|
||||||
this.get(type).delete(onceFn);
|
|
||||||
//@ts-expect-error
|
|
||||||
callback(...args);
|
|
||||||
}
|
|
||||||
this.get(type).add(onceFn);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
get<K extends keyof EM>(type: K) {
|
|
||||||
//@ts-expect-error
|
|
||||||
const event = this.eventMap.get(type);
|
|
||||||
if (!event) throw new Error('EVENT NOT EXIST')
|
|
||||||
return event;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export class $Event {
|
|
||||||
name: string;
|
|
||||||
private callbackList = new Set<Function>()
|
|
||||||
constructor(name: string) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
fire(...args: any[]) { this.callbackList.forEach(callback => callback(...args)) }
|
|
||||||
add(callback: Function) { this.callbackList.add(callback) }
|
|
||||||
delete(callback: Function) { this.callbackList.delete(callback) }
|
|
||||||
}
|
|
@ -1,66 +0,0 @@
|
|||||||
import { $Container } from "./node/$Container";
|
|
||||||
import { $Node } from "./node/$Node";
|
|
||||||
import { $Text } from "./node/$Text";
|
|
||||||
|
|
||||||
export class $NodeManager {
|
|
||||||
$container: $Container;
|
|
||||||
$elementList = new Set<$Node>
|
|
||||||
constructor(container: $Container) {
|
|
||||||
this.$container = container;
|
|
||||||
}
|
|
||||||
|
|
||||||
add(element: $Node | string) {
|
|
||||||
if (typeof element === 'string') {
|
|
||||||
const text = new $Text(element);
|
|
||||||
this.$elementList.add(text);
|
|
||||||
(text as Mutable<$Node>).parent = this.$container;
|
|
||||||
} else {
|
|
||||||
this.$elementList.add(element);
|
|
||||||
(element as Mutable<$Node>).parent = this.$container;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
remove(element: $Node) {
|
|
||||||
if (!this.$elementList.has(element)) return this;
|
|
||||||
this.$elementList.delete(element);
|
|
||||||
(element as Mutable<$Node>).parent = undefined;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
removeAll(render = true) {
|
|
||||||
this.$elementList.forEach(ele => this.remove(ele));
|
|
||||||
if (render) this.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
replace(target: $Node, replace: $Node) {
|
|
||||||
const array = this.array
|
|
||||||
array.splice(array.indexOf(target), 1, replace);
|
|
||||||
target.remove();
|
|
||||||
this.$elementList.clear();
|
|
||||||
array.forEach(node => this.$elementList.add(node));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const [domList, nodeList] = [this.array.map(node => node.dom), Array.from(this.dom.childNodes)];
|
|
||||||
const appendedNodeList: Node[] = []; // appended node list
|
|
||||||
// Rearrange
|
|
||||||
while (nodeList.length || domList.length) { // while nodeList or domList has item
|
|
||||||
const [node, dom] = [nodeList.at(0), domList.at(0)];
|
|
||||||
if (!dom) { if (node && !appendedNodeList.includes(node)) node.remove(); nodeList.shift()}
|
|
||||||
else if (!node) { if (!dom.$.__hidden) this.dom.append(dom); domList.shift();}
|
|
||||||
else if (dom !== node) {
|
|
||||||
if (!dom.$.__hidden) { this.dom.insertBefore(dom, node); appendedNodeList.push(dom) }
|
|
||||||
domList.shift();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (dom.$.__hidden) this.dom.removeChild(dom);
|
|
||||||
domList.shift(); nodeList.shift();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get array() {return [...this.$elementList.values()]};
|
|
||||||
|
|
||||||
get dom() {return this.$container.dom}
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
import { $Node } from "./node/$Node";
|
|
||||||
|
|
||||||
export interface $StateOption<T> {
|
|
||||||
format: (value: T) => string;
|
|
||||||
}
|
|
||||||
export class $State<T> {
|
|
||||||
readonly value: T;
|
|
||||||
readonly attributes = new Map<$Node, Set<string | number | symbol>>();
|
|
||||||
options: Partial<$StateOption<T>> = {}
|
|
||||||
constructor(value: T, options?: $StateOption<T>) {
|
|
||||||
this.value = value;
|
|
||||||
if (options) this.options = options;
|
|
||||||
}
|
|
||||||
set(value: T) {
|
|
||||||
(this as Mutable<$State<T>>).value = value;
|
|
||||||
for (const [node, attrList] of this.attributes.entries()) {
|
|
||||||
for (const attr of attrList) {
|
|
||||||
//@ts-expect-error
|
|
||||||
if (node[attr] instanceof Function) {
|
|
||||||
//@ts-expect-error
|
|
||||||
if (this.options.format) node[attr](this.options.format(value))
|
|
||||||
//@ts-expect-error
|
|
||||||
else node[attr](value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
toString(): string {
|
|
||||||
if (this.options.format) return this.options.format(this.value);
|
|
||||||
return `${this.value}`
|
|
||||||
}
|
|
||||||
|
|
||||||
use<T extends $Node, K extends keyof T>($node: T, attrName: K) {
|
|
||||||
const attrList = this.attributes.get($node)
|
|
||||||
if (attrList) attrList.add(attrName);
|
|
||||||
else this.attributes.set($node, new Set<string | number | symbol>().add(attrName))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export type $StateArgument<T> = T | $State<T | undefined>;
|
|
67
lib/$Util.ts
67
lib/$Util.ts
@ -1,67 +0,0 @@
|
|||||||
import { $State } from "./$State";
|
|
||||||
import { $Container } from "./node/$Container";
|
|
||||||
import { $Document } from "./node/$Document";
|
|
||||||
import { $Node } from "./node/$Node";
|
|
||||||
import { $SVGElement } from "./node/$SVGElement";
|
|
||||||
import { $Text } from "./node/$Text";
|
|
||||||
|
|
||||||
export namespace $Util {
|
|
||||||
export function fluent<T, A, V>(instance: T, args: IArguments, value: () => V, action: (...args: any[]) => void) {
|
|
||||||
if (!args.length) return value();
|
|
||||||
action();
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function orArrayResolve<T>(multable: OrArray<T>) {
|
|
||||||
if (multable instanceof Array) return multable;
|
|
||||||
else return [multable];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function mixin(target: any, constructors: OrArray<any>) {
|
|
||||||
orArrayResolve(constructors).forEach(constructor => {
|
|
||||||
Object.getOwnPropertyNames(constructor.prototype).forEach(name => {
|
|
||||||
if (name === 'constructor') return;
|
|
||||||
Object.defineProperty(
|
|
||||||
target.prototype,
|
|
||||||
name,
|
|
||||||
Object.getOwnPropertyDescriptor(constructor.prototype, name) || Object.create(null)
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function set<O, K extends keyof O>(object: O, key: K, value: any) {
|
|
||||||
if (value !== undefined) object[key] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function state<T>(value: T) {
|
|
||||||
return new $State<T>(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function from(element: Node): $Node {
|
|
||||||
if (element.$) return element.$;
|
|
||||||
if (element.nodeName.toLowerCase() === 'body') return new $Container('body', {dom: element as HTMLBodyElement});
|
|
||||||
if (element.nodeName.toLowerCase() === '#document') return $Document.from(element as Document);
|
|
||||||
else if (element instanceof HTMLElement) {
|
|
||||||
const instance = $.TagNameElementMap[element.tagName.toLowerCase() as keyof typeof $.TagNameElementMap];
|
|
||||||
const $node = instance === $Container
|
|
||||||
? new instance(element.tagName, {dom: element})
|
|
||||||
//@ts-expect-error
|
|
||||||
: new instance({dom: element} as any);
|
|
||||||
if ($node instanceof $Container) for (const childnode of Array.from($node.dom.childNodes)) {
|
|
||||||
$node.children.add($(childnode as any));
|
|
||||||
}
|
|
||||||
return $node as $Node;
|
|
||||||
}
|
|
||||||
else if (element instanceof Text) {
|
|
||||||
const node = new $Text(element.textContent ?? '') as Mutable<$Node>;
|
|
||||||
node.dom = element;
|
|
||||||
return node as $Node;
|
|
||||||
}
|
|
||||||
else if (element instanceof SVGElement) {
|
|
||||||
if (element.tagName.toLowerCase() === 'svg') {return new $SVGElement('svg', {dom: element}) };
|
|
||||||
}
|
|
||||||
throw `$NODE.FROM: NOT SUPPORT TARGET ELEMENT TYPE (${element.nodeName})`
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
import { $Container, $ContainerOptions } from "./$Container";
|
|
||||||
|
|
||||||
export interface AnchorOptions extends $ContainerOptions {}
|
|
||||||
|
|
||||||
export class $Anchor extends $Container<HTMLAnchorElement> {
|
|
||||||
constructor(options?: AnchorOptions) {
|
|
||||||
super('a', options);
|
|
||||||
// Link Handler event
|
|
||||||
this.dom.addEventListener('click', e => {
|
|
||||||
if ($.anchorPreventDefault) e.preventDefault();
|
|
||||||
if ($.anchorHandler && !!this.href()) $.anchorHandler(this, e)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/**Set URL of anchor element. */
|
|
||||||
href(): string;
|
|
||||||
href(url: string | undefined): this;
|
|
||||||
href(url?: string | undefined) { return $.fluent(this, arguments, () => this.dom.href, () => {if (url) this.dom.href = url}) }
|
|
||||||
/**Link open with this window, new tab or other */
|
|
||||||
target(): $AnchorTarget | undefined;
|
|
||||||
target(target: $AnchorTarget | undefined): this;
|
|
||||||
target(target?: $AnchorTarget | undefined) { return $.fluent(this, arguments, () => (this.dom.target ?? undefined) as $AnchorTarget | undefined, () => {if (target) this.dom.target = target}) }
|
|
||||||
}
|
|
||||||
|
|
||||||
export type $AnchorTarget = '_blank' | '_self' | '_parent' | '_top';
|
|
@ -1,22 +0,0 @@
|
|||||||
import { $Container, $ContainerOptions } from "./$Container";
|
|
||||||
import { $Node } from "./$Node";
|
|
||||||
export interface $AsyncNodeOptions extends $ContainerOptions {}
|
|
||||||
export class $Async<N extends $Node = $Node> extends $Container {
|
|
||||||
#loaded: boolean = false;
|
|
||||||
constructor(options?: $AsyncNodeOptions) {
|
|
||||||
super('async', options)
|
|
||||||
}
|
|
||||||
|
|
||||||
await<T extends $Node = $Node>($node: Promise<T>) {
|
|
||||||
$node.then($node => this._loaded($node));
|
|
||||||
return this as $Async<T>
|
|
||||||
}
|
|
||||||
|
|
||||||
protected _loaded($node: $Node) {
|
|
||||||
this.#loaded = true;
|
|
||||||
this.replace($node)
|
|
||||||
this.dom.dispatchEvent(new Event('load'))
|
|
||||||
}
|
|
||||||
|
|
||||||
get loaded() { return this.#loaded }
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
import { $Container, $ContainerOptions } from "./$Container";
|
|
||||||
import { $State, $StateArgument } from "../$State";
|
|
||||||
export interface $ButtonOptions extends $ContainerOptions {}
|
|
||||||
export class $Button extends $Container<HTMLButtonElement> {
|
|
||||||
constructor(options?: $ButtonOptions) {
|
|
||||||
super('button', options);
|
|
||||||
}
|
|
||||||
|
|
||||||
disabled(): boolean;
|
|
||||||
disabled(disabled: $StateArgument<boolean>): this;
|
|
||||||
disabled(disabled?: $StateArgument<boolean>) { return $.fluent(this, arguments, () => this.dom.disabled, () => $.set(this.dom, 'disabled', disabled))}
|
|
||||||
|
|
||||||
type(): ButtonType;
|
|
||||||
type(type: ButtonType): this;
|
|
||||||
type(type?: ButtonType) { return $.fluent(this, arguments, () => this.dom.type as ButtonType, () => $.set(this.dom, 'type', type as any))}
|
|
||||||
|
|
||||||
checkValidity() { return this.dom.checkValidity() }
|
|
||||||
reportValidity() { return this.dom.reportValidity() }
|
|
||||||
|
|
||||||
formAction(): string;
|
|
||||||
formAction(action: string | undefined): this;
|
|
||||||
formAction(action?: string) { return $.fluent(this, arguments, () => this.dom.formAction, () => $.set(this.dom, 'formAction', action))}
|
|
||||||
|
|
||||||
formEnctype(): string;
|
|
||||||
formEnctype(enctype: string | undefined): this;
|
|
||||||
formEnctype(enctype?: string) { return $.fluent(this, arguments, () => this.dom.formEnctype, () => $.set(this.dom, 'formEnctype', enctype))}
|
|
||||||
|
|
||||||
formMethod(): string;
|
|
||||||
formMethod(method: string | undefined): this;
|
|
||||||
formMethod(method?: string) { return $.fluent(this, arguments, () => this.dom.formMethod, () => $.set(this.dom, 'formMethod', method))}
|
|
||||||
|
|
||||||
formNoValidate(): boolean;
|
|
||||||
formNoValidate(boolean: boolean | undefined): this;
|
|
||||||
formNoValidate(boolean?: boolean) { return $.fluent(this, arguments, () => this.dom.formNoValidate, () => $.set(this.dom, 'formNoValidate', boolean))}
|
|
||||||
|
|
||||||
formTarget(): string;
|
|
||||||
formTarget(target: string | undefined): this;
|
|
||||||
formTarget(target?: string) { return $.fluent(this, arguments, () => this.dom.formTarget, () => $.set(this.dom, 'formTarget', target))}
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
import { $Container, $ContainerOptions } from "./$Container";
|
|
||||||
export interface $CanvasOptions extends $ContainerOptions {}
|
|
||||||
export class $Canvas extends $Container<HTMLCanvasElement> {
|
|
||||||
constructor(options?: $CanvasOptions) {
|
|
||||||
super('canvas', options);
|
|
||||||
}
|
|
||||||
|
|
||||||
height(): number;
|
|
||||||
height(height?: number): this;
|
|
||||||
height(height?: number) { return $.fluent(this, arguments, () => this.dom.height, () => { $.set(this.dom, 'height', height)}) }
|
|
||||||
|
|
||||||
width(): number;
|
|
||||||
width(width?: number): this;
|
|
||||||
width(width?: number) { return $.fluent(this, arguments, () => this.dom.width, () => { $.set(this.dom, 'width', width)}) }
|
|
||||||
|
|
||||||
captureStream(frameRequestRate?: number) { return this.dom.captureStream(frameRequestRate) }
|
|
||||||
|
|
||||||
getContext(contextId: "2d", options?: CanvasRenderingContext2DSettings): CanvasRenderingContext2D | null;
|
|
||||||
getContext(contextId: "bitmaprenderer", options?: ImageBitmapRenderingContextSettings): ImageBitmapRenderingContext | null;
|
|
||||||
getContext(contextId: "webgl", options?: WebGLContextAttributes): WebGLRenderingContext | null;
|
|
||||||
getContext(contextId: "webgl2", options?: WebGLContextAttributes): WebGL2RenderingContext | null;
|
|
||||||
getContext(contextId: string, options?: any): RenderingContext | null { return this.dom.getContext(contextId); }
|
|
||||||
|
|
||||||
toBlob(callback: BlobCallback, type?: string, quality?: any) { this.dom.toBlob(callback, type, quality); return this;}
|
|
||||||
|
|
||||||
toDataURL(type?: string, quality?: any) { return this.dom.toDataURL(type, quality) }
|
|
||||||
|
|
||||||
transferControlToOffscreen() { return this.dom.transferControlToOffscreen() }
|
|
||||||
}
|
|
@ -1,64 +0,0 @@
|
|||||||
import { $Element, $ElementOptions } from "./$Element";
|
|
||||||
import { $NodeManager } from "../$NodeManager";
|
|
||||||
import { $Node } from "./$Node";
|
|
||||||
import { $State, $StateArgument } from "../$State";
|
|
||||||
import { $Text } from "./$Text";
|
|
||||||
import { $HTMLElement, $HTMLElementOptions } from "./$HTMLElement";
|
|
||||||
|
|
||||||
export interface $ContainerOptions extends $HTMLElementOptions {}
|
|
||||||
export class $Container<H extends HTMLElement = HTMLElement> extends $HTMLElement<H> {
|
|
||||||
readonly children: $NodeManager = new $NodeManager(this);
|
|
||||||
constructor(tagname: string, options?: $ContainerOptions) {
|
|
||||||
super(tagname, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**Replace element to this element.
|
|
||||||
* @example Element.content([$('div')])
|
|
||||||
* Element.content('Hello World')*/
|
|
||||||
content(children: $ContainerContentBuilder<this>): this { return $.fluent(this, arguments, () => this, () => {
|
|
||||||
this.children.removeAll(false);
|
|
||||||
this.insert(children);
|
|
||||||
})}
|
|
||||||
|
|
||||||
/**Insert element to this element */
|
|
||||||
insert(children: $ContainerContentBuilder<this>): this { return $.fluent(this, arguments, () => this, () => {
|
|
||||||
if (children instanceof Function) children = children(this);
|
|
||||||
children = $.orArrayResolve(children);
|
|
||||||
for (const child of children) {
|
|
||||||
if (child === undefined) continue;
|
|
||||||
if (child instanceof Array) this.insert(child)
|
|
||||||
else if (child instanceof $State) {
|
|
||||||
const ele = new $Text(child.toString());
|
|
||||||
child.use(ele, 'content');
|
|
||||||
this.children.add(ele);
|
|
||||||
} else this.children.add(child);
|
|
||||||
}
|
|
||||||
this.children.render();
|
|
||||||
})}
|
|
||||||
|
|
||||||
/**Remove all children elemetn from this element */
|
|
||||||
clear() {
|
|
||||||
this.children.removeAll();
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
//**Query selector one of child element */
|
|
||||||
$<E extends $Element>(query: string): E | null { return $(this.dom.querySelector(query)) as E | null }
|
|
||||||
|
|
||||||
//**Query selector of child elements */
|
|
||||||
$all<E extends $Element>(query: string): E[] { return Array.from(this.dom.querySelectorAll(query)).map($dom => $($dom) as E) }
|
|
||||||
|
|
||||||
get scrollHeight() { return this.dom.scrollHeight }
|
|
||||||
get scrollWidth() { return this.dom.scrollWidth }
|
|
||||||
|
|
||||||
scrollTop(): number;
|
|
||||||
scrollTop(scrollTop: $StateArgument<number> | undefined): this
|
|
||||||
scrollTop(scrollTop?: $StateArgument<number> | undefined) { return $.fluent(this, arguments, () => this.dom.scrollTop, () => $.set(this.dom, 'scrollTop', scrollTop as any))}
|
|
||||||
|
|
||||||
scrollLeft(): number;
|
|
||||||
scrollLeft(scrollLeft: $StateArgument<number> | undefined): this
|
|
||||||
scrollLeft(scrollLeft?: $StateArgument<number> | undefined) { return $.fluent(this, arguments, () => this.dom.scrollLeft, () => $.set(this.dom, 'scrollLeft', scrollLeft as any))}
|
|
||||||
}
|
|
||||||
|
|
||||||
export type $ContainerContentBuilder<P extends $Container> = OrMatrix<$ContainerContentType> | (($node: P) => OrMatrix<$ContainerContentType>)
|
|
||||||
export type $ContainerContentType = $Node | string | undefined | $State<any>
|
|
@ -1,19 +0,0 @@
|
|||||||
import { $Container, $ContainerOptions } from "./$Container";
|
|
||||||
export interface $DialogOptions extends $ContainerOptions {}
|
|
||||||
export class $Dialog extends $Container<HTMLDialogElement> {
|
|
||||||
constructor(options?: $DialogOptions) {
|
|
||||||
super('dialog', options);
|
|
||||||
}
|
|
||||||
|
|
||||||
open(): boolean;
|
|
||||||
open(open?: boolean): this;
|
|
||||||
open(open?: boolean) { return $.fluent(this, arguments, () => this.dom.open, () => $.set(this.dom, 'open', open)) }
|
|
||||||
|
|
||||||
returnValue(): string;
|
|
||||||
returnValue(returnValue?: string): this;
|
|
||||||
returnValue(returnValue?: string) { return $.fluent(this, arguments, () => this.dom.returnValue, () => $.set(this.dom, 'returnValue', returnValue)) }
|
|
||||||
|
|
||||||
close() { this.dom.close(); return this; }
|
|
||||||
show() { this.dom.show(); return this; }
|
|
||||||
showModal() { this.dom.showModal(); return this; }
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
import { $Element, $DOMRect } from "./$Element";
|
|
||||||
import { $Node } from "./$Node";
|
|
||||||
export class $Document extends $Node {
|
|
||||||
dom: Node;
|
|
||||||
constructor(document: Document) {
|
|
||||||
super()
|
|
||||||
this.dom = document;
|
|
||||||
this.dom.$ = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
domRect(target?: $Element | $DOMRect) {
|
|
||||||
const this_rect: $DOMRect = {
|
|
||||||
bottom: innerHeight,
|
|
||||||
height: innerHeight,
|
|
||||||
left: 0,
|
|
||||||
right: innerWidth,
|
|
||||||
top: 0,
|
|
||||||
width: innerWidth,
|
|
||||||
x: 0,
|
|
||||||
y: 0
|
|
||||||
};
|
|
||||||
if (!target) return this_rect;
|
|
||||||
const target_rect = target instanceof $Element ? target.dom.getBoundingClientRect() : target;
|
|
||||||
const rect: $DOMRect = {
|
|
||||||
...this_rect,
|
|
||||||
top: this_rect.top - target_rect.top,
|
|
||||||
left: this_rect.left - target_rect.left,
|
|
||||||
right: this_rect.right - target_rect.left,
|
|
||||||
bottom: this_rect.bottom - target_rect.top,
|
|
||||||
x: this_rect.x - target_rect.x,
|
|
||||||
y: this_rect.y - target_rect.y,
|
|
||||||
}
|
|
||||||
return rect;
|
|
||||||
}
|
|
||||||
|
|
||||||
static from(document: Document) {
|
|
||||||
if (document.$ instanceof $Document) return document.$
|
|
||||||
else return new $Document(document);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,113 +0,0 @@
|
|||||||
import { $Node } from "./$Node";
|
|
||||||
|
|
||||||
export interface $ElementOptions {
|
|
||||||
id?: string;
|
|
||||||
class?: string[];
|
|
||||||
dom?: HTMLElement | SVGElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class $Element<H extends HTMLElement | SVGElement = HTMLElement> extends $Node<H> {
|
|
||||||
readonly dom: H;
|
|
||||||
private static_classes = new Set<string>();
|
|
||||||
constructor(tagname: string, options?: $ElementOptions) {
|
|
||||||
super();
|
|
||||||
this.dom = this.createDom(tagname, options) as H;
|
|
||||||
this.dom.$ = this;
|
|
||||||
this.setOptions(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
private createDom(tagname: string, options?: $ElementOptions) {
|
|
||||||
if (options?.dom) return options.dom;
|
|
||||||
if (tagname === 'svg') return document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
||||||
return document.createElement(tagname);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
setOptions(options: $ElementOptions | undefined) {
|
|
||||||
this.id(options?.id)
|
|
||||||
if (options && options.class) this.class(...options.class)
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**Replace id of element. @example Element.id('customId');*/
|
|
||||||
id(): string;
|
|
||||||
id(name: string | undefined): this;
|
|
||||||
id(name?: string | undefined): this | string {return $.fluent(this, arguments, () => this.dom.id, () => $.set(this.dom, 'id', name as any))}
|
|
||||||
|
|
||||||
/**Replace list of class name to element. @example Element.class('name1', 'name2') */
|
|
||||||
class(): DOMTokenList;
|
|
||||||
class(...name: (string | undefined)[]): this;
|
|
||||||
class(...name: (string | undefined)[]): this | DOMTokenList {return $.fluent(this, arguments, () => this.dom.classList, () => {this.dom.classList.forEach(n => this.static_classes.has(n) ?? this.dom.classList.remove(n)); this.dom.classList.add(...name.detype())})}
|
|
||||||
/**Add class name to dom. */
|
|
||||||
addClass(...name: (string | undefined)[]): this {return $.fluent(this, arguments, () => this, () => {this.dom.classList.add(...name.detype())})}
|
|
||||||
/**Remove class name from dom */
|
|
||||||
removeClass(...name: (string | undefined)[]): this {return $.fluent(this, arguments, () => this, () => {this.dom.classList.remove(...name.detype())})}
|
|
||||||
|
|
||||||
staticClass(): Set<string>;
|
|
||||||
staticClass(...name: (string | undefined)[]): this;
|
|
||||||
staticClass(...name: (string | undefined)[]) {return $.fluent(this, arguments, () => this.static_classes, () => {this.removeClass(...this.static_classes); this.static_classes.clear(); this.addStaticClass(...name);})}
|
|
||||||
addStaticClass(...name: (string | undefined)[]) {return $.fluent(this, arguments, () => this, () => {name.detype().forEach(n => this.static_classes.add(n)); this.addClass(...name)})}
|
|
||||||
removeStaticClass(...name: (string | undefined)[]) {return $.fluent(this, arguments, () => this, () => {name.detype().forEach(n => this.static_classes.delete(n)); this.removeClass(...name)})}
|
|
||||||
|
|
||||||
/**Modify css of element. */
|
|
||||||
css(): CSSStyleDeclaration
|
|
||||||
css(style: Partial<CSSStyleDeclaration>): this;
|
|
||||||
css(style?: Partial<CSSStyleDeclaration>) { return $.fluent(this, arguments, () => this.dom.style, () => {Object.assign(this.dom.style, style)})}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get or set attribute from this element.
|
|
||||||
* @param qualifiedName Attribute name
|
|
||||||
* @param value Attribute value. Set `null` will remove attribute.
|
|
||||||
*/
|
|
||||||
attribute(qualifiedName: string | undefined): string | null;
|
|
||||||
attribute(qualifiedName: string | undefined, value?: string | number | boolean | null): this;
|
|
||||||
attribute(qualifiedName: string | undefined, value?: string | number | boolean | null): this | string | null {
|
|
||||||
if (!arguments.length) return null;
|
|
||||||
if (arguments.length === 1) {
|
|
||||||
if (qualifiedName === undefined) return null;
|
|
||||||
return this.dom.getAttribute(qualifiedName);
|
|
||||||
}
|
|
||||||
if (arguments.length === 2) {
|
|
||||||
if (!qualifiedName) return this;
|
|
||||||
if (value === null) this.dom.removeAttribute(qualifiedName);
|
|
||||||
else if (value !== undefined) this.dom.setAttribute(qualifiedName, `${value}`);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
tabIndex(): number;
|
|
||||||
tabIndex(tabIndex: number): this;
|
|
||||||
tabIndex(tabIndex?: number) { return $.fluent(this, arguments, () => this.dom.tabIndex, () => $.set(this.dom, 'tabIndex', tabIndex as any))}
|
|
||||||
|
|
||||||
focus() { this.dom.focus(); return this; }
|
|
||||||
blur() { this.dom.blur(); return this; }
|
|
||||||
|
|
||||||
animate(keyframes: Keyframe[] | PropertyIndexedKeyframes | null, options?: number | KeyframeAnimationOptions, callback?: (animation: Animation) => void) {
|
|
||||||
const animation = this.dom.animate(keyframes, options);
|
|
||||||
if (callback) callback(animation);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
getAnimations(options?: GetAnimationsOptions) { return this.dom.getAnimations(options) }
|
|
||||||
|
|
||||||
get dataset() { return this.dom.dataset }
|
|
||||||
|
|
||||||
domRect(target?: $Element | $DOMRect) {
|
|
||||||
const this_rect = this.dom.getBoundingClientRect();
|
|
||||||
if (!target) return this_rect;
|
|
||||||
const target_rect = target instanceof $Element ? target.dom.getBoundingClientRect() : target;
|
|
||||||
const rect: $DOMRect = {
|
|
||||||
...this_rect,
|
|
||||||
top: this_rect.top - target_rect.top,
|
|
||||||
left: this_rect.left - target_rect.left,
|
|
||||||
right: this_rect.right - target_rect.left,
|
|
||||||
bottom: this_rect.bottom - target_rect.top,
|
|
||||||
x: this_rect.x - target_rect.x,
|
|
||||||
y: this_rect.y - target_rect.y,
|
|
||||||
}
|
|
||||||
return rect;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export type $DOMRect = Omit<DOMRect, 'toJSON'>;
|
|
@ -1,44 +0,0 @@
|
|||||||
import { $Container, $ContainerOptions } from "./$Container";
|
|
||||||
export interface $FormOptions extends $ContainerOptions {}
|
|
||||||
export class $Form extends $Container<HTMLFormElement> {
|
|
||||||
constructor(options?: $FormOptions) {
|
|
||||||
super('form', options);
|
|
||||||
}
|
|
||||||
|
|
||||||
autocomplete(): AutoFill;
|
|
||||||
autocomplete(autocomplete: AutoFill | undefined): this;
|
|
||||||
autocomplete(autocomplete?: AutoFill) { return $.fluent(this, arguments, () => this.dom.autocomplete as AutoFill, () => $.set(this.dom, 'autocomplete', autocomplete as AutoFillBase))}
|
|
||||||
|
|
||||||
action(): string;
|
|
||||||
action(action: string | undefined): this;
|
|
||||||
action(action?: string) { return $.fluent(this, arguments, () => this.dom.formAction, () => $.set(this.dom, 'formAction', action))}
|
|
||||||
|
|
||||||
enctype(): string;
|
|
||||||
enctype(enctype: string | undefined): this;
|
|
||||||
enctype(enctype?: string) { return $.fluent(this, arguments, () => this.dom.formEnctype, () => $.set(this.dom, 'formEnctype', enctype))}
|
|
||||||
|
|
||||||
method(): string;
|
|
||||||
method(method: string | undefined): this;
|
|
||||||
method(method?: string) { return $.fluent(this, arguments, () => this.dom.formMethod, () => $.set(this.dom, 'formMethod', method))}
|
|
||||||
|
|
||||||
noValidate(): boolean;
|
|
||||||
noValidate(boolean: boolean | undefined): this;
|
|
||||||
noValidate(boolean?: boolean) { return $.fluent(this, arguments, () => this.dom.formNoValidate, () => $.set(this.dom, 'formNoValidate', boolean))}
|
|
||||||
|
|
||||||
acceptCharset(): string;
|
|
||||||
acceptCharset(acceptCharset: string | undefined): this;
|
|
||||||
acceptCharset(acceptCharset?: string) { return $.fluent(this, arguments, () => this.dom.acceptCharset, () => $.set(this.dom, 'acceptCharset', acceptCharset))}
|
|
||||||
|
|
||||||
target(): string;
|
|
||||||
target(target: string | undefined): this;
|
|
||||||
target(target?: string) { return $.fluent(this, arguments, () => this.dom.formTarget, () => $.set(this.dom, 'formTarget', target))}
|
|
||||||
|
|
||||||
requestSubmit() { this.dom.requestSubmit(); return this }
|
|
||||||
reset(): this { this.dom.reset(); return this }
|
|
||||||
submit() { this.dom.submit(); return this }
|
|
||||||
checkValidity() { return this.dom.checkValidity() }
|
|
||||||
reportValidity() { return this.dom.reportValidity() }
|
|
||||||
|
|
||||||
get length() { return this.dom.length }
|
|
||||||
get elements() { return Array.from(this.dom.elements).map(ele => $(ele)) }
|
|
||||||
}
|
|
@ -1,65 +0,0 @@
|
|||||||
import { $Element, $ElementOptions } from "./$Element";
|
|
||||||
|
|
||||||
export interface $HTMLElementOptions extends $ElementOptions {}
|
|
||||||
export class $HTMLElement<H extends HTMLElement = HTMLElement> extends $Element<H> {
|
|
||||||
constructor(tagname: string, options?: $HTMLElementOptions) {
|
|
||||||
super(tagname, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
autocapitalize(): Autocapitalize;
|
|
||||||
autocapitalize(autocapitalize?: Autocapitalize): this;
|
|
||||||
autocapitalize(autocapitalize?: Autocapitalize) { return $.fluent(this, arguments, () => this.dom.autocapitalize, () => $.set(this.dom, 'autocapitalize', autocapitalize as any))}
|
|
||||||
|
|
||||||
innerText(): string;
|
|
||||||
innerText(text?: string): this;
|
|
||||||
innerText(text?: string) { return $.fluent(this, arguments, () => this.dom.innerText, () => $.set(this.dom, 'innerText', text as any))}
|
|
||||||
|
|
||||||
title(): string;
|
|
||||||
title(title?: string): this;
|
|
||||||
title(title?: string) { return $.fluent(this, arguments, () => this.dom.title, () => $.set(this.dom, 'title', title as any))}
|
|
||||||
|
|
||||||
dir(): TextDirection;
|
|
||||||
dir(dir?: TextDirection): this;
|
|
||||||
dir(dir?: TextDirection) { return $.fluent(this, arguments, () => this.dom.dir, () => $.set(this.dom, 'dir', dir as any))}
|
|
||||||
|
|
||||||
translate(): boolean;
|
|
||||||
translate(translate?: boolean): this;
|
|
||||||
translate(translate?: boolean) { return $.fluent(this, arguments, () => this.dom.translate, () => $.set(this.dom, 'translate', translate as any))}
|
|
||||||
|
|
||||||
popover(): string | null;
|
|
||||||
popover(popover?: string | null): this;
|
|
||||||
popover(popover?: string | null) { return $.fluent(this, arguments, () => this.dom.popover, () => $.set(this.dom, 'popover', popover as any))}
|
|
||||||
|
|
||||||
spellcheck(): boolean;
|
|
||||||
spellcheck(spellcheck?: boolean): this;
|
|
||||||
spellcheck(spellcheck?: boolean) { return $.fluent(this, arguments, () => this.dom.spellcheck, () => $.set(this.dom, 'spellcheck', spellcheck as any))}
|
|
||||||
|
|
||||||
inert(): boolean;
|
|
||||||
inert(inert?: boolean): this;
|
|
||||||
inert(inert?: boolean) { return $.fluent(this, arguments, () => this.dom.inert, () => $.set(this.dom, 'inert', inert as any))}
|
|
||||||
|
|
||||||
lang(): string;
|
|
||||||
lang(lang?: string): this;
|
|
||||||
lang(lang?: string) { return $.fluent(this, arguments, () => this.dom.lang, () => $.set(this.dom, 'lang', lang as any))}
|
|
||||||
|
|
||||||
draggable(): boolean;
|
|
||||||
draggable(draggable?: boolean): this;
|
|
||||||
draggable(draggable?: boolean) { return $.fluent(this, arguments, () => this.dom.draggable, () => $.set(this.dom, 'draggable', draggable as any))}
|
|
||||||
|
|
||||||
hidden(): boolean;
|
|
||||||
hidden(hidden?: boolean): this;
|
|
||||||
hidden(hidden?: boolean) { return $.fluent(this, arguments, () => this.dom.hidden, () => $.set(this.dom, 'hidden', hidden as any))}
|
|
||||||
|
|
||||||
click() { this.dom.click(); return this; }
|
|
||||||
attachInternals() { return this.dom.attachInternals(); }
|
|
||||||
hidePopover() { this.dom.hidePopover(); return this; }
|
|
||||||
showPopover() { this.dom.showPopover(); return this; }
|
|
||||||
togglePopover() { this.dom.togglePopover(); return this; }
|
|
||||||
|
|
||||||
get accessKeyLabel() { return this.dom.accessKeyLabel }
|
|
||||||
get offsetHeight() { return this.dom.offsetHeight }
|
|
||||||
get offsetLeft() { return this.dom.offsetLeft }
|
|
||||||
get offsetParent() { return $(this.dom.offsetParent) }
|
|
||||||
get offsetTop() { return this.dom.offsetTop }
|
|
||||||
get offsetWidth() { return this.dom.offsetWidth }
|
|
||||||
}
|
|
@ -1,118 +0,0 @@
|
|||||||
import { $HTMLElement, $HTMLElementOptions } from "./$HTMLElement";
|
|
||||||
import { $State } from "../$State";
|
|
||||||
export interface $ImageOptions extends $HTMLElementOptions {}
|
|
||||||
export class $Image extends $HTMLElement<HTMLImageElement> {
|
|
||||||
constructor(options?: $ImageOptions) {
|
|
||||||
super('img', options);
|
|
||||||
}
|
|
||||||
|
|
||||||
async load(src: Promise<string> | string): Promise<$Image> {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
const $img = this.once('load', () => {
|
|
||||||
resolve($img)
|
|
||||||
})
|
|
||||||
if (typeof src === 'string') $img.src(src);
|
|
||||||
else src.then(src => $img.src(src));
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
static resize(src: string | File, size: number | [number, number]): Promise<string> {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
const img = new Image();
|
|
||||||
img.addEventListener('load', () => {
|
|
||||||
const canvas = document.createElement('canvas');
|
|
||||||
const context = canvas.getContext('2d');
|
|
||||||
if (!context) throw '$Image.resize: context undefined';
|
|
||||||
const ratio = img.width / img.height;
|
|
||||||
const [landscape, portrait, square] = [ratio > 1, ratio < 1, ratio === 1];
|
|
||||||
const w = size instanceof Array ? size[0] : portrait ? size : size * ratio;
|
|
||||||
const h = size instanceof Array ? size[1] : landscape ? size : size / ratio;
|
|
||||||
canvas.height = h; canvas.width = w;
|
|
||||||
context.drawImage(img, 0, 0, w, h);
|
|
||||||
resolve(canvas.toDataURL());
|
|
||||||
}, {once: true})
|
|
||||||
if (src instanceof File) {
|
|
||||||
const fr = new FileReader()
|
|
||||||
fr.addEventListener('load', () => img.src = fr.result as string)
|
|
||||||
fr.readAsDataURL(src);
|
|
||||||
} else img.src = src;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**HTMLImageElement base property */
|
|
||||||
alt(): string;
|
|
||||||
alt(alt: string): this;
|
|
||||||
alt(alt?: string) { return $.fluent(this, arguments, () => this.dom.alt, () => $.set(this.dom, 'alt', alt))}
|
|
||||||
|
|
||||||
/**HTMLImageElement base property */
|
|
||||||
crossOrigin(): string | null;
|
|
||||||
crossOrigin(crossOrigin: string | null): this;
|
|
||||||
crossOrigin(crossOrigin?: string | null) { return $.fluent(this, arguments, () => this.dom.crossOrigin, () => $.set(this.dom, 'crossOrigin', crossOrigin))}
|
|
||||||
|
|
||||||
/**HTMLImageElement base property */
|
|
||||||
decoding(): ImageDecoding;
|
|
||||||
decoding(decoding: ImageDecoding): this;
|
|
||||||
decoding(decoding?: ImageDecoding) { return $.fluent(this, arguments, () => this.dom.decoding, () => $.set(this.dom, 'decoding', decoding))}
|
|
||||||
|
|
||||||
/**HTMLImageElement base property */
|
|
||||||
height(): number;
|
|
||||||
height(height: number): this;
|
|
||||||
height(height?: number) { return $.fluent(this, arguments, () => this.dom.height, () => $.set(this.dom, 'height', height))}
|
|
||||||
|
|
||||||
/**HTMLImageElement base property */
|
|
||||||
isMap(): boolean;
|
|
||||||
isMap(isMap: boolean): this;
|
|
||||||
isMap(isMap?: boolean) { return $.fluent(this, arguments, () => this.dom.isMap, () => $.set(this.dom, 'isMap', isMap))}
|
|
||||||
|
|
||||||
/**HTMLImageElement base property */
|
|
||||||
loading(): ImageLoading;
|
|
||||||
loading(loading: ImageLoading): this;
|
|
||||||
loading(loading?: ImageLoading) { return $.fluent(this, arguments, () => this.dom.loading, () => $.set(this.dom, 'loading', loading))}
|
|
||||||
|
|
||||||
/**HTMLImageElement base property */
|
|
||||||
referrerPolicy(): string;
|
|
||||||
referrerPolicy(referrerPolicy: string): this;
|
|
||||||
referrerPolicy(referrerPolicy?: string) { return $.fluent(this, arguments, () => this.dom.referrerPolicy, () => $.set(this.dom, 'referrerPolicy', referrerPolicy))}
|
|
||||||
|
|
||||||
/**HTMLImageElement base property */
|
|
||||||
sizes(): string;
|
|
||||||
sizes(sizes: string): this;
|
|
||||||
sizes(sizes?: string) { return $.fluent(this, arguments, () => this.dom.sizes, () => $.set(this.dom, 'sizes', sizes))}
|
|
||||||
|
|
||||||
/**HTMLImageElement base property */
|
|
||||||
src(): string;
|
|
||||||
src(src?: string | $State<string | undefined>): this;
|
|
||||||
src(src?: string | $State<string | undefined>) { return $.fluent(this, arguments, () => this.dom.src, () => $.set(this.dom, 'src', src))}
|
|
||||||
|
|
||||||
/**HTMLImageElement base property */
|
|
||||||
srcset(): string;
|
|
||||||
srcset(srcset: string): this;
|
|
||||||
srcset(srcset?: string) { return $.fluent(this, arguments, () => this.dom.srcset, () => $.set(this.dom, 'srcset', srcset))}
|
|
||||||
|
|
||||||
/**HTMLImageElement base property */
|
|
||||||
useMap(): string;
|
|
||||||
useMap(useMap: string): this;
|
|
||||||
useMap(useMap?: string) { return $.fluent(this, arguments, () => this.dom.useMap, () => $.set(this.dom, 'useMap', useMap))}
|
|
||||||
|
|
||||||
/**HTMLImageElement base property */
|
|
||||||
width(): number;
|
|
||||||
width(width: number): this;
|
|
||||||
width(width?: number) { return $.fluent(this, arguments, () => this.dom.width, () => $.set(this.dom, 'width', width))}
|
|
||||||
|
|
||||||
/**HTMLImageElement base method */
|
|
||||||
decode() { return this.dom.decode() }
|
|
||||||
|
|
||||||
/**HTMLImageElement base property */
|
|
||||||
get complete() { return this.dom.complete }
|
|
||||||
/**HTMLImageElement base property */
|
|
||||||
get currentSrc() { return this.dom.currentSrc }
|
|
||||||
/**HTMLImageElement base property */
|
|
||||||
get naturalHeight() { return this.dom.naturalHeight }
|
|
||||||
/**HTMLImageElement base property */
|
|
||||||
get naturalWidth() { return this.dom.naturalWidth }
|
|
||||||
/**HTMLImageElement base property */
|
|
||||||
get x() { return this.dom.x }
|
|
||||||
/**HTMLImageElement base property */
|
|
||||||
get y() { return this.dom.y }
|
|
||||||
|
|
||||||
}
|
|
@ -1,187 +0,0 @@
|
|||||||
import { $Element, $ElementOptions } from "./$Element";
|
|
||||||
import { $State, $StateArgument } from "../$State";
|
|
||||||
|
|
||||||
export interface $InputOptions extends $ElementOptions {}
|
|
||||||
export class $Input extends $Element<HTMLInputElement> {
|
|
||||||
constructor(options?: $InputOptions) {
|
|
||||||
super('input', options);
|
|
||||||
}
|
|
||||||
|
|
||||||
accept(): string[]
|
|
||||||
accept(...filetype: string[]): this
|
|
||||||
accept(...filetype: string[]) { return $.fluent(this, arguments, () => this.dom.accept.split(','), () => this.dom.accept = filetype.toString() )}
|
|
||||||
|
|
||||||
capture(): string;
|
|
||||||
capture(capture: string): this;
|
|
||||||
capture(capture?: string) { return $.fluent(this, arguments, () => this.dom.capture, () => $.set(this.dom, 'capture', capture))}
|
|
||||||
|
|
||||||
alt(): string;
|
|
||||||
alt(alt: string): this;
|
|
||||||
alt(alt?: string) { return $.fluent(this, arguments, () => this.dom.alt, () => $.set(this.dom, 'alt', alt))}
|
|
||||||
|
|
||||||
height(): number;
|
|
||||||
height(height: number): this;
|
|
||||||
height(height?: number) { return $.fluent(this, arguments, () => this.dom.height, () => $.set(this.dom, 'height', height))}
|
|
||||||
|
|
||||||
width(): number;
|
|
||||||
width(wdith: number): this;
|
|
||||||
width(width?: number) { return $.fluent(this, arguments, () => this.dom.width, () => $.set(this.dom, 'width', width))}
|
|
||||||
|
|
||||||
checked(): boolean;
|
|
||||||
checked(boolean: boolean): this;
|
|
||||||
checked(boolean?: boolean) { return $.fluent(this, arguments, () => this.dom.checked, () => $.set(this.dom, 'checked', boolean))}
|
|
||||||
|
|
||||||
max(): number;
|
|
||||||
max(max: number): this;
|
|
||||||
max(max?: number) { return $.fluent(this, arguments, () => this.dom.max === '' ? null : parseInt(this.dom.min), () => $.set(this.dom, 'max', max?.toString()))}
|
|
||||||
|
|
||||||
min(): number;
|
|
||||||
min(min: number): this;
|
|
||||||
min(min?: number) { return $.fluent(this, arguments, () => this.dom.min === '' ? null : parseInt(this.dom.min), () => $.set(this.dom, 'min', min?.toString()))}
|
|
||||||
|
|
||||||
maxLength(): number;
|
|
||||||
maxLength(maxLength: number): this;
|
|
||||||
maxLength(maxLength?: number) { return $.fluent(this, arguments, () => this.dom.maxLength, () => $.set(this.dom, 'maxLength', maxLength))}
|
|
||||||
|
|
||||||
minLength(): number;
|
|
||||||
minLength(minLength: number): this;
|
|
||||||
minLength(minLength?: number) { return $.fluent(this, arguments, () => this.dom.minLength, () => $.set(this.dom, 'minLength', minLength))}
|
|
||||||
|
|
||||||
autocomplete(): AutoFill;
|
|
||||||
autocomplete(autocomplete: AutoFill): this;
|
|
||||||
autocomplete(autocomplete?: AutoFill) { return $.fluent(this, arguments, () => this.dom.autocomplete, () => $.set(this.dom, 'autocomplete', autocomplete))}
|
|
||||||
|
|
||||||
defaultValue(): string;
|
|
||||||
defaultValue(defaultValue: string): this;
|
|
||||||
defaultValue(defaultValue?: string) { return $.fluent(this, arguments, () => this.dom.defaultValue, () => $.set(this.dom, 'defaultValue', defaultValue))}
|
|
||||||
|
|
||||||
defaultChecked(): boolean;
|
|
||||||
defaultChecked(defaultChecked: boolean): this;
|
|
||||||
defaultChecked(defaultChecked?: boolean) { return $.fluent(this, arguments, () => this.dom.defaultChecked, () => $.set(this.dom, 'defaultChecked', defaultChecked))}
|
|
||||||
|
|
||||||
dirName(): string;
|
|
||||||
dirName(dirName: string): this;
|
|
||||||
dirName(dirName?: string) { return $.fluent(this, arguments, () => this.dom.dirName, () => $.set(this.dom, 'dirName', dirName))}
|
|
||||||
|
|
||||||
disabled(): boolean;
|
|
||||||
disabled(disabled: boolean): this;
|
|
||||||
disabled(disabled?: boolean) { return $.fluent(this, arguments, () => this.dom.disabled, () => $.set(this.dom, 'disabled', disabled))}
|
|
||||||
|
|
||||||
multiple(): boolean;
|
|
||||||
multiple(multiple: boolean): this;
|
|
||||||
multiple(multiple?: boolean) { return $.fluent(this, arguments, () => this.dom.multiple, () => $.set(this.dom, 'multiple', multiple))}
|
|
||||||
|
|
||||||
pattern(): string;
|
|
||||||
pattern(pattern: string): this;
|
|
||||||
pattern(pattern?: string) { return $.fluent(this, arguments, () => this.dom.pattern, () => $.set(this.dom, 'pattern', pattern))}
|
|
||||||
|
|
||||||
placeholder(): string;
|
|
||||||
placeholder(placeholder?: string): this;
|
|
||||||
placeholder(placeholder?: string) { return $.fluent(this, arguments, () => this.dom.placeholder, () => $.set(this.dom, 'placeholder', placeholder))}
|
|
||||||
|
|
||||||
readOnly(): boolean;
|
|
||||||
readOnly(readOnly: boolean): this;
|
|
||||||
readOnly(readOnly?: boolean) { return $.fluent(this, arguments, () => this.dom.readOnly, () => $.set(this.dom, 'readOnly', readOnly))}
|
|
||||||
|
|
||||||
required(): boolean;
|
|
||||||
required(required: boolean): this;
|
|
||||||
required(required?: boolean) { return $.fluent(this, arguments, () => this.dom.required, () => $.set(this.dom, 'required', required))}
|
|
||||||
|
|
||||||
selectionDirection(): SelectionDirection | null;
|
|
||||||
selectionDirection(selectionDirection: SelectionDirection | null): this;
|
|
||||||
selectionDirection(selectionDirection?: SelectionDirection | null) { return $.fluent(this, arguments, () => this.dom.selectionDirection, () => $.set(this.dom, 'selectionDirection', selectionDirection))}
|
|
||||||
|
|
||||||
selectionEnd(): number | null;
|
|
||||||
selectionEnd(selectionEnd: number | null): this;
|
|
||||||
selectionEnd(selectionEnd?: number | null) { return $.fluent(this, arguments, () => this.dom.selectionEnd, () => $.set(this.dom, 'selectionEnd', selectionEnd))}
|
|
||||||
|
|
||||||
selectionStart(): number | null;
|
|
||||||
selectionStart(selectionStart: number | null): this;
|
|
||||||
selectionStart(selectionStart?: number | null) { return $.fluent(this, arguments, () => this.dom.selectionStart, () => $.set(this.dom, 'selectionStart', selectionStart))}
|
|
||||||
|
|
||||||
size(): number;
|
|
||||||
size(size: number): this;
|
|
||||||
size(size?: number) { return $.fluent(this, arguments, () => this.dom.size, () => $.set(this.dom, 'size', size))}
|
|
||||||
|
|
||||||
src(): string;
|
|
||||||
src(src: string): this;
|
|
||||||
src(src?: string) { return $.fluent(this, arguments, () => this.dom.src, () => $.set(this.dom, 'src', src))}
|
|
||||||
|
|
||||||
step(): number;
|
|
||||||
step(step: number): this;
|
|
||||||
step(step?: number) { return $.fluent(this, arguments, () => Number(this.dom.step), () => $.set(this.dom, 'step', step?.toString()))}
|
|
||||||
|
|
||||||
type(): InputType;
|
|
||||||
type(type: InputType): this;
|
|
||||||
type(type?: InputType) { return $.fluent(this, arguments, () => this.dom.type, () => $.set(this.dom, 'type', type))}
|
|
||||||
|
|
||||||
inputMode(): InputMode;
|
|
||||||
inputMode(mode: InputMode): this;
|
|
||||||
inputMode(mode?: InputMode) { return $.fluent(this, arguments, () => this.dom.inputMode as InputMode, () => $.set(this.dom, 'inputMode', mode))}
|
|
||||||
|
|
||||||
valueAsDate(): Date | null;
|
|
||||||
valueAsDate(date: Date | null): this;
|
|
||||||
valueAsDate(date?: Date | null) { return $.fluent(this, arguments, () => this.dom.valueAsDate, () => $.set(this.dom, 'valueAsDate', date))}
|
|
||||||
|
|
||||||
valueAsNumber(): number;
|
|
||||||
valueAsNumber(number: number): this;
|
|
||||||
valueAsNumber(number?: number) { return $.fluent(this, arguments, () => this.dom.valueAsNumber, () => $.set(this.dom, 'valueAsNumber', number))}
|
|
||||||
|
|
||||||
webkitdirectory(): boolean;
|
|
||||||
webkitdirectory(boolean: boolean): this;
|
|
||||||
webkitdirectory(boolean?: boolean) { return $.fluent(this, arguments, () => this.dom.webkitdirectory, () => $.set(this.dom, 'webkitdirectory', boolean))}
|
|
||||||
|
|
||||||
select() { this.dom.select(); return this }
|
|
||||||
setCustomValidity(error: string) { this.dom.setCustomValidity(error); return this }
|
|
||||||
setRangeText(replacement: string): this;
|
|
||||||
setRangeText(replacement: string, start: number, end: number, selectionMode?: SelectionMode): this;
|
|
||||||
setRangeText(replacement: string, start?: number, end?: number, selectionMode?: SelectionMode) {
|
|
||||||
if (typeof start === 'number' && typeof end === 'number') this.dom.setRangeText(replacement, start, end, selectionMode)
|
|
||||||
this.dom.setRangeText(replacement);
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
setSelectionRange(start: number | null, end: number | null, direction?: SelectionDirection) { this.dom.setSelectionRange(start, end, direction); return this }
|
|
||||||
showPicker() { this.dom.showPicker(); return this }
|
|
||||||
stepDown() { this.dom.stepDown(); return this }
|
|
||||||
stepUp() { this.dom.stepUp(); return this }
|
|
||||||
|
|
||||||
checkValidity() { return this.dom.checkValidity() }
|
|
||||||
reportValidity() { return this.dom.reportValidity() }
|
|
||||||
get files() { return this.dom.files }
|
|
||||||
get webkitEntries() { return this.dom.webkitEntries }
|
|
||||||
|
|
||||||
|
|
||||||
formAction(): string;
|
|
||||||
formAction(action: string | undefined): this;
|
|
||||||
formAction(action?: string) { return $.fluent(this, arguments, () => this.dom.formAction, () => $.set(this.dom, 'formAction', action))}
|
|
||||||
|
|
||||||
formEnctype(): string;
|
|
||||||
formEnctype(enctype: string | undefined): this;
|
|
||||||
formEnctype(enctype?: string) { return $.fluent(this, arguments, () => this.dom.formEnctype, () => $.set(this.dom, 'formEnctype', enctype))}
|
|
||||||
|
|
||||||
formMethod(): string;
|
|
||||||
formMethod(method: string | undefined): this;
|
|
||||||
formMethod(method?: string) { return $.fluent(this, arguments, () => this.dom.formMethod, () => $.set(this.dom, 'formMethod', method))}
|
|
||||||
|
|
||||||
formNoValidate(): boolean;
|
|
||||||
formNoValidate(boolean: boolean | undefined): this;
|
|
||||||
formNoValidate(boolean?: boolean) { return $.fluent(this, arguments, () => this.dom.formNoValidate, () => $.set(this.dom, 'formNoValidate', boolean))}
|
|
||||||
|
|
||||||
formTarget(): string;
|
|
||||||
formTarget(target: string | undefined): this;
|
|
||||||
formTarget(target?: string) { return $.fluent(this, arguments, () => this.dom.formTarget, () => $.set(this.dom, 'formTarget', target))}
|
|
||||||
|
|
||||||
name(): string;
|
|
||||||
name(name?: $StateArgument<string> | undefined): this;
|
|
||||||
name(name?: $StateArgument<string> | undefined) { return $.fluent(this, arguments, () => this.dom.name, () => $.set(this.dom, 'name', name))}
|
|
||||||
|
|
||||||
value(): string;
|
|
||||||
value(value: $StateArgument<string> | undefined): this;
|
|
||||||
value(value?: $StateArgument<string> | undefined) { return $.fluent(this, arguments, () => this.dom.value, () => $.set(this.dom, 'value', value))}
|
|
||||||
|
|
||||||
get form() { return this.dom.form ? $(this.dom.form) : null }
|
|
||||||
get labels() { return Array.from(this.dom.labels ?? []).map(label => $(label)) }
|
|
||||||
get validationMessage() { return this.dom.validationMessage }
|
|
||||||
get validity() { return this.dom.validity }
|
|
||||||
get willValidate() { return this.dom.willValidate }
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
import { $Container, $ContainerOptions } from "./$Container";
|
|
||||||
export interface $LabelOptions extends $ContainerOptions {}
|
|
||||||
export class $Label extends $Container<HTMLLabelElement> {
|
|
||||||
constructor(options?: $LabelOptions) {
|
|
||||||
super('label', options);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(): string;
|
|
||||||
for(name?: string): this;
|
|
||||||
for(name?: string) { return $.fluent(this, arguments, () => this.dom.htmlFor, () => { $.set(this.dom, 'htmlFor', name, 'for')}) }
|
|
||||||
|
|
||||||
get form() { return this.dom.form }
|
|
||||||
get control() { return this.dom.control }
|
|
||||||
}
|
|
@ -1,68 +0,0 @@
|
|||||||
import { $, $Element, $State, $Text } from "../../index";
|
|
||||||
import { $Container } from "./$Container";
|
|
||||||
|
|
||||||
export abstract class $Node<N extends Node = Node> {
|
|
||||||
abstract readonly dom: N;
|
|
||||||
readonly __hidden: boolean = false;
|
|
||||||
private domEvents: {[key: string]: Map<Function, Function>} = {};
|
|
||||||
readonly parent?: $Container;
|
|
||||||
|
|
||||||
on<K extends keyof HTMLElementEventMap>(type: K, callback: (event: HTMLElementEventMap[K], $node: this) => any, options?: AddEventListenerOptions | boolean) {
|
|
||||||
if (!this.domEvents[type]) this.domEvents[type] = new Map()
|
|
||||||
const middleCallback = (e: Event) => callback(e as HTMLElementEventMap[K], this);
|
|
||||||
this.domEvents[type].set(callback, middleCallback)
|
|
||||||
this.dom.addEventListener(type, middleCallback, options)
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
off<K extends keyof HTMLElementEventMap>(type: K, callback: (event: HTMLElementEventMap[K], $node: this) => any, options?: AddEventListenerOptions | boolean) {
|
|
||||||
const middleCallback = this.domEvents[type]?.get(callback);
|
|
||||||
if (middleCallback) this.dom.removeEventListener(type, middleCallback as EventListener, options)
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
once<K extends keyof HTMLElementEventMap>(type: K, callback: (event: HTMLElementEventMap[K], $node: this) => any, options?: AddEventListenerOptions | boolean) {
|
|
||||||
const onceFn = (event: Event) => {
|
|
||||||
this.dom.removeEventListener(type, onceFn, options)
|
|
||||||
callback(event as HTMLElementEventMap[K], this);
|
|
||||||
};
|
|
||||||
this.dom.addEventListener(type, onceFn, options)
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
hide(): boolean;
|
|
||||||
hide(hide?: boolean | $State<boolean>, render?: boolean): this;
|
|
||||||
hide(hide?: boolean | $State<boolean>, render = true) { return $.fluent(this, arguments, () => this.__hidden, () => {
|
|
||||||
if (hide === undefined) return;
|
|
||||||
if (hide instanceof $State) { (this as Mutable<$Node>).__hidden = hide.value; hide.use(this, 'hide')}
|
|
||||||
else (this as Mutable<$Node>).__hidden = hide;
|
|
||||||
if (render) this.parent?.children.render();
|
|
||||||
return this;
|
|
||||||
})}
|
|
||||||
|
|
||||||
/**Remove this element from parent */
|
|
||||||
remove() {
|
|
||||||
this.parent?.children.remove(this).render();
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**Replace $Node with this element */
|
|
||||||
replace($node: $Node) {
|
|
||||||
this.parent?.children.replace(this, $node).render();
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
contains(target: $Node | EventTarget | Node | null): boolean {
|
|
||||||
if (!target) return false;
|
|
||||||
if (target instanceof $Node) return this.dom.contains(target.dom);
|
|
||||||
else if (target instanceof EventTarget) return this.dom.contains($(target).dom)
|
|
||||||
else return this.dom.contains(target)
|
|
||||||
}
|
|
||||||
|
|
||||||
self(callback: ($node: this) => void) { callback(this); return this; }
|
|
||||||
inDOM() { return document.contains(this.dom); }
|
|
||||||
isElement(): this is $Element {
|
|
||||||
if (this instanceof $Element) return true;
|
|
||||||
else return false;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
import { $Container, $ContainerOptions } from "./$Container";
|
|
||||||
import { $State, $StateArgument } from "../$State";
|
|
||||||
|
|
||||||
export interface $OptGroupOptions extends $ContainerOptions {}
|
|
||||||
export class $OptGroup extends $Container<HTMLOptGroupElement> {
|
|
||||||
constructor(options?: $OptGroupOptions) {
|
|
||||||
super('optgroup', options);
|
|
||||||
}
|
|
||||||
|
|
||||||
disabled(): boolean;
|
|
||||||
disabled(disabled: $StateArgument<boolean> | undefined): this;
|
|
||||||
disabled(disabled?: $StateArgument<boolean> | undefined) { return $.fluent(this, arguments, () => this.dom.disabled, () => $.set(this.dom, 'disabled', disabled))}
|
|
||||||
|
|
||||||
label(): string;
|
|
||||||
label(label: $StateArgument<string> | undefined): this;
|
|
||||||
label(label?: $StateArgument<string> | undefined) { return $.fluent(this, arguments, () => this.dom.label, () => $.set(this.dom, 'label', label))}
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
import { $Container, $ContainerOptions } from "./$Container";
|
|
||||||
import { $State, $StateArgument } from "../$State";
|
|
||||||
|
|
||||||
export interface $OptionOptions extends $ContainerOptions {}
|
|
||||||
export class $Option extends $Container<HTMLOptionElement> {
|
|
||||||
constructor(options?: $OptionOptions) {
|
|
||||||
super('option', options);
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultSelected(): boolean;
|
|
||||||
defaultSelected(defaultSelected: $StateArgument<boolean> | undefined): this;
|
|
||||||
defaultSelected(defaultSelected?: $StateArgument<boolean> | undefined) { return $.fluent(this, arguments, () => this.dom.defaultSelected, () => $.set(this.dom, 'defaultSelected', defaultSelected))}
|
|
||||||
|
|
||||||
disabled(): boolean;
|
|
||||||
disabled(disabled: $StateArgument<boolean> | undefined): this;
|
|
||||||
disabled(disabled?: $StateArgument<boolean> | undefined) { return $.fluent(this, arguments, () => this.dom.disabled, () => $.set(this.dom, 'disabled', disabled))}
|
|
||||||
|
|
||||||
label(): string;
|
|
||||||
label(label: $StateArgument<string> | undefined): this;
|
|
||||||
label(label?: $StateArgument<string> | undefined) { return $.fluent(this, arguments, () => this.dom.label, () => $.set(this.dom, 'label', label))}
|
|
||||||
|
|
||||||
selected(): boolean;
|
|
||||||
selected(selected: $StateArgument<boolean> | undefined): this;
|
|
||||||
selected(selected?: $StateArgument<boolean> | undefined) { return $.fluent(this, arguments, () => this.dom.selected, () => $.set(this.dom, 'selected', selected))}
|
|
||||||
|
|
||||||
text(): string;
|
|
||||||
text(text: $StateArgument<string> | undefined): this;
|
|
||||||
text(text?: $StateArgument<string> | undefined) { return $.fluent(this, arguments, () => this.dom.text, () => $.set(this.dom, 'text', text))}
|
|
||||||
|
|
||||||
value(): string;
|
|
||||||
value(value: $StateArgument<string> | undefined): this;
|
|
||||||
value(value?: $StateArgument<string> | undefined) { return $.fluent(this, arguments, () => this.dom.value, () => $.set(this.dom, 'value', value))}
|
|
||||||
|
|
||||||
get form() { return this.dom.form ? $(this.dom.form) : null }
|
|
||||||
get index() { return this.dom.index }
|
|
||||||
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
import { $Element, $ElementOptions } from "./$Element"
|
|
||||||
|
|
||||||
export interface $SVGOptions extends $ElementOptions {}
|
|
||||||
export class $SVGElement<S extends SVGElement> extends $Element<S> {
|
|
||||||
constructor(tagname: string, options?: $SVGOptions) {
|
|
||||||
super(tagname, options);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,57 +0,0 @@
|
|||||||
import { $Container, $ContainerOptions } from "./$Container";
|
|
||||||
import { $OptGroup } from "./$OptGroup";
|
|
||||||
import { $Option } from "./$Option";
|
|
||||||
import { $State, $StateArgument } from "../$State";
|
|
||||||
|
|
||||||
export interface $SelectOptions extends $ContainerOptions {}
|
|
||||||
export class $Select extends $Container<HTMLSelectElement> {
|
|
||||||
constructor(options?: $SelectOptions) {
|
|
||||||
super('select')
|
|
||||||
}
|
|
||||||
|
|
||||||
add(option: $SelectContentType | OrMatrix<$SelectContentType>) {
|
|
||||||
this.insert(option);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
item(index: number) { return $(this.dom.item(index)) }
|
|
||||||
namedItem(name: string) { return $(this.dom.namedItem(name)) }
|
|
||||||
|
|
||||||
disabled(): boolean;
|
|
||||||
disabled(disabled: $StateArgument<boolean> | undefined): this;
|
|
||||||
disabled(disabled?: $StateArgument<boolean> | undefined) { return $.fluent(this, arguments, () => this.dom.disabled, () => $.set(this.dom, 'disabled', disabled))}
|
|
||||||
|
|
||||||
multiple(): boolean;
|
|
||||||
multiple(multiple: $StateArgument<boolean> | undefined): this;
|
|
||||||
multiple(multiple?: $StateArgument<boolean> | undefined) { return $.fluent(this, arguments, () => this.dom.multiple, () => $.set(this.dom, 'multiple', multiple))}
|
|
||||||
|
|
||||||
required(): boolean;
|
|
||||||
required(required: boolean): this;
|
|
||||||
required(required?: boolean) { return $.fluent(this, arguments, () => this.dom.required, () => $.set(this.dom, 'required', required))}
|
|
||||||
|
|
||||||
autocomplete(): AutoFill;
|
|
||||||
autocomplete(autocomplete: AutoFill): this;
|
|
||||||
autocomplete(autocomplete?: AutoFill) { return $.fluent(this, arguments, () => this.dom.autocomplete, () => $.set(this.dom, 'autocomplete', autocomplete))}
|
|
||||||
|
|
||||||
get length() { return this.dom.length }
|
|
||||||
get size() { return this.dom.size }
|
|
||||||
get options() { return Array.from(this.dom.options).map($option => $($option)) }
|
|
||||||
get selectedIndex() { return this.dom.selectedIndex }
|
|
||||||
get selectedOptions() { return Array.from(this.dom.selectedOptions).map($option => $($option)) }
|
|
||||||
|
|
||||||
name(): string;
|
|
||||||
name(name?: $StateArgument<string> | undefined): this;
|
|
||||||
name(name?: $StateArgument<string> | undefined) { return $.fluent(this, arguments, () => this.dom.name, () => $.set(this.dom, 'name', name))}
|
|
||||||
|
|
||||||
value(): string;
|
|
||||||
value(value?: $StateArgument<string> | undefined): this;
|
|
||||||
value(value?: $StateArgument<string> | undefined) { return $.fluent(this, arguments, () => this.dom.value, () => $.set(this.dom, 'value', value))}
|
|
||||||
|
|
||||||
get form() { return this.dom.form ? $(this.dom.form) : null }
|
|
||||||
get labels() { return Array.from(this.dom.labels ?? []).map(label => $(label)) }
|
|
||||||
get validationMessage() { return this.dom.validationMessage }
|
|
||||||
get validity() { return this.dom.validity }
|
|
||||||
get willValidate() { return this.dom.willValidate }
|
|
||||||
}
|
|
||||||
|
|
||||||
export type $SelectContentType = $Option | $OptGroup | undefined;
|
|
@ -1,14 +0,0 @@
|
|||||||
import { $Node } from "./$Node";
|
|
||||||
|
|
||||||
export class $Text extends $Node<Text> {
|
|
||||||
dom: Text;
|
|
||||||
constructor(data: string) {
|
|
||||||
super();
|
|
||||||
this.dom = new Text(data);
|
|
||||||
this.dom.$ = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
content(): string;
|
|
||||||
content(text: string): this;
|
|
||||||
content(text?: string) { return $.fluent(this, arguments, () => this.dom.textContent, () => $.set(this.dom, 'textContent', text))}
|
|
||||||
}
|
|
@ -1,100 +0,0 @@
|
|||||||
import { $Container, $ContainerOptions } from "./$Container";
|
|
||||||
import { $StateArgument } from "../$State";
|
|
||||||
|
|
||||||
export interface $TextareaOptions extends $ContainerOptions {}
|
|
||||||
export class $Textarea extends $Container<HTMLTextAreaElement> {
|
|
||||||
constructor(options?: $TextareaOptions) {
|
|
||||||
super('textarea', options);
|
|
||||||
}
|
|
||||||
|
|
||||||
cols(): number;
|
|
||||||
cols(cols: number): this;
|
|
||||||
cols(cols?: number) { return $.fluent(this, arguments, () => this.dom.cols, () => $.set(this.dom, 'cols', cols))}
|
|
||||||
|
|
||||||
name(): string;
|
|
||||||
name(name?: $StateArgument<string> | undefined): this;
|
|
||||||
name(name?: $StateArgument<string> | undefined) { return $.fluent(this, arguments, () => this.dom.name, () => $.set(this.dom, 'name', name))}
|
|
||||||
|
|
||||||
wrap(): string;
|
|
||||||
wrap(wrap?: $StateArgument<string> | undefined): this;
|
|
||||||
wrap(wrap?: $StateArgument<string> | undefined) { return $.fluent(this, arguments, () => this.dom.wrap, () => $.set(this.dom, 'wrap', wrap))}
|
|
||||||
|
|
||||||
value(): string;
|
|
||||||
value(value?: $StateArgument<string> | undefined): this;
|
|
||||||
value(value?: $StateArgument<string> | undefined) { return $.fluent(this, arguments, () => this.dom.value, () => $.set(this.dom, 'value', value))}
|
|
||||||
|
|
||||||
maxLength(): number;
|
|
||||||
maxLength(maxLength: number): this;
|
|
||||||
maxLength(maxLength?: number) { return $.fluent(this, arguments, () => this.dom.maxLength, () => $.set(this.dom, 'maxLength', maxLength))}
|
|
||||||
|
|
||||||
minLength(): number;
|
|
||||||
minLength(minLength: number): this;
|
|
||||||
minLength(minLength?: number) { return $.fluent(this, arguments, () => this.dom.minLength, () => $.set(this.dom, 'minLength', minLength))}
|
|
||||||
|
|
||||||
autocomplete(): AutoFill;
|
|
||||||
autocomplete(autocomplete: AutoFill): this;
|
|
||||||
autocomplete(autocomplete?: AutoFill) { return $.fluent(this, arguments, () => this.dom.autocomplete, () => $.set(this.dom, 'autocomplete', autocomplete))}
|
|
||||||
|
|
||||||
defaultValue(): string;
|
|
||||||
defaultValue(defaultValue: string): this;
|
|
||||||
defaultValue(defaultValue?: string) { return $.fluent(this, arguments, () => this.dom.defaultValue, () => $.set(this.dom, 'defaultValue', defaultValue))}
|
|
||||||
|
|
||||||
dirName(): string;
|
|
||||||
dirName(dirName: string): this;
|
|
||||||
dirName(dirName?: string) { return $.fluent(this, arguments, () => this.dom.dirName, () => $.set(this.dom, 'dirName', dirName))}
|
|
||||||
|
|
||||||
disabled(): boolean;
|
|
||||||
disabled(disabled: boolean): this;
|
|
||||||
disabled(disabled?: boolean) { return $.fluent(this, arguments, () => this.dom.disabled, () => $.set(this.dom, 'disabled', disabled))}
|
|
||||||
|
|
||||||
placeholder(): string;
|
|
||||||
placeholder(placeholder?: string): this;
|
|
||||||
placeholder(placeholder?: string) { return $.fluent(this, arguments, () => this.dom.placeholder, () => $.set(this.dom, 'placeholder', placeholder))}
|
|
||||||
|
|
||||||
readOnly(): boolean;
|
|
||||||
readOnly(readOnly: boolean): this;
|
|
||||||
readOnly(readOnly?: boolean) { return $.fluent(this, arguments, () => this.dom.readOnly, () => $.set(this.dom, 'readOnly', readOnly))}
|
|
||||||
|
|
||||||
required(): boolean;
|
|
||||||
required(required: boolean): this;
|
|
||||||
required(required?: boolean) { return $.fluent(this, arguments, () => this.dom.required, () => $.set(this.dom, 'required', required))}
|
|
||||||
|
|
||||||
selectionDirection(): SelectionDirection;
|
|
||||||
selectionDirection(selectionDirection: SelectionDirection): this;
|
|
||||||
selectionDirection(selectionDirection?: SelectionDirection) { return $.fluent(this, arguments, () => this.dom.selectionDirection, () => $.set(this.dom, 'selectionDirection', selectionDirection))}
|
|
||||||
|
|
||||||
selectionEnd(): number;
|
|
||||||
selectionEnd(selectionEnd: number): this;
|
|
||||||
selectionEnd(selectionEnd?: number) { return $.fluent(this, arguments, () => this.dom.selectionEnd, () => $.set(this.dom, 'selectionEnd', selectionEnd))}
|
|
||||||
|
|
||||||
selectionStart(): number;
|
|
||||||
selectionStart(selectionStart: number): this;
|
|
||||||
selectionStart(selectionStart?: number) { return $.fluent(this, arguments, () => this.dom.selectionStart, () => $.set(this.dom, 'selectionStart', selectionStart))}
|
|
||||||
|
|
||||||
type(): InputType;
|
|
||||||
type(type: InputType): this;
|
|
||||||
type(type?: InputType) { return $.fluent(this, arguments, () => this.dom.type, () => $.set(this.dom, 'type', type))}
|
|
||||||
|
|
||||||
inputMode(): InputMode;
|
|
||||||
inputMode(mode: InputMode): this;
|
|
||||||
inputMode(mode?: InputMode) { return $.fluent(this, arguments, () => this.dom.inputMode as InputMode, () => $.set(this.dom, 'inputMode', mode))}
|
|
||||||
|
|
||||||
select() { this.dom.select(); return this }
|
|
||||||
setCustomValidity(error: string) { this.dom.setCustomValidity(error); return this }
|
|
||||||
setRangeText(replacement: string): this;
|
|
||||||
setRangeText(replacement: string, start: number, end: number, selectionMode?: SelectionMode): this;
|
|
||||||
setRangeText(replacement: string, start?: number, end?: number, selectionMode?: SelectionMode) {
|
|
||||||
if (typeof start === 'number' && typeof end === 'number') this.dom.setRangeText(replacement, start, end, selectionMode)
|
|
||||||
this.dom.setRangeText(replacement);
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
setSelectionRange(start: number | null, end: number | null, direction?: SelectionDirection) { this.dom.setSelectionRange(start, end, direction); return this }
|
|
||||||
|
|
||||||
checkValidity() { return this.dom.checkValidity() }
|
|
||||||
reportValidity() { return this.dom.reportValidity() }
|
|
||||||
|
|
||||||
get validationMessage() { return this.dom.validationMessage }
|
|
||||||
get validity() { return this.dom.validity }
|
|
||||||
get form() { return this.dom.form ? $(this.dom.form) : null }
|
|
||||||
get labels() { return Array.from(this.dom.labels ?? []).map(label => $(label)) }
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
import { $Container, $ContainerOptions } from "./$Container";
|
|
||||||
import { $EventManager } from "../$EventManager";
|
|
||||||
import { $Node } from "./$Node";
|
|
||||||
|
|
||||||
export interface $ViewOptions extends $ContainerOptions {}
|
|
||||||
export class $View extends $Container {
|
|
||||||
protected view_cache = new Map<string, $Node>();
|
|
||||||
event = new $EventManager<$ViewEventMap>().register('switch')
|
|
||||||
content_id: string | null = null;
|
|
||||||
constructor(options?: $ViewOptions) {
|
|
||||||
super('view', options);
|
|
||||||
}
|
|
||||||
|
|
||||||
setView(id: string, $node: $Node) {
|
|
||||||
this.view_cache.set(id, $node);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteView(id: string) {
|
|
||||||
this.view_cache.delete(id);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteAllView() {
|
|
||||||
this.view_cache.clear();
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
switchView(id: string) {
|
|
||||||
const target_content = this.view_cache.get(id);
|
|
||||||
if (target_content === undefined) return this;
|
|
||||||
this.content(target_content);
|
|
||||||
this.content_id = id;
|
|
||||||
this.event.fire('switch', id);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface $ViewEventMap {
|
|
||||||
'switch': [id: string]
|
|
||||||
}
|
|
BIN
logo_dark.png
Normal file
BIN
logo_dark.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
BIN
logo_light.png
Normal file
BIN
logo_light.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
22
package.json
22
package.json
@ -1,22 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "elexis",
|
|
||||||
"description": "Web library design for JS/TS lover.",
|
|
||||||
"version": "0.1.0",
|
|
||||||
"author": {
|
|
||||||
"name": "defaultkavy",
|
|
||||||
"email": "defaultkavy@gmail.com",
|
|
||||||
"url": "https://github.com/defaultkavy"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/defaultkavy/elexis.git"
|
|
||||||
},
|
|
||||||
"module": "index.ts",
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/defaultkavy/elexis/issues"
|
|
||||||
},
|
|
||||||
"homepage": "https://github.com/defaultkavy/elexis",
|
|
||||||
"keywords": ["web", "front-end", "lib", "fluent", "framework"],
|
|
||||||
"license": "ISC",
|
|
||||||
"type": "module"
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"lib": ["dom", "ES2022"],
|
|
||||||
"module": "esnext",
|
|
||||||
"target": "esnext",
|
|
||||||
"moduleResolution": "bundler",
|
|
||||||
"moduleDetection": "force",
|
|
||||||
"allowImportingTsExtensions": true,
|
|
||||||
"noEmit": true,
|
|
||||||
"composite": true,
|
|
||||||
"strict": true,
|
|
||||||
"downlevelIteration": true,
|
|
||||||
"skipLibCheck": true,
|
|
||||||
"jsx": "react-jsx",
|
|
||||||
"allowSyntheticDefaultImports": true,
|
|
||||||
"forceConsistentCasingInFileNames": true,
|
|
||||||
"allowJs": true,
|
|
||||||
"experimentalDecorators": true
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user