claritykit-svelte
Version:
A comprehensive Svelte component library focused on accessibility, ADHD-optimized design, developer experience, and full SSR compatibility
209 lines (208 loc) • 6.25 kB
JavaScript
/**
* SSR-safe DOM utilities
* Provides safe wrappers for DOM operations that work in both server and client environments
*/
import { isBrowser, safelyAccessDOM } from './environment';
/**
* Safely queries for an element using querySelector
* @param selector - CSS selector string
* @returns Element or null if not found or not in browser
*/
export function querySelector(selector) {
return safelyAccessDOM(() => document.querySelector(selector), null) || null;
}
/**
* Safely gets an element by ID
* @param id - Element ID
* @returns Element or null if not found or not in browser
*/
export function getElementById(id) {
return safelyAccessDOM(() => document.getElementById(id), null) || null;
}
/**
* Safely adds an event listener to an element
* @param element - Target element
* @param event - Event type
* @param handler - Event handler function
* @param options - Event listener options
*/
export function addEventListener(element, event, handler, options) {
if (isBrowser && element && typeof element.addEventListener === 'function') {
try {
element.addEventListener(event, handler, options);
}
catch (error) {
console.warn(`Failed to add event listener for ${event}:`, error);
}
}
}
/**
* Safely removes an event listener from an element
* @param element - Target element
* @param event - Event type
* @param handler - Event handler function
* @param options - Event listener options
*/
export function removeEventListener(element, event, handler, options) {
if (isBrowser && element && typeof element.removeEventListener === 'function') {
try {
element.removeEventListener(event, handler, options);
}
catch (error) {
console.warn(`Failed to remove event listener for ${event}:`, error);
}
}
}
/**
* Safely gets computed styles for an element
* @param element - Target element
* @returns CSSStyleDeclaration or null if not available
*/
export function getComputedStyle(element) {
return safelyAccessDOM(() => {
if (window.getComputedStyle && element) {
return window.getComputedStyle(element);
}
return null;
}, null) || null;
}
/**
* Safely gets bounding client rect for an element
* @param element - Target element
* @returns DOMRect or null if not available
*/
export function getBoundingClientRect(element) {
return safelyAccessDOM(() => {
if (element && typeof element.getBoundingClientRect === 'function') {
return element.getBoundingClientRect();
}
return null;
}, null) || null;
}
/**
* Safely creates a custom event
* @param type - Event type
* @param eventInitDict - Event initialization options
* @returns Event or null if not available
*/
export function createEvent(type, eventInitDict) {
return safelyAccessDOM(() => {
if (typeof Event !== 'undefined') {
return new Event(type, eventInitDict);
}
return null;
}, null) || null;
}
/**
* Safely creates a custom event with detail data
* @param type - Event type
* @param detail - Custom data to include with event
* @param eventInitDict - Event initialization options
* @returns CustomEvent or null if not available
*/
export function createCustomEvent(type, detail, eventInitDict) {
return safelyAccessDOM(() => {
if (typeof CustomEvent !== 'undefined') {
return new CustomEvent(type, { detail, ...eventInitDict });
}
return null;
}, null) || null;
}
/**
* Safely dispatches an event on an element
* @param element - Target element
* @param event - Event to dispatch
* @returns True if event was dispatched, false otherwise
*/
export function dispatchEvent(element, event) {
return safelyAccessDOM(() => {
if (element && event && typeof element.dispatchEvent === 'function') {
return element.dispatchEvent(event);
}
return false;
}, false) || false;
}
/**
* Safely focuses an element
* @param element - Element to focus
* @param options - Focus options
*/
export function focusElement(element, options) {
safelyAccessDOM(() => {
if (element && typeof element.focus === 'function') {
element.focus(options);
}
});
}
/**
* Safely blurs an element
* @param element - Element to blur
*/
export function blurElement(element) {
safelyAccessDOM(() => {
if (element && typeof element.blur === 'function') {
element.blur();
}
});
}
/**
* Safely scrolls an element into view
* @param element - Element to scroll into view
* @param options - Scroll options
*/
export function scrollIntoView(element, options) {
safelyAccessDOM(() => {
if (element && typeof element.scrollIntoView === 'function') {
element.scrollIntoView(options);
}
});
}
/**
* Safely gets the active element
* @returns Active element or null
*/
export function getActiveElement() {
return safelyAccessDOM(() => document.activeElement, null) || null;
}
/**
* Safely checks if an element contains another element
* @param parent - Parent element
* @param child - Child element
* @returns True if parent contains child, false otherwise
*/
export function contains(parent, child) {
return safelyAccessDOM(() => {
if (parent && child && typeof parent.contains === 'function') {
return parent.contains(child);
}
return false;
}, false) || false;
}
/**
* Safely gets element dimensions
* @param element - Target element
* @returns Object with width and height, or null if not available
*/
export function getElementDimensions(element) {
return safelyAccessDOM(() => {
if (element) {
const rect = getBoundingClientRect(element);
if (rect) {
return { width: rect.width, height: rect.height };
}
}
return null;
}, null) || null;
}
/**
* Default SSR-safe DOM utilities implementation
*/
export const domUtils = {
querySelector,
getElementById,
addEventListener,
removeEventListener,
getComputedStyle,
getBoundingClientRect,
createEvent,
};