UNPKG

@neuroequality/neuroadapt-core

Version:

Core sensory, cognitive, and preference management for NeuroAdapt SDK

248 lines (238 loc) 8.33 kB
import { EventEmitter } from "eventemitter3"; const COLOR_VISION_FILTERS = { none: "none", // Protanopia (red-blind) - reduce red channel protanopia: "sepia(1) saturate(0.8) hue-rotate(-20deg) contrast(1.2)", // Deuteranopia (green-blind) - adjust green channel deuteranopia: "sepia(0.6) saturate(0.9) hue-rotate(40deg) contrast(1.1)", // Tritanopia (blue-blind) - reduce blue channel tritanopia: "sepia(0.8) saturate(1.2) hue-rotate(180deg) contrast(1.3)" }; const HIGH_CONTRAST_THEME = ` :root[data-theme="neuro-high-contrast"] { --neuro-bg-primary: #000000; --neuro-bg-secondary: #1a1a1a; --neuro-text-primary: #ffffff; --neuro-text-secondary: #cccccc; --neuro-border: #ffffff; --neuro-focus: #ffff00; --neuro-link: #00ffff; --neuro-link-visited: #ff00ff; --neuro-button-bg: #333333; --neuro-button-text: #ffffff; --neuro-input-bg: #1a1a1a; --neuro-input-border: #ffffff; } [data-theme="neuro-high-contrast"] { background-color: var(--neuro-bg-primary) !important; color: var(--neuro-text-primary) !important; border-color: var(--neuro-border) !important; } [data-theme="neuro-high-contrast"] * { background-color: inherit !important; color: inherit !important; } [data-theme="neuro-high-contrast"] a { color: var(--neuro-link) !important; } [data-theme="neuro-high-contrast"] a:visited { color: var(--neuro-link-visited) !important; } [data-theme="neuro-high-contrast"] button, [data-theme="neuro-high-contrast"] input[type="button"], [data-theme="neuro-high-contrast"] input[type="submit"] { background-color: var(--neuro-button-bg) !important; color: var(--neuro-button-text) !important; border: 2px solid var(--neuro-border) !important; } [data-theme="neuro-high-contrast"] input, [data-theme="neuro-high-contrast"] textarea, [data-theme="neuro-high-contrast"] select { background-color: var(--neuro-input-bg) !important; color: var(--neuro-text-primary) !important; border: 2px solid var(--neuro-input-border) !important; } [data-theme="neuro-high-contrast"] :focus { outline: 3px solid var(--neuro-focus) !important; outline-offset: 2px !important; } `; const MOTION_REDUCTION_CSS = ` .neuro-motion-reduced *, .neuro-motion-reduced *::before, .neuro-motion-reduced *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; transform: none !important; } .neuro-motion-reduced * { scroll-behavior: auto !important; } `; const ANTI_FLASHING_CSS = ` .neuro-anti-flash * { animation-duration: 1s !important; transition-duration: 0.3s !important; } .neuro-anti-flash *:hover, .neuro-anti-flash *:focus { transition-duration: 0.15s !important; } `; class VisualAdapter extends EventEmitter { constructor(preferences, options = {}) { super(); this.appliedAdaptations = /* @__PURE__ */ new Set(); this.currentAdaptations = {}; this.targetElement = options.targetElement || document.documentElement; this.prefix = options.prefix || "neuro"; this.initializeStyleElement(); if (options.autoApply !== false) { this.applyAdaptations(preferences); } } /** * Apply visual adaptations based on sensory preferences */ applyAdaptations(preferences) { try { this.currentAdaptations = { ...preferences }; if (preferences.motionReduction) { this.applyMotionReduction(); } else { this.removeMotionReduction(); } if (preferences.highContrast) { this.applyHighContrast(); } else { this.removeHighContrast(); } this.applyColorVisionFilter(preferences.colorVisionFilter); this.applyFontSizeScaling(preferences.fontSize); if (preferences.reducedFlashing) { this.applyReducedFlashing(); } else { this.removeReducedFlashing(); } if (preferences.darkMode) { this.applyDarkMode(); } else { this.removeDarkMode(); } } catch (error) { const errorObj = error instanceof Error ? error : new Error(String(error)); this.emit("error", errorObj); } } /** * Remove all applied visual adaptations */ disable() { var _a; try { this.removeMotionReduction(); this.removeHighContrast(); this.removeColorVisionFilter(); this.removeFontSizeScaling(); this.removeReducedFlashing(); this.removeDarkMode(); if ((_a = this.styleElement) == null ? void 0 : _a.parentNode) { this.styleElement.parentNode.removeChild(this.styleElement); } this.appliedAdaptations.clear(); this.currentAdaptations = {}; } catch (error) { const errorObj = error instanceof Error ? error : new Error(String(error)); this.emit("error", errorObj); } } /** * Get currently applied adaptations */ getCurrentAdaptations() { return { ...this.currentAdaptations }; } /** * Check if a specific adaptation is currently applied */ isAdaptationApplied(adaptation) { return this.appliedAdaptations.has(adaptation); } initializeStyleElement() { this.styleElement = document.createElement("style"); this.styleElement.id = `${this.prefix}-visual-adaptations`; this.styleElement.textContent = HIGH_CONTRAST_THEME + MOTION_REDUCTION_CSS + ANTI_FLASHING_CSS; document.head.appendChild(this.styleElement); } applyMotionReduction() { this.targetElement.classList.add(`${this.prefix}-motion-reduced`); this.appliedAdaptations.add("motionReduction"); this.emit("adaptation-applied", "motionReduction", { enabled: true }); } removeMotionReduction() { this.targetElement.classList.remove(`${this.prefix}-motion-reduced`); this.appliedAdaptations.delete("motionReduction"); this.emit("adaptation-removed", "motionReduction"); } applyHighContrast() { this.targetElement.setAttribute("data-theme", `${this.prefix}-high-contrast`); this.appliedAdaptations.add("highContrast"); this.emit("adaptation-applied", "highContrast", { theme: `${this.prefix}-high-contrast` }); } removeHighContrast() { this.targetElement.removeAttribute("data-theme"); this.appliedAdaptations.delete("highContrast"); this.emit("adaptation-removed", "highContrast"); } applyColorVisionFilter(filter) { if (filter === "none") { this.removeColorVisionFilter(); return; } const filterValue = COLOR_VISION_FILTERS[filter]; this.targetElement.style.filter = filterValue; this.appliedAdaptations.add("colorVisionFilter"); this.emit("adaptation-applied", "colorVisionFilter", { filter, value: filterValue }); } removeColorVisionFilter() { this.targetElement.style.removeProperty("filter"); this.appliedAdaptations.delete("colorVisionFilter"); this.emit("adaptation-removed", "colorVisionFilter"); } applyFontSizeScaling(scale) { const percentage = Math.round(scale * 100); this.targetElement.style.fontSize = `${percentage}%`; this.appliedAdaptations.add("fontSize"); this.emit("adaptation-applied", "fontSize", { scale, percentage }); } removeFontSizeScaling() { this.targetElement.style.removeProperty("font-size"); this.appliedAdaptations.delete("fontSize"); this.emit("adaptation-removed", "fontSize"); } applyReducedFlashing() { this.targetElement.classList.add(`${this.prefix}-anti-flash`); this.appliedAdaptations.add("reducedFlashing"); this.emit("adaptation-applied", "reducedFlashing", { enabled: true }); } removeReducedFlashing() { this.targetElement.classList.remove(`${this.prefix}-anti-flash`); this.appliedAdaptations.delete("reducedFlashing"); this.emit("adaptation-removed", "reducedFlashing"); } applyDarkMode() { this.targetElement.classList.add(`${this.prefix}-dark-mode`); this.appliedAdaptations.add("darkMode"); this.emit("adaptation-applied", "darkMode", { enabled: true }); } removeDarkMode() { this.targetElement.classList.remove(`${this.prefix}-dark-mode`); this.appliedAdaptations.delete("darkMode"); this.emit("adaptation-removed", "darkMode"); } } export { VisualAdapter }; //# sourceMappingURL=visual-adapter.js.map