planning
All checks were successful
Publish To Prod / deploy_and_publish (push) Successful in 35s

This commit is contained in:
2024-10-14 09:15:30 +02:00
parent bcba00a730
commit 6e64e138e2
21059 changed files with 2317811 additions and 1 deletions

3
node_modules/consolidated-events/.babelrc generated vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"presets": ["airbnb"]
}

1
node_modules/consolidated-events/.eslintignore generated vendored Normal file
View File

@@ -0,0 +1 @@
lib

8
node_modules/consolidated-events/.eslintrc generated vendored Normal file
View File

@@ -0,0 +1,8 @@
{
"extends": "airbnb-base",
"env": {
"browser": true,
"node": true
}
}

7
node_modules/consolidated-events/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,7 @@
language: node_js
sudo: false
node_js:
- "6"
- "7"
- "8"
- "10"

27
node_modules/consolidated-events/CHANGELOG.md generated vendored Normal file
View File

@@ -0,0 +1,27 @@
## v2.0.1
- Move TargetEventHandlers methods to prototype ([#15](https://github.com/lencioni/consolidated-events/pull/15))
## v2.0.0
- Now built with rollup ([#8](https://github.com/lencioni/consolidated-events/pull/8))
- Deprecated `removeEventListener` export removed ([#13](https://github.com/lencioni/consolidated-events/pull/13))
- Passive event listener test is now removed after being added ([#11](https://github.com/lencioni/consolidated-events/pull/11))
- Reduced bundle size impact by replacing a class with a function ([#12](https://github.com/lencioni/consolidated-events/pull/12))
## v1.1.1
- Prevent event handlers from being mutated during current iteration.
## v1.1.0
- Return an unsubscribe function from `addEventListener` and deprecate
`removeEventListener`.
## v1.0.1
- Fix bug with `handleEvent()`.
## v1.0.0
- Initial release.

21
node_modules/consolidated-events/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2016 Joe Lencioni
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

43
node_modules/consolidated-events/README.md generated vendored Normal file
View File

@@ -0,0 +1,43 @@
# consolidated-events <sup>[![Version Badge][npm-version-svg]][package-url]</sup>
[![Build Status][travis-svg]][travis-url]
[![dependency status][deps-svg]][deps-url]
[![dev dependency status][dev-deps-svg]][dev-deps-url]
[![License][license-image]][license-url]
[![Downloads][downloads-image]][downloads-url]
[![npm badge][npm-badge-png]][package-url]
Manage multiple event handlers using few event listeners.
## Example
```js
import { addEventListener } from 'consolidated-events';
const removeEventListener = addEventListener(
window,
'scroll',
() => { console.log('scrolling') },
{ passive: true }
);
...
removeEventListener();
```
[npm-version-svg]: http://versionbadg.es/lencioni/consolidated-events.svg
[package-url]: https://npmjs.org/package/consolidated-events
[travis-svg]: https://travis-ci.org/lencioni/consolidated-events.svg
[travis-url]: https://travis-ci.org/lencioni/consolidated-events
[deps-svg]: https://david-dm.org/lencioni/consolidated-events.svg
[deps-url]: https://david-dm.org/lencioni/consolidated-events
[dev-deps-svg]: https://david-dm.org/lencioni/consolidated-events/dev-status.svg
[dev-deps-url]: https://david-dm.org/lencioni/consolidated-events#info=devDependencies
[license-image]: http://img.shields.io/npm/l/consolidated-events.svg
[license-url]: LICENSE
[downloads-image]: http://img.shields.io/npm/dm/consolidated-events.svg
[downloads-url]: http://npm-stat.com/charts.html?package=consolidated-events
[npm-badge-png]: https://nodei.co/npm/consolidated-events.png?downloads=true&stars=true

6
node_modules/consolidated-events/__tests__/.eslintrc generated vendored Normal file
View File

@@ -0,0 +1,6 @@
{
"env": {
"jasmine": true,
"jest": true
}
}

View File

@@ -0,0 +1,196 @@
import TargetEventHandlers from '../src/TargetEventHandlers';
class MockTarget {
constructor() {
this.addEventListener = jest.fn();
this.removeEventListener = jest.fn();
}
}
describe('#add()', () => {
it('adds a single event listener to the target the first time', () => {
const target = new MockTarget();
const eventHandlers = new TargetEventHandlers(target);
const listener = () => {};
eventHandlers.add('scroll', listener);
expect(target.addEventListener).toHaveBeenCalledTimes(1);
expect(target.addEventListener)
.toHaveBeenCalledWith('scroll', jasmine.any(Function), undefined);
});
it('does not add an event listener to the target the second time', () => {
const target = new MockTarget();
const eventHandlers = new TargetEventHandlers(target);
const listener = () => {};
const listener2 = () => {};
eventHandlers.add('scroll', listener);
eventHandlers.add('scroll', listener2);
expect(target.addEventListener).toHaveBeenCalledTimes(1);
expect(target.addEventListener)
.toHaveBeenCalledWith('scroll', jasmine.any(Function), undefined);
});
it('adds an event listener for each set of options', () => {
const target = new MockTarget();
const eventHandlers = new TargetEventHandlers(target);
const listener = () => {};
const listener2 = () => {};
eventHandlers.add('scroll', listener);
eventHandlers.add('scroll', listener2, { passive: true });
expect(target.addEventListener).toHaveBeenCalledTimes(2);
expect(target.addEventListener)
.toHaveBeenCalledWith('scroll', jasmine.any(Function), undefined);
expect(target.addEventListener)
.toHaveBeenCalledWith('scroll', jasmine.any(Function), { passive: true });
});
it('adds an event listener for each event type', () => {
const target = new MockTarget();
const eventHandlers = new TargetEventHandlers(target);
const listener = () => {};
const listener2 = () => {};
eventHandlers.add('scroll', listener);
eventHandlers.add('resize', listener2);
expect(target.addEventListener).toHaveBeenCalledTimes(2);
expect(target.addEventListener)
.toHaveBeenCalledWith('scroll', jasmine.any(Function), undefined);
expect(target.addEventListener)
.toHaveBeenCalledWith('resize', jasmine.any(Function), undefined);
});
it('returns an unsubscribe function', () => {
const target = new MockTarget();
const eventHandlers = new TargetEventHandlers(target);
const remove = eventHandlers.add('scroll', () => {});
expect(typeof remove).toBe('function');
});
it('unsubscribe deletes the event listener when the only handler is removed', () => {
const target = new MockTarget();
const eventHandlers = new TargetEventHandlers(target);
const remove = eventHandlers.add('scroll', () => {});
remove();
expect(target.removeEventListener).toHaveBeenCalledTimes(1);
expect(target.removeEventListener)
.toHaveBeenCalledWith('scroll', jasmine.any(Function), undefined);
});
it('unsubscribe does not throw when called twice', () => {
const target = new MockTarget();
const eventHandlers = new TargetEventHandlers(target);
const remove = eventHandlers.add('scroll', () => {});
remove();
expect(remove).not.toThrow();
});
it('unsubscribe does not delete the event listener when there are more handlers left', () => {
const target = new MockTarget();
const eventHandlers = new TargetEventHandlers(target);
const remove = eventHandlers.add('scroll', () => {});
eventHandlers.add('scroll', () => {});
remove();
expect(target.removeEventListener).toHaveBeenCalledTimes(0);
});
it('unsubscribe called multiple times does not delete the event listener when there are more handlers left', () => {
const target = new MockTarget();
const eventHandlers = new TargetEventHandlers(target);
const remove = eventHandlers.add('scroll', () => {});
eventHandlers.add('scroll', () => {});
remove();
remove();
expect(target.removeEventListener).toHaveBeenCalledTimes(0);
});
it('unsubscribe deletes the event listener when all handlers are removed', () => {
const target = new MockTarget();
const eventHandlers = new TargetEventHandlers(target);
const remove = eventHandlers.add('scroll', () => {});
const remove2 = eventHandlers.add('scroll', () => {});
remove();
remove2();
expect(target.removeEventListener).toHaveBeenCalledTimes(1);
expect(target.removeEventListener)
.toHaveBeenCalledWith('scroll', jasmine.any(Function), undefined);
});
it('unsubscribe handles different options separately', () => {
const target = new MockTarget();
const eventHandlers = new TargetEventHandlers(target);
const remove = eventHandlers.add('scroll', () => {});
const remove2 = eventHandlers.add('scroll', () => {}, { passive: true });
remove();
remove2();
expect(target.removeEventListener).toHaveBeenCalledTimes(2);
expect(target.removeEventListener)
.toHaveBeenCalledWith('scroll', jasmine.any(Function), undefined);
expect(target.removeEventListener)
.toHaveBeenCalledWith('scroll', jasmine.any(Function), { passive: true });
});
});
describe('#handleEvent', () => {
it('calls each handler', () => {
const target = new MockTarget();
const eventHandlers = new TargetEventHandlers(target);
const handlers = [jest.fn(), jest.fn(), jest.fn()];
handlers.forEach((handler) => {
eventHandlers.add('scroll', handler);
});
const event = {};
eventHandlers.handleEvent('scroll', undefined, event);
handlers.forEach((handler) => {
expect(handler).toHaveBeenCalledTimes(1);
expect(handler).toHaveBeenCalledWith(event);
});
});
it('calls each handler even when one is removed when called', () => {
const target = new MockTarget();
const eventHandlers = new TargetEventHandlers(target);
let remove;
const firstHandler = jest.fn(() => remove());
remove = eventHandlers.add('scroll', firstHandler);
const secondHandler = jest.fn();
eventHandlers.add('scroll', secondHandler);
const event = {};
eventHandlers.handleEvent('scroll', undefined, event);
expect(firstHandler).toHaveBeenCalledTimes(1);
expect(firstHandler).toHaveBeenCalledWith(event);
expect(secondHandler).toHaveBeenCalledTimes(1);
expect(secondHandler).toHaveBeenCalledWith(event);
});
it('calls each handler with options', () => {
const target = new MockTarget();
const eventHandlers = new TargetEventHandlers(target);
const handlers = [jest.fn(), jest.fn(), jest.fn()];
handlers.forEach((handler) => {
eventHandlers.add('scroll', handler, { passive: true });
});
const event = {};
eventHandlers.handleEvent('scroll', { passive: true }, event);
handlers.forEach((handler) => {
expect(handler).toHaveBeenCalledTimes(1);
expect(handler).toHaveBeenCalledWith(event);
});
});
});

View File

@@ -0,0 +1,97 @@
import wrap from 'jest-wrap';
let canUsePassiveEventListeners;
beforeEach(() => {
jest.resetModules();
canUsePassiveEventListeners = require('../src/canUsePassiveEventListeners').default; // eslint-disable-line global-require
});
describe('when not canUseDOM', () => {
beforeEach(() => {
jest.mock('../src/canUseDOM', () => ({ default: false }));
});
it('returns false', () => {
expect(canUsePassiveEventListeners()).toEqual(false);
});
it('returns false multiple times', () => {
expect(canUsePassiveEventListeners()).toEqual(false);
expect(canUsePassiveEventListeners()).toEqual(false);
});
});
wrap()
.withGlobal('window', () => ({
addEventListener() {},
removeEventListener() {},
}))
.describe('when canUseDOM', () => {
beforeEach(() => {
jest.mock('../src/canUseDOM', () => ({ default: true }));
});
wrap()
.withOverride(() => window, 'addEventListener', () => null)
.describe('when addEventListener is not present', () => {
it('returns false', () => {
expect(canUsePassiveEventListeners()).toEqual(false);
});
it('returns false multiple times', () => {
expect(canUsePassiveEventListeners()).toEqual(false);
expect(canUsePassiveEventListeners()).toEqual(false);
});
});
wrap()
.withOverrides(() => window, () => ({
addEventListener: jest.fn(),
removeEventListener: null,
}))
.describe('when removeEventListener is not present', () => {
it('returns false', () => {
expect(canUsePassiveEventListeners()).toEqual(false);
});
it('returns false multiple times', () => {
expect(canUsePassiveEventListeners()).toEqual(false);
expect(canUsePassiveEventListeners()).toEqual(false);
});
it('does not call addEventListener', () => {
canUsePassiveEventListeners();
expect(window.addEventListener).toHaveBeenCalledTimes(0);
});
});
wrap()
.withOverrides(() => window, () => ({
addEventListener: jest.fn(),
}))
.describe('when addEventListener and removeEventListener are present', () => {
it('calls addEventListener', () => {
canUsePassiveEventListeners();
expect(window.addEventListener).toHaveBeenCalledTimes(1);
});
});
wrap()
.withOverride(
() => window,
'addEventListener',
() => jest.fn((event, listener, options) => options.passive /* invoke a getter */),
)
.describe('when "passive" property is accessed', () => {
it('returns true', () => {
expect(canUsePassiveEventListeners()).toEqual(true);
expect(window.addEventListener).toHaveBeenCalledTimes(1);
});
it('is memoized', () => {
expect(canUsePassiveEventListeners()).toEqual(true);
expect(canUsePassiveEventListeners()).toEqual(true);
expect(window.addEventListener).toHaveBeenCalledTimes(1);
});
});
});

View File

@@ -0,0 +1,71 @@
import eventOptionsKey from '../src/eventOptionsKey';
it('treats undefined and false the same', () => {
expect(eventOptionsKey(undefined))
.toBe(eventOptionsKey(false));
});
it('treats false and empty objects the same', () => {
expect(eventOptionsKey(false))
.toBe(eventOptionsKey({}));
});
it('treats empty objects and true differently', () => {
expect(eventOptionsKey({}))
.not.toBe(eventOptionsKey(true));
});
it('treats empty objects and a good option differently', () => {
expect(eventOptionsKey({}))
.not.toBe(eventOptionsKey({ capture: true }));
});
it('treats true and a good option differently', () => {
expect(eventOptionsKey(true))
.not.toBe(eventOptionsKey({ capture: true }));
});
it('treats capture and passive differently', () => {
expect(eventOptionsKey({ capture: true }))
.not.toBe(eventOptionsKey({ passive: true }));
});
it('treats capture and only differently', () => {
expect(eventOptionsKey({ capture: true }))
.not.toBe(eventOptionsKey({ only: true }));
});
it('treats passive and only differently', () => {
expect(eventOptionsKey({ passive: true }))
.not.toBe(eventOptionsKey({ only: true }));
});
it('treats capture/passive differently from capture', () => {
expect(eventOptionsKey({ capture: true, passive: true }))
.not.toBe(eventOptionsKey({ capture: true }));
});
it('treats capture/once differently from capture', () => {
expect(eventOptionsKey({ capture: true, once: true }))
.not.toBe(eventOptionsKey({ capture: true }));
});
it('treats capture/once differently from capture/passive', () => {
expect(eventOptionsKey({ capture: true, once: true }))
.not.toBe(eventOptionsKey({ capture: true, passive: true }));
});
it('treats capture/passive/once differently from capture/passive', () => {
expect(eventOptionsKey({ capture: true, passive: true, once: true }))
.not.toBe(eventOptionsKey({ capture: true, passive: true }));
});
it('treats capture/passive/once differently from capture/once', () => {
expect(eventOptionsKey({ capture: true, passive: true, once: true }))
.not.toBe(eventOptionsKey({ capture: true, once: true }));
});
it('does not care about the order of options', () => {
expect(eventOptionsKey({ capture: true, passive: true, once: true }))
.toBe(eventOptionsKey({ passive: true, once: true, capture: true }));
});

View File

@@ -0,0 +1,34 @@
import { addEventListener } from '../src';
import TargetEventHandlers from '../src/TargetEventHandlers';
class MockTarget {
constructor() {
this.addEventListener = jest.fn();
}
}
const EVENT_HANDLERS_KEY = '__consolidated_events_handlers__';
describe('addEventListener()', () => {
it('initializes an instance of TargetEventHandlers on new targets', () => {
const target = new MockTarget();
addEventListener(target, 'scroll', () => {});
expect(target[EVENT_HANDLERS_KEY]).toBeInstanceOf(TargetEventHandlers);
expect(target[EVENT_HANDLERS_KEY].target).toBe(target);
});
it('normalizes event options', () => {
const target = new MockTarget();
addEventListener(target, 'scroll', () => {}, { capture: true });
expect(target.addEventListener)
.toHaveBeenCalledWith('scroll', jasmine.any(Function), true);
});
it('returns an unsubscribe function', () => {
const target = new MockTarget();
const remove = addEventListener(target, 'scroll', () => {}, { capture: true });
expect(typeof remove).toBe('function');
});
});

View File

@@ -0,0 +1,52 @@
/* eslint-disable import/first */
jest.mock('../src/canUsePassiveEventListeners');
import canUsePassiveEventListeners from '../src/canUsePassiveEventListeners';
import normalizeEventOptions from '../src/normalizeEventOptions';
it('is undefined when event options are undefined', () => {
expect(normalizeEventOptions(undefined)).toBe(undefined);
});
it('is undefined when event options are null', () => {
expect(normalizeEventOptions(null)).toBe(undefined);
});
it('is undefined when event options are false', () => {
expect(normalizeEventOptions(false)).toBe(undefined);
});
describe('when able to use passive event listeners', () => {
beforeEach(() => {
canUsePassiveEventListeners.mockImplementation(() => true);
});
it('passes the eventOptions object through', () => {
expect(normalizeEventOptions({ passive: true }))
.toEqual({ passive: true });
expect(normalizeEventOptions({ capture: true }))
.toEqual({ capture: true });
expect(normalizeEventOptions({ capture: true, passive: true }))
.toEqual({ capture: true, passive: true });
});
});
describe('when not able to use passive event listeners', () => {
beforeEach(() => {
canUsePassiveEventListeners.mockImplementation(() => false);
});
it('is true when the capture option is on', () => {
expect(normalizeEventOptions({ capture: true })).toBe(true);
});
it('is false when the capture option is off', () => {
expect(normalizeEventOptions({ capture: false })).toBe(false);
});
it('is false when the capture option is missing', () => {
expect(normalizeEventOptions({ passive: true })).toBe(false);
});
});

206
node_modules/consolidated-events/lib/index.esm.js generated vendored Normal file
View File

@@ -0,0 +1,206 @@
var CAN_USE_DOM = !!(typeof window !== 'undefined' && window.document && window.document.createElement);
// Adapted from Modernizr
// https://github.com/Modernizr/Modernizr/blob/acb3f0d9/feature-detects/dom/passiveeventlisteners.js#L26-L37
function testPassiveEventListeners() {
if (!CAN_USE_DOM) {
return false;
}
if (!window.addEventListener || !window.removeEventListener || !Object.defineProperty) {
return false;
}
var supportsPassiveOption = false;
try {
var opts = Object.defineProperty({}, 'passive', {
// eslint-disable-next-line getter-return
get: function () {
function get() {
supportsPassiveOption = true;
}
return get;
}()
});
var noop = function noop() {};
window.addEventListener('testPassiveEventSupport', noop, opts);
window.removeEventListener('testPassiveEventSupport', noop, opts);
} catch (e) {
// do nothing
}
return supportsPassiveOption;
}
var memoized = void 0;
function canUsePassiveEventListeners() {
if (memoized === undefined) {
memoized = testPassiveEventListeners();
}
return memoized;
}
function normalizeEventOptions(eventOptions) {
if (!eventOptions) {
return undefined;
}
if (!canUsePassiveEventListeners()) {
// If the browser does not support the passive option, then it is expecting
// a boolean for the options argument to specify whether it should use
// capture or not. In more modern browsers, this is passed via the `capture`
// option, so let's just hoist that value up.
return !!eventOptions.capture;
}
return eventOptions;
}
/* eslint-disable no-bitwise */
/**
* Generate a unique key for any set of event options
*/
function eventOptionsKey(normalizedEventOptions) {
if (!normalizedEventOptions) {
return 0;
}
// If the browser does not support passive event listeners, the normalized
// event options will be a boolean.
if (normalizedEventOptions === true) {
return 100;
}
// At this point, the browser supports passive event listeners, so we expect
// the event options to be an object with possible properties of capture,
// passive, and once.
//
// We want to consistently return the same value, regardless of the order of
// these properties, so let's use binary maths to assign each property to a
// bit, and then add those together (with an offset to account for the
// booleans at the beginning of this function).
var capture = normalizedEventOptions.capture << 0;
var passive = normalizedEventOptions.passive << 1;
var once = normalizedEventOptions.once << 2;
return capture + passive + once;
}
function ensureCanMutateNextEventHandlers(eventHandlers) {
if (eventHandlers.handlers === eventHandlers.nextHandlers) {
// eslint-disable-next-line no-param-reassign
eventHandlers.nextHandlers = eventHandlers.handlers.slice();
}
}
function TargetEventHandlers(target) {
this.target = target;
this.events = {};
}
TargetEventHandlers.prototype.getEventHandlers = function () {
function getEventHandlers(eventName, options) {
var key = String(eventName) + ' ' + String(eventOptionsKey(options));
if (!this.events[key]) {
this.events[key] = {
handlers: [],
handleEvent: undefined
};
this.events[key].nextHandlers = this.events[key].handlers;
}
return this.events[key];
}
return getEventHandlers;
}();
TargetEventHandlers.prototype.handleEvent = function () {
function handleEvent(eventName, options, event) {
var eventHandlers = this.getEventHandlers(eventName, options);
eventHandlers.handlers = eventHandlers.nextHandlers;
eventHandlers.handlers.forEach(function (handler) {
if (handler) {
// We need to check for presence here because a handler function may
// cause later handlers to get removed. This can happen if you for
// instance have a waypoint that unmounts another waypoint as part of an
// onEnter/onLeave handler.
handler(event);
}
});
}
return handleEvent;
}();
TargetEventHandlers.prototype.add = function () {
function add(eventName, listener, options) {
var _this = this;
// options has already been normalized at this point.
var eventHandlers = this.getEventHandlers(eventName, options);
ensureCanMutateNextEventHandlers(eventHandlers);
if (eventHandlers.nextHandlers.length === 0) {
eventHandlers.handleEvent = this.handleEvent.bind(this, eventName, options);
this.target.addEventListener(eventName, eventHandlers.handleEvent, options);
}
eventHandlers.nextHandlers.push(listener);
var isSubscribed = true;
var unsubscribe = function () {
function unsubscribe() {
if (!isSubscribed) {
return;
}
isSubscribed = false;
ensureCanMutateNextEventHandlers(eventHandlers);
var index = eventHandlers.nextHandlers.indexOf(listener);
eventHandlers.nextHandlers.splice(index, 1);
if (eventHandlers.nextHandlers.length === 0) {
// All event handlers have been removed, so we want to remove the event
// listener from the target node.
if (_this.target) {
// There can be a race condition where the target may no longer exist
// when this function is called, e.g. when a React component is
// unmounting. Guarding against this prevents the following error:
//
// Cannot read property 'removeEventListener' of undefined
_this.target.removeEventListener(eventName, eventHandlers.handleEvent, options);
}
eventHandlers.handleEvent = undefined;
}
}
return unsubscribe;
}();
return unsubscribe;
}
return add;
}();
var EVENT_HANDLERS_KEY = '__consolidated_events_handlers__';
// eslint-disable-next-line import/prefer-default-export
function addEventListener(target, eventName, listener, options) {
if (!target[EVENT_HANDLERS_KEY]) {
// eslint-disable-next-line no-param-reassign
target[EVENT_HANDLERS_KEY] = new TargetEventHandlers(target);
}
var normalizedEventOptions = normalizeEventOptions(options);
return target[EVENT_HANDLERS_KEY].add(eventName, listener, normalizedEventOptions);
}
export { addEventListener };

210
node_modules/consolidated-events/lib/index.js generated vendored Normal file
View File

@@ -0,0 +1,210 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var CAN_USE_DOM = !!(typeof window !== 'undefined' && window.document && window.document.createElement);
// Adapted from Modernizr
// https://github.com/Modernizr/Modernizr/blob/acb3f0d9/feature-detects/dom/passiveeventlisteners.js#L26-L37
function testPassiveEventListeners() {
if (!CAN_USE_DOM) {
return false;
}
if (!window.addEventListener || !window.removeEventListener || !Object.defineProperty) {
return false;
}
var supportsPassiveOption = false;
try {
var opts = Object.defineProperty({}, 'passive', {
// eslint-disable-next-line getter-return
get: function () {
function get() {
supportsPassiveOption = true;
}
return get;
}()
});
var noop = function noop() {};
window.addEventListener('testPassiveEventSupport', noop, opts);
window.removeEventListener('testPassiveEventSupport', noop, opts);
} catch (e) {
// do nothing
}
return supportsPassiveOption;
}
var memoized = void 0;
function canUsePassiveEventListeners() {
if (memoized === undefined) {
memoized = testPassiveEventListeners();
}
return memoized;
}
function normalizeEventOptions(eventOptions) {
if (!eventOptions) {
return undefined;
}
if (!canUsePassiveEventListeners()) {
// If the browser does not support the passive option, then it is expecting
// a boolean for the options argument to specify whether it should use
// capture or not. In more modern browsers, this is passed via the `capture`
// option, so let's just hoist that value up.
return !!eventOptions.capture;
}
return eventOptions;
}
/* eslint-disable no-bitwise */
/**
* Generate a unique key for any set of event options
*/
function eventOptionsKey(normalizedEventOptions) {
if (!normalizedEventOptions) {
return 0;
}
// If the browser does not support passive event listeners, the normalized
// event options will be a boolean.
if (normalizedEventOptions === true) {
return 100;
}
// At this point, the browser supports passive event listeners, so we expect
// the event options to be an object with possible properties of capture,
// passive, and once.
//
// We want to consistently return the same value, regardless of the order of
// these properties, so let's use binary maths to assign each property to a
// bit, and then add those together (with an offset to account for the
// booleans at the beginning of this function).
var capture = normalizedEventOptions.capture << 0;
var passive = normalizedEventOptions.passive << 1;
var once = normalizedEventOptions.once << 2;
return capture + passive + once;
}
function ensureCanMutateNextEventHandlers(eventHandlers) {
if (eventHandlers.handlers === eventHandlers.nextHandlers) {
// eslint-disable-next-line no-param-reassign
eventHandlers.nextHandlers = eventHandlers.handlers.slice();
}
}
function TargetEventHandlers(target) {
this.target = target;
this.events = {};
}
TargetEventHandlers.prototype.getEventHandlers = function () {
function getEventHandlers(eventName, options) {
var key = String(eventName) + ' ' + String(eventOptionsKey(options));
if (!this.events[key]) {
this.events[key] = {
handlers: [],
handleEvent: undefined
};
this.events[key].nextHandlers = this.events[key].handlers;
}
return this.events[key];
}
return getEventHandlers;
}();
TargetEventHandlers.prototype.handleEvent = function () {
function handleEvent(eventName, options, event) {
var eventHandlers = this.getEventHandlers(eventName, options);
eventHandlers.handlers = eventHandlers.nextHandlers;
eventHandlers.handlers.forEach(function (handler) {
if (handler) {
// We need to check for presence here because a handler function may
// cause later handlers to get removed. This can happen if you for
// instance have a waypoint that unmounts another waypoint as part of an
// onEnter/onLeave handler.
handler(event);
}
});
}
return handleEvent;
}();
TargetEventHandlers.prototype.add = function () {
function add(eventName, listener, options) {
var _this = this;
// options has already been normalized at this point.
var eventHandlers = this.getEventHandlers(eventName, options);
ensureCanMutateNextEventHandlers(eventHandlers);
if (eventHandlers.nextHandlers.length === 0) {
eventHandlers.handleEvent = this.handleEvent.bind(this, eventName, options);
this.target.addEventListener(eventName, eventHandlers.handleEvent, options);
}
eventHandlers.nextHandlers.push(listener);
var isSubscribed = true;
var unsubscribe = function () {
function unsubscribe() {
if (!isSubscribed) {
return;
}
isSubscribed = false;
ensureCanMutateNextEventHandlers(eventHandlers);
var index = eventHandlers.nextHandlers.indexOf(listener);
eventHandlers.nextHandlers.splice(index, 1);
if (eventHandlers.nextHandlers.length === 0) {
// All event handlers have been removed, so we want to remove the event
// listener from the target node.
if (_this.target) {
// There can be a race condition where the target may no longer exist
// when this function is called, e.g. when a React component is
// unmounting. Guarding against this prevents the following error:
//
// Cannot read property 'removeEventListener' of undefined
_this.target.removeEventListener(eventName, eventHandlers.handleEvent, options);
}
eventHandlers.handleEvent = undefined;
}
}
return unsubscribe;
}();
return unsubscribe;
}
return add;
}();
var EVENT_HANDLERS_KEY = '__consolidated_events_handlers__';
// eslint-disable-next-line import/prefer-default-export
function addEventListener(target, eventName, listener, options) {
if (!target[EVENT_HANDLERS_KEY]) {
// eslint-disable-next-line no-param-reassign
target[EVENT_HANDLERS_KEY] = new TargetEventHandlers(target);
}
var normalizedEventOptions = normalizeEventOptions(options);
return target[EVENT_HANDLERS_KEY].add(eventName, listener, normalizedEventOptions);
}
exports.addEventListener = addEventListener;

54
node_modules/consolidated-events/package.json generated vendored Normal file
View File

@@ -0,0 +1,54 @@
{
"name": "consolidated-events",
"version": "2.0.2",
"description": "Manage multiple event handlers using few event listeners",
"main": "lib/index.js",
"module": "lib/index.esm.js",
"scripts": {
"build": "npm run clean && npm run build:js",
"build:js": "rollup -c",
"check-changelog": "expr $(git status --porcelain 2>/dev/null| grep \"^\\s*M.*CHANGELOG.md\" | wc -l) >/dev/null || (echo 'Please edit CHANGELOG.md' && exit 1)",
"check-only-changelog-changed": "(expr $(git status --porcelain 2>/dev/null| grep -v \"CHANGELOG.md\" | wc -l) >/dev/null && echo 'Only CHANGELOG.md may have uncommitted changes' && exit 1) || exit 0",
"clean": "rimraf lib",
"lint": "eslint .",
"postversion": "git commit package.json CHANGELOG.md -m \"Version $npm_package_version\" && npm run tag && git push && git push --tags && npm publish",
"prepublish": "in-publish && safe-publish-latest && npm run build || not-in-publish",
"pretest": "npm run --silent lint",
"tag": "git tag v$npm_package_version",
"test": "npm run --silent test:js",
"test:js": "jest",
"test:js:watch": "jest --watch",
"version:major": "npm --no-git-tag-version version major",
"version:minor": "npm --no-git-tag-version version minor",
"version:patch": "npm --no-git-tag-version version patch"
},
"repository": {
"type": "git",
"url": "git+https://github.com/lencioni/consolidated-events.git"
},
"keywords": [
"events",
"performance"
],
"author": "Joe Lencioni <joe.lencioni@gmail.com>",
"license": "MIT",
"bugs": {
"url": "https://github.com/lencioni/consolidated-events/issues"
},
"homepage": "https://github.com/lencioni/consolidated-events#readme",
"devDependencies": {
"babel-core": "^6.26.3",
"babel-jest": "^23.0.1",
"babel-preset-airbnb": "^2.5.1",
"eslint": "^4.19.1",
"eslint-config-airbnb-base": "^12.1.0",
"eslint-plugin-import": "^2.12.0",
"in-publish": "^2.0.0",
"jest": "^23.1.0",
"jest-wrap": "^1.4.0",
"rimraf": "^2.6.2",
"rollup": "^0.60.7",
"rollup-plugin-babel": "^3.0.4",
"safe-publish-latest": "^1.1.1"
}
}

22
node_modules/consolidated-events/rollup.config.js generated vendored Normal file
View File

@@ -0,0 +1,22 @@
import babel from 'rollup-plugin-babel';
import pkg from './package.json';
export default {
input: 'src/index.js',
output: [
{
file: pkg.main,
format: 'cjs',
},
{
file: pkg.module,
format: 'esm',
},
],
plugins: [
babel({
babelrc: false,
presets: [['airbnb', { modules: false }]],
}),
],
};

View File

@@ -0,0 +1,94 @@
import eventOptionsKey from './eventOptionsKey';
function ensureCanMutateNextEventHandlers(eventHandlers) {
if (eventHandlers.handlers === eventHandlers.nextHandlers) {
// eslint-disable-next-line no-param-reassign
eventHandlers.nextHandlers = eventHandlers.handlers.slice();
}
}
export default function TargetEventHandlers(target) {
this.target = target;
this.events = {};
}
TargetEventHandlers.prototype.getEventHandlers = function getEventHandlers(eventName, options) {
const key = `${eventName} ${eventOptionsKey(options)}`;
if (!this.events[key]) {
this.events[key] = {
handlers: [],
handleEvent: undefined,
};
this.events[key].nextHandlers = this.events[key].handlers;
}
return this.events[key];
};
TargetEventHandlers.prototype.handleEvent = function handleEvent(eventName, options, event) {
const eventHandlers = this.getEventHandlers(eventName, options);
eventHandlers.handlers = eventHandlers.nextHandlers;
eventHandlers.handlers.forEach((handler) => {
if (handler) {
// We need to check for presence here because a handler function may
// cause later handlers to get removed. This can happen if you for
// instance have a waypoint that unmounts another waypoint as part of an
// onEnter/onLeave handler.
handler(event);
}
});
};
TargetEventHandlers.prototype.add = function add(eventName, listener, options) {
// options has already been normalized at this point.
const eventHandlers = this.getEventHandlers(eventName, options);
ensureCanMutateNextEventHandlers(eventHandlers);
if (eventHandlers.nextHandlers.length === 0) {
eventHandlers.handleEvent = this.handleEvent.bind(this, eventName, options);
this.target.addEventListener(
eventName,
eventHandlers.handleEvent,
options,
);
}
eventHandlers.nextHandlers.push(listener);
let isSubscribed = true;
const unsubscribe = () => {
if (!isSubscribed) {
return;
}
isSubscribed = false;
ensureCanMutateNextEventHandlers(eventHandlers);
const index = eventHandlers.nextHandlers.indexOf(listener);
eventHandlers.nextHandlers.splice(index, 1);
if (eventHandlers.nextHandlers.length === 0) {
// All event handlers have been removed, so we want to remove the event
// listener from the target node.
if (this.target) {
// There can be a race condition where the target may no longer exist
// when this function is called, e.g. when a React component is
// unmounting. Guarding against this prevents the following error:
//
// Cannot read property 'removeEventListener' of undefined
this.target.removeEventListener(
eventName,
eventHandlers.handleEvent,
options,
);
}
eventHandlers.handleEvent = undefined;
}
};
return unsubscribe;
};

6
node_modules/consolidated-events/src/canUseDOM.js generated vendored Normal file
View File

@@ -0,0 +1,6 @@
const CAN_USE_DOM = !!(
(typeof window !== 'undefined' &&
window.document && window.document.createElement)
);
export default CAN_USE_DOM;

View File

@@ -0,0 +1,39 @@
import canUseDOM from './canUseDOM';
// Adapted from Modernizr
// https://github.com/Modernizr/Modernizr/blob/acb3f0d9/feature-detects/dom/passiveeventlisteners.js#L26-L37
function testPassiveEventListeners() {
if (!canUseDOM) {
return false;
}
if (!window.addEventListener || !window.removeEventListener || !Object.defineProperty) {
return false;
}
let supportsPassiveOption = false;
try {
const opts = Object.defineProperty({}, 'passive', {
// eslint-disable-next-line getter-return
get() {
supportsPassiveOption = true;
},
});
const noop = () => {};
window.addEventListener('testPassiveEventSupport', noop, opts);
window.removeEventListener('testPassiveEventSupport', noop, opts);
} catch (e) {
// do nothing
}
return supportsPassiveOption;
}
let memoized;
export default function canUsePassiveEventListeners() {
if (memoized === undefined) {
memoized = testPassiveEventListeners();
}
return memoized;
}

View File

@@ -0,0 +1,30 @@
/* eslint-disable no-bitwise */
/**
* Generate a unique key for any set of event options
*/
export default function eventOptionsKey(normalizedEventOptions) {
if (!normalizedEventOptions) {
return 0;
}
// If the browser does not support passive event listeners, the normalized
// event options will be a boolean.
if (normalizedEventOptions === true) {
return 100;
}
// At this point, the browser supports passive event listeners, so we expect
// the event options to be an object with possible properties of capture,
// passive, and once.
//
// We want to consistently return the same value, regardless of the order of
// these properties, so let's use binary maths to assign each property to a
// bit, and then add those together (with an offset to account for the
// booleans at the beginning of this function).
const capture = normalizedEventOptions.capture << 0;
const passive = normalizedEventOptions.passive << 1;
const once = normalizedEventOptions.once << 2;
return capture + passive + once;
}

14
node_modules/consolidated-events/src/index.js generated vendored Normal file
View File

@@ -0,0 +1,14 @@
import normalizeEventOptions from './normalizeEventOptions';
import TargetEventHandlers from './TargetEventHandlers';
const EVENT_HANDLERS_KEY = '__consolidated_events_handlers__';
// eslint-disable-next-line import/prefer-default-export
export function addEventListener(target, eventName, listener, options) {
if (!target[EVENT_HANDLERS_KEY]) {
// eslint-disable-next-line no-param-reassign
target[EVENT_HANDLERS_KEY] = new TargetEventHandlers(target);
}
const normalizedEventOptions = normalizeEventOptions(options);
return target[EVENT_HANDLERS_KEY].add(eventName, listener, normalizedEventOptions);
}

View File

@@ -0,0 +1,17 @@
import canUsePassiveEventListeners from './canUsePassiveEventListeners';
export default function normalizeEventOptions(eventOptions) {
if (!eventOptions) {
return undefined;
}
if (!canUsePassiveEventListeners()) {
// If the browser does not support the passive option, then it is expecting
// a boolean for the options argument to specify whether it should use
// capture or not. In more modern browsers, this is passed via the `capture`
// option, so let's just hoist that value up.
return !!eventOptions.capture;
}
return eventOptions;
}