107 lines
3.6 KiB
TypeScript
107 lines
3.6 KiB
TypeScript
import { iconLoaded, loadIcon, getIcon } from "iconify-icon";
|
|
import type { NodeProperties, Class } from "#shared/dom.util";
|
|
|
|
export type VirtualNode = string;
|
|
export function dom<K extends keyof HTMLElementTagNameMap>(tag: K, properties?: NodeProperties, children?: VirtualNode[]): VirtualNode
|
|
{
|
|
const node = [`<${tag}`];
|
|
if(properties?.attributes)
|
|
for(const [k, v] of Object.entries(properties.attributes))
|
|
if(typeof v === 'string' || typeof v === 'number') node.push(` ${k}="${v.toString(10).replaceAll('"', "'")}"`);
|
|
else if(typeof v === 'boolean' && v) node.push(` ${k.replaceAll('"', "'")}`);
|
|
|
|
if(properties?.class)
|
|
node.push(` class="${mergeClasses(properties.class).replaceAll('"', "'")}"`);
|
|
|
|
if(properties?.style)
|
|
{
|
|
if(typeof properties.style === 'string') node.push(` style="${properties.style.replaceAll('"', "'")}"`);
|
|
else node.push(` style="${Object.entries(properties.style).map(([k, v]) => { if(v !== undefined && v !== false) return `${k.replaceAll('"', "'")}: ${v.toString(10).replaceAll('"', "'")};` }).join('')}"`);
|
|
}
|
|
|
|
if(properties?.text)
|
|
{
|
|
const text = typeof properties.text === 'function' ? properties.text() : properties.text;
|
|
children ??= [];
|
|
text && children?.push(text.toString());
|
|
}
|
|
|
|
if(children)
|
|
node.push(`>${children.filter(e => !!e).join('')}</${tag}>`);
|
|
else
|
|
node.push(`></${tag}>`)
|
|
|
|
return node.join('');
|
|
}
|
|
export function div(cls?: Class, children?: VirtualNode[]): VirtualNode
|
|
{
|
|
return dom("div", { class: cls }, children);
|
|
}
|
|
export function span(cls?: Class, text?: string): VirtualNode
|
|
{
|
|
return dom("span", { class: cls, text: text });
|
|
}
|
|
export function svg<K extends keyof SVGElementTagNameMap>(tag: K, properties?: NodeProperties, children?: VirtualNode[]): VirtualNode
|
|
{
|
|
const node = [`<${tag}`];
|
|
if(properties?.attributes)
|
|
for(const [k, v] of Object.entries(properties.attributes))
|
|
if(typeof v === 'string' || typeof v === 'number') node.push(` ${k.replaceAll('"', "'")}="${v.toString(10).replaceAll('"', "'")}"`);
|
|
else if(typeof v === 'boolean' && v) node.push(` ${k.replaceAll('"', "'")}`);
|
|
|
|
if(properties?.class)
|
|
node.push(` class="${mergeClasses(properties.class).replaceAll('"', "'")}"`);
|
|
|
|
if(properties?.style)
|
|
{
|
|
if(typeof properties.style === 'string') node.push(` style="${properties.style.replaceAll('"', "'")}"`);
|
|
else node.push(` style="${Object.entries(properties.style).map(([k, v]) => { if(v !== undefined && v !== false) return `${k.replaceAll('"', "'")}: ${v.toString(10).replaceAll('"', "'")};"` }).join('')}"`);
|
|
}
|
|
|
|
if(children)
|
|
node.push(`>${children.filter(e => !!e).join('')}</${tag}>`);
|
|
else
|
|
node.push(`></${tag}>`)
|
|
|
|
return node.join(' ');
|
|
}
|
|
export function text(data: string): VirtualNode
|
|
{
|
|
return data;
|
|
}
|
|
export interface IconProperties
|
|
{
|
|
mode?: string;
|
|
inline?: boolean;
|
|
noobserver?: boolean;
|
|
width?: string|number;
|
|
height?: string|number;
|
|
flip?: string;
|
|
rotate?: number|string;
|
|
style?: Record<string, string | undefined> | string;
|
|
class?: Class;
|
|
}
|
|
export function icon(name: string, properties?: IconProperties): VirtualNode
|
|
{
|
|
return '';
|
|
}
|
|
|
|
export function mergeClasses(classes: Class): string
|
|
{
|
|
if(typeof classes === 'string')
|
|
{
|
|
return classes.trim();
|
|
}
|
|
else if(Array.isArray(classes))
|
|
{
|
|
return classes.map(e => mergeClasses(e)).join(' ');
|
|
}
|
|
else if(classes)
|
|
{
|
|
return Object.entries(classes).filter(e => e[1]).map(e => e[0].trim()).join(' ');
|
|
}
|
|
else
|
|
{
|
|
return '';
|
|
}
|
|
} |