UNPKG

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
/** * 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, };