summaryrefslogtreecommitdiff
path: root/ui/shadcn/.claude/hooks/check-accessibility.sh
diff options
context:
space:
mode:
authorTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2026-01-16 08:30:14 +0900
committerTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2026-01-16 08:30:14 +0900
commit3fbb9a18372f2b6a675dd6c039ba52be76f3eeb4 (patch)
treeaa694a36cdd323a7853672ee7a2ba60409ac3b06 /ui/shadcn/.claude/hooks/check-accessibility.sh
updates
Diffstat (limited to 'ui/shadcn/.claude/hooks/check-accessibility.sh')
-rwxr-xr-xui/shadcn/.claude/hooks/check-accessibility.sh197
1 files changed, 197 insertions, 0 deletions
diff --git a/ui/shadcn/.claude/hooks/check-accessibility.sh b/ui/shadcn/.claude/hooks/check-accessibility.sh
new file mode 100755
index 0000000..24be077
--- /dev/null
+++ b/ui/shadcn/.claude/hooks/check-accessibility.sh
@@ -0,0 +1,197 @@
+#!/bin/bash
+
+# Check accessibility compliance after component modifications
+# This hook runs after Write/Edit/MultiEdit operations
+
+# Colors for output
+RED='\033[0;31m'
+YELLOW='\033[1;33m'
+GREEN='\033[0;32m'
+BLUE='\033[0;34m'
+NC='\033[0m' # No Color
+
+# Read tool result from stdin
+TOOL_RESULT=$(cat)
+TOOL_NAME=$(echo "$TOOL_RESULT" | jq -r '.tool_name // empty' 2>/dev/null)
+
+# Only process if it's a file modification tool
+if [[ "$TOOL_NAME" != "Write" ]] && [[ "$TOOL_NAME" != "Edit" ]] && [[ "$TOOL_NAME" != "MultiEdit" ]]; then
+ echo "$TOOL_RESULT"
+ exit 0
+fi
+
+# Extract file path
+FILE_PATH=$(echo "$TOOL_RESULT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
+
+# Only process component files
+if [[ ! "$FILE_PATH" =~ \.(tsx?|jsx?)$ ]] || [[ ! "$FILE_PATH" =~ component ]]; then
+ echo "$TOOL_RESULT"
+ exit 0
+fi
+
+# Check if file exists
+if [ ! -f "$FILE_PATH" ]; then
+ echo "$TOOL_RESULT"
+ exit 0
+fi
+
+echo -e "${BLUE}🔍 Checking accessibility in $FILE_PATH...${NC}" >&2
+
+# Initialize counters
+ISSUES=0
+WARNINGS=0
+
+# Function to check patterns
+check_pattern() {
+ local pattern="$1"
+ local message="$2"
+ local type="$3" # "error" or "warning"
+
+ if grep -q "$pattern" "$FILE_PATH"; then
+ if [ "$type" = "error" ]; then
+ echo -e "${RED}❌ A11y Issue: $message${NC}" >&2
+ ((ISSUES++))
+ else
+ echo -e "${YELLOW}⚠️ A11y Warning: $message${NC}" >&2
+ ((WARNINGS++))
+ fi
+ return 1
+ fi
+ return 0
+}
+
+# Function to check for missing patterns
+check_missing() {
+ local pattern="$1"
+ local context="$2"
+ local message="$3"
+
+ if grep -q "$context" "$FILE_PATH"; then
+ if ! grep -q "$pattern" "$FILE_PATH"; then
+ echo -e "${YELLOW}⚠️ A11y Warning: $message${NC}" >&2
+ ((WARNINGS++))
+ return 1
+ fi
+ fi
+ return 0
+}
+
+# Check for interactive elements without keyboard support
+if grep -qE '<(button|a|input|select|textarea)' "$FILE_PATH"; then
+ # Check for onClick without onKeyDown/onKeyPress
+ if grep -q 'onClick=' "$FILE_PATH"; then
+ if ! grep -qE '(onKeyDown|onKeyPress|onKeyUp)=' "$FILE_PATH"; then
+ echo -e "${YELLOW}⚠️ A11y Warning: onClick handlers should have keyboard alternatives${NC}" >&2
+ ((WARNINGS++))
+ fi
+ fi
+
+ # Check for proper button usage
+ if grep -q '<div.*onClick=' "$FILE_PATH"; then
+ echo -e "${YELLOW}⚠️ A11y Warning: Use <button> instead of <div> with onClick for interactive elements${NC}" >&2
+ ((WARNINGS++))
+ fi
+fi
+
+# Check for images without alt text
+if grep -qE '<img[^>]*>' "$FILE_PATH"; then
+ IMG_TAGS=$(grep -o '<img[^>]*>' "$FILE_PATH")
+ while IFS= read -r img; do
+ if ! echo "$img" | grep -q 'alt='; then
+ echo -e "${RED}❌ A11y Issue: Image missing alt attribute${NC}" >&2
+ ((ISSUES++))
+ fi
+ done <<< "$IMG_TAGS"
+fi
+
+# Check for form elements
+if grep -qE '<(input|select|textarea)' "$FILE_PATH"; then
+ # Check for labels
+ check_missing "label" "input\|select\|textarea" "Form elements should have associated labels"
+
+ # Check for aria-required on required fields
+ if grep -q 'required' "$FILE_PATH"; then
+ check_missing "aria-required" "required" "Required fields should have aria-required attribute"
+ fi
+
+ # Check for error messages
+ if grep -q 'error' "$FILE_PATH"; then
+ check_missing "aria-describedby\|aria-errormessage" "error" "Error messages should be associated with form fields"
+ fi
+fi
+
+# Check for ARIA attributes
+if grep -q '<button' "$FILE_PATH"; then
+ # Icon-only buttons should have aria-label
+ if grep -qE '<button[^>]*>[\s]*<(svg|Icon)' "$FILE_PATH"; then
+ check_missing "aria-label" "<button.*Icon\|<button.*svg" "Icon-only buttons need aria-label"
+ fi
+fi
+
+# Check for modals/dialogs
+if grep -qE '(Dialog|Modal|Sheet|Popover)' "$FILE_PATH"; then
+ check_missing "aria-labelledby\|aria-label" "Dialog\|Modal" "Dialogs should have aria-labelledby or aria-label"
+ check_missing "aria-describedby" "DialogDescription" "Dialogs should have aria-describedby for descriptions"
+fi
+
+# Check for proper heading hierarchy
+if grep -qE '<h[1-6]' "$FILE_PATH"; then
+ # Extract all heading levels
+ HEADINGS=$(grep -o '<h[1-6]' "$FILE_PATH" | sed 's/<h//' | sort -n)
+ PREV=0
+ for h in $HEADINGS; do
+ if [ $PREV -ne 0 ] && [ $((h - PREV)) -gt 1 ]; then
+ echo -e "${YELLOW}⚠️ A11y Warning: Heading hierarchy skip detected (h$PREV to h$h)${NC}" >&2
+ ((WARNINGS++))
+ break
+ fi
+ PREV=$h
+ done
+fi
+
+# Check for color contrast (basic check for hardcoded colors)
+if grep -qE '(text-(white|black)|bg-(white|black))' "$FILE_PATH"; then
+ if grep -q 'text-white.*bg-white\|text-black.*bg-black' "$FILE_PATH"; then
+ echo -e "${RED}❌ A11y Issue: Potential color contrast issue detected${NC}" >&2
+ ((ISSUES++))
+ fi
+fi
+
+# Check for focus management
+if grep -qE '(focus:outline-none|outline-none)' "$FILE_PATH"; then
+ if ! grep -q 'focus-visible:\|focus:ring\|focus:border' "$FILE_PATH"; then
+ echo -e "${RED}❌ A11y Issue: Removing outline without providing alternative focus indicator${NC}" >&2
+ ((ISSUES++))
+ fi
+fi
+
+# Check for live regions
+if grep -q 'toast\|notification\|alert\|message' "$FILE_PATH"; then
+ check_missing "aria-live\|role=\"alert\"\|role=\"status\"" "toast\|notification\|alert" "Dynamic content should use live regions"
+fi
+
+# Check for lists
+if grep -qE '<li[^>]*>' "$FILE_PATH"; then
+ if ! grep -qE '<(ul|ol)[^>]*>' "$FILE_PATH"; then
+ echo -e "${YELLOW}⚠️ A11y Warning: <li> elements should be wrapped in <ul> or <ol>${NC}" >&2
+ ((WARNINGS++))
+ fi
+fi
+
+# Summary
+echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" >&2
+if [ $ISSUES -eq 0 ] && [ $WARNINGS -eq 0 ]; then
+ echo -e "${GREEN}✅ Accessibility check passed!${NC}" >&2
+else
+ if [ $ISSUES -gt 0 ]; then
+ echo -e "${RED}Found $ISSUES accessibility issues${NC}" >&2
+ fi
+ if [ $WARNINGS -gt 0 ]; then
+ echo -e "${YELLOW}Found $WARNINGS accessibility warnings${NC}" >&2
+ fi
+ echo -e "${BLUE}Consider running a full accessibility audit with axe-core${NC}" >&2
+fi
+
+# Pass through the original result
+echo "$TOOL_RESULT"
+exit 0 \ No newline at end of file