fix(core): should not be able to comment with empty content (#13061)

fix AF-2712

#### PR Dependency Tree


* **PR #13061** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## 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.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Peng Xiao
2025-07-07 13:49:34 +08:00
committed by GitHub
parent 0be63d6e0e
commit 90b2b33dde
3 changed files with 46 additions and 9 deletions

View File

@@ -93,6 +93,8 @@ export const CommentEditor = forwardRef<CommentEditorRef, CommentEditorProps>(
const snapshotHelper = useService(SnapshotHelper);
const editorRef = useRef<PageEditor>(null);
const [empty, setEmpty] = useState(true);
useImperativeHandle(
ref,
() => ({
@@ -138,12 +140,15 @@ export const CommentEditor = forwardRef<CommentEditorRef, CommentEditorProps>(
}, [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<CommentEditorRef, CommentEditorProps>(
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<CommentEditorRef, CommentEditorProps>(
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<CommentEditorRef, CommentEditorProps>(
{doc && <LitDocEditor ref={editorRef} specs={specs} doc={doc} />}
{!readonly && (
<div className={styles.footer}>
<button onClick={onCommit} className={styles.commitButton}>
<button
onClick={onCommit}
className={styles.commitButton}
disabled={empty}
>
<ArrowUpBigIcon />
</button>
</div>

View File

@@ -52,7 +52,7 @@ export const commitButton = style({
height: '28px',
fontSize: 20,
selectors: {
'&[data-disabled="true"]': {
'&[disabled]': {
background: cssVarV2('button/disable'),
cursor: 'default',
},

View File

@@ -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;
}
}