allow stuff like style to be easily specified using the old fashioned way

This commit is contained in:
Hamcha 2024-10-12 23:29:48 +02:00
parent de82c0f0a5
commit f03c6475bc
Signed by: hamcha
GPG key ID: 1669C533B8CF6D89

View file

@ -2,68 +2,79 @@
// Licensed under AGPL-3.0, check `LICENSE` for the full text. // Licensed under AGPL-3.0, check `LICENSE` for the full text.
type ElementProperties<T extends keyof HTMLElementTagNameMap> = { type ElementProperties<T extends keyof HTMLElementTagNameMap> = {
[key in keyof HTMLElementTagNameMap[T]]: HTMLElementTagNameMap[T][key]; [key in keyof HTMLElementTagNameMap[T]]:
| HTMLElementTagNameMap[T][key]
| string;
} & { } & {
[key in keyof HTMLElementEventMap as `@${key}`]: ( [key in keyof HTMLElementEventMap as `@${key}`]: (
this: HTMLElement, this: HTMLElement,
ev: HTMLElementEventMap[key] ev: HTMLElementEventMap[key],
) => void; ) => void;
}; };
type DOMElem = Node | string; type DOMElem = Node | string;
type WithClassOrId<T extends keyof HTMLElementTagNameMap> = type WithClassOrId<T extends keyof HTMLElementTagNameMap> =
| `${T}#${string}` | `${T}#${string}`
| `${T}.${string}`; | `${T}.${string}`;
export function $el<T extends keyof HTMLElementTagNameMap>( export function $el<T extends keyof HTMLElementTagNameMap>(
name: T | WithClassOrId<T>, name: T | WithClassOrId<T>,
...desc: [Partial<ElementProperties<T>>, ...DOMElem[]] | DOMElem[] ...desc: [Partial<ElementProperties<T>>, ...DOMElem[]] | DOMElem[]
): HTMLElementTagNameMap[T] { ): HTMLElementTagNameMap[T] {
// Take off ID or class from the name // Take off ID or class from the name
let elementName = name as string; let elementName = name as string;
let className = ""; let className = "";
let id = ""; let id = "";
if (name.includes("#")) { if (name.includes("#")) {
[elementName, id] = name.split("#"); [elementName, id] = name.split("#");
} }
if (name.includes(".")) { if (name.includes(".")) {
[elementName, className] = name.split("."); [elementName, className] = name.split(".");
} }
// Create the element and add the attributes (if found) // Create the element and add the attributes (if found)
const el = document.createElement(elementName as T); const el = document.createElement(elementName as T);
if (className) { if (className) {
el.className = className; el.className = className;
} }
if (id) { if (id) {
el.id = id; el.id = id;
} }
const attributes = desc[0]; const attributes = desc[0];
if (typeof attributes === "object" && !(attributes instanceof Node)) { if (typeof attributes === "object" && !(attributes instanceof Node)) {
for (const attr in attributes) { for (const attr in attributes) {
const value = (attributes as Record<string, any>)[attr]; const value = (attributes as Record<string, unknown>)[attr];
if (attr.startsWith("@")) { if (attr.startsWith("@")) {
el.addEventListener(attr.substring(1), value); el.addEventListener(
} else if (attr === "dataset") { attr.substring(1),
for (const key in value) { value as EventListenerOrEventListenerObject,
el.dataset[key] = value[key]; );
} } else if (attr === "dataset") {
} else { for (const key in value as Record<string, unknown>) {
el[attr as keyof HTMLElementTagNameMap[T]] = value; el.dataset[key] = (value as Record<string, string>)[key];
} }
} } else {
desc.shift(); // For some tricky attributes, set them the old fashioned way using strings
} if (typeof value === "string") {
el.setAttribute(attr, value as string);
} else {
el[attr as keyof HTMLElementTagNameMap[T]] =
value as HTMLElementTagNameMap[T][keyof HTMLElementTagNameMap[T]];
}
}
}
desc.shift();
}
for (const item of desc as DOMElem[]) { for (const item of desc as DOMElem[]) {
el.appendChild(item instanceof Node ? item : document.createTextNode(item)); el.appendChild(item instanceof Node ? item : document.createTextNode(item));
} }
return el; return el;
} }
export default $el; export default $el;