feat(web): give block editor an accessible dialog label

Expose role=dialog and a stable aria-label so save can be scoped
without changing the modal's visuals or save behavior.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
weichen
2026-09-13 17:46:37 +00:00
co-authored by Cursor
parent 4a4fbcf2a6
commit a42895ccdc
3 changed files with 50 additions and 1 deletions
+5 -1
View File
@@ -23,6 +23,7 @@ import {
} from 'lucide-react';
import katex from 'katex';
import { renderInlineMarkdown } from '../../engine/renderMarkdown';
import { BLOCK_EDITOR_DIALOG_LABEL, BLOCK_EDITOR_SAVE_NAME } from '../../lib/blockEditorDialog';
interface BlockEditorModalProps {
block: DocumentBlock;
@@ -216,6 +217,9 @@ export const BlockEditorModal: React.FC<BlockEditorModalProps> = ({ block, onSav
return (
<div
role="dialog"
aria-modal="true"
aria-label={BLOCK_EDITOR_DIALOG_LABEL}
style={{
position: 'fixed',
inset: 0,
@@ -973,7 +977,7 @@ export const BlockEditorModal: React.FC<BlockEditorModalProps> = ({ block, onSav
}}
>
<Check size={14} />
<span>保存修改</span>
<span>{BLOCK_EDITOR_SAVE_NAME}</span>
</button>
</div>
</div>
+28
View File
@@ -0,0 +1,28 @@
import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
import {
BLOCK_EDITOR_DIALOG_LABEL,
BLOCK_EDITOR_SAVE_NAME,
blockEditorDialogPolicy,
} from './blockEditorDialog';
describe('blockEditorDialogPolicy', () => {
it('pins an accessible dialog label and exact save name', () => {
const policy = blockEditorDialogPolicy();
assert.equal(policy.role, 'dialog');
assert.equal(policy.name, '编辑受控块');
assert.equal(policy.name, BLOCK_EDITOR_DIALOG_LABEL);
assert.equal(policy.saveButton.name, '保存修改');
assert.equal(policy.saveButton.name, BLOCK_EDITOR_SAVE_NAME);
assert.equal(policy.saveButton.exact, true);
});
it('rejects page-wide fuzzy /保存/ that would hit private-library buttons', () => {
const policy = blockEditorDialogPolicy();
const privateLibrary = '一键保存到我的私密文档库';
assert.match(privateLibrary, policy.forbidPageWideSaveRegex);
assert.equal(policy.saveButton.name === '保存修改', true);
assert.doesNotMatch(policy.saveButton.name, /^一键保存/);
assert.equal(policy.forbidPageWideSaveRegex.source, '保存修改|保存');
});
});
+17
View File
@@ -0,0 +1,17 @@
/** 块编辑弹窗的稳定可访问名称与保存按钮文案(禁止全页模糊 /保存/)。 */
export const BLOCK_EDITOR_DIALOG_LABEL = '编辑受控块';
export const BLOCK_EDITOR_SAVE_NAME = '保存修改';
export function blockEditorDialogPolicy(): {
role: 'dialog';
name: typeof BLOCK_EDITOR_DIALOG_LABEL;
saveButton: { name: typeof BLOCK_EDITOR_SAVE_NAME; exact: true };
forbidPageWideSaveRegex: RegExp;
} {
return {
role: 'dialog',
name: BLOCK_EDITOR_DIALOG_LABEL,
saveButton: { name: BLOCK_EDITOR_SAVE_NAME, exact: true },
forbidPageWideSaveRegex: /保存修改|保存/,
};
}