Skip to content

Commit

Permalink
feat: use side wheel to move conveyer (#15)
Browse files Browse the repository at this point in the history
* feat: add useSideWheel option

* fix: handle mixed horizontal with vertical scrolling wheel

* fix: modify side wheel scale

* skip: apply review

* fix: unify change condition of isReachEnd
  • Loading branch information
malangfox authored Jun 23, 2022
1 parent 0630847 commit 3cdeab5
Show file tree
Hide file tree
Showing 11 changed files with 203 additions and 30 deletions.
15 changes: 8 additions & 7 deletions packages/conveyer/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/conveyer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"drag"
],
"dependencies": {
"@egjs/axes": "^3.2.2",
"@egjs/axes": "^3.4.0",
"@egjs/component": "^3.0.1"
},
"devDependencies": {
Expand Down
47 changes: 32 additions & 15 deletions packages/conveyer/src/Conveyer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Copyright (c) 2022-present NAVER Corp.
* MIT license
*/
import Axes, { PanInput } from "@egjs/axes";
import Axes, { OnChange, OnHold, PanInput, WheelInput } from "@egjs/axes";
import Component from "@egjs/component";
import { IS_IE } from "./browser";
import { ReactiveSubscribe, Reactive, Ref } from "./cfcs";
Expand Down Expand Up @@ -108,6 +108,7 @@ class Conveyer extends Component<ConveyerEvents> {
this._options = {
horizontal: true,
useDrag: true,
useSideWheel: true,
autoInit: true,
scrollDebounce: 100,
...options,
Expand Down Expand Up @@ -371,37 +372,42 @@ class Conveyer extends Component<ConveyerEvents> {
const options = this._options;
const axes = new Axes({
scroll: {
circular: true,
range: [-1000, 1000],
range: [-Infinity, Infinity],
},
}, {
deceleration: 0.005,
round: 1,
nested: options.nested,
}, {
scroll: 0,
});
let isHold = false;

axes.on({
"hold": e => {
isHold = true;
isDrag = false;
const inputEvent = e.inputEvent.srcEvent;
const nativeEvent = this._getNativeEvent(e);

if (!inputEvent) {
if (!nativeEvent) {
return;
}
if (options.preventDefault) {
inputEvent.preventDefault();
nativeEvent.preventDefault();
}
if (options.preventClickOnDrag) {
this._disableClick();
}
},
"change": e => {
if (e.inputEvent && !isHold) {
const nativeEvent = this._getNativeEvent(e);
if (nativeEvent && !isHold) {
return;
}
if (options.useSideWheel && this._isMixedWheel(nativeEvent)) {
return;
}
this._isDragScroll = !!e.inputEvent;
this._isDragScroll = !!nativeEvent && nativeEvent.type !== "wheel";
this._isAnimation = !!isHold;
isDrag = true;
const scroll = e.delta.scroll;
Expand All @@ -411,8 +417,8 @@ class Conveyer extends Component<ConveyerEvents> {
} else {
scrollAreaElement.scrollTop -= scroll;
}
if (options.nested && e.inputEvent.srcEvent) {
this._checkNestedMove(e);
if (options.nested) {
this._checkNestedMove(nativeEvent);
}
},
"release": e => {
Expand All @@ -425,12 +431,17 @@ class Conveyer extends Component<ConveyerEvents> {
});

this._axes = axes;
if (this._options.useDrag) {
axes.connect(this._options.horizontal ? ["scroll", ""] : ["", "scroll"], new PanInput(scrollAreaElement, {
if (options.useDrag) {
axes.connect(options.horizontal ? ["scroll", ""] : ["", "scroll"], new PanInput(scrollAreaElement, {
inputType: ["mouse"],
touchAction: "auto",
}));
}
if (options.useSideWheel) {
axes.connect(options.horizontal ? ["scroll", ""] : ["", "scroll"], new WheelInput(scrollAreaElement, {
useNormalized: false,
}));
}
scrollAreaElement.addEventListener("scroll", this._onScroll);
window.addEventListener("resize", this.update);

Expand Down Expand Up @@ -465,6 +476,9 @@ class Conveyer extends Component<ConveyerEvents> {
size: horizontal ? element.offsetWidth : element.offsetHeight,
};
}
private _getNativeEvent(e: OnHold | OnChange) {
return e?.inputEvent?.srcEvent ? e.inputEvent?.srcEvent : e?.inputEvent;
}
private _getNextScrollPos(item: ConveyerItem, options: ScrollIntoViewOptions) {
const size = this._size;
const align = options.align || "start";
Expand All @@ -482,9 +496,12 @@ class Conveyer extends Component<ConveyerEvents> {
}
return scrollPos;
}
private _checkNestedMove(e: any) {
private _isMixedWheel(nativeEvent: any) {
return !!nativeEvent && nativeEvent?.type === "wheel" && nativeEvent?.deltaX && nativeEvent?.deltaY;
}
private _checkNestedMove(nativeEvent: any) {
if (this.isReachStart || this.isReachEnd) {
e.inputEvent.srcEvent.__childrenAxesAlreadyChanged = false;
nativeEvent.__childrenAxesAlreadyChanged = false;
}
}
private _onScroll = (e?: any) => {
Expand Down Expand Up @@ -524,7 +541,7 @@ class Conveyer extends Component<ConveyerEvents> {
* @event Conveyer#reachEnd
*/
this.trigger("reachEnd");
} else if (pos < scrollSize - size && this.isReachEnd !== false) {
} else if (!(scrollSize - size - pos < 1) && this.isReachEnd !== false) {
this._isReachEnd = false;
/**
* This event is fired when scroll leave end.
Expand Down
2 changes: 2 additions & 0 deletions packages/conveyer/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Conveyer from "./Conveyer";
* @property - scroll direction. (true: Horizontal Scroll, false: Vertical Scroll) (default: true) <ko>스크롤 방향. (true: 가로 스크롤, false: 세로 스크롤) (default: true)</ko>
* @property - selector to find items inside. (default: "") <ko>내부의 아이템들을 찾기 위한 selector. (default: "")</ko>
* @property - Whether to use drag (default: true) <ko> 드래그를 사용할지 여부. (default: true)</ko>
* @property - Whether to use the mouse wheel in a direction aside from the scroll direction (default: false) <ko>스크롤 방향과 다른 방향의 마우스 휠 입력을 사용할지 여부. (default: false)</ko>
* @property - The maximum amount of time the scroll event does not fire for the finishScroll event to be triggered. (default: 100) <ko> finishScroll 이벤트가 발생되기 위한 scroll 이벤트가 발생하지 않는 최대 시간. (default: 100)</ko>
* @property - Whether to prevent being selected. (default: true) <ko>셀렉트가 되는 것을 막을지 여부. (default: true) </ko>
* @property - Whether to prevent click event when dragging. (default: false) <ko>드래그하면 클릭이벤트를 막을지 여부. (default: true)</ko>
Expand All @@ -20,6 +21,7 @@ export interface ConveyerOptions {
horizontal?: boolean;
itemSelector?: string;
useDrag?: boolean;
useSideWheel?: boolean;
scrollDebounce?: number;
preventDefault?: boolean;
preventClickOnDrag?: boolean;
Expand Down
1 change: 1 addition & 0 deletions packages/conveyer/test/manual/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
<script>
const conveyer = new Conveyer(".items", {
preventClickOnDrag: true,
useSideWheel: true,
});

conveyer.on("reachStart", () => {
Expand Down
74 changes: 74 additions & 0 deletions packages/conveyer/test/manual/nested.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<style>
body {
background: #F0F3FB;
margin-left: 0;
margin-right: 0;
}

.items {
position: relative;
overflow: scroll hidden;
width: 100%;
white-space: nowrap;
overscroll-behavior: none;
user-select: none;
}
.container {
display: block;
position: relative;
width: 100%;
}

.item {
display: inline-block;
overflow: hidden;
margin: 18px 12px 30px 0;
width: 271px;
height: 244px;
line-height: 244px;
text-align: center;
font-weight: bold;
font-size: 40px;
border-radius: 3px;
background-color: #fff;
-webkit-box-shadow: 0 2px 2px 0 rgb(0 0 0 / 4%), 0 0 2px 0 rgb(0 0 0 / 15%);
box-shadow: 0 2px 2px 0 rgb(0 0 0 / 4%), 0 0 2px 0 rgb(0 0 0 / 15%);
}
</style>

<body>
<div class="items">
<div class="item">1</div>
<div class="item">2</div>
<div class="nested item">
<div class="item">3.1</div>
<div class="item">3.2</div>
<div class="item">3.3</div>
<div class="item">3.4</div>
<div class="item">3.5</div>
</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
<div class="item">7</div>
<div class="item">8</div>
<div class="item">9</div>
<div class="item">10</div>
<div class="item">11</div>
<div class="item">12</div>
</div>
</body>
<script src="../../dist/conveyer.js"></script>
<script>
const conveyer = new Conveyer(".items", {
preventClickOnDrag: true,
useSideWheel: true,
});
conveyer.init();
const nested = new Conveyer(".nested", {
preventClickOnDrag: true,
nested: true,
useSideWheel: true,
});
nested.init();
</script>
1 change: 1 addition & 0 deletions packages/conveyer/test/manual/vertical.html
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
<script>
const conveyer = new Conveyer(".items", {
preventClickOnDrag: true,
useSideWheel: true,
horizontal: false,
});

Expand Down
38 changes: 35 additions & 3 deletions packages/conveyer/test/unit/Conveyer.spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import {
cleanup,
dispatchDrag,
dispatchWheel,
sandbox,
waitEvent,
waitFor,
} from "./utils/utils";
import * as sinon from "sinon";
import Conveyer from "src";
import { CONVEYER_HTML, NESTED_CONVEYER_HTML } from "./utils/consts";
import {
HORIZONTAL_CONVEYER,
VERTICAL_CONVEYER,
NESTED_CONVEYER,
} from "./utils/consts";
import * as browserModules from "../../src/browser";
import { ImportMock } from "ts-mock-imports";

Expand All @@ -18,7 +23,7 @@ describe("test Conveyer", () => {
beforeEach(() => {
container = sandbox("")!;

container.innerHTML = CONVEYER_HTML;
container.innerHTML = HORIZONTAL_CONVEYER;
});

afterEach(() => {
Expand Down Expand Up @@ -597,11 +602,38 @@ describe("test Conveyer", () => {
});
});
describe("Options", () => {
describe("useSideWheel", () => {
["vertical", "horizontal"].forEach((direction) => {
[true, false].forEach((useSideWheel) => {
it(`should check if the ${direction} conveyer is moved by the side wheel only when useSideWheel is true (useSideWheel: ${useSideWheel})`, async () => {
// Given
container.innerHTML = direction === "horizontal" ? HORIZONTAL_CONVEYER : VERTICAL_CONVEYER;
conveyer = new Conveyer(".items", {
horizontal: direction === "horizontal",
useSideWheel,
});

// When
await dispatchWheel(
document.querySelector<HTMLElement>(".items")!,
direction === "vertical" ? "horizontal" : "vertical", // opposite side
600,
{ duration: 200, interval: 10 }
);
await waitFor(200); // wait until release animation is finished

// Then
expect(conveyer.scrollPos).to.be.equals(useSideWheel ? 600 : 0);
});
});
});
});

describe("nested", () => {
let childConveyer!: Conveyer;

beforeEach(() => {
container.innerHTML = NESTED_CONVEYER_HTML;
container.innerHTML = NESTED_CONVEYER;
conveyer = new Conveyer("#parent");
});

Expand Down
Loading

0 comments on commit 3cdeab5

Please sign in to comment.