fix: fence disabled Composer mutations

This commit is contained in:
2026-09-01 21:00:26 +09:00
parent 1aeb6fdb35
commit 409245cb52
3 changed files with 33 additions and 5 deletions
@@ -280,6 +280,18 @@
extensions: [ extensions: [
history(), history(),
Prec.highest(keymap.of([ Prec.highest(keymap.of([
{
key: "Mod-z",
run: (currentView) => currentView.state.readOnly,
},
{
key: "Mod-Shift-z",
run: (currentView) => currentView.state.readOnly,
},
{
key: "Mod-y",
run: (currentView) => currentView.state.readOnly,
},
{ {
key: "Backspace", key: "Backspace",
run: (currentView) => run: (currentView) =>
@@ -397,7 +409,7 @@
} }
export function replaceRange(from: number, to: number, content: string): void { export function replaceRange(from: number, to: number, content: string): void {
if (!view) return; if (!view || view.state.readOnly) return;
view.dispatch({ view.dispatch({
changes: { from, to, insert: content }, changes: { from, to, insert: content },
selection: EditorSelection.cursor(from + content.length), selection: EditorSelection.cursor(from + content.length),
@@ -608,7 +608,11 @@ Deno.test("Worker Console paste chips preserve typed draft and target authority"
"composerDeletionRange(selection, pastes, direction)", "composerDeletionRange(selection, pastes, direction)",
) && ) &&
composerInput.includes("EditorState.readOnly.of(isDisabled)") && composerInput.includes("EditorState.readOnly.of(isDisabled)") &&
composerInput.includes('key: "Mod-z"') &&
composerInput.includes("if (!view || view.state.readOnly) return") &&
composerInput.includes("if (currentView.state.readOnly) return false") && composerInput.includes("if (currentView.state.readOnly) return false") &&
consolePage.includes("activeComposerTargetKey !== targetKey") &&
consolePage.includes("if (!composerEditable) return") &&
composerInput.includes('chip.setAttribute("aria-label", label)') && composerInput.includes('chip.setAttribute("aria-label", label)') &&
composerInput.includes("preserveExactText = false") && composerInput.includes("preserveExactText = false") &&
consolePage.includes("buildComposerSegmentsRequest(value.segments, {") && consolePage.includes("buildComposerSegmentsRequest(value.segments, {") &&
@@ -353,10 +353,13 @@
} }
async function applyComposerCompletion() { async function applyComposerCompletion() {
if (!composerInputElement) return; if (!composerEditable || !composerInputElement) return;
const input = composerInputElement;
const targetKey = activeComposerTargetKey;
const document = draft.document;
const token = completionTokenAt( const token = completionTokenAt(
draft.document, document,
composerInputElement.cursor(), input.cursor(),
); );
completionToken = token; completionToken = token;
completionError = null; completionError = null;
@@ -368,12 +371,20 @@
completionBusy = true; completionBusy = true;
try { try {
const entries = await resolveCompletionEntries(token); const entries = await resolveCompletionEntries(token);
if (
!composerEditable ||
composerInputElement !== input ||
activeComposerTargetKey !== targetKey ||
draft.document !== document
) {
return;
}
completionEntries = entries; completionEntries = entries;
if (entries.length === 0) { if (entries.length === 0) {
completionError = `No completions for ${token.sigil}${token.prefix}`; completionError = `No completions for ${token.sigil}${token.prefix}`;
return; return;
} }
composerInputElement.replaceRange( input.replaceRange(
token.start, token.start,
token.end, token.end,
`${entries[0].value} `, `${entries[0].value} `,
@@ -433,6 +444,7 @@
return; return;
} }
event.preventDefault(); event.preventDefault();
if (!composerEditable) return;
void applyComposerCompletion(); void applyComposerCompletion();
} }