'use client' import { createContext, use, useCallback, useEffect, useState } from 'react' import { A11Y_COOKIE, A11Y_COOKIE_MAX_AGE, A11Y_DEFAULT, a11yAttributes, type A11yState, parseA11y, serializeA11y, } from './state.js' type A11yContextValue = { reset: () => void set: (key: K, value: A11yState[K]) => void state: A11yState } const A11yContext = createContext(null) function readCookie(name: string): string | undefined { if (typeof document === 'undefined') {return undefined} const match = document.cookie.match(new RegExp(`(?:^|; )${name}=([^;]*)`)) return match ? decodeURIComponent(match[1]) : undefined } /** * Provides accessibility preferences, persists them in a cookie, and applies them * as data-attributes on so the project's CSS can react. Like * ConsentProvider for cookies — wrap the app once; the widget/button consume it. * * The plugin ships NO styles: it only sets attributes (data-a11y-*). The project * writes CSS for those it supports (see docs/accessibility.md). This keeps the * design in the project's hands. * * // layout.tsx * import { AccessibilityProvider } from '@intecion/ipal-kit/client' * {children} * * To avoid a flash, the project can read the a11y-prefs cookie server-side and * set the attributes on during SSR (see docs). This provider re-applies * on the client and keeps them in sync. */ export function AccessibilityProvider({ children }: { children: React.ReactNode }) { const [state, setState] = useState(A11Y_DEFAULT) // Hydrate from cookie on mount. useEffect(() => { setState(parseA11y(readCookie(A11Y_COOKIE))) }, []) // Apply attributes to whenever state changes. useEffect(() => { const el = document.documentElement const attrs = a11yAttributes(state) for (const [attr, value] of Object.entries(attrs)) { if (value === null) {el.removeAttribute(attr)} else {el.setAttribute(attr, value)} } }, [state]) const persist = useCallback((next: A11yState) => { document.cookie = `${A11Y_COOKIE}=${encodeURIComponent( serializeA11y(next), )}; path=/; max-age=${A11Y_COOKIE_MAX_AGE}; samesite=lax` }, []) const set = useCallback( (key: K, value: A11yState[K]) => { setState((prev) => { const next = { ...prev, [key]: value } persist(next) return next }) }, [persist], ) const reset = useCallback(() => { setState(A11Y_DEFAULT) persist(A11Y_DEFAULT) }, [persist]) return {children} } /** Access accessibility preferences + setters. Use inside AccessibilityProvider. */ export function useAccessibility(): A11yContextValue { const ctx = use(A11yContext) if (!ctx) {throw new Error('useAccessibility must be used within ')} return ctx }