{"version":3,"sources":["../src/store/accessibilityStore.ts"],"sourcesContent":["import { create } from 'zustand';\nimport { devtools, persist } from 'zustand/middleware';\n\n/**\n * Modos de contraste suportados pelo widget de acessibilidade\n */\nexport type ContrastMode = 'normal' | 'high' | 'inverted';\n\n/**\n * Modos de saturação para usuários com sensibilidade visual\n */\nexport type SaturationMode = 'normal' | 'grayscale' | 'low';\n\n/**\n * Auxiliares de leitura mutuamente exclusivos:\n * - `none`: nenhum auxiliar\n * - `ruler`: linha horizontal acompanha o cursor\n * - `mask`: escurece a tela exceto uma faixa central na altura do cursor\n */\nexport type ReadingAid = 'none' | 'ruler' | 'mask';\n\n/**\n * Modo do leitor de texto (TTS):\n * - `off`: leitor desligado\n * - `click-to-read`: usuário clica em um elemento e o widget lê o texto dele\n * - `read-selection`: usuário pressiona \"Ler seleção\" para falar o texto selecionado\n */\nexport type TTSMode = 'off' | 'click-to-read' | 'read-selection';\n\n/** Status runtime da síntese de voz — não persistido. */\nexport type TTSStatus = 'idle' | 'speaking' | 'paused';\n\n/**\n * Modos de daltonismo. Aplicam matrizes `<feColorMatrix>` (SVG) que\n * remapeiam cores para ajudar usuários com cada tipo de discromatopsia.\n *\n * Enum (e não union de strings como os outros modos) porque cada valor\n * é também usado como identificador estável em três outros lugares —\n * classes CSS, IDs de filter SVG e seletores no CSS — então centralizar\n * em um enum + helpers evita strings duplicadas e typos silenciosos.\n */\nexport enum ColorBlindMode {\n  None = 'none',\n  Protanopia = 'protanopia',\n  Deuteranopia = 'deuteranopia',\n  Tritanopia = 'tritanopia',\n}\n\n/** Prefixo único para todos os identificadores de daltonismo (classe + SVG id) */\nconst COLOR_BLIND_PREFIX = 'a11y-cb-';\n\n/**\n * Retorna a classe CSS aplicada no `<html>` para o modo informado, ou\n * `null` quando nenhum modo está ativo.\n */\nexport const getColorBlindClass = (mode: ColorBlindMode): string | null =>\n  mode === ColorBlindMode.None ? null : `${COLOR_BLIND_PREFIX}${mode}`;\n\n/** Retorna o id do `<filter>` SVG correspondente ao modo. */\nexport const getColorBlindFilterId = (\n  mode: Exclude<ColorBlindMode, ColorBlindMode.None>\n): string => `${COLOR_BLIND_PREFIX}${mode}`;\n\n/**\n * Níveis discretos para tamanho de fonte (0 = padrão da página)\n */\nexport type FontSizeLevel = 0 | 1 | 2 | 3;\n\n/**\n * Níveis discretos para espaçamento entre letras e linhas\n */\nexport type SpacingLevel = 0 | 1 | 2 | 3;\n\n/**\n * Conjunto completo de preferências persistidas\n */\nexport interface AccessibilityPreferences {\n  contrastMode: ContrastMode;\n  saturationMode: SaturationMode;\n  fontSize: FontSizeLevel;\n  letterSpacing: SpacingLevel;\n  lineSpacing: SpacingLevel;\n  highlightLinks: boolean;\n  pauseAnimations: boolean;\n  bigCursor: boolean;\n  /** Fonte amigável para dislexia (OpenDyslexic com fallback Comic Sans MS) */\n  dyslexiaFont: boolean;\n  /** Auxiliar visual de leitura (régua, máscara ou nenhum) */\n  readingAid: ReadingAid;\n  /** Habilita atalho Alt+A para abrir/fechar o painel */\n  keyboardShortcut: boolean;\n  /** Modo de daltonismo aplicado (filtro SVG na página inteira) */\n  colorBlindMode: ColorBlindMode;\n  /** Modo do leitor de texto (TTS) */\n  ttsMode: TTSMode;\n  /** Velocidade da fala (0.5 a 2.0) */\n  ttsRate: number;\n  /** Voz selecionada pelo usuário (id retornado pelo provider) ou null para padrão */\n  ttsVoiceId: string | null;\n  /** Habilita o widget VLibras (gov.br) — carregado lazy ao ativar */\n  librasEnabled: boolean;\n}\n\nexport interface AccessibilityState extends AccessibilityPreferences {\n  /** Indica se o painel de acessibilidade está aberto */\n  isPanelOpen: boolean;\n  /** Status runtime da síntese de voz — não persistido */\n  ttsStatus: TTSStatus;\n}\n\nexport interface AccessibilityActions {\n  setContrastMode: (mode: ContrastMode) => void;\n  setSaturationMode: (mode: SaturationMode) => void;\n  setFontSize: (level: FontSizeLevel) => void;\n  setLetterSpacing: (level: SpacingLevel) => void;\n  setLineSpacing: (level: SpacingLevel) => void;\n  setHighlightLinks: (value: boolean) => void;\n  setPauseAnimations: (value: boolean) => void;\n  setBigCursor: (value: boolean) => void;\n  setDyslexiaFont: (value: boolean) => void;\n  setReadingAid: (mode: ReadingAid) => void;\n  setKeyboardShortcut: (value: boolean) => void;\n  setColorBlindMode: (mode: ColorBlindMode) => void;\n  setTTSMode: (mode: TTSMode) => void;\n  setTTSRate: (rate: number) => void;\n  setTTSVoiceId: (id: string | null) => void;\n  setTTSStatus: (status: TTSStatus) => void;\n  setLibrasEnabled: (value: boolean) => void;\n  /** Restaura todas as preferências para o estado padrão */\n  resetPreferences: () => void;\n  openPanel: () => void;\n  closePanel: () => void;\n  togglePanel: () => void;\n}\n\nexport type AccessibilityStore = AccessibilityState & AccessibilityActions;\n\nexport const DEFAULT_ACCESSIBILITY_PREFERENCES: AccessibilityPreferences = {\n  contrastMode: 'normal',\n  saturationMode: 'normal',\n  fontSize: 0,\n  letterSpacing: 0,\n  lineSpacing: 0,\n  highlightLinks: false,\n  pauseAnimations: false,\n  bigCursor: false,\n  dyslexiaFont: false,\n  readingAid: 'none',\n  keyboardShortcut: true,\n  colorBlindMode: ColorBlindMode.None,\n  ttsMode: 'off',\n  ttsRate: 1,\n  ttsVoiceId: null,\n  librasEnabled: false,\n};\n\n/**\n * Store Zustand com persistência em localStorage para preferências\n * de acessibilidade. As preferências são aplicadas ao DOM pelo hook\n * `useA11yPreferences` — este store apenas guarda o estado.\n */\nexport const useAccessibilityStore = create<AccessibilityStore>()(\n  devtools(\n    persist(\n      (set) => ({\n        ...DEFAULT_ACCESSIBILITY_PREFERENCES,\n        isPanelOpen: false,\n        ttsStatus: 'idle',\n\n        setContrastMode: (contrastMode) => set({ contrastMode }),\n        setSaturationMode: (saturationMode) => set({ saturationMode }),\n        setFontSize: (fontSize) => set({ fontSize }),\n        setLetterSpacing: (letterSpacing) => set({ letterSpacing }),\n        setLineSpacing: (lineSpacing) => set({ lineSpacing }),\n        setHighlightLinks: (highlightLinks) => set({ highlightLinks }),\n        setPauseAnimations: (pauseAnimations) => set({ pauseAnimations }),\n        setBigCursor: (bigCursor) => set({ bigCursor }),\n        setDyslexiaFont: (dyslexiaFont) => set({ dyslexiaFont }),\n        setReadingAid: (readingAid) => set({ readingAid }),\n        setKeyboardShortcut: (keyboardShortcut) => set({ keyboardShortcut }),\n        setColorBlindMode: (colorBlindMode) => set({ colorBlindMode }),\n        setTTSMode: (ttsMode) => set({ ttsMode }),\n        setTTSRate: (ttsRate) => set({ ttsRate }),\n        setTTSVoiceId: (ttsVoiceId) => set({ ttsVoiceId }),\n        setTTSStatus: (ttsStatus) => set({ ttsStatus }),\n        setLibrasEnabled: (librasEnabled) => set({ librasEnabled }),\n\n        resetPreferences: () => set({ ...DEFAULT_ACCESSIBILITY_PREFERENCES }),\n\n        openPanel: () => set({ isPanelOpen: true }),\n        closePanel: () => set({ isPanelOpen: false }),\n        togglePanel: () =>\n          set((state) => ({ isPanelOpen: !state.isPanelOpen })),\n      }),\n      {\n        name: 'accessibility-store',\n        // version 1: removeu `librasEnabled` da persistência (era custoso\n        // recarregar VLibras a cada refresh). A migração limpa esse valor\n        // de localStorages antigos para evitar auto-load surpresa.\n        version: 1,\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any -- migrate works with arbitrary persisted shapes from older versions\n        migrate: (persistedState: any) => {\n          if (\n            persistedState &&\n            typeof persistedState === 'object' &&\n            'librasEnabled' in persistedState\n          ) {\n            delete persistedState.librasEnabled;\n          }\n          return persistedState;\n        },\n        partialize: (state) => ({\n          contrastMode: state.contrastMode,\n          saturationMode: state.saturationMode,\n          fontSize: state.fontSize,\n          letterSpacing: state.letterSpacing,\n          lineSpacing: state.lineSpacing,\n          highlightLinks: state.highlightLinks,\n          pauseAnimations: state.pauseAnimations,\n          bigCursor: state.bigCursor,\n          dyslexiaFont: state.dyslexiaFont,\n          readingAid: state.readingAid,\n          keyboardShortcut: state.keyboardShortcut,\n          colorBlindMode: state.colorBlindMode,\n          ttsRate: state.ttsRate,\n          ttsVoiceId: state.ttsVoiceId,\n          // ttsMode e librasEnabled NÃO são persistidos:\n          // - ttsMode: o leitor sempre começa desligado ao recarregar\n          //   a página para evitar comportamento confuso\n          // - librasEnabled: o VLibras é pesado (~MBs de assets); auto-\n          //   carregar a cada refresh seria custoso e surpreendente. O\n          //   usuário ativa explicitamente quando precisa.\n        }),\n      }\n    ),\n    { name: 'accessibility-store' }\n  )\n);\n"],"mappings":"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","names":["ColorBlindMode"]}