mirror of
https://github.com/Shu-Ying/noname-shuying.git
synced 2026-10-20 22:29:59 +08:00
103 lines
3.9 KiB
JavaScript
103 lines
3.9 KiB
JavaScript
export function mountRelicStrip(root, getRelics, open, createIcon,
|
|
document, window) {
|
|
const strip = document.createElement("div");
|
|
strip.className = "mengsan-hand-relics-shuying";
|
|
strip.setAttribute("aria-label", "持有遗物,长按查看描述");
|
|
const before = root.style.getPropertyValue("--mengsan-relic-space");
|
|
const priority = root.style.getPropertyPriority("--mengsan-relic-space");
|
|
let pending = null, timer = null, signature = null, disposed = false;
|
|
const cancel = () => {
|
|
if (timer !== null) window.clearTimeout(timer);
|
|
pending?.button.classList.remove("is-pressed");
|
|
timer = null;
|
|
pending = null;
|
|
};
|
|
const stop = event => event.stopPropagation();
|
|
const down = event => {
|
|
stop(event);
|
|
cancel();
|
|
const button = event.target.closest?.("button");
|
|
if (!button || !strip.contains(button) || event.button !== 0) return;
|
|
pending = { button, id: event.pointerId,
|
|
x: event.clientX, y: event.clientY };
|
|
button.classList.add("is-pressed");
|
|
timer = window.setTimeout(() => {
|
|
const relic = getRelics().find(item => item.id === button.dataset.relicId);
|
|
cancel();
|
|
if (!disposed && relic) open(relic);
|
|
}, 500);
|
|
};
|
|
const move = event => {
|
|
if (event.pointerId !== pending?.id) return;
|
|
if (Math.hypot(event.clientX - pending.x,
|
|
event.clientY - pending.y) > 8) cancel();
|
|
};
|
|
const up = event => {
|
|
if (event.pointerId === pending?.id) cancel();
|
|
};
|
|
const click = event => {
|
|
stop(event);
|
|
event.preventDefault();
|
|
if (event.detail !== 0) return;
|
|
const button = event.target.closest?.("button");
|
|
const relic = getRelics().find(item => item.id === button?.dataset.relicId);
|
|
if (relic) open(relic);
|
|
};
|
|
const context = event => { stop(event); event.preventDefault(); };
|
|
const listeners = [
|
|
[strip, "pointerdown", down], [strip, "pointermove", stop],
|
|
[strip, "pointerup", stop], [strip, "click", click],
|
|
[strip, "keydown", stop], [strip, "keyup", stop],
|
|
[strip, "contextmenu", context], [strip, "scroll", cancel],
|
|
[strip, "wheel", stop], [strip, "touchstart", stop],
|
|
[strip, "touchmove", stop], [strip, "touchend", stop],
|
|
[window, "pointermove", move, true],
|
|
[window, "pointerup", up, true],
|
|
[window, "pointercancel", up, true], [window, "blur", cancel],
|
|
];
|
|
for (const args of listeners) args[0].addEventListener(...args.slice(1));
|
|
root.appendChild(strip);
|
|
const refresh = () => {
|
|
if (disposed) return;
|
|
const relics = getRelics();
|
|
const next = JSON.stringify(relics.map(item => [item.id, item.image, item.name]));
|
|
if (next === signature) return;
|
|
signature = next;
|
|
cancel();
|
|
strip.replaceChildren();
|
|
strip.hidden = relics.length === 0;
|
|
root.style.setProperty("--mengsan-relic-space", relics.length ? "88px" : "0px");
|
|
for (const relic of relics) {
|
|
const button = document.createElement("button");
|
|
button.type = "button";
|
|
button.dataset.relicId = relic.id;
|
|
button.setAttribute("aria-label", `${relic.name},长按查看描述`);
|
|
button.setAttribute("aria-haspopup", "dialog");
|
|
const fallback = document.createElement("span");
|
|
fallback.textContent = relic.name;
|
|
const icon = createIcon(relic.image);
|
|
if (icon) {
|
|
fallback.hidden = true;
|
|
icon.addEventListener("error", () => { fallback.hidden = false; },
|
|
{ once: true });
|
|
button.appendChild(icon);
|
|
}
|
|
button.appendChild(fallback);
|
|
strip.appendChild(button);
|
|
}
|
|
};
|
|
refresh();
|
|
return { refresh, dispose() {
|
|
if (disposed) return;
|
|
disposed = true;
|
|
cancel();
|
|
for (const args of listeners) args[0].removeEventListener(...args.slice(1));
|
|
strip.remove();
|
|
const value = root.style.getPropertyValue("--mengsan-relic-space");
|
|
if (value === "88px" || value === "0px") {
|
|
if (before) root.style.setProperty("--mengsan-relic-space", before, priority);
|
|
else root.style.removeProperty("--mengsan-relic-space");
|
|
}
|
|
} };
|
|
}
|