feat(editor): limit embed edgeless iframe block width and height (#11192)

[BS-2841](https://linear.app/affine-design/issue/BS-2841/iframe-embed-block-edgeless-block-component-限制-resize-时的最大最小宽高)
This commit is contained in:
donteatfriedrice
2025-03-26 08:38:06 +00:00
parent 39fa8e87cf
commit b5945c7e7d
3 changed files with 90 additions and 11 deletions

View File

@@ -69,6 +69,10 @@ import {
AI_CHAT_BLOCK_MAX_WIDTH,
AI_CHAT_BLOCK_MIN_HEIGHT,
AI_CHAT_BLOCK_MIN_WIDTH,
EMBED_IFRAME_BLOCK_MAX_HEIGHT,
EMBED_IFRAME_BLOCK_MAX_WIDTH,
EMBED_IFRAME_BLOCK_MIN_HEIGHT,
EMBED_IFRAME_BLOCK_MIN_WIDTH,
} from '../../utils/consts.js';
import {
getSelectableBounds,
@@ -81,6 +85,7 @@ import {
isEmbedFigmaBlock,
isEmbedGithubBlock,
isEmbedHtmlBlock,
isEmbedIframeBlock,
isEmbedLinkedDocBlock,
isEmbedLoomBlock,
isEmbedSyncedDocBlock,
@@ -114,6 +119,13 @@ export type SelectedRect = {
export const EDGELESS_SELECTED_RECT_WIDGET = 'edgeless-selected-rect';
interface ResizeConstraints {
minWidth: number;
maxWidth: number;
minHeight: number;
maxHeight: number;
}
export class EdgelessSelectedRectWidget extends WidgetComponent<
RootBlockModel,
EdgelessRootBlockComponent
@@ -526,6 +538,11 @@ export class EdgelessSelectedRectWidget extends WidgetComponent<
return;
}
if (isEmbedIframeBlock(element)) {
this.#adjustEmbedIframe(element, bound, direction);
return;
}
if (this._isProportionalElement(element)) {
this.#adjustProportional(element, bound, direction);
return;
@@ -949,37 +966,43 @@ export class EdgelessSelectedRectWidget extends WidgetComponent<
* TODO: Remove this function after the edgeless refactor completed
* This function is used to adjust the element bound and scale
* Should not be used in the future
* Related issue: https://linear.app/affine-design/issue/BS-1009/
* @deprecated
*/
#adjustAIChat(element: GfxModel, bound: Bound, direction: HandleDirection) {
#adjustBlockWithConstraints(
element: GfxModel,
bound: Bound,
direction: HandleDirection,
constraints: ResizeConstraints
) {
const curBound = Bound.deserialize(element.xywh);
const { minWidth, maxWidth, minHeight, maxHeight } = constraints;
let scale = 1;
if ('scale' in element) {
scale = element.scale as number;
if ('props' in element && 'scale' in element.props) {
scale = element.props.scale as number;
}
let width = curBound.w / scale;
let height = curBound.h / scale;
// Handle shift key scaling (maintain aspect ratio)
if (this._shiftKey) {
scale = bound.w / width;
this._scalePercent = `${Math.round(scale * 100)}%`;
this._scaleDirection = direction;
}
// Apply constraints
width = bound.w / scale;
width = clamp(width, AI_CHAT_BLOCK_MIN_WIDTH, AI_CHAT_BLOCK_MAX_WIDTH);
width = clamp(width, minWidth, maxWidth);
bound.w = width * scale;
height = bound.h / scale;
height = clamp(height, AI_CHAT_BLOCK_MIN_HEIGHT, AI_CHAT_BLOCK_MAX_HEIGHT);
height = clamp(height, minHeight, maxHeight);
bound.h = height * scale;
this._isWidthLimit =
width === AI_CHAT_BLOCK_MIN_WIDTH || width === AI_CHAT_BLOCK_MAX_WIDTH;
this._isHeightLimit =
height === AI_CHAT_BLOCK_MIN_HEIGHT ||
height === AI_CHAT_BLOCK_MAX_HEIGHT;
// Update limit flags
this._isWidthLimit = width === minWidth || width === maxWidth;
this._isHeightLimit = height === minHeight || height === maxHeight;
this.gfx.updateElement(element.id, {
scale,
@@ -987,6 +1010,42 @@ export class EdgelessSelectedRectWidget extends WidgetComponent<
});
}
/**
* TODO: Remove this function after the edgeless refactor completed
* This function is used to adjust the element bound and scale
* Should not be used in the future
* Related issue: https://linear.app/affine-design/issue/BS-1009/
* @deprecated
*/
#adjustAIChat(element: GfxModel, bound: Bound, direction: HandleDirection) {
this.#adjustBlockWithConstraints(element, bound, direction, {
minWidth: AI_CHAT_BLOCK_MIN_WIDTH,
maxWidth: AI_CHAT_BLOCK_MAX_WIDTH,
minHeight: AI_CHAT_BLOCK_MIN_HEIGHT,
maxHeight: AI_CHAT_BLOCK_MAX_HEIGHT,
});
}
/**
* TODO: Remove this function after the edgeless refactor completed
* This function is used to adjust the element bound and scale
* Should not be used in the future
* Related issue: https://linear.app/affine-design/issue/BS-2841/
* @deprecated
*/
#adjustEmbedIframe(
element: GfxModel,
bound: Bound,
direction: HandleDirection
) {
this.#adjustBlockWithConstraints(element, bound, direction, {
minWidth: EMBED_IFRAME_BLOCK_MIN_WIDTH,
maxWidth: EMBED_IFRAME_BLOCK_MAX_WIDTH,
minHeight: EMBED_IFRAME_BLOCK_MIN_HEIGHT,
maxHeight: EMBED_IFRAME_BLOCK_MAX_HEIGHT,
});
}
#adjustConnector(
element: ConnectorElementModel,
bounds: Bound,

View File

@@ -14,3 +14,8 @@ export const AI_CHAT_BLOCK_MIN_WIDTH = 260;
export const AI_CHAT_BLOCK_MIN_HEIGHT = 160;
export const AI_CHAT_BLOCK_MAX_WIDTH = 320;
export const AI_CHAT_BLOCK_MAX_HEIGHT = 300;
export const EMBED_IFRAME_BLOCK_MIN_WIDTH = 218;
export const EMBED_IFRAME_BLOCK_MIN_HEIGHT = 44;
export const EMBED_IFRAME_BLOCK_MAX_WIDTH = 3400;
export const EMBED_IFRAME_BLOCK_MAX_HEIGHT = 2200;

View File

@@ -88,6 +88,21 @@ export function isAIChatBlock(element: BlockModel | GfxModel | null) {
);
}
/**
* TODO: Remove this function after the edgeless refactor completed
* This function is used to check if the block is an EmbedIframeBlock for edgeless selected rect
* Should not be used in the future
* Related issue: https://linear.app/affine-design/issue/BS-2841/
* @deprecated
*/
export function isEmbedIframeBlock(element: BlockModel | GfxModel | null) {
return (
!!element &&
'flavour' in element &&
element.flavour === 'affine:embed-iframe'
);
}
export function isEmbeddedLinkBlock(element: BlockModel | GfxModel | null) {
return (
isEmbeddedBlock(element) &&