From a42895ccdcc16a496b8dba7331ac536a9ea7795e Mon Sep 17 00:00:00 2001 From: weichen Date: Sun, 13 Sep 2026 17:46:37 +0000 Subject: [PATCH] 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 --- web/src/components/doc/BlockEditorModal.tsx | 6 ++++- web/src/lib/blockEditorDialog.test.ts | 28 +++++++++++++++++++++ web/src/lib/blockEditorDialog.ts | 17 +++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 web/src/lib/blockEditorDialog.test.ts create mode 100644 web/src/lib/blockEditorDialog.ts diff --git a/web/src/components/doc/BlockEditorModal.tsx b/web/src/components/doc/BlockEditorModal.tsx index 682f42fa..0d9c4ec3 100644 --- a/web/src/components/doc/BlockEditorModal.tsx +++ b/web/src/components/doc/BlockEditorModal.tsx @@ -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 = ({ block, onSav return (
= ({ block, onSav }} > - 保存修改 + {BLOCK_EDITOR_SAVE_NAME}
diff --git a/web/src/lib/blockEditorDialog.test.ts b/web/src/lib/blockEditorDialog.test.ts new file mode 100644 index 00000000..3a738309 --- /dev/null +++ b/web/src/lib/blockEditorDialog.test.ts @@ -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, '保存修改|保存'); + }); +}); diff --git a/web/src/lib/blockEditorDialog.ts b/web/src/lib/blockEditorDialog.ts new file mode 100644 index 00000000..da4b72ac --- /dev/null +++ b/web/src/lib/blockEditorDialog.ts @@ -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: /保存修改|保存/, + }; +}