fix(core): should not be able to commit comments when uploading images (#13108)

#### PR Dependency Tree


* **PR #13108** 👈

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

* **Bug Fixes**
* The commit button in the comment editor is now properly disabled while
attachments are uploading or when the editor is empty without
attachments, preventing accidental or premature submissions.
* **New Features**
* Attachment delete button now shows a loading state during uploads for
clearer user feedback.
* **Style**
* Updated comment editor attachment button styles for a cleaner and more
consistent appearance.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Peng Xiao
2025-07-09 15:56:34 +08:00
committed by GitHub
parent 8236ecf486
commit 9071c5032d
3 changed files with 25 additions and 37 deletions

View File

@@ -47,3 +47,7 @@ export const NullCommentInlineSpecExtension =
match: () => false, match: () => false,
renderer: () => html``, renderer: () => html``,
}); });
// reuse the same identifier
NullCommentInlineSpecExtension.identifier =
CommentInlineSpecExtension.identifier;

View File

@@ -1,4 +1,4 @@
import { IconButton, Loading } from '@affine/component'; import { IconButton } from '@affine/component';
import { LitDocEditor, type PageEditor } from '@affine/core/blocksuite/editors'; import { LitDocEditor, type PageEditor } from '@affine/core/blocksuite/editors';
import { SnapshotHelper } from '@affine/core/modules/comment/services/snapshot-helper'; import { SnapshotHelper } from '@affine/core/modules/comment/services/snapshot-helper';
import type { CommentAttachment } from '@affine/core/modules/comment/types'; import type { CommentAttachment } from '@affine/core/modules/comment/types';
@@ -144,6 +144,11 @@ export const CommentEditor = forwardRef<CommentEditorRef, CommentEditorProps>(
); );
const isImageUploadDisabled = (attachments?.length ?? 0) >= MAX_IMAGE_COUNT; const isImageUploadDisabled = (attachments?.length ?? 0) >= MAX_IMAGE_COUNT;
const uploadingAttachments = attachments?.some(
att => att.status === 'uploading'
);
const commitDisabled =
(empty && (attachments?.length ?? 0) === 0) || uploadingAttachments;
const addImages = useAsyncCallback( const addImages = useAsyncCallback(
async (files: File[]) => { async (files: File[]) => {
@@ -296,13 +301,13 @@ export const CommentEditor = forwardRef<CommentEditorRef, CommentEditorProps>(
// upload attachments and call original onCommit // upload attachments and call original onCommit
const handleCommit = useAsyncCallback(async () => { const handleCommit = useAsyncCallback(async () => {
if (readonly) return; if (readonly || commitDisabled) return;
onCommit?.(); onCommit?.();
setAttachments(prev => { setAttachments(prev => {
prev.forEach(att => att.localUrl && URL.revokeObjectURL(att.localUrl)); prev.forEach(att => att.localUrl && URL.revokeObjectURL(att.localUrl));
return []; return [];
}); });
}, [readonly, onCommit, setAttachments]); }, [readonly, commitDisabled, onCommit, setAttachments]);
const focusEditor = useAsyncCallback(async () => { const focusEditor = useAsyncCallback(async () => {
if (editorRef.current) { if (editorRef.current) {
@@ -447,20 +452,17 @@ export const CommentEditor = forwardRef<CommentEditorRef, CommentEditorProps>(
onClick={e => handleImageClick(e, index)} onClick={e => handleImageClick(e, index)}
> >
{!readonly && ( {!readonly && (
<div <IconButton
className={styles.deleteBtn} size={12}
className={styles.attachmentButton}
loading={att.status === 'uploading'}
variant="danger"
onClick={e => { onClick={e => {
e.stopPropagation(); e.stopPropagation();
handleImageRemove(att.id); handleImageRemove(att.id);
}} }}
> icon={<CloseIcon />}
<CloseIcon width={12} height={12} /> />
</div>
)}
{att.status === 'uploading' && (
<div className={styles.spinnerWrapper}>
<Loading size={16} />
</div>
)} )}
</div> </div>
))} ))}
@@ -480,7 +482,7 @@ export const CommentEditor = forwardRef<CommentEditorRef, CommentEditorProps>(
<button <button
onClick={handleCommit} onClick={handleCommit}
className={styles.commitButton} className={styles.commitButton}
disabled={empty && (attachments?.length ?? 0) === 0} disabled={commitDisabled}
> >
<ArrowUpBigIcon /> <ArrowUpBigIcon />
</button> </button>

View File

@@ -91,36 +91,18 @@ export const previewBox = style({
}, },
}); });
export const deleteBtn = style({ export const attachmentButton = style({
position: 'absolute', position: 'absolute',
top: -6, top: -6,
right: -6, right: -6,
width: 16, background: cssVarV2('layer/background/primary'),
height: 16, border: '1px solid',
borderRadius: 4, borderColor: cssVarV2('layer/insideBorder/border'),
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
border: `0.5px solid ${cssVarV2('layer/insideBorder/border')}`,
backgroundColor: cssVarV2('layer/background/primary'),
cursor: 'pointer',
selectors: { selectors: {
'&:hover': { '&:hover': {
backgroundColor: cssVarV2('layer/background/error'), background: cssVarV2('layer/background/error'),
borderColor: cssVarV2('button/error'), borderColor: cssVarV2('button/error'),
color: cssVarV2('button/error'), color: cssVarV2('button/error'),
}, },
}, },
}); });
export const spinnerWrapper = style({
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'rgba(255,255,255,0.6)',
});