Skip to content
Open
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
4169150
Changed scroll animation
ion-andrusciac-lgp Aug 29, 2025
e89ac70
Changed timing animation function
ion-andrusciac-lgp Sep 1, 2025
0c03026
Fixed lint warnings
ion-andrusciac-lgp Sep 1, 2025
814da10
Adjusted animation function
ion-andrusciac-lgp Sep 2, 2025
1a4b0c2
Merge branch 'develop' of https://github.com/enactjs/enact into featu…
ion-andrusciac-lgp Sep 2, 2025
4437865
Adjusted timing function
ion-andrusciac-lgp Sep 4, 2025
47bf3f8
Added `unit-tests`
ion-andrusciac-lgp Sep 4, 2025
15066be
Added `unit-tests`
ion-andrusciac-lgp Sep 4, 2025
42c9da2
Added `unit-tests`
ion-andrusciac-lgp Sep 4, 2025
fe64975
Adjusted animation function
ion-andrusciac-lgp Sep 17, 2025
1d790e7
Fixed lint warnings
ion-andrusciac-lgp Sep 17, 2025
acaf252
Adjustments
ion-andrusciac-lgp Sep 17, 2025
8e39da9
Added acceleration to scroll
ion-andrusciac-lgp Sep 17, 2025
c0048aa
Small fix
ion-andrusciac-lgp Sep 17, 2025
7e0a4fc
Small fix
ion-andrusciac-lgp Sep 17, 2025
a4149bc
Small fix
ion-andrusciac-lgp Sep 17, 2025
5b515a9
Merge branch 'develop' of https://github.com/enactjs/enact into featu…
ion-andrusciac-lgp Sep 23, 2025
f2d6800
Small fix
ion-andrusciac-lgp Sep 23, 2025
bea7552
Small fix
ion-andrusciac-lgp Sep 23, 2025
036c536
Merge branch 'develop' of https://github.com/enactjs/enact into featu…
ion-andrusciac-lgp Sep 24, 2025
ca5213e
Fixed `unit-tests`
ion-andrusciac-lgp Sep 24, 2025
933c019
Fixed lint warnings
ion-andrusciac-lgp Sep 24, 2025
06e4b91
Merge remote-tracking branch 'origin/develop' into feature/WRR-29169-1
daniel-stoian-lgp Sep 24, 2025
d65d139
Merge branch 'feature/WRR-29169-1' of https://github.com/enactjs/enac…
daniel-stoian-lgp Sep 24, 2025
ef0dbee
Added `CHANGELOG`
ion-andrusciac-lgp Sep 24, 2025
50fa46f
Review fixes
ion-andrusciac-lgp Sep 25, 2025
6cd37e7
Adjusted animation function
ion-andrusciac-lgp Oct 15, 2025
c1e0570
Small fix
ion-andrusciac-lgp Oct 15, 2025
5f37204
Merge branch 'develop' of https://github.com/enactjs/enact into featu…
ion-andrusciac-lgp Oct 15, 2025
7a9accb
Small fix
ion-andrusciac-lgp Oct 16, 2025
2970d77
Small fix
ion-andrusciac-lgp Oct 16, 2025
0c7a07d
Fixed lint warnings
ion-andrusciac-lgp Oct 16, 2025
ddb74d6
Fixed unit tests
ion-andrusciac-lgp Oct 16, 2025
58b942d
Added condition to apply animation only on `ev.repeat`
ion-andrusciac-lgp Oct 17, 2025
d1d9951
Added description for `animateScroll`
ion-andrusciac-lgp Oct 21, 2025
976f14e
Merge branch 'develop' of https://github.com/enactjs/enact into featu…
ion-andrusciac-lgp Oct 27, 2025
538f7f6
Adjusted scroll pace
ion-andrusciac-lgp Oct 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

The following is a curated list of changes in the Enact project, newest changes on the top.

## [unreleased]

### Changed

- `ui/Scroller` scroll animation method for `scrollMode: native`
## [5.3.1] - 2025-10-14

### Fixed
Expand Down
5 changes: 5 additions & 0 deletions packages/ui/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

The following is a curated list of changes in the Enact ui module, newest changes on the top.

## [unreleased]

### Changed

- `ui/Scroller` scroll animation method for `scrollMode: native`
## [5.3.1] - 2025-10-14

### Fixed
Expand Down
42 changes: 40 additions & 2 deletions packages/ui/Scroller/ScrollerBasic.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ class ScrollerBasic extends Component {
}
}

scrollAnimationId = null;

scrollBounds = {
clientWidth: 0,
clientHeight: 0,
Expand Down Expand Up @@ -117,8 +119,44 @@ class ScrollerBasic extends Component {
}

// scrollMode 'native'
scrollToPosition (left, top, behavior) {
this.props.scrollContentRef.current.scrollTo({left: this.getRtlPositionX(left), top, behavior});
scrollToPosition (left, top, behavior, repeat) {
const node = this.props.scrollContentRef.current;
const smoothBehavior = behavior === 'smooth';

if (platform.chrome && smoothBehavior && repeat) {
this.animateScroll(this.getRtlPositionX(left), top, node);
} else {
node.scrollTo({left: this.getRtlPositionX(left), top, behavior});
}
}

// scrollMode 'native'
animateScroll (left, top, node) {
const directionX = Math.sign(left - node.scrollLeft);
const directionY = Math.sign(top - node.scrollTop);

const animateScroll = () => {
const scrollLeft = directionX > 0 ? node.scrollLeft < left : node.scrollLeft > left;
const scrollTop = directionY > 0 ? node.scrollTop < top : node.scrollTop > top;

// Check if we reached the scroll bounds and cancel the animation
if (
top > this.scrollBounds.maxTop && node.scrollTop === this.scrollBounds.maxTop ||
left > this.scrollBounds.maxLeft && node.scrollLeft === this.scrollBounds.maxLeft ||
top < 0 && node.scrollTop === 0 ||
left < 0 && node.scrollLeft === 0
) {
window.cancelAnimationFrame(this.scrollAnimationId);
return;
}

if (scrollTop || scrollLeft) {
node.scrollBy({top: directionY * 18, left: directionX * 18, behavior: 'instant'});
this.scrollAnimationId = window.requestAnimationFrame(animateScroll);
}
};

this.scrollAnimationId = window.requestAnimationFrame(animateScroll);
}

// scrollMode 'native'
Expand Down
61 changes: 61 additions & 0 deletions packages/ui/Scroller/tests/ScrollerBasic-specs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import '@testing-library/jest-dom';

import {ScrollerBasic} from '../Scroller';

describe('ScrollBasic', () => {
let scrollContentRef;

beforeEach(() => {
jest.createMockFromModule('@enact/core/platform');

scrollContentRef = {
current: {
scrollLeft: 0,
scrollTop: 0,
scrollBy: jest.fn(),
scrollTo: jest.fn()
}
};
});

afterEach(() => {
jest.clearAllMocks();
});

test(
'should call scrollBy on scrollToPosition',
() => {
const instance = new ScrollerBasic({scrollContentRef, direction: 'both'});

instance.scrollToPosition(100, 200, 'smooth');
expect(scrollContentRef.current.scrollTo).toHaveBeenCalledWith({left: 100, top: 200, behavior: 'smooth'});

instance.scrollToPosition(100, 200, 'instant');
expect(scrollContentRef.current.scrollTo).toHaveBeenCalledWith({left: 100, top: 200, behavior: 'instant'});
}
);

test(
'should call scrollBy with animated values during animateScroll',
() => {
let rafCallback;
const instance = new ScrollerBasic({scrollContentRef, direction: 'both'});
instance.scrollBounds.maxTop = 500;
instance.scrollBounds.maxLeft = 500;

window.requestAnimationFrame = jest.fn((cb) => {
rafCallback = cb;
});
window.cancelAnimationFrame = jest.fn();

instance.animateScroll(100, 200, scrollContentRef.current);
rafCallback();
expect(scrollContentRef.current.scrollBy).toHaveBeenCalled();

scrollContentRef.current.scrollTop = 500;
instance.animateScroll(550, 550, scrollContentRef.current);
rafCallback();
expect(window.cancelAnimationFrame).toHaveBeenCalled();
}
);
});
4 changes: 3 additions & 1 deletion packages/ui/useScroll/useScroll.js
Original file line number Diff line number Diff line change
Expand Up @@ -825,6 +825,8 @@ const useScrollBase = (props) => {
}
} else {
props.preventScroll?.(ev);
mutableRef.current.repeat = ev.repeat;
if (ev.repeat && mutableRef.current.lastInputType === 'arrowKey') return;
forward('onKeyDown', ev, props);
}
}
Expand Down Expand Up @@ -1161,7 +1163,7 @@ const useScrollBase = (props) => {
let {roundedTargetX, roundedTargetY} = roundTarget(scrollContentHandle.current, targetX, targetY);

if (animate) {
scrollContentHandle.current.scrollToPosition(roundedTargetX, roundedTargetY, 'smooth');
scrollContentHandle.current.scrollToPosition(roundedTargetX, roundedTargetY, 'smooth', mutableRef.current.repeat);
} else {
scrollContentHandle.current.scrollToPosition(roundedTargetX, roundedTargetY, 'instant');
}
Expand Down