analytica-frontend-lib
Version:
Repositório público dos componentes utilizados nas plataformas da Analytica Ensino
1 lines • 11.7 kB
Source Map (JSON)
{"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"]}