Initial Commit

This commit is contained in:
2026-02-12 17:10:03 -06:00
commit 6992a06105
135 changed files with 18014 additions and 0 deletions
+121
View File
@@ -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;