fix(editor): use ProseMirror schema for image upload state
Address code review feedback: - Replace rAF + DOM query with Image extension `uploading` attribute managed by ProseMirror schema (no race conditions) - Remove redundant removeAttribute call (setNodeMarkup rebuilds DOM) - Restore pulse animation on img[data-uploading] for upload feedback - Remove dev mock from use-file-upload.ts (was blocking real uploads) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
fe975fb2bb
commit
b8b4731602
2 changed files with 22 additions and 23 deletions
|
|
@ -241,14 +241,14 @@
|
|||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
/* Uploading image placeholder (blob: URLs = in-flight uploads) */
|
||||
.rich-text-editor img[src^="blob:"] {
|
||||
/* Uploading image placeholder — data-uploading attribute managed by ProseMirror schema */
|
||||
.rich-text-editor img[data-uploading] {
|
||||
opacity: 0.5;
|
||||
border-radius: var(--radius);
|
||||
animation: rte-pulse 1.5s ease-in-out infinite;
|
||||
animation: rte-upload-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||
}
|
||||
|
||||
@keyframes rte-pulse {
|
||||
@keyframes rte-upload-pulse {
|
||||
0%, 100% { opacity: 0.5; }
|
||||
50% { opacity: 0.3; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -150,23 +150,13 @@ function createFileUploadExtension(
|
|||
const isImage = file.type.startsWith("image/");
|
||||
|
||||
if (isImage) {
|
||||
// Instant preview via blob URL, then replace with real URL after upload
|
||||
// Instant preview via blob URL with uploading flag for CSS styling
|
||||
const blobUrl = URL.createObjectURL(file);
|
||||
const imgAttrs = { src: blobUrl, alt: file.name, uploading: true };
|
||||
if (pos !== undefined) {
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.insertContentAt(pos, {
|
||||
type: "image",
|
||||
attrs: { src: blobUrl, alt: file.name },
|
||||
})
|
||||
.run();
|
||||
editor.chain().focus().insertContentAt(pos, { type: "image", attrs: imgAttrs }).run();
|
||||
} else {
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.setImage({ src: blobUrl, alt: file.name })
|
||||
.run();
|
||||
editor.chain().focus().setImage(imgAttrs).run();
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
@ -174,14 +164,12 @@ function createFileUploadExtension(
|
|||
if (result) {
|
||||
const { tr } = editor.state;
|
||||
editor.state.doc.descendants((node, nodePos) => {
|
||||
if (
|
||||
node.type.name === "image" &&
|
||||
node.attrs.src === blobUrl
|
||||
) {
|
||||
if (node.type.name === "image" && node.attrs.src === blobUrl) {
|
||||
tr.setNodeMarkup(nodePos, undefined, {
|
||||
...node.attrs,
|
||||
src: result.link,
|
||||
alt: result.filename,
|
||||
uploading: false,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
@ -330,7 +318,18 @@ const RichTextEditor = forwardRef<RichTextEditorRef, RichTextEditorProps>(
|
|||
LinkExtension,
|
||||
Typography,
|
||||
MentionExtension,
|
||||
Image.configure({
|
||||
Image.extend({
|
||||
addAttributes() {
|
||||
return {
|
||||
...this.parent?.(),
|
||||
uploading: {
|
||||
default: false,
|
||||
renderHTML: (attrs) => (attrs.uploading ? { "data-uploading": "" } : {}),
|
||||
parseHTML: (el) => el.hasAttribute("data-uploading"),
|
||||
},
|
||||
};
|
||||
},
|
||||
}).configure({
|
||||
inline: false,
|
||||
allowBase64: false,
|
||||
HTMLAttributes: { style: "max-width: 100%; height: auto;" },
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue