From 97d02bb233576764473f0e6033c092c85b18ed4f Mon Sep 17 00:00:00 2001 From: Daragh King Date: Tue, 14 May 2024 12:44:23 +0100 Subject: [PATCH] fix(other): fixed memory leak in click outside decorator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fixed memory leak in click outside decorator ✅ Closes: COMUI-2823 --- .../src/utils/decorator/on-click-outside.ts | 45 +++++++++---------- .../src/utils/decorator/on-mutation.ts | 10 ++--- .../src/utils/decorator/on-resize.ts | 11 +++-- 3 files changed, 34 insertions(+), 32 deletions(-) diff --git a/packages/genesys-spark-components/src/utils/decorator/on-click-outside.ts b/packages/genesys-spark-components/src/utils/decorator/on-click-outside.ts index acb6d9241..90f94426f 100644 --- a/packages/genesys-spark-components/src/utils/decorator/on-click-outside.ts +++ b/packages/genesys-spark-components/src/utils/decorator/on-click-outside.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ /* eslint-disable @typescript-eslint/no-unsafe-return */ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/unbound-method */ @@ -31,59 +32,57 @@ export function OnClickOutside( (BUILD as any).connectedCallback = true; (BUILD as any).disconnectedCallback = true; - // eslint-disable-next-line const { connectedCallback, disconnectedCallback } = proto; + const store = new Map(); + proto.connectedCallback = function () { const host = getElement(this); const method = this[methodName]; - // eslint-disable-next-line @typescript-eslint/no-unsafe-argument - registerOnClickOutside(this, host, method, opt); + + registerOnClickOutside(store, this, host, method, opt); + return connectedCallback && connectedCallback.call(this); }; proto.disconnectedCallback = function () { - const host = getElement(this); - const method = this[methodName]; - // eslint-disable-next-line @typescript-eslint/no-unsafe-argument - removeOnClickOutside(this, host, method, opt); + removeOnClickOutside(store, this, opt); + return disconnectedCallback && disconnectedCallback.call(this); }; }; } export function registerOnClickOutside( + store: Map, component: ComponentInterface, element: HTMLElement, callback: OnClickOutsideCallback, opt: OnClickOutsideOptions = OnClickOutsideOptionsDefaults ): void { const excludedNodes = getExcludedNodes(opt); + const listener = (e: Event) => { + initOnClickOutside(e, component, element, callback, excludedNodes); + }; + + store.set(component, listener); + getTriggerEvents(opt).forEach(triggerEvent => { - window.addEventListener( - triggerEvent, - (e: Event) => { - initOnClickOutside(e, component, element, callback, excludedNodes); - }, - false - ); + window.addEventListener(triggerEvent, listener, false); }); } export function removeOnClickOutside( + store: Map, component: ComponentInterface, - element: HTMLElement, - callback: OnClickOutsideCallback, opt: OnClickOutsideOptions = OnClickOutsideOptionsDefaults ): void { + const listener = store.get(component); + + store.delete(component); + getTriggerEvents(opt).forEach(triggerEvent => { - window.removeEventListener( - triggerEvent, - (e: Event) => { - initOnClickOutside(e, component, element, callback); - }, - false - ); + window.removeEventListener(triggerEvent, listener, false); }); } diff --git a/packages/genesys-spark-components/src/utils/decorator/on-mutation.ts b/packages/genesys-spark-components/src/utils/decorator/on-mutation.ts index 0d4098202..5a2f0792c 100644 --- a/packages/genesys-spark-components/src/utils/decorator/on-mutation.ts +++ b/packages/genesys-spark-components/src/utils/decorator/on-mutation.ts @@ -21,7 +21,7 @@ export function OnMutation(options: MutationObserverInit): OnMutationDecorator { const { connectedCallback, disconnectedCallback } = proto; - const store = new Map(); + const store = new Map(); proto.connectedCallback = function () { const method = this[methodName]; @@ -41,8 +41,8 @@ export function OnMutation(options: MutationObserverInit): OnMutationDecorator { } function registerObserver( - store: Map, - key: unknown, + store: Map, + key: ComponentInterface, observer: MutationObserver, options: MutationObserverInit ) { @@ -56,8 +56,8 @@ function registerObserver( } function deregisterObserver( - store: Map, - key: unknown + store: Map, + key: ComponentInterface ) { if (store.has(key)) { store.get(key).disconnect(); diff --git a/packages/genesys-spark-components/src/utils/decorator/on-resize.ts b/packages/genesys-spark-components/src/utils/decorator/on-resize.ts index 09c066b25..620449eed 100644 --- a/packages/genesys-spark-components/src/utils/decorator/on-resize.ts +++ b/packages/genesys-spark-components/src/utils/decorator/on-resize.ts @@ -21,7 +21,7 @@ export function OnResize(): OnResizeDecorator { const { connectedCallback, disconnectedCallback } = proto; - const store = new Map(); + const store = new Map(); proto.connectedCallback = function () { const method = this[methodName]; @@ -41,8 +41,8 @@ export function OnResize(): OnResizeDecorator { } function registerObserver( - store: Map, - key: unknown, + store: Map, + key: ComponentInterface, observer: ResizeObserver ) { if (store.has(key)) { @@ -54,7 +54,10 @@ function registerObserver( observer.observe(getElement(key)); } -function deregisterObserver(store: Map, key: unknown) { +function deregisterObserver( + store: Map, + key: ComponentInterface +) { if (store.has(key)) { store.get(key).disconnect(); }