mirror of
				https://github.com/jaandrle/deka-dom-el
				synced 2025-10-31 05:49:15 +01:00 
			
		
		
		
	🎉 ⚡
This commit is contained in:
		
							
								
								
									
										36
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								README.md
									
									
									
									
									
								
							| @@ -1,4 +1,6 @@ | ||||
| **WIP** (the experimentation phase) | [source code on GitHub](https://github.com/jaandrle/deka-dom-el) | [*mirrored* on Gitea](https://gitea.jaandrle.cz/jaandrle/deka-dom-el) | ||||
| **WIP** (the experimentation phase) | ||||
| | [source code on GitHub](https://github.com/jaandrle/deka-dom-el) | ||||
| | [*mirrored* on Gitea](https://gitea.jaandrle.cz/jaandrle/deka-dom-el) | ||||
|  | ||||
| ***Vanilla for flavouring — a full-fledged feast for large projects*** | ||||
|  | ||||
| @@ -10,11 +12,14 @@ document.body.append( | ||||
| 	el("p", "See some syntax examples here:"), | ||||
| 	el("ul").append( | ||||
| 		el("li").append( | ||||
| 			el("a", { textContent: "Link to the library repo", title: "Deka DOM El — GitHub", href: "https://github.com/jaandrle/deka-dom-el" }) | ||||
| 			el("a", { textContent: "Link to the library repo", | ||||
| 				title: "Deka DOM El — GitHub", | ||||
| 				href: "https://github.com/jaandrle/deka-dom-el" }) | ||||
| 		), | ||||
| 		el("li").append( | ||||
| 			"Use extended Vanilla JavaScript DOM/IDL API: ", | ||||
| 			el("span", { textContent: "» this is a span with class=cN and data-a=A, data-b=B «", className: "cN", dataset: { a: "A", b: "B" } }) | ||||
| 			el("span", { textContent: "» this is a span with class=cN and data-a=A, data-b=B «", | ||||
| 				className: "cN", dataset: { a: "A", b: "B" } }) | ||||
| 		), | ||||
| 		el("li").append( | ||||
| 			el(component, { textContent: "A component", className: "example" }, on("change", console.log)) | ||||
| @@ -35,18 +40,22 @@ function component({ textContent, className }){ | ||||
| } | ||||
| ``` | ||||
| # Deka DOM Elements | ||||
| Creating reactive elements, components and Web components using [IDL](https://developer.mozilla.org/en-US/docs/Glossary/IDL)/JavaScript DOM API and [**signals/observables**](#signals). | ||||
| Creating reactive elements, components and Web components using [IDL](https://developer.mozilla.org/en-US/docs/ | ||||
| Glossary/IDL)/JavaScript DOM API and [**signals/observables**](#signals). | ||||
|  | ||||
| ## Inspiration and suggested alternatives | ||||
| - my previous library (mostly used internaly): [jaandrle/dollar_dom_component: Functional DOM components without JSX and virtual DOM.](https://github.com/jaandrle/dollar_dom_component) | ||||
| - [vanjs-org/van: 🍦 VanJS: World's smallest reactive UI framework. Incredibly Powerful, Insanely Small - Everyone can build a useful UI app in an hour.](https://github.com/vanjs-org/van) | ||||
| - my previous library (mostly used internaly): [jaandrle/dollar_dom_component: Functional DOM components without | ||||
| JSX and virtual DOM.](https://github.com/jaandrle/dollar_dom_component) | ||||
| - [vanjs-org/van: 🍦 VanJS: World's smallest reactive UI framework. Incredibly Powerful, Insanely Small - | ||||
| Everyone can build a useful UI app in an hour.](https://github.com/vanjs-org/van) | ||||
| - [hyperhype/hyperscript: Create HyperText with JavaScript.](https://github.com/hyperhype/hyperscript) | ||||
| - [adamhaile/S: S.js - Simple, Clean, Fast Reactive Programming in Javascript](https://github.com/adamhaile/S) ([adamhaile/surplus: High performance JSX web views for S.js applications](https://github.com/adamhaile/surplus)) | ||||
| - [adamhaile/S: S.js - Simple, Clean, Fast Reactive Programming in Javascript](https://github.com/adamhaile/S) | ||||
| ([adamhaile/surplus: High performance JSX web views for S.js applications](https://github.com/adamhaile/surplus)) | ||||
| - [potch/signals: a small reactive signals library](https://github.com/potch/signals) | ||||
|  | ||||
| ## Why an another one? | ||||
| This library falls somewhere between van/hyperscript and [solid-js](https://github.com/solidjs/solid) in terms of size, complexity, | ||||
| and usability. | ||||
| This library falls somewhere between van/hyperscript and [solid-js](https://github.com/solidjs/solid) in terms of size, | ||||
| complexity, and usability. | ||||
|  | ||||
| Another goal is to proceed in the best spirit of functional programming. This involves starting with | ||||
| pure JavaScript (DOM API) and gradually adding auxiliary functions, ranging from “minor” improvements | ||||
| @@ -74,7 +83,10 @@ To balance these requirements, numerous compromises have been made. To summarize | ||||
| 	- [dist/](dist/) (`https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/`…) | ||||
|  | ||||
| ## Signals | ||||
| - [Signals — whats going on behind the scenes | by Ryan Hoffnan | ITNEXT](https://itnext.io/signals-whats-going-on-behind-the-scenes-ec858589ea63) | ||||
| - [The Evolution of Signals in JavaScript - DEV Community](https://dev.to/this-is-learning/the-evolution-of-signals-in-javascript-8ob) | ||||
| - there is also [tc39/proposal-signals: A proposal to add signals to JavaScript.](https://github.com/tc39/proposal-signals) | ||||
| - [Signals — whats going on behind the scenes | by Ryan Hoffnan | ITNEXT](https://itnext.io/ | ||||
| signals-whats-going-on-behind-the-scenes-ec858589ea63) | ||||
| - [The Evolution of Signals in JavaScript - DEV Community](https://dev.to/this-is-learning/the-evolution-of-signals-in- | ||||
| javascript-8ob) | ||||
| - there is also [tc39/proposal-signals: A proposal to add signals to JavaScript.](https://github.com/tc39/proposal- | ||||
| signals) | ||||
| - [Observer pattern - Wikipedia](https://en.wikipedia.org/wiki/Observer_pattern) | ||||
|   | ||||
							
								
								
									
										17
									
								
								bs/README.md
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								bs/README.md
									
									
									
									
									
								
							| @@ -1 +1,16 @@ | ||||
| [jaandrle/bs: The simplest possible build system using executables](https://github.com/jaandrle/bs/) | ||||
| ## bs: Build system based on executables | ||||
| This project uses [jaandrle/bs: The simplest possible build system using executable/bash scripts]( | ||||
| https://github.com/jaandrle/bs). | ||||
|  | ||||
| #### bs/build.js [--minify|--help] | ||||
| Generates alternative versions of the project (other than native ESM code). | ||||
| Also generates typescript definitions. | ||||
|  | ||||
| #### bs/docs.js | ||||
| Generates documentation, from `docs/`. Uses “SSR” technique, using deka-dom-el itself. | ||||
|  | ||||
| #### bs/lint.sh | ||||
| Lints size of the project, jshint. See configs: | ||||
|  | ||||
| - `package.json`: key `size-limit` | ||||
| - `package.json`: key `jshintConfig` | ||||
|   | ||||
| @@ -34,7 +34,7 @@ $.api("", true) | ||||
| 		const file_dts_out= filesOut(file_dts); | ||||
| 		echoVariant(file_dts_out); | ||||
| 		s.echo(bundleDTS(file_dts)).to(file_dts_out); | ||||
| 		 | ||||
|  | ||||
| 		await toDDE(out, file_root); | ||||
| 	} | ||||
| 	$.exit(0); | ||||
| @@ -43,10 +43,13 @@ $.api("", true) | ||||
| 		const name= "dde"; | ||||
| 		const out= filesOut(file_root+".js", name); | ||||
| 		echoVariant(`${out} (${file} → globalThis.${name})`) | ||||
| 		 | ||||
|  | ||||
| 		let content= s.cat(file).toString().split(/export ?{/); | ||||
| 		content.splice(1, 0, `\nglobalThis.${name}= {`); | ||||
| 		content[2]= content[2].replace(/,(?!\n)/g, ",\n").replace(/(?<!\n)}/, "\n}").replace(/^(\t*)(.*) as ([^,\n]*)(,?)$/mg, "$1$3: $2$4"); | ||||
| 		content[2]= content[2] | ||||
| 			.replace(/,(?!\n)/g, ",\n") | ||||
| 			.replace(/(?<!\n)}/, "\n}") | ||||
| 			.replace(/^(\t*)(.*) as ([^,\n]*)(,?)$/mg, "$1$3: $2$4"); | ||||
| 		s.echo([ | ||||
| 			`//deka-dom-el library is available via global namespace \`${name}\``, | ||||
| 			"(()=> {", | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| #!/usr/bin/env -S npx nodejsscript | ||||
| /* jshint esversion: 11,-W097, -W040, module: true, node: true, expr: true, undef: true *//* global echo, $, pipe, s, fetch, cyclicLoop */ | ||||
| /* jshint esversion: 11,-W097, -W040, module: true, node: true, expr: true, undef: true *//* global echo, $, pipe, s, fetch, cyclicLoop */// editorconfig-checker-disable-line | ||||
| echo("Building static documentation files…"); | ||||
| echo("Preparing…"); | ||||
| import { path_target, pages as pages_registered, styles, dispatchEvent, t } from "../docs/ssr.js"; | ||||
|   | ||||
| @@ -10,7 +10,7 @@ export function createHTMl(html, options= {}){ | ||||
| 	if(dom) cleanHTML(); | ||||
| 	// set a default url if we don't get one - otherwise things explode when we copy localstorage keys | ||||
| 	if (!('url' in options)) { Object.assign(options, { url: 'http://localhost:3000' }) } | ||||
| 	 | ||||
|  | ||||
| 	dom= new JSDOM(html, options); | ||||
| 	const window= dom.window; | ||||
| 	return { | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| #!/usr/bin/env bash | ||||
| set -eou pipefail | ||||
| npx editorconfig-checker -format gcc | ||||
| npx size-limit | ||||
| npx jshint index.js src | ||||
|   | ||||
| @@ -51,9 +51,9 @@ let is_registered= {}; | ||||
| /** @param {string} page_id */ | ||||
| function registerClientPart(page_id){ | ||||
| 	if(is_registered[page_id]) return; | ||||
| 	 | ||||
|  | ||||
| 	document.head.append( | ||||
| 		 el("script", { src: "https://cdn.jsdelivr.net/npm/shiki@0.9", defer: true }), | ||||
| 		el("script", { src: "https://cdn.jsdelivr.net/npm/shiki@0.9", defer: true }), | ||||
| 	); | ||||
| 	registerClientFile( | ||||
| 		new URL("./code.js.js", import.meta.url), | ||||
|   | ||||
| @@ -47,7 +47,7 @@ let is_registered= {}; | ||||
| /** @param {string} page_id */ | ||||
| function registerClientPart(page_id){ | ||||
| 	if(is_registered[page_id]) return; | ||||
| 	 | ||||
|  | ||||
| 	document.head.append( | ||||
| 		el("script", { src: "https://flems.io/flems.html", type: "text/javascript", charset: "utf-8" }), | ||||
| 	); | ||||
| @@ -64,5 +64,5 @@ function generateCodeId(src){ | ||||
| 		.replace(/000+/g, ""); | ||||
| 	const count= 1 + ( store_prev.get(candidate) || 0 ); | ||||
| 	store_prev.set(candidate, count); | ||||
| 	return count.toString()+"-"+candidate;  | ||||
| 	return count.toString()+"-"+candidate; | ||||
| } | ||||
|   | ||||
| @@ -2,7 +2,7 @@ import { | ||||
| 	customElementRender, | ||||
| 	customElementWithDDE, | ||||
| 	observedAttributes, | ||||
| 	el, on, scope  | ||||
| 	el, on, scope | ||||
| } from "deka-dom-el"; | ||||
| import { S } from "deka-dom-el/signals"; | ||||
| export class HTMLCustomElement extends HTMLElement{ | ||||
|   | ||||
| @@ -2,8 +2,8 @@ import { elNS, assign } from "deka-dom-el"; | ||||
| const elSVG= elNS("http://www.w3.org/2000/svg"); | ||||
| const elMath= elNS("http://www.w3.org/1998/Math/MathML"); | ||||
| document.body.append( | ||||
| 	elSVG("svg"), // see https://developer.mozilla.org/en-US/docs/Web/SVG and https://developer.mozilla.org/en-US/docs/Web/API/SVGElement | ||||
| 	elMath("math") // see https://developer.mozilla.org/en-US/docs/Web/MathML and https://developer.mozilla.org/en-US/docs/Web/MathML/Global_attributes | ||||
| 	elSVG("svg"), // see https://developer.mozilla.org/en-US/docs/Web/SVG and https://developer.mozilla.org/en-US/docs/Web/API/SVGElement // editorconfig-checker-disable-line | ||||
| 	elMath("math") // see https://developer.mozilla.org/en-US/docs/Web/MathML and https://developer.mozilla.org/en-US/docs/Web/MathML/Global_attributes // editorconfig-checker-disable-line | ||||
| ); | ||||
|  | ||||
| console.log( | ||||
|   | ||||
| @@ -36,7 +36,7 @@ function elClass(_class, attributes, ...addons){ | ||||
| 	}); | ||||
| 	element.prepend(el_mark); | ||||
| 	if(is_fragment) element_host= el_mark; | ||||
| 	 | ||||
|  | ||||
| 	chainableAppend(element); | ||||
| 	addons.forEach(c=> c(element_host)); | ||||
| 	scope.pop(); | ||||
|   | ||||
| @@ -23,7 +23,7 @@ function component(){ | ||||
| 	 *	const data= O("data"); | ||||
| 	 *	ul.append(el("li", data)); | ||||
| 	 * }); | ||||
| 	 *  | ||||
| 	 * | ||||
| 	 * // THE HOST IS PROBABLY DIFFERENT THAN | ||||
| 	 * // YOU EXPECT AND OBSERVABLES MAY BE | ||||
| 	 * // UNEXPECTEDLY REMOVED!!! | ||||
|   | ||||
| @@ -4,25 +4,32 @@ import { mnemonicUl } from "../mnemonicUl.html.js"; | ||||
| export function mnemonic(){ | ||||
| 	return mnemonicUl().append( | ||||
| 		el("li").append( | ||||
| 			el("code", "customElementRender(<custom-element>, <connect-target>, <render-function>[, <properties>])"), " — use function to render DOM structure for given <custom-element>", | ||||
| 			el("code", "customElementRender(<custom-element>, <connect-target>, <render-function>[, <properties>])"), | ||||
| 			" — use function to render DOM structure for given <custom-element>", | ||||
| 		), | ||||
| 		el("li").append( | ||||
| 			el("code", "customElementWithDDE(<custom-element>)"), " — register <custom-element> to DDE library, see also `lifecyclesToEvents`, can be also used as decorator", | ||||
| 			el("code", "customElementWithDDE(<custom-element>)"), | ||||
| 			" — register <custom-element> to DDE library, see also `lifecyclesToEvents`, can be also used as decorator", | ||||
| 		), | ||||
| 		el("li").append( | ||||
| 			el("code", "observedAttributes(<custom-element>)"), " — returns record of observed attributes (keys uses camelCase)", | ||||
| 			el("code", "observedAttributes(<custom-element>)"), | ||||
| 			" — returns record of observed attributes (keys uses camelCase)", | ||||
| 		), | ||||
| 		el("li").append( | ||||
| 			el("code", "S.observedAttributes(<custom-element>)"), " — returns record of observed attributes (keys uses camelCase and values are signals)", | ||||
| 			el("code", "S.observedAttributes(<custom-element>)"), | ||||
| 			" — returns record of observed attributes (keys uses camelCase and values are signals)", | ||||
| 		), | ||||
| 		el("li").append( | ||||
| 			el("code", "lifecyclesToEvents(<class-declaration>)"), " — convert lifecycle methods to events, can be also used as decorator", | ||||
| 			el("code", "lifecyclesToEvents(<class-declaration>)"), | ||||
| 			" — convert lifecycle methods to events, can be also used as decorator", | ||||
| 		), | ||||
| 		el("li").append( | ||||
| 			el("code", "simulateSlots(<class-instance>, <body>[, <mapper>])"), " — simulate slots for Custom Elements without shadow DOM", | ||||
| 			el("code", "simulateSlots(<class-instance>, <body>[, <mapper>])"), | ||||
| 			" — simulate slots for Custom Elements without shadow DOM", | ||||
| 		), | ||||
| 		el("li").append( | ||||
| 			el("code", "simulateSlots(<dde-component>[, <mapper>])"), " — simulate slots for “dde”/functional components", | ||||
| 			el("code", "simulateSlots(<dde-component>[, <mapper>])"), | ||||
| 			" — simulate slots for “dde”/functional components", | ||||
| 		), | ||||
| 	); | ||||
| } | ||||
|   | ||||
| @@ -4,22 +4,28 @@ import { mnemonicUl } from "../mnemonicUl.html.js"; | ||||
| export function mnemonic(){ | ||||
| 	return mnemonicUl().append( | ||||
| 		el("li").append( | ||||
| 			el("code", "assign(<element>, ...<idl-objects>): <element>"), " — assign properties to the element", | ||||
| 			el("code", "assign(<element>, ...<idl-objects>): <element>"), | ||||
| 			" — assign properties to the element", | ||||
| 		), | ||||
| 		el("li").append( | ||||
| 			el("code", "el(<tag-name>, <primitive>)[.append(...)]: <element-from-tag-name>"), " — simple element containing only text", | ||||
| 			el("code", "el(<tag-name>, <primitive>)[.append(...)]: <element-from-tag-name>"), | ||||
| 			" — simple element containing only text", | ||||
| 		), | ||||
| 		el("li").append( | ||||
| 			el("code", "el(<tag-name>, <idl-object>)[.append(...)]: <element-from-tag-name>"), " — element with more properties", | ||||
| 			el("code", "el(<tag-name>, <idl-object>)[.append(...)]: <element-from-tag-name>"), | ||||
| 			" — element with more properties", | ||||
| 		), | ||||
| 		el("li").append( | ||||
| 			el("code", "el(<function>, <function-argument(s)>)[.append(...)]: <element-returned-by-function>"), " — using component represented by function", | ||||
| 			el("code", "el(<function>, <function-argument(s)>)[.append(...)]: <element-returned-by-function>"), | ||||
| 			" — using component represented by function", | ||||
| 		), | ||||
| 		el("li").append( | ||||
| 			el("code", "el(<...>, <...>, ...<addons>)"), " — see following page" | ||||
| 			el("code", "el(<...>, <...>, ...<addons>)"), | ||||
| 			" — see following page" | ||||
| 		), | ||||
| 		el("li").append( | ||||
| 			el("code", "elNS(<namespace>)(<as-el-see-above>)[.append(...)]: <element-based-on-arguments>"), " — typically SVG elements", | ||||
| 			el("code", "elNS(<namespace>)(<as-el-see-above>)[.append(...)]: <element-based-on-arguments>"), | ||||
| 			" — typically SVG elements", | ||||
| 		) | ||||
| 	); | ||||
| } | ||||
|   | ||||
| @@ -4,17 +4,21 @@ import { mnemonicUl } from "../mnemonicUl.html.js"; | ||||
| export function mnemonic(){ | ||||
| 	return mnemonicUl().append( | ||||
| 		el("li").append( | ||||
| 			el("code", "on(<event>, <listener>[, <options>])(<element>)"), " — just ", el("code", "<element>.addEventListener(<event>, <listener>[, <options>])") | ||||
| 			el("code", "on(<event>, <listener>[, <options>])(<element>)"), | ||||
| 			" — just ", el("code", "<element>.addEventListener(<event>, <listener>[, <options>])") | ||||
| 		), | ||||
| 		el("li").append( | ||||
| 			el("code", "on.<live-cycle>(<event>, <listener>[, <options>])(<element>)"), " — corresponds to custom elemnets callbacks ", el("code", "<live-cycle>Callback(...){...}"), | ||||
| 			el("code", "on.<live-cycle>(<event>, <listener>[, <options>])(<element>)"), | ||||
| 			" — corresponds to custom elemnets callbacks ", el("code", "<live-cycle>Callback(...){...}"), | ||||
| 			". To connect to custom element see following page, else it is simulated by MutationObserver." | ||||
| 		), | ||||
| 		el("li").append( | ||||
| 			el("code", "dispatchEvent(<event>[, <options>])(element)"), " — just ", el("code", "<element>.dispatchEvent(new Event(<event>[, <options>]))") | ||||
| 			el("code", "dispatchEvent(<event>[, <options>])(element)"), | ||||
| 			" — just ", el("code", "<element>.dispatchEvent(new Event(<event>[, <options>]))") | ||||
| 		), | ||||
| 		el("li").append( | ||||
| 			el("code", "dispatchEvent(<event>[, <options>])(element, detail)"), " — just ", el("code", "<element>.dispatchEvent(new CustomEvent(<event>, { detail, ...<options> }))") | ||||
| 			el("code", "dispatchEvent(<event>[, <options>])(element, detail)"), | ||||
| 			" — just ", el("code", "<element>.dispatchEvent(new CustomEvent(<event>, { detail, ...<options> }))") | ||||
| 		), | ||||
| 	); | ||||
| } | ||||
|   | ||||
| @@ -4,13 +4,16 @@ import { mnemonicUl } from "../mnemonicUl.html.js"; | ||||
| export function mnemonic(){ | ||||
| 	return mnemonicUl().append( | ||||
| 		el("li").append( | ||||
| 			el("code", "el(<function>, <function-argument(s)>)[.append(...)]: <element-returned-by-function>"), " — using component represented by function", | ||||
| 			el("code", "el(<function>, <function-argument(s)>)[.append(...)]: <element-returned-by-function>"), | ||||
| 			" — using component represented by function", | ||||
| 		), | ||||
| 		el("li").append( | ||||
| 			el("code", "scope.host()"), " — get current component reference" | ||||
| 			el("code", "scope.host()"), | ||||
| 			" — get current component reference" | ||||
| 		), | ||||
| 		el("li").append( | ||||
| 			el("code", "scope.host(...<addons>)"), " — use addons to current component", | ||||
| 			el("code", "scope.host(...<addons>)"), | ||||
| 			" — use addons to current component", | ||||
| 		) | ||||
| 	); | ||||
| } | ||||
|   | ||||
| @@ -7,22 +7,28 @@ export function mnemonic(){ | ||||
| 			el("code", "S(<value>)"), " — signal: reactive value", | ||||
| 		), | ||||
| 		el("li").append( | ||||
| 			el("code", "S(()=> <computation>)"), " — read-only signal: reactive value dependent on calculation using other signals", | ||||
| 			el("code", "S(()=> <computation>)"), | ||||
| 			" — read-only signal: reactive value dependent on calculation using other signals", | ||||
| 		), | ||||
| 		el("li").append( | ||||
| 			el("code", "S.on(<signal>, <listener>[, <options>])"), " — listen to the signal value changes", | ||||
| 			el("code", "S.on(<signal>, <listener>[, <options>])"), | ||||
| 			" — listen to the signal value changes", | ||||
| 		), | ||||
| 		el("li").append( | ||||
| 			el("code", "S.clear(...<signals>)"), " — off and clear signals", | ||||
| 			el("code", "S.clear(...<signals>)"), | ||||
| 			" — off and clear signals", | ||||
| 		), | ||||
| 		el("li").append( | ||||
| 			el("code", "S(<value>, <actions>)"), " — signal: pattern to create complex reactive objects/arrays", | ||||
| 			el("code", "S(<value>, <actions>)"), | ||||
| 			" — signal: pattern to create complex reactive objects/arrays", | ||||
| 		), | ||||
| 		el("li").append( | ||||
| 			el("code", "S.action(<signal>, <action-name>, ...<action-arguments>)"), " — invoke an action for given signal" | ||||
| 			el("code", "S.action(<signal>, <action-name>, ...<action-arguments>)"), | ||||
| 			" — invoke an action for given signal" | ||||
| 		), | ||||
| 		el("li").append( | ||||
| 			el("code", "S.el(<signal>, <function-returning-dom>)"), " — render partial dom structure (template) based on the current signal value", | ||||
| 			el("code", "S.el(<signal>, <function-returning-dom>)"), | ||||
| 			" — render partial dom structure (template) based on the current signal value", | ||||
| 		) | ||||
| 	); | ||||
| } | ||||
|   | ||||
| @@ -27,7 +27,7 @@ export function page({ pkg, info }){ | ||||
| 	const page_id= info.id; | ||||
| 	return el(simplePage, { info, pkg }).append( | ||||
| 		el("p", t`The library tries to provide pure JavaScript tool(s) to create reactive interfaces using …`), | ||||
| 		 | ||||
|  | ||||
| 		el(h3, t`Event-driven programming (3 parts separation ≡ 3PS)`), | ||||
| 		el("p").append(t` | ||||
| 			Let's introduce the basic principle on which the library is built. We'll use the JavaScript listener as | ||||
| @@ -56,7 +56,7 @@ export function page({ pkg, info }){ | ||||
| 			describe usage in specific situations, see for example ${el("a", { textContent: t`MVVM`, ...references.w_mvv })} | ||||
| 			or ${el("a", { textContent: t`MVC`, ...references.w_mvc })}. | ||||
| 		`), | ||||
| 		 | ||||
|  | ||||
| 		el(h3, t`Organization of the documentation`), | ||||
| 	); | ||||
| } | ||||
|   | ||||
| @@ -69,7 +69,7 @@ function metaFacebook({ name, description, homepage }){ | ||||
| function iconGitHub(){ | ||||
| 	const el= elNS("http://www.w3.org/2000/svg"); | ||||
| 	return el("svg", { className: "icon", viewBox: "0 0 32 32" }).append( | ||||
| 		el("path", { d: [ //see https://svg-path-visualizer.netlify.app/#M16%200.395c-8.836%200-16%207.163-16%2016%200%207.069%204.585%2013.067%2010.942%2015.182%200.8%200.148%201.094-0.347%201.094-0.77%200-0.381-0.015-1.642-0.022-2.979-4.452%200.968-5.391-1.888-5.391-1.888-0.728-1.849-1.776-2.341-1.776-2.341-1.452-0.993%200.11-0.973%200.11-0.973%201.606%200.113%202.452%201.649%202.452%201.649%201.427%202.446%203.743%201.739%204.656%201.33%200.143-1.034%200.558-1.74%201.016-2.14-3.554-0.404-7.29-1.777-7.29-7.907%200-1.747%200.625-3.174%201.649-4.295-0.166-0.403-0.714-2.030%200.155-4.234%200%200%201.344-0.43%204.401%201.64%201.276-0.355%202.645-0.532%204.005-0.539%201.359%200.006%202.729%200.184%204.008%200.539%203.054-2.070%204.395-1.64%204.395-1.64%200.871%202.204%200.323%203.831%200.157%204.234%201.026%201.12%201.647%202.548%201.647%204.295%200%206.145-3.743%207.498-7.306%207.895%200.574%200.497%201.085%201.47%201.085%202.963%200%202.141-0.019%203.864-0.019%204.391%200%200.426%200.288%200.925%201.099%200.768%206.354-2.118%2010.933-8.113%2010.933-15.18%200-8.837-7.164-16-16-16z | ||||
| 		el("path", { d: [ //see https://svg-path-visualizer.netlify.app/#M16%200.395c-8.836%200-16%207.163-16%2016%200%207.069%204.585%2013.067%2010.942%2015.182%200.8%200.148%201.094-0.347%201.094-0.77%200-0.381-0.015-1.642-0.022-2.979-4.452%200.968-5.391-1.888-5.391-1.888-0.728-1.849-1.776-2.341-1.776-2.341-1.452-0.993%200.11-0.973%200.11-0.973%201.606%200.113%202.452%201.649%202.452%201.649%201.427%202.446%203.743%201.739%204.656%201.33%200.143-1.034%200.558-1.74%201.016-2.14-3.554-0.404-7.29-1.777-7.29-7.907%200-1.747%200.625-3.174%201.649-4.295-0.166-0.403-0.714-2.030%200.155-4.234%200%200%201.344-0.43%204.401%201.64%201.276-0.355%202.645-0.532%204.005-0.539%201.359%200.006%202.729%200.184%204.008%200.539%203.054-2.070%204.395-1.64%204.395-1.64%200.871%202.204%200.323%203.831%200.157%204.234%201.026%201.12%201.647%202.548%201.647%204.295%200%206.145-3.743%207.498-7.306%207.895%200.574%200.497%201.085%201.47%201.085%202.963%200%202.141-0.019%203.864-0.019%204.391%200%200.426%200.288%200.925%201.099%200.768%206.354-2.118%2010.933-8.113%2010.933-15.18%200-8.837-7.164-16-16-16z // editorconfig-checker-disable-line | ||||
| 			"M 16,0.395", | ||||
| 			"c -8.836,0 -16,7.163 -16,16", | ||||
| 			"c 0,7.069 4.585,13.067 10.942,15.182", | ||||
|   | ||||
| @@ -54,7 +54,7 @@ export function page({ pkg, info }){ | ||||
| 		`), | ||||
|  | ||||
| 		el(code, { src: fileURL("./components/examples/elements/intro.js"), page_id }), | ||||
| 		 | ||||
|  | ||||
| 		el(h3, t`Creating element(s) (with custom attributes)`), | ||||
| 		el("p").append(...T` | ||||
| 			You can create a native DOM element by using the ${el("a", references.mdn_create).append( | ||||
| @@ -77,8 +77,9 @@ export function page({ pkg, info }){ | ||||
| 		el("p").append(...T` | ||||
| 			You can study all JavaScript elements interfaces to the corresponding HTML elements. All HTML elements | ||||
| 			inherits from ${el("a", { textContent: "HTMLElement", ...references.mdn_el })}. To see | ||||
| 			all available IDLs for example for paragraphs, see ${el("a", { textContent: "HTMLParagraphElement", ...references.mdn_p })}. | ||||
| 			Moreover, the ${el("code", "assign")} provides a way to sets declaratively some convenient properties: | ||||
| 			all available IDLs for example for paragraphs, see ${el("a", { textContent: "HTMLParagraphElement", | ||||
| 			...references.mdn_p })}. Moreover, the ${el("code", "assign")} provides a way to sets declaratively | ||||
| 			some convenient properties: | ||||
| 		`), | ||||
| 		el("ul").append( | ||||
| 			el("li").append(...T` | ||||
| @@ -114,7 +115,7 @@ export function page({ pkg, info }){ | ||||
| 			${el("code", "classListDeclarative")}. | ||||
| 		`), | ||||
| 		el(example, { src: fileURL("./components/examples/elements/dekaAssign.js"), page_id }), | ||||
| 		 | ||||
|  | ||||
| 		el(h3, t`Native JavaScript templating`), | ||||
| 		el("p", t`By default, the native JS has no good way to define HTML template using DOM API:`), | ||||
| 		el(example, { src: fileURL("./components/examples/elements/nativeAppend.js"), page_id }), | ||||
| @@ -123,8 +124,8 @@ export function page({ pkg, info }){ | ||||
| 			parent element. | ||||
| 		`), | ||||
| 		el(example, { src: fileURL("./components/examples/elements/dekaAppend.js"), page_id }), | ||||
| 		 | ||||
| 		 | ||||
|  | ||||
|  | ||||
| 		el(h3, t`Basic (state-less) components`), | ||||
| 		el("p").append(...T` | ||||
| 			You can use functions for encapsulation (repeating) logic. The ${el("code", "el")} accepts function | ||||
| @@ -149,7 +150,7 @@ export function page({ pkg, info }){ | ||||
| 			the ${el("code", "elNS")} function: | ||||
| 		`), | ||||
| 		el(example, { src: fileURL("./components/examples/elements/dekaElNS.js"), page_id }), | ||||
| 		 | ||||
|  | ||||
| 		el(mnemonic) | ||||
| 	); | ||||
| } | ||||
|   | ||||
| @@ -29,7 +29,7 @@ const references= { | ||||
| 	}, | ||||
| 	/** Custom Element lifecycle callbacks */ | ||||
| 	mdn_customElement: { | ||||
| 		href: "https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks"  | ||||
| 		href: "https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks" // editorconfig-checker-disable-line | ||||
| 	}, | ||||
| 	/** MutationObserver */ | ||||
| 	mdn_mutation: { | ||||
| @@ -50,9 +50,9 @@ export function page({ pkg, info }){ | ||||
| 			We quickly introduce helper to listening to the native DOM events. And library syntax/pattern so-called | ||||
| 			${el("em", t`Addon`)} to incorporate not only this in UI templates declaratively. | ||||
| 		`), | ||||
| 		 | ||||
|  | ||||
| 		el(code, { src: fileURL("./components/examples/events/intro.js"), page_id }), | ||||
| 		 | ||||
|  | ||||
| 		el(h3, t`Events and listenners`), | ||||
| 		el("p").append(...T` | ||||
| 			In JavaScript you can listen to the native DOM events of the given element by using | ||||
| @@ -105,17 +105,20 @@ export function page({ pkg, info }){ | ||||
| 		`), | ||||
| 		el("p").append(...T` | ||||
| 			The library provide three additional live-cycle events corresponding to how they are named in a case of | ||||
| 			custom elements: ${el("code", "on.connected")}, ${el("code", "on.disconnected")} and ${el("code", "on.attributeChanged")}. | ||||
| 			custom elements: ${el("code", "on.connected")}, ${el("code", "on.disconnected")} and ${el("code", | ||||
| 			"on.attributeChanged")}. | ||||
| 		`), | ||||
| 		el(example, { src: fileURL("./components/examples/events/live-cycle.js"), page_id }), | ||||
| 		el("p").append(...T` | ||||
| 			For Custom elements, we will later introduce a way to replace ${el("code", "*Callback")} syntax with | ||||
| 			${el("code", "dde:*")} events. The ${el("code", "on.*")} functions then listen to the appropriate | ||||
| 			Custom Elements events (see ${el("a", { textContent: t`Custom element lifecycle callbacks | MDN`, ...references.mdn_customElement })}). | ||||
| 			Custom Elements events (see ${el("a", { textContent: t`Custom element lifecycle callbacks | MDN`, | ||||
| 			...references.mdn_customElement })}). | ||||
| 		`), | ||||
| 		el("p").append(...T` | ||||
| 			But, in case of regular elemnets the ${el("a", references.mdn_mutation).append(el("code", "MutationObserver"), " | MDN")} | ||||
| 			is internaly used to track these events. Therefore, there are some drawbacks: | ||||
| 			But, in case of regular elemnets the ${el("a", references.mdn_mutation).append(el("code", | ||||
| 			"MutationObserver"), " | MDN")} is internaly used to track these events. Therefore, there are some | ||||
| 			drawbacks: | ||||
| 		`), | ||||
| 		el("ul").append( | ||||
| 			el("li").append(...T` | ||||
| @@ -136,14 +139,15 @@ export function page({ pkg, info }){ | ||||
| 			native behaviour re-(dis)connecting element, use: | ||||
| 		`), | ||||
| 		el("ul").append( | ||||
| 			el("li").append(...T`custom ${el("code", "MutationObserver")} or logic in (dis)${el("code", "connectedCallback")} or…`), | ||||
| 			el("li").append(...T`custom ${el("code", "MutationObserver")} or logic in (dis)${el("code", | ||||
| 			"connectedCallback")} or…`), | ||||
| 			el("li").append(...T`re-add ${el("code", "on.connected")} or ${el("code", "on.disconnected")} listeners.`) | ||||
| 		), | ||||
|  | ||||
| 		el(h3, t`Final notes`), | ||||
| 		el("p", t`The library also provides a method to dispatch the events.`), | ||||
| 		el(example, { src: fileURL("./components/examples/events/compareDispatch.js"), page_id }), | ||||
| 		 | ||||
|  | ||||
| 		el(mnemonic) | ||||
| 	); | ||||
| } | ||||
|   | ||||
| @@ -49,7 +49,7 @@ export function page({ pkg, info }){ | ||||
| 			programming. If we desire to solve the issue in a declarative manner, signals may be a viable approach. | ||||
| 		`), | ||||
| 		el(code, { src: fileURL("./components/examples/signals/intro.js"), page_id }), | ||||
| 		 | ||||
|  | ||||
| 		el(h3, t`Introducing signals`), | ||||
| 		el("p").append(...T` | ||||
| 			Let’s re-introduce | ||||
| @@ -62,7 +62,7 @@ export function page({ pkg, info }){ | ||||
| 		`), | ||||
| 		el(example, { src: fileURL("./components/examples/signals/signals.js"), page_id }), | ||||
| 		el("p").append(...T` | ||||
| 			All this is just an example of  | ||||
| 			All this is just an example of | ||||
| 			${el("a", { textContent: t`Event-driven programming`, ...references.wiki_event_driven })} and | ||||
| 			${el("a", { textContent: t`Publish–subscribe pattern`, ...references.wiki_pubsub })} (compare for example | ||||
| 			with ${el("a", { textContent: t`fpubsub library`, ...references.fpubsub })}). All three parts can be in | ||||
| @@ -109,8 +109,8 @@ export function page({ pkg, info }){ | ||||
| 		el("p").append(...T` | ||||
| 			To derived attribute based on value of signal variable just use the signal as a value of the attribute | ||||
| 			(${el("code", "assign(element, { attribute: S('value') })")}). ${el("code", "assign")}/${el("code", "el")} | ||||
| 			 provides ways to glue reactive attributes/classes more granularly into the DOM. Just use dedicated build-in | ||||
| 			 attributes ${el("code", "dataset")}, ${el("code", "ariaset")} and ${el("code", "classList")}. | ||||
| 			provides ways to glue reactive attributes/classes more granularly into the DOM. Just use dedicated build-in | ||||
| 			attributes ${el("code", "dataset")}, ${el("code", "ariaset")} and ${el("code", "classList")}. | ||||
| 		`), | ||||
| 		el("p").append(...T` | ||||
| 			For computation, you can use the “derived signal” (see above) like | ||||
|   | ||||
| @@ -36,7 +36,7 @@ export function page({ pkg, info }){ | ||||
| 		`), | ||||
| 		el(code, { src: fileURL("./components/examples/scopes/intro.js"), page_id }), | ||||
| 		el("p").append(...T`The library therefore use ${el("em", t`scopes`)} to provide these functionalities.`), | ||||
| 		 | ||||
|  | ||||
| 		el(h3, t`Scopes and hosts`), | ||||
| 		el("p").append(...T` | ||||
| 			The ${el("strong", "host")} is the name for the element representing the component. This is typically | ||||
|   | ||||
| @@ -21,7 +21,7 @@ const references= { | ||||
| 	/** observedAttributes on MDN */ | ||||
| 	mdn_observedAttributes: { | ||||
| 		title: t`MDN documentation page for observedAttributes`, | ||||
| 		href: "https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#responding_to_attribute_changes", | ||||
| 		href: "https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#responding_to_attribute_changes", // editorconfig-checker-disable-line | ||||
| 	}, | ||||
| 	/** Custom Elements on MDN */ | ||||
| 	mdn_custom_elements: { | ||||
| @@ -55,10 +55,10 @@ export function page({ pkg, info }){ | ||||
| 	return el(simplePage, { info, pkg }).append( | ||||
| 		el("h2", t`Using web components in combinantion with DDE`), | ||||
| 		el("p").append(...T` | ||||
| 			The DDE library allows for use within ${el("a", references.mdn_web_components).append( el("strong", t`Web Components`) )} | ||||
| 			for dom-tree generation. However, in order to be able to use signals (possibly mapping to registered | ||||
| 			${el("a", references.mdn_observedAttributes).append( el("code", "observedAttributes") )}) and additional | ||||
| 			functionality is (unfortunately) required to use helpers provided by the library. | ||||
| 			The DDE library allows for use within ${el("a", references.mdn_web_components).append( el("strong", | ||||
| 			t`Web Components`) )} for dom-tree generation. However, in order to be able to use signals (possibly | ||||
| 			mapping to registered ${el("a", references.mdn_observedAttributes).append( el("code", "observedAttributes") | ||||
| 			)}) and additional functionality is (unfortunately) required to use helpers provided by the library. | ||||
| 		`), | ||||
| 		el(code, { src: fileURL("./components/examples/customElement/intro.js"), page_id }), | ||||
|  | ||||
| @@ -82,8 +82,8 @@ export function page({ pkg, info }){ | ||||
| 		`), | ||||
| 		el("p").append(...T` | ||||
| 			Also see the Life Cycle Events sections, very similarly we would like to use | ||||
| 			${el("a", { textContent: t`DDE events`, href: "./p03-events.html", title: t`See events part of the library documentation` })}. | ||||
| 			To do it, the library provides function ${el("code", "customElementWithDDE")}… | ||||
| 			${el("a", { textContent: t`DDE events`, href: "./p03-events.html", title: t`See events part of the library | ||||
| 			documentation` })}. To do it, the library provides function ${el("code", "customElementWithDDE")}… | ||||
| 		`), | ||||
| 		el(example, { src: fileURL("./components/examples/customElement/customElementWithDDE.js"), page_id }), | ||||
|  | ||||
|   | ||||
| @@ -21,7 +21,8 @@ export function thirdParty(){ | ||||
| 	}); | ||||
| 	// Array.from((new URL(location)).searchParams.entries()) | ||||
| 	// 	.forEach(([ key, value ])=> S.action(store, "set", key, value)); | ||||
| 	// S.on(store, data=> history.replaceState("", "", "?"+(new URLSearchParams(JSON.parse(JSON.stringify(data)))).toString())); | ||||
| 	// S.on(store, data=> history.replaceState("", "", | ||||
| 	// "?"+(new URLSearchParams(JSON.parse(JSON.stringify(data)))).toString())); | ||||
| 	useStore(store_adapter, { | ||||
| 		onread(data){ | ||||
| 			Array.from(data.entries()) | ||||
|   | ||||
| @@ -15,6 +15,7 @@ export function fullNameComponent(){ | ||||
| 		on.disconnected(()=> console.log(fullNameComponent)) | ||||
| 	); | ||||
|  | ||||
| 	const style= { height: "80px", display: "block", fill: "currentColor" }; | ||||
| 	const elSVG= elNS("http://www.w3.org/2000/svg"); | ||||
| 	return el("div", { className }).append( | ||||
| 		el("h2", "Simple form:"), | ||||
| @@ -29,7 +30,7 @@ export function fullNameComponent(){ | ||||
| 			": ", | ||||
| 			el("#text", full_name) | ||||
| 		), | ||||
| 		elSVG("svg", { viewBox: "0 0 240 80", style: { height: "80px", display: "block" } }).append( | ||||
| 		elSVG("svg", { viewBox: "0 0 240 80", style }).append( | ||||
| 			//elSVG("style", {  }) | ||||
| 			elSVG("text", { x: 20, y: 35, textContent: "Text" }), | ||||
| 		) | ||||
|   | ||||
| @@ -17,22 +17,25 @@ const className= style.host(todosComponent).css` | ||||
| /** @param {{ todos: string[] }} */ | ||||
| export function todosComponent({ todos= [ "Task A" ] }= {}){ | ||||
| 	let key= 0; | ||||
| 	const todosO= S(new Map(), { | ||||
| 	const todosO= S( /** @type {Map<number, ddeSignal<string>>} */ (new Map()), { | ||||
| 		/** @param {string} v */ | ||||
| 		add(v){ this.value.set(key++, S(v)); }, | ||||
| 		/** @param {number} key */ | ||||
| 		remove(key){ S.clear(this.value.get(key)); this.value.delete(key); } | ||||
| 	}); | ||||
| 	todos.forEach(text=> S.action(todosO, "add", text)); | ||||
|  | ||||
| 	const name= "todoName"; | ||||
| 	const onsubmitAdd= on("submit", event=> { | ||||
| 		const el= event.target.elements[name]; | ||||
| 		const el_form= /** @type {HTMLFormElement} */ (event.target); | ||||
| 		const el= /** @type {HTMLInputElement} */ (el_form.elements[name]); | ||||
| 		event.preventDefault(); | ||||
| 		S.action(todosO, "add", el.value); | ||||
| 		el.value= ""; | ||||
| 	}); | ||||
| 	const onremove= on("remove", event=> | ||||
| 		S.action(todosO, "remove", event.detail)); | ||||
| 	 | ||||
| 	const onremove= on("remove", /** @param {CustomEvent<number>} event */ | ||||
| 		event=> S.action(todosO, "remove", event.detail)); | ||||
|  | ||||
| 	return el("div", { className }).append( | ||||
| 		el("div").append( | ||||
| 			el("h2", "Todos:"), | ||||
| @@ -60,19 +63,24 @@ export function todosComponent({ todos= [ "Task A" ] }= {}){ | ||||
| 	) | ||||
| } | ||||
| /** | ||||
|  * @param {{ textContent: ddeSignal<string>, value: ddeSignal<number> }} attrs | ||||
|  * @dispatchs {number} remove | ||||
|  * */ | ||||
| function todoComponent({ textContent, value }){ | ||||
| 	const { host }= scope; | ||||
| 	const dispatchRemove= /** @type {(data: number) => void} */ | ||||
| 		(dispatchEvent("remove", null, host)); | ||||
| 	const onclick= on("click", event=> { | ||||
| 		const value= Number(event.target.value); | ||||
| 		const el= /** @type {HTMLButtonElement} */ (event.target); | ||||
| 		const value= Number(el.value); | ||||
| 		event.preventDefault(); | ||||
| 		event.stopPropagation(); | ||||
| 		dispatchEvent("remove")(host(), value); | ||||
| 		dispatchRemove(value); | ||||
| 	}); | ||||
| 	const is_editable= S(false); | ||||
| 	const onedited= on("change", ev=> { | ||||
| 		textContent(ev.target.value); | ||||
| 		const el= /** @type {HTMLInputElement} */ (ev.target); | ||||
| 		textContent(el.value); | ||||
| 		is_editable(false); | ||||
| 	}); | ||||
| 	return el("li").append( | ||||
|   | ||||
| @@ -38,7 +38,7 @@ export class CustomHTMLTestElement extends HTMLElement{ | ||||
| 		); | ||||
| 	} | ||||
| 	test= "A"; | ||||
| 	 | ||||
|  | ||||
| 	get name(){ return this.getAttribute("name"); } | ||||
| 	set name(value){ this.setAttribute("name", value); } | ||||
| 	/** @attr pre-name */ | ||||
|   | ||||
| @@ -1,4 +1,9 @@ | ||||
| import { style, el, S } from './exports.js'; | ||||
| style.css` | ||||
| :root{ | ||||
| 	color-scheme: dark light; | ||||
| } | ||||
| `; | ||||
| document.head.append(style.element); | ||||
| import { fullNameComponent } from './components/fullNameComponent.js'; | ||||
| import { todosComponent } from './components/todosComponent.js'; | ||||
|   | ||||
							
								
								
									
										83
									
								
								index.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										83
									
								
								index.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -2,10 +2,10 @@ declare global{ /* ddeSignal */ } | ||||
|  | ||||
| type CustomElementTagNameMap= { '#text': Text, '#comment': Comment } | ||||
| type SupportedElement= | ||||
| 	  HTMLElementTagNameMap[keyof HTMLElementTagNameMap] | ||||
| 	| SVGElementTagNameMap[keyof SVGElementTagNameMap] | ||||
| 	| MathMLElementTagNameMap[keyof MathMLElementTagNameMap] | ||||
| 	| CustomElementTagNameMap[keyof CustomElementTagNameMap] | ||||
| 		HTMLElementTagNameMap[keyof HTMLElementTagNameMap] | ||||
| 	|	SVGElementTagNameMap[keyof SVGElementTagNameMap] | ||||
| 	|	MathMLElementTagNameMap[keyof MathMLElementTagNameMap] | ||||
| 	|	CustomElementTagNameMap[keyof CustomElementTagNameMap] | ||||
| declare global { | ||||
| 	type ddeComponentAttributes= Record<any, any> | undefined; | ||||
| 	type ddeElementAddon<El extends SupportedElement | DocumentFragment>= (element: El)=> El | void; | ||||
| @@ -15,9 +15,12 @@ type AttrsModified= { | ||||
| 	/** | ||||
| 	 * Use string like in HTML (internally uses `*.setAttribute("style", *)`), or object representation (like DOM API). | ||||
| 	 */ | ||||
| 	style: string | Partial<CSSStyleDeclaration> | ddeSignal<string> | Partial<{ [K in keyof CSSStyleDeclaration]: ddeSignal<CSSStyleDeclaration[K]> }> | ||||
| 	style: string | Partial<CSSStyleDeclaration> | ddeSignal<string> | ||||
| 		| Partial<{ [K in keyof CSSStyleDeclaration]: ddeSignal<CSSStyleDeclaration[K]> }> | ||||
| 	/** | ||||
| 	 * Provide option to add/remove/toggle CSS clasess (index of object) using 1/0/-1. In fact `el.classList.toggle(class_name)` for `-1` and `el.classList.toggle(class_name, Boolean(...))` for others. | ||||
| 	 * Provide option to add/remove/toggle CSS clasess (index of object) using 1/0/-1. | ||||
| 	 * In fact `el.classList.toggle(class_name)` for `-1` and `el.classList.toggle(class_name, Boolean(...))` | ||||
| 	 * for others. | ||||
| 	 */ | ||||
| 	classList: Record<string,-1|0|1|boolean|ddeSignal<-1|0|1|boolean>>, | ||||
| 	/** | ||||
| @@ -28,20 +31,32 @@ type AttrsModified= { | ||||
| 	 * Sets `aria-*` simiraly to `dataset` | ||||
| 	 * */ | ||||
| 	ariaset: Record<string,string|ddeSignal<string>>, | ||||
| } & Record<`=${string}` | `data${PascalCase}` | `aria${PascalCase}`, string|ddeSignal<string>> & Record<`.${string}`, any> | ||||
| }	& Record<`=${string}` | `data${PascalCase}` | `aria${PascalCase}`, string|ddeSignal<string>> | ||||
| 	& Record<`.${string}`, any> | ||||
| type _fromElsInterfaces<EL extends SupportedElement>= Omit<EL, keyof AttrsModified>; | ||||
| /** | ||||
|  * Just element attributtes | ||||
|  * | ||||
|  * In most cases, you can use native propertie such as [MDN WEB/API/Element](https://developer.mozilla.org/en-US/docs/Web/API/Element) and so on (e.g. [`Text`](https://developer.mozilla.org/en-US/docs/Web/API/Text)). | ||||
|  * In most cases, you can use native propertie such as | ||||
|  * [MDN WEB/API/Element](https://developer.mozilla.org/en-US/docs/Web/API/Element) and so on | ||||
|  * (e.g. [`Text`](https://developer.mozilla.org/en-US/docs/Web/API/Text)). | ||||
|  * | ||||
|  * There is added support for `data[A-Z].*`/`aria[A-Z].*` to be converted to the kebab-case alternatives. | ||||
|  * @private | ||||
|  */ | ||||
| type ElementAttributes<T extends SupportedElement>= Partial<{ [K in keyof _fromElsInterfaces<T>]: _fromElsInterfaces<T>[K] | ddeSignal<_fromElsInterfaces<T>[K]> } & AttrsModified> & Record<string, any>; | ||||
| export function classListDeclarative<El extends SupportedElement>(element: El, classList: AttrsModified["classList"]): El | ||||
| type ElementAttributes<T extends SupportedElement>= Partial<{ | ||||
| 	[K in keyof _fromElsInterfaces<T>]: _fromElsInterfaces<T>[K] | ddeSignal<_fromElsInterfaces<T>[K]> | ||||
| } & AttrsModified> & Record<string, any>; | ||||
| export function classListDeclarative<El extends SupportedElement>( | ||||
| 	element: El, | ||||
| 	classList: AttrsModified["classList"] | ||||
| ): El | ||||
| export function assign<El extends SupportedElement>(element: El, ...attrs_array: ElementAttributes<El>[]): El | ||||
| export function assignAttribute<El extends SupportedElement, ATT extends keyof ElementAttributes<El>>(element: El, attr: ATT, value: ElementAttributes<El>[ATT]): ElementAttributes<El>[ATT] | ||||
| export function assignAttribute<El extends SupportedElement, ATT extends keyof ElementAttributes<El>>( | ||||
| 	element: El, | ||||
| 	attr: ATT, | ||||
| 	value: ElementAttributes<El>[ATT] | ||||
| ): ElementAttributes<El>[ATT] | ||||
|  | ||||
| type ExtendedHTMLElementTagNameMap= HTMLElementTagNameMap & CustomElementTagNameMap; | ||||
| type textContent= string | ddeSignal<string>; | ||||
| @@ -68,7 +83,9 @@ export function el< | ||||
| 	component: C, | ||||
| 	attrs?: Parameters<C>[0] | textContent, | ||||
| 	...addons: ddeElementAddon<ReturnType<C>>[] | ||||
| ): ReturnType<C> extends ddeHTMLElementTagNameMap[keyof ddeHTMLElementTagNameMap] ? ReturnType<C> : ( ReturnType<C> extends ddeDocumentFragment ? ReturnType<C> : ddeHTMLElement ) | ||||
| ): ReturnType<C> extends ddeHTMLElementTagNameMap[keyof ddeHTMLElementTagNameMap] | ||||
| 	? ReturnType<C> | ||||
| 	: ( ReturnType<C> extends ddeDocumentFragment ? ReturnType<C> : ddeHTMLElement ) | ||||
| export { el as createElement } | ||||
|  | ||||
| export function elNS( | ||||
| @@ -88,7 +105,9 @@ export function elNS( | ||||
| 	EL extends ( TAG extends keyof MathMLElementTagNameMap ? MathMLElementTagNameMap[TAG] : MathMLElement ), | ||||
| >( | ||||
| 	tag_name: TAG, | ||||
| 	attrs?: string | textContent | Partial<{ [key in keyof EL]: EL[key] | ddeSignal<EL[key]> | string | number | boolean }>, | ||||
| 	attrs?: string | textContent | Partial<{ | ||||
| 		[key in keyof EL]: EL[key] | ddeSignal<EL[key]> | string | number | boolean | ||||
| 	}>, | ||||
| 	...addons: ddeElementAddon<EL>[] | ||||
| )=> ddeMathMLElement | ||||
| export function elNS( | ||||
| @@ -106,18 +125,27 @@ export function chainableAppend<EL extends SupportedElement>(el: EL): EL; | ||||
|  * */ | ||||
| type simulateSlotsMapper= (body: HTMLSlotElement, el: HTMLElement)=> void; | ||||
| /** Simulate slots for ddeComponents */ | ||||
| export function simulateSlots<EL extends SupportedElement | DocumentFragment>(root: EL, mapper?: simulateSlotsMapper): EL | ||||
| export function simulateSlots<EL extends SupportedElement | DocumentFragment>( | ||||
| 	root: EL, | ||||
| 	mapper?: simulateSlotsMapper | ||||
| ): EL | ||||
| /** | ||||
|  * Simulate slots in Custom Elements without using `shadowRoot`. | ||||
|  * @param el Custom Element root element | ||||
|  * @param body Body of the custom element | ||||
|  * */ | ||||
| export function simulateSlots<EL extends SupportedElement | DocumentFragment>(el: HTMLElement, body: EL, mapper?: simulateSlotsMapper): EL | ||||
| export function simulateSlots<EL extends SupportedElement | DocumentFragment>( | ||||
| 	el: HTMLElement, | ||||
| 	body: EL, mapper?: simulateSlotsMapper | ||||
| ): EL | ||||
|  | ||||
| export function dispatchEvent(name: keyof DocumentEventMap | string, options?: EventInit): | ||||
| 	(element: SupportedElement, data?: any)=> void; | ||||
| export function dispatchEvent(name: keyof DocumentEventMap | string, options: EventInit | null, element: SupportedElement | (()=> SupportedElement)): | ||||
| 	(data?: any)=> void; | ||||
| export function dispatchEvent( | ||||
| 	name: keyof DocumentEventMap | string, | ||||
| 	options: EventInit | null, | ||||
| 	element: SupportedElement | (()=> SupportedElement) | ||||
| ): (data?: any)=> void; | ||||
| interface On{ | ||||
| 	/** Listens to the DOM event. See {@link Document.addEventListener} */ | ||||
| 	< | ||||
| @@ -135,7 +163,7 @@ interface On{ | ||||
| 			listener: (this: El, 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 */ | ||||
| 	/** 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 ) | ||||
| @@ -143,7 +171,7 @@ interface On{ | ||||
| 			listener: (this: El, event: CustomEvent<El>) => any, | ||||
| 			options?: AddEventListenerOptions | ||||
| 		) : EE; | ||||
| 	/** 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 */ | ||||
| 	/** 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 ) | ||||
| @@ -151,7 +179,7 @@ interface On{ | ||||
| 			listener: (this: El, event: CustomEvent<void>) => any, | ||||
| 			options?: AddEventListenerOptions | ||||
| 		) : EE; | ||||
| 	/** 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 */ | ||||
| 	/** 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 ) | ||||
| @@ -162,7 +190,12 @@ interface On{ | ||||
| } | ||||
| export const on: On; | ||||
|  | ||||
| type Scope= { scope: Node | Function | Object, host: ddeElementAddon<any>, custom_element: false | HTMLElement, prevent: boolean } | ||||
| type Scope= { | ||||
| 	scope: Node | Function | Object, | ||||
| 	host: ddeElementAddon<any>, | ||||
| 	custom_element: false | HTMLElement, | ||||
| 	prevent: boolean | ||||
| }; | ||||
| /** Current scope created last time the `el(Function)` was invoke. (Or {@link scope.push}) */ | ||||
| export const scope: { | ||||
| 	current: Scope, | ||||
| @@ -176,7 +209,7 @@ export const scope: { | ||||
| 	 * — `scope.host(on.connected(console.log))`. | ||||
| 	 * */ | ||||
| 	host: (...addons: ddeElementAddon<SupportedElement>[])=> HTMLElement, | ||||
| 	 | ||||
|  | ||||
| 	state: Scope[], | ||||
| 	/** Adds new child scope. All attributes are inherited by default. */ | ||||
| 	push(scope: Partial<Scope>): ReturnType<Array<Scope>["push"]>, | ||||
| @@ -202,12 +235,12 @@ export function observedAttributes(custom_element: HTMLElement): Record<string, | ||||
| /* TypeScript MEH */ | ||||
| declare global{ | ||||
| 	type ddeAppend<el>= (...nodes: (Node | string)[])=> el; | ||||
| 	 | ||||
|  | ||||
| 	interface ddeDocumentFragment extends DocumentFragment{ append: ddeAppend<ddeDocumentFragment>; } | ||||
| 	interface ddeHTMLElement extends HTMLElement{ append: ddeAppend<ddeHTMLElement>; } | ||||
| 	interface ddeSVGElement extends SVGElement{ append: ddeAppend<ddeSVGElement>; } | ||||
| 	interface ddeMathMLElement extends MathMLElement{ append: ddeAppend<ddeMathMLElement>; } | ||||
| 	 | ||||
|  | ||||
| 	interface ddeHTMLElementTagNameMap { | ||||
| 		"a": ddeHTMLAnchorElement; | ||||
| 		"area": ddeHTMLAreaElement; | ||||
| @@ -350,6 +383,7 @@ declare global{ | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // editorconfig-checker-disable | ||||
| interface ddeHTMLAnchorElement extends HTMLAnchorElement{ append: ddeAppend<ddeHTMLAnchorElement>; } | ||||
| interface ddeHTMLAreaElement extends HTMLAreaElement{ append: ddeAppend<ddeHTMLAreaElement>; } | ||||
| interface ddeHTMLAudioElement extends HTMLAudioElement{ append: ddeAppend<ddeHTMLAudioElement>; } | ||||
| @@ -477,3 +511,4 @@ interface ddeSVGTitleElement extends SVGTitleElement{ append: ddeAppend<ddeSVGTi | ||||
| interface ddeSVGTSpanElement extends SVGTSpanElement{ append: ddeAppend<ddeSVGTSpanElement>; } | ||||
| interface ddeSVGUseElement extends SVGUseElement{ append: ddeAppend<ddeSVGUseElement>; } | ||||
| interface ddeSVGViewElement extends SVGViewElement{ append: ddeAppend<ddeSVGViewElement>; } | ||||
| // editorconfig-checker-enable | ||||
|   | ||||
							
								
								
									
										2
									
								
								jsdom.js
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								jsdom.js
									
									
									
									
									
								
							| @@ -29,7 +29,7 @@ export function register(dom){ | ||||
| export function unregister(){ | ||||
| 	if(!dom_last) | ||||
| 		return false; | ||||
| 	 | ||||
|  | ||||
| 	Object.assign(env, env_bk); | ||||
| 	env_bk= {}; | ||||
| 	dom_last= undefined; | ||||
|   | ||||
							
								
								
									
										19
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										19
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -11,6 +11,7 @@ | ||||
| 			"devDependencies": { | ||||
| 				"@size-limit/preset-small-lib": "~11.0", | ||||
| 				"dts-bundler": "~0.1", | ||||
| 				"editorconfig-checker": "^6.0.0", | ||||
| 				"esbuild": "~0.24", | ||||
| 				"jsdom": "~25.0", | ||||
| 				"jshint": "~2.13", | ||||
| @@ -1424,6 +1425,24 @@ | ||||
| 				"typescript": "^2.4.0" | ||||
| 			} | ||||
| 		}, | ||||
| 		"node_modules/editorconfig-checker": { | ||||
| 			"version": "6.0.0", | ||||
| 			"resolved": "https://registry.npmjs.org/editorconfig-checker/-/editorconfig-checker-6.0.0.tgz", | ||||
| 			"integrity": "sha512-uyTOwLJzR/k7ugiu7ITjCzkLKBhXeirQZ8hGlUkt1u/hq2Qu1E8EslgFZDN+lxZoQc97eiI87sUFgVILK4P+YQ==", | ||||
| 			"dev": true, | ||||
| 			"license": "MIT", | ||||
| 			"bin": { | ||||
| 				"ec": "dist/index.js", | ||||
| 				"editorconfig-checker": "dist/index.js" | ||||
| 			}, | ||||
| 			"engines": { | ||||
| 				"node": ">=20.11.0" | ||||
| 			}, | ||||
| 			"funding": { | ||||
| 				"type": "buymeacoffee", | ||||
| 				"url": "https://www.buymeacoffee.com/mstruebing" | ||||
| 			} | ||||
| 		}, | ||||
| 		"node_modules/emoji-regex": { | ||||
| 			"version": "8.0.0", | ||||
| 			"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", | ||||
|   | ||||
| @@ -83,9 +83,7 @@ | ||||
| 	"modifyEsbuildConfig": { | ||||
| 		"platform": "browser" | ||||
| 	}, | ||||
| 	"scripts": { | ||||
| 		"test": "echo \"Error: no test specified\" && exit 1" | ||||
| 	}, | ||||
| 	"scripts": {}, | ||||
| 	"keywords": [ | ||||
| 		"dom", | ||||
| 		"javascript", | ||||
| @@ -95,6 +93,7 @@ | ||||
| 	"devDependencies": { | ||||
| 		"@size-limit/preset-small-lib": "~11.0", | ||||
| 		"dts-bundler": "~0.1", | ||||
| 		"editorconfig-checker": "~6.0", | ||||
| 		"esbuild": "~0.24", | ||||
| 		"jsdom": "~25.0", | ||||
| 		"jshint": "~2.13", | ||||
|   | ||||
							
								
								
									
										2
									
								
								signals.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								signals.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -55,7 +55,7 @@ interface signal{ | ||||
| 	 * */ | ||||
| 	el<S extends any>(signal: Signal<S, any>, el: (v: S)=> Element | Element[] | DocumentFragment): DocumentFragment; | ||||
|  | ||||
|     observedAttributes(custom_element: HTMLElement): Record<string, Signal<string, {}>>; | ||||
| 	observedAttributes(custom_element: HTMLElement): Record<string, Signal<string, {}>>; | ||||
| } | ||||
| export const signal: signal; | ||||
| export const S: signal; | ||||
|   | ||||
| @@ -13,11 +13,11 @@ function setDeleteAttr(obj, prop, val){ | ||||
| 		For some native attrs you can unset only to set empty string. | ||||
| 		This can be confusing as it is seen in inspector `<… id=""`. | ||||
| 		Options: | ||||
| 		 1. Leave it, as it is native behaviour | ||||
| 		 2. Sets as empty string and removes the corresponding attribute when also has empty string | ||||
| 		*3. Sets as undefined and removes the corresponding attribute when "undefined" string discovered | ||||
| 		 4. Point 2. with checks for coincidence (e.g. use special string) | ||||
| 		*/ | ||||
| 			1. Leave it, as it is native behaviour | ||||
| 			2. Sets as empty string and removes the corresponding attribute when also has empty string | ||||
| 			3. (*) Sets as undefined and removes the corresponding attribute when "undefined" string discovered | ||||
| 			4. Point 2. with checks for coincidence (e.g. use special string) | ||||
| 	*/ | ||||
| 	Reflect.set(obj, prop, val); | ||||
| 	if(!isUndef(val)) return; | ||||
| 	Reflect.deleteProperty(obj, prop); | ||||
|   | ||||
							
								
								
									
										35
									
								
								src/dom.js
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								src/dom.js
									
									
									
									
									
								
							| @@ -10,13 +10,13 @@ const scopes= [ { | ||||
| export const scope= { | ||||
| 	get current(){ return scopes[scopes.length-1]; }, | ||||
| 	get host(){ return this.current.host; }, | ||||
| 	 | ||||
|  | ||||
| 	preventDefault(){ | ||||
| 		const { current }= this; | ||||
| 		current.prevent= true; | ||||
| 		return current; | ||||
| 	}, | ||||
| 	 | ||||
|  | ||||
| 	get state(){ return [ ...scopes ]; }, | ||||
| 	push(s= {}){ return scopes.push(Object.assign({}, this.current, { prevent: false }, s)); }, | ||||
| 	pushRoot(){ return scopes.push(scopes[0]); }, | ||||
| @@ -25,9 +25,11 @@ export const scope= { | ||||
| 		return scopes.pop(); | ||||
| 	}, | ||||
| }; | ||||
| // following chainableAppend implementation is OK as the ElementPrototype.append description already is { writable: true, enumerable: true, configurable: true } | ||||
| // following chainableAppend implementation is OK as the ElementPrototype.append description already is { writable: true, enumerable: true, configurable: true } // editorconfig-checker-disable-line | ||||
| function append(...els){ this.appendOriginal(...els); return this; } | ||||
| export function chainableAppend(el){ if(el.append===append) return el; el.appendOriginal= el.append; el.append= append; return el; } | ||||
| export function chainableAppend(el){ | ||||
| 	if(el.append===append) return el; el.appendOriginal= el.append; el.append= append; return el; | ||||
| } | ||||
| let namespace; | ||||
| export function createElement(tag, attributes, ...addons){ | ||||
| 	/* jshint maxcomplexity: 15 */ | ||||
| @@ -40,7 +42,9 @@ export function createElement(tag, attributes, ...addons){ | ||||
| 	switch(true){ | ||||
| 		case typeof tag==="function": { | ||||
| 			scoped= 1; | ||||
| 			scope.push({ scope: tag, host: (...c)=> c.length ? (scoped===1 ? addons.unshift(...c) : c.forEach(c=> c(el_host)), undefined) : el_host }); | ||||
| 			const host= (...c)=> !c.length ? el_host : | ||||
| 				(scoped===1 ? addons.unshift(...c) : c.forEach(c=> c(el_host)), undefined); | ||||
| 			scope.push({ scope: tag, host }); | ||||
| 			el= tag(attributes || undefined); | ||||
| 			const is_fragment= el instanceof env.F; | ||||
| 			if(el.nodeName==="#comment") break; | ||||
| @@ -108,7 +112,9 @@ export function simulateSlots(element, root, mapper){ | ||||
| } | ||||
| function simulateSlotReplace(slot, element, mapper){ | ||||
| 	if(mapper) mapper(slot, element); | ||||
| 	try{ slot.replaceWith(assign(element, { className: [ element.className, slot.className ], dataset: { ...slot.dataset } })); } | ||||
| 	try{ slot.replaceWith(assign(element, { | ||||
| 		className: [ element.className, slot.className ], | ||||
| 		dataset: { ...slot.dataset } })); } | ||||
| 	catch(_){ slot.replaceWith(element); } | ||||
| } | ||||
| /** | ||||
| @@ -141,7 +147,7 @@ const { setDeleteAttr }= env; | ||||
| export function assign(element, ...attributes){ | ||||
| 	if(!attributes.length) return element; | ||||
| 	assign_context.set(element, assignContext(element, this)); | ||||
| 	 | ||||
|  | ||||
| 	for(const [ key, value ] of Object.entries(Object.assign({}, ...attributes))) | ||||
| 		assignAttribute.call(this, element, key, value); | ||||
| 	assign_context.delete(element); | ||||
| @@ -150,7 +156,7 @@ export function assign(element, ...attributes){ | ||||
| export function assignAttribute(element, key, value){ | ||||
| 	const { setRemoveAttr, s }= assignContext(element, this); | ||||
| 	const _this= this; | ||||
| 	 | ||||
|  | ||||
| 	value= s.processReactiveAttribute(element, key, value, | ||||
| 		(key, value)=> assignAttribute.call(_this, element, key, value)); | ||||
| 	const [ k ]= key; | ||||
| @@ -216,7 +222,9 @@ function getPropDescriptor(p, key){ | ||||
| 	return des; | ||||
| } | ||||
|  | ||||
| /** @template {Record<any, any>} T @param {object} s @param {T} obj @param {(param: [ keyof T, T[keyof T] ])=> void} cb */ | ||||
| /** | ||||
|  * @template {Record<any, any>} T @param {object} s @param {T} obj @param {(param: [ keyof T, T[keyof T] ])=> void} cb | ||||
|  * */ | ||||
| function forEachEntries(s, obj, cb){ | ||||
| 	if(typeof obj !== "object" || obj===null) return; | ||||
| 	return Object.entries(obj).forEach(function process([ key, val ]){ | ||||
| @@ -227,6 +235,9 @@ function forEachEntries(s, obj, cb){ | ||||
| } | ||||
|  | ||||
| function attrArrToStr(attr){ return Array.isArray(attr) ? attr.filter(Boolean).join(" ") : attr; } | ||||
| function setRemove(obj, prop, key, val){ return obj[ (isUndef(val) ? "remove" : "set") + prop ](key, attrArrToStr(val)); } | ||||
| function setRemoveNS(obj, prop, key, val, ns= null){ return obj[ (isUndef(val) ? "remove" : "set") + prop + "NS" ](ns, key, attrArrToStr(val)); } | ||||
| function setDelete(obj, key, val){ Reflect.set(obj, key, val); if(!isUndef(val)) return; return Reflect.deleteProperty(obj, key); } | ||||
| function setRemove(obj, prop, key, val){ | ||||
| 	return obj[ (isUndef(val) ? "remove" : "set") + prop ](key, attrArrToStr(val)); } | ||||
| function setRemoveNS(obj, prop, key, val, ns= null){ | ||||
| 	return obj[ (isUndef(val) ? "remove" : "set") + prop + "NS" ](ns, key, attrArrToStr(val)); } | ||||
| function setDelete(obj, key, val){ | ||||
| 	Reflect.set(obj, key, val); if(!isUndef(val)) return; return Reflect.deleteProperty(obj, key); } | ||||
|   | ||||
| @@ -103,10 +103,10 @@ function connectionsChangesObserverConstructor(){ | ||||
| 		for(const element of addedNodes){ | ||||
| 			if(is_root) collectChildren(element).then(observerAdded); | ||||
| 			if(!store.has(element)) continue; | ||||
| 			 | ||||
|  | ||||
| 			const ls= store.get(element); | ||||
| 			if(!ls.length_c) continue; | ||||
| 			 | ||||
|  | ||||
| 			element.dispatchEvent(new Event(evc)); | ||||
| 			ls.connected= new WeakSet(); | ||||
| 			ls.length_c= 0; | ||||
| @@ -120,7 +120,7 @@ function connectionsChangesObserverConstructor(){ | ||||
| 		for(const element of removedNodes){ | ||||
| 			if(is_root) collectChildren(element).then(observerRemoved); | ||||
| 			if(!store.has(element)) continue; | ||||
| 			 | ||||
|  | ||||
| 			const ls= store.get(element); | ||||
| 			if(!ls.length_d) continue; | ||||
| 			(globalThis.queueMicrotask || setTimeout)(dispatchRemove(element)); | ||||
|   | ||||
| @@ -64,9 +64,9 @@ on.attributeChanged= function(listener, options){ | ||||
| 		element.addEventListener(eva, listener, options); | ||||
| 		if(element[keyLTE] || els_attribute_store.has(element)) | ||||
| 			return element; | ||||
| 		 | ||||
|  | ||||
| 		if(!env.M) return element; | ||||
| 		 | ||||
|  | ||||
| 		const observer= new env.M(function(mutations){ | ||||
| 			for(const { attributeName, target } of mutations) | ||||
| 				target.dispatchEvent( | ||||
| @@ -77,4 +77,4 @@ on.attributeChanged= function(listener, options){ | ||||
| 		//TODO: clean up when element disconnected | ||||
| 		return element; | ||||
| 	}; | ||||
| };	 | ||||
| }; | ||||
|   | ||||
| @@ -21,7 +21,7 @@ export function signal(value, actions){ | ||||
| 	if(typeof value!=="function") | ||||
| 		return create(false, value, actions); | ||||
| 	if(isSignal(value)) return value; | ||||
| 	 | ||||
|  | ||||
| 	const out= create(true); | ||||
| 	const contextReWatch= function(){ | ||||
| 		const [ origin, ...deps_old ]= deps.get(contextReWatch); | ||||
| @@ -77,11 +77,11 @@ signal.clear= function(...signals){ | ||||
| 		o.listeners.forEach(l=> { | ||||
| 			o.listeners.delete(l); | ||||
| 			if(!deps.has(l)) return; | ||||
| 			 | ||||
|  | ||||
| 			const ls= deps.get(l); | ||||
| 			ls.delete(s); | ||||
| 			if(ls.size>1) return; | ||||
| 			 | ||||
|  | ||||
| 			s.clear(...ls); | ||||
| 			deps.delete(l); | ||||
| 		}); | ||||
|   | ||||
| @@ -21,7 +21,7 @@ export function signal(value, actions){ | ||||
| 	if(typeof value!=="function") | ||||
| 		return create(false, value, actions); | ||||
| 	if(isSignal(value)) return value; | ||||
| 	 | ||||
|  | ||||
| 	const out= create(true); | ||||
| 	const contextReWatch= function(){ | ||||
| 		const [ origin, ...deps_old ]= deps.get(contextReWatch); | ||||
| @@ -77,11 +77,11 @@ signal.clear= function(...signals){ | ||||
| 		o.listeners.forEach(l=> { | ||||
| 			o.listeners.delete(l); | ||||
| 			if(!deps.has(l)) return; | ||||
| 			 | ||||
|  | ||||
| 			const ls= deps.get(l); | ||||
| 			ls.delete(s); | ||||
| 			if(ls.size>1) return; | ||||
| 			 | ||||
|  | ||||
| 			s.clear(...ls); | ||||
| 			deps.delete(l); | ||||
| 		}); | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| { | ||||
|   "compilerOptions": { | ||||
|     "emitDeclarationOnly": true, | ||||
|     "declaration": true, | ||||
| 	"declarationDir": "dist" | ||||
|   } | ||||
| 	"compilerOptions": { | ||||
| 		"emitDeclarationOnly": true, | ||||
| 		"declaration": true, | ||||
| 		"declarationDir": "dist" | ||||
| 	} | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user