🚀 Socket Launch Week Day 4:Socket MCP Adds Org Alerts, Threat Feed Review, and Package Inspection.Learn more
Sign In

@seahax/elemental

Package Overview
Dependencies
Maintainers
2
Versions
48
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@seahax/elemental - npm Package Compare versions

Comparing version
0.6.7
to
0.7.0
+2
-22
dist/html.d.ts
type Alpha = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z';
type ChildValue = Node | HtmlDeferredElement | string | number | bigint | false | null | undefined;
type ChildValue = Node | string | number | bigint | false | null | undefined;
type AttrValue = string | number | bigint | boolean | null | undefined;

@@ -12,27 +12,7 @@ type TagMap = HTMLElementTagNameMap & HTMLElementDeprecatedTagNameMap;

export type HtmlConfig<TElement> = ElementAttrs<TElement> & ElementProps<ElementType<TElement>>;
export type HtmlConfigWithKey<TElement> = {
readonly [DATA_KEY]: string;
} & HtmlConfig<TElement>;
export interface HtmlDeferredElement<TElement extends HTMLElement = HTMLElement> {
readonly tag: string;
readonly config: {
readonly [DATA_KEY]: string;
} & HtmlConfig<TElement>;
readonly children: readonly ChildValue[] | undefined;
toElement: () => TElement;
}
declare const DATA_KEY = "data-key";
/**
* Create a deferred HTML element with a key.
*
* Final element creation is deferred until the element is used as a child,
* when it can be determined if a new element should be created, or an existing
* element with the same key and tag-name should be updated.
*/
export declare function html<const TElement extends keyof TagMap | (string & {}) | CustomElementConstructor>(el: TElement, config: HtmlConfigWithKey<TElement>, children?: readonly ChildValue[]): HtmlDeferredElement<ElementType<TElement>>;
/**
* Create or update an HTML element.
*/
export declare function html<TElement extends keyof TagMap | (string & {}) | CustomElementConstructor | Element | Document | ShadowRoot>(el: TElement, attrs?: HtmlConfig<TElement>, children?: readonly ChildValue[]): ElementType<NoInfer<TElement>>;
export declare function html<TElement extends keyof TagMap | (string & {}) | CustomElementConstructor | Element | Document | ShadowRoot>(el: TElement, config?: HtmlConfig<TElement>, children?: readonly ChildValue[]): ElementType<NoInfer<TElement>>;
export declare function html<TElement extends keyof TagMap | (string & {}) | CustomElementConstructor | Element | Document | ShadowRoot>(el: TElement, children?: readonly ChildValue[]): ElementType<TElement>;
export {};
+21
-33
//#region src/html.ts
var e = "data-key";
function t(n, r = {}, i = []) {
if (typeof n == "function") {
let e = customElements.getName(n);
e ?? (e = `ce-${crypto.randomUUID()}`, customElements.define(e, n)), n = e;
function e(e, t = {}, n) {
if (typeof e == "function") {
let t = customElements.getName(e);
t ?? (t = `ce-${crypto.randomUUID()}`, customElements.define(t, e)), e = t;
}
let a;
if ([a, i] = Array.isArray(r) ? [{}, r] : [r, i], typeof n == "string") return e in a ? {
tag: n,
config: a,
children: i,
toElement: () => t(document.createElement(n), a, i)
} : t(document.createElement(n), a, i);
if ("setAttribute" in n) {
for (let [e, t] of Object.entries(a)) if (!(t === void 0 || e.startsWith(":"))) if (t === null || t === !1) n.hasAttribute(e) && n.removeAttribute(e);
typeof e == "string" && (e = document.createElement(e));
let r;
if ([r, n] = Array.isArray(t) ? [{}, t] : [t, n], "setAttribute" in e) {
for (let [t, n] of Object.entries(r)) if (!(n === void 0 || t.startsWith(":"))) if (n === null || n === !1) e.hasAttribute(t) && e.removeAttribute(t);
else {
let r = t == 1 ? "" : String(t);
if (n.getAttribute(e) !== r) try {
n.setAttribute(e, r);
let r = n == 1 ? "" : String(n);
if (e.getAttribute(t) !== r) try {
e.setAttribute(t, r);
} catch (e) {

@@ -26,22 +20,16 @@ console.warn(e);

}
for (let [e, t] of Object.entries(a)) {
if (t === void 0 || !e.startsWith(":")) continue;
let r = e.slice(1);
Reflect.get(n, r) !== t && Reflect.set(n, r, t);
for (let [t, n] of Object.entries(r)) {
if (n === void 0 || !t.startsWith(":")) continue;
let r = t.slice(1);
Reflect.get(e, r) !== n && Reflect.set(e, r, n);
}
let o, s = document.activeElement;
return n.replaceChildren(...i.filter((e) => e != null && e !== !1).map((r) => {
if (typeof r != "object") return document.createTextNode(String(r));
if (r instanceof Node) return r;
o ??= new Map([...n.children].flatMap((t) => {
let n = t.getAttribute(e);
return n == null ? [] : [[n, t]];
}));
let i = r.config[e], a = o.get(i);
return a && a.tagName.toLowerCase() === r.tag ? (o.delete(i), t(a, r.config, r.children)) : r.toElement();
})), s?.isConnected && document.activeElement !== s && s.focus(), n;
if (n) {
let t = n.filter((e) => e != null && e !== !1).map((e) => typeof e == "object" ? e : document.createTextNode(String(e)));
e.replaceChildren(...t);
}
return e;
}
//#endregion
export { t as html };
export { e as html };
//# sourceMappingURL=html.js.map

@@ -1,1 +0,1 @@

{"version":3,"file":"html.js","names":[],"sources":["../src/html.ts"],"sourcesContent":["// prettier-ignore\ntype Alpha = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z';\ntype ChildValue = Node | HtmlDeferredElement | string | number | bigint | false | null | undefined;\ntype AttrValue = string | number | bigint | boolean | null | undefined;\ntype TagMap = HTMLElementTagNameMap & HTMLElementDeprecatedTagNameMap;\n\ntype IfEquals<T, U, Y = unknown, N = never> =\n (<G>() => G extends T ? 1 : 2) extends <G>() => G extends U ? 1 : 2 ? Y : N;\n\ntype ElementType<TElement> = TElement extends string\n ? TElement extends keyof TagMap\n ? TagMap[TElement]\n : HTMLElement\n : TElement extends CustomElementConstructor\n ? InstanceType<TElement>\n : TElement extends Element | Document | ShadowRoot\n ? TElement\n : never;\n\ntype ElementProps<TElement> = {\n readonly [P in keyof TElement & string as TElement[P] extends ((...args: any[]) => any) | null | undefined\n ? never\n : IfEquals<Record<P, TElement[P]>, Pick<TElement, P>, `:${P}`, never>]?: TElement[P];\n};\n\ntype ElementAttrs<TElement> = TElement extends string | CustomElementConstructor | Element\n ? Readonly<Record<`${Alpha}${string}`, AttrValue>>\n : {};\n\nexport type HtmlConfig<TElement> = ElementAttrs<TElement> & ElementProps<ElementType<TElement>>;\nexport type HtmlConfigWithKey<TElement> = { readonly [DATA_KEY]: string } & HtmlConfig<TElement>;\n\nexport interface HtmlDeferredElement<TElement extends HTMLElement = HTMLElement> {\n readonly tag: string;\n readonly config: { readonly [DATA_KEY]: string } & HtmlConfig<TElement>;\n readonly children: readonly ChildValue[] | undefined;\n toElement: () => TElement;\n}\n\nconst DATA_KEY = 'data-key';\n\n/**\n * Create a deferred HTML element with a key.\n *\n * Final element creation is deferred until the element is used as a child,\n * when it can be determined if a new element should be created, or an existing\n * element with the same key and tag-name should be updated.\n */\nexport function html<const TElement extends keyof TagMap | (string & {}) | CustomElementConstructor>(\n el: TElement,\n config: HtmlConfigWithKey<TElement>,\n children?: readonly ChildValue[],\n): HtmlDeferredElement<ElementType<TElement>>;\n\n/**\n * Create or update an HTML element.\n */\nexport function html<\n TElement extends keyof TagMap | (string & {}) | CustomElementConstructor | Element | Document | ShadowRoot,\n>(el: TElement, attrs?: HtmlConfig<TElement>, children?: readonly ChildValue[]): ElementType<NoInfer<TElement>>;\nexport function html<\n TElement extends keyof TagMap | (string & {}) | CustomElementConstructor | Element | Document | ShadowRoot,\n>(el: TElement, children?: readonly ChildValue[]): ElementType<TElement>;\n\nexport function html(\n el: string | CustomElementConstructor | Element | Document | ShadowRoot,\n attrsOrChildren: readonly ChildValue[] | Readonly<Record<string, any>> = {},\n children: readonly ChildValue[] = [],\n): Node | HtmlDeferredElement {\n if (typeof el === 'function') {\n let name = customElements.getName(el);\n\n if (name == null) {\n name = `ce-${crypto.randomUUID()}`;\n customElements.define(name, el);\n }\n\n el = name;\n }\n\n let attrs: Readonly<Record<string, any>>;\n [attrs, children] = Array.isArray(attrsOrChildren)\n ? [{}, attrsOrChildren as readonly ChildValue[]]\n : [attrsOrChildren as Readonly<Record<string, any>>, children];\n\n if (typeof el === 'string') {\n return DATA_KEY in attrs\n ? {\n tag: el,\n config: attrs as HtmlDeferredElement['config'],\n children,\n toElement: () => html(document.createElement(el), attrs, children),\n }\n : html(document.createElement(el), attrs, children);\n }\n\n if ('setAttribute' in el) {\n for (const [name, rawValue] of Object.entries(attrs)) {\n if (rawValue === undefined || name.startsWith(':')) continue;\n\n if (rawValue === null || rawValue === false) {\n if (el.hasAttribute(name)) el.removeAttribute(name);\n } else {\n const value = rawValue == true ? '' : String(rawValue);\n if (el.getAttribute(name) !== value) {\n try {\n el.setAttribute(name, value);\n } catch (error) {\n console.warn(error);\n }\n }\n }\n }\n }\n\n for (const [rawName, value] of Object.entries(attrs)) {\n if (value === undefined || !rawName.startsWith(':')) continue;\n const name = rawName.slice(1);\n if (Reflect.get(el, name) !== value) Reflect.set(el, name, value);\n }\n\n let keyElements: Map<string, Element> | undefined;\n const activeElement = document.activeElement;\n\n el.replaceChildren(\n ...children\n .filter((child) => child != null && child !== false)\n .map((child) => {\n if (typeof child !== 'object') return document.createTextNode(String(child));\n if (child instanceof Node) return child;\n\n keyElements ??= new Map(\n [...el.children].flatMap((child) => {\n const key = child.getAttribute(DATA_KEY);\n return key == null ? [] : [[key, child] as const];\n }),\n );\n\n const key = child.config[DATA_KEY];\n const reused = keyElements.get(key);\n\n if (reused && reused.tagName.toLowerCase() === child.tag) {\n keyElements.delete(key);\n return html(reused, child.config, child.children);\n }\n\n return child.toElement();\n }),\n );\n\n // Restore focus in case the current child contains focus.\n if (activeElement?.isConnected && document.activeElement !== activeElement) {\n (activeElement as HTMLElement).focus();\n }\n\n return el;\n}\n"],"mappings":";AAuCA,IAAM,IAAW;AAyBjB,SAAgB,EACd,GACA,IAAyE,EAAE,EAC3E,IAAkC,EAAE,EACR;AAC5B,KAAI,OAAO,KAAO,YAAY;EAC5B,IAAI,IAAO,eAAe,QAAQ,EAAG;AAOrC,EALI,MACF,IAAO,MAAM,OAAO,YAAY,IAChC,eAAe,OAAO,GAAM,EAAG,GAGjC,IAAK;;CAGP,IAAI;AAKJ,KAJA,CAAC,GAAO,KAAY,MAAM,QAAQ,EAAgB,GAC9C,CAAC,EAAE,EAAE,EAAyC,GAC9C,CAAC,GAAkD,EAAS,EAE5D,OAAO,KAAO,SAChB,QAAO,KAAY,IACf;EACE,KAAK;EACL,QAAQ;EACR;EACA,iBAAiB,EAAK,SAAS,cAAc,EAAG,EAAE,GAAO,EAAS;EACnE,GACD,EAAK,SAAS,cAAc,EAAG,EAAE,GAAO,EAAS;AAGvD,KAAI,kBAAkB,GACpB;OAAK,IAAM,CAAC,GAAM,MAAa,OAAO,QAAQ,EAAM,CAC9C,aAAa,KAAA,KAAa,EAAK,WAAW,IAAI,EAElD,KAAI,MAAa,QAAQ,MAAa,IAChC,EAAG,aAAa,EAAK,IAAE,EAAG,gBAAgB,EAAK;OAC9C;GACL,IAAM,IAAQ,KAAY,IAAO,KAAK,OAAO,EAAS;AACtD,OAAI,EAAG,aAAa,EAAK,KAAK,EAC5B,KAAI;AACF,MAAG,aAAa,GAAM,EAAM;YACrB,GAAO;AACd,YAAQ,KAAK,EAAM;;;;AAO7B,MAAK,IAAM,CAAC,GAAS,MAAU,OAAO,QAAQ,EAAM,EAAE;AACpD,MAAI,MAAU,KAAA,KAAa,CAAC,EAAQ,WAAW,IAAI,CAAE;EACrD,IAAM,IAAO,EAAQ,MAAM,EAAE;AAC7B,EAAI,QAAQ,IAAI,GAAI,EAAK,KAAK,KAAO,QAAQ,IAAI,GAAI,GAAM,EAAM;;CAGnE,IAAI,GACE,IAAgB,SAAS;AAiC/B,QA/BA,EAAG,gBACD,GAAG,EACA,QAAQ,MAAU,KAAS,QAAQ,MAAU,GAAM,CACnD,KAAK,MAAU;AACd,MAAI,OAAO,KAAU,SAAU,QAAO,SAAS,eAAe,OAAO,EAAM,CAAC;AAC5E,MAAI,aAAiB,KAAM,QAAO;AAElC,QAAgB,IAAI,IAClB,CAAC,GAAG,EAAG,SAAS,CAAC,SAAS,MAAU;GAClC,IAAM,IAAM,EAAM,aAAa,EAAS;AACxC,UAAO,KAAO,OAAO,EAAE,GAAG,CAAC,CAAC,GAAK,EAAM,CAAU;IACjD,CACH;EAED,IAAM,IAAM,EAAM,OAAO,IACnB,IAAS,EAAY,IAAI,EAAI;AAOnC,SALI,KAAU,EAAO,QAAQ,aAAa,KAAK,EAAM,OACnD,EAAY,OAAO,EAAI,EAChB,EAAK,GAAQ,EAAM,QAAQ,EAAM,SAAS,IAG5C,EAAM,WAAW;GACxB,CACL,EAGG,GAAe,eAAe,SAAS,kBAAkB,KAC1D,EAA8B,OAAO,EAGjC"}
{"version":3,"file":"html.js","names":[],"sources":["../src/html.ts"],"sourcesContent":["// prettier-ignore\ntype Alpha = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z';\ntype ChildValue = Node | string | number | bigint | false | null | undefined;\ntype AttrValue = string | number | bigint | boolean | null | undefined;\ntype TagMap = HTMLElementTagNameMap & HTMLElementDeprecatedTagNameMap;\n\ntype IfEquals<T, U, Y = unknown, N = never> =\n (<G>() => G extends T ? 1 : 2) extends <G>() => G extends U ? 1 : 2 ? Y : N;\n\ntype ElementType<TElement> = TElement extends string\n ? TElement extends keyof TagMap\n ? TagMap[TElement]\n : HTMLElement\n : TElement extends CustomElementConstructor\n ? InstanceType<TElement>\n : TElement extends Element | Document | ShadowRoot\n ? TElement\n : never;\n\ntype ElementProps<TElement> = {\n readonly [P in keyof TElement & string as TElement[P] extends ((...args: any[]) => any) | null | undefined\n ? never\n : IfEquals<Record<P, TElement[P]>, Pick<TElement, P>, `:${P}`, never>]?: TElement[P];\n};\n\ntype ElementAttrs<TElement> = TElement extends string | CustomElementConstructor | Element\n ? Readonly<Record<`${Alpha}${string}`, AttrValue>>\n : {};\n\nexport type HtmlConfig<TElement> = ElementAttrs<TElement> & ElementProps<ElementType<TElement>>;\n\n/**\n * Create or update an HTML element.\n */\nexport function html<\n TElement extends keyof TagMap | (string & {}) | CustomElementConstructor | Element | Document | ShadowRoot,\n>(el: TElement, config?: HtmlConfig<TElement>, children?: readonly ChildValue[]): ElementType<NoInfer<TElement>>;\nexport function html<\n TElement extends keyof TagMap | (string & {}) | CustomElementConstructor | Element | Document | ShadowRoot,\n>(el: TElement, children?: readonly ChildValue[]): ElementType<TElement>;\n\nexport function html(\n el: string | CustomElementConstructor | Element | Document | ShadowRoot,\n configOrChildren: readonly ChildValue[] | Readonly<Record<string, any>> = {},\n children?: readonly ChildValue[],\n): Node {\n if (typeof el === 'function') {\n let name = customElements.getName(el);\n\n if (name == null) {\n name = `ce-${crypto.randomUUID()}`;\n customElements.define(name, el);\n }\n\n el = name;\n }\n\n if (typeof el === 'string') el = document.createElement(el);\n\n let config: Readonly<Record<string, any>>;\n [config, children] = Array.isArray(configOrChildren)\n ? [{}, configOrChildren as readonly ChildValue[]]\n : [configOrChildren as Readonly<Record<string, any>>, children];\n\n if ('setAttribute' in el) {\n for (const [name, rawValue] of Object.entries(config)) {\n if (rawValue === undefined || name.startsWith(':')) continue;\n\n if (rawValue === null || rawValue === false) {\n if (el.hasAttribute(name)) el.removeAttribute(name);\n } else {\n const value = rawValue == true ? '' : String(rawValue);\n if (el.getAttribute(name) !== value) {\n try {\n el.setAttribute(name, value);\n } catch (error) {\n console.warn(error);\n }\n }\n }\n }\n }\n\n for (const [rawName, value] of Object.entries(config)) {\n if (value === undefined || !rawName.startsWith(':')) continue;\n const name = rawName.slice(1);\n if (Reflect.get(el, name) !== value) Reflect.set(el, name, value);\n }\n\n if (children) {\n const childNodes = children\n .filter((child) => child != null && child !== false)\n .map((child) => (typeof child !== 'object' ? document.createTextNode(String(child)) : child));\n\n el.replaceChildren(...childNodes);\n }\n\n return el;\n}\n"],"mappings":";AAyCA,SAAgB,EACd,GACA,IAA0E,EAAE,EAC5E,GACM;AACN,KAAI,OAAO,KAAO,YAAY;EAC5B,IAAI,IAAO,eAAe,QAAQ,EAAG;AAOrC,EALI,MACF,IAAO,MAAM,OAAO,YAAY,IAChC,eAAe,OAAO,GAAM,EAAG,GAGjC,IAAK;;AAGP,CAAI,OAAO,KAAO,aAAU,IAAK,SAAS,cAAc,EAAG;CAE3D,IAAI;AAKJ,KAJA,CAAC,GAAQ,KAAY,MAAM,QAAQ,EAAiB,GAChD,CAAC,EAAE,EAAE,EAA0C,GAC/C,CAAC,GAAmD,EAAS,EAE7D,kBAAkB,GACpB;OAAK,IAAM,CAAC,GAAM,MAAa,OAAO,QAAQ,EAAO,CAC/C,aAAa,KAAA,KAAa,EAAK,WAAW,IAAI,EAElD,KAAI,MAAa,QAAQ,MAAa,IAChC,EAAG,aAAa,EAAK,IAAE,EAAG,gBAAgB,EAAK;OAC9C;GACL,IAAM,IAAQ,KAAY,IAAO,KAAK,OAAO,EAAS;AACtD,OAAI,EAAG,aAAa,EAAK,KAAK,EAC5B,KAAI;AACF,MAAG,aAAa,GAAM,EAAM;YACrB,GAAO;AACd,YAAQ,KAAK,EAAM;;;;AAO7B,MAAK,IAAM,CAAC,GAAS,MAAU,OAAO,QAAQ,EAAO,EAAE;AACrD,MAAI,MAAU,KAAA,KAAa,CAAC,EAAQ,WAAW,IAAI,CAAE;EACrD,IAAM,IAAO,EAAQ,MAAM,EAAE;AAC7B,EAAI,QAAQ,IAAI,GAAI,EAAK,KAAK,KAAO,QAAQ,IAAI,GAAI,GAAM,EAAM;;AAGnE,KAAI,GAAU;EACZ,IAAM,IAAa,EAChB,QAAQ,MAAU,KAAS,QAAQ,MAAU,GAAM,CACnD,KAAK,MAAW,OAAO,KAAU,WAAoD,IAAzC,SAAS,eAAe,OAAO,EAAM,CAAC,CAAU;AAE/F,IAAG,gBAAgB,GAAG,EAAW;;AAGnC,QAAO"}

@@ -24,3 +24,3 @@ {

},
"version": "0.6.7"
"version": "0.7.0"
}

@@ -9,3 +9,2 @@ # @seahax/elemental

- Direct and safe access to the DOM (no virtual DOM)
- React-style list rendering using unique keys
- React-style code reuse using composable hooks

@@ -351,20 +350,2 @@ - Global & local state reactivity

## Render Lists With Keys
```ts
// Create a reusable root element.
const parent = h('div');
h(parent, items.map((item) => {
// No previous children, so all children will be created.
return h('p', { 'data-key': item.id }, [item.text]);
}));
// Update children with matching keys.
h(parent, items.map((item) => {
// Second render, so reuse (and update) children with matching keys.
return h('p', { 'data-key': item.id }, [item.text]);
}));
```
## Combine Conditional Classes

@@ -371,0 +352,0 @@