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