wave-roll
Version:
JavaScript Library for Comparative MIDI Piano-Roll Visualization
531 lines (530 loc) • 28.5 kB
JavaScript
import { D as q, t as B, O as U, r as _, P as O, a as K, b as Y } from "./index-C4TFo-hd.js";
function V(t = "multi-midi-settings-modal") {
const r = document.getElementById(t);
if (r)
return {
overlay: r,
modal: r.firstElementChild
};
const p = document.createElement("div");
p.id = t, p.style.cssText = `
position: fixed;
inset: 0;
background: rgba(0,0,0,0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 2000;
`;
const o = document.createElement("div");
return o.style.cssText = `
width: 600px;
max-width: 95%;
max-height: 80vh;
overflow-y: auto;
background: var(--panel-bg);
border-radius: 12px;
padding: 24px;
display: flex;
flex-direction: column;
gap: 24px;
`, p.appendChild(o), { overlay: p, modal: o };
}
function J(t, r) {
const p = document.createElement("div");
p.style.cssText = "display:flex;justify-content:space-between;align-items:center;";
const o = document.createElement("h2");
o.textContent = t, o.style.cssText = "margin:0;font-size:20px;font-weight:700;color:var(--text-primary);";
const C = document.createElement("button");
return C.textContent = "✕", C.style.cssText = "border:none;background:transparent;font-size:24px;cursor:pointer;color:var(--text-muted);", C.onclick = r, p.appendChild(o), p.appendChild(C), p;
}
function Q(t, r, p, o) {
const C = document.getElementById("wr-onset-picker-overlay");
C && C.remove();
const f = document.createElement("div");
f.id = "wr-onset-picker-overlay", f.style.cssText = `
position: fixed; inset: 0; z-index: 3000; background: transparent;
`;
const l = document.createElement("div");
l.setAttribute("role", "dialog"), l.setAttribute("aria-label", "Onset marker picker"), l.style.cssText = `
position: absolute; min-width: 240px; max-width: 420px;
background: var(--surface); border: 1px solid var(--ui-border);
border-radius: 8px; box-shadow: 0 8px 24px rgba(0,0,0,0.18);
padding: 10px; display: flex; flex-direction: column; gap: 10px;
`;
function M() {
const E = p.getBoundingClientRect(), S = l.offsetHeight, A = l.offsetWidth, w = window.innerHeight - E.bottom - 8, N = E.top - 8;
let R;
S <= w || w >= N ? R = Math.min(E.bottom + 6, window.innerHeight - S - 8) : R = Math.max(8, E.top - S - 6);
let j = Math.max(8, Math.min(window.innerWidth - A - 8, E.left));
l.style.top = `${Math.round(R)}px`, l.style.left = `${Math.round(j)}px`;
}
const P = document.createElement("div");
P.textContent = "Choose color & marker", P.style.cssText = "font-size:12px;color:var(--text-muted);margin-bottom:2px;";
const { activePaletteId: D, customPalettes: h } = t.midiManager.getState(), a = [...q, ...h].find((d) => d.id === D) || q[0], m = t.midiManager.getState().files.find((d) => d.id === r), e = B(m?.color ?? 0), n = t.stateManager.getOnsetMarkerForFile(r) || t.stateManager.ensureOnsetMarkerForFile(r), u = document.createElement("div");
u.setAttribute("role", "listbox"), u.style.cssText = "display:flex;gap:6px;flex-wrap:wrap;";
const b = [];
let i = e;
const c = () => {
b.forEach((d) => {
const x = (d.dataset.hex || "").toLowerCase() === i.toLowerCase();
d.style.outline = x ? "2px solid var(--focus-ring)" : "none", d.setAttribute("aria-selected", String(x)), d.tabIndex = x ? 0 : -1;
});
};
a.colors.forEach((d, x) => {
const E = B(d), S = document.createElement("button");
S.type = "button", S.dataset.hex = E, S.setAttribute("aria-label", `Select color ${E}`), S.style.cssText = `width:22px;height:22px;border-radius:4px;border:1px solid var(--ui-border);background:${E};cursor:pointer;`, S.onclick = () => {
t.midiManager.updateColor(r, d), i = E, c(), o && o(n, E);
}, x === 0 && (S.tabIndex = 0), b.push(S), u.appendChild(S);
}), c();
const s = document.createElement("div");
s.style.cssText = "height:1px;background:var(--ui-border);margin:2px 0;";
const g = document.createElement("div");
g.style.cssText = "display:flex;flex-direction:column;gap:6px;";
const L = ["filled", "outlined"], y = [];
let T = { ...n };
const F = () => {
y.forEach((d) => {
const x = d.dataset.shape === T.shape && d.dataset.variant === T.variant;
d.style.outline = x ? "2px solid var(--focus-ring)" : "none", d.setAttribute("aria-pressed", String(x)), x && (d.tabIndex = 0);
});
};
L.forEach((d) => {
const x = document.createElement("div");
x.textContent = d === "filled" ? "Filled" : "Outlined", x.style.cssText = "font-size:11px;color:var(--text-muted);";
const E = document.createElement("div");
E.style.cssText = "display:grid;grid-template-columns:repeat(7,28px);gap:6px;", U.forEach((S) => {
const A = { shape: S, variant: d, size: 12, strokeWidth: 2 }, w = document.createElement("button");
w.type = "button", w.setAttribute("aria-label", `${S} ${d}`), w.dataset.shape = String(S), w.dataset.variant = String(d), w.dataset.index = String(y.length), w.style.cssText = "width:28px;height:28px;border:1px solid var(--ui-border);border-radius:6px;background:var(--surface);display:flex;align-items:center;justify-content:center;cursor:pointer;", w.innerHTML = _(A, e, 16), w.onclick = () => {
t.stateManager.setOnsetMarkerForFile(r, A);
const N = t.midiManager.getState().files.find((j) => j.id === r), R = B(N?.color ?? 0);
T = A, F(), o && o(A, R);
}, E.appendChild(w), y.push(w);
}), g.appendChild(x), g.appendChild(E);
}), F();
const z = document.createElement("div");
z.style.cssText = "display:flex;gap:8px;justify-content:flex-end;";
const v = document.createElement("button");
v.type = "button", v.textContent = "Auto assign", v.style.cssText = "padding:4px 8px;border:1px solid var(--ui-border);border-radius:4px;background:var(--surface);cursor:pointer;", v.onclick = () => {
const d = t.stateManager.assignNextUniqueOnsetMarker ? t.stateManager.assignNextUniqueOnsetMarker(r) : t.stateManager.ensureOnsetMarkerForFile(r), x = t.midiManager.getState().files.find((S) => S.id === r), E = B(x?.color ?? 0);
T = d, F(), o && o(d, E);
};
const I = document.createElement("button");
I.type = "button", I.textContent = "Close", I.style.cssText = "padding:4px 8px;border:1px solid var(--ui-border);border-radius:4px;background:var(--surface);cursor:pointer;", I.onclick = () => f.remove(), z.appendChild(v), z.appendChild(I), l.appendChild(P), l.appendChild(u), l.appendChild(s), l.appendChild(g), l.appendChild(z), f.appendChild(l), f.addEventListener("click", (d) => {
d.target === f && f.remove();
}), f.addEventListener("keydown", (d) => {
d.key === "Escape" && f.remove();
}), f.addEventListener("keydown", (d) => {
const x = d, E = x.target;
if (E && E.tagName.toLowerCase() === "button") {
if (E.hasAttribute("data-index")) {
const A = Number(E.getAttribute("data-index") || "0");
let w = A;
if (x.key === "ArrowRight") w = Math.min(y.length - 1, A + 1);
else if (x.key === "ArrowLeft") w = Math.max(0, A - 1);
else if (x.key === "ArrowDown") w = Math.min(y.length - 1, A + 7);
else if (x.key === "ArrowUp") w = Math.max(0, A - 7);
else if (x.key === "Enter" || x.key === " ") {
E.click(), x.preventDefault();
return;
}
w !== A && (x.preventDefault(), y[w]?.focus());
} else if (u.contains(E)) {
const A = b.indexOf(E);
if (A >= 0) {
let w = A;
if (x.key === "ArrowRight") w = Math.min(b.length - 1, A + 1);
else if (x.key === "ArrowLeft") w = Math.max(0, A - 1);
else if (x.key === "Enter" || x.key === " ") {
E.click(), x.preventDefault();
return;
}
w !== A && (x.preventDefault(), b[w]?.focus());
}
}
}
}), document.body.appendChild(f), l.style.visibility = "hidden", requestAnimationFrame(() => {
l.style.visibility = "visible", M();
});
const H = () => M();
window.addEventListener("resize", H), window.addEventListener("scroll", H, { passive: !0 });
const G = () => {
window.removeEventListener("resize", H), window.removeEventListener("scroll", H);
};
f.addEventListener("remove", G), setTimeout(() => {
l.querySelector("button")?.focus?.();
}, 0);
}
function X(t) {
const r = document.createElement("div"), p = document.createElement("h3");
p.textContent = "MIDI Files", p.style.cssText = "margin:0 0 12px;font-size:16px;font-weight:600;", r.appendChild(p);
const o = document.createElement("div");
o.style.cssText = "display:flex;flex-direction:column;gap:8px;", r.appendChild(o);
const C = () => {
o.innerHTML = "";
const f = t.midiManager.getState().files, l = t.permissions?.canRemoveFiles !== !1, M = (a) => {
a.preventDefault();
}, P = (a) => {
a.preventDefault();
const m = parseInt(
a.dataTransfer.getData("text/plain"),
10
);
if (Number.isNaN(m)) return;
const e = f.length - 1;
m !== e && (t.midiManager.reorderFiles(m, e), C());
};
o.removeEventListener("dragover", M), o.removeEventListener("drop", P), o.addEventListener("dragover", M), o.addEventListener("drop", P), f.forEach((a, m) => {
const e = document.createElement("div");
e.style.cssText = "display:flex;align-items:center;gap:8px;background:var(--surface-alt);padding:8px;border-radius:6px;";
const n = document.createElement("span");
n.id = `file-list-handle-${a.id}`, n.draggable = !0, n.innerHTML = O.menu, n.style.cssText = "cursor:grab;color:var(--text-muted);display:flex;align-items:center;justify-content:center;width:18px;user-select:none;";
const u = (v) => {
v.stopPropagation();
}, b = B(a.color), i = document.createElement("div");
i.style.cssText = "position:relative;display:flex;align-items:center;";
const c = document.createElement("button");
c.type = "button", c.title = "Click to change color", c.style.cssText = "width:24px;height:24px;border-radius:4px;border:1px solid var(--ui-border);cursor:pointer;background:transparent;position:relative;padding:0;display:flex;align-items:center;justify-content:center;";
const s = document.createElement("div");
s.style.cssText = "width:18px;height:18px;display:flex;align-items:center;justify-content:center;";
const g = (v, I) => _(v, I, 16), L = t.stateManager.ensureOnsetMarkerForFile(a.id);
s.innerHTML = g(L, b), c.appendChild(s);
const y = document.createElement("input");
y.type = "color", y.value = b, y.style.cssText = "position:absolute;opacity:0;width:0;height:0;border:0;padding:0;", c.onclick = (v) => {
Q(
t,
a.id,
c,
(I, H) => {
s.innerHTML = g(I, H);
}
);
}, y.onchange = (v) => {
const I = v.target.value;
t.midiManager.updateColor(
a.id,
parseInt(I.substring(1), 16)
);
const H = t.stateManager.getOnsetMarkerForFile(a.id) || L;
s.innerHTML = g(H, I);
}, c.appendChild(y), i.appendChild(c);
const T = document.createElement("input");
T.type = "text", T.value = a.name, T.onchange = (v) => {
t.midiManager.updateName(
a.id,
v.target.value
);
}, T.style.cssText = "flex:1;padding:4px 6px;border:1px solid var(--ui-border);border-radius:4px;background:var(--surface);color:var(--text-primary);";
const F = document.createElement("button");
F.setAttribute("aria-label", "Delete MIDI file"), F.innerHTML = O.trash, F.style.cssText = "border:none;background:transparent;cursor:pointer;width:24px;height:24px;display:flex;align-items:center;justify-content:center;color:var(--text-muted);", F.onclick = () => {
l && confirm(`Delete ${a.name}?`) && (t.midiManager.removeMidiFile(a.id), C());
}, e.dataset.index = m.toString(), n.addEventListener("dragstart", (v) => {
v.dataTransfer.effectAllowed = "move", v.dataTransfer.setData(
"text/plain",
(e.dataset.index || "0").toString()
), e.style.opacity = "0.6", n.style.cursor = "grabbing";
}), n.addEventListener("dragend", () => {
e.style.opacity = "1", n.style.cursor = "grab", e.style.outline = "none";
}), e.draggable = !1, [c, T, F].forEach((v) => {
v.addEventListener("mousedown", u), v.addEventListener("touchstart", u);
}), e.addEventListener("dragover", (v) => {
v.preventDefault(), v.stopPropagation(), e.style.outline = "2px dashed var(--focus-ring)";
}), e.addEventListener("dragleave", () => {
e.style.outline = "none";
}), n.addEventListener("dragover", (v) => {
v.preventDefault(), v.stopPropagation(), e.style.outline = "2px dashed var(--focus-ring)";
});
const z = (v) => (I) => {
I.preventDefault(), I.stopPropagation();
const H = parseInt(
I.dataTransfer.getData("text/plain"),
10
);
!Number.isNaN(H) && H !== v && (t.midiManager.reorderFiles(H, v), C()), e.style.outline = "none";
};
e.addEventListener("drop", z(m)), n.addEventListener("drop", z(m)), e.appendChild(n), e.appendChild(i), e.appendChild(T), l && e.appendChild(F), o.appendChild(e);
});
const D = t.permissions?.canAddFiles !== !1, h = document.createElement("button");
h.type = "button", h.textContent = "Add MIDI Files", h.style.cssText = "margin-top:12px;padding:8px;border:1px solid var(--ui-border);border-radius:6px;background:var(--surface);cursor:pointer;font-size:14px;color:var(--text-primary);";
const k = document.createElement("input");
k.type = "file", k.accept = ".mid,.midi", k.multiple = !0, k.style.display = "none", h.onclick = () => {
D && k.click();
}, k.onchange = async (a) => {
if (!D)
return;
const m = Array.from(a.target.files || []);
if (m.length !== 0) {
for (const e of m)
try {
const n = t.stateManager?.getState(), u = n?.visual.pedalElongate ?? !0, b = n?.visual.pedalThreshold ?? 64, i = await K(e, {
applyPedalElongate: u,
pedalThreshold: b
});
t.midiManager.addMidiFile(e.name, i, void 0, e);
} catch (n) {
console.error("Failed to parse MIDI", n);
}
C(), k.value = "";
}
}, D && o.appendChild(h);
};
return C(), typeof t.midiManager.subscribe == "function" && t.midiManager.subscribe(C), r;
}
function W(t, r, p, o = r ? "edit" : "create") {
const { overlay: C, modal: f } = V(
"palette-editor-modal"
);
for (; f.firstChild; ) f.removeChild(f.firstChild);
const l = o === "edit", M = l && r ? r.id : Date.now().toString(), P = o === "clone" && r ? `${r.name} Copy` : r?.name ?? "";
function D() {
if (r) return r.colors;
const c = t.midiManager.getState().files.map((s) => s.color);
return c.filter((s, g) => c.indexOf(s) === g);
}
const h = D().length > 0 ? D().map((c) => B(c)) : [B(0)], k = document.createElement("label");
k.textContent = "Palette name", k.style.cssText = "font-weight:600;font-size:14px;display:block;margin-bottom:4px;";
const a = document.createElement("input");
a.type = "text", a.value = P, a.placeholder = "My palette", a.style.cssText = "width:100%;padding:6px 8px;border:1px solid var(--ui-border);border-radius:6px;margin-bottom:12px;background:var(--surface);color:var(--text-primary);";
const m = document.createElement("div");
m.style.cssText = "display:flex;flex-wrap:wrap;gap:8px;margin-bottom:12px;";
const e = () => {
for (; m.firstChild; ) m.removeChild(m.firstChild);
h.forEach((c, s) => {
const g = document.createElement("div");
g.style.cssText = "display:flex;flex-direction:column;align-items:center;gap:4px;";
const L = document.createElement("button");
L.type = "button", L.title = "Click to change color, right-click to remove", L.style.cssText = `width:32px;height:32px;border-radius:4px;border:1px solid var(--ui-border);background:${c};cursor:pointer;position:relative;`;
const y = document.createElement("input");
y.type = "text", y.maxLength = 7, y.placeholder = "#000000", y.value = c, y.style.cssText = "width:70px;padding:2px 4px;font-size:10px;font-family:monospace;text-align:center;border:1px solid var(--ui-border);border-radius:4px;background:var(--surface);color:var(--text-primary);";
const T = document.createElement("input");
T.type = "color", T.value = c, T.style.cssText = "position:absolute;opacity:0;width:0;height:0;border:0;padding:0;", T.onchange = () => {
h[s] = T.value, L.style.background = T.value, y.value = T.value.replace("#", "");
}, L.onclick = () => T.click(), L.oncontextmenu = (F) => {
F.preventDefault(), h.length > 1 && (h.splice(s, 1), e());
}, L.appendChild(T), y.oninput = () => {
const F = y.value.trim();
/^#[0-9a-fA-F]{0,6}$/.test(F) && F.length === 7 && (h[s] = F, L.style.background = F, T.value = F);
}, g.appendChild(L), g.appendChild(y), m.appendChild(g);
});
};
e();
const n = document.createElement("button");
n.type = "button", n.textContent = "+ Add color", n.style.cssText = "padding:6px 8px;border:1px dashed var(--ui-border);border-radius:6px;background:var(--surface);font-size:12px;cursor:pointer;margin-bottom:16px;color:var(--text-primary);", n.onclick = () => {
h.push("#000000"), e();
};
const u = document.createElement("div");
u.style.cssText = "display:flex;justify-content:flex-end;gap:8px;";
const b = document.createElement("button");
b.type = "button", b.textContent = "Cancel", b.style.cssText = "padding:6px 12px;border:1px solid var(--ui-border);border-radius:6px;background:var(--surface);cursor:pointer;color:var(--text-primary);", b.onclick = () => C.remove();
const i = document.createElement("button");
i.type = "button", i.textContent = l ? "Update" : "Create", i.style.cssText = "padding:6px 12px;border:1px solid var(--accent-strong);border-radius:6px;background:var(--accent-strong);color:var(--on-accent);cursor:pointer;", i.onclick = () => {
const c = a.value.trim();
if (!c) {
alert("Palette name is required");
return;
}
const s = h.map((g) => g.replace("#", "")).filter((g) => /^([0-9a-fA-F]{6})$/.test(g)).map((g) => parseInt(g, 16));
if (s.length === 0) {
alert("At least one valid color is required");
return;
}
l ? t.midiManager.updateCustomPalette(M, {
name: c,
colors: s
}) : t.midiManager.addCustomPalette({
id: M,
name: c,
colors: s
}), C.remove(), p();
}, u.append(b, i), f.append(k, a, m, n, u), document.body.appendChild(C);
}
function $(t) {
const r = document.createElement("div");
r.setAttribute("data-palette-selector", "true");
const p = document.createElement("h3");
p.id = "palette-title", p.textContent = "Color Palette", p.style.cssText = "margin:0 0 12px;font-size:16px;font-weight:600;color:var(--text-primary);";
const o = document.createElement("div");
o.id = "palette-grid", o.style.cssText = "display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:12px;";
const { customPalettes: C, activePaletteId: f } = t.midiManager.getState(), l = [...q, ...C], M = document.createElement("div");
M.style.cssText = "margin-top:12px;padding:8px;border:1px solid var(--ui-border);border-radius:6px;background:var(--surface-alt);display:none;flex-wrap:wrap;gap:12px;align-items:center;";
let P = "";
const D = (e) => {
if (P === e.id) {
M.style.display = "none", M.innerHTML = "", P = "";
return;
}
P = e.id, M.innerHTML = "";
const n = document.createElement("div");
n.style.cssText = "display:flex;gap:4px;flex-wrap:wrap;", e.colors.forEach((s) => {
const g = document.createElement("div");
g.style.cssText = `width:20px;height:20px;border-radius:3px;background:${B(
s
)}`, n.appendChild(g);
});
const u = document.createElement("span");
u.textContent = e.name, u.style.cssText = "font-size:14px;font-weight:600;color:var(--text-primary);";
const b = document.createElement("div");
b.style.cssText = "display:flex;gap:8px;margin-left:auto;";
const i = (s, g, L) => {
const y = document.createElement("button");
return y.type = "button", y.title = g, y.innerHTML = s, y.style.cssText = "width:24px;height:24px;display:flex;align-items:center;justify-content:center;border:none;background:none;cursor:pointer;color:var(--text-muted);", y.onclick = (T) => {
T.stopPropagation(), L();
}, y;
};
b.appendChild(
i(O.duplicate, "Duplicate", () => {
W(
t,
e,
() => {
const s = $(t);
r.replaceWith(s);
},
"clone"
);
})
), C.some((s) => s.id === e.id) && (b.appendChild(
i(O.edit, "Edit", () => {
W(
t,
e,
() => {
const s = $(t);
r.replaceWith(s);
},
"edit"
);
})
), b.appendChild(
i(O.trash, "Delete", () => {
if (confirm(
`Delete palette "${e.name}"? This action cannot be undone.`
)) {
t.midiManager.removeCustomPalette(e.id);
const s = $(t);
r.replaceWith(s);
}
})
)), M.append(n, u, b), M.style.display = "flex";
};
l.forEach((e) => {
const n = document.createElement("button");
n.type = "button", n.style.cssText = `display:flex;flex-direction:column;align-items:center;padding:6px 4px;border:1px solid var(--ui-border);border-radius:6px;cursor:pointer;background:${e.id === f ? "var(--surface-alt)" : "var(--surface)"};transition:background 0.2s;`;
const u = document.createElement("div");
u.style.cssText = "display:flex;gap:2px;margin-bottom:4px;", e.colors.slice(0, 8).forEach((g) => {
const L = document.createElement("div");
L.style.cssText = `width:12px;height:12px;border-radius:2px;background:${B(
g
)}`, u.appendChild(L);
});
const b = document.createElement("span");
b.textContent = e.name, b.style.cssText = "font-size:12px;color:var(--text-muted);";
const i = document.createElement("div");
i.style.cssText = "display:flex;gap:4px;position:absolute;top:4px;right:4px;opacity:0;transition:opacity 0.15s;";
const c = () => i.style.opacity = "1", s = () => i.style.opacity = "0";
n.addEventListener("mouseenter", c), n.addEventListener("mouseleave", s), n.addEventListener("focus", c), n.addEventListener("blur", s), n.onclick = () => {
t.midiManager.getState().activePaletteId !== e.id && t.midiManager.setActivePalette(e.id), [...o.children].forEach(
(g) => g instanceof HTMLElement && (g.style.background = "var(--surface)")
), n.style.background = "var(--surface-alt)", D(e);
}, n.style.position = "relative", n.append(u, b), o.appendChild(n);
});
const h = document.createElement("button");
h.type = "button", h.style.cssText = "display:flex;flex-direction:column;align-items:center;justify-content:center;padding:6px 4px;border:1px dashed var(--ui-border);border-radius:6px;cursor:pointer;background:var(--surface);gap:4px;transition:background 0.2s;";
const k = document.createElement("span");
k.textContent = "+", k.style.cssText = "font-size:20px;line-height:1;color:var(--text-muted);";
const a = document.createElement("span");
a.textContent = "New Palette", a.style.cssText = "font-size:12px;color:var(--text-muted);", h.append(k, a), h.onclick = () => {
W(t, null, () => {
const e = $(t);
r.replaceWith(e);
});
}, o.appendChild(h);
const m = l.find((e) => e.id === f) ?? l[0];
return D(m), r.append(p, o, M), r;
}
function Z(t) {
const r = document.createElement("div"), p = document.createElement("h3");
p.textContent = "WAV File", p.style.cssText = "margin:0 0 12px;font-size:16px;font-weight:600;color:var(--text-primary);", r.appendChild(p);
const o = document.createElement("div");
o.style.cssText = "display:flex;flex-direction:column;gap:8px;", r.appendChild(o);
const C = () => globalThis._waveRollAudio, f = () => {
o.innerHTML = "";
const l = C(), M = l?.getFiles?.() ?? [];
M.forEach((k) => {
const a = document.createElement("div");
a.style.cssText = "display:flex;align-items:center;gap:8px;background:var(--surface-alt);padding:8px;border-radius:6px;border:1px solid var(--ui-border);";
const m = document.createElement("button");
m.type = "button";
const e = `#${(k.color >>> 0).toString(16).padStart(6, "0")}`;
m.style.cssText = `width:20px;height:20px;border-radius:3px;border:1px solid var(--ui-border);background:${e};cursor:pointer;position:relative;padding:0;`;
const n = document.createElement("input");
n.type = "color", n.value = e, n.style.cssText = "position:absolute;opacity:0;width:0;height:0;border:0;padding:0;", n.addEventListener("change", () => {
const i = n.value, c = parseInt(i.replace("#", ""), 16);
l?.updateColor?.(k.id, c), m.style.background = i;
}), m.addEventListener("click", () => n.click()), m.appendChild(n);
const u = document.createElement("input");
if (u.type = "text", u.value = k.name, u.style.cssText = "flex:1;padding:4px 6px;border:1px solid var(--ui-border);border-radius:4px;background:var(--surface);color:var(--text-primary);", u.addEventListener("change", () => {
l?.updateName?.(k.id, u.value.trim());
}), a.appendChild(m), a.appendChild(u), t.permissions?.canRemoveFiles !== !1) {
const i = document.createElement("button");
i.type = "button", i.innerHTML = O.trash, i.style.cssText = "width:24px;height:24px;padding:0;border:none;background:transparent;cursor:pointer;display:flex;align-items:center;justify-content:center;color:var(--text-muted);opacity:0.7;", i.title = "Remove audio file", i.addEventListener("mouseenter", () => {
i.style.opacity = "1", i.style.color = "var(--danger, #dc3545)";
}), i.addEventListener("mouseleave", () => {
i.style.opacity = "0.7", i.style.color = "var(--text-muted)";
}), i.addEventListener("click", () => {
l?.remove?.(k.id);
try {
t.audioPlayer?.pause?.();
} catch {
}
f();
const c = document.querySelector('[data-role="file-toggle"]');
if (c) {
const s = window.FileToggleManager;
s && s.updateFileToggleSection(c, t);
}
}), a.appendChild(i);
}
o.appendChild(a);
});
const P = t.permissions?.canAddFiles !== !1, D = document.createElement("button");
D.type = "button", D.textContent = M.length > 0 ? "Change WAV File" : "Add WAV File", D.style.cssText = "margin-top:12px;padding:8px;border:1px solid var(--ui-border);border-radius:6px;background:var(--surface);cursor:pointer;font-size:14px;color:var(--text-primary);";
const h = document.createElement("input");
h.type = "file", h.accept = ".wav,.mp3,.m4a,.ogg", h.style.display = "none", D.onclick = () => {
P && h.click();
}, h.onchange = async (k) => {
if (!P)
return;
const a = k.target.files;
if (!a || a.length === 0) return;
const m = a[0];
try {
const e = URL.createObjectURL(m);
await Y(null, e, m.name), f();
const n = document.querySelector('[data-role="file-toggle"]');
if (n) {
const u = window.FileToggleManager;
u && u.updateFileToggleSection(n, t);
}
} catch (e) {
console.error("Failed to load audio file", e);
}
h.value = "";
}, P && (o.appendChild(D), o.appendChild(h));
};
return f(), r;
}
function te(t) {
const { overlay: r, modal: p } = V();
if (p.childElementCount > 0) {
r.parentElement || document.body.appendChild(r);
return;
}
const o = J("Tracks & Appearance", () => r.remove()), C = $(t), f = Z(t), l = X(t);
p.appendChild(o), p.appendChild(C), p.appendChild(f), p.appendChild(l), r.addEventListener("click", (M) => {
M.target === r && r.remove();
}), document.body.appendChild(r);
}
export {
te as openSettingsModal
};