UNPKG

aura-glass

Version:

A comprehensive glassmorphism design system for React applications with 142+ production-ready components

155 lines (152 loc) 4.33 kB
import { useState, useRef, useCallback } from 'react'; import { KEYS } from './a11y.js'; /** * AuraGlass Accessibility Hooks * Enhanced accessibility hooks for comprehensive WCAG 2.1 AA compliance */ function useKeyboardNavigation(options) { const { items, orientation = 'vertical', loop = true, homeEndKeys = true, pageKeys = false, onActivate, onSelect } = options; const [focusedIndex, setFocusedIndex] = useState(0); const [selectedIds, setSelectedIds] = useState(new Set()); const itemRefs = useRef(new Map()); const enabledItems = items.filter(item => !item.disabled); const focusItem = useCallback(index => { if (index < 0 || index >= enabledItems.length) return; const item = enabledItems[index]; const element = itemRefs.current.get(item.id); if (element) { element.focus(); setFocusedIndex(index); } }, [enabledItems]); const moveNext = useCallback(() => { const nextIndex = focusedIndex + 1; if (nextIndex < enabledItems.length) { focusItem(nextIndex); } else if (loop) { focusItem(0); } }, [focusedIndex, enabledItems.length, loop, focusItem]); const movePrevious = useCallback(() => { const prevIndex = focusedIndex - 1; if (prevIndex >= 0) { focusItem(prevIndex); } else if (loop) { focusItem(enabledItems.length - 1); } }, [focusedIndex, enabledItems.length, loop, focusItem]); const moveToFirst = useCallback(() => { focusItem(0); }, [focusItem]); const moveToLast = useCallback(() => { focusItem(enabledItems.length - 1); }, [enabledItems.length, focusItem]); const handleKeyDown = useCallback(event => { const { key } = event; const isVertical = orientation === 'vertical' || orientation === 'both'; const isHorizontal = orientation === 'horizontal' || orientation === 'both'; switch (key) { case KEYS.ARROW_DOWN: if (isVertical) { event.preventDefault(); moveNext(); } break; case KEYS.ARROW_UP: if (isVertical) { event.preventDefault(); movePrevious(); } break; case KEYS.ARROW_RIGHT: if (isHorizontal) { event.preventDefault(); moveNext(); } break; case KEYS.ARROW_LEFT: if (isHorizontal) { event.preventDefault(); movePrevious(); } break; case KEYS.HOME: if (homeEndKeys) { event.preventDefault(); moveToFirst(); } break; case KEYS.END: if (homeEndKeys) { event.preventDefault(); moveToLast(); } break; case KEYS.PAGE_UP: if (pageKeys) { event.preventDefault(); const jumpIndex = Math.max(0, focusedIndex - 10); focusItem(jumpIndex); } break; case KEYS.PAGE_DOWN: if (pageKeys) { event.preventDefault(); const jumpIndex = Math.min(enabledItems.length - 1, focusedIndex + 10); focusItem(jumpIndex); } break; case KEYS.ENTER: case KEYS.SPACE: if (focusedIndex >= 0 && focusedIndex < enabledItems.length) { event.preventDefault(); const item = enabledItems[focusedIndex]; onActivate?.(item.id); } break; } }, [orientation, moveNext, movePrevious, moveToFirst, moveToLast, homeEndKeys, pageKeys, focusedIndex, enabledItems, focusItem, onActivate]); const registerItem = useCallback((id, element) => { if (element) { itemRefs.current.set(id, element); } else { itemRefs.current.delete(id); } }, []); const selectItem = useCallback((id, multiSelect = false) => { setSelectedIds(prev => { const newSelection = new Set(multiSelect ? prev : []); if (newSelection.has(id)) { newSelection.delete(id); } else { newSelection.add(id); } return newSelection; }); onSelect?.(id); }, [onSelect]); return { focusedIndex, selectedIds, handleKeyDown, registerItem, focusItem, selectItem, moveNext, movePrevious, moveToFirst, moveToLast }; } export { useKeyboardNavigation }; //# sourceMappingURL=a11yHooks.js.map