feat(mobile): bump touch-target heights on Button/Input/Textarea, keep 16px to prevent iOS zoom

This commit is contained in:
Matt Ciaccio
2026-04-29 14:06:59 +02:00
parent 3fbfba6598
commit 38527d71fc
3 changed files with 56 additions and 65 deletions

View File

@@ -1,57 +1,49 @@
import * as React from "react" import * as React from 'react';
import { Slot } from "@radix-ui/react-slot" import { Slot } from '@radix-ui/react-slot';
import { cva, type VariantProps } from "class-variance-authority" import { cva, type VariantProps } from 'class-variance-authority';
import { cn } from "@/lib/utils" import { cn } from '@/lib/utils';
const buttonVariants = cva( const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
{ {
variants: { variants: {
variant: { variant: {
default: default: 'bg-primary text-primary-foreground shadow hover:bg-primary/90',
"bg-primary text-primary-foreground shadow hover:bg-primary/90", destructive: 'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90',
destructive:
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
outline: outline:
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground", 'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',
secondary: secondary: 'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80',
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80", ghost: 'hover:bg-accent hover:text-accent-foreground',
ghost: "hover:bg-accent hover:text-accent-foreground", link: 'text-primary underline-offset-4 hover:underline',
link: "text-primary underline-offset-4 hover:underline",
}, },
size: { size: {
default: "h-9 px-4 py-2", default: 'h-11 px-4 py-2',
sm: "h-8 rounded-md px-3 text-xs", sm: 'h-9 rounded-md px-3 text-xs',
lg: "h-10 rounded-md px-8", lg: 'h-12 rounded-md px-8',
icon: "h-9 w-9", icon: 'h-11 w-11',
}, },
}, },
defaultVariants: { defaultVariants: {
variant: "default", variant: 'default',
size: "default", size: 'default',
}, },
} },
) );
export interface ButtonProps export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>, extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
VariantProps<typeof buttonVariants> { asChild?: boolean;
asChild?: boolean
} }
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>( const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => { ({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button" const Comp = asChild ? Slot : 'button';
return ( return (
<Comp <Comp className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props} />
className={cn(buttonVariants({ variant, size, className }))} );
ref={ref} },
{...props} );
/> Button.displayName = 'Button';
)
}
)
Button.displayName = "Button"
export { Button, buttonVariants } export { Button, buttonVariants };

View File

@@ -1,22 +1,22 @@
import * as React from "react" import * as React from 'react';
import { cn } from "@/lib/utils" import { cn } from '@/lib/utils';
const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>( const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<'input'>>(
({ className, type, ...props }, ref) => { ({ className, type, ...props }, ref) => {
return ( return (
<input <input
type={type} type={type}
className={cn( className={cn(
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", 'flex h-11 w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',
className className,
)} )}
ref={ref} ref={ref}
{...props} {...props}
/> />
) );
} },
) );
Input.displayName = "Input" Input.displayName = 'Input';
export { Input } export { Input };

View File

@@ -1,22 +1,21 @@
import * as React from "react" import * as React from 'react';
import { cn } from "@/lib/utils" import { cn } from '@/lib/utils';
const Textarea = React.forwardRef< const Textarea = React.forwardRef<HTMLTextAreaElement, React.ComponentProps<'textarea'>>(
HTMLTextAreaElement, ({ className, ...props }, ref) => {
React.ComponentProps<"textarea"> return (
>(({ className, ...props }, ref) => { <textarea
return ( className={cn(
<textarea 'flex min-h-[80px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',
className={cn( className,
"flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", )}
className ref={ref}
)} {...props}
ref={ref} />
{...props} );
/> },
) );
}) Textarea.displayName = 'Textarea';
Textarea.displayName = "Textarea"
export { Textarea } export { Textarea };