mirror of
				https://github.com/jaandrle/deka-dom-el
				synced 2025-10-30 21:49:14 +01:00 
			
		
		
		
	Compare commits
	
		
			4 Commits
		
	
	
		
			3301a6600c
			...
			330f702409
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 330f702409 | |||
| 2f57f115a0 | |||
| d1b017c1a1 | |||
| 992370b4e3 | 
							
								
								
									
										43
									
								
								dist/esm-with-signals.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										43
									
								
								dist/esm-with-signals.js
									
									
									
									
										vendored
									
									
								
							| @@ -41,19 +41,6 @@ function observedAttributes(instance, observedAttribute2) { | ||||
| function kebabToCamel(name) { | ||||
| 	return name.replace(/-./g, (x) => x[1].toUpperCase()); | ||||
| } | ||||
| var Defined = class extends Error { | ||||
| 	constructor() { | ||||
| 		super(); | ||||
| 		const [curr, ...rest] = this.stack.split("\n"); | ||||
| 		const curr_file = curr.slice(curr.indexOf("@"), curr.indexOf(".js:") + 4); | ||||
| 		const curr_lib = curr_file.includes("src/helpers.js") ? "src/" : curr_file; | ||||
| 		this.stack = rest.find((l) => !l.includes(curr_lib)) || curr; | ||||
| 	} | ||||
| 	get compact() { | ||||
| 		const { stack } = this; | ||||
| 		return stack.slice(0, stack.indexOf("@") + 1) + "\u2026" + stack.slice(stack.lastIndexOf("/")); | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| // src/dom-lib/common.js | ||||
| var enviroment = { | ||||
| @@ -303,7 +290,7 @@ var store_abort = /* @__PURE__ */ new WeakMap(); | ||||
| var scope = { | ||||
| 	/** | ||||
| 	* Gets the current scope | ||||
| 	* @returns {Object} Current scope context | ||||
| 	* @returns {typeof scopes[number]} Current scope context | ||||
| 	*/ | ||||
| 	get current() { | ||||
| 		return scopes[scopes.length - 1]; | ||||
| @@ -663,9 +650,9 @@ function memo(key, generator) { | ||||
| memo.isScope = function(obj) { | ||||
| 	return obj[memoMark]; | ||||
| }; | ||||
| memo.scope = function memoScope(fun, { signal: signal2, onlyLast } = {}) { | ||||
| memo.scope = function memoScopeCreate(fun, { signal: signal2, onlyLast } = {}) { | ||||
| 	let cache = oCreate(); | ||||
| 	function memoScope2(...args) { | ||||
| 	function memoScope(...args) { | ||||
| 		if (signal2 && signal2.aborted) | ||||
| 			return fun.apply(this, args); | ||||
| 		let cache_local = onlyLast ? cache : oCreate(); | ||||
| @@ -680,10 +667,10 @@ memo.scope = function memoScope(fun, { signal: signal2, onlyLast } = {}) { | ||||
| 		cache = cache_local; | ||||
| 		return out; | ||||
| 	} | ||||
| 	memoScope2[memoMark] = true; | ||||
| 	memoScope2.clear = () => cache = oCreate(); | ||||
| 	if (signal2) signal2.addEventListener("abort", memoScope2.clear); | ||||
| 	return memoScope2; | ||||
| 	memoScope[memoMark] = true; | ||||
| 	memoScope.clear = () => cache = oCreate(); | ||||
| 	if (signal2) signal2.addEventListener("abort", memoScope.clear); | ||||
| 	return memoScope; | ||||
| }; | ||||
|  | ||||
| // src/signals-lib/helpers.js | ||||
| @@ -800,17 +787,17 @@ signal.clear = function(...signals2) { | ||||
| }; | ||||
| var key_reactive = "__dde_reactive"; | ||||
| signal.el = function(s, map) { | ||||
| 	map = memo.isScope(map) ? map : memo.scope(map, { onlyLast: true }); | ||||
| 	const mark_start = createElement.mark({ type: "reactive", source: new Defined().compact }, true); | ||||
| 	const mapScoped = memo.isScope(map) ? map : memo.scope(map, { onlyLast: true }); | ||||
| 	const { current } = scope, { scope: sc } = current; | ||||
| 	const mark_start = createElement.mark({ type: "reactive", component: sc && sc.name || "" }, true); | ||||
| 	const mark_end = mark_start.end; | ||||
| 	const out = enviroment.D.createDocumentFragment(); | ||||
| 	out.append(mark_start, mark_end); | ||||
| 	const { current } = scope; | ||||
| 	const reRenderReactiveElement = (v) => { | ||||
| 		if (!mark_start.parentNode || !mark_end.parentNode) | ||||
| 			return removeSignalListener(s, reRenderReactiveElement); | ||||
| 		scope.push(current); | ||||
| 		let els = map(v); | ||||
| 		let els = mapScoped(v); | ||||
| 		scope.pop(); | ||||
| 		if (!Array.isArray(els)) | ||||
| 			els = [els]; | ||||
| @@ -830,7 +817,7 @@ signal.el = function(s, map) { | ||||
| 	current.host(on.disconnected( | ||||
| 		() => ( | ||||
| 			/*! Clears cached elements for reactive element `S.el` */ | ||||
| 			map.clear() | ||||
| 			mapScoped.clear() | ||||
| 		) | ||||
| 	)); | ||||
| 	return out; | ||||
| @@ -902,9 +889,8 @@ var signals_config = { | ||||
| function removeSignalsFromElements(s, listener, ...notes) { | ||||
| 	const { current } = scope; | ||||
| 	current.host(function(element) { | ||||
| 		if (element[key_reactive]) | ||||
| 			return element[key_reactive].push([[s, listener], ...notes]); | ||||
| 		element[key_reactive] = []; | ||||
| 		if (!element[key_reactive]) element[key_reactive] = []; | ||||
| 		element[key_reactive].push([[s, listener], ...notes]); | ||||
| 		if (current.prevent) return; | ||||
| 		on.disconnected( | ||||
| 			() => ( | ||||
| @@ -949,7 +935,6 @@ function toSignal(s, value, actions, readonly = false) { | ||||
| 			onclear, | ||||
| 			host, | ||||
| 			listeners: /* @__PURE__ */ new Set(), | ||||
| 			defined: new Defined().stack, | ||||
| 			readonly | ||||
| 		}), | ||||
| 		enumerable: false, | ||||
|   | ||||
							
								
								
									
										7
									
								
								dist/esm-with-signals.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								dist/esm-with-signals.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										14
									
								
								dist/esm.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								dist/esm.js
									
									
									
									
										vendored
									
									
								
							| @@ -274,7 +274,7 @@ var store_abort = /* @__PURE__ */ new WeakMap(); | ||||
| var scope = { | ||||
| 	/** | ||||
| 	* Gets the current scope | ||||
| 	* @returns {Object} Current scope context | ||||
| 	* @returns {typeof scopes[number]} Current scope context | ||||
| 	*/ | ||||
| 	get current() { | ||||
| 		return scopes[scopes.length - 1]; | ||||
| @@ -634,9 +634,9 @@ function memo(key, generator) { | ||||
| memo.isScope = function(obj) { | ||||
| 	return obj[memoMark]; | ||||
| }; | ||||
| memo.scope = function memoScope(fun, { signal, onlyLast } = {}) { | ||||
| memo.scope = function memoScopeCreate(fun, { signal, onlyLast } = {}) { | ||||
| 	let cache = oCreate(); | ||||
| 	function memoScope2(...args) { | ||||
| 	function memoScope(...args) { | ||||
| 		if (signal && signal.aborted) | ||||
| 			return fun.apply(this, args); | ||||
| 		let cache_local = onlyLast ? cache : oCreate(); | ||||
| @@ -651,10 +651,10 @@ memo.scope = function memoScope(fun, { signal, onlyLast } = {}) { | ||||
| 		cache = cache_local; | ||||
| 		return out; | ||||
| 	} | ||||
| 	memoScope2[memoMark] = true; | ||||
| 	memoScope2.clear = () => cache = oCreate(); | ||||
| 	if (signal) signal.addEventListener("abort", memoScope2.clear); | ||||
| 	return memoScope2; | ||||
| 	memoScope[memoMark] = true; | ||||
| 	memoScope.clear = () => cache = oCreate(); | ||||
| 	if (signal) signal.addEventListener("abort", memoScope.clear); | ||||
| 	return memoScope; | ||||
| }; | ||||
| export { | ||||
| 	assign, | ||||
|   | ||||
							
								
								
									
										2
									
								
								dist/esm.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/esm.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										43
									
								
								dist/iife-with-signals.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										43
									
								
								dist/iife-with-signals.js
									
									
									
									
										vendored
									
									
								
							| @@ -86,19 +86,6 @@ var DDE = (() => { | ||||
| 	function kebabToCamel(name) { | ||||
| 		return name.replace(/-./g, (x) => x[1].toUpperCase()); | ||||
| 	} | ||||
| 	var Defined = class extends Error { | ||||
| 		constructor() { | ||||
| 			super(); | ||||
| 			const [curr, ...rest] = this.stack.split("\n"); | ||||
| 			const curr_file = curr.slice(curr.indexOf("@"), curr.indexOf(".js:") + 4); | ||||
| 			const curr_lib = curr_file.includes("src/helpers.js") ? "src/" : curr_file; | ||||
| 			this.stack = rest.find((l) => !l.includes(curr_lib)) || curr; | ||||
| 		} | ||||
| 		get compact() { | ||||
| 			const { stack } = this; | ||||
| 			return stack.slice(0, stack.indexOf("@") + 1) + "\u2026" + stack.slice(stack.lastIndexOf("/")); | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| 	// src/dom-lib/common.js | ||||
| 	var enviroment = { | ||||
| @@ -348,7 +335,7 @@ var DDE = (() => { | ||||
| 	var scope = { | ||||
| 		/** | ||||
| 		* Gets the current scope | ||||
| 		* @returns {Object} Current scope context | ||||
| 		* @returns {typeof scopes[number]} Current scope context | ||||
| 		*/ | ||||
| 		get current() { | ||||
| 			return scopes[scopes.length - 1]; | ||||
| @@ -708,9 +695,9 @@ var DDE = (() => { | ||||
| 	memo.isScope = function(obj) { | ||||
| 		return obj[memoMark]; | ||||
| 	}; | ||||
| 	memo.scope = function memoScope(fun, { signal: signal2, onlyLast } = {}) { | ||||
| 	memo.scope = function memoScopeCreate(fun, { signal: signal2, onlyLast } = {}) { | ||||
| 		let cache = oCreate(); | ||||
| 		function memoScope2(...args) { | ||||
| 		function memoScope(...args) { | ||||
| 			if (signal2 && signal2.aborted) | ||||
| 				return fun.apply(this, args); | ||||
| 			let cache_local = onlyLast ? cache : oCreate(); | ||||
| @@ -725,10 +712,10 @@ var DDE = (() => { | ||||
| 			cache = cache_local; | ||||
| 			return out; | ||||
| 		} | ||||
| 		memoScope2[memoMark] = true; | ||||
| 		memoScope2.clear = () => cache = oCreate(); | ||||
| 		if (signal2) signal2.addEventListener("abort", memoScope2.clear); | ||||
| 		return memoScope2; | ||||
| 		memoScope[memoMark] = true; | ||||
| 		memoScope.clear = () => cache = oCreate(); | ||||
| 		if (signal2) signal2.addEventListener("abort", memoScope.clear); | ||||
| 		return memoScope; | ||||
| 	}; | ||||
|  | ||||
| 	// src/signals-lib/helpers.js | ||||
| @@ -845,17 +832,17 @@ var DDE = (() => { | ||||
| 	}; | ||||
| 	var key_reactive = "__dde_reactive"; | ||||
| 	signal.el = function(s, map) { | ||||
| 		map = memo.isScope(map) ? map : memo.scope(map, { onlyLast: true }); | ||||
| 		const mark_start = createElement.mark({ type: "reactive", source: new Defined().compact }, true); | ||||
| 		const mapScoped = memo.isScope(map) ? map : memo.scope(map, { onlyLast: true }); | ||||
| 		const { current } = scope, { scope: sc } = current; | ||||
| 		const mark_start = createElement.mark({ type: "reactive", component: sc && sc.name || "" }, true); | ||||
| 		const mark_end = mark_start.end; | ||||
| 		const out = enviroment.D.createDocumentFragment(); | ||||
| 		out.append(mark_start, mark_end); | ||||
| 		const { current } = scope; | ||||
| 		const reRenderReactiveElement = (v) => { | ||||
| 			if (!mark_start.parentNode || !mark_end.parentNode) | ||||
| 				return removeSignalListener(s, reRenderReactiveElement); | ||||
| 			scope.push(current); | ||||
| 			let els = map(v); | ||||
| 			let els = mapScoped(v); | ||||
| 			scope.pop(); | ||||
| 			if (!Array.isArray(els)) | ||||
| 				els = [els]; | ||||
| @@ -875,7 +862,7 @@ var DDE = (() => { | ||||
| 		current.host(on.disconnected( | ||||
| 			() => ( | ||||
| 				/*! Clears cached elements for reactive element `S.el` */ | ||||
| 				map.clear() | ||||
| 				mapScoped.clear() | ||||
| 			) | ||||
| 		)); | ||||
| 		return out; | ||||
| @@ -947,9 +934,8 @@ var DDE = (() => { | ||||
| 	function removeSignalsFromElements(s, listener, ...notes) { | ||||
| 		const { current } = scope; | ||||
| 		current.host(function(element) { | ||||
| 			if (element[key_reactive]) | ||||
| 				return element[key_reactive].push([[s, listener], ...notes]); | ||||
| 			element[key_reactive] = []; | ||||
| 			if (!element[key_reactive]) element[key_reactive] = []; | ||||
| 			element[key_reactive].push([[s, listener], ...notes]); | ||||
| 			if (current.prevent) return; | ||||
| 			on.disconnected( | ||||
| 				() => ( | ||||
| @@ -994,7 +980,6 @@ var DDE = (() => { | ||||
| 				onclear, | ||||
| 				host, | ||||
| 				listeners: /* @__PURE__ */ new Set(), | ||||
| 				defined: new Defined().stack, | ||||
| 				readonly | ||||
| 			}), | ||||
| 			enumerable: false, | ||||
|   | ||||
							
								
								
									
										7
									
								
								dist/iife-with-signals.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								dist/iife-with-signals.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										14
									
								
								dist/iife.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								dist/iife.js
									
									
									
									
										vendored
									
									
								
							| @@ -316,7 +316,7 @@ var DDE = (() => { | ||||
| 	var scope = { | ||||
| 		/** | ||||
| 		* Gets the current scope | ||||
| 		* @returns {Object} Current scope context | ||||
| 		* @returns {typeof scopes[number]} Current scope context | ||||
| 		*/ | ||||
| 		get current() { | ||||
| 			return scopes[scopes.length - 1]; | ||||
| @@ -676,9 +676,9 @@ var DDE = (() => { | ||||
| 	memo.isScope = function(obj) { | ||||
| 		return obj[memoMark]; | ||||
| 	}; | ||||
| 	memo.scope = function memoScope(fun, { signal, onlyLast } = {}) { | ||||
| 	memo.scope = function memoScopeCreate(fun, { signal, onlyLast } = {}) { | ||||
| 		let cache = oCreate(); | ||||
| 		function memoScope2(...args) { | ||||
| 		function memoScope(...args) { | ||||
| 			if (signal && signal.aborted) | ||||
| 				return fun.apply(this, args); | ||||
| 			let cache_local = onlyLast ? cache : oCreate(); | ||||
| @@ -693,10 +693,10 @@ var DDE = (() => { | ||||
| 			cache = cache_local; | ||||
| 			return out; | ||||
| 		} | ||||
| 		memoScope2[memoMark] = true; | ||||
| 		memoScope2.clear = () => cache = oCreate(); | ||||
| 		if (signal) signal.addEventListener("abort", memoScope2.clear); | ||||
| 		return memoScope2; | ||||
| 		memoScope[memoMark] = true; | ||||
| 		memoScope.clear = () => cache = oCreate(); | ||||
| 		if (signal) signal.addEventListener("abort", memoScope.clear); | ||||
| 		return memoScope; | ||||
| 	}; | ||||
| 	return __toCommonJS(index_exports); | ||||
| })(); | ||||
|   | ||||
							
								
								
									
										2
									
								
								dist/iife.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/iife.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -23,14 +23,6 @@ export function DataDashboard() { | ||||
| 		conversion: [2.9, 3.5, 3.7, 2.6, 3.4, 3.5, 2.8, 2.8, 2.8, 3.1, 3.0, 2.7], | ||||
| 		months: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] | ||||
| 	}; | ||||
|  | ||||
| 	// Application state | ||||
| 	const selectedYear = S(2024); | ||||
| 	const selectedDataType = S(/** @type {'sales' | 'visitors' | 'conversion'} */ ('sales')); | ||||
| 	const isLoading = S(false); | ||||
| 	const error = S(null); | ||||
|  | ||||
| 	// Filter options | ||||
| 	const years = [2022, 2023, 2024]; | ||||
| 	const dataTypes = [ | ||||
| 		{ id: 'sales', label: 'Sales', unit: 'K' }, | ||||
| @@ -38,42 +30,32 @@ export function DataDashboard() { | ||||
| 		{ id: 'conversion', label: 'Conversion Rate', unit: '%' } | ||||
| 	]; | ||||
|  | ||||
| 	// Computed values | ||||
| 	const selectedData = S(() => { | ||||
| 		return DATA[selectedDataType.get()]; | ||||
| 	}); | ||||
|  | ||||
| 	const currentDataType = S(() => { | ||||
| 		return dataTypes.find(type => type.id === selectedDataType.get()); | ||||
| 	}); | ||||
|  | ||||
| 	const totalValue = S(() => { | ||||
| 		const data = selectedData.get(); | ||||
| 		return data.reduce((sum, value) => sum + value, 0); | ||||
| 	}); | ||||
|  | ||||
| 	const averageValue = S(() => { | ||||
| 		const data = selectedData.get(); | ||||
| 		return data.reduce((sum, value) => sum + value, 0) / data.length; | ||||
| 	}); | ||||
|  | ||||
| 	const highestValue = S(() => { | ||||
| 		return Math.max(...selectedData.get()); | ||||
| 	}); | ||||
|  | ||||
| 	// Event handlers | ||||
| 	// Filter options | ||||
| 	const selectedYear = S(2024); | ||||
| 	const onYearChange = on("change", e => { | ||||
| 		selectedYear.set(parseInt(/** @type {HTMLSelectElement} */(e.target).value)); | ||||
| 		loadData(); | ||||
| 	}); | ||||
|  | ||||
| 	const selectedDataType = S(/** @type {'sales' | 'visitors' | 'conversion'} */ ('sales')); | ||||
| 	const onDataTypeChange = on("click", e => { | ||||
| 		const type = /** @type {'sales' | 'visitors' | 'conversion'} */( | ||||
| 			/** @type {HTMLButtonElement} */(e.currentTarget).dataset.type); | ||||
| 		selectedDataType.set(type); | ||||
| 	}); | ||||
| 	const currentDataType = S(() => dataTypes.find(type => type.id === selectedDataType.get())); | ||||
| 	const selectedData = S(() => DATA[selectedDataType.get()]); | ||||
|  | ||||
| 	// Values based on filters | ||||
| 	const totalValue = S(() => selectedData.get().reduce((sum, value) => sum + value, 0)); | ||||
| 	const averageValue = S(() => { | ||||
| 		const data = selectedData.get(); | ||||
| 		return data.reduce((sum, value) => sum + value, 0) / data.length; | ||||
| 	}); | ||||
| 	const highestValue = S(() => Math.max(...selectedData.get())); | ||||
|  | ||||
| 	// Simulate data loading | ||||
| 	const isLoading = S(false); | ||||
| 	const error = S(null); | ||||
| 	function loadData() { | ||||
| 		isLoading.set(true); | ||||
| 		error.set(null); | ||||
| @@ -114,7 +96,7 @@ export function DataDashboard() { | ||||
| 			// Draw grid labels | ||||
| 			ctx.fillStyle = '#999'; | ||||
| 			ctx.font = '12px Arial'; | ||||
| 			ctx.fillText(Math.round(maxValue * (i / 5)), 20, y + 5); | ||||
| 			ctx.fillText(Math.round(maxValue * (i / 5)).toString(), 20, y + 5); | ||||
| 		} | ||||
| 		ctx.stroke(); | ||||
|  | ||||
| @@ -154,7 +136,6 @@ export function DataDashboard() { | ||||
| 			) | ||||
| 		), | ||||
|  | ||||
| 		// Error message (only shown when there's an error) | ||||
| 		S.el(error, errorMsg => !errorMsg | ||||
| 			? el() | ||||
| 			: el("div", { className: "error-message" }).append( | ||||
| @@ -163,7 +144,6 @@ export function DataDashboard() { | ||||
| 				), | ||||
| 		), | ||||
|  | ||||
| 		// Loading indicator | ||||
| 		S.el(isLoading, loading => !loading | ||||
| 			? el() | ||||
| 			: el("div", { className: "loading-spinner" }) | ||||
|   | ||||
| @@ -27,25 +27,23 @@ const imagesSample = (url=> [ | ||||
|  * @returns {HTMLElement} Gallery element | ||||
|  */ | ||||
| export function ImageGallery(images= imagesSample) { | ||||
|  | ||||
| 	// Application state | ||||
| 	const selectedImageId = S(null); | ||||
| 	const filterTag = S('all'); | ||||
| 	const imagesToDisplay = S(() => { | ||||
| 		const tag = filterTag.get(); | ||||
| 		if (tag === 'all') return images; | ||||
| 		else return images.filter(img => img.alt.toLowerCase() === tag); | ||||
| 	}) | ||||
| 	const onFilterChange = tag => on("click", () => { | ||||
| 		filterTag.set(tag); | ||||
| 	}); | ||||
|  | ||||
| 	// Derived state | ||||
| 	// Lightbox | ||||
| 	const selectedImageId = S(null); | ||||
| 	const selectedImage = S(() => { | ||||
| 		const id = selectedImageId.get(); | ||||
| 		return id ? images.find(img => img.id === id) : null; | ||||
| 	}); | ||||
|  | ||||
| 	const isLightboxOpen = S(() => selectedImage.get() !== null); | ||||
|  | ||||
| 	// Event handlers | ||||
| 	const onImageClick = id => on("click", () => { | ||||
| 		selectedImageId.set(id); | ||||
| 		document.body.style.overflow = 'hidden'; // Prevent scrolling when lightbox is open | ||||
| @@ -76,9 +74,6 @@ export function ImageGallery(images= imagesSample) { | ||||
| 		const nextIndex = (currentIndex + 1) % images.length; | ||||
| 		selectedImageId.set(images[nextIndex].id); | ||||
| 	}; | ||||
| 	const onFilterChange = tag => on("click", () => { | ||||
| 		filterTag.set(tag); | ||||
| 	}); | ||||
|  | ||||
| 	// Keyboard navigation handler | ||||
| 	function handleKeyDown(e) { | ||||
|   | ||||
| @@ -73,8 +73,17 @@ export function Form({ initial }) { | ||||
| 			this.value[key] = value; | ||||
| 		} | ||||
| 	}); | ||||
| 	/** | ||||
| 	 * Event handler for input events | ||||
| 	 * @param {"value"|"checked"} prop | ||||
| 	 * @returns {(ev: Event) => void} | ||||
| 	 * */ | ||||
| 	const onChange= prop => ev => { | ||||
| 		const input = /** @type {HTMLInputElement} */(ev.target); | ||||
| 		S.action(formState, "update", /** @type {keyof FormState} */(input.id), input[prop]); | ||||
| 	}; | ||||
|  | ||||
| 	// Derived signals for validation | ||||
| 	// Form validate state | ||||
| 	const nameValid = S(() => formState.get().name.length >= 3); | ||||
| 	const emailValid = S(() => { | ||||
| 		const email = formState.get().email; | ||||
| @@ -89,8 +98,6 @@ export function Form({ initial }) { | ||||
| 		return password === confirmPassword && confirmPassword !== ''; | ||||
| 	}); | ||||
| 	const termsAgreed = S(() => formState.get().agreedToTerms); | ||||
|  | ||||
| 	// Overall form validity | ||||
| 	const formValid = S(() => | ||||
| 		nameValid.get() && | ||||
| 		emailValid.get() && | ||||
| @@ -99,16 +106,6 @@ export function Form({ initial }) { | ||||
| 		termsAgreed.get() | ||||
| 	); | ||||
|  | ||||
| 	// Event handlers | ||||
| 	/** | ||||
| 	 * Event handler for input events | ||||
| 	 * @param {"value"|"checked"} prop | ||||
| 	 * @returns {(ev: Event) => void} | ||||
| 	 * */ | ||||
| 	const onChange= prop => ev => { | ||||
| 		const input = /** @type {HTMLInputElement} */(ev.target); | ||||
| 		S.action(formState, "update", /** @type {keyof FormState} */(input.id), input[prop]); | ||||
| 	}; | ||||
| 	const dispatcSubmit = dispatchEvent("form:submit", host); | ||||
| 	const onSubmit = on("submit", e => { | ||||
| 		e.preventDefault(); | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| // Example of reactive element marker | ||||
| <!--<dde:mark type="reactive" source="...">--> | ||||
| <!--<dde:mark type="reactive" component="<component-name>">--> | ||||
| <!-- content that updates when signal changes --> | ||||
| <!--</dde:mark>--> | ||||
|   | ||||
| @@ -81,7 +81,6 @@ export function page({ pkg, info }){ | ||||
| 			el("li", t`actions: Custom actions that can be performed on the signal`), | ||||
| 			el("li", t`onclear: Functions to run when the signal is cleared`), | ||||
| 			el("li", t`host: Reference to the host element/scope in which the signal was created`), | ||||
| 			el("li", t`defined: Stack trace information for debugging`), | ||||
| 			el("li", t`readonly: Boolean flag indicating if the signal is read-only`) | ||||
| 		), | ||||
| 		el("p").append(T` | ||||
|   | ||||
							
								
								
									
										4
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -1,12 +1,12 @@ | ||||
| { | ||||
| 	"name": "deka-dom-el", | ||||
| 	"version": "0.9.2-alpha", | ||||
| 	"version": "0.9.3-alpha", | ||||
| 	"lockfileVersion": 3, | ||||
| 	"requires": true, | ||||
| 	"packages": { | ||||
| 		"": { | ||||
| 			"name": "deka-dom-el", | ||||
| 			"version": "0.9.2-alpha", | ||||
| 			"version": "0.9.3-alpha", | ||||
| 			"license": "MIT", | ||||
| 			"devDependencies": { | ||||
| 				"@size-limit/preset-small-lib": "~11.2", | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
| 	"name": "deka-dom-el", | ||||
| 	"version": "0.9.2-alpha", | ||||
| 	"version": "0.9.3-alpha", | ||||
| 	"description": "A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks.", | ||||
| 	"author": "Jan Andrle <andrle.jan@centrum.cz>", | ||||
| 	"license": "MIT", | ||||
|   | ||||
| @@ -19,7 +19,7 @@ const store_abort= new WeakMap(); | ||||
| export const scope= { | ||||
| 	/** | ||||
| 	 * Gets the current scope | ||||
| 	 * @returns {Object} Current scope context | ||||
| 	 * @returns {typeof scopes[number]} Current scope context | ||||
| 	 */ | ||||
| 	get current(){ return scopes[scopes.length-1]; }, | ||||
|  | ||||
|   | ||||
| @@ -68,21 +68,3 @@ export function observedAttributes(instance, observedAttribute){ | ||||
|  * @returns {string} The camelCase string | ||||
|  */ | ||||
| function kebabToCamel(name){ return name.replace(/-./g, x=> x[1].toUpperCase()); } | ||||
|  | ||||
| /** | ||||
|  * Error class for definition tracking | ||||
|  * Shows the correct stack trace for debugging (signal) creation | ||||
|  */ | ||||
| export class Defined extends Error{ | ||||
| 	constructor(){ | ||||
| 		super(); | ||||
| 		const [ curr, ...rest ]= this.stack.split("\n"); | ||||
| 		const curr_file= curr.slice(curr.indexOf("@"), curr.indexOf(".js:")+4); | ||||
| 		const curr_lib= curr_file.includes("src/helpers.js") ? "src/" : curr_file; | ||||
| 		this.stack= rest.find(l=> !l.includes(curr_lib)) || curr; | ||||
| 	} | ||||
| 	get compact(){ | ||||
| 		const { stack }= this; | ||||
| 		return stack.slice(0, stack.indexOf("@")+1)+"…"+stack.slice(stack.lastIndexOf("/")); | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -27,7 +27,7 @@ memo.isScope= function(obj){ return obj[memoMark]; }; | ||||
|  * @param {AbortSignal} options.signal | ||||
|  * @param {boolean} [options.onlyLast=false] | ||||
|  * */ | ||||
| memo.scope= function memoScope(fun, { signal, onlyLast }= {}){ | ||||
| memo.scope= function memoScopeCreate(fun, { signal, onlyLast }= {}){ | ||||
| 	let cache= oCreate(); | ||||
| 	function memoScope(...args){ | ||||
| 		if(signal && signal.aborted) | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import { queueSignalWrite, mark } from "./helpers.js"; | ||||
| export { mark }; | ||||
| import { hasOwn, Defined, oCreate, oAssign } from "../helpers.js"; | ||||
| import { hasOwn, oCreate, oAssign } from "../helpers.js"; | ||||
|  | ||||
| const Signal = oCreate(null, { | ||||
| 	get: { value(){ return read(this); } }, | ||||
| @@ -169,21 +169,21 @@ import { memo } from "../memo.js"; | ||||
|  * Creates a reactive DOM element that re-renders when signal changes | ||||
|  * | ||||
|  * @param {Object} s - Signal object to watch | ||||
|  * @param {Function} map - Function mapping signal value to DOM elements | ||||
|  * @param {Function} mapScoped - Function mapping signal value to DOM elements | ||||
|  * @returns {DocumentFragment} Fragment containing reactive elements | ||||
|  */ | ||||
| signal.el= function(s, map){ | ||||
| 	map= memo.isScope(map) ? map : memo.scope(map, { onlyLast: true }); | ||||
| 	const mark_start= el.mark({ type: "reactive", source: new Defined().compact }, true); | ||||
| 	const mapScoped= memo.isScope(map) ? map : memo.scope(map, { onlyLast: true }); | ||||
| 	const { current }= scope, { scope: sc }= current; | ||||
| 	const mark_start= el.mark({ type: "reactive", component: sc && sc.name || "" }, true); | ||||
| 	const mark_end= mark_start.end; | ||||
| 	const out= env.D.createDocumentFragment(); | ||||
| 	out.append(mark_start, mark_end); | ||||
| 	const { current }= scope; | ||||
| 	const reRenderReactiveElement= v=> { | ||||
| 		if(!mark_start.parentNode || !mark_end.parentNode) // === `isConnected` or wasn’t yet rendered | ||||
| 			return removeSignalListener(s, reRenderReactiveElement); | ||||
| 		scope.push(current); | ||||
| 		let els= map(v); | ||||
| 		let els= mapScoped(v); | ||||
| 		scope.pop(); | ||||
| 		if(!Array.isArray(els)) | ||||
| 			els= [ els ]; | ||||
| @@ -202,7 +202,7 @@ signal.el= function(s, map){ | ||||
| 	reRenderReactiveElement(s.get()); | ||||
| 	current.host(on.disconnected(()=> | ||||
| 		/*! Clears cached elements for reactive element `S.el` */ | ||||
| 		map.clear() | ||||
| 		mapScoped.clear() | ||||
| 	)); | ||||
| 	return out; | ||||
| }; | ||||
| @@ -314,9 +314,8 @@ export const signals_config= { | ||||
| function removeSignalsFromElements(s, listener, ...notes){ | ||||
| 	const { current }= scope; | ||||
| 	current.host(function(element){ | ||||
| 		if(element[key_reactive]) | ||||
| 			return element[key_reactive].push([ [ s, listener ], ...notes ]); | ||||
| 		element[key_reactive]= []; | ||||
| 		if(!element[key_reactive]) element[key_reactive]= []; | ||||
| 		element[key_reactive].push([ [ s, listener ], ...notes ]); | ||||
| 		if(current.prevent) return; // typically document.body, doenst need auto-remove as it should happen on page leave | ||||
| 		on.disconnected(()=> | ||||
| 			/*! Clears all Signals listeners added in the current scope/host (`S.el`, `assign`, …?). | ||||
| @@ -386,7 +385,6 @@ function toSignal(s, value, actions, readonly= false){ | ||||
| 		value: oAssign(oCreate(protoSigal), { | ||||
| 			value, actions, onclear, host, | ||||
| 			listeners: new Set(), | ||||
| 			defined: new Defined().stack, | ||||
| 			readonly | ||||
| 		}), | ||||
| 		enumerable: false, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user