UNPKG

stencil-click-outside

Version:

Decorator for StencilJs to run annotated method on click outside of component.

107 lines (106 loc) 3.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var core_1 = require("@stencil/core"); var ClickOutsideOptionsDefaults = { triggerEvents: "click", exclude: "" }; /** * Call this function as soon as the click outside of annotated method's host is done. * @example ``` @ClickOutside() callback() { // this will run when click outside of element (host component) is done. } ``` */ function ClickOutside(opt) { if (opt === void 0) { opt = ClickOutsideOptionsDefaults; } return function (proto, methodName) { // this is to resolve the 'compiler optimization issue': // lifecycle events not being called when not explicitly declared in at least one of components from bundle core_1.Build.connectedCallback = true; core_1.Build.disconnectedCallback = true; var connectedCallback = proto.connectedCallback, disconnectedCallback = proto.disconnectedCallback; proto.connectedCallback = function () { var host = core_1.getElement(this); var method = this[methodName]; registerClickOutside(this, host, method, opt); return connectedCallback && connectedCallback.call(this); }; proto.disconnectedCallback = function () { var host = core_1.getElement(this); var method = this[methodName]; removeClickOutside(this, host, method, opt); return disconnectedCallback && disconnectedCallback.call(this); }; }; } exports.ClickOutside = ClickOutside; /** * Register callback function for HTMLElement to be executed when user clicks outside of element. * @example ``` <span ref={spanEl => registerClickOutside(this, spanEl, () => this.test())}> Hello, World! </span>; ``` */ function registerClickOutside(component, element, callback, opt) { if (opt === void 0) { opt = ClickOutsideOptionsDefaults; } var excludedNodes = getExcludedNodes(opt); getTriggerEvents(opt).forEach(function (triggerEvent) { window.addEventListener(triggerEvent, function (e) { initClickOutside(e, component, element, callback, excludedNodes); }, false); }); } exports.registerClickOutside = registerClickOutside; /** * Remove click outside callback function for HTMLElement. */ function removeClickOutside(component, element, callback, opt) { if (opt === void 0) { opt = ClickOutsideOptionsDefaults; } getTriggerEvents(opt).forEach(function (triggerEvent) { window.removeEventListener(triggerEvent, function (e) { initClickOutside(e, component, element, callback); }, false); }); } exports.removeClickOutside = removeClickOutside; function initClickOutside(event, component, element, callback, excludedNodes) { var target = event.target; if (!element.contains(target) && !isExcluded(target, excludedNodes)) { callback.call(component); } } function getTriggerEvents(opt) { if (opt.triggerEvents) { return opt.triggerEvents.split(",").map(function (e) { return e.trim(); }); } return ["click"]; } function getExcludedNodes(opt) { if (opt.exclude) { try { return Array.from(document.querySelectorAll(opt.exclude)); } catch (err) { console.warn("@ClickOutside: Exclude: '" + opt.exclude + "' will not be evaluated. Check your exclude selector syntax.", err); } } return; } function isExcluded(target, excudedNodes) { if (target && excudedNodes) { for (var _i = 0, excudedNodes_1 = excudedNodes; _i < excudedNodes_1.length; _i++) { var excludedNode = excudedNodes_1[_i]; if (excludedNode.contains(target)) { return true; } } } return false; }