mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-27 10:52:40 +08:00
refactor(editor): optimize pasting process of attachments and images (#12276)
Related to: [BS-3146](https://linear.app/affine-design/issue/BS-3146/import-paste-接口改进优化)
This commit is contained in:
@@ -143,7 +143,11 @@ export class AttachmentBlockComponent extends CaptionedBlockComponent<Attachment
|
||||
this.disposables.add(this.resourceController.subscribe());
|
||||
this.disposables.add(this.resourceController);
|
||||
|
||||
this.refreshData();
|
||||
this.disposables.add(
|
||||
this.model.props.sourceId$.subscribe(() => {
|
||||
this.refreshData();
|
||||
})
|
||||
);
|
||||
|
||||
if (!this.model.props.style && !this.store.readonly) {
|
||||
this.store.withoutTransact(() => {
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
} from '@blocksuite/affine-shared/commands';
|
||||
import { ImageSelection } from '@blocksuite/affine-shared/selection';
|
||||
import { unsafeCSSVarV2 } from '@blocksuite/affine-shared/theme';
|
||||
import { WithDisposable } from '@blocksuite/global/lit';
|
||||
import { SignalWatcher, WithDisposable } from '@blocksuite/global/lit';
|
||||
import type { BlockComponent, UIEventStateContext } from '@blocksuite/std';
|
||||
import {
|
||||
BlockSelection,
|
||||
@@ -15,8 +15,9 @@ import {
|
||||
TextSelection,
|
||||
} from '@blocksuite/std';
|
||||
import type { BaseSelection } from '@blocksuite/store';
|
||||
import { computed } from '@preact/signals-core';
|
||||
import { css, html, type PropertyValues } from 'lit';
|
||||
import { property, query, state } from 'lit/decorators.js';
|
||||
import { property, query } from 'lit/decorators.js';
|
||||
import { styleMap } from 'lit/directives/style-map.js';
|
||||
import { when } from 'lit/directives/when.js';
|
||||
|
||||
@@ -25,7 +26,9 @@ import { ImageResizeManager } from '../image-resize-manager';
|
||||
import { shouldResizeImage } from '../utils';
|
||||
import { ImageSelectedRect } from './image-selected-rect';
|
||||
|
||||
export class ImageBlockPageComponent extends WithDisposable(ShadowlessElement) {
|
||||
export class ImageBlockPageComponent extends SignalWatcher(
|
||||
WithDisposable(ShadowlessElement)
|
||||
) {
|
||||
static override styles = css`
|
||||
affine-page-image {
|
||||
position: relative;
|
||||
@@ -68,6 +71,8 @@ export class ImageBlockPageComponent extends WithDisposable(ShadowlessElement) {
|
||||
}
|
||||
`;
|
||||
|
||||
resizeable$ = computed(() => this.block.resizeable$.value);
|
||||
|
||||
private _isDragging = false;
|
||||
|
||||
private get _doc() {
|
||||
@@ -134,21 +139,21 @@ export class ImageBlockPageComponent extends WithDisposable(ShadowlessElement) {
|
||||
return true;
|
||||
},
|
||||
Delete: ctx => {
|
||||
if (this._host.store.readonly || !this._isSelected) return;
|
||||
if (this._host.store.readonly || !this.resizeable$.peek()) return;
|
||||
|
||||
addParagraph(ctx);
|
||||
this._doc.deleteBlock(this._model);
|
||||
return true;
|
||||
},
|
||||
Backspace: ctx => {
|
||||
if (this._host.store.readonly || !this._isSelected) return;
|
||||
if (this._host.store.readonly || !this.resizeable$.peek()) return;
|
||||
|
||||
addParagraph(ctx);
|
||||
this._doc.deleteBlock(this._model);
|
||||
return true;
|
||||
},
|
||||
Enter: ctx => {
|
||||
if (this._host.store.readonly || !this._isSelected) return;
|
||||
if (this._host.store.readonly || !this.resizeable$.peek()) return;
|
||||
|
||||
addParagraph(ctx);
|
||||
return true;
|
||||
@@ -213,19 +218,6 @@ export class ImageBlockPageComponent extends WithDisposable(ShadowlessElement) {
|
||||
|
||||
private _handleSelection() {
|
||||
const selection = this._host.selection;
|
||||
this._disposables.add(
|
||||
selection.slots.changed.subscribe(selList => {
|
||||
this._isSelected = selList.some(
|
||||
sel => sel.blockId === this.block.blockId && sel.is(ImageSelection)
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
this._disposables.add(
|
||||
this._model.propsUpdated.subscribe(() => {
|
||||
this.requestUpdate();
|
||||
})
|
||||
);
|
||||
|
||||
this._disposables.addFromEvent(
|
||||
this.resizeImg,
|
||||
@@ -249,7 +241,7 @@ export class ImageBlockPageComponent extends WithDisposable(ShadowlessElement) {
|
||||
this.block.handleEvent(
|
||||
'click',
|
||||
() => {
|
||||
if (!this._isSelected) return;
|
||||
if (!this.resizeable$.peek()) return;
|
||||
|
||||
selection.update(selList =>
|
||||
selList.filter(
|
||||
@@ -356,7 +348,7 @@ export class ImageBlockPageComponent extends WithDisposable(ShadowlessElement) {
|
||||
override render() {
|
||||
const imageSize = this._normalizeImageSize();
|
||||
|
||||
const imageSelectedRect = this._isSelected
|
||||
const imageSelectedRect = this.resizeable$.value
|
||||
? ImageSelectedRect(this._doc.readonly)
|
||||
: null;
|
||||
|
||||
@@ -389,9 +381,6 @@ export class ImageBlockPageComponent extends WithDisposable(ShadowlessElement) {
|
||||
`;
|
||||
}
|
||||
|
||||
@state()
|
||||
accessor _isSelected = false;
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor block!: ImageBlockComponent;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import { getLoadingIconWith } from '@blocksuite/affine-components/icons';
|
||||
import { Peekable } from '@blocksuite/affine-components/peek';
|
||||
import { ResourceController } from '@blocksuite/affine-components/resource';
|
||||
import type { ImageBlockModel } from '@blocksuite/affine-model';
|
||||
import { ImageSelection } from '@blocksuite/affine-shared/selection';
|
||||
import {
|
||||
ThemeProvider,
|
||||
ToolbarRegistryIdentifier,
|
||||
@@ -30,6 +31,13 @@ import {
|
||||
enableOn: () => !IS_MOBILE,
|
||||
})
|
||||
export class ImageBlockComponent extends CaptionedBlockComponent<ImageBlockModel> {
|
||||
resizeable$ = computed(() =>
|
||||
this.std.selection.value.some(
|
||||
selection =>
|
||||
selection.is(ImageSelection) && selection.blockId === this.blockId
|
||||
)
|
||||
);
|
||||
|
||||
resourceController = new ResourceController(
|
||||
computed(() => this.model.props.sourceId$.value),
|
||||
'Image'
|
||||
@@ -104,7 +112,11 @@ export class ImageBlockComponent extends CaptionedBlockComponent<ImageBlockModel
|
||||
this.disposables.add(this.resourceController.subscribe());
|
||||
this.disposables.add(this.resourceController);
|
||||
|
||||
this.refreshData();
|
||||
this.disposables.add(
|
||||
this.model.props.sourceId$.subscribe(() => {
|
||||
this.refreshData();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
override firstUpdated() {
|
||||
|
||||
@@ -100,7 +100,11 @@ export class ImageEdgelessBlockComponent extends GfxBlockComponent<ImageBlockMod
|
||||
this.disposables.add(this.resourceController.subscribe());
|
||||
this.disposables.add(this.resourceController);
|
||||
|
||||
this.refreshData();
|
||||
this.disposables.add(
|
||||
this.model.props.sourceId$.subscribe(() => {
|
||||
this.refreshData();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
override renderGfxBlock() {
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
pasteMiddleware,
|
||||
replaceIdMiddleware,
|
||||
surfaceRefToEmbed,
|
||||
uploadMiddleware,
|
||||
} from '@blocksuite/affine-shared/adapters';
|
||||
import {
|
||||
clearAndSelectFirstModelCommand,
|
||||
@@ -34,14 +35,17 @@ export class PageClipboard extends ReadOnlyClipboard {
|
||||
// When pastina a surface-ref block to another doc
|
||||
const surfaceRefToEmbedMiddleware = surfaceRefToEmbed(this.std);
|
||||
const replaceId = replaceIdMiddleware(this.std.store.workspace.idGenerator);
|
||||
const upload = uploadMiddleware(this.std);
|
||||
this.std.clipboard.use(paste);
|
||||
this.std.clipboard.use(surfaceRefToEmbedMiddleware);
|
||||
this.std.clipboard.use(replaceId);
|
||||
this.std.clipboard.use(upload);
|
||||
this._disposables.add({
|
||||
dispose: () => {
|
||||
this.std.clipboard.unuse(paste);
|
||||
this.std.clipboard.unuse(surfaceRefToEmbedMiddleware);
|
||||
this.std.clipboard.unuse(replaceId);
|
||||
this.std.clipboard.unuse(upload);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user