Skip to content

Commit

Permalink
Prevent scrolling when the container is fully visible in the viewport (
Browse files Browse the repository at this point in the history
  • Loading branch information
jalal246 authored Nov 4, 2023
1 parent 381680b commit c21c4d6
Show file tree
Hide file tree
Showing 15 changed files with 507 additions and 446 deletions.
16 changes: 8 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,25 +50,25 @@
"@babel/preset-typescript": "^7.23.2",
"@changesets/cli": "^2.26.2",
"@playwright/test": "^1.39.0",
"@size-limit/preset-big-lib": "^10.0.1",
"@types/jest": "^29.5.6",
"@types/node": "^20.8.9",
"@types/react": "^18.2.33",
"@size-limit/preset-big-lib": "^10.0.2",
"@types/jest": "^29.5.7",
"@types/node": "^20.8.10",
"@types/react": "^18.2.34",
"@types/react-dom": "^18.2.14",
"@types/react-router-dom": "^5.3.3",
"@vitejs/plugin-react": "^4.1.0",
"@vitejs/plugin-react": "^4.1.1",
"cross-env": "^7.0.3",
"cypress": "^13.3.3",
"cypress": "^13.4.0",
"eslint-config-dflex": "workspace:*",
"istanbul-lib-instrument": "^6.0.1",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"prettier": "^3.0.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.17.0",
"react-router-dom": "^6.18.0",
"rimraf": "^5.0.5",
"size-limit": "^10.0.1",
"size-limit": "^10.0.2",
"start-server-and-test": "^2.0.1",
"ts-jest": "^29.1.1",
"ts-node": "^10.9.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class DFlexParentContainer {
private _boundariesByRow: BoxNum;

/** Strict Rect for siblings containers. */
private _siblingBoundaries: BoxNum | null;
private _siblingBoundaries: BoxRect | null;

private _rect: BoxRect;

Expand Down Expand Up @@ -102,7 +102,7 @@ class DFlexParentContainer {
if (this._siblingBoundaries) {
this._siblingBoundaries.assignBiggestBox(rect);
} else {
this._siblingBoundaries = new BoxNum(
this._siblingBoundaries = new BoxRect(
rect.top,
rect.right,
rect.bottom,
Expand Down Expand Up @@ -155,8 +155,8 @@ class DFlexParentContainer {
*
* @returns
*/
getBoundaries(): AbstractBox<number> {
return this._siblingBoundaries || this._rect.getBox();
getBoundaries(): BoxRect {
return this._siblingBoundaries || this._rect;
}

/**
Expand Down
82 changes: 45 additions & 37 deletions packages/dflex-core-instance/src/Container/DFlexScrollContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ class DFlexScrollContainer {
/**
* scroll container in the viewport. Only in the visible area.
*/
private _staticScrollViewport: BoxRect;

visibleScrollRect: BoxRect;

/**
Expand Down Expand Up @@ -120,6 +122,7 @@ class DFlexScrollContainer {
// Rect.
this.totalScrollRect = new BoxRect(0, 0, 0, 0);
this.visibleScrollRect = new BoxRect(0, 0, 0, 0);
this._staticScrollViewport = new BoxRect(0, 0, 0, 0);
this._isCandidateForDynamicVisibility = false;

this.initialize(DOMRef, siblingsLength);
Expand Down Expand Up @@ -164,13 +167,14 @@ class DFlexScrollContainer {
): void {
const instance = this._thresholdInViewport[type];

// Then it's destroy.
if (!thresholdValue) {
if (instance.threshold) {
instance.threshold.destroy();
instance.threshold = null;
}
// Always reset the threshold.
if (instance.threshold) {
instance.threshold.destroy();
instance.threshold = null;
}

// If not value, then destroy and leave.
if (!thresholdValue) {
return;
}

Expand All @@ -179,7 +183,7 @@ class DFlexScrollContainer {

threshold.setMainThreshold(
instance.key,
this.visibleScrollRect,
this._staticScrollViewport,
type === "inner",
);
}
Expand Down Expand Up @@ -216,11 +220,9 @@ class DFlexScrollContainer {
// Only tagged if there's overflow.
this._updateDOMDataset(true, true);

this._initializeOrDestroyThreshold("inner", null);
this._initializeOrDestroyThreshold("inner", INNER_THRESHOLD);

if (this.hasDynamicVisibility()) {
this._initializeOrDestroyThreshold("outer", null);
this._initializeOrDestroyThreshold("outer", OUTER_THRESHOLD);
}
}
Expand Down Expand Up @@ -275,12 +277,32 @@ class DFlexScrollContainer {
);

// Calculate the visible portion of the container
this.visibleScrollRect.setByPointAndDimensions(
this._staticScrollViewport.setByPointAndDimensions(
0,
0,
clientHeight,
clientWidth,
);

// Calculate the visible portion of the container
if (this._isDocumentContainer) {
// For document container, the visible area is the entire client viewport
this.visibleScrollRect.setByPointAndDimensions(
scrollTop,
scrollLeft,
clientHeight,
clientWidth,
);
} else {
const { left, top } = this._containerDOM.getBoundingClientRect();

this.visibleScrollRect.setByPointAndDimensions(
top,
left,
clientHeight,
clientWidth,
);
}
}

private _updateScrollPosition(
Expand All @@ -299,6 +321,15 @@ class DFlexScrollContainer {

this.totalScrollRect.setPosition(scrollLeft, scrollTop);

const { width, height } = this.visibleScrollRect;

this.visibleScrollRect.setBox(
scrollTop,
scrollLeft + width,
scrollTop + height,
scrollLeft,
);

if (withDOM) {
this._containerDOM.scrollTop = scrollTop;
this._containerDOM.scrollLeft = scrollLeft;
Expand All @@ -325,7 +356,7 @@ class DFlexScrollContainer {
const endPos = this.totalScrollRect[end];

const dimension = getDimensionTypeByAxis(axis);
const viewportSize = this.visibleScrollRect[dimension];
const viewportSize = this._staticScrollViewport[dimension];

return [startPos, endPos, viewportSize];
}
Expand Down Expand Up @@ -425,7 +456,7 @@ class DFlexScrollContainer {
* @returns
*/
getMaximumScrollContainerLeft() {
const { left, width } = this.visibleScrollRect;
const { left, width } = this._staticScrollViewport;

return left + width + this.totalScrollRect.left;
}
Expand All @@ -435,7 +466,7 @@ class DFlexScrollContainer {
* @returns
*/
getMaximumScrollContainerTop() {
const { top, height } = this.visibleScrollRect;
const { top, height } = this._staticScrollViewport;

return top + height + this.totalScrollRect.top;
}
Expand All @@ -452,33 +483,10 @@ class DFlexScrollContainer {
return [viewportTop, viewportLeft];
}

isElmOutViewport(absPos: BoxNum, isOuter: boolean): [boolean, BoxBool] {
const viewportPos: BoxNum = absPos;

isElmOutViewport(viewportPos: BoxNum, isOuter: boolean): [boolean, BoxBool] {
const scrollThreshold: ScrollThreshold =
this._thresholdInViewport[isOuter ? "outer" : "inner"];

if (__DEV__) {
if (!scrollThreshold) {
throw new Error(
"isElmOutViewport: _thresholdInViewport is not initialized. Please call setInnerThreshold() method before using isElmOutViewport().",
);
}

if (!this.hasOverflow) {
throw new Error(
"isElmOutViewport: Scrollable element does not have overflow.",
);
}

if (this.hasOverflow.x && this.hasOverflow.y) {
// eslint-disable-next-line no-console
console.warn(
"isElmOutViewport: Scrollable element has overflow in both x and y directions.\nDFlex is not yet fully optimized to handle this scenario, and the results may be inaccurate.",
);
}
}

const { threshold, key } = scrollThreshold;

const isExceeded = (a: Axis) =>
Expand Down
10 changes: 8 additions & 2 deletions packages/dflex-dnd/src/LayoutManager/DFlexDnDStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -697,8 +697,7 @@ class DFlexDnDStore extends DFlexBaseStore {
}

private _reconcileSiblings(SK: string, syncAllSiblings: boolean): void {
const container = this.containers.get(SK)!;
const scroll = this.scrolls.get(SK)!;
const [container, scroll] = this.getContainers(SK);

if (__DEV__) {
if (!container) {
Expand Down Expand Up @@ -924,6 +923,13 @@ class DFlexDnDStore extends DFlexBaseStore {
return undefined;
}

getContainers(SK: string): [DFlexParentContainer, DFlexScrollContainer] {
const container = this.containers.get(SK)!;
const scroll = this.scrolls.get(SK)!;

return [container, scroll];
}

cleanupSiblingsAttachments(BK: string, SK: string, depth: number): void {
const scroll = this.scrolls.get(SK)!;

Expand Down
Loading

0 comments on commit c21c4d6

Please sign in to comment.