mirror of
				https://github.com/jaandrle/deka-dom-el
				synced 2025-10-31 13:59:14 +01:00 
			
		
		
		
	Compare commits
	
		
			8 Commits
		
	
	
		
			93b905e677
			...
			64566f17af
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 64566f17af | |||
| 2fcec0551c | |||
| 7ed2856298 | |||
| a2b0223c4f | |||
| 19b0e4666e | |||
| 3823b66003 | |||
| ba13055d7d | |||
| 36fab5276d | 
							
								
								
									
										26
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								README.md
									
									
									
									
									
								
							| @@ -31,7 +31,7 @@ function EmojiCounter({ initial }) { | |||||||
| 		el("p", { | 		el("p", { | ||||||
| 			className: "output", | 			className: "output", | ||||||
| 			textContent: S(() => | 			textContent: S(() => | ||||||
| 				`Hello World ${emoji.get().repeat(clicks.get())}`), | 				`Hello World ${emoji.get().repeat(count.get())}`), | ||||||
| 		}), | 		}), | ||||||
|  |  | ||||||
| 		// 🎮 Controls - Update state on events | 		// 🎮 Controls - Update state on events | ||||||
| @@ -39,12 +39,12 @@ function EmojiCounter({ initial }) { | |||||||
| 			on("click", () => count.set(count.get() + 1)) | 			on("click", () => count.set(count.get() + 1)) | ||||||
| 		), | 		), | ||||||
|  |  | ||||||
| 		el("select", null, | 		el("select", null, on.host(el=> el.value= initial), | ||||||
| 			on("change", e => emoji.set(e.target.value)) | 			on("change", e => emoji.set(e.target.value)) | ||||||
| 		).append( | 		).append( | ||||||
| 			el(Option, "🎉", isSelected), | 			el(Option, "🎉"), | ||||||
| 			el(Option, "🚀", isSelected), | 			el(Option, "🚀"), | ||||||
| 			el(Option, "💖", isSelected), | 			el(Option, "💖"), | ||||||
| 		) | 		) | ||||||
| 	); | 	); | ||||||
| } | } | ||||||
| @@ -93,11 +93,23 @@ into existing projects. | |||||||
| # npm install deka-dom-el | # npm install deka-dom-el | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| #### Direct Script | #### CDN / Direct Script | ||||||
|  |  | ||||||
|  | For CDN links and various build formats (ESM/IIFE, with/without signals, minified/unminified), see the [interactive | ||||||
|  | format selector](https://jaandrle.github.io/deka-dom-el/) on the documentation site. | ||||||
|  |  | ||||||
| ```html | ```html | ||||||
|  | <!-- Example with IIFE build (creates a global DDE object) --> | ||||||
| <script src="https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/iife-with-signals.min.js"></script> | <script src="https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/iife-with-signals.min.js"></script> | ||||||
| <script type="module"> | <script> | ||||||
| 	const { el, S } = DDE; | 	const { el, S } = DDE; | ||||||
|  | 	// Your code here | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <!-- Or with ES modules --> | ||||||
|  | <script type="module"> | ||||||
|  | 	import { el, S } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.min.js"; | ||||||
|  | 	// Your code here | ||||||
| </script> | </script> | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										29
									
								
								dist/esm-with-signals.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								dist/esm-with-signals.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -4,7 +4,7 @@ export interface Signal<V, A> { | |||||||
| 	/** The current value of the signal */ | 	/** The current value of the signal */ | ||||||
| 	get(): V; | 	get(): V; | ||||||
| 	/** Set new value of the signal */ | 	/** Set new value of the signal */ | ||||||
| 	set(value: V): V; | 	set(value: V, force?: boolean): V; | ||||||
| 	toJSON(): V; | 	toJSON(): V; | ||||||
| 	valueOf(): V; | 	valueOf(): V; | ||||||
| } | } | ||||||
| @@ -173,17 +173,28 @@ declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options? | |||||||
| declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options: EventInit | null, host: Host<SupportedElement>): (data?: any) => void; | declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options: EventInit | null, host: Host<SupportedElement>): (data?: any) => void; | ||||||
| export interface On { | export interface On { | ||||||
| 	/** Listens to the DOM event. See {@link Document.addEventListener} */ | 	/** Listens to the DOM event. See {@link Document.addEventListener} */ | ||||||
| 	<Event extends keyof DocumentEventMap, EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: Event, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: DocumentEventMap[Event]) => any, options?: AddEventListenerOptions): EE; | 	<Event extends keyof DocumentEventMap, EL extends SupportedElement>(type: Event, listener: (this: EL, ev: DocumentEventMap[Event]) => any, options?: AddEventListenerOptions): ddeElementAddon<EL>; | ||||||
| 	<EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: string, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: Event | CustomEvent) => any, options?: AddEventListenerOptions): EE; | 	<EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: string, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: Event | CustomEvent) => any, options?: AddEventListenerOptions): EE; | ||||||
| 	/** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | 	/** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | ||||||
| 	connected<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<El>) => any, options?: AddEventListenerOptions): EE; | 	connected<EL extends SupportedElement>(listener: (this: EL, event: CustomEvent<NoInfer<EL>>) => any, options?: AddEventListenerOptions): ddeElementAddon<EL>; | ||||||
| 	/** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | 	/** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | ||||||
| 	disconnected<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<void>) => any, options?: AddEventListenerOptions): EE; | 	disconnected<EL extends SupportedElement>(listener: (this: EL, event: CustomEvent<void>) => any, options?: AddEventListenerOptions): ddeElementAddon<EL>; | ||||||
| 	/** Listens to the element attribute changes. In case of custom elements uses [`attributeChangedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | 	/** | ||||||
| 	attributeChanged<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<[ | 	 * Fires when the host element is "ready", for host element itsel, it is just an alias for `scope.host(listener)`. | ||||||
| 		string, | 	 * This is handy to apply some property depending on full template such as: | ||||||
| 		string | 	 * ```js | ||||||
| 	]>) => any, options?: AddEventListenerOptions): EE; | 	 * const selected= "Z"; | ||||||
|  | 	 * //... | ||||||
|  | 	 * return el("form").append( | ||||||
|  | 	 *		el("select", null, on.host(e=> e.value=selected)).append( | ||||||
|  | 	 *			el("option", { value: "A", textContent: "A" }), | ||||||
|  | 	 *			//... | ||||||
|  | 	 *			el("option", { value: "Z", textContent: "Z" }), | ||||||
|  | 	 *		), | ||||||
|  | 	 * ); | ||||||
|  | 	 * ``` | ||||||
|  | 	 * */ | ||||||
|  | 	host<EL extends SupportedElement>(listener: (element: EL) => any, host?: Host<SupportedElement>): ddeElementAddon<EL>; | ||||||
| } | } | ||||||
| export const on: On; | export const on: On; | ||||||
| export type Scope = { | export type Scope = { | ||||||
|   | |||||||
							
								
								
									
										180
									
								
								dist/esm-with-signals.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										180
									
								
								dist/esm-with-signals.js
									
									
									
									
										vendored
									
									
								
							| @@ -55,38 +55,7 @@ var Defined = class extends Error { | |||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
|  |  | ||||||
| // src/signals-lib/common.js | // src/dom-lib/common.js | ||||||
| var signals_global = { |  | ||||||
| 	/** |  | ||||||
| 	* Checks if a value is a signal |  | ||||||
| 	* @param {any} attributes - Value to check |  | ||||||
| 	* @returns {boolean} Whether the value is a signal |  | ||||||
| 	*/ |  | ||||||
| 	isSignal(attributes) { |  | ||||||
| 		return false; |  | ||||||
| 	}, |  | ||||||
| 	/** |  | ||||||
| 	* Processes an attribute that might be reactive |  | ||||||
| 	* @param {Element} obj - Element that owns the attribute |  | ||||||
| 	* @param {string} key - Attribute name |  | ||||||
| 	* @param {any} attr - Attribute value |  | ||||||
| 	* @param {Function} set - Function to set the attribute |  | ||||||
| 	* @returns {any} Processed attribute value |  | ||||||
| 	*/ |  | ||||||
| 	processReactiveAttribute(obj, key, attr, set) { |  | ||||||
| 		return attr; |  | ||||||
| 	} |  | ||||||
| }; |  | ||||||
| function registerReactivity(def, global = true) { |  | ||||||
| 	if (global) return oAssign(signals_global, def); |  | ||||||
| 	Object.setPrototypeOf(def, signals_global); |  | ||||||
| 	return def; |  | ||||||
| } |  | ||||||
| function signals(_this) { |  | ||||||
| 	return isProtoFrom(_this, signals_global) && _this !== signals_global ? _this : signals_global; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // src/dom-common.js |  | ||||||
| var enviroment = { | var enviroment = { | ||||||
| 	setDeleteAttr, | 	setDeleteAttr, | ||||||
| 	ssr: "", | 	ssr: "", | ||||||
| @@ -112,7 +81,7 @@ var evc = "dde:connected"; | |||||||
| var evd = "dde:disconnected"; | var evd = "dde:disconnected"; | ||||||
| var eva = "dde:attributeChanged"; | var eva = "dde:attributeChanged"; | ||||||
|  |  | ||||||
| // src/events-observer.js | // src/dom-lib/events-observer.js | ||||||
| var c_ch_o = enviroment.M ? connectionsChangesObserverConstructor() : new Proxy({}, { | var c_ch_o = enviroment.M ? connectionsChangesObserverConstructor() : new Proxy({}, { | ||||||
| 	get() { | 	get() { | ||||||
| 		return () => { | 		return () => { | ||||||
| @@ -276,7 +245,7 @@ function connectionsChangesObserverConstructor() { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| // src/events.js | // src/dom-lib/events.js | ||||||
| function dispatchEvent(name, options, host) { | function dispatchEvent(name, options, host) { | ||||||
| 	if (typeof options === "function") { | 	if (typeof options === "function") { | ||||||
| 		host = options; | 		host = options; | ||||||
| @@ -321,10 +290,7 @@ on.disconnected = function(listener, options) { | |||||||
| 	}; | 	}; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| // src/dom.js | // src/dom-lib/scopes.js | ||||||
| function queue(promise) { |  | ||||||
| 	return enviroment.q(promise); |  | ||||||
| } |  | ||||||
| var scopes = [{ | var scopes = [{ | ||||||
| 	get scope() { | 	get scope() { | ||||||
| 		return enviroment.D.body; | 		return enviroment.D.body; | ||||||
| @@ -399,6 +365,61 @@ var scope = { | |||||||
| 		return scopes.pop(); | 		return scopes.pop(); | ||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
|  | on.host = (fn, host = scope.host) => (el) => host(() => fn(el)); | ||||||
|  |  | ||||||
|  | // src/signals-lib/common.js | ||||||
|  | var signals_global = { | ||||||
|  | 	/** | ||||||
|  | 	* Checks if a value is a signal | ||||||
|  | 	* @param {any} attributes - Value to check | ||||||
|  | 	* @returns {boolean} Whether the value is a signal | ||||||
|  | 	*/ | ||||||
|  | 	isSignal(attributes) { | ||||||
|  | 		return false; | ||||||
|  | 	}, | ||||||
|  | 	/** | ||||||
|  | 	* Processes an attribute that might be reactive | ||||||
|  | 	* @param {Element} obj - Element that owns the attribute | ||||||
|  | 	* @param {string} key - Attribute name | ||||||
|  | 	* @param {any} attr - Attribute value | ||||||
|  | 	* @param {Function} set - Function to set the attribute | ||||||
|  | 	* @returns {any} Processed attribute value | ||||||
|  | 	*/ | ||||||
|  | 	processReactiveAttribute(obj, key, attr, set) { | ||||||
|  | 		return attr; | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  | function registerReactivity(def, global = true) { | ||||||
|  | 	if (global) return oAssign(signals_global, def); | ||||||
|  | 	Object.setPrototypeOf(def, signals_global); | ||||||
|  | 	return def; | ||||||
|  | } | ||||||
|  | function signals(_this) { | ||||||
|  | 	return isProtoFrom(_this, signals_global) && _this !== signals_global ? _this : signals_global; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // src/dom-lib/helpers.js | ||||||
|  | function setRemove(obj, prop, key, val) { | ||||||
|  | 	return obj[(isUndef(val) ? "remove" : "set") + prop](key, val); | ||||||
|  | } | ||||||
|  | function setRemoveNS(obj, prop, key, val, ns = null) { | ||||||
|  | 	return obj[(isUndef(val) ? "remove" : "set") + prop + "NS"](ns, key, val); | ||||||
|  | } | ||||||
|  | function setDelete(obj, key, val) { | ||||||
|  | 	Reflect.set(obj, key, val); | ||||||
|  | 	if (!isUndef(val)) return; | ||||||
|  | 	return Reflect.deleteProperty(obj, key); | ||||||
|  | } | ||||||
|  | function elementAttribute(element, op, key, value) { | ||||||
|  | 	if (isInstance(element, enviroment.H)) | ||||||
|  | 		return element[op + "Attribute"](key, value); | ||||||
|  | 	return element[op + "AttributeNS"](null, key, value); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // src/dom-lib/el.js | ||||||
|  | function queue(promise) { | ||||||
|  | 	return enviroment.q(promise); | ||||||
|  | } | ||||||
| function append(...els) { | function append(...els) { | ||||||
| 	this.appendOriginal(...els); | 	this.appendOriginal(...els); | ||||||
| 	return this; | 	return this; | ||||||
| @@ -468,38 +489,6 @@ function createElementNS(ns) { | |||||||
| 		return el; | 		return el; | ||||||
| 	}; | 	}; | ||||||
| } | } | ||||||
| function simulateSlots(element, root = element) { |  | ||||||
| 	const mark_e = "\xB9\u2070", mark_s = "\u2713"; |  | ||||||
| 	const slots = Object.fromEntries( |  | ||||||
| 		Array.from(root.querySelectorAll("slot")).filter((s) => !s.name.endsWith(mark_e)).map((s) => [s.name += mark_e, s]) |  | ||||||
| 	); |  | ||||||
| 	element.append = new Proxy(element.append, { |  | ||||||
| 		apply(orig, _, els) { |  | ||||||
| 			if (els[0] === root) return orig.apply(element, els); |  | ||||||
| 			for (const el of els) { |  | ||||||
| 				const name = (el.slot || "") + mark_e; |  | ||||||
| 				try { |  | ||||||
| 					elementAttribute(el, "remove", "slot"); |  | ||||||
| 				} catch (_error) { |  | ||||||
| 				} |  | ||||||
| 				const slot = slots[name]; |  | ||||||
| 				if (!slot) return; |  | ||||||
| 				if (!slot.name.startsWith(mark_s)) { |  | ||||||
| 					slot.childNodes.forEach((c) => c.remove()); |  | ||||||
| 					slot.name = mark_s + name; |  | ||||||
| 				} |  | ||||||
| 				slot.append(el); |  | ||||||
| 			} |  | ||||||
| 			element.append = orig; |  | ||||||
| 			return element; |  | ||||||
| 		} |  | ||||||
| 	}); |  | ||||||
| 	if (element !== root) { |  | ||||||
| 		const els = Array.from(element.childNodes); |  | ||||||
| 		element.append(...els); |  | ||||||
| 	} |  | ||||||
| 	return root; |  | ||||||
| } |  | ||||||
| var assign_context = /* @__PURE__ */ new WeakMap(); | var assign_context = /* @__PURE__ */ new WeakMap(); | ||||||
| var { setDeleteAttr: setDeleteAttr2 } = enviroment; | var { setDeleteAttr: setDeleteAttr2 } = enviroment; | ||||||
| function assign(element, ...attributes) { | function assign(element, ...attributes) { | ||||||
| @@ -562,11 +551,6 @@ function classListDeclarative(element, toggle) { | |||||||
| 	); | 	); | ||||||
| 	return element; | 	return element; | ||||||
| } | } | ||||||
| function elementAttribute(element, op, key, value) { |  | ||||||
| 	if (isInstance(element, enviroment.H)) |  | ||||||
| 		return element[op + "Attribute"](key, value); |  | ||||||
| 	return element[op + "AttributeNS"](null, key, value); |  | ||||||
| } |  | ||||||
| function isPropSetter(el, key) { | function isPropSetter(el, key) { | ||||||
| 	if (!(key in el)) return false; | 	if (!(key in el)) return false; | ||||||
| 	const des = getPropDescriptor(el, key); | 	const des = getPropDescriptor(el, key); | ||||||
| @@ -590,19 +574,40 @@ function forEachEntries(s, target, element, obj, cb) { | |||||||
| 		cb(key, val); | 		cb(key, val); | ||||||
| 	}); | 	}); | ||||||
| } | } | ||||||
| function setRemove(obj, prop, key, val) { |  | ||||||
| 	return obj[(isUndef(val) ? "remove" : "set") + prop](key, val); |  | ||||||
| } |  | ||||||
| function setRemoveNS(obj, prop, key, val, ns = null) { |  | ||||||
| 	return obj[(isUndef(val) ? "remove" : "set") + prop + "NS"](ns, key, val); |  | ||||||
| } |  | ||||||
| function setDelete(obj, key, val) { |  | ||||||
| 	Reflect.set(obj, key, val); |  | ||||||
| 	if (!isUndef(val)) return; |  | ||||||
| 	return Reflect.deleteProperty(obj, key); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // src/customElement.js | // src/dom-lib/customElement.js | ||||||
|  | function simulateSlots(element, root = element) { | ||||||
|  | 	const mark_e = "\xB9\u2070", mark_s = "\u2713"; | ||||||
|  | 	const slots = Object.fromEntries( | ||||||
|  | 		Array.from(root.querySelectorAll("slot")).filter((s) => !s.name.endsWith(mark_e)).map((s) => [s.name += mark_e, s]) | ||||||
|  | 	); | ||||||
|  | 	element.append = new Proxy(element.append, { | ||||||
|  | 		apply(orig, _, els) { | ||||||
|  | 			if (els[0] === root) return orig.apply(element, els); | ||||||
|  | 			for (const el of els) { | ||||||
|  | 				const name = (el.slot || "") + mark_e; | ||||||
|  | 				try { | ||||||
|  | 					elementAttribute(el, "remove", "slot"); | ||||||
|  | 				} catch (_error) { | ||||||
|  | 				} | ||||||
|  | 				const slot = slots[name]; | ||||||
|  | 				if (!slot) return; | ||||||
|  | 				if (!slot.name.startsWith(mark_s)) { | ||||||
|  | 					slot.childNodes.forEach((c) => c.remove()); | ||||||
|  | 					slot.name = mark_s + name; | ||||||
|  | 				} | ||||||
|  | 				slot.append(el); | ||||||
|  | 			} | ||||||
|  | 			element.append = orig; | ||||||
|  | 			return element; | ||||||
|  | 		} | ||||||
|  | 	}); | ||||||
|  | 	if (element !== root) { | ||||||
|  | 		const els = Array.from(element.childNodes); | ||||||
|  | 		element.append(...els); | ||||||
|  | 	} | ||||||
|  | 	return root; | ||||||
|  | } | ||||||
| function customElementRender(target, render, props = {}) { | function customElementRender(target, render, props = {}) { | ||||||
| 	const custom_element = target.host || target; | 	const custom_element = target.host || target; | ||||||
| 	scope.push({ | 	scope.push({ | ||||||
| @@ -1004,7 +1009,6 @@ export { | |||||||
| 	dispatchEvent, | 	dispatchEvent, | ||||||
| 	createElement as el, | 	createElement as el, | ||||||
| 	createElementNS as elNS, | 	createElementNS as elNS, | ||||||
| 	elementAttribute, |  | ||||||
| 	isSignal, | 	isSignal, | ||||||
| 	lifecyclesToEvents, | 	lifecyclesToEvents, | ||||||
| 	memo, | 	memo, | ||||||
|   | |||||||
							
								
								
									
										29
									
								
								dist/esm-with-signals.min.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								dist/esm-with-signals.min.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -4,7 +4,7 @@ export interface Signal<V, A> { | |||||||
| 	/** The current value of the signal */ | 	/** The current value of the signal */ | ||||||
| 	get(): V; | 	get(): V; | ||||||
| 	/** Set new value of the signal */ | 	/** Set new value of the signal */ | ||||||
| 	set(value: V): V; | 	set(value: V, force?: boolean): V; | ||||||
| 	toJSON(): V; | 	toJSON(): V; | ||||||
| 	valueOf(): V; | 	valueOf(): V; | ||||||
| } | } | ||||||
| @@ -173,17 +173,28 @@ declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options? | |||||||
| declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options: EventInit | null, host: Host<SupportedElement>): (data?: any) => void; | declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options: EventInit | null, host: Host<SupportedElement>): (data?: any) => void; | ||||||
| export interface On { | export interface On { | ||||||
| 	/** Listens to the DOM event. See {@link Document.addEventListener} */ | 	/** Listens to the DOM event. See {@link Document.addEventListener} */ | ||||||
| 	<Event extends keyof DocumentEventMap, EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: Event, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: DocumentEventMap[Event]) => any, options?: AddEventListenerOptions): EE; | 	<Event extends keyof DocumentEventMap, EL extends SupportedElement>(type: Event, listener: (this: EL, ev: DocumentEventMap[Event]) => any, options?: AddEventListenerOptions): ddeElementAddon<EL>; | ||||||
| 	<EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: string, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: Event | CustomEvent) => any, options?: AddEventListenerOptions): EE; | 	<EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: string, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: Event | CustomEvent) => any, options?: AddEventListenerOptions): EE; | ||||||
| 	/** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | 	/** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | ||||||
| 	connected<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<El>) => any, options?: AddEventListenerOptions): EE; | 	connected<EL extends SupportedElement>(listener: (this: EL, event: CustomEvent<NoInfer<EL>>) => any, options?: AddEventListenerOptions): ddeElementAddon<EL>; | ||||||
| 	/** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | 	/** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | ||||||
| 	disconnected<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<void>) => any, options?: AddEventListenerOptions): EE; | 	disconnected<EL extends SupportedElement>(listener: (this: EL, event: CustomEvent<void>) => any, options?: AddEventListenerOptions): ddeElementAddon<EL>; | ||||||
| 	/** Listens to the element attribute changes. In case of custom elements uses [`attributeChangedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | 	/** | ||||||
| 	attributeChanged<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<[ | 	 * Fires when the host element is "ready", for host element itsel, it is just an alias for `scope.host(listener)`. | ||||||
| 		string, | 	 * This is handy to apply some property depending on full template such as: | ||||||
| 		string | 	 * ```js | ||||||
| 	]>) => any, options?: AddEventListenerOptions): EE; | 	 * const selected= "Z"; | ||||||
|  | 	 * //... | ||||||
|  | 	 * return el("form").append( | ||||||
|  | 	 *		el("select", null, on.host(e=> e.value=selected)).append( | ||||||
|  | 	 *			el("option", { value: "A", textContent: "A" }), | ||||||
|  | 	 *			//... | ||||||
|  | 	 *			el("option", { value: "Z", textContent: "Z" }), | ||||||
|  | 	 *		), | ||||||
|  | 	 * ); | ||||||
|  | 	 * ``` | ||||||
|  | 	 * */ | ||||||
|  | 	host<EL extends SupportedElement>(listener: (element: EL) => any, host?: Host<SupportedElement>): ddeElementAddon<EL>; | ||||||
| } | } | ||||||
| export const on: On; | export const on: On; | ||||||
| export type Scope = { | export type Scope = { | ||||||
|   | |||||||
							
								
								
									
										8
									
								
								dist/esm-with-signals.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								dist/esm-with-signals.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										29
									
								
								dist/esm.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								dist/esm.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -4,7 +4,7 @@ export interface Signal<V, A> { | |||||||
| 	/** The current value of the signal */ | 	/** The current value of the signal */ | ||||||
| 	get(): V; | 	get(): V; | ||||||
| 	/** Set new value of the signal */ | 	/** Set new value of the signal */ | ||||||
| 	set(value: V): V; | 	set(value: V, force?: boolean): V; | ||||||
| 	toJSON(): V; | 	toJSON(): V; | ||||||
| 	valueOf(): V; | 	valueOf(): V; | ||||||
| } | } | ||||||
| @@ -172,17 +172,28 @@ declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options? | |||||||
| declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options: EventInit | null, host: Host<SupportedElement>): (data?: any) => void; | declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options: EventInit | null, host: Host<SupportedElement>): (data?: any) => void; | ||||||
| export interface On { | export interface On { | ||||||
| 	/** Listens to the DOM event. See {@link Document.addEventListener} */ | 	/** Listens to the DOM event. See {@link Document.addEventListener} */ | ||||||
| 	<Event extends keyof DocumentEventMap, EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: Event, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: DocumentEventMap[Event]) => any, options?: AddEventListenerOptions): EE; | 	<Event extends keyof DocumentEventMap, EL extends SupportedElement>(type: Event, listener: (this: EL, ev: DocumentEventMap[Event]) => any, options?: AddEventListenerOptions): ddeElementAddon<EL>; | ||||||
| 	<EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: string, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: Event | CustomEvent) => any, options?: AddEventListenerOptions): EE; | 	<EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: string, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: Event | CustomEvent) => any, options?: AddEventListenerOptions): EE; | ||||||
| 	/** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | 	/** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | ||||||
| 	connected<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<El>) => any, options?: AddEventListenerOptions): EE; | 	connected<EL extends SupportedElement>(listener: (this: EL, event: CustomEvent<NoInfer<EL>>) => any, options?: AddEventListenerOptions): ddeElementAddon<EL>; | ||||||
| 	/** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | 	/** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | ||||||
| 	disconnected<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<void>) => any, options?: AddEventListenerOptions): EE; | 	disconnected<EL extends SupportedElement>(listener: (this: EL, event: CustomEvent<void>) => any, options?: AddEventListenerOptions): ddeElementAddon<EL>; | ||||||
| 	/** Listens to the element attribute changes. In case of custom elements uses [`attributeChangedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | 	/** | ||||||
| 	attributeChanged<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<[ | 	 * Fires when the host element is "ready", for host element itsel, it is just an alias for `scope.host(listener)`. | ||||||
| 		string, | 	 * This is handy to apply some property depending on full template such as: | ||||||
| 		string | 	 * ```js | ||||||
| 	]>) => any, options?: AddEventListenerOptions): EE; | 	 * const selected= "Z"; | ||||||
|  | 	 * //... | ||||||
|  | 	 * return el("form").append( | ||||||
|  | 	 *		el("select", null, on.host(e=> e.value=selected)).append( | ||||||
|  | 	 *			el("option", { value: "A", textContent: "A" }), | ||||||
|  | 	 *			//... | ||||||
|  | 	 *			el("option", { value: "Z", textContent: "Z" }), | ||||||
|  | 	 *		), | ||||||
|  | 	 * ); | ||||||
|  | 	 * ``` | ||||||
|  | 	 * */ | ||||||
|  | 	host<EL extends SupportedElement>(listener: (element: EL) => any, host?: Host<SupportedElement>): ddeElementAddon<EL>; | ||||||
| } | } | ||||||
| export const on: On; | export const on: On; | ||||||
| export type Scope = { | export type Scope = { | ||||||
|   | |||||||
							
								
								
									
										180
									
								
								dist/esm.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										180
									
								
								dist/esm.js
									
									
									
									
										vendored
									
									
								
							| @@ -26,38 +26,7 @@ function onAbort(signal, listener) { | |||||||
| 	}; | 	}; | ||||||
| } | } | ||||||
|  |  | ||||||
| // src/signals-lib/common.js | // src/dom-lib/common.js | ||||||
| var signals_global = { |  | ||||||
| 	/** |  | ||||||
| 	* Checks if a value is a signal |  | ||||||
| 	* @param {any} attributes - Value to check |  | ||||||
| 	* @returns {boolean} Whether the value is a signal |  | ||||||
| 	*/ |  | ||||||
| 	isSignal(attributes) { |  | ||||||
| 		return false; |  | ||||||
| 	}, |  | ||||||
| 	/** |  | ||||||
| 	* Processes an attribute that might be reactive |  | ||||||
| 	* @param {Element} obj - Element that owns the attribute |  | ||||||
| 	* @param {string} key - Attribute name |  | ||||||
| 	* @param {any} attr - Attribute value |  | ||||||
| 	* @param {Function} set - Function to set the attribute |  | ||||||
| 	* @returns {any} Processed attribute value |  | ||||||
| 	*/ |  | ||||||
| 	processReactiveAttribute(obj, key, attr, set) { |  | ||||||
| 		return attr; |  | ||||||
| 	} |  | ||||||
| }; |  | ||||||
| function registerReactivity(def, global = true) { |  | ||||||
| 	if (global) return oAssign(signals_global, def); |  | ||||||
| 	Object.setPrototypeOf(def, signals_global); |  | ||||||
| 	return def; |  | ||||||
| } |  | ||||||
| function signals(_this) { |  | ||||||
| 	return isProtoFrom(_this, signals_global) && _this !== signals_global ? _this : signals_global; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // src/dom-common.js |  | ||||||
| var enviroment = { | var enviroment = { | ||||||
| 	setDeleteAttr, | 	setDeleteAttr, | ||||||
| 	ssr: "", | 	ssr: "", | ||||||
| @@ -83,7 +52,7 @@ var evc = "dde:connected"; | |||||||
| var evd = "dde:disconnected"; | var evd = "dde:disconnected"; | ||||||
| var eva = "dde:attributeChanged"; | var eva = "dde:attributeChanged"; | ||||||
|  |  | ||||||
| // src/events-observer.js | // src/dom-lib/events-observer.js | ||||||
| var c_ch_o = enviroment.M ? connectionsChangesObserverConstructor() : new Proxy({}, { | var c_ch_o = enviroment.M ? connectionsChangesObserverConstructor() : new Proxy({}, { | ||||||
| 	get() { | 	get() { | ||||||
| 		return () => { | 		return () => { | ||||||
| @@ -247,7 +216,7 @@ function connectionsChangesObserverConstructor() { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| // src/events.js | // src/dom-lib/events.js | ||||||
| function dispatchEvent(name, options, host) { | function dispatchEvent(name, options, host) { | ||||||
| 	if (typeof options === "function") { | 	if (typeof options === "function") { | ||||||
| 		host = options; | 		host = options; | ||||||
| @@ -292,10 +261,7 @@ on.disconnected = function(listener, options) { | |||||||
| 	}; | 	}; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| // src/dom.js | // src/dom-lib/scopes.js | ||||||
| function queue(promise) { |  | ||||||
| 	return enviroment.q(promise); |  | ||||||
| } |  | ||||||
| var scopes = [{ | var scopes = [{ | ||||||
| 	get scope() { | 	get scope() { | ||||||
| 		return enviroment.D.body; | 		return enviroment.D.body; | ||||||
| @@ -370,6 +336,61 @@ var scope = { | |||||||
| 		return scopes.pop(); | 		return scopes.pop(); | ||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
|  | on.host = (fn, host = scope.host) => (el) => host(() => fn(el)); | ||||||
|  |  | ||||||
|  | // src/signals-lib/common.js | ||||||
|  | var signals_global = { | ||||||
|  | 	/** | ||||||
|  | 	* Checks if a value is a signal | ||||||
|  | 	* @param {any} attributes - Value to check | ||||||
|  | 	* @returns {boolean} Whether the value is a signal | ||||||
|  | 	*/ | ||||||
|  | 	isSignal(attributes) { | ||||||
|  | 		return false; | ||||||
|  | 	}, | ||||||
|  | 	/** | ||||||
|  | 	* Processes an attribute that might be reactive | ||||||
|  | 	* @param {Element} obj - Element that owns the attribute | ||||||
|  | 	* @param {string} key - Attribute name | ||||||
|  | 	* @param {any} attr - Attribute value | ||||||
|  | 	* @param {Function} set - Function to set the attribute | ||||||
|  | 	* @returns {any} Processed attribute value | ||||||
|  | 	*/ | ||||||
|  | 	processReactiveAttribute(obj, key, attr, set) { | ||||||
|  | 		return attr; | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  | function registerReactivity(def, global = true) { | ||||||
|  | 	if (global) return oAssign(signals_global, def); | ||||||
|  | 	Object.setPrototypeOf(def, signals_global); | ||||||
|  | 	return def; | ||||||
|  | } | ||||||
|  | function signals(_this) { | ||||||
|  | 	return isProtoFrom(_this, signals_global) && _this !== signals_global ? _this : signals_global; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // src/dom-lib/helpers.js | ||||||
|  | function setRemove(obj, prop, key, val) { | ||||||
|  | 	return obj[(isUndef(val) ? "remove" : "set") + prop](key, val); | ||||||
|  | } | ||||||
|  | function setRemoveNS(obj, prop, key, val, ns = null) { | ||||||
|  | 	return obj[(isUndef(val) ? "remove" : "set") + prop + "NS"](ns, key, val); | ||||||
|  | } | ||||||
|  | function setDelete(obj, key, val) { | ||||||
|  | 	Reflect.set(obj, key, val); | ||||||
|  | 	if (!isUndef(val)) return; | ||||||
|  | 	return Reflect.deleteProperty(obj, key); | ||||||
|  | } | ||||||
|  | function elementAttribute(element, op, key, value) { | ||||||
|  | 	if (isInstance(element, enviroment.H)) | ||||||
|  | 		return element[op + "Attribute"](key, value); | ||||||
|  | 	return element[op + "AttributeNS"](null, key, value); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // src/dom-lib/el.js | ||||||
|  | function queue(promise) { | ||||||
|  | 	return enviroment.q(promise); | ||||||
|  | } | ||||||
| function append(...els) { | function append(...els) { | ||||||
| 	this.appendOriginal(...els); | 	this.appendOriginal(...els); | ||||||
| 	return this; | 	return this; | ||||||
| @@ -439,38 +460,6 @@ function createElementNS(ns) { | |||||||
| 		return el; | 		return el; | ||||||
| 	}; | 	}; | ||||||
| } | } | ||||||
| function simulateSlots(element, root = element) { |  | ||||||
| 	const mark_e = "\xB9\u2070", mark_s = "\u2713"; |  | ||||||
| 	const slots = Object.fromEntries( |  | ||||||
| 		Array.from(root.querySelectorAll("slot")).filter((s) => !s.name.endsWith(mark_e)).map((s) => [s.name += mark_e, s]) |  | ||||||
| 	); |  | ||||||
| 	element.append = new Proxy(element.append, { |  | ||||||
| 		apply(orig, _, els) { |  | ||||||
| 			if (els[0] === root) return orig.apply(element, els); |  | ||||||
| 			for (const el of els) { |  | ||||||
| 				const name = (el.slot || "") + mark_e; |  | ||||||
| 				try { |  | ||||||
| 					elementAttribute(el, "remove", "slot"); |  | ||||||
| 				} catch (_error) { |  | ||||||
| 				} |  | ||||||
| 				const slot = slots[name]; |  | ||||||
| 				if (!slot) return; |  | ||||||
| 				if (!slot.name.startsWith(mark_s)) { |  | ||||||
| 					slot.childNodes.forEach((c) => c.remove()); |  | ||||||
| 					slot.name = mark_s + name; |  | ||||||
| 				} |  | ||||||
| 				slot.append(el); |  | ||||||
| 			} |  | ||||||
| 			element.append = orig; |  | ||||||
| 			return element; |  | ||||||
| 		} |  | ||||||
| 	}); |  | ||||||
| 	if (element !== root) { |  | ||||||
| 		const els = Array.from(element.childNodes); |  | ||||||
| 		element.append(...els); |  | ||||||
| 	} |  | ||||||
| 	return root; |  | ||||||
| } |  | ||||||
| var assign_context = /* @__PURE__ */ new WeakMap(); | var assign_context = /* @__PURE__ */ new WeakMap(); | ||||||
| var { setDeleteAttr: setDeleteAttr2 } = enviroment; | var { setDeleteAttr: setDeleteAttr2 } = enviroment; | ||||||
| function assign(element, ...attributes) { | function assign(element, ...attributes) { | ||||||
| @@ -533,11 +522,6 @@ function classListDeclarative(element, toggle) { | |||||||
| 	); | 	); | ||||||
| 	return element; | 	return element; | ||||||
| } | } | ||||||
| function elementAttribute(element, op, key, value) { |  | ||||||
| 	if (isInstance(element, enviroment.H)) |  | ||||||
| 		return element[op + "Attribute"](key, value); |  | ||||||
| 	return element[op + "AttributeNS"](null, key, value); |  | ||||||
| } |  | ||||||
| function isPropSetter(el, key) { | function isPropSetter(el, key) { | ||||||
| 	if (!(key in el)) return false; | 	if (!(key in el)) return false; | ||||||
| 	const des = getPropDescriptor(el, key); | 	const des = getPropDescriptor(el, key); | ||||||
| @@ -561,19 +545,40 @@ function forEachEntries(s, target, element, obj, cb) { | |||||||
| 		cb(key, val); | 		cb(key, val); | ||||||
| 	}); | 	}); | ||||||
| } | } | ||||||
| function setRemove(obj, prop, key, val) { |  | ||||||
| 	return obj[(isUndef(val) ? "remove" : "set") + prop](key, val); |  | ||||||
| } |  | ||||||
| function setRemoveNS(obj, prop, key, val, ns = null) { |  | ||||||
| 	return obj[(isUndef(val) ? "remove" : "set") + prop + "NS"](ns, key, val); |  | ||||||
| } |  | ||||||
| function setDelete(obj, key, val) { |  | ||||||
| 	Reflect.set(obj, key, val); |  | ||||||
| 	if (!isUndef(val)) return; |  | ||||||
| 	return Reflect.deleteProperty(obj, key); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // src/customElement.js | // src/dom-lib/customElement.js | ||||||
|  | function simulateSlots(element, root = element) { | ||||||
|  | 	const mark_e = "\xB9\u2070", mark_s = "\u2713"; | ||||||
|  | 	const slots = Object.fromEntries( | ||||||
|  | 		Array.from(root.querySelectorAll("slot")).filter((s) => !s.name.endsWith(mark_e)).map((s) => [s.name += mark_e, s]) | ||||||
|  | 	); | ||||||
|  | 	element.append = new Proxy(element.append, { | ||||||
|  | 		apply(orig, _, els) { | ||||||
|  | 			if (els[0] === root) return orig.apply(element, els); | ||||||
|  | 			for (const el of els) { | ||||||
|  | 				const name = (el.slot || "") + mark_e; | ||||||
|  | 				try { | ||||||
|  | 					elementAttribute(el, "remove", "slot"); | ||||||
|  | 				} catch (_error) { | ||||||
|  | 				} | ||||||
|  | 				const slot = slots[name]; | ||||||
|  | 				if (!slot) return; | ||||||
|  | 				if (!slot.name.startsWith(mark_s)) { | ||||||
|  | 					slot.childNodes.forEach((c) => c.remove()); | ||||||
|  | 					slot.name = mark_s + name; | ||||||
|  | 				} | ||||||
|  | 				slot.append(el); | ||||||
|  | 			} | ||||||
|  | 			element.append = orig; | ||||||
|  | 			return element; | ||||||
|  | 		} | ||||||
|  | 	}); | ||||||
|  | 	if (element !== root) { | ||||||
|  | 		const els = Array.from(element.childNodes); | ||||||
|  | 		element.append(...els); | ||||||
|  | 	} | ||||||
|  | 	return root; | ||||||
|  | } | ||||||
| function customElementRender(target, render, props = {}) { | function customElementRender(target, render, props = {}) { | ||||||
| 	const custom_element = target.host || target; | 	const custom_element = target.host || target; | ||||||
| 	scope.push({ | 	scope.push({ | ||||||
| @@ -662,7 +667,6 @@ export { | |||||||
| 	dispatchEvent, | 	dispatchEvent, | ||||||
| 	createElement as el, | 	createElement as el, | ||||||
| 	createElementNS as elNS, | 	createElementNS as elNS, | ||||||
| 	elementAttribute, |  | ||||||
| 	lifecyclesToEvents, | 	lifecyclesToEvents, | ||||||
| 	memo, | 	memo, | ||||||
| 	on, | 	on, | ||||||
|   | |||||||
							
								
								
									
										29
									
								
								dist/esm.min.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								dist/esm.min.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -4,7 +4,7 @@ export interface Signal<V, A> { | |||||||
| 	/** The current value of the signal */ | 	/** The current value of the signal */ | ||||||
| 	get(): V; | 	get(): V; | ||||||
| 	/** Set new value of the signal */ | 	/** Set new value of the signal */ | ||||||
| 	set(value: V): V; | 	set(value: V, force?: boolean): V; | ||||||
| 	toJSON(): V; | 	toJSON(): V; | ||||||
| 	valueOf(): V; | 	valueOf(): V; | ||||||
| } | } | ||||||
| @@ -172,17 +172,28 @@ declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options? | |||||||
| declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options: EventInit | null, host: Host<SupportedElement>): (data?: any) => void; | declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options: EventInit | null, host: Host<SupportedElement>): (data?: any) => void; | ||||||
| export interface On { | export interface On { | ||||||
| 	/** Listens to the DOM event. See {@link Document.addEventListener} */ | 	/** Listens to the DOM event. See {@link Document.addEventListener} */ | ||||||
| 	<Event extends keyof DocumentEventMap, EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: Event, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: DocumentEventMap[Event]) => any, options?: AddEventListenerOptions): EE; | 	<Event extends keyof DocumentEventMap, EL extends SupportedElement>(type: Event, listener: (this: EL, ev: DocumentEventMap[Event]) => any, options?: AddEventListenerOptions): ddeElementAddon<EL>; | ||||||
| 	<EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: string, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: Event | CustomEvent) => any, options?: AddEventListenerOptions): EE; | 	<EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: string, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: Event | CustomEvent) => any, options?: AddEventListenerOptions): EE; | ||||||
| 	/** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | 	/** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | ||||||
| 	connected<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<El>) => any, options?: AddEventListenerOptions): EE; | 	connected<EL extends SupportedElement>(listener: (this: EL, event: CustomEvent<NoInfer<EL>>) => any, options?: AddEventListenerOptions): ddeElementAddon<EL>; | ||||||
| 	/** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | 	/** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | ||||||
| 	disconnected<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<void>) => any, options?: AddEventListenerOptions): EE; | 	disconnected<EL extends SupportedElement>(listener: (this: EL, event: CustomEvent<void>) => any, options?: AddEventListenerOptions): ddeElementAddon<EL>; | ||||||
| 	/** Listens to the element attribute changes. In case of custom elements uses [`attributeChangedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | 	/** | ||||||
| 	attributeChanged<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<[ | 	 * Fires when the host element is "ready", for host element itsel, it is just an alias for `scope.host(listener)`. | ||||||
| 		string, | 	 * This is handy to apply some property depending on full template such as: | ||||||
| 		string | 	 * ```js | ||||||
| 	]>) => any, options?: AddEventListenerOptions): EE; | 	 * const selected= "Z"; | ||||||
|  | 	 * //... | ||||||
|  | 	 * return el("form").append( | ||||||
|  | 	 *		el("select", null, on.host(e=> e.value=selected)).append( | ||||||
|  | 	 *			el("option", { value: "A", textContent: "A" }), | ||||||
|  | 	 *			//... | ||||||
|  | 	 *			el("option", { value: "Z", textContent: "Z" }), | ||||||
|  | 	 *		), | ||||||
|  | 	 * ); | ||||||
|  | 	 * ``` | ||||||
|  | 	 * */ | ||||||
|  | 	host<EL extends SupportedElement>(listener: (element: EL) => any, host?: Host<SupportedElement>): ddeElementAddon<EL>; | ||||||
| } | } | ||||||
| export const on: On; | export const on: On; | ||||||
| export type Scope = { | export type Scope = { | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								dist/esm.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/esm.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										29
									
								
								dist/iife-with-signals.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								dist/iife-with-signals.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -4,7 +4,7 @@ export interface Signal<V, A> { | |||||||
| 	/** The current value of the signal */ | 	/** The current value of the signal */ | ||||||
| 	get(): V; | 	get(): V; | ||||||
| 	/** Set new value of the signal */ | 	/** Set new value of the signal */ | ||||||
| 	set(value: V): V; | 	set(value: V, force?: boolean): V; | ||||||
| 	toJSON(): V; | 	toJSON(): V; | ||||||
| 	valueOf(): V; | 	valueOf(): V; | ||||||
| } | } | ||||||
| @@ -173,17 +173,28 @@ declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options? | |||||||
| declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options: EventInit | null, host: Host<SupportedElement>): (data?: any) => void; | declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options: EventInit | null, host: Host<SupportedElement>): (data?: any) => void; | ||||||
| export interface On { | export interface On { | ||||||
| 	/** Listens to the DOM event. See {@link Document.addEventListener} */ | 	/** Listens to the DOM event. See {@link Document.addEventListener} */ | ||||||
| 	<Event extends keyof DocumentEventMap, EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: Event, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: DocumentEventMap[Event]) => any, options?: AddEventListenerOptions): EE; | 	<Event extends keyof DocumentEventMap, EL extends SupportedElement>(type: Event, listener: (this: EL, ev: DocumentEventMap[Event]) => any, options?: AddEventListenerOptions): ddeElementAddon<EL>; | ||||||
| 	<EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: string, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: Event | CustomEvent) => any, options?: AddEventListenerOptions): EE; | 	<EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: string, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: Event | CustomEvent) => any, options?: AddEventListenerOptions): EE; | ||||||
| 	/** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | 	/** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | ||||||
| 	connected<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<El>) => any, options?: AddEventListenerOptions): EE; | 	connected<EL extends SupportedElement>(listener: (this: EL, event: CustomEvent<NoInfer<EL>>) => any, options?: AddEventListenerOptions): ddeElementAddon<EL>; | ||||||
| 	/** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | 	/** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | ||||||
| 	disconnected<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<void>) => any, options?: AddEventListenerOptions): EE; | 	disconnected<EL extends SupportedElement>(listener: (this: EL, event: CustomEvent<void>) => any, options?: AddEventListenerOptions): ddeElementAddon<EL>; | ||||||
| 	/** Listens to the element attribute changes. In case of custom elements uses [`attributeChangedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | 	/** | ||||||
| 	attributeChanged<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<[ | 	 * Fires when the host element is "ready", for host element itsel, it is just an alias for `scope.host(listener)`. | ||||||
| 		string, | 	 * This is handy to apply some property depending on full template such as: | ||||||
| 		string | 	 * ```js | ||||||
| 	]>) => any, options?: AddEventListenerOptions): EE; | 	 * const selected= "Z"; | ||||||
|  | 	 * //... | ||||||
|  | 	 * return el("form").append( | ||||||
|  | 	 *		el("select", null, on.host(e=> e.value=selected)).append( | ||||||
|  | 	 *			el("option", { value: "A", textContent: "A" }), | ||||||
|  | 	 *			//... | ||||||
|  | 	 *			el("option", { value: "Z", textContent: "Z" }), | ||||||
|  | 	 *		), | ||||||
|  | 	 * ); | ||||||
|  | 	 * ``` | ||||||
|  | 	 * */ | ||||||
|  | 	host<EL extends SupportedElement>(listener: (element: EL) => any, host?: Host<SupportedElement>): ddeElementAddon<EL>; | ||||||
| } | } | ||||||
| export const on: On; | export const on: On; | ||||||
| export type Scope = { | export type Scope = { | ||||||
|   | |||||||
							
								
								
									
										180
									
								
								dist/iife-with-signals.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										180
									
								
								dist/iife-with-signals.js
									
									
									
									
										vendored
									
									
								
							| @@ -32,7 +32,6 @@ var DDE = (() => { | |||||||
| 		dispatchEvent: () => dispatchEvent, | 		dispatchEvent: () => dispatchEvent, | ||||||
| 		el: () => createElement, | 		el: () => createElement, | ||||||
| 		elNS: () => createElementNS, | 		elNS: () => createElementNS, | ||||||
| 		elementAttribute: () => elementAttribute, |  | ||||||
| 		isSignal: () => isSignal, | 		isSignal: () => isSignal, | ||||||
| 		lifecyclesToEvents: () => lifecyclesToEvents, | 		lifecyclesToEvents: () => lifecyclesToEvents, | ||||||
| 		memo: () => memo, | 		memo: () => memo, | ||||||
| @@ -101,38 +100,7 @@ var DDE = (() => { | |||||||
| 		} | 		} | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	// src/signals-lib/common.js | 	// src/dom-lib/common.js | ||||||
| 	var signals_global = { |  | ||||||
| 		/** |  | ||||||
| 		* Checks if a value is a signal |  | ||||||
| 		* @param {any} attributes - Value to check |  | ||||||
| 		* @returns {boolean} Whether the value is a signal |  | ||||||
| 		*/ |  | ||||||
| 		isSignal(attributes) { |  | ||||||
| 			return false; |  | ||||||
| 		}, |  | ||||||
| 		/** |  | ||||||
| 		* Processes an attribute that might be reactive |  | ||||||
| 		* @param {Element} obj - Element that owns the attribute |  | ||||||
| 		* @param {string} key - Attribute name |  | ||||||
| 		* @param {any} attr - Attribute value |  | ||||||
| 		* @param {Function} set - Function to set the attribute |  | ||||||
| 		* @returns {any} Processed attribute value |  | ||||||
| 		*/ |  | ||||||
| 		processReactiveAttribute(obj, key, attr, set) { |  | ||||||
| 			return attr; |  | ||||||
| 		} |  | ||||||
| 	}; |  | ||||||
| 	function registerReactivity(def, global = true) { |  | ||||||
| 		if (global) return oAssign(signals_global, def); |  | ||||||
| 		Object.setPrototypeOf(def, signals_global); |  | ||||||
| 		return def; |  | ||||||
| 	} |  | ||||||
| 	function signals(_this) { |  | ||||||
| 		return isProtoFrom(_this, signals_global) && _this !== signals_global ? _this : signals_global; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// src/dom-common.js |  | ||||||
| 	var enviroment = { | 	var enviroment = { | ||||||
| 		setDeleteAttr, | 		setDeleteAttr, | ||||||
| 		ssr: "", | 		ssr: "", | ||||||
| @@ -158,7 +126,7 @@ var DDE = (() => { | |||||||
| 	var evd = "dde:disconnected"; | 	var evd = "dde:disconnected"; | ||||||
| 	var eva = "dde:attributeChanged"; | 	var eva = "dde:attributeChanged"; | ||||||
|  |  | ||||||
| 	// src/events-observer.js | 	// src/dom-lib/events-observer.js | ||||||
| 	var c_ch_o = enviroment.M ? connectionsChangesObserverConstructor() : new Proxy({}, { | 	var c_ch_o = enviroment.M ? connectionsChangesObserverConstructor() : new Proxy({}, { | ||||||
| 		get() { | 		get() { | ||||||
| 			return () => { | 			return () => { | ||||||
| @@ -322,7 +290,7 @@ var DDE = (() => { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// src/events.js | 	// src/dom-lib/events.js | ||||||
| 	function dispatchEvent(name, options, host) { | 	function dispatchEvent(name, options, host) { | ||||||
| 		if (typeof options === "function") { | 		if (typeof options === "function") { | ||||||
| 			host = options; | 			host = options; | ||||||
| @@ -367,10 +335,7 @@ var DDE = (() => { | |||||||
| 		}; | 		}; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	// src/dom.js | 	// src/dom-lib/scopes.js | ||||||
| 	function queue(promise) { |  | ||||||
| 		return enviroment.q(promise); |  | ||||||
| 	} |  | ||||||
| 	var scopes = [{ | 	var scopes = [{ | ||||||
| 		get scope() { | 		get scope() { | ||||||
| 			return enviroment.D.body; | 			return enviroment.D.body; | ||||||
| @@ -445,6 +410,61 @@ var DDE = (() => { | |||||||
| 			return scopes.pop(); | 			return scopes.pop(); | ||||||
| 		} | 		} | ||||||
| 	}; | 	}; | ||||||
|  | 	on.host = (fn, host = scope.host) => (el) => host(() => fn(el)); | ||||||
|  |  | ||||||
|  | 	// src/signals-lib/common.js | ||||||
|  | 	var signals_global = { | ||||||
|  | 		/** | ||||||
|  | 		* Checks if a value is a signal | ||||||
|  | 		* @param {any} attributes - Value to check | ||||||
|  | 		* @returns {boolean} Whether the value is a signal | ||||||
|  | 		*/ | ||||||
|  | 		isSignal(attributes) { | ||||||
|  | 			return false; | ||||||
|  | 		}, | ||||||
|  | 		/** | ||||||
|  | 		* Processes an attribute that might be reactive | ||||||
|  | 		* @param {Element} obj - Element that owns the attribute | ||||||
|  | 		* @param {string} key - Attribute name | ||||||
|  | 		* @param {any} attr - Attribute value | ||||||
|  | 		* @param {Function} set - Function to set the attribute | ||||||
|  | 		* @returns {any} Processed attribute value | ||||||
|  | 		*/ | ||||||
|  | 		processReactiveAttribute(obj, key, attr, set) { | ||||||
|  | 			return attr; | ||||||
|  | 		} | ||||||
|  | 	}; | ||||||
|  | 	function registerReactivity(def, global = true) { | ||||||
|  | 		if (global) return oAssign(signals_global, def); | ||||||
|  | 		Object.setPrototypeOf(def, signals_global); | ||||||
|  | 		return def; | ||||||
|  | 	} | ||||||
|  | 	function signals(_this) { | ||||||
|  | 		return isProtoFrom(_this, signals_global) && _this !== signals_global ? _this : signals_global; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// src/dom-lib/helpers.js | ||||||
|  | 	function setRemove(obj, prop, key, val) { | ||||||
|  | 		return obj[(isUndef(val) ? "remove" : "set") + prop](key, val); | ||||||
|  | 	} | ||||||
|  | 	function setRemoveNS(obj, prop, key, val, ns = null) { | ||||||
|  | 		return obj[(isUndef(val) ? "remove" : "set") + prop + "NS"](ns, key, val); | ||||||
|  | 	} | ||||||
|  | 	function setDelete(obj, key, val) { | ||||||
|  | 		Reflect.set(obj, key, val); | ||||||
|  | 		if (!isUndef(val)) return; | ||||||
|  | 		return Reflect.deleteProperty(obj, key); | ||||||
|  | 	} | ||||||
|  | 	function elementAttribute(element, op, key, value) { | ||||||
|  | 		if (isInstance(element, enviroment.H)) | ||||||
|  | 			return element[op + "Attribute"](key, value); | ||||||
|  | 		return element[op + "AttributeNS"](null, key, value); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// src/dom-lib/el.js | ||||||
|  | 	function queue(promise) { | ||||||
|  | 		return enviroment.q(promise); | ||||||
|  | 	} | ||||||
| 	function append(...els) { | 	function append(...els) { | ||||||
| 		this.appendOriginal(...els); | 		this.appendOriginal(...els); | ||||||
| 		return this; | 		return this; | ||||||
| @@ -514,38 +534,6 @@ var DDE = (() => { | |||||||
| 			return el; | 			return el; | ||||||
| 		}; | 		}; | ||||||
| 	} | 	} | ||||||
| 	function simulateSlots(element, root = element) { |  | ||||||
| 		const mark_e = "\xB9\u2070", mark_s = "\u2713"; |  | ||||||
| 		const slots = Object.fromEntries( |  | ||||||
| 			Array.from(root.querySelectorAll("slot")).filter((s) => !s.name.endsWith(mark_e)).map((s) => [s.name += mark_e, s]) |  | ||||||
| 		); |  | ||||||
| 		element.append = new Proxy(element.append, { |  | ||||||
| 			apply(orig, _, els) { |  | ||||||
| 				if (els[0] === root) return orig.apply(element, els); |  | ||||||
| 				for (const el of els) { |  | ||||||
| 					const name = (el.slot || "") + mark_e; |  | ||||||
| 					try { |  | ||||||
| 						elementAttribute(el, "remove", "slot"); |  | ||||||
| 					} catch (_error) { |  | ||||||
| 					} |  | ||||||
| 					const slot = slots[name]; |  | ||||||
| 					if (!slot) return; |  | ||||||
| 					if (!slot.name.startsWith(mark_s)) { |  | ||||||
| 						slot.childNodes.forEach((c) => c.remove()); |  | ||||||
| 						slot.name = mark_s + name; |  | ||||||
| 					} |  | ||||||
| 					slot.append(el); |  | ||||||
| 				} |  | ||||||
| 				element.append = orig; |  | ||||||
| 				return element; |  | ||||||
| 			} |  | ||||||
| 		}); |  | ||||||
| 		if (element !== root) { |  | ||||||
| 			const els = Array.from(element.childNodes); |  | ||||||
| 			element.append(...els); |  | ||||||
| 		} |  | ||||||
| 		return root; |  | ||||||
| 	} |  | ||||||
| 	var assign_context = /* @__PURE__ */ new WeakMap(); | 	var assign_context = /* @__PURE__ */ new WeakMap(); | ||||||
| 	var { setDeleteAttr: setDeleteAttr2 } = enviroment; | 	var { setDeleteAttr: setDeleteAttr2 } = enviroment; | ||||||
| 	function assign(element, ...attributes) { | 	function assign(element, ...attributes) { | ||||||
| @@ -608,11 +596,6 @@ var DDE = (() => { | |||||||
| 		); | 		); | ||||||
| 		return element; | 		return element; | ||||||
| 	} | 	} | ||||||
| 	function elementAttribute(element, op, key, value) { |  | ||||||
| 		if (isInstance(element, enviroment.H)) |  | ||||||
| 			return element[op + "Attribute"](key, value); |  | ||||||
| 		return element[op + "AttributeNS"](null, key, value); |  | ||||||
| 	} |  | ||||||
| 	function isPropSetter(el, key) { | 	function isPropSetter(el, key) { | ||||||
| 		if (!(key in el)) return false; | 		if (!(key in el)) return false; | ||||||
| 		const des = getPropDescriptor(el, key); | 		const des = getPropDescriptor(el, key); | ||||||
| @@ -636,19 +619,40 @@ var DDE = (() => { | |||||||
| 			cb(key, val); | 			cb(key, val); | ||||||
| 		}); | 		}); | ||||||
| 	} | 	} | ||||||
| 	function setRemove(obj, prop, key, val) { |  | ||||||
| 		return obj[(isUndef(val) ? "remove" : "set") + prop](key, val); |  | ||||||
| 	} |  | ||||||
| 	function setRemoveNS(obj, prop, key, val, ns = null) { |  | ||||||
| 		return obj[(isUndef(val) ? "remove" : "set") + prop + "NS"](ns, key, val); |  | ||||||
| 	} |  | ||||||
| 	function setDelete(obj, key, val) { |  | ||||||
| 		Reflect.set(obj, key, val); |  | ||||||
| 		if (!isUndef(val)) return; |  | ||||||
| 		return Reflect.deleteProperty(obj, key); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// src/customElement.js | 	// src/dom-lib/customElement.js | ||||||
|  | 	function simulateSlots(element, root = element) { | ||||||
|  | 		const mark_e = "\xB9\u2070", mark_s = "\u2713"; | ||||||
|  | 		const slots = Object.fromEntries( | ||||||
|  | 			Array.from(root.querySelectorAll("slot")).filter((s) => !s.name.endsWith(mark_e)).map((s) => [s.name += mark_e, s]) | ||||||
|  | 		); | ||||||
|  | 		element.append = new Proxy(element.append, { | ||||||
|  | 			apply(orig, _, els) { | ||||||
|  | 				if (els[0] === root) return orig.apply(element, els); | ||||||
|  | 				for (const el of els) { | ||||||
|  | 					const name = (el.slot || "") + mark_e; | ||||||
|  | 					try { | ||||||
|  | 						elementAttribute(el, "remove", "slot"); | ||||||
|  | 					} catch (_error) { | ||||||
|  | 					} | ||||||
|  | 					const slot = slots[name]; | ||||||
|  | 					if (!slot) return; | ||||||
|  | 					if (!slot.name.startsWith(mark_s)) { | ||||||
|  | 						slot.childNodes.forEach((c) => c.remove()); | ||||||
|  | 						slot.name = mark_s + name; | ||||||
|  | 					} | ||||||
|  | 					slot.append(el); | ||||||
|  | 				} | ||||||
|  | 				element.append = orig; | ||||||
|  | 				return element; | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  | 		if (element !== root) { | ||||||
|  | 			const els = Array.from(element.childNodes); | ||||||
|  | 			element.append(...els); | ||||||
|  | 		} | ||||||
|  | 		return root; | ||||||
|  | 	} | ||||||
| 	function customElementRender(target, render, props = {}) { | 	function customElementRender(target, render, props = {}) { | ||||||
| 		const custom_element = target.host || target; | 		const custom_element = target.host || target; | ||||||
| 		scope.push({ | 		scope.push({ | ||||||
|   | |||||||
							
								
								
									
										29
									
								
								dist/iife-with-signals.min.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								dist/iife-with-signals.min.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -4,7 +4,7 @@ export interface Signal<V, A> { | |||||||
| 	/** The current value of the signal */ | 	/** The current value of the signal */ | ||||||
| 	get(): V; | 	get(): V; | ||||||
| 	/** Set new value of the signal */ | 	/** Set new value of the signal */ | ||||||
| 	set(value: V): V; | 	set(value: V, force?: boolean): V; | ||||||
| 	toJSON(): V; | 	toJSON(): V; | ||||||
| 	valueOf(): V; | 	valueOf(): V; | ||||||
| } | } | ||||||
| @@ -173,17 +173,28 @@ declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options? | |||||||
| declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options: EventInit | null, host: Host<SupportedElement>): (data?: any) => void; | declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options: EventInit | null, host: Host<SupportedElement>): (data?: any) => void; | ||||||
| export interface On { | export interface On { | ||||||
| 	/** Listens to the DOM event. See {@link Document.addEventListener} */ | 	/** Listens to the DOM event. See {@link Document.addEventListener} */ | ||||||
| 	<Event extends keyof DocumentEventMap, EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: Event, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: DocumentEventMap[Event]) => any, options?: AddEventListenerOptions): EE; | 	<Event extends keyof DocumentEventMap, EL extends SupportedElement>(type: Event, listener: (this: EL, ev: DocumentEventMap[Event]) => any, options?: AddEventListenerOptions): ddeElementAddon<EL>; | ||||||
| 	<EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: string, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: Event | CustomEvent) => any, options?: AddEventListenerOptions): EE; | 	<EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: string, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: Event | CustomEvent) => any, options?: AddEventListenerOptions): EE; | ||||||
| 	/** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | 	/** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | ||||||
| 	connected<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<El>) => any, options?: AddEventListenerOptions): EE; | 	connected<EL extends SupportedElement>(listener: (this: EL, event: CustomEvent<NoInfer<EL>>) => any, options?: AddEventListenerOptions): ddeElementAddon<EL>; | ||||||
| 	/** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | 	/** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | ||||||
| 	disconnected<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<void>) => any, options?: AddEventListenerOptions): EE; | 	disconnected<EL extends SupportedElement>(listener: (this: EL, event: CustomEvent<void>) => any, options?: AddEventListenerOptions): ddeElementAddon<EL>; | ||||||
| 	/** Listens to the element attribute changes. In case of custom elements uses [`attributeChangedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | 	/** | ||||||
| 	attributeChanged<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<[ | 	 * Fires when the host element is "ready", for host element itsel, it is just an alias for `scope.host(listener)`. | ||||||
| 		string, | 	 * This is handy to apply some property depending on full template such as: | ||||||
| 		string | 	 * ```js | ||||||
| 	]>) => any, options?: AddEventListenerOptions): EE; | 	 * const selected= "Z"; | ||||||
|  | 	 * //... | ||||||
|  | 	 * return el("form").append( | ||||||
|  | 	 *		el("select", null, on.host(e=> e.value=selected)).append( | ||||||
|  | 	 *			el("option", { value: "A", textContent: "A" }), | ||||||
|  | 	 *			//... | ||||||
|  | 	 *			el("option", { value: "Z", textContent: "Z" }), | ||||||
|  | 	 *		), | ||||||
|  | 	 * ); | ||||||
|  | 	 * ``` | ||||||
|  | 	 * */ | ||||||
|  | 	host<EL extends SupportedElement>(listener: (element: EL) => any, host?: Host<SupportedElement>): ddeElementAddon<EL>; | ||||||
| } | } | ||||||
| export const on: On; | export const on: On; | ||||||
| export type Scope = { | export type Scope = { | ||||||
|   | |||||||
							
								
								
									
										8
									
								
								dist/iife-with-signals.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								dist/iife-with-signals.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										29
									
								
								dist/iife.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								dist/iife.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -4,7 +4,7 @@ export interface Signal<V, A> { | |||||||
| 	/** The current value of the signal */ | 	/** The current value of the signal */ | ||||||
| 	get(): V; | 	get(): V; | ||||||
| 	/** Set new value of the signal */ | 	/** Set new value of the signal */ | ||||||
| 	set(value: V): V; | 	set(value: V, force?: boolean): V; | ||||||
| 	toJSON(): V; | 	toJSON(): V; | ||||||
| 	valueOf(): V; | 	valueOf(): V; | ||||||
| } | } | ||||||
| @@ -172,17 +172,28 @@ declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options? | |||||||
| declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options: EventInit | null, host: Host<SupportedElement>): (data?: any) => void; | declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options: EventInit | null, host: Host<SupportedElement>): (data?: any) => void; | ||||||
| export interface On { | export interface On { | ||||||
| 	/** Listens to the DOM event. See {@link Document.addEventListener} */ | 	/** Listens to the DOM event. See {@link Document.addEventListener} */ | ||||||
| 	<Event extends keyof DocumentEventMap, EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: Event, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: DocumentEventMap[Event]) => any, options?: AddEventListenerOptions): EE; | 	<Event extends keyof DocumentEventMap, EL extends SupportedElement>(type: Event, listener: (this: EL, ev: DocumentEventMap[Event]) => any, options?: AddEventListenerOptions): ddeElementAddon<EL>; | ||||||
| 	<EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: string, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: Event | CustomEvent) => any, options?: AddEventListenerOptions): EE; | 	<EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: string, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: Event | CustomEvent) => any, options?: AddEventListenerOptions): EE; | ||||||
| 	/** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | 	/** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | ||||||
| 	connected<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<El>) => any, options?: AddEventListenerOptions): EE; | 	connected<EL extends SupportedElement>(listener: (this: EL, event: CustomEvent<NoInfer<EL>>) => any, options?: AddEventListenerOptions): ddeElementAddon<EL>; | ||||||
| 	/** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | 	/** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | ||||||
| 	disconnected<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<void>) => any, options?: AddEventListenerOptions): EE; | 	disconnected<EL extends SupportedElement>(listener: (this: EL, event: CustomEvent<void>) => any, options?: AddEventListenerOptions): ddeElementAddon<EL>; | ||||||
| 	/** Listens to the element attribute changes. In case of custom elements uses [`attributeChangedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | 	/** | ||||||
| 	attributeChanged<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<[ | 	 * Fires when the host element is "ready", for host element itsel, it is just an alias for `scope.host(listener)`. | ||||||
| 		string, | 	 * This is handy to apply some property depending on full template such as: | ||||||
| 		string | 	 * ```js | ||||||
| 	]>) => any, options?: AddEventListenerOptions): EE; | 	 * const selected= "Z"; | ||||||
|  | 	 * //... | ||||||
|  | 	 * return el("form").append( | ||||||
|  | 	 *		el("select", null, on.host(e=> e.value=selected)).append( | ||||||
|  | 	 *			el("option", { value: "A", textContent: "A" }), | ||||||
|  | 	 *			//... | ||||||
|  | 	 *			el("option", { value: "Z", textContent: "Z" }), | ||||||
|  | 	 *		), | ||||||
|  | 	 * ); | ||||||
|  | 	 * ``` | ||||||
|  | 	 * */ | ||||||
|  | 	host<EL extends SupportedElement>(listener: (element: EL) => any, host?: Host<SupportedElement>): ddeElementAddon<EL>; | ||||||
| } | } | ||||||
| export const on: On; | export const on: On; | ||||||
| export type Scope = { | export type Scope = { | ||||||
|   | |||||||
							
								
								
									
										180
									
								
								dist/iife.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										180
									
								
								dist/iife.js
									
									
									
									
										vendored
									
									
								
							| @@ -31,7 +31,6 @@ var DDE = (() => { | |||||||
| 		dispatchEvent: () => dispatchEvent, | 		dispatchEvent: () => dispatchEvent, | ||||||
| 		el: () => createElement, | 		el: () => createElement, | ||||||
| 		elNS: () => createElementNS, | 		elNS: () => createElementNS, | ||||||
| 		elementAttribute: () => elementAttribute, |  | ||||||
| 		lifecyclesToEvents: () => lifecyclesToEvents, | 		lifecyclesToEvents: () => lifecyclesToEvents, | ||||||
| 		memo: () => memo, | 		memo: () => memo, | ||||||
| 		on: () => on, | 		on: () => on, | ||||||
| @@ -69,38 +68,7 @@ var DDE = (() => { | |||||||
| 		}; | 		}; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// src/signals-lib/common.js | 	// src/dom-lib/common.js | ||||||
| 	var signals_global = { |  | ||||||
| 		/** |  | ||||||
| 		* Checks if a value is a signal |  | ||||||
| 		* @param {any} attributes - Value to check |  | ||||||
| 		* @returns {boolean} Whether the value is a signal |  | ||||||
| 		*/ |  | ||||||
| 		isSignal(attributes) { |  | ||||||
| 			return false; |  | ||||||
| 		}, |  | ||||||
| 		/** |  | ||||||
| 		* Processes an attribute that might be reactive |  | ||||||
| 		* @param {Element} obj - Element that owns the attribute |  | ||||||
| 		* @param {string} key - Attribute name |  | ||||||
| 		* @param {any} attr - Attribute value |  | ||||||
| 		* @param {Function} set - Function to set the attribute |  | ||||||
| 		* @returns {any} Processed attribute value |  | ||||||
| 		*/ |  | ||||||
| 		processReactiveAttribute(obj, key, attr, set) { |  | ||||||
| 			return attr; |  | ||||||
| 		} |  | ||||||
| 	}; |  | ||||||
| 	function registerReactivity(def, global = true) { |  | ||||||
| 		if (global) return oAssign(signals_global, def); |  | ||||||
| 		Object.setPrototypeOf(def, signals_global); |  | ||||||
| 		return def; |  | ||||||
| 	} |  | ||||||
| 	function signals(_this) { |  | ||||||
| 		return isProtoFrom(_this, signals_global) && _this !== signals_global ? _this : signals_global; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// src/dom-common.js |  | ||||||
| 	var enviroment = { | 	var enviroment = { | ||||||
| 		setDeleteAttr, | 		setDeleteAttr, | ||||||
| 		ssr: "", | 		ssr: "", | ||||||
| @@ -126,7 +94,7 @@ var DDE = (() => { | |||||||
| 	var evd = "dde:disconnected"; | 	var evd = "dde:disconnected"; | ||||||
| 	var eva = "dde:attributeChanged"; | 	var eva = "dde:attributeChanged"; | ||||||
|  |  | ||||||
| 	// src/events-observer.js | 	// src/dom-lib/events-observer.js | ||||||
| 	var c_ch_o = enviroment.M ? connectionsChangesObserverConstructor() : new Proxy({}, { | 	var c_ch_o = enviroment.M ? connectionsChangesObserverConstructor() : new Proxy({}, { | ||||||
| 		get() { | 		get() { | ||||||
| 			return () => { | 			return () => { | ||||||
| @@ -290,7 +258,7 @@ var DDE = (() => { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// src/events.js | 	// src/dom-lib/events.js | ||||||
| 	function dispatchEvent(name, options, host) { | 	function dispatchEvent(name, options, host) { | ||||||
| 		if (typeof options === "function") { | 		if (typeof options === "function") { | ||||||
| 			host = options; | 			host = options; | ||||||
| @@ -335,10 +303,7 @@ var DDE = (() => { | |||||||
| 		}; | 		}; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	// src/dom.js | 	// src/dom-lib/scopes.js | ||||||
| 	function queue(promise) { |  | ||||||
| 		return enviroment.q(promise); |  | ||||||
| 	} |  | ||||||
| 	var scopes = [{ | 	var scopes = [{ | ||||||
| 		get scope() { | 		get scope() { | ||||||
| 			return enviroment.D.body; | 			return enviroment.D.body; | ||||||
| @@ -413,6 +378,61 @@ var DDE = (() => { | |||||||
| 			return scopes.pop(); | 			return scopes.pop(); | ||||||
| 		} | 		} | ||||||
| 	}; | 	}; | ||||||
|  | 	on.host = (fn, host = scope.host) => (el) => host(() => fn(el)); | ||||||
|  |  | ||||||
|  | 	// src/signals-lib/common.js | ||||||
|  | 	var signals_global = { | ||||||
|  | 		/** | ||||||
|  | 		* Checks if a value is a signal | ||||||
|  | 		* @param {any} attributes - Value to check | ||||||
|  | 		* @returns {boolean} Whether the value is a signal | ||||||
|  | 		*/ | ||||||
|  | 		isSignal(attributes) { | ||||||
|  | 			return false; | ||||||
|  | 		}, | ||||||
|  | 		/** | ||||||
|  | 		* Processes an attribute that might be reactive | ||||||
|  | 		* @param {Element} obj - Element that owns the attribute | ||||||
|  | 		* @param {string} key - Attribute name | ||||||
|  | 		* @param {any} attr - Attribute value | ||||||
|  | 		* @param {Function} set - Function to set the attribute | ||||||
|  | 		* @returns {any} Processed attribute value | ||||||
|  | 		*/ | ||||||
|  | 		processReactiveAttribute(obj, key, attr, set) { | ||||||
|  | 			return attr; | ||||||
|  | 		} | ||||||
|  | 	}; | ||||||
|  | 	function registerReactivity(def, global = true) { | ||||||
|  | 		if (global) return oAssign(signals_global, def); | ||||||
|  | 		Object.setPrototypeOf(def, signals_global); | ||||||
|  | 		return def; | ||||||
|  | 	} | ||||||
|  | 	function signals(_this) { | ||||||
|  | 		return isProtoFrom(_this, signals_global) && _this !== signals_global ? _this : signals_global; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// src/dom-lib/helpers.js | ||||||
|  | 	function setRemove(obj, prop, key, val) { | ||||||
|  | 		return obj[(isUndef(val) ? "remove" : "set") + prop](key, val); | ||||||
|  | 	} | ||||||
|  | 	function setRemoveNS(obj, prop, key, val, ns = null) { | ||||||
|  | 		return obj[(isUndef(val) ? "remove" : "set") + prop + "NS"](ns, key, val); | ||||||
|  | 	} | ||||||
|  | 	function setDelete(obj, key, val) { | ||||||
|  | 		Reflect.set(obj, key, val); | ||||||
|  | 		if (!isUndef(val)) return; | ||||||
|  | 		return Reflect.deleteProperty(obj, key); | ||||||
|  | 	} | ||||||
|  | 	function elementAttribute(element, op, key, value) { | ||||||
|  | 		if (isInstance(element, enviroment.H)) | ||||||
|  | 			return element[op + "Attribute"](key, value); | ||||||
|  | 		return element[op + "AttributeNS"](null, key, value); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// src/dom-lib/el.js | ||||||
|  | 	function queue(promise) { | ||||||
|  | 		return enviroment.q(promise); | ||||||
|  | 	} | ||||||
| 	function append(...els) { | 	function append(...els) { | ||||||
| 		this.appendOriginal(...els); | 		this.appendOriginal(...els); | ||||||
| 		return this; | 		return this; | ||||||
| @@ -482,38 +502,6 @@ var DDE = (() => { | |||||||
| 			return el; | 			return el; | ||||||
| 		}; | 		}; | ||||||
| 	} | 	} | ||||||
| 	function simulateSlots(element, root = element) { |  | ||||||
| 		const mark_e = "\xB9\u2070", mark_s = "\u2713"; |  | ||||||
| 		const slots = Object.fromEntries( |  | ||||||
| 			Array.from(root.querySelectorAll("slot")).filter((s) => !s.name.endsWith(mark_e)).map((s) => [s.name += mark_e, s]) |  | ||||||
| 		); |  | ||||||
| 		element.append = new Proxy(element.append, { |  | ||||||
| 			apply(orig, _, els) { |  | ||||||
| 				if (els[0] === root) return orig.apply(element, els); |  | ||||||
| 				for (const el of els) { |  | ||||||
| 					const name = (el.slot || "") + mark_e; |  | ||||||
| 					try { |  | ||||||
| 						elementAttribute(el, "remove", "slot"); |  | ||||||
| 					} catch (_error) { |  | ||||||
| 					} |  | ||||||
| 					const slot = slots[name]; |  | ||||||
| 					if (!slot) return; |  | ||||||
| 					if (!slot.name.startsWith(mark_s)) { |  | ||||||
| 						slot.childNodes.forEach((c) => c.remove()); |  | ||||||
| 						slot.name = mark_s + name; |  | ||||||
| 					} |  | ||||||
| 					slot.append(el); |  | ||||||
| 				} |  | ||||||
| 				element.append = orig; |  | ||||||
| 				return element; |  | ||||||
| 			} |  | ||||||
| 		}); |  | ||||||
| 		if (element !== root) { |  | ||||||
| 			const els = Array.from(element.childNodes); |  | ||||||
| 			element.append(...els); |  | ||||||
| 		} |  | ||||||
| 		return root; |  | ||||||
| 	} |  | ||||||
| 	var assign_context = /* @__PURE__ */ new WeakMap(); | 	var assign_context = /* @__PURE__ */ new WeakMap(); | ||||||
| 	var { setDeleteAttr: setDeleteAttr2 } = enviroment; | 	var { setDeleteAttr: setDeleteAttr2 } = enviroment; | ||||||
| 	function assign(element, ...attributes) { | 	function assign(element, ...attributes) { | ||||||
| @@ -576,11 +564,6 @@ var DDE = (() => { | |||||||
| 		); | 		); | ||||||
| 		return element; | 		return element; | ||||||
| 	} | 	} | ||||||
| 	function elementAttribute(element, op, key, value) { |  | ||||||
| 		if (isInstance(element, enviroment.H)) |  | ||||||
| 			return element[op + "Attribute"](key, value); |  | ||||||
| 		return element[op + "AttributeNS"](null, key, value); |  | ||||||
| 	} |  | ||||||
| 	function isPropSetter(el, key) { | 	function isPropSetter(el, key) { | ||||||
| 		if (!(key in el)) return false; | 		if (!(key in el)) return false; | ||||||
| 		const des = getPropDescriptor(el, key); | 		const des = getPropDescriptor(el, key); | ||||||
| @@ -604,19 +587,40 @@ var DDE = (() => { | |||||||
| 			cb(key, val); | 			cb(key, val); | ||||||
| 		}); | 		}); | ||||||
| 	} | 	} | ||||||
| 	function setRemove(obj, prop, key, val) { |  | ||||||
| 		return obj[(isUndef(val) ? "remove" : "set") + prop](key, val); |  | ||||||
| 	} |  | ||||||
| 	function setRemoveNS(obj, prop, key, val, ns = null) { |  | ||||||
| 		return obj[(isUndef(val) ? "remove" : "set") + prop + "NS"](ns, key, val); |  | ||||||
| 	} |  | ||||||
| 	function setDelete(obj, key, val) { |  | ||||||
| 		Reflect.set(obj, key, val); |  | ||||||
| 		if (!isUndef(val)) return; |  | ||||||
| 		return Reflect.deleteProperty(obj, key); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// src/customElement.js | 	// src/dom-lib/customElement.js | ||||||
|  | 	function simulateSlots(element, root = element) { | ||||||
|  | 		const mark_e = "\xB9\u2070", mark_s = "\u2713"; | ||||||
|  | 		const slots = Object.fromEntries( | ||||||
|  | 			Array.from(root.querySelectorAll("slot")).filter((s) => !s.name.endsWith(mark_e)).map((s) => [s.name += mark_e, s]) | ||||||
|  | 		); | ||||||
|  | 		element.append = new Proxy(element.append, { | ||||||
|  | 			apply(orig, _, els) { | ||||||
|  | 				if (els[0] === root) return orig.apply(element, els); | ||||||
|  | 				for (const el of els) { | ||||||
|  | 					const name = (el.slot || "") + mark_e; | ||||||
|  | 					try { | ||||||
|  | 						elementAttribute(el, "remove", "slot"); | ||||||
|  | 					} catch (_error) { | ||||||
|  | 					} | ||||||
|  | 					const slot = slots[name]; | ||||||
|  | 					if (!slot) return; | ||||||
|  | 					if (!slot.name.startsWith(mark_s)) { | ||||||
|  | 						slot.childNodes.forEach((c) => c.remove()); | ||||||
|  | 						slot.name = mark_s + name; | ||||||
|  | 					} | ||||||
|  | 					slot.append(el); | ||||||
|  | 				} | ||||||
|  | 				element.append = orig; | ||||||
|  | 				return element; | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  | 		if (element !== root) { | ||||||
|  | 			const els = Array.from(element.childNodes); | ||||||
|  | 			element.append(...els); | ||||||
|  | 		} | ||||||
|  | 		return root; | ||||||
|  | 	} | ||||||
| 	function customElementRender(target, render, props = {}) { | 	function customElementRender(target, render, props = {}) { | ||||||
| 		const custom_element = target.host || target; | 		const custom_element = target.host || target; | ||||||
| 		scope.push({ | 		scope.push({ | ||||||
|   | |||||||
							
								
								
									
										29
									
								
								dist/iife.min.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								dist/iife.min.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -4,7 +4,7 @@ export interface Signal<V, A> { | |||||||
| 	/** The current value of the signal */ | 	/** The current value of the signal */ | ||||||
| 	get(): V; | 	get(): V; | ||||||
| 	/** Set new value of the signal */ | 	/** Set new value of the signal */ | ||||||
| 	set(value: V): V; | 	set(value: V, force?: boolean): V; | ||||||
| 	toJSON(): V; | 	toJSON(): V; | ||||||
| 	valueOf(): V; | 	valueOf(): V; | ||||||
| } | } | ||||||
| @@ -172,17 +172,28 @@ declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options? | |||||||
| declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options: EventInit | null, host: Host<SupportedElement>): (data?: any) => void; | declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options: EventInit | null, host: Host<SupportedElement>): (data?: any) => void; | ||||||
| export interface On { | export interface On { | ||||||
| 	/** Listens to the DOM event. See {@link Document.addEventListener} */ | 	/** Listens to the DOM event. See {@link Document.addEventListener} */ | ||||||
| 	<Event extends keyof DocumentEventMap, EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: Event, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: DocumentEventMap[Event]) => any, options?: AddEventListenerOptions): EE; | 	<Event extends keyof DocumentEventMap, EL extends SupportedElement>(type: Event, listener: (this: EL, ev: DocumentEventMap[Event]) => any, options?: AddEventListenerOptions): ddeElementAddon<EL>; | ||||||
| 	<EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: string, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: Event | CustomEvent) => any, options?: AddEventListenerOptions): EE; | 	<EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: string, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: Event | CustomEvent) => any, options?: AddEventListenerOptions): EE; | ||||||
| 	/** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | 	/** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | ||||||
| 	connected<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<El>) => any, options?: AddEventListenerOptions): EE; | 	connected<EL extends SupportedElement>(listener: (this: EL, event: CustomEvent<NoInfer<EL>>) => any, options?: AddEventListenerOptions): ddeElementAddon<EL>; | ||||||
| 	/** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | 	/** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | ||||||
| 	disconnected<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<void>) => any, options?: AddEventListenerOptions): EE; | 	disconnected<EL extends SupportedElement>(listener: (this: EL, event: CustomEvent<void>) => any, options?: AddEventListenerOptions): ddeElementAddon<EL>; | ||||||
| 	/** Listens to the element attribute changes. In case of custom elements uses [`attributeChangedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line | 	/** | ||||||
| 	attributeChanged<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<[ | 	 * Fires when the host element is "ready", for host element itsel, it is just an alias for `scope.host(listener)`. | ||||||
| 		string, | 	 * This is handy to apply some property depending on full template such as: | ||||||
| 		string | 	 * ```js | ||||||
| 	]>) => any, options?: AddEventListenerOptions): EE; | 	 * const selected= "Z"; | ||||||
|  | 	 * //... | ||||||
|  | 	 * return el("form").append( | ||||||
|  | 	 *		el("select", null, on.host(e=> e.value=selected)).append( | ||||||
|  | 	 *			el("option", { value: "A", textContent: "A" }), | ||||||
|  | 	 *			//... | ||||||
|  | 	 *			el("option", { value: "Z", textContent: "Z" }), | ||||||
|  | 	 *		), | ||||||
|  | 	 * ); | ||||||
|  | 	 * ``` | ||||||
|  | 	 * */ | ||||||
|  | 	host<EL extends SupportedElement>(listener: (element: EL) => any, host?: Host<SupportedElement>): ddeElementAddon<EL>; | ||||||
| } | } | ||||||
| export const on: On; | export const on: On; | ||||||
| export type Scope = { | export type Scope = { | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								dist/iife.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/iife.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -184,7 +184,7 @@ import { el } from "deka-dom-el"; | |||||||
|  * @param {string} [attrs.className] |  * @param {string} [attrs.className] | ||||||
|  * @param {URL} [attrs.src] Example code file path |  * @param {URL} [attrs.src] Example code file path | ||||||
|  * @param {string} [attrs.content] Example code |  * @param {string} [attrs.content] Example code | ||||||
|  * @param {"js"|"ts"|"html"|"css"} [attrs.language="js"] Language of the code |  * @param {"js"|"ts"|"html"|"css"|"shell"} [attrs.language="js"] Language of the code | ||||||
|  * @param {string} [attrs.page_id] ID of the page, if setted it registers shiki |  * @param {string} [attrs.page_id] ID of the page, if setted it registers shiki | ||||||
|  * */ |  * */ | ||||||
| export function code({ id, src, content, language= "js", className= host.slice(1), page_id }){ | export function code({ id, src, content, language= "js", className= host.slice(1), page_id }){ | ||||||
|   | |||||||
							
								
								
									
										175
									
								
								docs/components/converter.html.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								docs/components/converter.html.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,175 @@ | |||||||
|  | import { styles } from "../ssr.js"; | ||||||
|  |  | ||||||
|  | styles.css` | ||||||
|  | #html-to-dde-converter { | ||||||
|  | 	grid-column: full-main; | ||||||
|  | 	display: flex; | ||||||
|  | 	flex-direction: column; | ||||||
|  | 	gap: 1.5rem; | ||||||
|  | 	padding: 1.5rem; | ||||||
|  | 	border-radius: var(--border-radius); | ||||||
|  | 	background-color: var(--bg-sidebar); | ||||||
|  | 	box-shadow: var(--shadow); | ||||||
|  | 	border: 1px solid var(--border); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #html-to-dde-converter h3 { | ||||||
|  | 	margin-top: 0; | ||||||
|  | 	color: var(--primary); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #html-to-dde-converter .description { | ||||||
|  | 	color: var(--text-light); | ||||||
|  | 	font-size: 0.95rem; | ||||||
|  | 	margin-top: -1rem; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #html-to-dde-converter .converter-form { | ||||||
|  | 	display: flex; | ||||||
|  | 	flex-direction: column; | ||||||
|  | 	gap: 1rem; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #html-to-dde-converter .input-group, | ||||||
|  | #html-to-dde-converter .output-group { | ||||||
|  | 	display: flex; | ||||||
|  | 	flex-direction: column; | ||||||
|  | 	gap: 0.5rem; | ||||||
|  | } | ||||||
|  | #html-to-dde-converter [type="number"]{ | ||||||
|  | 	width: 3em; | ||||||
|  | 	font-variant-numeric: tabular-nums; | ||||||
|  | 	font-size: 1rem; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #html-to-dde-converter label { | ||||||
|  | 	font-weight: 500; | ||||||
|  | 	display: flex; | ||||||
|  | 	justify-content: space-between; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #html-to-dde-converter .options { | ||||||
|  | 	display: flex; | ||||||
|  | 	flex-wrap: wrap; | ||||||
|  | 	gap: 1rem; | ||||||
|  | 	margin-bottom: 0.5rem; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #html-to-dde-converter .option-group { | ||||||
|  | 	display: flex; | ||||||
|  | 	align-items: center; | ||||||
|  | 	gap: 0.5rem; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #html-to-dde-converter textarea { | ||||||
|  | 	font-family: var(--font-mono); | ||||||
|  | 	font-size: 0.9rem; | ||||||
|  | 	padding: 1rem; | ||||||
|  | 	border-radius: var(--border-radius); | ||||||
|  | 	border: 1px solid var(--border); | ||||||
|  | 	background-color: var(--bg); | ||||||
|  | 	color: var(--text); | ||||||
|  | 	min-height: 200px; | ||||||
|  | 	resize: vertical; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #html-to-dde-converter textarea:focus { | ||||||
|  | 	outline: 2px solid var(--primary-light); | ||||||
|  | 	outline-offset: 1px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #html-to-dde-converter .button-group { | ||||||
|  | 	display: flex; | ||||||
|  | 	gap: 0.5rem; | ||||||
|  | 	justify-content: space-between; | ||||||
|  | 	align-items: center; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #html-to-dde-converter button { | ||||||
|  | 	padding: 0.5rem 1rem; | ||||||
|  | 	border-radius: var(--border-radius); | ||||||
|  | 	border: none; | ||||||
|  | 	background-color: var(--primary); | ||||||
|  | 	color: var(--button-text); | ||||||
|  | 	font-weight: 500; | ||||||
|  | 	cursor: pointer; | ||||||
|  | 	transition: background-color 0.2s ease; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #html-to-dde-converter button:hover { | ||||||
|  | 	background-color: var(--primary-dark); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #html-to-dde-converter button.secondary { | ||||||
|  | 	background-color: transparent; | ||||||
|  | 	border: 1px solid var(--border); | ||||||
|  | 	color: var(--text); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #html-to-dde-converter button.secondary:hover { | ||||||
|  | 	background-color: var(--bg); | ||||||
|  | 	border-color: var(--primary); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #html-to-dde-converter .copy-button { | ||||||
|  | 	background-color: var(--secondary); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #html-to-dde-converter .copy-button:hover { | ||||||
|  | 	background-color: var(--secondary-dark); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #html-to-dde-converter .status { | ||||||
|  | 	font-size: 0.9rem; | ||||||
|  | 	color: var(--text-light); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #html-to-dde-converter .error { | ||||||
|  | 	color: hsl(0, 100%, 60%); | ||||||
|  | 	font-size: 0.9rem; | ||||||
|  | 	margin-top: 0.5rem; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Sample HTML examples list */ | ||||||
|  | #html-to-dde-converter .examples-list { | ||||||
|  | 	display: flex; | ||||||
|  | 	flex-wrap: wrap; | ||||||
|  | 	gap: 0.5rem; | ||||||
|  | 	margin-top: 0.5rem; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #html-to-dde-converter .example-button { | ||||||
|  | 	font-size: 0.85rem; | ||||||
|  | 	padding: 0.25rem 0.5rem; | ||||||
|  | } | ||||||
|  | `; | ||||||
|  |  | ||||||
|  | import { ireland } from "./ireland.html.js"; | ||||||
|  | import { el } from "deka-dom-el"; | ||||||
|  | const fileURL= url=> new URL(url, import.meta.url); | ||||||
|  |  | ||||||
|  | export function converter({ page_id }){ | ||||||
|  | 	registerClientPart(page_id); | ||||||
|  | 	return el(ireland, { | ||||||
|  | 		src: fileURL("./converter.js.js"), | ||||||
|  | 		exportName: "converter", | ||||||
|  | 		page_id, | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | let is_registered= {}; | ||||||
|  | /** @param {string} page_id */ | ||||||
|  | function registerClientPart(page_id){ | ||||||
|  | 	if(is_registered[page_id]) return; | ||||||
|  |  | ||||||
|  | 	document.head.append( | ||||||
|  | 		el("script", { | ||||||
|  | 			// src: "https://unpkg.com/@beforesemicolon/html-parser/dist/client.js", | ||||||
|  | 			src: "https://cdn.jsdelivr.net/npm/@beforesemicolon/html-parser/dist/client.js", | ||||||
|  | 			type: "text/javascript", | ||||||
|  | 			charset: "utf-8", | ||||||
|  | 			defer: true | ||||||
|  | 		}), | ||||||
|  | 	); | ||||||
|  | 	is_registered[page_id]= true; | ||||||
|  | } | ||||||
							
								
								
									
										383
									
								
								docs/components/converter.js.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										383
									
								
								docs/components/converter.js.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,383 @@ | |||||||
|  | import { el, on } from "deka-dom-el"; | ||||||
|  | import { S } from "deka-dom-el/signals"; | ||||||
|  | const { parse }= globalThis.BFS || { parse(){ return { children: [ "not implemented" ] } } }; | ||||||
|  | // Example HTML snippets | ||||||
|  | const examples = [ | ||||||
|  | { | ||||||
|  | 	name: "Simple Component", | ||||||
|  | 	html: `<div class="card"> | ||||||
|  | 	<img src="image.jpg" alt="Card Image" class="card-image"> | ||||||
|  | 	<h2 class="card-title">Card Title</h2> | ||||||
|  | 	<p class="card-text">This is a simple card component</p> | ||||||
|  | 	<button aria-pressed="mixed" type="button" class="card-button">Click Me</button> | ||||||
|  | </div>` | ||||||
|  | }, | ||||||
|  | { | ||||||
|  | 	name: "Navigation", | ||||||
|  | 	html: `<nav class="main-nav"> | ||||||
|  | 	<ul> | ||||||
|  | 		<li><a href="/" class="active">Home</a></li> | ||||||
|  | 		<li><a href="/about">About</a></li> | ||||||
|  | 		<li><a href="/services">Services</a></li> | ||||||
|  | 		<li><a href="/contact">Contact</a></li> | ||||||
|  | 	</ul> | ||||||
|  | </nav>` | ||||||
|  | }, | ||||||
|  | { | ||||||
|  | 	name: "Form", | ||||||
|  | 	html: `<form class="contact-form" onsubmit="submitForm(event)"> | ||||||
|  | 	<div class="form-group"> | ||||||
|  | 		<label for="name">Name:</label> | ||||||
|  | 		<input type="text" id="name" name="name" required> | ||||||
|  | 	</div> | ||||||
|  | 	<div class="form-group"> | ||||||
|  | 		<label for="email">Email:</label> | ||||||
|  | 		<input type="email" id="email" name="email" required> | ||||||
|  | 	</div> | ||||||
|  | 	<div class="form-group"> | ||||||
|  | 		<label for="message">Message:</label> | ||||||
|  | 		<textarea id="message" name="message" rows="4" required></textarea> | ||||||
|  | 	</div> | ||||||
|  | 	<button type="submit" class="submit-btn">Send Message</button> | ||||||
|  | </form>` | ||||||
|  | } | ||||||
|  | ]; | ||||||
|  |  | ||||||
|  | // Convert HTML to dd<el> code | ||||||
|  | function convertHTMLtoDDE(html, options = {}) { | ||||||
|  |  | ||||||
|  | 	try { | ||||||
|  | 		const parsed = parse(html); | ||||||
|  | 		const content = parsed.children[0] || parsed.childNodes[0]; | ||||||
|  | 		return !content ? "" : nodeToDDE(content, options); | ||||||
|  | 	} catch (error) { | ||||||
|  | 		console.error("Parsing error:", error); | ||||||
|  | 		return `// Error parsing HTML: ${error.message}`; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Node types based on standard DOM nodeType values | ||||||
|  | const NODE_TYPE = { | ||||||
|  | 	ELEMENT: 1,      // Standard element node (equivalent to node.type === "element") | ||||||
|  | 	TEXT: 3,         // Text node (equivalent to node.type === "text") | ||||||
|  | 	COMMENT: 8       // Comment node (equivalent to node.type === "comment") | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // Convert a parsed node to dd<el> code | ||||||
|  | function nodeToDDE(node, options = {}, level = 0) { | ||||||
|  | 	const tab= options.indent === "-1" ? "\t" : " ".repeat(options.indent); | ||||||
|  | 	const indent = tab.repeat(level); | ||||||
|  | 	const nextIndent = tab.repeat(level + 1); | ||||||
|  |  | ||||||
|  | 	const { nodeType } = node; | ||||||
|  | 	// Handle text nodes | ||||||
|  | 	if (nodeType === NODE_TYPE.TEXT) { | ||||||
|  | 		const text = el("i", { innerText: node.nodeValue }).textContent; | ||||||
|  | 		if (!text.trim()) return null; | ||||||
|  |  | ||||||
|  | 		// Return as plain text or template string for longer text | ||||||
|  | 		return text.includes("\n") || text.includes('"') | ||||||
|  | 			? `\`${text}\`` | ||||||
|  | 			: `"${text}"`; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Handle comment nodes | ||||||
|  | 	if (nodeType === NODE_TYPE.COMMENT) { | ||||||
|  | 		const text = node.nodeValue; | ||||||
|  | 		if (!text.trim()) return null; | ||||||
|  | 		return text.includes("\n") | ||||||
|  | 			? [ "/*", ...text.trim().split("\n").map(l=> tab+l), "*/" ] | ||||||
|  | 			: [ `// ${text}` ]; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// For element nodes | ||||||
|  | 	if (nodeType === NODE_TYPE.ELEMENT) { | ||||||
|  | 		// Special case for SVG elements | ||||||
|  | 		const isNS = node.tagName === "svg"; | ||||||
|  | 		const elFunction = isNS ? "elNS" : "el"; | ||||||
|  |  | ||||||
|  | 		// Get tag name | ||||||
|  | 		let tagStr = `"${node.tagName}"`; | ||||||
|  |  | ||||||
|  | 		// Process attributes | ||||||
|  | 		const attrs = []; | ||||||
|  | 		const sets = { | ||||||
|  | 			aria: {}, | ||||||
|  | 			data: {}, | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		for (const { name: key, value } of node.attributes) { | ||||||
|  | 			// Handle class attribute | ||||||
|  | 			if (key === "class") { | ||||||
|  | 				attrs.push(`className: "${value}"`); | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// Handle style attribute | ||||||
|  | 			if (key === "style") { | ||||||
|  | 				if (options.styleAsObject) { | ||||||
|  | 				// Convert inline style to object | ||||||
|  | 				const styleObj = {}; | ||||||
|  | 				value.split(";").forEach(part => { | ||||||
|  | 					const [propRaw, valueRaw] = part.split(":"); | ||||||
|  | 					if (propRaw && valueRaw) { | ||||||
|  | 						const prop = propRaw.trim(); | ||||||
|  | 						const propCamel = prop.replace(/-([a-z])/g, (_, c) => c.toUpperCase()); | ||||||
|  | 						styleObj[propCamel] = valueRaw.trim(); | ||||||
|  | 					} | ||||||
|  | 				}); | ||||||
|  |  | ||||||
|  | 				if (Object.keys(styleObj).length > 0) { | ||||||
|  | 					const styleStr = JSON.stringify(styleObj).replace(/"([^"]+)":/g, "$1:"); | ||||||
|  | 					attrs.push(`style: ${styleStr}`); | ||||||
|  | 				} | ||||||
|  | 				} else { | ||||||
|  | 					// Keep as string | ||||||
|  | 					attrs.push(`style: "${value}"`); | ||||||
|  | 				} | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// Handle boolean attributes | ||||||
|  | 			if (value === "" || value === key) { | ||||||
|  | 				attrs.push(`${key}: true`); | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// Handle data/aria attributes | ||||||
|  | 			if (key.startsWith("data-") || key.startsWith("aria-")) { | ||||||
|  | 				const keyName = key.startsWith("aria-") ? "aria" : "data"; | ||||||
|  | 				const keyCamel = key.slice(keyName.length + 1).replace(/-([a-z])/g, (_, c) => c.toUpperCase()); | ||||||
|  | 				sets[keyName][keyCamel] = value; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// Regular attributes | ||||||
|  | 			const keyRegular = key==="for" | ||||||
|  | 				? "htmlFor" | ||||||
|  | 				: key.startsWith("on") | ||||||
|  | 				? `"=${key}"` | ||||||
|  | 				: key.replace(/-([a-z])/g, (_, c) => c.toUpperCase()); | ||||||
|  | 			attrs.push(`${keyRegular}: "${value}"`); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Process sets | ||||||
|  | 		for (const [name, set] of Object.entries(sets)) { | ||||||
|  | 		if(options.dataAttrsAsCamel) | ||||||
|  | 			for (const [key, value] of Object.entries(set)) | ||||||
|  | 			attrs.push(`${name}${key[0].toUpperCase() + key.substring(1)}: "${value}"`); | ||||||
|  | 		else { | ||||||
|  | 			const setStr= Object.entries(set).map(([key, value]) => `${key}: "${value}"`).join(","); | ||||||
|  | 			if (setStr !== "") | ||||||
|  | 			attrs.push(`${name}set: { ${setStr} }`); | ||||||
|  | 		} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Process children | ||||||
|  | 		const children = []; | ||||||
|  | 		for (const child of node.childNodes) { | ||||||
|  | 			const childCode = nodeToDDE(child, options, level + 1); | ||||||
|  | 			if (!childCode) continue; | ||||||
|  |  | ||||||
|  | 			children.push(childCode); | ||||||
|  | 		} | ||||||
|  | 		if(node.childNodes.length===1 && node.childNodes[0].nodeType===NODE_TYPE.TEXT){ | ||||||
|  | 			const textContent= children.pop().slice(1, -1); | ||||||
|  | 			attrs.unshift(`textContent: "${textContent}"`); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Build the element creation code | ||||||
|  | 		let result = `${elFunction}("${node.tagName.toLowerCase()}"`; | ||||||
|  |  | ||||||
|  | 		// Add attributes if any | ||||||
|  | 		if (attrs.length > 0) { | ||||||
|  | 		const tooLong= attrs.join(``).length+result.length > 55; | ||||||
|  | 		if(options.expaned || tooLong || attrs.length > 3) | ||||||
|  | 			result += `, {\n${nextIndent}${attrs.join(`,\n${nextIndent}`)},\n${indent}}`; | ||||||
|  | 		else | ||||||
|  | 			result += `, { ${attrs.join(", ")} }`; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Add children if any | ||||||
|  | 		if (children.length > 0) { | ||||||
|  | 			const chs= children.map(ch=> | ||||||
|  | 				Array.isArray(ch) ? ch.map(l=> nextIndent + l).join("\n") : | ||||||
|  | 				nextIndent + ch + ","); | ||||||
|  | 			result += `).append(\n${chs.join("\n")}\n${indent})`; | ||||||
|  | 		} else { | ||||||
|  | 			result += ")"; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return result; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return null; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function converter() { | ||||||
|  | 	// State for the converter | ||||||
|  | 	const htmlInput = S(examples[0].html); | ||||||
|  | 	const error = S(""); | ||||||
|  |  | ||||||
|  | 	const status = S(""); | ||||||
|  | 	const showStatus= msg => { | ||||||
|  | 		status.set(msg); | ||||||
|  | 		// Clear status after 3 seconds | ||||||
|  | 		setTimeout(() => status.set(""), 3000); | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	// Options state | ||||||
|  | 	const options = { | ||||||
|  | 		styleAsObject: { | ||||||
|  | 			title: "Convert style to object", | ||||||
|  | 			value: S(true), | ||||||
|  | 		}, | ||||||
|  | 		dataAttrsAsCamel: { | ||||||
|  | 			title: "dataKey/ariaKey (or dataset/ariaset)", | ||||||
|  | 			value: S(true), | ||||||
|  | 		}, | ||||||
|  | 		indent: { | ||||||
|  | 			title: "Indentation (-1 for tabs)", | ||||||
|  | 			value: S("-1"), | ||||||
|  | 			type: "number", | ||||||
|  | 		}, | ||||||
|  | 		expaned: { | ||||||
|  | 			title: "Force multiline", | ||||||
|  | 			value: S(false), | ||||||
|  | 		} | ||||||
|  | 	}; | ||||||
|  | 	const getOptions = ()=> Object.fromEntries(Object.entries(options) | ||||||
|  | 		.map(([key, option]) => ([ | ||||||
|  | 			key, | ||||||
|  | 			option.value.get() | ||||||
|  | 		])) | ||||||
|  | 	); | ||||||
|  |  | ||||||
|  | 	// Update the dd<el> output when input or options change | ||||||
|  | 	const ddeOutput = S(() => { | ||||||
|  | 		try { | ||||||
|  | 			const result = convertHTMLtoDDE(htmlInput.get(), getOptions()); | ||||||
|  | 			error.set(""); | ||||||
|  | 			return result; | ||||||
|  | 		} catch (err) { | ||||||
|  | 			error.set(`Error: ${err.message}`); | ||||||
|  | 			return ""; | ||||||
|  | 		} | ||||||
|  | 	}); | ||||||
|  |  | ||||||
|  | 	// Event handlers | ||||||
|  | 	const onConvert = on("submit", e => { | ||||||
|  | 		e.preventDefault(); | ||||||
|  | 		htmlInput.set(htmlInput.get(), true); | ||||||
|  | 		showStatus("Converted!"); | ||||||
|  | 	}); | ||||||
|  |  | ||||||
|  | 	const onCopy = on("click", async () => { | ||||||
|  | 		if (!ddeOutput.get()) return; | ||||||
|  |  | ||||||
|  | 		try { | ||||||
|  | 			await navigator.clipboard.writeText(ddeOutput.get()); | ||||||
|  | 			showStatus("Copied to clipboard!"); | ||||||
|  | 		} catch (err) { | ||||||
|  | 			error.set(`Could not copy: ${err.message}`); | ||||||
|  | 		} | ||||||
|  | 	}); | ||||||
|  | 	const onClear = on("click", () => { | ||||||
|  | 		htmlInput.set(""); | ||||||
|  | 		showStatus("Input cleared"); | ||||||
|  | 	}); | ||||||
|  | 	const onExampleLoad = (example) => on("click", () => { | ||||||
|  | 		htmlInput.set(example.html); | ||||||
|  | 		showStatus(`Loaded "${example.name}" example`); | ||||||
|  | 	}); | ||||||
|  |  | ||||||
|  | 	const optionsElements = () => Object.entries(options) | ||||||
|  | 		.map(([key, option]) => | ||||||
|  | 			el("label", { className: "option-group" }).append( | ||||||
|  | 				option.type==="number" | ||||||
|  | 					? el("input", { | ||||||
|  | 						type: option.type || "checkbox", | ||||||
|  | 						name: key, | ||||||
|  | 						value: option.value.get(), | ||||||
|  | 						max: 10, | ||||||
|  | 					}, on("change", e => option.value.set(e.target.value))) | ||||||
|  | 					: el("input", { | ||||||
|  | 						type: option.type || "checkbox", | ||||||
|  | 						name: key, | ||||||
|  | 						checked: option.value.get(), | ||||||
|  | 					}, on("change", e => option.value.set(e.target.checked))), | ||||||
|  | 				option.title, | ||||||
|  | 			) | ||||||
|  | 	); | ||||||
|  | 	const exampleButtons = examples.map(example => | ||||||
|  | 		el("button", { | ||||||
|  | 			type: "button", | ||||||
|  | 			className: "secondary example-button" | ||||||
|  | 		}, onExampleLoad(example)).append(example.name) | ||||||
|  | 	); | ||||||
|  |  | ||||||
|  | 	return el("div", { id: "html-to-dde-converter" }).append( | ||||||
|  | 		el("h3", "HTML to dd<el> Converter"), | ||||||
|  | 		el("p", { className: "description" }).append( | ||||||
|  | 			"Convert HTML markup to dd<el> JavaScript code. Paste your HTML below or choose from an example." | ||||||
|  | 		), | ||||||
|  |  | ||||||
|  | 		el("form", { className: "converter-form" }, onConvert).append( | ||||||
|  | 			el("div", { className: "options" }).append(...optionsElements()), | ||||||
|  |  | ||||||
|  | 			el("div", { className: "examples-list" }).append( | ||||||
|  | 				el("label", "Examples: "), | ||||||
|  | 				...exampleButtons | ||||||
|  | 			), | ||||||
|  |  | ||||||
|  | 			el("div", { className: "editor-container" }).append( | ||||||
|  | 				el("div", { className: "input-group" }).append( | ||||||
|  | 					el("label", { htmlFor: "html-input" }).append( | ||||||
|  | 						"HTML Input", | ||||||
|  | 						el("div", { className: "button-group" }).append( | ||||||
|  | 							el("button", { | ||||||
|  | 								type: "button", | ||||||
|  | 								className: "secondary", | ||||||
|  | 								title: "Clear input" | ||||||
|  | 							}, onClear).append("Clear") | ||||||
|  | 						) | ||||||
|  | 					), | ||||||
|  | 					el("textarea", { | ||||||
|  | 						id: "html-input", | ||||||
|  | 						spellcheck: false, | ||||||
|  | 						value: htmlInput, | ||||||
|  | 						placeholder: "Paste your HTML here or choose an example", | ||||||
|  | 						oninput: e => htmlInput.set(e.target.value) | ||||||
|  | 					}) | ||||||
|  | 				), | ||||||
|  |  | ||||||
|  | 				el("div", { className: "output-group" }).append( | ||||||
|  | 					el("label", { htmlFor: "dde-output" }).append( | ||||||
|  | 						"dd<el> Output", | ||||||
|  | 						el("div", { className: "button-group" }).append( | ||||||
|  | 							el("button", { | ||||||
|  | 								type: "button", | ||||||
|  | 								className: "copy-button", | ||||||
|  | 								title: "Copy to clipboard", | ||||||
|  | 								disabled: S(() => !ddeOutput.get()) | ||||||
|  | 							}, onCopy).append("Copy") | ||||||
|  | 						) | ||||||
|  | 					), | ||||||
|  | 					el("textarea", { | ||||||
|  | 						id: "dde-output", | ||||||
|  | 						readonly: true, | ||||||
|  | 						spellcheck: false, | ||||||
|  | 						placeholder: "The converted dd<el> code will appear here", | ||||||
|  | 						value: S(() => ddeOutput.get() || "// Convert HTML to see results here") | ||||||
|  | 					}) | ||||||
|  | 				) | ||||||
|  | 			), | ||||||
|  |  | ||||||
|  | 			el("div", { className: "button-group" }).append( | ||||||
|  | 				S.el(error, error => !error ? el() : el("div", { className: "error" }).append(error)), | ||||||
|  | 				el("div", { className: "status", textContent: status }), | ||||||
|  | 				el("button", { type: "submit" }).append("Convert") | ||||||
|  | 			) | ||||||
|  | 		) | ||||||
|  | 	); | ||||||
|  | } | ||||||
| @@ -1,13 +1,28 @@ | |||||||
| import { el, on } from "deka-dom-el"; | import { el, on } from "deka-dom-el"; | ||||||
| const paragraph= el("p", "See lifecycle events in console.", | function allLifecycleEvents(){ | ||||||
|  | 	return el("form", null, | ||||||
| 		el=> log({ type: "dde:created", detail: el }), | 		el=> log({ type: "dde:created", detail: el }), | ||||||
| 		on.connected(log), | 		on.connected(log), | ||||||
| 		on.disconnected(log), | 		on.disconnected(log), | ||||||
| ); | 	).append( | ||||||
|  | 		el("select", { id: "country" }, on.host(select => { | ||||||
|  | 			// This runs when the host (select) is ready with all its options | ||||||
|  | 			select.value = "cz"; // Pre-select Czechia | ||||||
|  | 			log({ type: "dde:on.host", detail: select }); | ||||||
|  | 		})).append( | ||||||
|  | 			el("option", { value: "au", textContent: "Australia" }), | ||||||
|  | 			el("option", { value: "ca", textContent: "Canada" }), | ||||||
|  | 			el("option", { value: "cz", textContent: "Czechia" }), | ||||||
|  | 		), | ||||||
|  | 		el("p", "See lifecycle events in console."), | ||||||
|  | 	); | ||||||
|  | } | ||||||
|  |  | ||||||
| document.body.append( | document.body.append( | ||||||
| 	paragraph, | 	el(allLifecycleEvents), | ||||||
| 	el("button", "Remove", on("click", ()=> paragraph.remove())) | 	el("button", "Remove Element", on("click", function(){ | ||||||
|  | 		this.previousSibling.remove(); | ||||||
|  | 	})) | ||||||
| ); | ); | ||||||
|  |  | ||||||
| /** @param {Partial<CustomEvent>} event */ | /** @param {Partial<CustomEvent>} event */ | ||||||
|   | |||||||
| @@ -1,8 +0,0 @@ | |||||||
| import { styles } from "../ssr.js"; |  | ||||||
|  |  | ||||||
| styles.css` |  | ||||||
| #library-url-form { |  | ||||||
| 	display: flex; |  | ||||||
| 	flex-flow: column nowrap; |  | ||||||
| } |  | ||||||
| `; |  | ||||||
							
								
								
									
										83
									
								
								docs/components/getLibraryUrl.html.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								docs/components/getLibraryUrl.html.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | |||||||
|  | import { styles } from "../ssr.js"; | ||||||
|  |  | ||||||
|  | styles.css` | ||||||
|  | #library-url-form { | ||||||
|  | 	display: flex; | ||||||
|  | 	flex-flow: column nowrap; | ||||||
|  | 	gap: 1rem; | ||||||
|  | 	padding: 1.5rem; | ||||||
|  | 	border-radius: var(--border-radius); | ||||||
|  | 	background-color: var(--bg-sidebar); | ||||||
|  | 	box-shadow: var(--shadow); | ||||||
|  | 	border: 1px solid var(--border); | ||||||
|  | 	margin: 1.5rem 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #library-url-form .selectors { | ||||||
|  | 	display: flex; | ||||||
|  | 	flex-flow: row wrap; | ||||||
|  | 	gap: 0.75rem; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #library-url-form output { | ||||||
|  | 	display: flex; | ||||||
|  | 	flex-flow: column nowrap; | ||||||
|  | 	gap: 0.75rem; | ||||||
|  | 	margin-top: 0.5rem; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #library-url-form output p { | ||||||
|  | 	font-weight: 500; | ||||||
|  | 	margin: 0.25rem 0; | ||||||
|  | 	color: var(--text-light); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #library-url-form .url-title { | ||||||
|  | 	display: flex; | ||||||
|  | 	align-items: center; | ||||||
|  | 	gap: 0.5rem; | ||||||
|  | 	margin-bottom: -0.25rem; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #library-url-form .url-title strong { | ||||||
|  | 	font-family: var(--font-mono); | ||||||
|  | 	font-size: 0.95rem; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #library-url-form .url-title span { | ||||||
|  | 	color: var(--text-light); | ||||||
|  | 	font-size: 0.9rem; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #library-url-form .code { | ||||||
|  | 	margin-bottom: 1rem; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #library-url-form .info-text { | ||||||
|  | 	font-size: 0.9rem; | ||||||
|  | 	font-style: italic; | ||||||
|  | 	margin-top: 1rem; | ||||||
|  | 	color: var(--text-light); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @media (max-width: 768px) { | ||||||
|  | 	#library-url-form .selectors { | ||||||
|  | 		flex-direction: column; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	#library-url-form select { | ||||||
|  | 		width: 100%; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | `; | ||||||
|  |  | ||||||
|  | import { el } from "deka-dom-el"; | ||||||
|  | import { ireland } from "./ireland.html.js"; | ||||||
|  |  | ||||||
|  | export function getLibraryUrl({ page_id }){ | ||||||
|  | 	return el(ireland, { | ||||||
|  | 		src: new URL("./getLibraryUrl.js.js", import.meta.url), | ||||||
|  | 		exportName: "getLibraryUrl", | ||||||
|  | 		page_id, | ||||||
|  | 	}); | ||||||
|  | } | ||||||
| @@ -8,6 +8,13 @@ const url_base= { | |||||||
| export function getLibraryUrl(){ | export function getLibraryUrl(){ | ||||||
| 	const lib= S([ "esm", "-with-signals", ".min" ]); | 	const lib= S([ "esm", "-with-signals", ".min" ]); | ||||||
| 	const url= S(()=> url_base.jsdeka+lib.get().join("")); | 	const url= S(()=> url_base.jsdeka+lib.get().join("")); | ||||||
|  | 	const urlLabel= S(() => { | ||||||
|  | 		const [format, signalsPart, minified] = lib.get(); | ||||||
|  | 		const formatText = format === "esm" ? "ES Module" : "IIFE"; | ||||||
|  | 		const signalsText = signalsPart ? " with signals" : ""; | ||||||
|  | 		const minText = minified ? " (minified)" : ""; | ||||||
|  | 		return `${formatText}${signalsText}${minText}`; | ||||||
|  | 	}) | ||||||
| 	const onSubmit= on("submit", ev => { | 	const onSubmit= on("submit", ev => { | ||||||
| 		ev.preventDefault(); | 		ev.preventDefault(); | ||||||
| 		const form= new FormData(/** @type {HTMLFormElement} */ (ev.target)); | 		const form= new FormData(/** @type {HTMLFormElement} */ (ev.target)); | ||||||
| @@ -20,56 +27,66 @@ export function getLibraryUrl(){ | |||||||
| 	const onChangeSubmit= on("change", | 	const onChangeSubmit= on("change", | ||||||
| 		ev=> /** @type {HTMLSelectElement} */(ev.target).form.requestSubmit() | 		ev=> /** @type {HTMLSelectElement} */(ev.target).form.requestSubmit() | ||||||
| 	); | 	); | ||||||
| 	const onCopy= on("click", ev => { |  | ||||||
| 		const code= /** @type {HTMLDivElement} */ (ev.target).previousElementSibling; |  | ||||||
| 		navigator.clipboard.writeText(code.textContent); |  | ||||||
| 	}); |  | ||||||
|  |  | ||||||
| 	return el("form", { id: "library-url-form" }, onSubmit).append( | 	return el("form", { id: "library-url-form" }, onSubmit).append( | ||||||
| 		el("select", { name: "module" }, onChangeSubmit).append( | 		el("h4", "Select your preferred library format:"), | ||||||
| 			el("option", { value: "esm", textContent: "ESM — modern JavaScript module" }, | 		el("div", { className: "selectors" }).append( | ||||||
| 				isSelected(lib.get()[0])), | 			el("select", { name: "module" }, onChangeSubmit, | ||||||
| 			el("option", { value: "iife", textContent: "IIFE — legacy JavaScript with DDE global variable" }, | 				on.host(select => select.value = lib.get()[0]), | ||||||
| 				isSelected(lib.get()[0])), | 			).append( | ||||||
|  | 				el("option", { value: "esm", textContent: "ESM — modern JavaScript module" }), | ||||||
|  | 				el("option", { value: "iife", textContent: "IIFE — legacy JavaScript with DDE global variable" }), | ||||||
| 			), | 			), | ||||||
| 		el("select", { name: "what" }, onChangeSubmit).append( | 			el("select", { name: "what" }, onChangeSubmit, | ||||||
| 			el("option", { value: "", textContent: "only DOM part" }, | 				on.host(select => select.value = lib.get()[1]), | ||||||
| 				isSelected(lib.get()[1])), | 			).append( | ||||||
| 			el("option", { value: "-with-signals", textContent: "DOM part and signals library" }, | 				el("option", { value: "", textContent: "DOM part only" }), | ||||||
| 				isSelected(lib.get()[1])), | 				el("option", { value: "-with-signals", textContent: "DOM + signals" }), | ||||||
|  | 			), | ||||||
|  | 			el("select", { name: "minified" }, onChangeSubmit, | ||||||
|  | 				on.host(select => select.value = lib.get()[2]), | ||||||
|  | 			).append( | ||||||
|  | 				el("option", { value: "", textContent: "Unminified" }), | ||||||
|  | 				el("option", { value: ".min", textContent: "Minified" }), | ||||||
| 			), | 			), | ||||||
| 		el("select", { name: "minified" }, onChangeSubmit).append( |  | ||||||
| 			el("option", { value: "", textContent: "unminified" }, |  | ||||||
| 				isSelected(lib.get()[2])), |  | ||||||
| 			el("option", { value: ".min", textContent: "minified" }, |  | ||||||
| 				isSelected(lib.get()[2])), |  | ||||||
| 		), | 		), | ||||||
| 		el("output").append( | 		el("output").append( | ||||||
| 			el("p", "Library URL:"), | 			el("div", { className: "url-title" }).append( | ||||||
| 			el("div", { className: "code", dataJs: "done", tabIndex: 0 }).append( | 				el("strong", "JavaScript:"), | ||||||
| 				el("code").append( | 				el("span", urlLabel), | ||||||
| 					el("pre", S(()=> url.get()+".js")), |  | ||||||
| 			), | 			), | ||||||
| 				el("button", { | 			el(code, { value: S(()=> url.get()+".js") }), | ||||||
| 					className: "copy-button", | 			el("div", { className: "url-title" }).append( | ||||||
| 					textContent: "Copy", | 				el("strong", "TypeScript definition:") | ||||||
| 					ariaLabel: "Copy code to clipboard", |  | ||||||
| 				}, onCopy), |  | ||||||
| 			), |  | ||||||
| 			el("p", "Library type definition:"), |  | ||||||
| 			el("div", { className: "code", dataJs: "done", tabIndex: 0 }).append( |  | ||||||
| 				el("code").append( |  | ||||||
| 					el("pre", S(()=> url.get()+".d.ts")), |  | ||||||
| 				), |  | ||||||
| 				el("button", { |  | ||||||
| 					className: "copy-button", |  | ||||||
| 					textContent: "Copy", |  | ||||||
| 					ariaLabel: "Copy code to clipboard", |  | ||||||
| 				}, onCopy), |  | ||||||
| 			), | 			), | ||||||
|  | 			el(code, { value: S(()=> url.get()+".d.ts") }), | ||||||
|  | 			el("p", { className: "info-text", | ||||||
|  | 				textContent: "Use the CDN URL in your HTML or import it in your JavaScript files." | ||||||
|  | 			}) | ||||||
| 		) | 		) | ||||||
| 	) | 	) | ||||||
| } | } | ||||||
| function isSelected(value){ | /** @param {{ value: ddeSignal<string> }} props */ | ||||||
| 	return element=> element.selected= element.value===value; | function code({ value }){ | ||||||
|  | 	/** @type {ddeSignal<"Copy"|"Copied!">} */ | ||||||
|  | 	const textContent= S("Copy"); | ||||||
|  | 	const onCopy= on("click", () => { | ||||||
|  | 		navigator.clipboard.writeText(value.get()); | ||||||
|  |  | ||||||
|  | 		textContent.set("Copied!"); | ||||||
|  | 		setTimeout(() => { | ||||||
|  | 			textContent.set("Copy"); | ||||||
|  | 		}, 1500); | ||||||
|  | 	}); | ||||||
|  | 	return el("div", { className: "code", dataJs: "done", tabIndex: 0 }).append( | ||||||
|  | 		el("code").append( | ||||||
|  | 			el("pre", value), | ||||||
|  | 		), | ||||||
|  | 		el("button", { | ||||||
|  | 			className: "copy-button", | ||||||
|  | 			textContent, | ||||||
|  | 			ariaLabel: "Copy code to clipboard", | ||||||
|  | 		}, onCopy) | ||||||
|  | 	) | ||||||
|  | 	; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,3 +1,33 @@ | |||||||
|  | import { styles } from "../ssr.js"; | ||||||
|  | styles.css` | ||||||
|  | [data-dde-mark] { | ||||||
|  | 	opacity: .5; | ||||||
|  | 	filter: grayscale(); | ||||||
|  |  | ||||||
|  | 	@media (prefers-reduced-motion: no-preference) { | ||||||
|  | 		animation: fadein 2s infinite ease forwards;; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	position: relative; | ||||||
|  | 	&::after { | ||||||
|  | 		content: "Loading Ireland…"; | ||||||
|  | 		background-color: rgba(0, 0, 0, .5); | ||||||
|  | 		color: white; | ||||||
|  | 		font-weight: bold; | ||||||
|  | 		border-radius: 5px; | ||||||
|  | 		padding: 5px 10px; | ||||||
|  | 		position: absolute; | ||||||
|  | 		top: 3%; | ||||||
|  | 		left: 50%; | ||||||
|  | 		transform: translateX(-50%); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @keyframes fadein { | ||||||
|  | 	from { opacity: .5; } | ||||||
|  | 	to { opacity: .85; } | ||||||
|  | } | ||||||
|  | `; | ||||||
|  |  | ||||||
| import { el, queue } from "deka-dom-el"; | import { el, queue } from "deka-dom-el"; | ||||||
| import { addEventListener, registerClientFile } from "../ssr.js"; | import { addEventListener, registerClientFile } from "../ssr.js"; | ||||||
| import { relative } from "node:path"; | import { relative } from "node:path"; | ||||||
| @@ -21,10 +51,17 @@ export function ireland({ src, exportName = "default", props = {} }) { | |||||||
| 	const path= "./"+relative(dir, src.pathname); | 	const path= "./"+relative(dir, src.pathname); | ||||||
| 	const id = "ireland-" + generateComponentId(src); | 	const id = "ireland-" + generateComponentId(src); | ||||||
| 	const element = el.mark({ type: "later", name: ireland.name }); | 	const element = el.mark({ type: "later", name: ireland.name }); | ||||||
| 	queue(import(path).then(module => { | 	queue( | ||||||
|  | 		import(path) | ||||||
|  | 		.then(module => { | ||||||
| 			const component = module[exportName]; | 			const component = module[exportName]; | ||||||
| 		element.replaceWith(el(component, props, mark(id))); | 			const content= el(component, props, mark(id)); | ||||||
| 	})); | 			element.replaceWith(content); | ||||||
|  | 			content.querySelectorAll("input, textarea, button") | ||||||
|  | 				.forEach(el=> el.disabled= true); | ||||||
|  | 		}) | ||||||
|  | 		.catch(console.error) | ||||||
|  | 	); | ||||||
|  |  | ||||||
| 	if(!componentsRegistry.size) | 	if(!componentsRegistry.size) | ||||||
| 		addEventListener("oneachrender", registerClientPart); | 		addEventListener("oneachrender", registerClientPart); | ||||||
|   | |||||||
| @@ -37,3 +37,14 @@ styles.css` | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| `;
 | `;
 | ||||||
|  | 
 | ||||||
|  | import { el } from "deka-dom-el"; | ||||||
|  | import { ireland } from "./ireland.html.js"; | ||||||
|  | 
 | ||||||
|  | export function scrollTop(){ | ||||||
|  | 	return el(ireland, { | ||||||
|  | 		src: new URL("./scrollTop.js.js", import.meta.url), | ||||||
|  | 		exportName: "scrollTop", | ||||||
|  | 		page_id: "*", | ||||||
|  | 	}); | ||||||
|  | } | ||||||
| @@ -86,7 +86,7 @@ html { | |||||||
| } | } | ||||||
|  |  | ||||||
| :focus-visible { | :focus-visible { | ||||||
| 	outline: 3px solid hsl(231, 48%, 70%); | 	outline: 3px solid var(--primary-light); | ||||||
| 	outline-offset: 2px; | 	outline-offset: 2px; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -207,6 +207,20 @@ figure { | |||||||
| 		max-width: 100%; | 		max-width: 100%; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | select { | ||||||
|  | 	padding: 0.5rem 0.75rem; | ||||||
|  | 	border-radius: var(--border-radius); | ||||||
|  | 	border: 1px solid var(--border); | ||||||
|  | 	background-color: var(--bg); | ||||||
|  | 	color: var(--text); | ||||||
|  | 	cursor: pointer; | ||||||
|  | 	font-size: 0.95rem; | ||||||
|  | 	font-family: var(--font-main); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | select:hover { | ||||||
|  | 	border-color: var(--primary); | ||||||
|  | } | ||||||
|  |  | ||||||
| /* Layout */ | /* Layout */ | ||||||
| body { | body { | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| import "./components/getLibraryUrl.css.js"; | import "./components/getLibraryUrl.html.js"; | ||||||
| import { t, T } from "./utils/index.js"; | import { t, T } from "./utils/index.js"; | ||||||
| export const info= { | export const info= { | ||||||
| 	href: "./", | 	href: "./", | ||||||
| @@ -12,7 +12,7 @@ import { simplePage } from "./layout/simplePage.html.js"; | |||||||
| import { h3 } from "./components/pageUtils.html.js"; | import { h3 } from "./components/pageUtils.html.js"; | ||||||
| import { example } from "./components/example.html.js"; | import { example } from "./components/example.html.js"; | ||||||
| import { code } from "./components/code.html.js"; | import { code } from "./components/code.html.js"; | ||||||
| import { ireland } from "./components/ireland.html.js"; | import { getLibraryUrl } from "./components/getLibraryUrl.html.js"; | ||||||
| /** @param {string} url */ | /** @param {string} url */ | ||||||
| const fileURL= url=> new URL(url, import.meta.url); | const fileURL= url=> new URL(url, import.meta.url); | ||||||
| const references= { | const references= { | ||||||
| @@ -101,13 +101,29 @@ export function page({ pkg, info }){ | |||||||
|  |  | ||||||
| 		el(h3, t`Getting Started`), | 		el(h3, t`Getting Started`), | ||||||
| 		el("p").append(T` | 		el("p").append(T` | ||||||
| 			To get builded dd<el> to be used immediately in your browser, you can download the latest version from: | 			There are multiple ways to include dd<el> in your project. You can use npm for a full development setup, | ||||||
|  | 			or directly include it from a CDN for quick prototyping. | ||||||
| 		`), | 		`), | ||||||
| 		el(ireland, { | 		el("h4", "npm installation"), | ||||||
| 			src: fileURL("./components/getLibraryUrl.js.js"), | 		el(code, { content: "npm install deka-dom-el # Coming soon", language: "shell", page_id }), | ||||||
| 			exportName: "getLibraryUrl", | 		el("h4", "CDN / Direct Script Usage"), | ||||||
| 			page_id, | 		el("p").append(T` | ||||||
| 		}), | 			Use the interactive selector below to choose your preferred format: | ||||||
|  | 		`), | ||||||
|  | 		el(getLibraryUrl, { page_id }), | ||||||
|  | 		el("div", { className: "note" }).append( | ||||||
|  | 			el("p").append(T` | ||||||
|  | 				Based on your selection, you can use dd<el> in your project like this: | ||||||
|  | 			`), | ||||||
|  | 			el(code, { content: ` | ||||||
|  | 				// ESM format (modern JavaScript with import/export) | ||||||
|  | 				import { el, on } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.min.js"; | ||||||
|  |  | ||||||
|  | 				// Or with IIFE format (creates a global DDE object) | ||||||
|  | 				// <script src="https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/iife-with-signals.min.js"></script> | ||||||
|  | 				const { el, on } = DDE; | ||||||
|  | 			`, language: "js", page_id }), | ||||||
|  | 		), | ||||||
|  |  | ||||||
| 		el(h3, t`How to Use This Documentation`), | 		el(h3, t`How to Use This Documentation`), | ||||||
| 		el("p").append(T` | 		el("p").append(T` | ||||||
|   | |||||||
| @@ -3,10 +3,7 @@ import { el, simulateSlots } from "deka-dom-el"; | |||||||
|  |  | ||||||
| import { header } from "./head.html.js"; | import { header } from "./head.html.js"; | ||||||
| import { prevNext } from "../components/pageUtils.html.js"; | import { prevNext } from "../components/pageUtils.html.js"; | ||||||
| import { ireland } from "../components/ireland.html.js"; | import { scrollTop } from "../components/scrollTop.html.js"; | ||||||
| import "../components/scrollTop.css.js"; |  | ||||||
| /** @param {string} url */ |  | ||||||
| const fileURL= url=> new URL(url, import.meta.url); |  | ||||||
|  |  | ||||||
| /** @param {Pick<import("../types.d.ts").PageAttrs, "pkg" | "info">} attrs */ | /** @param {Pick<import("../types.d.ts").PageAttrs, "pkg" | "info">} attrs */ | ||||||
| export function simplePage({ pkg, info }){ | export function simplePage({ pkg, info }){ | ||||||
| @@ -33,6 +30,6 @@ export function simplePage({ pkg, info }){ | |||||||
| 		), | 		), | ||||||
|  |  | ||||||
| 		// Scroll to top button | 		// Scroll to top button | ||||||
| 		el(ireland, { src: fileURL("../components/scrollTop.js.js"), exportName: "scrollTop" }) | 		el(scrollTop), | ||||||
| 	)); | 	)); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -155,8 +155,8 @@ export function page({ pkg, info }){ | |||||||
| 			You can think of an Addon as an “oncreate” event handler. | 			You can think of an Addon as an “oncreate” event handler. | ||||||
| 		`), | 		`), | ||||||
| 		el("p").append(T` | 		el("p").append(T` | ||||||
| 			dd<el> provides two additional lifecycle events that correspond to ${el("a", { textContent: | 			dd<el> provides three additional lifecycle events that correspond to ${el("a", { textContent: | ||||||
| 				"custom element", ...references.mdn_customElements })} lifecycle callbacks: | 				"custom element", ...references.mdn_customElements })} lifecycle callbacks and component patterns: | ||||||
| 		`), | 		`), | ||||||
| 		el("div", { className: "function-table" }).append( | 		el("div", { className: "function-table" }).append( | ||||||
| 			el("dl").append( | 			el("dl").append( | ||||||
| @@ -165,6 +165,10 @@ export function page({ pkg, info }){ | |||||||
|  |  | ||||||
| 				el("dt", t`on.disconnected(callback)`), | 				el("dt", t`on.disconnected(callback)`), | ||||||
| 				el("dd", t`Fires when the element is removed from the DOM`), | 				el("dd", t`Fires when the element is removed from the DOM`), | ||||||
|  |  | ||||||
|  | 				el("dt", t`on.host(callback, host?)`), | ||||||
|  | 				el("dd", t`Fires when the host element is "ready" and allows applying properties based on the fully | ||||||
|  | 					built template`), | ||||||
| 			) | 			) | ||||||
| 		), | 		), | ||||||
| 		el(example, { src: fileURL("./components/examples/events/live-cycle.js"), page_id }), | 		el(example, { src: fileURL("./components/examples/events/live-cycle.js"), page_id }), | ||||||
|   | |||||||
							
								
								
									
										99
									
								
								docs/p14-converter.html.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								docs/p14-converter.html.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,99 @@ | |||||||
|  | import "./components/converter.html.js"; | ||||||
|  | import { T, t } from "./utils/index.js"; | ||||||
|  | export const info= { | ||||||
|  | 	title: t`Convert to dd<el>`, | ||||||
|  | 	fullTitle: t`HTML to dd<el> Converter`, | ||||||
|  | 	description: t`Convert your HTML markup to dd<el> JavaScript code with our interactive tool`, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | import { el } from "deka-dom-el"; | ||||||
|  | import { simplePage } from "./layout/simplePage.html.js"; | ||||||
|  | import { h3 } from "./components/pageUtils.html.js"; | ||||||
|  | import { code } from "./components/code.html.js"; | ||||||
|  | import { converter } from "./components/converter.html.js"; | ||||||
|  |  | ||||||
|  | /** @param {import("./types.d.ts").PageAttrs} attrs */ | ||||||
|  | export function page({ pkg, info }){ | ||||||
|  | 	const page_id= info.id; | ||||||
|  | 	return el(simplePage, { info, pkg }).append( | ||||||
|  | 		el("p").append(T` | ||||||
|  | 			Transitioning from HTML to dd<el> is simple with our interactive converter. This tool helps you quickly | ||||||
|  | 			transform existing HTML markup into dd<el> JavaScript code, making it easier to adopt dd<el> in your projects. | ||||||
|  | 		`), | ||||||
|  |  | ||||||
|  | 		el("div", { className: "callout" }).append( | ||||||
|  | 			el("h4", t`Features`), | ||||||
|  | 			el("ul").append( | ||||||
|  | 				el("li", t`Convert any HTML snippet to dd<el> code instantly`), | ||||||
|  | 				el("li", t`Choose between different output formats (append vs arrays, style handling)`), | ||||||
|  | 				el("li", t`Try pre-built examples or paste your own HTML`), | ||||||
|  | 				el("li", t`Copy results to clipboard with one click`) | ||||||
|  | 			) | ||||||
|  | 		), | ||||||
|  |  | ||||||
|  | 		el("h3", t`How to Use the Converter`), | ||||||
|  | 		el("ol").append( | ||||||
|  | 			el("li").append(T` | ||||||
|  | 				${el("strong", "Paste your HTML")} into the input box or select one of the example templates | ||||||
|  | 			`), | ||||||
|  | 			el("li").append(T` | ||||||
|  | 				${el("strong", "Configure options")} to match your preferred coding style: | ||||||
|  | 				${el("ul").append( | ||||||
|  | 					el("li", t`Convert inline styles to JavaScript objects`), | ||||||
|  | 					el("li", t`Transform data-attributes/aria-attributes`), | ||||||
|  | 				)} | ||||||
|  | 			`), | ||||||
|  | 			el("li").append(T` | ||||||
|  | 				${el("strong", "Click convert")} to generate dd<el> code | ||||||
|  | 			`), | ||||||
|  | 			el("li").append(T` | ||||||
|  | 				${el("strong", "Copy the result")} to your project | ||||||
|  | 			`) | ||||||
|  | 		), | ||||||
|  |  | ||||||
|  | 		// The actual converter component | ||||||
|  | 		el(converter, { page_id }), | ||||||
|  |  | ||||||
|  | 		el("h3", t`How the Converter Works`), | ||||||
|  | 		el("p").append(T` | ||||||
|  | 			The converter uses a three-step process: | ||||||
|  | 		`), | ||||||
|  | 		el("ol").append( | ||||||
|  | 			el("li").append(T` | ||||||
|  | 				${el("strong", "Parsing:")} The HTML is parsed into a structured AST (Abstract Syntax Tree) | ||||||
|  | 			`), | ||||||
|  | 			el("li").append(T` | ||||||
|  | 				${el("strong", "Transformation:")} Each HTML node is converted to its dd<el> equivalent | ||||||
|  | 			`), | ||||||
|  | 			el("li").append(T` | ||||||
|  | 				${el("strong", "Code Generation:")} The final JavaScript code is properly formatted and indented | ||||||
|  | 			`) | ||||||
|  | 		), | ||||||
|  |  | ||||||
|  | 		el("div", { className: "warning" }).append( | ||||||
|  | 			el("p").append(T` | ||||||
|  | 				While the converter handles most basic HTML patterns, complex attributes or specialized elements might | ||||||
|  | 				need manual adjustments. Always review the generated code before using it in production. | ||||||
|  | 			`) | ||||||
|  | 		), | ||||||
|  |  | ||||||
|  | 		el("h3", t`Next Steps`), | ||||||
|  | 		el("p").append(T` | ||||||
|  | 			After converting your HTML to dd<el>, you might want to: | ||||||
|  | 		`), | ||||||
|  | 		el("ul").append( | ||||||
|  | 			el("li").append(T` | ||||||
|  | 				Add signal bindings for dynamic content (see ${el("a", { href: "p04-signals.html", | ||||||
|  | 					textContent: "Signals section" })}) | ||||||
|  | 			`), | ||||||
|  | 			el("li").append(T` | ||||||
|  | 				Organize your components with scopes (see ${el("a", { href: "p05-scopes.html", | ||||||
|  | 					textContent: "Scopes section" })}) | ||||||
|  | 			`), | ||||||
|  | 			el("li").append(T` | ||||||
|  | 				Add event handlers for interactivity (see ${el("a", { href: "p03-events.html", | ||||||
|  | 					textContent: "Events section" })}) | ||||||
|  | 			`) | ||||||
|  | 		) | ||||||
|  | 	); | ||||||
|  | } | ||||||
							
								
								
									
										47
									
								
								index.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										47
									
								
								index.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -184,12 +184,12 @@ interface On{ | |||||||
| 	/** Listens to the DOM event. See {@link Document.addEventListener} */ | 	/** Listens to the DOM event. See {@link Document.addEventListener} */ | ||||||
| 	< | 	< | ||||||
| 		Event extends keyof DocumentEventMap, | 		Event extends keyof DocumentEventMap, | ||||||
| 		EE extends ddeElementAddon<SupportedElement>= ddeElementAddon<HTMLElement>, | 		EL extends SupportedElement | ||||||
| 		>( | 		>( | ||||||
| 			type: Event, | 			type: Event, | ||||||
| 			listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: DocumentEventMap[Event]) => any, | 			listener: (this: EL, ev: DocumentEventMap[Event]) => any, | ||||||
| 			options?: AddEventListenerOptions | 			options?: AddEventListenerOptions | ||||||
| 		) : EE; | 		) : ddeElementAddon<EL>; | ||||||
| 	< | 	< | ||||||
| 		EE extends ddeElementAddon<SupportedElement>= ddeElementAddon<HTMLElement>, | 		EE extends ddeElementAddon<SupportedElement>= ddeElementAddon<HTMLElement>, | ||||||
| 		>( | 		>( | ||||||
| @@ -199,28 +199,39 @@ interface On{ | |||||||
| 		) : EE; | 		) : EE; | ||||||
| 	/** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */// editorconfig-checker-disable-line | 	/** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */// editorconfig-checker-disable-line | ||||||
| 	connected< | 	connected< | ||||||
| 		EE extends ddeElementAddon<SupportedElement>, | 		EL extends SupportedElement | ||||||
| 		El extends ( EE extends ddeElementAddon<infer El> ? El : never ) |  | ||||||
| 		>( | 		>( | ||||||
| 			listener: (this: El, event: CustomEvent<El>) => any, | 			listener: (this: EL, event: CustomEvent<NoInfer<EL>>) => any, | ||||||
| 			options?: AddEventListenerOptions | 			options?: AddEventListenerOptions | ||||||
| 		) : EE; | 		) : ddeElementAddon<EL>; | ||||||
| 	/** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */// editorconfig-checker-disable-line | 	/** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */// editorconfig-checker-disable-line | ||||||
| 	disconnected< | 	disconnected< | ||||||
| 		EE extends ddeElementAddon<SupportedElement>, | 		EL extends SupportedElement | ||||||
| 		El extends ( EE extends ddeElementAddon<infer El> ? El : never ) |  | ||||||
| 		>( | 		>( | ||||||
| 			listener: (this: El, event: CustomEvent<void>) => any, | 			listener: (this: EL, event: CustomEvent<void>) => any, | ||||||
| 			options?: AddEventListenerOptions | 			options?: AddEventListenerOptions | ||||||
| 		) : EE; | 		) : ddeElementAddon<EL>; | ||||||
| 	/** Listens to the element attribute changes. In case of custom elements uses [`attributeChangedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */// editorconfig-checker-disable-line | 	/** | ||||||
| 	attributeChanged< | 	 * Fires when the host element is "ready", for host element itsel, it is just an alias for `scope.host(listener)`. | ||||||
| 		EE extends ddeElementAddon<SupportedElement>, | 	 * This is handy to apply some property depending on full template such as: | ||||||
| 		El extends ( EE extends ddeElementAddon<infer El> ? El : never ) | 	 * ```js | ||||||
|  | 	 * const selected= "Z"; | ||||||
|  | 	 * //... | ||||||
|  | 	 * return el("form").append( | ||||||
|  | 	 *		el("select", null, on.host(e=> e.value=selected)).append( | ||||||
|  | 	 *			el("option", { value: "A", textContent: "A" }), | ||||||
|  | 	 *			//... | ||||||
|  | 	 *			el("option", { value: "Z", textContent: "Z" }), | ||||||
|  | 	 *		), | ||||||
|  | 	 * ); | ||||||
|  | 	 * ``` | ||||||
|  | 	 * */ | ||||||
|  | 	host< | ||||||
|  | 		EL extends SupportedElement | ||||||
| 	>( | 	>( | ||||||
| 			listener: (this: El, event: CustomEvent<[ string, string ]>) => any, | 		listener: (element: EL) => any, | ||||||
| 			options?: AddEventListenerOptions | 		host?: Host<SupportedElement> | ||||||
| 		) : EE; | 	) : ddeElementAddon<EL>; | ||||||
| } | } | ||||||
| export const on: On; | export const on: On; | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								index.js
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								index.js
									
									
									
									
									
								
							| @@ -1,5 +1,3 @@ | |||||||
| export * from "./src/dom.js"; | export * from "./src/dom-lib/index.js"; | ||||||
| export * from "./src/customElement.js"; |  | ||||||
| export * from "./src/events.js"; |  | ||||||
| export { registerReactivity } from "./src/signals-lib/common.js"; |  | ||||||
| export { memo } from "./src/memo.js"; | export { memo } from "./src/memo.js"; | ||||||
|  | export { registerReactivity } from "./src/signals-lib/common.js"; | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								jsdom.js
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								jsdom.js
									
									
									
									
									
								
							| @@ -1,4 +1,4 @@ | |||||||
| import { enviroment as env } from './src/dom-common.js'; | import { enviroment as env } from './src/dom-lib/common.js'; | ||||||
| env.ssr= " ssr"; | env.ssr= " ssr"; | ||||||
|  |  | ||||||
| const q_store= new Set(); | const q_store= new Set(); | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								signals.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								signals.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -2,7 +2,7 @@ export interface Signal<V, A> { | |||||||
| 	/** The current value of the signal */ | 	/** The current value of the signal */ | ||||||
| 	get(): V; | 	get(): V; | ||||||
| 	/** Set new value of the signal */ | 	/** Set new value of the signal */ | ||||||
| 	set(value: V): V; | 	set(value: V, force?: boolean): V; | ||||||
| 	toJSON(): V; | 	toJSON(): V; | ||||||
| 	valueOf(): V; | 	valueOf(): V; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -21,7 +21,7 @@ export const enviroment= { | |||||||
| 	M: globalThis.MutationObserver, | 	M: globalThis.MutationObserver, | ||||||
| 	q: p=> p || Promise.resolve(), | 	q: p=> p || Promise.resolve(), | ||||||
| }; | }; | ||||||
| import { isInstance, isUndef } from './helpers.js'; | import { isInstance, isUndef } from '../helpers.js'; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Handles attribute setting with special undefined handling |  * Handles attribute setting with special undefined handling | ||||||
| @@ -1,6 +1,47 @@ | |||||||
| import { keyLTE, evc, evd, eva } from "./dom-common.js"; | import { keyLTE, evc, evd, eva } from "./common.js"; | ||||||
| import { scope } from "./dom.js"; | import { scope } from "./scopes.js"; | ||||||
| import { c_ch_o } from "./events-observer.js"; | import { c_ch_o } from "./events-observer.js"; | ||||||
|  | import { elementAttribute } from "./helpers.js"; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Simulates slot functionality for elements | ||||||
|  |  * | ||||||
|  |  * @param {HTMLElement} element - Parent element | ||||||
|  |  * @param {HTMLElement} [root=element] - Root element containing slots | ||||||
|  |  * @returns {HTMLElement} The root element | ||||||
|  |  */ | ||||||
|  | export function simulateSlots(element, root= element){ | ||||||
|  | 	const mark_e= "¹⁰", mark_s= "✓"; //NOTE: Markers to identify slots processed by this function. Also “prevents” native behavior as it is unlikely to use these in names. // editorconfig-checker-disable-line
 | ||||||
|  | 	const slots= Object.fromEntries( | ||||||
|  | 		Array.from(root.querySelectorAll("slot")) | ||||||
|  | 			.filter(s => !s.name.endsWith(mark_e)) | ||||||
|  | 			.map(s => [(s.name += mark_e), s])); | ||||||
|  | 	element.append= new Proxy(element.append, { | ||||||
|  | 		apply(orig, _, els){ | ||||||
|  | 			if(els[0]===root) return orig.apply(element, els); | ||||||
|  | 			for(const el of els){ | ||||||
|  | 				const name= (el.slot||"")+mark_e; | ||||||
|  | 				try{ elementAttribute(el, "remove", "slot"); } catch(_error){} | ||||||
|  | 				const slot= slots[name]; | ||||||
|  | 				if(!slot) return; | ||||||
|  | 				if(!slot.name.startsWith(mark_s)){ | ||||||
|  | 					slot.childNodes.forEach(c=> c.remove()); | ||||||
|  | 					slot.name= mark_s+name; | ||||||
|  | 				} | ||||||
|  | 				slot.append(el); | ||||||
|  | 				//TODO?: el.dispatchEvent(new CustomEvent("dde:slotchange", { detail: slot }));
 | ||||||
|  | 			} | ||||||
|  | 			element.append= orig; //TODO?: better memory management, but non-native behavior!
 | ||||||
|  | 			return element; | ||||||
|  | 		} | ||||||
|  | 	}); | ||||||
|  | 	if(element!==root){ | ||||||
|  | 		const els= Array.from(element.childNodes); | ||||||
|  | 		//TODO?: els.forEach(el=> el.remove());
 | ||||||
|  | 		element.append(...els); | ||||||
|  | 	} | ||||||
|  | 	return root; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Renders content into a custom element or shadow root |  * Renders content into a custom element or shadow root | ||||||
| @@ -1,7 +1,6 @@ | |||||||
| import { signals } from "./signals-lib/common.js"; | import { signals } from "../signals-lib/common.js"; | ||||||
| import { enviroment as env } from './dom-common.js'; | import { enviroment as env } from './common.js'; | ||||||
| import { isInstance, isUndef, oAssign } from "./helpers.js"; | import { isInstance, isUndef, oAssign } from "../helpers.js"; | ||||||
| import { on } from "./events.js"; |  | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Queues a promise, this is helpful for crossplatform components (on server side we can wait for all registered |  * Queues a promise, this is helpful for crossplatform components (on server side we can wait for all registered | ||||||
| @@ -11,84 +10,6 @@ import { on } from "./events.js"; | |||||||
|  */ |  */ | ||||||
| export function queue(promise){ return env.q(promise); } | export function queue(promise){ return env.q(promise); } | ||||||
| 
 | 
 | ||||||
| /** |  | ||||||
|  * Array of scope contexts for tracking component hierarchies |  | ||||||
|  * @type {{ scope: object, prevent: boolean, host: function }[]} |  | ||||||
|  */ |  | ||||||
| const scopes= [ { |  | ||||||
| 	get scope(){ return  env.D.body; }, |  | ||||||
| 	host: c=> c ? c(env.D.body) : env.D.body, |  | ||||||
| 	prevent: true, |  | ||||||
| } ]; |  | ||||||
| /** Store for disconnect abort controllers */ |  | ||||||
| const store_abort= new WeakMap(); |  | ||||||
| /** |  | ||||||
|  * Scope management utility for tracking component hierarchies |  | ||||||
|  */ |  | ||||||
| export const scope= { |  | ||||||
| 	/** |  | ||||||
| 	 * Gets the current scope |  | ||||||
| 	 * @returns {Object} Current scope context |  | ||||||
| 	 */ |  | ||||||
| 	get current(){ return scopes[scopes.length-1]; }, |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Gets the host element of the current scope |  | ||||||
| 	 * @returns {Function} Host accessor function |  | ||||||
| 	 */ |  | ||||||
| 	get host(){ return this.current.host; }, |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Creates/gets an AbortController that triggers when the element disconnects |  | ||||||
| 	 * */ |  | ||||||
| 	get signal(){ |  | ||||||
| 		const { host }= this; |  | ||||||
| 		if(store_abort.has(host)) return store_abort.get(host); |  | ||||||
| 
 |  | ||||||
| 		const a= new AbortController(); |  | ||||||
| 		store_abort.set(host, a); |  | ||||||
| 		host(on.disconnected(()=> a.abort())); |  | ||||||
| 		return a.signal; |  | ||||||
| 	}, |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Prevents default behavior in the current scope |  | ||||||
| 	 * @returns {Object} Current scope context |  | ||||||
| 	 */ |  | ||||||
| 	preventDefault(){ |  | ||||||
| 		const { current }= this; |  | ||||||
| 		current.prevent= true; |  | ||||||
| 		return current; |  | ||||||
| 	}, |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Gets a copy of the current scope stack |  | ||||||
| 	 * @returns {Array} Copy of scope stack |  | ||||||
| 	 */ |  | ||||||
| 	get state(){ return [ ...scopes ]; }, |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Pushes a new scope to the stack |  | ||||||
| 	 * @param {Object} [s={}] - Scope object to push |  | ||||||
| 	 * @returns {number} New length of the scope stack |  | ||||||
| 	 */ |  | ||||||
| 	push(s= {}){ return scopes.push(oAssign({}, this.current, { prevent: false }, s)); }, |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Pushes the root scope to the stack |  | ||||||
| 	 * @returns {number} New length of the scope stack |  | ||||||
| 	 */ |  | ||||||
| 	pushRoot(){ return scopes.push(scopes[0]); }, |  | ||||||
| 
 |  | ||||||
| 	/** |  | ||||||
| 	 * Pops the current scope from the stack |  | ||||||
| 	 * @returns {Object|undefined} Popped scope or undefined if only one scope remains |  | ||||||
| 	 */ |  | ||||||
| 	pop(){ |  | ||||||
| 		if(scopes.length===1) return; |  | ||||||
| 		return scopes.pop(); |  | ||||||
| 	}, |  | ||||||
| }; |  | ||||||
| /** | /** | ||||||
|  * Chainable append function for elements |  * Chainable append function for elements | ||||||
|  * @private |  * @private | ||||||
| @@ -107,6 +28,7 @@ export function chainableAppend(el){ | |||||||
| /** Current namespace for element creation */ | /** Current namespace for element creation */ | ||||||
| let namespace; | let namespace; | ||||||
| 
 | 
 | ||||||
|  | import { scope } from "./scopes.js"; | ||||||
| /** | /** | ||||||
|  * Creates a DOM element with specified tag, attributes and addons |  * Creates a DOM element with specified tag, attributes and addons | ||||||
|  * |  * | ||||||
| @@ -191,46 +113,6 @@ export function createElementNS(ns){ | |||||||
| /** Alias for createElementNS */ | /** Alias for createElementNS */ | ||||||
| export { createElementNS as elNS }; | export { createElementNS as elNS }; | ||||||
| 
 | 
 | ||||||
| /** |  | ||||||
|  * Simulates slot functionality for elements |  | ||||||
|  * |  | ||||||
|  * @param {HTMLElement} element - Parent element |  | ||||||
|  * @param {HTMLElement} [root=element] - Root element containing slots |  | ||||||
|  * @returns {HTMLElement} The root element |  | ||||||
|  */ |  | ||||||
| export function simulateSlots(element, root= element){ |  | ||||||
| 	const mark_e= "¹⁰", mark_s= "✓"; //NOTE: Markers to identify slots processed by this function. Also “prevents” native behavior as it is unlikely to use these in names. // editorconfig-checker-disable-line
 |  | ||||||
| 	const slots= Object.fromEntries( |  | ||||||
| 		Array.from(root.querySelectorAll("slot")) |  | ||||||
| 			.filter(s => !s.name.endsWith(mark_e)) |  | ||||||
| 			.map(s => [(s.name += mark_e), s])); |  | ||||||
| 	element.append= new Proxy(element.append, { |  | ||||||
| 		apply(orig, _, els){ |  | ||||||
| 			if(els[0]===root) return orig.apply(element, els); |  | ||||||
| 			for(const el of els){ |  | ||||||
| 				const name= (el.slot||"")+mark_e; |  | ||||||
| 				try{ elementAttribute(el, "remove", "slot"); } catch(_error){} |  | ||||||
| 				const slot= slots[name]; |  | ||||||
| 				if(!slot) return; |  | ||||||
| 				if(!slot.name.startsWith(mark_s)){ |  | ||||||
| 					slot.childNodes.forEach(c=> c.remove()); |  | ||||||
| 					slot.name= mark_s+name; |  | ||||||
| 				} |  | ||||||
| 				slot.append(el); |  | ||||||
| 				//TODO?: el.dispatchEvent(new CustomEvent("dde:slotchange", { detail: slot }));
 |  | ||||||
| 			} |  | ||||||
| 			element.append= orig; //TODO?: better memory management, but non-native behavior!
 |  | ||||||
| 			return element; |  | ||||||
| 		} |  | ||||||
| 	}); |  | ||||||
| 	if(element!==root){ |  | ||||||
| 		const els= Array.from(element.childNodes); |  | ||||||
| 		//TODO?: els.forEach(el=> el.remove());
 |  | ||||||
| 		element.append(...els); |  | ||||||
| 	} |  | ||||||
| 	return root; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** Store for element assignment contexts */ | /** Store for element assignment contexts */ | ||||||
| const assign_context= new WeakMap(); | const assign_context= new WeakMap(); | ||||||
| const { setDeleteAttr }= env; | const { setDeleteAttr }= env; | ||||||
| @@ -251,6 +133,7 @@ export function assign(element, ...attributes){ | |||||||
| 	assign_context.delete(element); | 	assign_context.delete(element); | ||||||
| 	return element; | 	return element; | ||||||
| } | } | ||||||
|  | import { setDelete } from "./helpers.js"; | ||||||
| /** | /** | ||||||
|  * Assigns a single attribute to an element |  * Assigns a single attribute to an element | ||||||
|  * |  * | ||||||
| @@ -290,6 +173,7 @@ export function assignAttribute(element, key, value){ | |||||||
| 	} | 	} | ||||||
| 	return isPropSetter(element, key) ? setDeleteAttr(element, key, value) : setRemoveAttr(key, value); | 	return isPropSetter(element, key) ? setDeleteAttr(element, key, value) : setRemoveAttr(key, value); | ||||||
| } | } | ||||||
|  | import { setRemove, setRemoveNS } from "./helpers.js"; | ||||||
| /** | /** | ||||||
|  * Gets or creates assignment context for an element |  * Gets or creates assignment context for an element | ||||||
|  * |  * | ||||||
| @@ -320,21 +204,6 @@ export function classListDeclarative(element, toggle){ | |||||||
| 	return element; | 	return element; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** |  | ||||||
|  * Generic element attribute manipulation |  | ||||||
|  * |  | ||||||
|  * @param {Element} element - Element to manipulate |  | ||||||
|  * @param {string} op - Operation ("set" or "remove") |  | ||||||
|  * @param {string} key - Attribute name |  | ||||||
|  * @param {any} [value] - Attribute value |  | ||||||
|  * @returns {void} |  | ||||||
|  */ |  | ||||||
| export function elementAttribute(element, op, key, value){ |  | ||||||
| 	if(isInstance(element, env.H)) |  | ||||||
| 		return element[op+"Attribute"](key, value); |  | ||||||
| 	return element[op+"AttributeNS"](null, key, value); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| //TODO: add cache? `(Map/Set)<el.tagName+key,isUndef>`
 | //TODO: add cache? `(Map/Set)<el.tagName+key,isUndef>`
 | ||||||
| /** | /** | ||||||
|  * Checks if a property can be set on an element |  * Checks if a property can be set on an element | ||||||
| @@ -385,45 +254,3 @@ function forEachEntries(s, target, element, obj, cb){ | |||||||
| 		cb(key, val); | 		cb(key, val); | ||||||
| 	}); | 	}); | ||||||
| } | } | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Sets or removes an attribute based on value |  | ||||||
|  * |  | ||||||
|  * @param {Element} obj - Element to modify |  | ||||||
|  * @param {string} prop - Property suffix ("Attribute") |  | ||||||
|  * @param {string} key - Attribute name |  | ||||||
|  * @param {any} val - Attribute value |  | ||||||
|  * @returns {void} |  | ||||||
|  * @private |  | ||||||
|  */ |  | ||||||
| function setRemove(obj, prop, key, val){ |  | ||||||
| 	return obj[ (isUndef(val) ? "remove" : "set") + prop ](key, val); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Sets or removes a namespaced attribute based on value |  | ||||||
|  * |  | ||||||
|  * @param {Element} obj - Element to modify |  | ||||||
|  * @param {string} prop - Property suffix ("Attribute") |  | ||||||
|  * @param {string} key - Attribute name |  | ||||||
|  * @param {any} val - Attribute value |  | ||||||
|  * @param {string|null} [ns=null] - Namespace URI |  | ||||||
|  * @returns {void} |  | ||||||
|  * @private |  | ||||||
|  */ |  | ||||||
| function setRemoveNS(obj, prop, key, val, ns= null){ |  | ||||||
| 	return obj[ (isUndef(val) ? "remove" : "set") + prop + "NS" ](ns, key, val); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Sets or deletes a property based on value |  | ||||||
|  * |  | ||||||
|  * @param {Object} obj - Object to modify |  | ||||||
|  * @param {string} key - Property name |  | ||||||
|  * @param {any} val - Property value |  | ||||||
|  * @returns {void} |  | ||||||
|  * @private |  | ||||||
|  */ |  | ||||||
| function setDelete(obj, key, val){ |  | ||||||
| 	Reflect.set(obj, key, val); if(!isUndef(val)) return; return Reflect.deleteProperty(obj, key); |  | ||||||
| } |  | ||||||
| @@ -1,5 +1,5 @@ | |||||||
| import { enviroment as env, evc, evd } from './dom-common.js'; | import { enviroment as env, evc, evd } from './common.js'; | ||||||
| import { isInstance } from "./helpers.js"; | import { isInstance } from "../helpers.js"; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Connection changes observer for tracking element connection/disconnection |  * Connection changes observer for tracking element connection/disconnection | ||||||
| @@ -1,5 +1,5 @@ | |||||||
| import { keyLTE, evc, evd } from './dom-common.js'; | import { keyLTE, evc, evd } from './common.js'; | ||||||
| import { oAssign, onAbort } from './helpers.js'; | import { oAssign, onAbort } from '../helpers.js'; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Creates a function to dispatch events on elements |  * Creates a function to dispatch events on elements | ||||||
							
								
								
									
										57
									
								
								src/dom-lib/helpers.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/dom-lib/helpers.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | |||||||
|  | import { enviroment as env } from './common.js'; | ||||||
|  | import { isInstance, isUndef } from "../helpers.js"; | ||||||
|  | /** | ||||||
|  |  * Sets or removes an attribute based on value | ||||||
|  |  * | ||||||
|  |  * @param {Element} obj - Element to modify | ||||||
|  |  * @param {string} prop - Property suffix ("Attribute") | ||||||
|  |  * @param {string} key - Attribute name | ||||||
|  |  * @param {any} val - Attribute value | ||||||
|  |  * @returns {void} | ||||||
|  |  * @private | ||||||
|  |  */ | ||||||
|  | export function setRemove(obj, prop, key, val){ | ||||||
|  | 	return obj[ (isUndef(val) ? "remove" : "set") + prop ](key, val); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Sets or removes a namespaced attribute based on value | ||||||
|  |  * | ||||||
|  |  * @param {Element} obj - Element to modify | ||||||
|  |  * @param {string} prop - Property suffix ("Attribute") | ||||||
|  |  * @param {string} key - Attribute name | ||||||
|  |  * @param {any} val - Attribute value | ||||||
|  |  * @param {string|null} [ns=null] - Namespace URI | ||||||
|  |  * @returns {void} | ||||||
|  |  * @private | ||||||
|  |  */ | ||||||
|  | export function setRemoveNS(obj, prop, key, val, ns= null){ | ||||||
|  | 	return obj[ (isUndef(val) ? "remove" : "set") + prop + "NS" ](ns, key, val); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Sets or deletes a property based on value | ||||||
|  |  * | ||||||
|  |  * @param {Object} obj - Object to modify | ||||||
|  |  * @param {string} key - Property name | ||||||
|  |  * @param {any} val - Property value | ||||||
|  |  * @returns {void} | ||||||
|  |  * @private | ||||||
|  |  */ | ||||||
|  | export function setDelete(obj, key, val){ | ||||||
|  | 	Reflect.set(obj, key, val); if(!isUndef(val)) return; return Reflect.deleteProperty(obj, key); | ||||||
|  | } | ||||||
|  | /** | ||||||
|  |  * Generic element attribute manipulation | ||||||
|  |  * | ||||||
|  |  * @param {Element} element - Element to manipulate | ||||||
|  |  * @param {string} op - Operation ("set" or "remove") | ||||||
|  |  * @param {string} key - Attribute name | ||||||
|  |  * @param {any} [value] - Attribute value | ||||||
|  |  * @returns {void} | ||||||
|  |  */ | ||||||
|  | export function elementAttribute(element, op, key, value){ | ||||||
|  | 	if(isInstance(element, env.H)) | ||||||
|  | 		return element[op+"Attribute"](key, value); | ||||||
|  | 	return element[op+"AttributeNS"](null, key, value); | ||||||
|  | } | ||||||
							
								
								
									
										4
									
								
								src/dom-lib/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/dom-lib/index.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | |||||||
|  | export * from "./scopes.js"; | ||||||
|  | export * from "./el.js"; | ||||||
|  | export * from "./events.js"; | ||||||
|  | export * from "./customElement.js"; | ||||||
							
								
								
									
										84
									
								
								src/dom-lib/scopes.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								src/dom-lib/scopes.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,84 @@ | |||||||
|  | import { enviroment as env } from './common.js'; | ||||||
|  | import { oAssign } from "../helpers.js"; | ||||||
|  | import { on } from "./events.js"; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Array of scope contexts for tracking component hierarchies | ||||||
|  |  * @type {{ scope: object, prevent: boolean, host: function }[]} | ||||||
|  |  */ | ||||||
|  | const scopes= [ { | ||||||
|  | 	get scope(){ return  env.D.body; }, | ||||||
|  | 	host: c=> c ? c(env.D.body) : env.D.body, | ||||||
|  | 	prevent: true, | ||||||
|  | } ]; | ||||||
|  | /** Store for disconnect abort controllers */ | ||||||
|  | const store_abort= new WeakMap(); | ||||||
|  | /** | ||||||
|  |  * Scope management utility for tracking component hierarchies | ||||||
|  |  */ | ||||||
|  | export const scope= { | ||||||
|  | 	/** | ||||||
|  | 	 * Gets the current scope | ||||||
|  | 	 * @returns {Object} Current scope context | ||||||
|  | 	 */ | ||||||
|  | 	get current(){ return scopes[scopes.length-1]; }, | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Gets the host element of the current scope | ||||||
|  | 	 * @returns {Function} Host accessor function | ||||||
|  | 	 */ | ||||||
|  | 	get host(){ return this.current.host; }, | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Creates/gets an AbortController that triggers when the element disconnects | ||||||
|  | 	 * */ | ||||||
|  | 	get signal(){ | ||||||
|  | 		const { host }= this; | ||||||
|  | 		if(store_abort.has(host)) return store_abort.get(host); | ||||||
|  |  | ||||||
|  | 		const a= new AbortController(); | ||||||
|  | 		store_abort.set(host, a); | ||||||
|  | 		host(on.disconnected(()=> a.abort())); | ||||||
|  | 		return a.signal; | ||||||
|  | 	}, | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Prevents default behavior in the current scope | ||||||
|  | 	 * @returns {Object} Current scope context | ||||||
|  | 	 */ | ||||||
|  | 	preventDefault(){ | ||||||
|  | 		const { current }= this; | ||||||
|  | 		current.prevent= true; | ||||||
|  | 		return current; | ||||||
|  | 	}, | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Gets a copy of the current scope stack | ||||||
|  | 	 * @returns {Array} Copy of scope stack | ||||||
|  | 	 */ | ||||||
|  | 	get state(){ return [ ...scopes ]; }, | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Pushes a new scope to the stack | ||||||
|  | 	 * @param {Object} [s={}] - Scope object to push | ||||||
|  | 	 * @returns {number} New length of the scope stack | ||||||
|  | 	 */ | ||||||
|  | 	push(s= {}){ return scopes.push(oAssign({}, this.current, { prevent: false }, s)); }, | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Pushes the root scope to the stack | ||||||
|  | 	 * @returns {number} New length of the scope stack | ||||||
|  | 	 */ | ||||||
|  | 	pushRoot(){ return scopes.push(scopes[0]); }, | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Pops the current scope from the stack | ||||||
|  | 	 * @returns {Object|undefined} Popped scope or undefined if only one scope remains | ||||||
|  | 	 */ | ||||||
|  | 	pop(){ | ||||||
|  | 		if(scopes.length===1) return; | ||||||
|  | 		return scopes.pop(); | ||||||
|  | 	}, | ||||||
|  | }; | ||||||
|  | // TODO: better place while no cross-import? | ||||||
|  | on.host= (fn, host= scope.host)=> el=> host(()=> fn(el)); | ||||||
| @@ -159,10 +159,10 @@ signal.clear= function(...signals){ | |||||||
| }; | }; | ||||||
| /** Property key for tracking reactive elements */ | /** Property key for tracking reactive elements */ | ||||||
| const key_reactive= "__dde_reactive"; | const key_reactive= "__dde_reactive"; | ||||||
| import { enviroment as env, eva } from "../dom-common.js"; | import { enviroment as env, eva } from "../dom-lib/common.js"; | ||||||
| import { el } from "../dom.js"; | import { el } from "../dom-lib/index.js"; | ||||||
| import { scope } from "../dom.js"; | import { scope } from "../dom-lib/scopes.js"; | ||||||
| import { on } from "../events.js"; | import { on } from "../dom-lib/events.js"; | ||||||
| import { memo } from "../memo.js"; | import { memo } from "../memo.js"; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user