mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-23 04:51:49 +08:00
feat(editor): support to copy in preview root block (#10214)
[BS-2590](https://linear.app/affine-design/issue/BS-2590/ai-chat-panel-的-copy-code-不-work-了) [BS-2550](https://linear.app/affine-design/issue/BS-2550/chat-panel-内的内容复制粘贴到-affine-编辑器时-时没办法保留格式)
This commit is contained in:
@@ -1,240 +1,2 @@
|
|||||||
import { deleteTextCommand } from '@blocksuite/affine-components/rich-text';
|
export * from './page-clipboard.js';
|
||||||
import {
|
export * from './readonly-clipboard.js';
|
||||||
AttachmentAdapter,
|
|
||||||
copyMiddleware,
|
|
||||||
HtmlAdapter,
|
|
||||||
ImageAdapter,
|
|
||||||
MixTextAdapter,
|
|
||||||
NotionTextAdapter,
|
|
||||||
pasteMiddleware,
|
|
||||||
} from '@blocksuite/affine-shared/adapters';
|
|
||||||
import {
|
|
||||||
clearAndSelectFirstModelCommand,
|
|
||||||
copySelectedModelsCommand,
|
|
||||||
deleteSelectedModelsCommand,
|
|
||||||
draftSelectedModelsCommand,
|
|
||||||
getBlockIndexCommand,
|
|
||||||
getBlockSelectionsCommand,
|
|
||||||
getImageSelectionsCommand,
|
|
||||||
getSelectedModelsCommand,
|
|
||||||
getTextSelectionCommand,
|
|
||||||
retainFirstModelCommand,
|
|
||||||
} from '@blocksuite/affine-shared/commands';
|
|
||||||
import type { BlockComponent, UIEventHandler } from '@blocksuite/block-std';
|
|
||||||
import { DisposableGroup } from '@blocksuite/global/utils';
|
|
||||||
import type { BlockSnapshot, Store } from '@blocksuite/store';
|
|
||||||
|
|
||||||
import {
|
|
||||||
defaultImageProxyMiddleware,
|
|
||||||
replaceIdMiddleware,
|
|
||||||
titleMiddleware,
|
|
||||||
} from '../../_common/transformers/middlewares.js';
|
|
||||||
import { ClipboardAdapter } from './adapter.js';
|
|
||||||
|
|
||||||
export class PageClipboard {
|
|
||||||
private readonly _copySelected = (onCopy?: () => void) => {
|
|
||||||
return this._std.command
|
|
||||||
.chain()
|
|
||||||
.with({ onCopy })
|
|
||||||
.pipe(getSelectedModelsCommand)
|
|
||||||
.pipe(draftSelectedModelsCommand)
|
|
||||||
.pipe(copySelectedModelsCommand);
|
|
||||||
};
|
|
||||||
|
|
||||||
protected _disposables = new DisposableGroup();
|
|
||||||
|
|
||||||
protected _init = () => {
|
|
||||||
this._std.clipboard.registerAdapter(
|
|
||||||
ClipboardAdapter.MIME,
|
|
||||||
ClipboardAdapter,
|
|
||||||
100
|
|
||||||
);
|
|
||||||
this._std.clipboard.registerAdapter(
|
|
||||||
'text/_notion-text-production',
|
|
||||||
NotionTextAdapter,
|
|
||||||
95
|
|
||||||
);
|
|
||||||
this._std.clipboard.registerAdapter('text/html', HtmlAdapter, 90);
|
|
||||||
[
|
|
||||||
'image/apng',
|
|
||||||
'image/avif',
|
|
||||||
'image/gif',
|
|
||||||
'image/jpeg',
|
|
||||||
'image/png',
|
|
||||||
'image/svg+xml',
|
|
||||||
'image/webp',
|
|
||||||
].forEach(type =>
|
|
||||||
this._std.clipboard.registerAdapter(type, ImageAdapter, 80)
|
|
||||||
);
|
|
||||||
this._std.clipboard.registerAdapter('text/plain', MixTextAdapter, 70);
|
|
||||||
this._std.clipboard.registerAdapter('*/*', AttachmentAdapter, 60);
|
|
||||||
const copy = copyMiddleware(this._std);
|
|
||||||
const paste = pasteMiddleware(this._std);
|
|
||||||
this._std.clipboard.use(copy);
|
|
||||||
this._std.clipboard.use(paste);
|
|
||||||
this._std.clipboard.use(
|
|
||||||
replaceIdMiddleware(this._std.store.workspace.idGenerator)
|
|
||||||
);
|
|
||||||
this._std.clipboard.use(
|
|
||||||
titleMiddleware(this._std.store.workspace.meta.docMetas)
|
|
||||||
);
|
|
||||||
this._std.clipboard.use(defaultImageProxyMiddleware);
|
|
||||||
|
|
||||||
this._disposables.add({
|
|
||||||
dispose: () => {
|
|
||||||
this._std.clipboard.unregisterAdapter(ClipboardAdapter.MIME);
|
|
||||||
this._std.clipboard.unregisterAdapter('text/plain');
|
|
||||||
[
|
|
||||||
'image/apng',
|
|
||||||
'image/avif',
|
|
||||||
'image/gif',
|
|
||||||
'image/jpeg',
|
|
||||||
'image/png',
|
|
||||||
'image/svg+xml',
|
|
||||||
'image/webp',
|
|
||||||
].forEach(type => this._std.clipboard.unregisterAdapter(type));
|
|
||||||
this._std.clipboard.unregisterAdapter('text/html');
|
|
||||||
this._std.clipboard.unregisterAdapter('*/*');
|
|
||||||
this._std.clipboard.unuse(copy);
|
|
||||||
this._std.clipboard.unuse(paste);
|
|
||||||
this._std.clipboard.unuse(
|
|
||||||
replaceIdMiddleware(this._std.store.workspace.idGenerator)
|
|
||||||
);
|
|
||||||
this._std.clipboard.unuse(
|
|
||||||
titleMiddleware(this._std.store.workspace.meta.docMetas)
|
|
||||||
);
|
|
||||||
this._std.clipboard.unuse(defaultImageProxyMiddleware);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
host: BlockComponent;
|
|
||||||
|
|
||||||
onBlockSnapshotPaste = async (
|
|
||||||
snapshot: BlockSnapshot,
|
|
||||||
doc: Store,
|
|
||||||
parent?: string,
|
|
||||||
index?: number
|
|
||||||
) => {
|
|
||||||
const block = await this._std.clipboard.pasteBlockSnapshot(
|
|
||||||
snapshot,
|
|
||||||
doc,
|
|
||||||
parent,
|
|
||||||
index
|
|
||||||
);
|
|
||||||
return block?.id ?? null;
|
|
||||||
};
|
|
||||||
|
|
||||||
onPageCopy: UIEventHandler = ctx => {
|
|
||||||
const e = ctx.get('clipboardState').raw;
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
this._copySelected().run();
|
|
||||||
};
|
|
||||||
|
|
||||||
onPageCut: UIEventHandler = ctx => {
|
|
||||||
const e = ctx.get('clipboardState').raw;
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
this._copySelected(() => {
|
|
||||||
this._std.command
|
|
||||||
.chain()
|
|
||||||
.try<{}>(cmd => [
|
|
||||||
cmd.pipe(getTextSelectionCommand).pipe(deleteTextCommand),
|
|
||||||
cmd.pipe(getSelectedModelsCommand).pipe(deleteSelectedModelsCommand),
|
|
||||||
])
|
|
||||||
.run();
|
|
||||||
}).run();
|
|
||||||
};
|
|
||||||
|
|
||||||
onPagePaste: UIEventHandler = ctx => {
|
|
||||||
const e = ctx.get('clipboardState').raw;
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
this._std.store.captureSync();
|
|
||||||
this._std.command
|
|
||||||
.chain()
|
|
||||||
.try(cmd => [
|
|
||||||
cmd.pipe(getTextSelectionCommand),
|
|
||||||
cmd
|
|
||||||
.pipe(getSelectedModelsCommand)
|
|
||||||
.pipe(clearAndSelectFirstModelCommand)
|
|
||||||
.pipe(retainFirstModelCommand)
|
|
||||||
.pipe(deleteSelectedModelsCommand),
|
|
||||||
])
|
|
||||||
.try<{ currentSelectionPath: string }>(cmd => [
|
|
||||||
cmd.pipe(getTextSelectionCommand).pipe((ctx, next) => {
|
|
||||||
const textSelection = ctx.currentTextSelection;
|
|
||||||
if (!textSelection) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
next({ currentSelectionPath: textSelection.from.blockId });
|
|
||||||
}),
|
|
||||||
cmd.pipe(getBlockSelectionsCommand).pipe((ctx, next) => {
|
|
||||||
const currentBlockSelections = ctx.currentBlockSelections;
|
|
||||||
if (!currentBlockSelections) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const blockSelection = currentBlockSelections.at(-1);
|
|
||||||
if (!blockSelection) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
next({ currentSelectionPath: blockSelection.blockId });
|
|
||||||
}),
|
|
||||||
cmd.pipe(getImageSelectionsCommand).pipe((ctx, next) => {
|
|
||||||
const currentImageSelections = ctx.currentImageSelections;
|
|
||||||
if (!currentImageSelections) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const imageSelection = currentImageSelections.at(-1);
|
|
||||||
if (!imageSelection) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
next({ currentSelectionPath: imageSelection.blockId });
|
|
||||||
}),
|
|
||||||
])
|
|
||||||
.pipe(getBlockIndexCommand)
|
|
||||||
.pipe((ctx, next) => {
|
|
||||||
if (!ctx.parentBlock) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._std.clipboard
|
|
||||||
.paste(
|
|
||||||
e,
|
|
||||||
this._std.store,
|
|
||||||
ctx.parentBlock.model.id,
|
|
||||||
ctx.blockIndex ? ctx.blockIndex + 1 : 1
|
|
||||||
)
|
|
||||||
.catch(console.error);
|
|
||||||
|
|
||||||
return next();
|
|
||||||
})
|
|
||||||
.run();
|
|
||||||
};
|
|
||||||
|
|
||||||
private get _std() {
|
|
||||||
return this.host.std;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(host: BlockComponent) {
|
|
||||||
this.host = host;
|
|
||||||
}
|
|
||||||
|
|
||||||
hostConnected() {
|
|
||||||
if (this._disposables.disposed) {
|
|
||||||
this._disposables = new DisposableGroup();
|
|
||||||
}
|
|
||||||
if (navigator.clipboard) {
|
|
||||||
this.host.handleEvent('copy', this.onPageCopy);
|
|
||||||
this.host.handleEvent('paste', this.onPagePaste);
|
|
||||||
this.host.handleEvent('cut', this.onPageCut);
|
|
||||||
this._init();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hostDisconnected() {
|
|
||||||
this._disposables.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export { copyMiddleware, pasteMiddleware };
|
|
||||||
|
|||||||
@@ -0,0 +1,133 @@
|
|||||||
|
import { deleteTextCommand } from '@blocksuite/affine-components/rich-text';
|
||||||
|
import {
|
||||||
|
clearAndSelectFirstModelCommand,
|
||||||
|
deleteSelectedModelsCommand,
|
||||||
|
getBlockIndexCommand,
|
||||||
|
getBlockSelectionsCommand,
|
||||||
|
getImageSelectionsCommand,
|
||||||
|
getSelectedModelsCommand,
|
||||||
|
getTextSelectionCommand,
|
||||||
|
retainFirstModelCommand,
|
||||||
|
} from '@blocksuite/affine-shared/commands';
|
||||||
|
import type { UIEventHandler } from '@blocksuite/block-std';
|
||||||
|
import { DisposableGroup } from '@blocksuite/global/utils';
|
||||||
|
import type { BlockSnapshot, Store } from '@blocksuite/store';
|
||||||
|
|
||||||
|
import { ReadOnlyClipboard } from './readonly-clipboard';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PageClipboard is a class that provides a clipboard for the page root block.
|
||||||
|
* It is supported to copy and paste models in the page root block.
|
||||||
|
*/
|
||||||
|
export class PageClipboard extends ReadOnlyClipboard {
|
||||||
|
protected _init = () => {
|
||||||
|
this._initAdapters();
|
||||||
|
};
|
||||||
|
|
||||||
|
onBlockSnapshotPaste = async (
|
||||||
|
snapshot: BlockSnapshot,
|
||||||
|
doc: Store,
|
||||||
|
parent?: string,
|
||||||
|
index?: number
|
||||||
|
) => {
|
||||||
|
const block = await this._std.clipboard.pasteBlockSnapshot(
|
||||||
|
snapshot,
|
||||||
|
doc,
|
||||||
|
parent,
|
||||||
|
index
|
||||||
|
);
|
||||||
|
return block?.id ?? null;
|
||||||
|
};
|
||||||
|
|
||||||
|
onPageCut: UIEventHandler = ctx => {
|
||||||
|
const e = ctx.get('clipboardState').raw;
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
this._copySelected(() => {
|
||||||
|
this._std.command
|
||||||
|
.chain()
|
||||||
|
.try<{}>(cmd => [
|
||||||
|
cmd.pipe(getTextSelectionCommand).pipe(deleteTextCommand),
|
||||||
|
cmd.pipe(getSelectedModelsCommand).pipe(deleteSelectedModelsCommand),
|
||||||
|
])
|
||||||
|
.run();
|
||||||
|
}).run();
|
||||||
|
};
|
||||||
|
|
||||||
|
onPagePaste: UIEventHandler = ctx => {
|
||||||
|
const e = ctx.get('clipboardState').raw;
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
this._std.store.captureSync();
|
||||||
|
this._std.command
|
||||||
|
.chain()
|
||||||
|
.try(cmd => [
|
||||||
|
cmd.pipe(getTextSelectionCommand),
|
||||||
|
cmd
|
||||||
|
.pipe(getSelectedModelsCommand)
|
||||||
|
.pipe(clearAndSelectFirstModelCommand)
|
||||||
|
.pipe(retainFirstModelCommand)
|
||||||
|
.pipe(deleteSelectedModelsCommand),
|
||||||
|
])
|
||||||
|
.try<{ currentSelectionPath: string }>(cmd => [
|
||||||
|
cmd.pipe(getTextSelectionCommand).pipe((ctx, next) => {
|
||||||
|
const textSelection = ctx.currentTextSelection;
|
||||||
|
if (!textSelection) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
next({ currentSelectionPath: textSelection.from.blockId });
|
||||||
|
}),
|
||||||
|
cmd.pipe(getBlockSelectionsCommand).pipe((ctx, next) => {
|
||||||
|
const currentBlockSelections = ctx.currentBlockSelections;
|
||||||
|
if (!currentBlockSelections) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const blockSelection = currentBlockSelections.at(-1);
|
||||||
|
if (!blockSelection) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
next({ currentSelectionPath: blockSelection.blockId });
|
||||||
|
}),
|
||||||
|
cmd.pipe(getImageSelectionsCommand).pipe((ctx, next) => {
|
||||||
|
const currentImageSelections = ctx.currentImageSelections;
|
||||||
|
if (!currentImageSelections) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const imageSelection = currentImageSelections.at(-1);
|
||||||
|
if (!imageSelection) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
next({ currentSelectionPath: imageSelection.blockId });
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
.pipe(getBlockIndexCommand)
|
||||||
|
.pipe((ctx, next) => {
|
||||||
|
if (!ctx.parentBlock) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._std.clipboard
|
||||||
|
.paste(
|
||||||
|
e,
|
||||||
|
this._std.store,
|
||||||
|
ctx.parentBlock.model.id,
|
||||||
|
ctx.blockIndex ? ctx.blockIndex + 1 : 1
|
||||||
|
)
|
||||||
|
.catch(console.error);
|
||||||
|
|
||||||
|
return next();
|
||||||
|
})
|
||||||
|
.run();
|
||||||
|
};
|
||||||
|
|
||||||
|
override hostConnected() {
|
||||||
|
if (this._disposables.disposed) {
|
||||||
|
this._disposables = new DisposableGroup();
|
||||||
|
}
|
||||||
|
if (navigator.clipboard) {
|
||||||
|
this.host.handleEvent('copy', this.onPageCopy);
|
||||||
|
this.host.handleEvent('paste', this.onPagePaste);
|
||||||
|
this.host.handleEvent('cut', this.onPageCut);
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
import {
|
||||||
|
AttachmentAdapter,
|
||||||
|
copyMiddleware,
|
||||||
|
HtmlAdapter,
|
||||||
|
ImageAdapter,
|
||||||
|
MixTextAdapter,
|
||||||
|
NotionTextAdapter,
|
||||||
|
pasteMiddleware,
|
||||||
|
} from '@blocksuite/affine-shared/adapters';
|
||||||
|
import {
|
||||||
|
copySelectedModelsCommand,
|
||||||
|
draftSelectedModelsCommand,
|
||||||
|
getSelectedModelsCommand,
|
||||||
|
} from '@blocksuite/affine-shared/commands';
|
||||||
|
import type { BlockComponent, UIEventHandler } from '@blocksuite/block-std';
|
||||||
|
import { DisposableGroup } from '@blocksuite/global/utils';
|
||||||
|
|
||||||
|
import {
|
||||||
|
defaultImageProxyMiddleware,
|
||||||
|
replaceIdMiddleware,
|
||||||
|
titleMiddleware,
|
||||||
|
} from '../../_common/transformers/middlewares.js';
|
||||||
|
import { ClipboardAdapter } from './adapter.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ReadOnlyClipboard is a class that provides a read-only clipboard for the root block.
|
||||||
|
* It is supported to copy models in the root block.
|
||||||
|
*/
|
||||||
|
export class ReadOnlyClipboard {
|
||||||
|
protected readonly _copySelected = (onCopy?: () => void) => {
|
||||||
|
return this._std.command
|
||||||
|
.chain()
|
||||||
|
.with({ onCopy })
|
||||||
|
.pipe(getSelectedModelsCommand)
|
||||||
|
.pipe(draftSelectedModelsCommand)
|
||||||
|
.pipe(copySelectedModelsCommand);
|
||||||
|
};
|
||||||
|
|
||||||
|
protected _disposables = new DisposableGroup();
|
||||||
|
|
||||||
|
protected _initAdapters = () => {
|
||||||
|
this._std.clipboard.registerAdapter(
|
||||||
|
ClipboardAdapter.MIME,
|
||||||
|
ClipboardAdapter,
|
||||||
|
100
|
||||||
|
);
|
||||||
|
this._std.clipboard.registerAdapter(
|
||||||
|
'text/_notion-text-production',
|
||||||
|
NotionTextAdapter,
|
||||||
|
95
|
||||||
|
);
|
||||||
|
this._std.clipboard.registerAdapter('text/html', HtmlAdapter, 90);
|
||||||
|
[
|
||||||
|
'image/apng',
|
||||||
|
'image/avif',
|
||||||
|
'image/gif',
|
||||||
|
'image/jpeg',
|
||||||
|
'image/png',
|
||||||
|
'image/svg+xml',
|
||||||
|
'image/webp',
|
||||||
|
].forEach(type =>
|
||||||
|
this._std.clipboard.registerAdapter(type, ImageAdapter, 80)
|
||||||
|
);
|
||||||
|
this._std.clipboard.registerAdapter('text/plain', MixTextAdapter, 70);
|
||||||
|
this._std.clipboard.registerAdapter('*/*', AttachmentAdapter, 60);
|
||||||
|
const copy = copyMiddleware(this._std);
|
||||||
|
const paste = pasteMiddleware(this._std);
|
||||||
|
this._std.clipboard.use(copy);
|
||||||
|
this._std.clipboard.use(paste);
|
||||||
|
this._std.clipboard.use(
|
||||||
|
replaceIdMiddleware(this._std.store.workspace.idGenerator)
|
||||||
|
);
|
||||||
|
this._std.clipboard.use(
|
||||||
|
titleMiddleware(this._std.store.workspace.meta.docMetas)
|
||||||
|
);
|
||||||
|
this._std.clipboard.use(defaultImageProxyMiddleware);
|
||||||
|
|
||||||
|
this._disposables.add({
|
||||||
|
dispose: () => {
|
||||||
|
this._std.clipboard.unregisterAdapter(ClipboardAdapter.MIME);
|
||||||
|
this._std.clipboard.unregisterAdapter('text/plain');
|
||||||
|
[
|
||||||
|
'image/apng',
|
||||||
|
'image/avif',
|
||||||
|
'image/gif',
|
||||||
|
'image/jpeg',
|
||||||
|
'image/png',
|
||||||
|
'image/svg+xml',
|
||||||
|
'image/webp',
|
||||||
|
].forEach(type => this._std.clipboard.unregisterAdapter(type));
|
||||||
|
this._std.clipboard.unregisterAdapter('text/html');
|
||||||
|
this._std.clipboard.unregisterAdapter('*/*');
|
||||||
|
this._std.clipboard.unuse(copy);
|
||||||
|
this._std.clipboard.unuse(paste);
|
||||||
|
this._std.clipboard.unuse(
|
||||||
|
replaceIdMiddleware(this._std.store.workspace.idGenerator)
|
||||||
|
);
|
||||||
|
this._std.clipboard.unuse(
|
||||||
|
titleMiddleware(this._std.store.workspace.meta.docMetas)
|
||||||
|
);
|
||||||
|
this._std.clipboard.unuse(defaultImageProxyMiddleware);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
host: BlockComponent;
|
||||||
|
|
||||||
|
onPageCopy: UIEventHandler = ctx => {
|
||||||
|
const e = ctx.get('clipboardState').raw;
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
this._copySelected().run();
|
||||||
|
};
|
||||||
|
|
||||||
|
protected get _std() {
|
||||||
|
return this.host.std;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(host: BlockComponent) {
|
||||||
|
this.host = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
hostConnected() {
|
||||||
|
if (this._disposables.disposed) {
|
||||||
|
this._disposables = new DisposableGroup();
|
||||||
|
}
|
||||||
|
if (navigator.clipboard) {
|
||||||
|
this.host.handleEvent('copy', this.onPageCopy);
|
||||||
|
this._initAdapters();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hostDisconnected() {
|
||||||
|
this._disposables.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { copyMiddleware, pasteMiddleware };
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
// import { PageRootBlockComponent } from '../page/page-root-block.js';
|
|
||||||
import { BlockComponent } from '@blocksuite/block-std';
|
import { BlockComponent } from '@blocksuite/block-std';
|
||||||
import { css, html } from 'lit';
|
import { css, html } from 'lit';
|
||||||
|
|
||||||
|
import { ReadOnlyClipboard } from '../clipboard/readonly-clipboard';
|
||||||
|
|
||||||
export class PreviewRootBlockComponent extends BlockComponent {
|
export class PreviewRootBlockComponent extends BlockComponent {
|
||||||
static override styles = css`
|
static override styles = css`
|
||||||
affine-preview-root {
|
affine-preview-root {
|
||||||
@@ -9,6 +10,18 @@ export class PreviewRootBlockComponent extends BlockComponent {
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
clipboardController = new ReadOnlyClipboard(this);
|
||||||
|
|
||||||
|
override connectedCallback() {
|
||||||
|
super.connectedCallback();
|
||||||
|
this.clipboardController.hostConnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
override disconnectedCallback() {
|
||||||
|
super.disconnectedCallback();
|
||||||
|
this.clipboardController.hostDisconnected();
|
||||||
|
}
|
||||||
|
|
||||||
override renderBlock() {
|
override renderBlock() {
|
||||||
return html`<div class="affine-preview-root">
|
return html`<div class="affine-preview-root">
|
||||||
${this.host.renderChildren(this.model)}
|
${this.host.renderChildren(this.model)}
|
||||||
|
|||||||
Reference in New Issue
Block a user