@mui/x-internal-gestures
Version:
The core engine of GestureEvents, a modern and robust multi-pointer gesture detection library for JavaScript.
237 lines (218 loc) • 7.79 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.TurnWheelGesture = void 0;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _Gesture = require("../Gesture");
var _utils = require("../utils");
/**
* TurnWheelGesture - Detects wheel events on an element
*
* This gesture tracks mouse wheel or touchpad scroll events on elements, firing events when:
* - The user scrolls/wheels on the element (ongoing)
*
* Unlike other gestures which may have start/ongoing/end states,
* wheel gestures are always considered "ongoing" since they are discrete events.
*/
/**
* Configuration options for the TurnWheelGesture
* Uses the base gesture options with additional wheel-specific options
*/
/**
* Event data specific to wheel gesture events
* Contains information about scroll delta amounts and mode
*/
/**
* Type definition for the CustomEvent created by TurnWheelGesture
*/
/**
* State tracking for the TurnWheelGesture
*/
/**
* TurnWheelGesture class for handling wheel/scroll interactions
*
* This gesture detects when users scroll or use the mouse wheel on elements,
* and dispatches corresponding scroll events with delta information.
* Unlike most gestures, it extends directly from Gesture rather than PointerGesture.
*/
class TurnWheelGesture extends _Gesture.Gesture {
constructor(options) {
super(options);
this.state = {
totalDeltaX: 0,
totalDeltaY: 0,
totalDeltaZ: 0
};
this.isSinglePhase = void 0;
this.eventType = void 0;
this.optionsType = void 0;
this.mutableOptionsType = void 0;
this.mutableStateType = void 0;
/**
* Scaling factor for delta values
* Values > 1 increase sensitivity, values < 1 decrease sensitivity
*/
this.sensitivity = void 0;
/**
* Maximum value for totalDelta values
* Limits how large the accumulated wheel deltas can be
*/
this.max = void 0;
/**
* Minimum value for totalDelta values
* Sets a lower bound for accumulated wheel deltas
*/
this.min = void 0;
/**
* Initial value for totalDelta values
* Sets the starting value for delta trackers
*/
this.initialDelta = void 0;
/**
* Whether to invert the direction of delta changes
* When true, reverses the sign of deltaX, deltaY, and deltaZ values
*/
this.invert = void 0;
// Store bound event handlers to properly remove them
this.handleWheelEventBound = void 0;
this.sensitivity = options.sensitivity ?? 1;
this.max = options.max ?? Number.MAX_SAFE_INTEGER;
this.min = options.min ?? Number.MIN_SAFE_INTEGER;
this.initialDelta = options.initialDelta ?? 0;
this.invert = options.invert ?? false;
this.state.totalDeltaX = this.initialDelta;
this.state.totalDeltaY = this.initialDelta;
this.state.totalDeltaZ = this.initialDelta;
this.handleWheelEventBound = this.handleWheelEvent.bind(this);
}
clone(overrides) {
return new TurnWheelGesture((0, _extends2.default)({
name: this.name,
preventDefault: this.preventDefault,
stopPropagation: this.stopPropagation,
sensitivity: this.sensitivity,
max: this.max,
min: this.min,
initialDelta: this.initialDelta,
invert: this.invert,
requiredKeys: [...this.requiredKeys],
pointerMode: [...this.pointerMode],
preventIf: [...this.preventIf]
}, overrides));
}
init(element, pointerManager, gestureRegistry, keyboardManager) {
super.init(element, pointerManager, gestureRegistry, keyboardManager);
// Add event listener directly to the element
// @ts-expect-error, WheelEvent is correct.
this.element.addEventListener('wheel', this.handleWheelEventBound);
}
destroy() {
// Remove the element-specific event listener
// @ts-expect-error, WheelEvent is correct.
this.element.removeEventListener('wheel', this.handleWheelEventBound);
this.resetState();
super.destroy();
}
resetState() {
this.isActive = false;
this.state = {
totalDeltaX: 0,
totalDeltaY: 0,
totalDeltaZ: 0
};
}
updateOptions(options) {
super.updateOptions(options);
this.sensitivity = options.sensitivity ?? this.sensitivity;
this.max = options.max ?? this.max;
this.min = options.min ?? this.min;
this.initialDelta = options.initialDelta ?? this.initialDelta;
this.invert = options.invert ?? this.invert;
}
/**
* Handle wheel events for a specific element
* @param element The element that received the wheel event
* @param event The original wheel event
*/
handleWheelEvent(event) {
// Check if this gesture should be prevented by active gestures
if (this.shouldPreventGesture(this.element)) {
return;
}
// Get pointers from the PointerManager to use for centroid calculation
const pointers = this.pointerManager.getPointers() || new Map();
const pointersArray = Array.from(pointers.values());
// Update total deltas with scaled values
this.state.totalDeltaX += event.deltaX * this.sensitivity * (this.invert ? -1 : 1);
this.state.totalDeltaY += event.deltaY * this.sensitivity * (this.invert ? -1 : 1);
this.state.totalDeltaZ += event.deltaZ * this.sensitivity * (this.invert ? -1 : 1);
// Apply proper min/max clamping for each axis
// Ensure values stay between min and max bounds
['totalDeltaX', 'totalDeltaY', 'totalDeltaZ'].forEach(axis => {
// First clamp at the minimum bound
if (this.state[axis] < this.min) {
this.state[axis] = this.min;
}
// Then clamp at the maximum bound
if (this.state[axis] > this.max) {
this.state[axis] = this.max;
}
});
// Emit the wheel event
this.emitWheelEvent(pointersArray, event);
}
/**
* Emit wheel-specific events
* @param pointers The current pointers on the element
* @param event The original wheel event
*/
emitWheelEvent(pointers, event) {
// Calculate centroid - either from existing pointers or from the wheel event position
const centroid = pointers.length > 0 ? (0, _utils.calculateCentroid)(pointers) : {
x: event.clientX,
y: event.clientY
};
// Get list of active gestures
const activeGestures = this.gesturesRegistry.getActiveGestures(this.element);
// Create custom event data
const customEventData = {
gestureName: this.name,
centroid,
target: event.target,
srcEvent: event,
phase: 'ongoing',
// Wheel events are always in "ongoing" state
pointers,
timeStamp: event.timeStamp,
deltaX: event.deltaX * this.sensitivity * (this.invert ? -1 : 1),
deltaY: event.deltaY * this.sensitivity * (this.invert ? -1 : 1),
deltaZ: event.deltaZ * this.sensitivity * (this.invert ? -1 : 1),
deltaMode: event.deltaMode,
totalDeltaX: this.state.totalDeltaX,
totalDeltaY: this.state.totalDeltaY,
totalDeltaZ: this.state.totalDeltaZ,
activeGestures,
customData: this.customData
};
// Apply default event behavior if configured
if (this.preventDefault) {
event.preventDefault();
}
if (this.stopPropagation) {
event.stopPropagation();
}
// Event names to trigger
const eventName = (0, _utils.createEventName)(this.name, 'ongoing');
// Dispatch custom events on the element
const domEvent = new CustomEvent(eventName, {
bubbles: true,
cancelable: true,
composed: true,
detail: customEventData
});
this.element.dispatchEvent(domEvent);
}
}
exports.TurnWheelGesture = TurnWheelGesture;