67 lines
1.9 KiB
TypeScript
67 lines
1.9 KiB
TypeScript
export function AddOption(
|
|
onSubmit: (label: string) => string | null,
|
|
): HTMLElement {
|
|
const wrapper = document.createElement("div");
|
|
wrapper.className = "add-option-wrapper";
|
|
|
|
const input = document.createElement("input");
|
|
input.type = "text";
|
|
input.className = "add-option-input";
|
|
input.placeholder = "Add an option\u2026";
|
|
input.maxLength = 100;
|
|
input.setAttribute("aria-label", "New poll option");
|
|
|
|
const btn = document.createElement("button");
|
|
btn.className = "add-option-btn";
|
|
btn.setAttribute("aria-label", "Add option");
|
|
btn.innerHTML = `
|
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
|
<path d="M8 2v12M2 8h12" stroke="currentColor" stroke-width="1.75" stroke-linecap="round"/>
|
|
</svg>
|
|
<span>Add</span>
|
|
`;
|
|
|
|
const feedback = document.createElement("div");
|
|
feedback.className = "add-option-feedback";
|
|
feedback.setAttribute("aria-live", "polite");
|
|
|
|
wrapper.append(input, btn, feedback);
|
|
|
|
function submit() {
|
|
const name = input.value.trim();
|
|
if (!name) {
|
|
input.focus();
|
|
input.classList.add("shake");
|
|
input.addEventListener("animationend", () => input.classList.remove("shake"), { once: true });
|
|
return;
|
|
}
|
|
|
|
const error = onSubmit(name);
|
|
if (error) {
|
|
feedback.textContent = error;
|
|
feedback.style.display = "";
|
|
setTimeout(() => {
|
|
feedback.textContent = "";
|
|
feedback.style.display = "none";
|
|
}, 3000);
|
|
return;
|
|
}
|
|
|
|
input.value = "";
|
|
feedback.textContent = "";
|
|
feedback.style.display = "none";
|
|
input.focus();
|
|
}
|
|
|
|
btn.addEventListener("click", submit);
|
|
input.addEventListener("keydown", (e) => {
|
|
if (e.key === "Enter") submit();
|
|
});
|
|
input.addEventListener("input", () => {
|
|
feedback.textContent = "";
|
|
feedback.style.display = "none";
|
|
});
|
|
|
|
return wrapper;
|
|
}
|