You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
swel/mod.ts

134 lines
3.0 KiB
TypeScript

/// <reference lib="dom" />
type BasicProperties<T> = {
[K in keyof T as T[K] extends string | number | boolean ? K : never]: T[K];
};
export type Child = Node | string | null;
export type SwelOpts<T extends keyof HTMLElementTagNameMap> = Partial<
BasicProperties<HTMLElementTagNameMap[T]>
> & {
on: Partial<{
[Ev in keyof HTMLElementEventMap]: (
this: HTMLElement,
ev: HTMLElementEventMap[Ev],
) => void;
}>;
children: (Node | string)[] | null;
attributes: Record<string, string | boolean | number>;
className: string;
style: Record<string, string | boolean | number> | null;
};
export type Renderable = Child | Child[];
interface Swel {
<T extends keyof HTMLElementTagNameMap>(
tag: T,
opts?: Partial<SwelOpts<T>>,
): HTMLElementTagNameMap[T];
<T extends keyof HTMLElementTagNameMap>(
tag: T,
children?: Child[],
): HTMLElementTagNameMap[T];
<T extends keyof HTMLElementTagNameMap>(
tag: T,
child?: Child,
): HTMLElementTagNameMap[T];
<T extends keyof HTMLElementTagNameMap>(
tag: T,
opts?: Partial<Omit<SwelOpts<T>, "children">>,
children?: Child[],
): HTMLElementTagNameMap[T];
<T extends keyof HTMLElementTagNameMap>(
tag: T,
opts?: Partial<Omit<SwelOpts<T>, "children">>,
child?: Child,
): HTMLElementTagNameMap[T];
<T extends keyof HTMLElementTagNameMap>(
tag: T,
opts?: Partial<Omit<SwelOpts<T>, "children">>,
renderable?: Renderable,
): HTMLElementTagNameMap[T];
<T extends keyof HTMLElementTagNameMap>(
tag: T,
renderable?: Renderable,
): HTMLElementTagNameMap[T];
}
export const swel: Swel = <T extends keyof HTMLElementTagNameMap>(
tag: T,
opts?: Partial<SwelOpts<T>> | Renderable,
children?: Renderable,
): HTMLElementTagNameMap[T] => {
let o: Partial<SwelOpts<T>> | null = null;
if (children) {
let c: Child[] | null;
if (Array.isArray(children)) {
c = children;
} else {
c = [children];
}
o = {
...(opts as any),
children: c,
};
} else if (opts) {
if (Array.isArray(opts)) {
o = { children: opts } as any;
} else if (typeof opts === "string" || opts instanceof Node) {
o = { children: [opts] } as any;
} else {
o = opts;
}
} else {
o = {};
}
let o_ = o!;
if (o_.children) {
o_.children = o_.children.filter((c) => !!c) as any;
}
return swel_(tag, o);
};
const swel_ = <T extends keyof HTMLElementTagNameMap>(
tag: T,
opts: Partial<SwelOpts<T>> | null,
): HTMLElementTagNameMap[T] => {
const el = document.createElement(tag) as unknown as HTMLElementTagNameMap[T];
if (opts) {
const { children, on, attributes, style, ...rest } = opts;
if (children) {
el.append(...children);
}
if (on) {
Object.entries(on).forEach(([ev, h]) => {
el.addEventListener(ev, h as any);
});
}
if (attributes) {
Object.entries(attributes).map(([k, v]) => {
el.setAttribute(k, v as unknown as string);
});
}
if (style) {
Object.entries(style).map(([k, v]) => {
Reflect.set(el.style, k, v);
});
}
Object.assign(el, rest);
}
return el;
};