refactor(arr): subtitle chip takes shared delete
Drops the hand-rolled arm, disarm, timeout and label swap, and the local 12-grid close glyph that came with it.
This commit is contained in:
+23
-66
@@ -893,11 +893,11 @@ function subtitleChip(subtitle: Subtitle, onDeleted: () => void): HTMLSpanElemen
|
||||
}
|
||||
|
||||
/**
|
||||
* The delete affordance nested in a present-subtitle chip (issue #223): first
|
||||
* click arms it, second confirms — same idiom as `armedDelete`, scoped down
|
||||
* to an icon so it fits inside a chip. The confirmation names the sidecar
|
||||
* itself, in the title and `aria-label` both, since a chip is too narrow to
|
||||
* spell out a filename in its own text (§9.6's one-row constraint).
|
||||
* The delete affordance nested in a present-subtitle chip (issue #223): the
|
||||
* shared arm-then-confirm control at chip scale (#251), not a second copy of
|
||||
* the idiom. The label names the sidecar itself, in the title and
|
||||
* `aria-label` both, since a chip is too narrow to spell out a filename in
|
||||
* its own text (§9.6's one-row constraint).
|
||||
*/
|
||||
function subtitleDeleteButton(
|
||||
subtitleId: number,
|
||||
@@ -906,54 +906,26 @@ function subtitleDeleteButton(
|
||||
onDeleted: () => void,
|
||||
): HTMLButtonElement {
|
||||
const name = fileName(path);
|
||||
const button = document.createElement("button");
|
||||
button.type = "button";
|
||||
button.className = "chip-delete";
|
||||
button.append(closeIcon());
|
||||
|
||||
let armed = false;
|
||||
let resetTimer: number | undefined;
|
||||
const label = (confirming: boolean) => `${confirming ? "confirm " : ""}delete ${name}`;
|
||||
const paint = (confirming: boolean) => {
|
||||
button.title = label(confirming);
|
||||
button.setAttribute("aria-label", label(confirming));
|
||||
};
|
||||
const disarm = () => {
|
||||
armed = false;
|
||||
window.clearTimeout(resetTimer);
|
||||
delete button.dataset.armed;
|
||||
paint(false);
|
||||
};
|
||||
|
||||
paint(false);
|
||||
const button = armedDeleteIcon(
|
||||
`delete ${name}`,
|
||||
() => {
|
||||
delete chipEl.dataset.tone;
|
||||
chipEl.title = "";
|
||||
void deleteSubtitle(subtitleId).then((outcome) => {
|
||||
if (outcome.kind === "error") {
|
||||
button.disabled = false;
|
||||
chipEl.dataset.tone = "fault";
|
||||
chipEl.title = `delete failed — ${outcome.detail}`;
|
||||
return;
|
||||
}
|
||||
onDeleted();
|
||||
});
|
||||
},
|
||||
{ compact: true },
|
||||
);
|
||||
// the chip itself carries no click behaviour today, but never assume that stays true
|
||||
button.addEventListener("click", (event) => {
|
||||
// the chip itself carries no click behaviour today, but never assume that stays true
|
||||
event.stopPropagation();
|
||||
if (!armed) {
|
||||
armed = true;
|
||||
button.dataset.armed = "true";
|
||||
paint(true);
|
||||
resetTimer = window.setTimeout(disarm, 4000);
|
||||
return;
|
||||
}
|
||||
disarm();
|
||||
button.disabled = true;
|
||||
delete chipEl.dataset.tone;
|
||||
chipEl.title = "";
|
||||
void deleteSubtitle(subtitleId).then((outcome) => {
|
||||
if (outcome.kind === "error") {
|
||||
button.disabled = false;
|
||||
chipEl.dataset.tone = "fault";
|
||||
chipEl.title = `delete failed — ${outcome.detail}`;
|
||||
return;
|
||||
}
|
||||
onDeleted();
|
||||
});
|
||||
});
|
||||
button.addEventListener("blur", () => {
|
||||
if (armed) {
|
||||
disarm();
|
||||
}
|
||||
});
|
||||
return button;
|
||||
}
|
||||
@@ -2161,21 +2133,6 @@ function starIcon(): SVGSVGElement {
|
||||
return svg;
|
||||
}
|
||||
|
||||
/** The drawn × on a delete affordance — no glyph standing in for an icon. */
|
||||
function closeIcon(): SVGSVGElement {
|
||||
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
||||
svg.setAttribute("viewBox", "0 0 12 12");
|
||||
svg.setAttribute("class", "close-icon");
|
||||
svg.setAttribute("aria-hidden", "true");
|
||||
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
||||
path.setAttribute("d", "M2.5 2.5 L9.5 9.5 M9.5 2.5 L2.5 9.5");
|
||||
path.setAttribute("stroke", "currentColor");
|
||||
path.setAttribute("stroke-width", "1.5");
|
||||
path.setAttribute("stroke-linecap", "round");
|
||||
svg.append(path);
|
||||
return svg;
|
||||
}
|
||||
|
||||
/** External links read as quiet controls; they leave the app entirely. */
|
||||
function externalLink(mark: SVGSVGElement, label: string, href: string): HTMLAnchorElement {
|
||||
const link = document.createElement("a");
|
||||
|
||||
Reference in New Issue
Block a user