vlibras-player-webjs
Version:
Biblioteca JavaScript moderna para integração do VLibras Player com React, Vue, Angular e vanilla JS
226 lines • 9.66 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.useVLibrasAccessibility = useVLibrasAccessibility;
const react_1 = require("react");
const useIsomorphicLayoutEffect_1 = require("../ssr/useIsomorphicLayoutEffect");
const useVLibras_1 = require("./useVLibras");
/**
* Hook para funcionalidades de acessibilidade do VLibras
*/
function useVLibrasAccessibility(initialOptions = {}) {
const defaultOptions = {
enableScreenReader: true,
announceTranslations: true,
enableKeyboardNav: true,
enableReducedMotion: false,
enableHighContrast: false,
textSize: 'medium',
language: 'pt-BR'
};
const { player, isLoaded, isPlaying } = (0, useVLibras_1.useVLibras)();
const [options, setOptions] = (0, react_1.useState)({
...defaultOptions,
...initialOptions
});
const announceRef = (0, react_1.useRef)(null);
// Detectar preferências do sistema
const [isReducedMotion, setIsReducedMotion] = (0, react_1.useState)(false);
const [isHighContrast, setIsHighContrast] = (0, react_1.useState)(false);
// Detectar preferências de movimento reduzido
(0, react_1.useEffect)(() => {
if (!useIsomorphicLayoutEffect_1.isBrowser || !useIsomorphicLayoutEffect_1.safeWindow?.matchMedia)
return;
const mediaQuery = useIsomorphicLayoutEffect_1.safeWindow.matchMedia('(prefers-reduced-motion: reduce)');
setIsReducedMotion(mediaQuery.matches);
const handleChange = (e) => {
setIsReducedMotion(e.matches);
setOptions(prev => ({ ...prev, enableReducedMotion: e.matches }));
};
mediaQuery.addEventListener('change', handleChange);
return () => mediaQuery.removeEventListener('change', handleChange);
}, []);
// Detectar preferências de alto contraste
(0, react_1.useEffect)(() => {
if (!useIsomorphicLayoutEffect_1.isBrowser || !useIsomorphicLayoutEffect_1.safeWindow?.matchMedia)
return;
const mediaQuery = useIsomorphicLayoutEffect_1.safeWindow.matchMedia('(prefers-contrast: high)');
setIsHighContrast(mediaQuery.matches);
const handleChange = (e) => {
setIsHighContrast(e.matches);
setOptions(prev => ({ ...prev, enableHighContrast: e.matches }));
};
mediaQuery.addEventListener('change', handleChange);
return () => mediaQuery.removeEventListener('change', handleChange);
}, []);
// Criar região de anúncios para leitores de tela
(0, react_1.useEffect)(() => {
if (!options.enableScreenReader || !useIsomorphicLayoutEffect_1.isBrowser || !useIsomorphicLayoutEffect_1.safeDocument)
return;
let announceDiv = useIsomorphicLayoutEffect_1.safeDocument.getElementById('vlibras-announcements');
if (!announceDiv) {
announceDiv = useIsomorphicLayoutEffect_1.safeDocument.createElement('div');
announceDiv.id = 'vlibras-announcements';
announceDiv.setAttribute('aria-live', 'polite');
announceDiv.setAttribute('aria-atomic', 'true');
announceDiv.style.position = 'absolute';
announceDiv.style.left = '-10000px';
announceDiv.style.width = '1px';
announceDiv.style.height = '1px';
announceDiv.style.overflow = 'hidden';
useIsomorphicLayoutEffect_1.safeDocument.body.appendChild(announceDiv);
}
announceRef.current = announceDiv;
return () => {
if (announceDiv && announceDiv.parentNode) {
announceDiv.parentNode.removeChild(announceDiv);
}
};
}, [options.enableScreenReader]);
const updateOptions = (0, react_1.useCallback)((newOptions) => {
setOptions(prev => ({ ...prev, ...newOptions }));
}, []);
const announce = (0, react_1.useCallback)((message, priority = 'polite') => {
if (!options.enableScreenReader || !announceRef.current)
return;
announceRef.current.setAttribute('aria-live', priority);
announceRef.current.textContent = message;
// Limpar depois de um tempo para permitir novos anúncios
setTimeout(() => {
if (announceRef.current) {
announceRef.current.textContent = '';
}
}, 1000);
}, [options.enableScreenReader]);
const focusPlayer = (0, react_1.useCallback)(() => {
if (!useIsomorphicLayoutEffect_1.isBrowser || !useIsomorphicLayoutEffect_1.safeDocument)
return;
const playerElement = useIsomorphicLayoutEffect_1.safeDocument.querySelector('[data-vlibras-player]');
if (playerElement && playerElement.focus) {
playerElement.focus();
}
}, []);
const getKeyboardShortcuts = (0, react_1.useCallback)(() => {
return {
'Space': 'Pausar/Continuar reprodução',
'Enter': 'Traduzir texto selecionado',
'Escape': 'Parar reprodução',
'r': 'Repetir última tradução',
'f': 'Focar no player',
'+/-': 'Aumentar/Diminuir velocidade',
'1-4': 'Alterar tamanho do player'
};
}, []);
// Configurar atalhos de teclado
(0, react_1.useEffect)(() => {
if (!options.enableKeyboardNav)
return;
const handleKeyPress = (event) => {
// Evitar conflitos quando usuário está digitando
if (event.target instanceof HTMLInputElement ||
event.target instanceof HTMLTextAreaElement) {
return;
}
switch (event.key.toLowerCase()) {
case ' ':
event.preventDefault();
if (isPlaying) {
player?.pause();
announce('Reprodução pausada');
}
else {
player?.play();
announce('Reprodução iniciada');
}
break;
case 'enter':
event.preventDefault();
const selectedText = window.getSelection()?.toString();
if (selectedText && player) {
player.translateAsync(selectedText);
announce(`Traduzindo: ${selectedText}`);
}
break;
case 'escape':
event.preventDefault();
player?.stop();
announce('Reprodução parada');
break;
case 'r':
if (event.ctrlKey || event.metaKey)
return; // Evitar conflito com refresh
event.preventDefault();
player?.play();
announce('Repetindo última tradução');
break;
case 'f':
if (event.ctrlKey || event.metaKey)
return; // Evitar conflito com busca
event.preventDefault();
focusPlayer();
break;
}
};
if (useIsomorphicLayoutEffect_1.isBrowser && useIsomorphicLayoutEffect_1.safeDocument) {
useIsomorphicLayoutEffect_1.safeDocument.addEventListener('keydown', handleKeyPress);
return () => {
if (useIsomorphicLayoutEffect_1.safeDocument) {
useIsomorphicLayoutEffect_1.safeDocument.removeEventListener('keydown', handleKeyPress);
}
};
}
return undefined;
}, [options.enableKeyboardNav, isPlaying, player, announce, focusPlayer]);
// Anunciar mudanças de estado
(0, react_1.useEffect)(() => {
if (!options.announceTranslations)
return;
if (isLoaded) {
announce('VLibras carregado e pronto para uso');
}
}, [isLoaded, options.announceTranslations, announce]);
(0, react_1.useEffect)(() => {
if (!options.announceTranslations)
return;
if (isPlaying) {
announce('Reproduzindo tradução em Libras');
}
}, [isPlaying, options.announceTranslations, announce]);
// Aplicar estilos de acessibilidade
(0, react_1.useEffect)(() => {
if (!useIsomorphicLayoutEffect_1.isBrowser || !useIsomorphicLayoutEffect_1.safeDocument)
return;
const root = useIsomorphicLayoutEffect_1.safeDocument.documentElement;
// Tamanho do texto
const textSizeMap = {
'small': '0.875rem',
'medium': '1rem',
'large': '1.125rem',
'x-large': '1.25rem'
};
root.style.setProperty('--vlibras-text-size', textSizeMap[options.textSize || 'medium']);
// Alto contraste
if (options.enableHighContrast) {
root.classList.add('vlibras-high-contrast');
}
else {
root.classList.remove('vlibras-high-contrast');
}
// Movimento reduzido
if (options.enableReducedMotion) {
root.classList.add('vlibras-reduced-motion');
}
else {
root.classList.remove('vlibras-reduced-motion');
}
}, [options.textSize, options.enableHighContrast, options.enableReducedMotion]);
return {
options,
updateOptions,
announce,
isReducedMotion,
isHighContrast,
focusPlayer,
getKeyboardShortcuts
};
}
//# sourceMappingURL=useVLibrasAccessibility.js.map