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

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

View File

@@ -91,36 +91,18 @@ export const previewBox = style({
},
});
export const deleteBtn = style({
export const attachmentButton = style({
position: 'absolute',
top: -6,
right: -6,
width: 16,
height: 16,
borderRadius: 4,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
border: `0.5px solid ${cssVarV2('layer/insideBorder/border')}`,
backgroundColor: cssVarV2('layer/background/primary'),
cursor: 'pointer',
background: cssVarV2('layer/background/primary'),
border: '1px solid',
borderColor: cssVarV2('layer/insideBorder/border'),
selectors: {
'&:hover': {
backgroundColor: cssVarV2('layer/background/error'),
background: cssVarV2('layer/background/error'),
borderColor: 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)',
});