fix: resolve ESLint errors and apply formatting

- Remove onClick handler from Switch label (accessibility fix)
- Fix React Hook conditional usage in useControlled
- Remove unnecessary isControlled dependency from useCallback
- Apply Biome formatting (template literals, className simplification)
- Fix playground Checkbox/Switch onChange usage

All CI checks should now pass: lint, type-check, format-check, build.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Ajax Davis 2025-11-27 02:29:18 +10:00
parent 535717e34f
commit c521c4a1e1
3 changed files with 32 additions and 47 deletions

View file

@ -464,7 +464,9 @@ export default function Example() {
{/* Forms Section */}
<section className="space-y-6">
<h2 className="text-3xl font-semibold border-b border-border pb-2">Form Components</h2>
<h2 className="text-3xl font-semibold border-b border-border pb-2">
Form Components
</h2>
{/* Textarea */}
<div className="space-y-4">
@ -479,12 +481,7 @@ export default function Example() {
/>
</FormField>
<FormField label="Feedback" helperText="Maximum 200 characters">
<Textarea
placeholder="Your feedback..."
rows={4}
maxLength={200}
showCount
/>
<Textarea placeholder="Your feedback..." rows={4} maxLength={200} showCount />
</FormField>
</div>
</div>
@ -496,12 +493,12 @@ export default function Example() {
<CardContent className="p-6 space-y-4">
<Checkbox
checked={newsletter}
onCheckedChange={setNewsletter}
onChange={(e) => setNewsletter(e.target.checked)}
label="Subscribe to newsletter"
/>
<Checkbox
checked={terms}
onCheckedChange={setTerms}
onChange={(e) => setTerms(e.target.checked)}
label="I agree to the terms and conditions"
/>
<Checkbox disabled label="Disabled checkbox" />
@ -546,7 +543,7 @@ export default function Example() {
Receive email notifications about updates
</p>
</div>
<Switch checked={notifications} onCheckedChange={setNotifications} />
<Switch checked={notifications} onChange={setNotifications} />
</div>
<div className="flex items-center justify-between">
<div className="space-y-0.5">
@ -560,9 +557,7 @@ export default function Example() {
<div className="flex items-center justify-between opacity-50">
<div className="space-y-0.5">
<Label>Disabled switch</Label>
<p className="text-sm text-foreground-secondary">
This switch is disabled
</p>
<p className="text-sm text-foreground-secondary">This switch is disabled</p>
</div>
<Switch disabled />
</div>
@ -654,7 +649,11 @@ export default function Example() {
/>
</FormField>
<FormField label="Bio" htmlFor="profile-bio" helperText="Tell us about yourself">
<FormField
label="Bio"
htmlFor="profile-bio"
helperText="Tell us about yourself"
>
<Textarea
id="profile-bio"
placeholder="Write something..."
@ -683,12 +682,12 @@ export default function Example() {
<div className="space-y-3">
<Checkbox
checked={newsletter}
onCheckedChange={setNewsletter}
onChange={(e) => setNewsletter(e.target.checked)}
label="Subscribe to newsletter"
/>
<Checkbox
checked={terms}
onCheckedChange={setTerms}
onChange={(e) => setTerms(e.target.checked)}
label="I agree to the terms and conditions"
/>
</div>

View file

@ -178,13 +178,6 @@ export const Switch = forwardRef<HTMLButtonElement, SwitchProps>(
labelPosition === 'left' ? 'mr-2' : 'ml-2',
(disabled || loading) && 'cursor-not-allowed opacity-50'
)}
onClick={(e) => {
// Prevent label from triggering button click (button handles it)
e.preventDefault();
if (!disabled && !loading) {
handleClick();
}
}}
>
{label}
</label>
@ -192,10 +185,7 @@ export const Switch = forwardRef<HTMLButtonElement, SwitchProps>(
return (
<div
className={cn(
'inline-flex items-center',
(disabled || loading) && 'cursor-not-allowed'
)}
className={cn('inline-flex items-center', (disabled || loading) && 'cursor-not-allowed')}
>
{labelPosition === 'left' && labelElement}
{switchButton}

View file

@ -48,31 +48,27 @@ export function useControlled<T>({
// Use controlled value if provided, otherwise use internal state
const value = isControlled ? controlled : valueState;
// Track previous controlled state for dev warning
const prevControlledRef = useRef(isControlled);
// Dev warning for switching between controlled and uncontrolled
if (process.env.NODE_ENV !== 'production') {
// biome-ignore lint/correctness/useHookAtTopLevel: dev-only warning
useRef(() => {
if (isControlled !== (controlled !== undefined)) {
console.error(
`Warning: A component (\`${name}\`) is changing from ${
isControlled ? 'controlled' : 'uncontrolled'
} to ${isControlled ? 'uncontrolled' : 'controlled'}. ` +
'Components should not switch from controlled to uncontrolled (or vice versa). ' +
'Decide between using a controlled or uncontrolled component for the lifetime of the component.'
);
}
});
if (prevControlledRef.current !== (controlled !== undefined)) {
console.error(
`Warning: A component (\`${name}\`) is changing from ${
prevControlledRef.current ? 'controlled' : 'uncontrolled'
} to ${prevControlledRef.current ? 'uncontrolled' : 'controlled'}. Components should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled component for the lifetime of the component.`
);
}
prevControlledRef.current = controlled !== undefined;
}
// Callback to update the value
const setValueIfUncontrolled = useCallback(
(newValue: T) => {
if (!isControlled) {
setValue(newValue);
}
},
[isControlled]
);
const setValueIfUncontrolled = useCallback((newValue: T) => {
if (!isControlled) {
setValue(newValue);
}
}, []);
return [value as T, setValueIfUncontrolled];
}