Initial Commit
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
// saladui/core/click-outside.js
|
||||
/**
|
||||
* ClickOutsideMonitor utility for SaladUI components
|
||||
* Detects clicks outside of specified elements and triggers a callback
|
||||
*/
|
||||
class ClickOutsideMonitor {
|
||||
/**
|
||||
* Create a click outside monitor
|
||||
*
|
||||
* @param {HTMLElement|HTMLElement[]} elements - Element(s) to monitor clicks outside of
|
||||
* @param {Function} callback - Function to call when click outside is detected
|
||||
* @param {Object} options - Additional options
|
||||
*/
|
||||
constructor(elements, callback, options = {}) {
|
||||
// Normalize elements to an array
|
||||
this.elements = Array.isArray(elements) ? elements : [elements];
|
||||
this.callback = callback;
|
||||
this.options = {
|
||||
// Whether to also monitor touchend events (for mobile)
|
||||
trackTouch: true,
|
||||
// Optional filter function to determine if a click should trigger the callback
|
||||
filter: null,
|
||||
...options,
|
||||
};
|
||||
|
||||
this.active = false;
|
||||
|
||||
// Bind methods to maintain correct this context
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
this.handleTouchEnd = this.handleTouchEnd.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start monitoring clicks outside the element(s)
|
||||
*/
|
||||
start() {
|
||||
if (this.active) return;
|
||||
|
||||
// Add document-level event listeners
|
||||
document.addEventListener("click", this.handleClick);
|
||||
if (this.options.trackTouch) {
|
||||
document.addEventListener("touchend", this.handleTouchEnd);
|
||||
}
|
||||
|
||||
this.active = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop monitoring clicks
|
||||
*/
|
||||
stop() {
|
||||
if (!this.active) return;
|
||||
|
||||
// Remove document-level event listeners
|
||||
document.removeEventListener("click", this.handleClick);
|
||||
if (this.options.trackTouch) {
|
||||
document.removeEventListener("touchend", this.handleTouchEnd);
|
||||
}
|
||||
|
||||
this.active = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle click events
|
||||
*/
|
||||
handleClick(event) {
|
||||
this.checkOutsideClick(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle touchend events
|
||||
*/
|
||||
handleTouchEnd(event) {
|
||||
this.checkOutsideClick(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if click/touch was outside monitored elements
|
||||
*/
|
||||
checkOutsideClick(event) {
|
||||
// Skip if not active or no callback
|
||||
if (!this.active || !this.callback) return;
|
||||
|
||||
// Apply custom filter if provided
|
||||
if (this.options.filter && !this.options.filter(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the event target
|
||||
const target = event.target;
|
||||
|
||||
// Check if click was outside all monitored elements
|
||||
const isOutside = !this.elements.some((element) => {
|
||||
return element && (element === target || element.contains(target));
|
||||
});
|
||||
|
||||
// If click was outside, call the callback
|
||||
if (isOutside) {
|
||||
this.callback(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the monitored elements
|
||||
*/
|
||||
updateElements(elements) {
|
||||
this.elements = Array.isArray(elements) ? elements : [elements];
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up all references
|
||||
*/
|
||||
destroy() {
|
||||
this.stop();
|
||||
this.elements = null;
|
||||
this.callback = null;
|
||||
this.options = null;
|
||||
}
|
||||
}
|
||||
|
||||
export default ClickOutsideMonitor;
|
||||
Reference in New Issue
Block a user