mirror of
https://github.com/jaandrle/deka-dom-el
synced 2025-07-01 04:12:14 +02:00
🐛 📺 v0.9.5-alpha (#44)
* ⚡ 📺 package (version and publint) * 🔤 docs typos * 🐛 this address / fixes #43 * ⚡ tiny el optimalization * 🔤 improve docs wording * 🔤 case-studies/products.js (AbortSignal) * 🔤 🐛 case-studies/image-gallery.js
This commit is contained in:
@ -82,10 +82,10 @@ export function ImageGallery(images= imagesSample) {
|
||||
closeLightbox();
|
||||
break;
|
||||
case 'ArrowLeft':
|
||||
document.querySelector('.lightbox-prev-btn').click();
|
||||
onPrevImage(e);
|
||||
break;
|
||||
case 'ArrowRight':
|
||||
document.querySelector('.lightbox-next-btn').click();
|
||||
onNextImage(e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -126,12 +126,12 @@ export function ImageGallery(images= imagesSample) {
|
||||
el("div", {
|
||||
className: "gallery-item",
|
||||
dataTag: image.alt.toLowerCase()
|
||||
}).append(
|
||||
}, onImageClick(image.id)).append(
|
||||
el("img", {
|
||||
src: image.src,
|
||||
alt: image.alt,
|
||||
loading: "lazy"
|
||||
}, onImageClick(image.id)),
|
||||
}),
|
||||
el("div", { className: "gallery-item-caption" }).append(
|
||||
el("h3", image.title),
|
||||
el("p", image.alt)
|
||||
@ -146,41 +146,41 @@ export function ImageGallery(images= imagesSample) {
|
||||
S.el(isLightboxOpen, open => !open
|
||||
? el()
|
||||
: el("div", { className: "lightbox-overlay" }, on("click", closeLightbox)).append(
|
||||
el("div", {
|
||||
className: "lightbox-content",
|
||||
onClick: e => e.stopPropagation() // Prevent closing when clicking inside
|
||||
}).append(
|
||||
el("button", {
|
||||
className: "lightbox-close-btn",
|
||||
"aria-label": "Close lightbox"
|
||||
}, on("click", closeLightbox)).append("×"),
|
||||
el("div", {
|
||||
className: "lightbox-content",
|
||||
onClick: e => e.stopPropagation() // Prevent closing when clicking inside
|
||||
}).append(
|
||||
el("button", {
|
||||
className: "lightbox-close-btn",
|
||||
ariaLabel: "Close lightbox",
|
||||
}, on("click", closeLightbox)).append("×"),
|
||||
|
||||
el("button", {
|
||||
className: "lightbox-prev-btn",
|
||||
"aria-label": "Previous image"
|
||||
}, on("click", onPrevImage)).append("❮"),
|
||||
el("button", {
|
||||
className: "lightbox-prev-btn",
|
||||
ariaLabel: "Previous image",
|
||||
}, on("click", onPrevImage)).append("❮"),
|
||||
|
||||
el("button", {
|
||||
className: "lightbox-next-btn",
|
||||
"aria-label": "Next image"
|
||||
}, on("click", onNextImage)).append("❯"),
|
||||
el("button", {
|
||||
className: "lightbox-next-btn",
|
||||
ariaLabel: "Next image",
|
||||
}, on("click", onNextImage)).append("❯"),
|
||||
|
||||
S.el(selectedImage, img => !img
|
||||
? el()
|
||||
: el("div", { className: "lightbox-image-container" }).append(
|
||||
el("img", {
|
||||
src: img.src,
|
||||
alt: img.alt,
|
||||
className: "lightbox-image"
|
||||
}),
|
||||
el("div", { className: "lightbox-caption" }).append(
|
||||
el("h2", img.title),
|
||||
el("p", img.alt)
|
||||
)
|
||||
)
|
||||
S.el(selectedImage, img => !img
|
||||
? el()
|
||||
: el("div", { className: "lightbox-image-container" }).append(
|
||||
el("img", {
|
||||
src: img.src,
|
||||
alt: img.alt,
|
||||
className: "lightbox-image",
|
||||
}),
|
||||
el("div", { className: "lightbox-caption" }).append(
|
||||
el("h2", img.title),
|
||||
el("p", img.alt),
|
||||
),
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -1,9 +1,13 @@
|
||||
import { el, on } from "deka-dom-el";
|
||||
import { el, on, scope } from "deka-dom-el";
|
||||
import { S } from "deka-dom-el/signals";
|
||||
|
||||
export function ProductCatalog() {
|
||||
const { signal }= scope;
|
||||
|
||||
const itemsPerPage = 5;
|
||||
const products = asyncSignal(S, fetchProducts, { initial: [], keepLast: true });
|
||||
const products = asyncSignal(S,
|
||||
fetchProducts,
|
||||
{ initial: [], keepLast: true, signal });
|
||||
const searchTerm = S("");
|
||||
const handleSearch = (e) => searchTerm.set(e.target.value);
|
||||
const sortOrder = S("default");
|
||||
@ -220,10 +224,14 @@ function simulateNetworkDelay(min = 300, max = 1200) {
|
||||
* @template T
|
||||
* @param {typeof S} S - Signal constructor
|
||||
* @param {(params: { signal: AbortSignal }) => Promise<T>} invoker - Async function to execute
|
||||
* @param {{ initial?: T, keepLast?: boolean }} options - Configuration options
|
||||
* @param {{ initial?: T, keepLast?: boolean, signal?: AbortSignal }} options - Configuration options
|
||||
* @returns {Object} Status signals and control methods
|
||||
*/
|
||||
export function asyncSignal(S, invoker, { initial, keepLast } = {}) {
|
||||
export function asyncSignal(S, invoker, { initial, keepLast, signal } = {}) {
|
||||
/** @type {(s: AbortSignal) => AbortSignal} */
|
||||
const anySignal = !signal || !AbortSignal.any // TODO: make better
|
||||
? s=> s
|
||||
: s=> AbortSignal.any([s, signal]);
|
||||
// Status tracking signals
|
||||
const status = S("pending");
|
||||
const result = S(initial);
|
||||
@ -242,7 +250,7 @@ export function asyncSignal(S, invoker, { initial, keepLast } = {}) {
|
||||
|
||||
try {
|
||||
const data = await invoker({
|
||||
signal: controller.signal,
|
||||
signal: anySignal(controller.signal),
|
||||
});
|
||||
if (!controller.signal.aborted) {
|
||||
status.set("resolved");
|
||||
|
Reference in New Issue
Block a user