fix: ForkModal accessibility and UX (escape, click-outside, labels, maxLength)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useState } from 'react'
|
||||
import { useState, useEffect } from 'react'
|
||||
import { GitBranch, X } from 'lucide-react'
|
||||
import { treesApi } from '@/api/trees'
|
||||
import { toast } from '@/lib/toast'
|
||||
@@ -18,6 +18,14 @@ export function ForkModal({ treeId, treeName, onClose }: ForkModalProps) {
|
||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
if (e.key === 'Escape') onClose()
|
||||
}
|
||||
document.addEventListener('keydown', handleKeyDown)
|
||||
return () => document.removeEventListener('keydown', handleKeyDown)
|
||||
}, [onClose])
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault()
|
||||
if (!name.trim()) return
|
||||
@@ -40,8 +48,14 @@ export function ForkModal({ treeId, treeName, onClose }: ForkModalProps) {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4">
|
||||
<div className="w-full max-w-md rounded-xl border border-border bg-card shadow-xl">
|
||||
<div
|
||||
className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4"
|
||||
onClick={onClose}
|
||||
>
|
||||
<div
|
||||
className="w-full max-w-md rounded-xl border border-border bg-card shadow-xl"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between border-b border-border px-5 py-4">
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -50,6 +64,7 @@ export function ForkModal({ treeId, treeName, onClose }: ForkModalProps) {
|
||||
</div>
|
||||
<button
|
||||
onClick={onClose}
|
||||
aria-label="Close"
|
||||
className="rounded-md p-1 text-muted-foreground hover:bg-accent hover:text-foreground"
|
||||
>
|
||||
<X className="h-4 w-4" />
|
||||
@@ -59,15 +74,17 @@ export function ForkModal({ treeId, treeName, onClose }: ForkModalProps) {
|
||||
{/* Body */}
|
||||
<form onSubmit={handleSubmit} className="space-y-4 px-5 py-4">
|
||||
<div>
|
||||
<label className="mb-1.5 block text-xs font-medium text-muted-foreground">
|
||||
<label htmlFor="fork-name" className="mb-1.5 block text-xs font-medium text-muted-foreground">
|
||||
Name <span className="text-red-400">*</span>
|
||||
</label>
|
||||
<input
|
||||
id="fork-name"
|
||||
type="text"
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
required
|
||||
autoFocus
|
||||
maxLength={255}
|
||||
className={cn(
|
||||
'w-full rounded-lg border border-border bg-card px-3 py-2 text-sm text-foreground',
|
||||
'placeholder:text-muted-foreground focus:border-primary focus:outline-none focus:ring-1 focus:ring-primary/20'
|
||||
@@ -76,11 +93,12 @@ export function ForkModal({ treeId, treeName, onClose }: ForkModalProps) {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="mb-1.5 block text-xs font-medium text-muted-foreground">
|
||||
<label htmlFor="fork-reason" className="mb-1.5 block text-xs font-medium text-muted-foreground">
|
||||
Reason for Forking{' '}
|
||||
<span className="text-muted-foreground/60">(optional)</span>
|
||||
</label>
|
||||
<textarea
|
||||
id="fork-reason"
|
||||
value={forkReason}
|
||||
onChange={(e) => setForkReason(e.target.value)}
|
||||
rows={3}
|
||||
@@ -108,7 +126,7 @@ export function ForkModal({ treeId, treeName, onClose }: ForkModalProps) {
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isSubmitting || !name.trim()}
|
||||
className="bg-gradient-brand flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-medium text-white shadow-lg shadow-primary/20 hover:opacity-90 disabled:opacity-40"
|
||||
className="bg-gradient-brand flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-medium text-white shadow-lg shadow-primary/20 hover:opacity-90 disabled:opacity-40 disabled:cursor-not-allowed"
|
||||
>
|
||||
{isSubmitting ? 'Forking…' : 'Fork Flow'}
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user