UNPKG

@avatijs/listener

Version:

Listener package part of Avati project

970 lines (938 loc) 33.2 kB
/*! * @avatijs/listener 0.1.1 * Copyright (c) 2024 Khaled Sameer <khaled.smq@hotmail.com> * Licensed under MIT, https://opensource.org/licenses/MIT/ * Please visit https://avati.io/ for details. */ /* eslint-disable */ (function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define("Avati", [], factory); else if(typeof exports === 'object') exports["Avati"] = factory(); else root["Avati"] = root["Avati"] || {}, root["Avati"]["Listener"] = factory(); })(typeof self !== 'undefined' ? self : this, () => { return /******/ (() => { // webpackBootstrap /******/ var __webpack_modules__ = ({ /***/ 747: /***/ (function(module) { /*! * @avatijs/debounce 0.1.2 * Copyright (c) 2024 Khaled Sameer <khaled.smq@hotmail.com> * Licensed under MIT, https://opensource.org/licenses/MIT/ * Please visit https://avati.io/ for details. */ /* eslint-disable */ (function webpackUniversalModuleDefinition(root, factory) { if(true) module.exports = factory(); else {} })(typeof self !== 'undefined' ? self : this, () => { return /******/ (() => { // webpackBootstrap /******/ "use strict"; /******/ // The require scope /******/ var __nested_webpack_require_786__ = {}; /******/ /************************************************************************/ /******/ /* webpack/runtime/define property getters */ /******/ (() => { /******/ // define getter functions for harmony exports /******/ __nested_webpack_require_786__.d = (exports, definition) => { /******/ for(var key in definition) { /******/ if(__nested_webpack_require_786__.o(definition, key) && !__nested_webpack_require_786__.o(exports, key)) { /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); /******/ } /******/ } /******/ }; /******/ })(); /******/ /******/ /* webpack/runtime/hasOwnProperty shorthand */ /******/ (() => { /******/ __nested_webpack_require_786__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) /******/ })(); /******/ /******/ /* webpack/runtime/make namespace object */ /******/ (() => { /******/ // define __esModule on exports /******/ __nested_webpack_require_786__.r = (exports) => { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ })(); /******/ /************************************************************************/ var __nested_webpack_exports__ = {}; // ESM COMPAT FLAG __nested_webpack_require_786__.r(__nested_webpack_exports__); // EXPORTS __nested_webpack_require_786__.d(__nested_webpack_exports__, { debounce: () => (/* reexport */ debounce) }); ;// ./src/debouce.ts /** * Advanced debounce utility with TypeScript support * Provides a way to limit the rate at which a function can fire by delaying its execution * until after a specified amount of time has elapsed since its last invocation. * @module debounce */ /** WeakMap to store private state for each debounced function */ const privateState = new WeakMap(); /** * Creates a logger instance based on debug flag * @param debug - Whether debug logging is enabled * @returns Object with logging methods * @private */ const createLogger = (debug) => ({ log: (...args) => debug && console.log('[Debounce]', ...args), warn: (...args) => debug && console.warn('[Debounce]', ...args), error: (...args) => debug && console.error('[Debounce]', ...args), }); /** * Creates a debounced version of the provided function that delays invoking func until after * wait milliseconds have elapsed since the last time the debounced function was invoked. * * @template T - The type of the function to debounce * @param {T} func - The function to debounce * @param {DebounceOptions} [options={}] - Configuration options * @returns {DebouncedFunction<T>} The debounced function * @throws {TypeError} If func is not a function * @throws {RangeError} If wait or maxWait values are invalid * @throws {Error} If neither leading nor trailing is true * * @example * const debouncedFn = debounce(async (x: number) => x * 2, { wait: 1000 }); * await debouncedFn(5); // Will execute after 1000ms of inactivity * const debouncedFn = debounce( * async (x: number) => x * 2, * { * wait: 1000, * onError: (error) => console.error('Error in debounced function:', error) * } * ); */ function debounce(func, options = {}) { // Input validation if (typeof func !== 'function') { throw new TypeError('Expected a function'); } const { wait = 0, leading = false, trailing = true, maxWait, debug = false, signal, onError, } = options; // Validate options if (wait < 0 || (maxWait !== undefined && maxWait < wait)) { throw new RangeError('Invalid wait/maxWait values'); } if (!leading && !trailing) { throw new Error('At least one of leading or trailing must be true'); } const logger = createLogger(debug); const state = { lastInvokeTime: 0, pendingPromises: [], aborted: false, }; // Setup abort controller handling if (signal) { signal.addEventListener('abort', () => { state.aborted = true; cancel(); }); } /** * Cancels all active timers * @private */ function cancelTimers() { if (state.timerId !== undefined) { clearTimeout(state.timerId); state.timerId = undefined; logger.log('Cleared debounce timer'); } if (state.maxTimerId !== undefined) { clearTimeout(state.maxTimerId); state.maxTimerId = undefined; logger.log('Cleared max wait timer'); } } /** * Cancels any pending function invocations * Rejects all pending promises and resets internal state */ function cancel() { logger.log('Cancelling pending invocations'); cancelTimers(); state.lastInvokeTime = 0; state.lastArgs = undefined; state.lastThis = undefined; state.lastCallTime = undefined; const error = new Error('Debounced function cancelled'); handleError(error); state.pendingPromises.forEach(({ reject }) => reject(new Error('Debounced function cancelled'))); state.pendingPromises = []; } /** * Handles errors during function execution * @param {Error} error - The error that occurred * @private */ function handleError(error) { logger.error('Error occurred:', error); if (onError) { try { onError(error); } catch (callbackError) { logger.error('Error in onError callback:', callbackError); } } } /** * Checks if there are any pending function invocations * @returns {boolean} True if there are pending invocations */ function pending() { return state.timerId !== undefined; } /** * Determines if the function should be invoked based on timing conditions * @param {number} time - Current timestamp * @returns {boolean} True if function should be invoked * @private */ function shouldInvoke(time) { if (state.aborted) return false; const timeSinceLastCall = state.lastCallTime === undefined ? 0 : time - state.lastCallTime; const timeSinceLastInvoke = time - state.lastInvokeTime; return (state.lastCallTime === undefined || timeSinceLastCall >= wait || timeSinceLastCall < 0 || (maxWait !== undefined && timeSinceLastInvoke >= maxWait)); } /** * Executes the underlying function and manages promise resolution * @param {number} time - Current timestamp * @returns {Promise} Promise resolving to function result * @private */ async function invokeFunc(time) { logger.log(`Invoking function at ${time}`); state.lastInvokeTime = time; const args = state.lastArgs; const thisArg = state.lastThis; state.lastArgs = undefined; state.lastThis = undefined; try { const result = await func.apply(thisArg, args); state.result = result; state.pendingPromises.forEach(({ resolve }) => resolve(result)); state.pendingPromises = []; logger.log('Function invoked successfully', result); return result; } catch (error) { const wrappedError = error instanceof Error ? error : new Error(String(error)); logger.error('Error in function invocation:', wrappedError); handleError(wrappedError); // Clear pending promises after handling error const currentPromises = [...state.pendingPromises]; state.pendingPromises = []; // Reject all pending promises currentPromises.forEach(({ reject }) => reject(wrappedError)); } } /** * Starts both the debounce timer and maxWait timer if configured * @param {number} time - Current timestamp * @private */ function startTimer(time) { const remainingTime = remainingWait(time); state.timerId = setTimeout(timerExpired, remainingTime); logger.log(`Started debounce timer for ${remainingTime}ms`); if (maxWait !== undefined && !state.maxTimerId) { const timeToMaxWait = maxWait - (time - state.lastCallTime); state.maxTimerId = setTimeout(() => { logger.log('Max wait timer expired'); cancelTimers(); invokeFunc(Date.now()); }, Math.max(0, timeToMaxWait)); logger.log(`Started max wait timer for ${timeToMaxWait}ms`); } } /** * Calculates remaining wait time before next execution * @param {number} time - Current timestamp * @returns {number} Milliseconds until next allowed execution * @private */ function remainingWait(time) { const timeSinceLastCall = state.lastCallTime ? time - state.lastCallTime : 0; return Math.max(0, wait - timeSinceLastCall); } /** * Handles timer expiration * @private */ function timerExpired() { const time = Date.now(); logger.log('Debounce timer expired'); if (shouldInvoke(time)) { return trailingEdge(time); } startTimer(time); } /** * Handles leading edge execution * @param {number} time - Current timestamp * @private */ function leadingEdge(time) { logger.log('Leading edge triggered'); state.lastInvokeTime = time; startTimer(time); if (leading) { invokeFunc(time); } } /** * Handles trailing edge execution * @param {number} time - Current timestamp * @private */ function trailingEdge(time) { logger.log('Trailing edge triggered'); cancelTimers(); if (trailing && state.lastArgs) { invokeFunc(time); } else { state.pendingPromises.forEach(({ resolve }) => { resolve(state.result); }); state.pendingPromises = []; } } /** * Immediately executes the debounced function * @param {...Parameters<T>} args - Function arguments * @returns {Promise<ReturnType<T>>} Promise resolving to function result */ async function flush(...args) { logger.log('Flush requested'); const argsToUse = args.length > 0 ? args : state.lastArgs; const thisArg = state.lastThis; cancelTimers(); if (argsToUse) { state.lastArgs = argsToUse; state.lastThis = thisArg; return invokeFunc(Date.now()); } return Promise.resolve(state.result); } /** * Cleans up resources used by the debounced function */ function cleanup() { logger.log('Cleanup initiated'); cancel(); privateState.delete(debounced); } /** * The debounced function that wraps the original * @param {...Parameters<T>} args - Function arguments * @returns {Promise<ReturnType<T>>} Promise resolving to function result */ const debounced = function (...args) { if (state.aborted) { return Promise.reject(new Error('Debounced function aborted')); } const time = Date.now(); const isInvoking = shouldInvoke(time); state.lastArgs = args; state.lastThis = this; state.lastCallTime = time; logger.log('Function called', { time, isInvoking, args, pending: pending(), }); return new Promise((resolve, reject) => { state.pendingPromises.push({ resolve, reject }); if (state.timerId === undefined) { leadingEdge(time); } else { cancelTimers(); startTimer(time); } }); }; // Store private state privateState.set(debounced, state); // Add utility methods Object.defineProperties(debounced, { cancel: { value: cancel, writable: false, configurable: false }, flush: { value: flush, writable: false, configurable: false }, pending: { value: pending, writable: false, configurable: false }, cleanup: { value: cleanup, writable: false, configurable: false }, }); return debounced; } ;// ./src/index.ts /******/ return __nested_webpack_exports__; /******/ })() ; }); //# sourceMappingURL=index.js.map /***/ }), /***/ 94: /***/ (function(module) { /*! * @avatijs/throttle 0.1.2 * Copyright (c) 2024 Khaled Sameer <khaled.smq@hotmail.com> * Licensed under MIT, https://opensource.org/licenses/MIT/ * Please visit https://avati.io/ for details. */ /* eslint-disable */ (function webpackUniversalModuleDefinition(root, factory) { if(true) module.exports = factory(); else {} })(typeof self !== 'undefined' ? self : this, () => { return /******/ (() => { // webpackBootstrap /******/ "use strict"; /******/ // The require scope /******/ var __nested_webpack_require_786__ = {}; /******/ /************************************************************************/ /******/ /* webpack/runtime/define property getters */ /******/ (() => { /******/ // define getter functions for harmony exports /******/ __nested_webpack_require_786__.d = (exports, definition) => { /******/ for(var key in definition) { /******/ if(__nested_webpack_require_786__.o(definition, key) && !__nested_webpack_require_786__.o(exports, key)) { /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); /******/ } /******/ } /******/ }; /******/ })(); /******/ /******/ /* webpack/runtime/hasOwnProperty shorthand */ /******/ (() => { /******/ __nested_webpack_require_786__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) /******/ })(); /******/ /******/ /* webpack/runtime/make namespace object */ /******/ (() => { /******/ // define __esModule on exports /******/ __nested_webpack_require_786__.r = (exports) => { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ })(); /******/ /************************************************************************/ var __nested_webpack_exports__ = {}; // ESM COMPAT FLAG __nested_webpack_require_786__.r(__nested_webpack_exports__); // EXPORTS __nested_webpack_require_786__.d(__nested_webpack_exports__, { throttle: () => (/* reexport */ throttle) }); ;// ./src/throttle.ts /** * Creates a throttled version function that limits the rate at which it executes. * * @param callback - The function to throttle * @param limit - The minimum time (in milliseconds) that must pass between function executions defaults to 120ms * @param {ThrottleOptions} options - Configuration options for the throttle behavior * * @returns A throttled version of the provided callback function * * @example * const throttledHandler = throttle( * (event: MouseEvent) => console.log(event.clientX), * 250, * { leading: false, trailing: false } * ); * window.addEventListener('mousemove', throttledHandler); */ function throttle(callback, limit = 1000 / 120, // 120 FPS options = {}) { let timeoutId; let lastCallTime = null; let savedArgs = null; let savedThis = null; let isExecuting = false; const { leading = true, trailing = true, onError } = options; /** * Invokes the callback with the saved context and arguments. */ const invokeCallback = () => { if (savedArgs === null) return; isExecuting = true; const startTime = now(); try { callback.apply(savedThis, savedArgs); } catch (error) { if (onError) { onError(error instanceof Error ? error : new Error(String(error))); } else { throw error; } } finally { isExecuting = false; } lastCallTime = now(); savedArgs = null; savedThis = null; // Track execution time const executionTime = now() - startTime; if (executionTime > limit) { console.warn(`Execution time (${executionTime}ms) exceeded throttle limit (${limit}ms)`); } }; /** * Handles trailing edge execution with optimized timing */ const trailingExecute = () => { if (timeoutId) { clearTimeout(timeoutId); timeoutId = undefined; if (!isExecuting && trailing && savedArgs) { const timeSinceLastCall = lastCallTime ? now() - lastCallTime : Infinity; // Only execute if enough time has passed if (timeSinceLastCall >= limit) { invokeCallback(); return true; } } } return false; }; /** * Starts the timer for the trailing edge invocation. * @param remaining - The remaining time before the callback should be invoked. */ const startTimer = (remaining) => { timeoutId = setTimeout(() => { timeoutId = undefined; if (trailing) { invokeCallback(); } }, remaining); }; const now = typeof performance !== 'undefined' ? () => performance.now() : () => Date.now(); /** * The throttled function that controls the execution rate of the callback. */ const throttled = function (...args) { const _now = now(); // Handle first call optimization if (lastCallTime === null) { if (leading) { savedArgs = args; // eslint-disable-next-line @typescript-eslint/no-this-alias savedThis = this; invokeCallback(); return; } lastCallTime = _now; } const remaining = lastCallTime ? limit - (_now - lastCallTime) : 0; savedArgs = args; // eslint-disable-next-line @typescript-eslint/no-this-alias savedThis = this; if (remaining < 0 || remaining > limit) { if (timeoutId) { clearTimeout(timeoutId); timeoutId = undefined; } lastCallTime = _now; invokeCallback(); } else if (!timeoutId && trailing) { startTimer(remaining); } }; /** * Cancels any pending executions and resets the throttle state. */ throttled.cancel = () => { if (timeoutId) { clearTimeout(timeoutId); } lastCallTime = null; savedArgs = null; savedThis = null; timeoutId = undefined; isExecuting = false; }; /** * Immediately invokes the pending execution of the throttled function. */ throttled.flush = () => { trailingExecute(); }; return throttled; } ;// ./src/index.ts /******/ return __nested_webpack_exports__; /******/ })() ; }); //# sourceMappingURL=index.js.map /***/ }) /******/ }); /************************************************************************/ /******/ // The module cache /******/ var __webpack_module_cache__ = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache /******/ var cachedModule = __webpack_module_cache__[moduleId]; /******/ if (cachedModule !== undefined) { /******/ return cachedModule.exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = __webpack_module_cache__[moduleId] = { /******/ // no module.id needed /******/ // no module.loaded needed /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /************************************************************************/ /******/ /* webpack/runtime/define property getters */ /******/ (() => { /******/ // define getter functions for harmony exports /******/ __webpack_require__.d = (exports, definition) => { /******/ for(var key in definition) { /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); /******/ } /******/ } /******/ }; /******/ })(); /******/ /******/ /* webpack/runtime/hasOwnProperty shorthand */ /******/ (() => { /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) /******/ })(); /******/ /******/ /* webpack/runtime/make namespace object */ /******/ (() => { /******/ // define __esModule on exports /******/ __webpack_require__.r = (exports) => { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ })(); /******/ /************************************************************************/ var __webpack_exports__ = {}; // This entry needs to be wrapped in an IIFE because it needs to be in strict mode. (() => { "use strict"; // ESM COMPAT FLAG __webpack_require__.r(__webpack_exports__); // EXPORTS __webpack_require__.d(__webpack_exports__, { EventListenerManager: () => (/* reexport */ EventListenerManager) }); // EXTERNAL MODULE: ../debounce/dist/umd/index.js var umd = __webpack_require__(747); // EXTERNAL MODULE: ../throttle/dist/umd/index.js var dist_umd = __webpack_require__(94); ;// ./src/EventListenerManager.ts var _a, _b, _c; // Private symbol declarations const _listeners = Symbol('listeners'); const _weakRefMap = Symbol('weakRefMap'); const _handleWeakRef = Symbol('handleWeakRef'); const _validateParams = Symbol('validateParams'); const _generateEventId = Symbol('generateEventId'); const _eventIdCounter = Symbol('eventIdCounter'); class EventListenerManager { constructor() { Object.defineProperty(this, "defaultOptions", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, _a, { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, _b, { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, _c, { enumerable: true, configurable: true, writable: true, value: void 0 }); // TODO - Add more event mappings Object.defineProperty(this, "EVENT_MAPPINGS", { enumerable: true, configurable: true, writable: true, value: { debounce: new Set(['input', 'change', 'keyup', 'keydown', 'focus', 'blur', 'click']), throttle: new Set(['mousemove', 'scroll', 'resize', 'wheel']), } }); this[_listeners] = new Map(); this[_weakRefMap] = new WeakMap(); this[_eventIdCounter] = 0; // Bind methods to preserve context this.add = this.add.bind(this); this.remove = this.remove.bind(this); this.defaultOptions = Object.freeze({ capture: false, passive: true, once: false, async: false, }); } /** * Adds an event listener with advanced options. * @param element - The target element to attach the event listener. * @param eventType - The type of the event to listen for. * @param callback - The callback function to execute when the event is triggered. * @param options - Additional options for the event listener. * @returns A unique EventId representing the event listener. */ add(element, eventType, callback, options = {}) { this[_validateParams](element, eventType, callback); const eventId = this[_generateEventId](); const finalOptions = { ...this.defaultOptions, ...options }; let enhancedCallback = callback; if (finalOptions.debounce && finalOptions.throttle) { throw new Error('Cannot specify both debounce and throttle options'); } // Create the async wrapper first if needed if (finalOptions.async) { const asyncCallback = async (event) => { try { await callback(event); } catch (error) { if (finalOptions.onError && error instanceof Error) { finalOptions.onError(error); } else { throw error; } } }; enhancedCallback = asyncCallback; } // Apply debounce/throttle after async wrapper if (finalOptions.debounce) { // check recommendation this.recommendation(eventType, 'debounce'); enhancedCallback = (0,umd.debounce)(enhancedCallback, { wait: finalOptions.debounce, leading: finalOptions.leading, trailing: finalOptions.trailing, debug: finalOptions.debug, onError: finalOptions.onError, }); } else if (finalOptions.throttle) { this.recommendation(eventType, 'throttle'); enhancedCallback = (0,dist_umd.throttle)(enhancedCallback, finalOptions.throttle, { leading: finalOptions.leading, trailing: finalOptions.trailing, onError: finalOptions.onError, }); } // Create wrapper that includes event metadata and error handling const wrappedCallback = async (event) => { if (finalOptions.metadata) { event.metadata = { timestamp: Date.now(), eventId, originalCallback: callback.name || 'anonymous', }; } try { await enhancedCallback.call(element, event); } catch (error) { if (finalOptions.onError && error instanceof Error) { finalOptions.onError(error); } else { throw error; } } // Handle 'once' option if (finalOptions.once) { this.remove(eventId); } }; // Store listener details const listenerDetails = { element: new WeakRef(element), eventType, callback: wrappedCallback, originalCallback: callback, options: finalOptions, timestamp: Date.now(), }; this[_listeners].set(eventId, listenerDetails); this[_handleWeakRef](element, eventId); element.addEventListener(eventType, wrappedCallback, finalOptions); return eventId; } /** * Removes an event listener */ remove(eventId) { const listener = this[_listeners].get(eventId); if (!listener) return false; const element = listener.element.deref(); if (element) { element.removeEventListener(listener.eventType, listener.callback, listener.options); // Remove eventId from _weakRefMap const elementRefs = this[_weakRefMap].get(element); if (elementRefs) { elementRefs.delete(eventId); if (elementRefs.size === 0) { this[_weakRefMap].delete(element); } } } this[_listeners].delete(eventId); return true; } /** * Adds event listener with automatic cleanup */ addWithCleanup(element, eventType, callback, options = {}) { const eventId = this.add(element, eventType, callback, options); return () => this.remove(eventId); } /** * Gets all active listeners for an element */ getListeners(element) { const elementRefs = this[_weakRefMap].get(element); if (!elementRefs) return []; return Array.from(elementRefs) .map((eventId) => { const listener = this[_listeners].get(eventId); if (!listener) return null; const el = listener.element.deref(); if (!el || el !== element) return null; return { eventId, eventType: listener.eventType, options: listener.options, timestamp: listener.timestamp, }; }) .filter((item) => item !== null); } /** * Removes all listeners from an element */ removeAll(element) { const elementRefs = this[_weakRefMap].get(element); if (!elementRefs) return; for (const eventId of elementRefs) { this.remove(eventId); } this[_weakRefMap].delete(element); } /** * Creates a one-time event listener that auto-removes */ once(element, eventType, callback, options = {}) { return this.add(element, eventType, callback, { ...options, once: true }); } /** * Validates input parameters * @private */ [(_a = _listeners, _b = _weakRefMap, _c = _eventIdCounter, _validateParams)](element, eventType, callback) { if (!(element instanceof Element || element instanceof Window || element instanceof Document)) { throw new TypeError('Element must be an instance of Element, Window, or Document'); } if (typeof eventType !== 'string') { throw new TypeError('Event type must be a string'); } if (typeof callback !== 'function') { throw new TypeError('Callback must be a function'); } } /** * Generates a unique event ID * @private */ [_generateEventId]() { return `event_${++this[_eventIdCounter]}`; } /** * Handles WeakRef management * @private */ [_handleWeakRef](element, eventId) { let elementRefs = this[_weakRefMap].get(element); if (!elementRefs) { elementRefs = new Set(); this[_weakRefMap].set(element, elementRefs); } elementRefs.add(eventId); } recommendation(eventType, limiterType) { const oppositeType = limiterType === 'throttle' ? 'debounce' : 'throttle'; if (this.EVENT_MAPPINGS[oppositeType].has(eventType)) { console.warn(`Event type '${eventType}' is recommended to be ${oppositeType}d instead of ${limiterType}d.`); } } } ;// ./src/index.ts })(); /******/ return __webpack_exports__; /******/ })() ; }); //# sourceMappingURL=index.js.map