remove: $FormElementMethod
This commit is contained in:
defaultkavy 2024-04-20 22:28:58 +08:00
parent b51edda800
commit 1f052609a4
8 changed files with 99 additions and 63 deletions

View File

@ -116,19 +116,27 @@ export namespace $ {
: 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 multableResolve<T>(multable: OrArray<T>) {
export function orArrayResolve<T>(multable: OrArray<T>) {
if (multable instanceof Array) return multable;
else return [multable];
}
export function mixin(target: any, constructors: OrArray<any>) {
multableResolve(constructors).forEach(constructor => {
orArrayResolve(constructors).forEach(constructor => {
Object.getOwnPropertyNames(constructor.prototype).forEach(name => {
if (name === 'constructor') return;
Object.defineProperty(
@ -140,15 +148,24 @@ export namespace $ {
})
return target;
}
export function set<O, K extends keyof O>(object: O, key: K, value: any, methodKey?: string) {
/**
* A helper for $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 ? (Parameters<O[K]> | $State<Parameters<O[K]>>) : O[K] | undefined | $State<O[K]>, methodKey?: string) {
if (value === undefined) return;
if (value instanceof $State && object instanceof Node) {
value.use(object.$, methodKey ?? key as any);
object[key] = value.value;
const prop = object[key];
if (prop instanceof Function) prop(value.value);
else object[key] = value.value;
return;
}
object[key] = value;
object[key] = value as any;
}
export function state<T>(value: T) {

View File

@ -1,10 +1,6 @@
import { $Container, $ContainerOptions } from "./$Container";
import { FormElementMethod, $FormElementMethod } from "./$Form";
import { $State } from "./$State";
export interface $ButtonOptions extends $ContainerOptions {}
//@ts-expect-error
export interface $Button extends $FormElementMethod {}
@FormElementMethod
export class $Button extends $Container<HTMLButtonElement> {
constructor(options?: $ButtonOptions) {
super('button', options);
@ -16,8 +12,28 @@ export class $Button extends $Container<HTMLButtonElement> {
type(): ButtonType;
type(type: ButtonType): this;
type(type?: ButtonType) { return $.fluent(this, arguments, () => this.dom.type as ButtonType, () => $.set(this.dom, 'type', type))}
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))}
}

View File

@ -23,7 +23,7 @@ export class $Container<H extends HTMLElement = HTMLElement> extends $Element<H>
/**Insert element to this element */
insert(children: $ContainerContentBuilder<this>): this { return $.fluent(this, arguments, () => this, () => {
if (children instanceof Function) children = children(this);
children = $.multableResolve(children);
children = $.orArrayResolve(children);
for (const child of children) {
if (child === undefined) continue;
if (child instanceof Array) this.insert(child)

View File

@ -7,9 +7,9 @@ export class $Form extends $Container<HTMLFormElement> {
super('form', options);
}
autocomplete(): AutoFillBase;
autocomplete(): AutoFill;
autocomplete(autocomplete: AutoFill | undefined): this;
autocomplete(autocomplete?: AutoFill) { return $.fluent(this, arguments, () => this.dom.autocomplete, () => $.set(this.dom, 'autocomplete', autocomplete))}
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;
@ -43,43 +43,4 @@ export class $Form extends $Container<HTMLFormElement> {
get length() { return this.dom.length }
get elements() { return Array.from(this.dom.elements).map(ele => $(ele)) }
}
export function FormElementMethod(target: any) { return $Util.mixin(target, $FormElementMethod) }
export abstract class $FormElementMethod {
abstract dom: HTMLButtonElement | HTMLInputElement;
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?: string | $State<string>): this;
name(name?: string | $State<string>) { return $.fluent(this, arguments, () => this.dom.name, () => $.set(this.dom, 'name', name))}
value(): string;
value(value?: string | $State<string>): this;
value(value?: string | $State<string>) { 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 }
}

View File

@ -1,10 +1,7 @@
import { $Element, $ElementOptions } from "./$Element";
import { $FormElementMethod, FormElementMethod } from "./$Form";
import { $State } from "./$State";
export interface $InputOptions extends $ElementOptions {}
//@ts-expect-error
export interface $Input extends $FormElementMethod {}
@FormElementMethod
export class $Input extends $Element<HTMLInputElement> {
constructor(options?: $InputOptions) {
super('input', options);
@ -152,4 +149,39 @@ export class $Input extends $Element<HTMLInputElement> {
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?: string | $State<string>): this;
name(name?: string | $State<string>) { return $.fluent(this, arguments, () => this.dom.name, () => $.set(this.dom, 'name', name))}
value(): string;
value(value?: string | $State<string>): this;
value(value?: string | $State<string>) { 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 }
}

View File

@ -1,13 +1,9 @@
import { $Container, $ContainerOptions } from "./$Container";
import { $FormElementMethod, FormElementMethod } from "./$Form";
import { $OptGroup } from "./$OptGroup";
import { $Option } from "./$Option";
import { $State } from "./$State";
export interface $SelectOptions extends $ContainerOptions {}
//@ts-expect-error
export interface $Select extends $FormElementMethod {}
@FormElementMethod
export class $Select extends $Container<HTMLSelectElement> {
constructor() {
super('select')
@ -42,6 +38,20 @@ export class $Select extends $Container<HTMLSelectElement> {
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?: string | $State<string>): this;
name(name?: string | $State<string>) { return $.fluent(this, arguments, () => this.dom.name, () => $.set(this.dom, 'name', name))}
value(): string;
value(value?: string | $State<string>): this;
value(value?: string | $State<string>) { 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;

View File

@ -17,7 +17,7 @@ export class Router {
/**Add route to Router. @example Router.addRoute(new Route('/', 'Hello World')) */
addRoute(routes: OrArray<Route<any>>) {
routes = $.multableResolve(routes);
routes = $.orArrayResolve(routes);
for (const route of routes) this.routeMap.set(route.path, route);
return this;
}

View File

@ -1,7 +1,7 @@
{
"name": "fluentx",
"description": "Fast, fluent, simple web builder",
"version": "0.0.4",
"version": "0.0.5",
"type": "module",
"module": "index.ts",
"author": {