style: format all files with prettier

This commit is contained in:
Seth Hobson
2026-01-19 17:07:03 -05:00
parent 8d37048deb
commit 56848874a2
355 changed files with 15215 additions and 10241 deletions

View File

@@ -73,7 +73,7 @@ function Accordion({ items }) {
onClick={() => setOpenIndex(isOpen ? -1 : index)}
>
{item.title}
<span aria-hidden="true">{isOpen ? '' : '+'}</span>
<span aria-hidden="true">{isOpen ? "" : "+"}</span>
</button>
</h3>
<div
@@ -103,16 +103,16 @@ function Tabs({ tabs }) {
let newIndex = index;
switch (e.key) {
case 'ArrowRight':
case "ArrowRight":
newIndex = (index + 1) % tabs.length;
break;
case 'ArrowLeft':
case "ArrowLeft":
newIndex = (index - 1 + tabs.length) % tabs.length;
break;
case 'Home':
case "Home":
newIndex = 0;
break;
case 'End':
case "End":
newIndex = tabs.length - 1;
break;
default:
@@ -172,7 +172,7 @@ function MenuButton({ label, items }) {
const handleKeyDown = (e) => {
switch (e.key) {
case 'ArrowDown':
case "ArrowDown":
e.preventDefault();
if (!isOpen) {
setIsOpen(true);
@@ -181,16 +181,16 @@ function MenuButton({ label, items }) {
setActiveIndex((prev) => Math.min(prev + 1, items.length - 1));
}
break;
case 'ArrowUp':
case "ArrowUp":
e.preventDefault();
setActiveIndex((prev) => Math.max(prev - 1, 0));
break;
case 'Escape':
case "Escape":
setIsOpen(false);
buttonRef.current?.focus();
break;
case 'Enter':
case ' ':
case "Enter":
case " ":
if (isOpen && activeIndex >= 0) {
e.preventDefault();
items[activeIndex].onClick();
@@ -253,36 +253,36 @@ function MenuButton({ label, items }) {
```tsx
function Combobox({ options, onSelect, placeholder }) {
const [inputValue, setInputValue] = useState('');
const [inputValue, setInputValue] = useState("");
const [isOpen, setIsOpen] = useState(false);
const [activeIndex, setActiveIndex] = useState(-1);
const inputRef = useRef(null);
const listboxId = useId();
const filteredOptions = options.filter((opt) =>
opt.toLowerCase().includes(inputValue.toLowerCase())
opt.toLowerCase().includes(inputValue.toLowerCase()),
);
const handleKeyDown = (e) => {
switch (e.key) {
case 'ArrowDown':
case "ArrowDown":
e.preventDefault();
setIsOpen(true);
setActiveIndex((prev) =>
Math.min(prev + 1, filteredOptions.length - 1)
Math.min(prev + 1, filteredOptions.length - 1),
);
break;
case 'ArrowUp':
case "ArrowUp":
e.preventDefault();
setActiveIndex((prev) => Math.max(prev - 1, 0));
break;
case 'Enter':
case "Enter":
if (activeIndex >= 0) {
e.preventDefault();
selectOption(filteredOptions[activeIndex]);
}
break;
case 'Escape':
case "Escape":
setIsOpen(false);
setActiveIndex(-1);
break;
@@ -396,16 +396,16 @@ function Toolbar({ items }) {
let newIndex = activeIndex;
switch (e.key) {
case 'ArrowRight':
case "ArrowRight":
newIndex = (activeIndex + 1) % items.length;
break;
case 'ArrowLeft':
case "ArrowLeft":
newIndex = (activeIndex - 1 + items.length) % items.length;
break;
case 'Home':
case "Home":
newIndex = 0;
break;
case 'End':
case "End":
newIndex = items.length - 1;
break;
default:
@@ -414,7 +414,7 @@ function Toolbar({ items }) {
e.preventDefault();
setActiveIndex(newIndex);
toolbarRef.current?.querySelectorAll('button')[newIndex]?.focus();
toolbarRef.current?.querySelectorAll("button")[newIndex]?.focus();
};
return (

View File

@@ -34,12 +34,11 @@ Mobile accessibility ensures apps work for users with disabilities on iOS and An
// Ensure adequate spacing between touch targets
function ButtonGroup({ buttons }) {
return (
<div className="flex gap-3"> {/* 12px minimum gap */}
<div className="flex gap-3">
{" "}
{/* 12px minimum gap */}
{buttons.map((btn) => (
<button
key={btn.id}
className="min-w-[44px] min-h-[44px] px-4 py-2"
>
<button key={btn.id} className="min-w-[44px] min-h-[44px] px-4 py-2">
{btn.label}
</button>
))}
@@ -66,7 +65,7 @@ function IconButton({ icon, label, onClick }) {
### React Native Accessibility Props
```tsx
import { View, Text, TouchableOpacity, AccessibilityInfo } from 'react-native';
import { View, Text, TouchableOpacity, AccessibilityInfo } from "react-native";
// Basic accessible button
function AccessibleButton({ onPress, title, hint }) {
@@ -91,15 +90,15 @@ function ProductCard({ product }) {
accessibilityLabel={`${product.name}, ${product.price}, ${product.rating} stars`}
accessibilityRole="button"
accessibilityActions={[
{ name: 'activate', label: 'View details' },
{ name: 'addToCart', label: 'Add to cart' },
{ name: "activate", label: "View details" },
{ name: "addToCart", label: "Add to cart" },
]}
onAccessibilityAction={(event) => {
switch (event.nativeEvent.actionName) {
case 'addToCart':
case "addToCart":
addToCart(product);
break;
case 'activate':
case "activate":
viewDetails(product);
break;
}
@@ -356,11 +355,9 @@ function SwipeableCard({ item, onDelete }) {
return (
<View
accessible={true}
accessibilityActions={[
{ name: 'delete', label: 'Delete item' },
]}
accessibilityActions={[{ name: "delete", label: "Delete item" }]}
onAccessibilityAction={(event) => {
if (event.nativeEvent.actionName === 'delete') {
if (event.nativeEvent.actionName === "delete") {
onDelete(item);
}
}}
@@ -382,7 +379,7 @@ function SwipeableCard({ item, onDelete }) {
<TouchableOpacity
accessibilityLabel={`Delete ${item.title}`}
onPress={() => onDelete(item)}
style={{ position: 'absolute', right: 0 }}
style={{ position: "absolute", right: 0 }}
>
<Text>Delete</Text>
</TouchableOpacity>
@@ -395,7 +392,7 @@ function SwipeableCard({ item, onDelete }) {
```tsx
// Respect reduced motion preference
import { AccessibilityInfo } from 'react-native';
import { AccessibilityInfo } from "react-native";
function AnimatedComponent() {
const [reduceMotion, setReduceMotion] = useState(false);
@@ -404,8 +401,8 @@ function AnimatedComponent() {
AccessibilityInfo.isReduceMotionEnabled().then(setReduceMotion);
const subscription = AccessibilityInfo.addEventListener(
'reduceMotionChanged',
setReduceMotion
"reduceMotionChanged",
setReduceMotion,
);
return () => subscription.remove();
@@ -414,9 +411,7 @@ function AnimatedComponent() {
return (
<Animated.View
style={{
transform: reduceMotion
? []
: [{ translateX: animatedValue }],
transform: reduceMotion ? [] : [{ translateX: animatedValue }],
opacity: reduceMotion ? 1 : animatedOpacity,
}}
>
@@ -503,6 +498,7 @@ const scaledFontSize = (size: number) => {
```markdown
## VoiceOver (iOS) Testing
- [ ] All interactive elements have labels
- [ ] Swipe navigation covers all content in logical order
- [ ] Custom actions available for complex interactions
@@ -511,6 +507,7 @@ const scaledFontSize = (size: number) => {
- [ ] Images have appropriate descriptions or are hidden
## TalkBack (Android) Testing
- [ ] Focus order is logical
- [ ] Touch exploration works correctly
- [ ] Custom actions available
@@ -519,12 +516,14 @@ const scaledFontSize = (size: number) => {
- [ ] Grouped content read together
## Motor Accessibility
- [ ] Touch targets at least 44x44 points
- [ ] Adequate spacing between targets (8dp minimum)
- [ ] Alternatives to complex gestures
- [ ] No time-limited interactions
## Visual Accessibility
- [ ] Text scales to 200% without loss
- [ ] Content visible in high contrast mode
- [ ] Color not sole indicator

View File

@@ -259,7 +259,7 @@ function Tooltip({ content, children }) {
<div
role="tooltip"
// Dismissible: user can close without moving pointer
onKeyDown={(e) => e.key === 'Escape' && setIsVisible(false)}
onKeyDown={(e) => e.key === "Escape" && setIsVisible(false)}
// Hoverable: content stays visible when pointer moves to it
onMouseEnter={() => setIsVisible(true)}
onMouseLeave={() => setIsVisible(false)}
@@ -292,7 +292,7 @@ function CustomButton({ onClick, children }) {
tabIndex={0}
onClick={onClick}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
onClick();
}
@@ -331,10 +331,10 @@ function Modal({ isOpen, onClose, children }) {
// Allow Escape to close
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Escape') onClose();
if (e.key === "Escape") onClose();
};
document.addEventListener('keydown', handleKeyDown);
return () => document.removeEventListener('keydown', handleKeyDown);
document.addEventListener("keydown", handleKeyDown);
return () => document.removeEventListener("keydown", handleKeyDown);
}, [onClose]);
return (
@@ -357,12 +357,18 @@ function Modal({ isOpen, onClose, children }) {
```tsx
// Skip links
<body>
<a href="#main" className="skip-link">Skip to main content</a>
<a href="#nav" className="skip-link">Skip to navigation</a>
<a href="#main" className="skip-link">
Skip to main content
</a>
<a href="#nav" className="skip-link">
Skip to navigation
</a>
<header>...</header>
<nav id="nav" aria-label="Main">...</nav>
<nav id="nav" aria-label="Main">
...
</nav>
<main id="main" tabIndex={-1}>
{/* Main content */}
@@ -455,8 +461,12 @@ Content and interface must be understandable.
```html
<!DOCTYPE html>
<html lang="en">
<head>...</head>
<body>...</body>
<head>
...
</head>
<body>
...
</body>
</html>
```
@@ -571,7 +581,7 @@ function CustomCheckbox({ checked, onChange, label }) {
aria-label={label}
onClick={() => onChange(!checked)}
>
{checked ? '✓' : '○'} {label}
{checked ? "✓" : "○"} {label}
</button>
);
}
@@ -587,8 +597,8 @@ function CustomSlider({ value, min, max, label, onChange }) {
aria-label={label}
tabIndex={0}
onKeyDown={(e) => {
if (e.key === 'ArrowRight') onChange(Math.min(value + 1, max));
if (e.key === 'ArrowLeft') onChange(Math.max(value - 1, min));
if (e.key === "ArrowRight") onChange(Math.min(value + 1, max));
if (e.key === "ArrowLeft") onChange(Math.max(value - 1, min));
}}
>
<div style={{ width: `${((value - min) / (max - min)) * 100}%` }} />
@@ -601,6 +611,7 @@ function CustomSlider({ value, min, max, label, onChange }) {
```markdown
## Keyboard Testing
- [ ] All interactive elements focusable with Tab
- [ ] Focus order matches visual order
- [ ] Focus indicator always visible
@@ -609,6 +620,7 @@ function CustomSlider({ value, min, max, label, onChange }) {
- [ ] Enter/Space activates buttons and links
## Screen Reader Testing
- [ ] All images have alt text
- [ ] Form inputs have labels
- [ ] Headings in logical order
@@ -617,6 +629,7 @@ function CustomSlider({ value, min, max, label, onChange }) {
- [ ] Error messages announced
## Visual Testing
- [ ] Text contrast at least 4.5:1
- [ ] UI component contrast at least 3:1
- [ ] Works at 200% zoom