fix: delete complete Composer selections
This commit is contained in:
@@ -28,6 +28,7 @@
|
||||
type ComposerPasteMeasurement,
|
||||
} from "$lib/workspace/console/composer-paste.ts";
|
||||
import {
|
||||
composerDeletionRange,
|
||||
composerPasteAtoms,
|
||||
composerPasteToken,
|
||||
pasteChipLabel,
|
||||
@@ -255,18 +256,15 @@
|
||||
direction: "backward" | "forward",
|
||||
): boolean {
|
||||
const selection = currentView.state.selection.main;
|
||||
if (!selection.empty) return false;
|
||||
const pastes = composerPasteAtoms(
|
||||
currentView.state.doc.toString(),
|
||||
currentView.state.field(pasteRegistry),
|
||||
);
|
||||
const paste = direction === "backward"
|
||||
? pastes.find((candidate) => candidate.to === selection.head)
|
||||
: pastes.find((candidate) => candidate.from === selection.head);
|
||||
if (!paste) return false;
|
||||
const deletion = composerDeletionRange(selection, pastes, direction);
|
||||
if (!deletion) return false;
|
||||
currentView.dispatch({
|
||||
changes: { from: paste.from, to: paste.to },
|
||||
selection: EditorSelection.cursor(paste.from),
|
||||
changes: deletion,
|
||||
selection: EditorSelection.cursor(deletion.from),
|
||||
annotations: isolateHistory.of("full"),
|
||||
userEvent: "delete",
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { Segment } from "$lib/generated/protocol.ts";
|
||||
import {
|
||||
composerDeletionRange,
|
||||
type ComposerPaste,
|
||||
composerPasteToken,
|
||||
pasteChipLabel,
|
||||
@@ -76,6 +77,30 @@ Deno.test("composer draft preserves mixed Text and Paste order exactly", () => {
|
||||
assertEquals(snapshot.pastes.map((entry) => entry.key), [11, 12]);
|
||||
});
|
||||
|
||||
Deno.test("selection deletion covers mixed Text and every selected paste chip", () => {
|
||||
const pastes = [
|
||||
{ ...paste(1, "first"), key: 10, from: 2, to: 5 },
|
||||
{ ...paste(2, "second"), key: 11, from: 8, to: 11 },
|
||||
];
|
||||
|
||||
assertEquals(
|
||||
composerDeletionRange({ from: 1, to: 12, head: 12 }, pastes, "backward"),
|
||||
{ from: 1, to: 12 },
|
||||
);
|
||||
assertEquals(
|
||||
composerDeletionRange({ from: 2, to: 11, head: 2 }, pastes, "forward"),
|
||||
{ from: 2, to: 11 },
|
||||
);
|
||||
assertEquals(
|
||||
composerDeletionRange({ from: 5, to: 5, head: 5 }, pastes, "backward"),
|
||||
{ from: 2, to: 5 },
|
||||
);
|
||||
assertEquals(
|
||||
composerDeletionRange({ from: 8, to: 8, head: 8 }, pastes, "forward"),
|
||||
{ from: 8, to: 11 },
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("composer paste chip label is compact and accessible", () => {
|
||||
assertEquals(
|
||||
pasteChipLabel({ id: 4, content: "payload", chars: 7, lines: 1 }),
|
||||
|
||||
@@ -24,6 +24,26 @@ export interface ComposerTextPaste {
|
||||
content: string;
|
||||
}
|
||||
|
||||
export interface ComposerSelection {
|
||||
from: number;
|
||||
to: number;
|
||||
head: number;
|
||||
}
|
||||
|
||||
export function composerDeletionRange(
|
||||
selection: ComposerSelection,
|
||||
pastes: readonly ComposerPasteAtom[],
|
||||
direction: "backward" | "forward",
|
||||
): { from: number; to: number } | null {
|
||||
if (selection.from !== selection.to) {
|
||||
return { from: selection.from, to: selection.to };
|
||||
}
|
||||
const paste = direction === "backward"
|
||||
? pastes.find((candidate) => candidate.to === selection.head)
|
||||
: pastes.find((candidate) => candidate.from === selection.head);
|
||||
return paste ? { from: paste.from, to: paste.to } : null;
|
||||
}
|
||||
|
||||
export interface ComposerDraftSnapshot {
|
||||
document: string;
|
||||
content: string;
|
||||
|
||||
@@ -604,6 +604,9 @@ Deno.test("Worker Console paste chips preserve typed draft and target authority"
|
||||
composerInput.includes("EditorView.atomicRanges") &&
|
||||
composerInput.includes('key: "Backspace"') &&
|
||||
composerInput.includes('key: "Delete"') &&
|
||||
composerInput.includes(
|
||||
"composerDeletionRange(selection, pastes, direction)",
|
||||
) &&
|
||||
composerInput.includes('chip.setAttribute("aria-label", label)') &&
|
||||
composerInput.includes("preserveExactText = false") &&
|
||||
consolePage.includes("buildComposerSegmentsRequest(value.segments, {") &&
|
||||
|
||||
Reference in New Issue
Block a user