From 90b2b33dde58587d3bba2b995a29a9939b5bed29 Mon Sep 17 00:00:00 2001 From: Peng Xiao Date: Mon, 7 Jul 2025 13:49:34 +0800 Subject: [PATCH] fix(core): should not be able to comment with empty content (#13061) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix AF-2712 #### PR Dependency Tree * **PR #13061** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) ## Summary by CodeRabbit * **New Features** * The comment editor now disables the commit button when the editor is empty, preventing accidental submissions. * The commit action is now triggered by pressing Enter together with CMD/CTRL, instead of Enter without Shift. * **Style** * The disabled state styling for the commit button now matches the native HTML `disabled` attribute for improved consistency. --- .../comment/comment-editor/index.tsx | 25 +++++++++++------ .../comment/comment-editor/style.css.ts | 2 +- .../comment/services/snapshot-helper.ts | 28 +++++++++++++++++++ 3 files changed, 46 insertions(+), 9 deletions(-) diff --git a/packages/frontend/core/src/components/comment/comment-editor/index.tsx b/packages/frontend/core/src/components/comment/comment-editor/index.tsx index 4ca60041b1..66b1547086 100644 --- a/packages/frontend/core/src/components/comment/comment-editor/index.tsx +++ b/packages/frontend/core/src/components/comment/comment-editor/index.tsx @@ -93,6 +93,8 @@ export const CommentEditor = forwardRef( const snapshotHelper = useService(SnapshotHelper); const editorRef = useRef(null); + const [empty, setEmpty] = useState(true); + useImperativeHandle( ref, () => ({ @@ -138,12 +140,15 @@ export const CommentEditor = forwardRef( }, [autoFocus, doc]); useEffect(() => { - if (doc && onChange) { + if (doc) { const subscription = doc.slots.blockUpdated.subscribe(() => { - const snapshot = snapshotHelper.getSnapshot(doc); - if (snapshot) { - onChange?.(snapshot); + if (onChange) { + const snapshot = snapshotHelper.getSnapshot(doc); + if (snapshot) { + onChange?.(snapshot); + } } + setEmpty(snapshotHelper.isDocEmpty(doc)); }); return () => { subscription?.unsubscribe(); @@ -152,7 +157,7 @@ export const CommentEditor = forwardRef( return; }, [doc, onChange, snapshotHelper]); - // Add keydown handler to commit on Enter key + // Add keydown handler to commit on CMD/CTRL + Enter key const handleKeyDown = useCallback( (e: React.KeyboardEvent) => { if (readonly) return; @@ -161,8 +166,8 @@ export const CommentEditor = forwardRef( const activeElement = document.activeElement; if (!editorRef.current?.contains(activeElement)) return; - // If Enter is pressed without Shift key, commit the comment - if (e.key === 'Enter' && !e.shiftKey) { + // If Enter is pressed with CMD/CTRL key, commit the comment + if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) { e.preventDefault(); e.stopPropagation(); onCommit?.(); @@ -194,7 +199,11 @@ export const CommentEditor = forwardRef( {doc && } {!readonly && (
-
diff --git a/packages/frontend/core/src/components/comment/comment-editor/style.css.ts b/packages/frontend/core/src/components/comment/comment-editor/style.css.ts index f25571297d..28e226b9aa 100644 --- a/packages/frontend/core/src/components/comment/comment-editor/style.css.ts +++ b/packages/frontend/core/src/components/comment/comment-editor/style.css.ts @@ -52,7 +52,7 @@ export const commitButton = style({ height: '28px', fontSize: 20, selectors: { - '&[data-disabled="true"]': { + '&[disabled]': { background: cssVarV2('button/disable'), cursor: 'default', }, diff --git a/packages/frontend/core/src/modules/comment/services/snapshot-helper.ts b/packages/frontend/core/src/modules/comment/services/snapshot-helper.ts index b67ad8048e..d281870d75 100644 --- a/packages/frontend/core/src/modules/comment/services/snapshot-helper.ts +++ b/packages/frontend/core/src/modules/comment/services/snapshot-helper.ts @@ -5,6 +5,7 @@ import { MarkdownAdapter, } from '@blocksuite/affine/shared/adapters'; import { + type BlockModel, type DocSnapshot, nanoid, type Store, @@ -152,4 +153,31 @@ export class SnapshotHelper extends Service { return undefined; } } + + isDocEmpty(store?: Store): boolean { + if (!store) { + return true; + } + + const checkBlock = (block: BlockModel) => { + if (block.text && block.text.length > 0) { + return false; + } + const children = block.children; + for (const child of children) { + if (!checkBlock(child)) { + return false; + } + } + return true; + }; + + const blocks = store.blocks.peek(); + for (const block of Object.values(blocks)) { + if (!checkBlock(block.model)) { + return false; + } + } + return true; + } }