feat(editor): add replace action in attachment toolbar (#12512)

Closes:
[BS-3549](https://linear.app/affine-design/issue/BS-3549/附件-toolbar-上添加-replace-action)

[Screen Recording 2025-06-04 at 15.37.40.mov <span
class="graphite__hidden">(uploaded via Graphite)</span> <img
class="graphite__hidden"
src="https://app.graphite.dev/api/v1/graphite/video/thumbnail/8ypiIKZXudF5a0tIgIzf/480c8690-7ec9-4188-92fd-ee3339afb558.mov"
/>](https://app.graphite.dev/media/video/8ypiIKZXudF5a0tIgIzf/480c8690-7ec9-4188-92fd-ee3339afb558.mov)



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

- **New Features**
- Added the ability to replace attachments directly from the toolbar,
allowing users to select and update files seamlessly.
- **Bug Fixes**
- Improved handling when replacing embedded attachments with unsupported
file types, ensuring the view falls back to a card view as needed.
- **Tests**
- Introduced end-to-end tests to verify attachment replacement and
correct UI behavior in both standard and edgeless editing modes.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Fangdun Tsai
2025-06-11 14:57:31 +08:00
committed by GitHub
parent 814364489f
commit a71904e641
10 changed files with 282 additions and 64 deletions

View File

@@ -176,9 +176,7 @@ export async function openFilesWith(
resolve(input.files ? Array.from(input.files) : null);
});
// The `cancel` event fires when the user cancels the dialog.
input.addEventListener('cancel', () => {
resolve(null);
});
input.addEventListener('cancel', () => resolve(null));
// Show the picker.
if ('showPicker' in HTMLInputElement.prototype) {
input.showPicker();
@@ -188,16 +186,16 @@ export async function openFilesWith(
});
}
export function openSingleFileWith(
export async function openSingleFileWith(
acceptType?: AcceptTypes
): Promise<File | null> {
return openFilesWith(acceptType, false).then(files => files?.at(0) ?? null);
const files = await openFilesWith(acceptType, false);
return files?.at(0) ?? null;
}
export async function getImageFilesFromLocal() {
const imageFiles = await openFilesWith('Images');
if (!imageFiles) return [];
return imageFiles;
const files = await openFilesWith('Images');
return files ?? [];
}
export function downloadBlob(blob: Blob, name: string) {