Skip to content

Commit

Permalink
Merge pull request #216 from Broadway33/update-upstream
Browse files Browse the repository at this point in the history
Add option to define a selection of MouseButtons to ignore
  • Loading branch information
simonwep committed Dec 9, 2023
2 parents 563e43a + 0de0275 commit ff34f72
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 1 deletion.
6 changes: 5 additions & 1 deletion packages/vanilla/src/index.ts
@@ -1,7 +1,7 @@
import {EventTarget} from './EventEmitter';
import type {AreaLocation, Coordinates, ScrollEvent, SelectionEvents, SelectionOptions, SelectionStore} from './types';
import {PartialSelectionOptions} from './types';
import {css, frames, Frames, intersects, isSafariBrowser, isTouchDevice, off, on, selectAll, SelectAllSelectors, simplifyEvent} from './utils';
import {css, frames, Frames, intersects, isSafariBrowser, isTouchDevice, off, on, selectAll, SelectAllSelectors, simplifyEvent, shouldTrigger} from './utils';

// Re-export types
export * from './types';
Expand Down Expand Up @@ -69,6 +69,7 @@ export default class SelectionArea extends EventTarget<SelectionEvents> {
behaviour: {
overlap: 'invert',
intersect: 'touch',
triggers: [0],
...opt.behaviour,
startThreshold: opt.behaviour?.startThreshold ?
typeof opt.behaviour.startThreshold === 'number' ?
Expand Down Expand Up @@ -154,6 +155,9 @@ export default class SelectionArea extends EventTarget<SelectionEvents> {
const {_options} = this;
const {document} = this._options;
const targetBoundingClientRect = target.getBoundingClientRect();

if (evt instanceof MouseEvent && !shouldTrigger(evt, _options.behaviour.triggers))
return;

// Find start-areas and boundaries
const startAreas = selectAll(_options.startAreas, _options.document);
Expand Down
20 changes: 20 additions & 0 deletions packages/vanilla/src/types.ts
Expand Up @@ -55,6 +55,25 @@ export interface Coordinates {
export type TapMode = 'touch' | 'native';
export type OverlapMode = 'keep' | 'drop' | 'invert';

// https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button#value
export type MouseButton = 0 // Main
| 1 // Auxiliary
| 2 // Secondary
| 3 // Fourth
| 4; // Fifth

export type Modifier = 'ctrl'
| 'meta'
| 'alt'
| 'shift';

export type Trigger = MouseButton | MouseButtonWithModifiers;

export type MouseButtonWithModifiers = {
button: MouseButton,
modifiers: Modifier[]
};

export interface Scrolling {
speedDivider: number;
manualSpeed: number;
Expand All @@ -77,6 +96,7 @@ export interface Behaviour {
startThreshold: number | Coordinates;
overlap: OverlapMode;
scrolling: Scrolling;
triggers: Trigger[];
}

export interface SelectionOptions {
Expand Down
1 change: 1 addition & 0 deletions packages/vanilla/src/utils/index.ts
Expand Up @@ -4,3 +4,4 @@ export * from './intersects';
export * from './selectAll';
export * from './constants';
export * from './frames';
export * from './shouldTrigger';
48 changes: 48 additions & 0 deletions packages/vanilla/src/utils/shouldTrigger.ts
@@ -0,0 +1,48 @@
import { Modifier, Trigger } from "../types";

type MouseEventModifierProperty = Extract<keyof MouseEvent, "altKey" | "ctrlKey" | "metaKey" | "shiftKey">;

/**
* Determines whether a MouseEvent should execute until completion depending on
* which button and modifier(s) are active for the MouseEvent.
* The Event will execute to completion if ANY of the triggers "matches"
* @param event MouseEvent that should be checked
* @param triggers A list of Triggers that signify that the event should execute until completion
* @returns Whether the MouseEvent should execute until completion
*/
export function shouldTrigger(event: MouseEvent, triggers: Trigger[]): boolean {
for (const trigger of triggers) {
// The trigger requires only a specific button to be pressed
if (typeof trigger === "number") {
if (event.button === trigger) return true;
}

// The trigger requires a specific button to be pressed AND some modifiers
if (typeof trigger === "object") {
const reqButtonIsPressed = trigger.button === event.button;
const allReqModifiersArePressed = trigger.modifiers.reduce((doActivate, modifier) => {
const prop = modifierToMouseEventProperty(modifier);

if (prop === null) return false;

const modifierIsPressed = event[prop];

return doActivate && modifierIsPressed;
}, true);

if (reqButtonIsPressed && allReqModifiersArePressed) return true;
}
}

// By default we do not process the event
return false;
}

function modifierToMouseEventProperty(modifier: Modifier): MouseEventModifierProperty | null {
if (modifier === "alt") return "altKey";
if (modifier === "ctrl") return "ctrlKey";
if (modifier === "meta") return "metaKey";
if (modifier === "shift") return "shiftKey";

return null;
}

0 comments on commit ff34f72

Please sign in to comment.