Skip to content

Commit

Permalink
Fix canvas scroll on component select from layers. Closes GrapesJS#5342
Browse files Browse the repository at this point in the history
  • Loading branch information
artf committed Aug 30, 2023
1 parent 0315af8 commit d9c5ee9
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 25 deletions.
4 changes: 3 additions & 1 deletion src/canvas/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ export interface ToWorldOption {
toWorld?: boolean;
}

export interface GetBoxRectOptions extends ToScreenOption {}
export interface GetBoxRectOptions extends ToScreenOption {
local?: boolean;
}

/**{START_EVENTS}*/
export enum CanvasEvents {
Expand Down
5 changes: 5 additions & 0 deletions src/canvas/view/CanvasView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,11 @@ export default class CanvasView extends ModuleView<Canvas> {
height,
};

if (opts.local) {
boxRect.x = left;
boxRect.y = top;
}

return opts.toScreen ? this.getRectToScreen(boxRect) : boxRect;
}

Expand Down
47 changes: 23 additions & 24 deletions src/dom_components/view/ComponentView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,6 @@ import ComponentsView from './ComponentsView';

type ClbObj = ReturnType<ComponentView['_clbObj']>;

interface Rect {
top?: number;
left?: number;
bottom?: number;
right?: number;
}

export interface IComponentView extends ExtractMethods<ComponentView> {}

export default class ComponentView extends View</**
Expand Down Expand Up @@ -433,7 +426,7 @@ Component> {
* have to take in account offsetParent
*/
getOffsetRect() {
const rect: Rect = {};
const rect = { top: 0, left: 0, bottom: 0, right: 0 };
const target = this.el;
let gtop = 0;
let gleft = 0;
Expand All @@ -457,32 +450,38 @@ Component> {
return rect;
}

isInViewport({ rect }: { rect?: Rect } = {}) {
const { el } = this;
const elDoc = el.ownerDocument;
const { body } = elDoc;
const frameElement = elDoc.defaultView?.frameElement as HTMLIFrameElement;
const { top, left } = rect || this.getOffsetRect();
const frame = this.frameView.getOffsetRect();
isInViewport() {
const { el, em, frameView } = this;
const canvasView = em.Canvas.getCanvasView();
const elRect = canvasView.getElBoxRect(el, { local: true });
const frameEl = frameView.el;
const frameH = frameEl.clientHeight;
const frameW = frameEl.clientWidth;

const elTop = elRect.y;
const elRight = elRect.x;
const elBottom = elTop + elRect.height;
const elLeft = elRight + elRect.width;
const isTopInside = elTop >= 0 && elTop < frameH;
const isBottomInside = elBottom > 0 && elBottom < frameH;
const isLeftInside = elLeft >= 0 && elLeft < frameW;
const isRightInside = elRight > 0 && elRight <= frameW;

const partiallyIn = (isTopInside || isBottomInside) && (isLeftInside || isRightInside);

return (
top! >= frame.scrollTop &&
left! >= frame.scrollLeft &&
top! <= frame.scrollBottom &&
left! <= frameElement?.offsetWidth + body.scrollLeft
);
return partiallyIn;
}

scrollIntoView(opts: { force?: boolean } & ScrollIntoViewOptions = {}) {
const rect = this.getOffsetRect();
const isInViewport = this.isInViewport({ rect });
const isInViewport = this.isInViewport();

if (!isInViewport || opts.force) {
const { el } = this;

// PATCH: scrollIntoView won't work with multiple requests from iframes
if (opts.behavior !== 'smooth') {
el.ownerDocument.defaultView?.scrollTo(0, rect.top!);
const rect = this.getOffsetRect();
el.ownerDocument.defaultView?.scrollTo(0, rect.top);
} else {
el.scrollIntoView({
behavior: 'smooth',
Expand Down

0 comments on commit d9c5ee9

Please sign in to comment.