feat: dnd image preview && edgeless dnd preview issue (#10177)
### Changed - Add new image block to render dnd preview - Fixed the bug that dragging uploaded image does not have width and height - Fixed the bug that drag image block from page to edgeless does not have width and height - Better edgeless dnd preview
This commit is contained in:
@@ -2,10 +2,20 @@ import { ImageBlockFallbackCard } from './components/image-block-fallback.js';
|
|||||||
import { ImageBlockPageComponent } from './components/page-image-block.js';
|
import { ImageBlockPageComponent } from './components/page-image-block.js';
|
||||||
import { ImageBlockComponent } from './image-block.js';
|
import { ImageBlockComponent } from './image-block.js';
|
||||||
import { ImageEdgelessBlockComponent } from './image-edgeless-block.js';
|
import { ImageEdgelessBlockComponent } from './image-edgeless-block.js';
|
||||||
|
import { ImageEdgelessPlaceholderBlockComponent } from './preview-image/edgeless.js';
|
||||||
|
import { ImagePlaceholderBlockComponent } from './preview-image/page.js';
|
||||||
|
|
||||||
export function effects() {
|
export function effects() {
|
||||||
customElements.define('affine-image', ImageBlockComponent);
|
customElements.define('affine-image', ImageBlockComponent);
|
||||||
customElements.define('affine-edgeless-image', ImageEdgelessBlockComponent);
|
customElements.define('affine-edgeless-image', ImageEdgelessBlockComponent);
|
||||||
customElements.define('affine-page-image', ImageBlockPageComponent);
|
customElements.define('affine-page-image', ImageBlockPageComponent);
|
||||||
customElements.define('affine-image-fallback-card', ImageBlockFallbackCard);
|
customElements.define('affine-image-fallback-card', ImageBlockFallbackCard);
|
||||||
|
customElements.define(
|
||||||
|
'affine-placeholder-preview-image',
|
||||||
|
ImagePlaceholderBlockComponent
|
||||||
|
);
|
||||||
|
customElements.define(
|
||||||
|
'affine-edgeless-placeholder-preview-image',
|
||||||
|
ImageEdgelessPlaceholderBlockComponent
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ export class ImageEdgelessBlockComponent extends GfxBlockComponent<ImageBlockMod
|
|||||||
fetchImageBlob(this)
|
fetchImageBlob(this)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const { width, height } = this.model;
|
const { width, height } = this.model;
|
||||||
if (!width || !height) {
|
if ((!width || !height) && this.blob) {
|
||||||
return resetImageSize(this);
|
return resetImageSize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
25
blocksuite/affine/block-image/src/preview-image/edgeless.ts
Normal file
25
blocksuite/affine/block-image/src/preview-image/edgeless.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { toGfxBlockComponent } from '@blocksuite/block-std';
|
||||||
|
import { css } from 'lit';
|
||||||
|
|
||||||
|
import { ImagePlaceholderBlockComponent } from './page.js';
|
||||||
|
|
||||||
|
export class ImageEdgelessPlaceholderBlockComponent extends toGfxBlockComponent(
|
||||||
|
ImagePlaceholderBlockComponent
|
||||||
|
) {
|
||||||
|
static override styles = css`
|
||||||
|
affine-edgeless-placeholder-preview-image
|
||||||
|
.affine-placeholder-preview-container {
|
||||||
|
border: 1px solid var(--affine-background-tertiary-color);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
override renderGfxBlock(): unknown {
|
||||||
|
return super.renderGfxBlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'affine-edgeless-placeholder-preview-image': ImageEdgelessPlaceholderBlockComponent;
|
||||||
|
}
|
||||||
|
}
|
||||||
58
blocksuite/affine/block-image/src/preview-image/page.ts
Normal file
58
blocksuite/affine/block-image/src/preview-image/page.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import type { ImageBlockModel } from '@blocksuite/affine-model';
|
||||||
|
import { unsafeCSSVarV2 } from '@blocksuite/affine-shared/theme';
|
||||||
|
import { BlockComponent } from '@blocksuite/block-std';
|
||||||
|
import { ImageIcon } from '@blocksuite/icons/lit';
|
||||||
|
import { css, html } from 'lit';
|
||||||
|
|
||||||
|
export class ImagePlaceholderBlockComponent extends BlockComponent<ImageBlockModel> {
|
||||||
|
static override styles = css`
|
||||||
|
.affine-placeholder-preview-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
padding: 4px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: ${unsafeCSSVarV2(
|
||||||
|
'layer/background/overlayPanel',
|
||||||
|
'#FBFBFC'
|
||||||
|
)};
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder-preview-content {
|
||||||
|
padding: 4px 16px;
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder-preview-content > svg {
|
||||||
|
color: ${unsafeCSSVarV2('icon/primary', '#77757D')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder-preview-content > .text {
|
||||||
|
color: var(--affine-text-primary-color);
|
||||||
|
color: ${unsafeCSSVarV2('text/primary', '#121212')};
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
override renderBlock() {
|
||||||
|
return html`<div
|
||||||
|
class="affine-placeholder-preview-container"
|
||||||
|
contenteditable="false"
|
||||||
|
>
|
||||||
|
<div class="placeholder-preview-content">
|
||||||
|
${ImageIcon({ width: '24px', height: '24px' })}
|
||||||
|
<span class="text">Image Block</span>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'affine-placeholder-preview-image': ImagePlaceholderBlockComponent;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -68,15 +68,30 @@ export async function uploadBlobForImage(
|
|||||||
setImageUploaded(blockId);
|
setImageUploaded(blockId);
|
||||||
|
|
||||||
const imageModel = doc.getBlockById(blockId) as ImageBlockModel | null;
|
const imageModel = doc.getBlockById(blockId) as ImageBlockModel | null;
|
||||||
|
if (sourceId && imageModel) {
|
||||||
doc.withoutTransact(() => {
|
const props: Partial<ImageBlockProps> = {
|
||||||
if (!imageModel) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
doc.updateBlock(imageModel, {
|
|
||||||
sourceId,
|
sourceId,
|
||||||
} satisfies Partial<ImageBlockProps>);
|
// Assign a default size to make sure the image can be displayed correctly.
|
||||||
});
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
};
|
||||||
|
|
||||||
|
const blob = await doc.blobSync.get(sourceId);
|
||||||
|
if (blob) {
|
||||||
|
try {
|
||||||
|
const size = await readImageSize(blob);
|
||||||
|
props.width = size.width;
|
||||||
|
props.height = size.height;
|
||||||
|
} catch {
|
||||||
|
// Ignore the error
|
||||||
|
console.warn('Failed to read image size');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
doc.withoutTransact(() => {
|
||||||
|
doc.updateBlock(imageModel, props);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,10 +213,19 @@ export async function resetImageSize(
|
|||||||
|
|
||||||
const file = new File([blob], 'image.png', { type: blob.type });
|
const file = new File([blob], 'image.png', { type: blob.type });
|
||||||
const size = await readImageSize(file);
|
const size = await readImageSize(file);
|
||||||
block.doc.updateBlock(model, {
|
const bound = model.elementBound;
|
||||||
|
const props: Partial<ImageBlockProps> = {
|
||||||
width: size.width,
|
width: size.width,
|
||||||
height: size.height,
|
height: size.height,
|
||||||
});
|
};
|
||||||
|
|
||||||
|
if (!bound.w || !bound.h) {
|
||||||
|
bound.w = size.width;
|
||||||
|
bound.h = size.height;
|
||||||
|
props.xywh = bound.serialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
block.doc.updateBlock(model, props);
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertToPng(blob: Blob): Promise<Blob | null> {
|
function convertToPng(blob: Blob): Promise<Blob | null> {
|
||||||
@@ -401,7 +425,7 @@ export async function turnImageIntoCardView(
|
|||||||
transformModel(model, 'affine:attachment', attachmentProp);
|
transformModel(model, 'affine:attachment', attachmentProp);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function readImageSize(file: File) {
|
export function readImageSize(file: File | Blob) {
|
||||||
return new Promise<{ width: number; height: number }>(resolve => {
|
return new Promise<{ width: number; height: number }>(resolve => {
|
||||||
const size = { width: 0, height: 0 };
|
const size = { width: 0, height: 0 };
|
||||||
const img = new Image();
|
const img = new Image();
|
||||||
|
|||||||
@@ -1,24 +1,37 @@
|
|||||||
|
import { SurfaceBlockModel } from '@blocksuite/affine-block-surface';
|
||||||
|
import { RootBlockModel } from '@blocksuite/affine-model';
|
||||||
import {
|
import {
|
||||||
DocModeExtension,
|
DocModeExtension,
|
||||||
DocModeProvider,
|
DocModeProvider,
|
||||||
EditorSettingExtension,
|
EditorSettingExtension,
|
||||||
EditorSettingProvider,
|
EditorSettingProvider,
|
||||||
} from '@blocksuite/affine-shared/services';
|
} from '@blocksuite/affine-shared/services';
|
||||||
import { SpecProvider } from '@blocksuite/affine-shared/utils';
|
import { matchModels, SpecProvider } from '@blocksuite/affine-shared/utils';
|
||||||
import { BlockStdScope, LifeCycleWatcher } from '@blocksuite/block-std';
|
|
||||||
import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx';
|
|
||||||
import {
|
import {
|
||||||
type BlockViewType,
|
type BlockComponent,
|
||||||
type Query,
|
BlockStdScope,
|
||||||
type SliceSnapshot,
|
BlockViewIdentifier,
|
||||||
|
LifeCycleWatcher,
|
||||||
|
} from '@blocksuite/block-std';
|
||||||
|
import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx';
|
||||||
|
import type {
|
||||||
|
BlockModel,
|
||||||
|
BlockViewType,
|
||||||
|
ExtensionType,
|
||||||
|
Query,
|
||||||
|
SliceSnapshot,
|
||||||
} from '@blocksuite/store';
|
} from '@blocksuite/store';
|
||||||
import { signal } from '@preact/signals-core';
|
import { signal } from '@preact/signals-core';
|
||||||
|
import { literal } from 'lit/static-html.js';
|
||||||
|
|
||||||
import type { AffineDragHandleWidget } from '../drag-handle.js';
|
import type { AffineDragHandleWidget } from '../drag-handle.js';
|
||||||
import { getSnapshotRect } from '../utils.js';
|
import { getSnapshotRect } from '../utils.js';
|
||||||
|
|
||||||
export class PreviewHelper {
|
export class PreviewHelper {
|
||||||
private readonly _calculateQuery = (selectedIds: string[]): Query => {
|
private readonly _calculateQuery = (
|
||||||
|
selectedIds: string[],
|
||||||
|
mode: 'page' | 'edgeless'
|
||||||
|
): Query => {
|
||||||
const ids: Array<{ id: string; viewType: BlockViewType }> = selectedIds.map(
|
const ids: Array<{ id: string; viewType: BlockViewType }> = selectedIds.map(
|
||||||
id => ({
|
id => ({
|
||||||
id,
|
id,
|
||||||
@@ -39,11 +52,28 @@ export class PreviewHelper {
|
|||||||
|
|
||||||
// The children of the selected blocks should be rendered as Display
|
// The children of the selected blocks should be rendered as Display
|
||||||
const addChildren = (id: string) => {
|
const addChildren = (id: string) => {
|
||||||
const children = this.widget.doc.getBlock(id)?.model.children ?? [];
|
const model = this.widget.doc.getBlock(id)?.model;
|
||||||
children.forEach(child => {
|
if (!model) {
|
||||||
ids.push({ viewType: 'display', id: child.id });
|
return;
|
||||||
addChildren(child.id);
|
}
|
||||||
});
|
|
||||||
|
const children = model.children ?? [];
|
||||||
|
if (
|
||||||
|
mode === 'edgeless' &&
|
||||||
|
matchModels(model, [RootBlockModel, SurfaceBlockModel])
|
||||||
|
) {
|
||||||
|
children.forEach(child => {
|
||||||
|
if (selectedIds.includes(child.id)) {
|
||||||
|
ids.push({ viewType: 'display', id: child.id });
|
||||||
|
addChildren(child.id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
children.forEach(child => {
|
||||||
|
ids.push({ viewType: 'display', id: child.id });
|
||||||
|
addChildren(child.id);
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
selectedIds.forEach(addChildren);
|
selectedIds.forEach(addChildren);
|
||||||
|
|
||||||
@@ -61,23 +91,42 @@ export class PreviewHelper {
|
|||||||
const widget = this.widget;
|
const widget = this.widget;
|
||||||
const std = widget.std;
|
const std = widget.std;
|
||||||
const sourceGfx = std.get(GfxControllerIdentifier);
|
const sourceGfx = std.get(GfxControllerIdentifier);
|
||||||
|
const isEdgeless = mode === 'edgeless';
|
||||||
|
blockIds = blockIds.slice();
|
||||||
|
|
||||||
|
if (isEdgeless) {
|
||||||
|
blockIds.push(sourceGfx.surface!.id, std.store.root!.id);
|
||||||
|
}
|
||||||
|
|
||||||
const docModeService = std.get(DocModeProvider);
|
const docModeService = std.get(DocModeProvider);
|
||||||
const editorSetting = std.get(EditorSettingProvider).peek();
|
const editorSetting = std.get(EditorSettingProvider).peek();
|
||||||
const query = this._calculateQuery(blockIds as string[]);
|
const query = this._calculateQuery(blockIds as string[], mode);
|
||||||
const store = widget.doc.doc.getStore({ query });
|
const store = widget.doc.doc.getStore({ query });
|
||||||
const previewSpec = SpecProvider.getInstance().getSpec(
|
const previewSpec = SpecProvider.getInstance().getSpec(
|
||||||
mode === 'edgeless' ? 'edgeless:preview' : 'page:preview'
|
isEdgeless ? 'edgeless:preview' : 'page:preview'
|
||||||
);
|
);
|
||||||
const settingSignal = signal({ ...editorSetting });
|
const settingSignal = signal({ ...editorSetting });
|
||||||
const extensions = [
|
const extensions = [
|
||||||
DocModeExtension(docModeService),
|
DocModeExtension(docModeService),
|
||||||
EditorSettingExtension(settingSignal),
|
EditorSettingExtension(settingSignal),
|
||||||
|
{
|
||||||
|
setup(di) {
|
||||||
|
di.override(BlockViewIdentifier('affine:image'), () => {
|
||||||
|
return (model: BlockModel) => {
|
||||||
|
const parent = model.doc.getParent(model.id);
|
||||||
|
|
||||||
|
if (parent?.flavour === 'affine:surface') {
|
||||||
|
return literal`affine-edgeless-placeholder-preview-image`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return literal`affine-placeholder-preview-image`;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
} as ExtensionType,
|
||||||
];
|
];
|
||||||
|
|
||||||
if (mode === 'edgeless') {
|
if (isEdgeless) {
|
||||||
if (!blockIds.includes(sourceGfx.surface!.id)) {
|
|
||||||
blockIds.push(sourceGfx.surface!.id);
|
|
||||||
}
|
|
||||||
class PreviewViewportInitializer extends LifeCycleWatcher {
|
class PreviewViewportInitializer extends LifeCycleWatcher {
|
||||||
static override key = 'preview-viewport-initializer';
|
static override key = 'preview-viewport-initializer';
|
||||||
|
|
||||||
@@ -91,9 +140,11 @@ export class PreviewHelper {
|
|||||||
if (payload.view.model.flavour === 'affine:page') {
|
if (payload.view.model.flavour === 'affine:page') {
|
||||||
const gfx = this.std.get(GfxControllerIdentifier);
|
const gfx = this.std.get(GfxControllerIdentifier);
|
||||||
|
|
||||||
queueMicrotask(() => {
|
(
|
||||||
gfx.viewport.setViewportByBound(rect);
|
payload.view as BlockComponent & { overrideBackground: string }
|
||||||
});
|
).overrideBackground = 'transparent';
|
||||||
|
|
||||||
|
gfx.viewport.setViewportByBound(rect);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -116,11 +167,9 @@ export class PreviewHelper {
|
|||||||
|
|
||||||
let width: number = 500;
|
let width: number = 500;
|
||||||
let height;
|
let height;
|
||||||
|
let scale = 1;
|
||||||
|
|
||||||
if (mode === 'page') {
|
if (isEdgeless) {
|
||||||
const noteBlock = this.widget.host.querySelector('affine-note');
|
|
||||||
width = noteBlock?.offsetWidth ?? noteBlock?.clientWidth ?? 500;
|
|
||||||
} else {
|
|
||||||
const rect = getSnapshotRect(snapshot);
|
const rect = getSnapshotRect(snapshot);
|
||||||
if (rect) {
|
if (rect) {
|
||||||
width = rect.w;
|
width = rect.w;
|
||||||
@@ -128,9 +177,14 @@ export class PreviewHelper {
|
|||||||
} else {
|
} else {
|
||||||
height = 500;
|
height = 500;
|
||||||
}
|
}
|
||||||
|
scale = sourceGfx.viewport.zoom;
|
||||||
|
} else {
|
||||||
|
const noteBlock = this.widget.host.querySelector('affine-note');
|
||||||
|
width = noteBlock?.offsetWidth ?? noteBlock?.clientWidth ?? 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
scale,
|
||||||
previewStd,
|
previewStd,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
@@ -144,13 +198,14 @@ export class PreviewHelper {
|
|||||||
mode: 'page' | 'edgeless';
|
mode: 'page' | 'edgeless';
|
||||||
}): void => {
|
}): void => {
|
||||||
const { blockIds, snapshot, container, mode } = options;
|
const { blockIds, snapshot, container, mode } = options;
|
||||||
const { previewStd, width, height } = this.getPreviewStd(
|
const { previewStd, width, height, scale } = this.getPreviewStd(
|
||||||
blockIds,
|
blockIds,
|
||||||
snapshot,
|
snapshot,
|
||||||
mode
|
mode
|
||||||
);
|
);
|
||||||
const previewTemplate = previewStd.render();
|
const previewTemplate = previewStd.render();
|
||||||
|
|
||||||
|
container.style.transform = `scale(${scale})`;
|
||||||
container.style.width = `${width}px`;
|
container.style.width = `${width}px`;
|
||||||
if (height) {
|
if (height) {
|
||||||
container.style.height = `${height}px`;
|
container.style.height = `${height}px`;
|
||||||
|
|||||||
@@ -349,11 +349,12 @@ export class DragEventWatcher {
|
|||||||
|
|
||||||
return selectedElements;
|
return selectedElements;
|
||||||
};
|
};
|
||||||
const toSnapshotRequiredBlocks = (models: string[]) => {
|
const toSnapshotRequiredBlocks = (selectedModels: string[]) => {
|
||||||
let surfaceAdded = false;
|
let surfaceAdded = false;
|
||||||
const blocks: BlockModel[] = [];
|
const blocks: BlockModel[] = [];
|
||||||
|
const blocksUnderSurface: BlockModel[] = [];
|
||||||
|
|
||||||
models.forEach(id => {
|
selectedModels.forEach(id => {
|
||||||
const model = this.gfx.getElementById(id);
|
const model = this.gfx.getElementById(id);
|
||||||
|
|
||||||
if (!model) {
|
if (!model) {
|
||||||
@@ -368,16 +369,19 @@ export class DragEventWatcher {
|
|||||||
const parentModel = this.std.store.getParent(model);
|
const parentModel = this.std.store.getParent(model);
|
||||||
|
|
||||||
if (matchModels(parentModel, [SurfaceBlockModel])) {
|
if (matchModels(parentModel, [SurfaceBlockModel])) {
|
||||||
if (surfaceAdded) return;
|
blocksUnderSurface.push(model);
|
||||||
surfaceAdded = true;
|
|
||||||
blocks.push(this.gfx.surface!);
|
|
||||||
} else {
|
} else {
|
||||||
blocks.push(model);
|
blocks.push(model);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return blocks;
|
if (surfaceAdded) {
|
||||||
|
// surface children are included, so no need to add the blocksUnderSurface
|
||||||
|
return blocks;
|
||||||
|
} else {
|
||||||
|
return blocks.concat(blocksUnderSurface);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectedElements = getElementsInContainer(
|
const selectedElements = getElementsInContainer(
|
||||||
@@ -953,13 +957,19 @@ export class DragEventWatcher {
|
|||||||
block.flavour === 'affine:attachment' ||
|
block.flavour === 'affine:attachment' ||
|
||||||
block.flavour.startsWith('affine:embed-')
|
block.flavour.startsWith('affine:embed-')
|
||||||
) {
|
) {
|
||||||
const style = (block.props.style ?? 'vertical') as EmbedCardStyle;
|
const style = 'vertical' as EmbedCardStyle;
|
||||||
block.props.style = style;
|
block.props.style = style;
|
||||||
|
|
||||||
blockBound.w = EMBED_CARD_WIDTH[style];
|
blockBound.w = EMBED_CARD_WIDTH[style];
|
||||||
blockBound.h = EMBED_CARD_HEIGHT[style];
|
blockBound.h = EMBED_CARD_HEIGHT[style];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (block.flavour === 'affine:image') {
|
||||||
|
assertType<{ width: number; height: number }>(block.props);
|
||||||
|
blockBound.w = blockBound.w || block.props.width || 100;
|
||||||
|
blockBound.h = blockBound.h || block.props.height || 100;
|
||||||
|
}
|
||||||
|
|
||||||
if (ignoreOriginalPos) {
|
if (ignoreOriginalPos) {
|
||||||
blockBound.x = modelX;
|
blockBound.x = modelX;
|
||||||
blockBound.y = modelY;
|
blockBound.y = modelY;
|
||||||
@@ -1013,8 +1023,10 @@ export class DragEventWatcher {
|
|||||||
.then(slices => {
|
.then(slices => {
|
||||||
slices?.content.forEach((block, idx) => {
|
slices?.content.forEach((block, idx) => {
|
||||||
if (
|
if (
|
||||||
block.flavour === 'affine:attachment' ||
|
block.id === content[idx].id &&
|
||||||
block.flavour.startsWith('affine:embed-')
|
(block.flavour === 'affine:image' ||
|
||||||
|
block.flavour === 'affine:attachment' ||
|
||||||
|
block.flavour.startsWith('affine:embed-'))
|
||||||
) {
|
) {
|
||||||
store.updateBlock(block as BlockModel, {
|
store.updateBlock(block as BlockModel, {
|
||||||
xywh: content[idx].props.xywh,
|
xywh: content[idx].props.xywh,
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export class EdgelessWatcher {
|
|||||||
private readonly _handleEdgelessToolUpdated = (
|
private readonly _handleEdgelessToolUpdated = (
|
||||||
newTool: GfxToolsFullOptionValue
|
newTool: GfxToolsFullOptionValue
|
||||||
) => {
|
) => {
|
||||||
// @ts-expect-error FIXME: resolve after gfx tool refactor
|
// @ts-expect-error GfxToolsFullOptionValue is extended in other packages
|
||||||
if (newTool.type === 'default') {
|
if (newTool.type === 'default') {
|
||||||
this.updateAnchorElement();
|
this.updateAnchorElement();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import type { GfxViewportElement } from '@blocksuite/block-std/gfx';
|
|||||||
import { assertExists } from '@blocksuite/global/utils';
|
import { assertExists } from '@blocksuite/global/utils';
|
||||||
import { css, html } from 'lit';
|
import { css, html } from 'lit';
|
||||||
import { query, state } from 'lit/decorators.js';
|
import { query, state } from 'lit/decorators.js';
|
||||||
|
import { styleMap } from 'lit/directives/style-map.js';
|
||||||
|
|
||||||
import type { EdgelessRootBlockWidgetName } from '../types.js';
|
import type { EdgelessRootBlockWidgetName } from '../types.js';
|
||||||
import type { EdgelessRootService } from './edgeless-root-service.js';
|
import type { EdgelessRootService } from './edgeless-root-service.js';
|
||||||
@@ -229,8 +230,12 @@ export class EdgelessRootPreviewBlockComponent
|
|||||||
}
|
}
|
||||||
|
|
||||||
override renderBlock() {
|
override renderBlock() {
|
||||||
|
const background = styleMap({
|
||||||
|
background: this.overrideBackground,
|
||||||
|
});
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div class="edgeless-background edgeless-container">
|
<div class="edgeless-background edgeless-container" style=${background}>
|
||||||
<gfx-viewport
|
<gfx-viewport
|
||||||
.enableChildrenSchedule=${!this._disableScheduleUpdate}
|
.enableChildrenSchedule=${!this._disableScheduleUpdate}
|
||||||
.viewport=${this.service.viewport}
|
.viewport=${this.service.viewport}
|
||||||
@@ -260,6 +265,9 @@ export class EdgelessRootPreviewBlockComponent
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@state()
|
||||||
|
accessor overrideBackground: string | undefined = undefined;
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
accessor editorViewportSelector = '.affine-edgeless-viewport';
|
accessor editorViewportSelector = '.affine-edgeless-viewport';
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
export { FramePreview } from './components/frame/frame-preview.js';
|
export { FramePreview } from './components/frame/frame-preview.js';
|
||||||
export * from './edgeless-root-block.js';
|
export * from './edgeless-root-block.js';
|
||||||
|
export { EdgelessRootPreviewBlockComponent } from './edgeless-root-preview-block.js';
|
||||||
export { EdgelessRootService } from './edgeless-root-service.js';
|
export { EdgelessRootService } from './edgeless-root-service.js';
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export class GfxViewportElement extends WithDisposable(ShadowlessElement) {
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
private readonly _hideOutsideBlock = requestThrottledConnectedFrame(() => {
|
private readonly _hideOutsideBlock = () => {
|
||||||
if (this.getModelsInViewport && this.host) {
|
if (this.getModelsInViewport && this.host) {
|
||||||
const host = this.host;
|
const host = this.host;
|
||||||
const modelsInViewport = this.getModelsInViewport();
|
const modelsInViewport = this.getModelsInViewport();
|
||||||
@@ -73,7 +73,7 @@ export class GfxViewportElement extends WithDisposable(ShadowlessElement) {
|
|||||||
|
|
||||||
this._lastVisibleModels = modelsInViewport;
|
this._lastVisibleModels = modelsInViewport;
|
||||||
}
|
}
|
||||||
}, this);
|
};
|
||||||
|
|
||||||
private _lastVisibleModels?: Set<GfxBlockElementModel>;
|
private _lastVisibleModels?: Set<GfxBlockElementModel>;
|
||||||
|
|
||||||
@@ -95,14 +95,13 @@ export class GfxViewportElement extends WithDisposable(ShadowlessElement) {
|
|||||||
|
|
||||||
const viewportUpdateCallback = () => {
|
const viewportUpdateCallback = () => {
|
||||||
this._refreshViewport();
|
this._refreshViewport();
|
||||||
this._hideOutsideBlock();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!this.enableChildrenSchedule) {
|
if (!this.enableChildrenSchedule) {
|
||||||
delete this.scheduleUpdateChildren;
|
delete this.scheduleUpdateChildren;
|
||||||
}
|
}
|
||||||
|
|
||||||
viewportUpdateCallback();
|
this._hideOutsideBlock();
|
||||||
this.disposables.add(
|
this.disposables.add(
|
||||||
this.viewport.viewportUpdated.on(() => viewportUpdateCallback())
|
this.viewport.viewportUpdated.on(() => viewportUpdateCallback())
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user