fixed accessibility and keyboard navigation for edit node and connection modals

This commit is contained in:
findthelorax
2026-04-23 15:59:46 -04:00
parent 4e68af7cac
commit 31b5bc4515
2 changed files with 23 additions and 9 deletions
+9 -3
View File
@@ -68,7 +68,7 @@ export function EdgeModal({ open, onClose, onSubmit, onDelete, onClearWaypoints,
<div className="flex flex-col gap-1.5">
<Label className="text-xs text-muted-foreground">Link Type</Label>
<Select value={type} onValueChange={(v) => setType(v as EdgeType)}>
<SelectTrigger className="bg-[#21262d] border-[#30363d] text-sm h-8">
<SelectTrigger className="bg-[#21262d] border-[#30363d] text-sm h-8 cursor-pointer" aria-label="Edge type selector">
<SelectValue />
</SelectTrigger>
<SelectContent className="bg-[#21262d] border-[#30363d]">
@@ -112,7 +112,9 @@ export function EdgeModal({ open, onClose, onSubmit, onDelete, onClearWaypoints,
key={style}
type="button"
onClick={() => setPathStyle(style)}
className="flex-1 py-1 text-xs capitalize transition-colors"
className="flex-1 py-1 text-xs capitalize transition-colors cursor-pointer"
tabIndex={0}
aria-label={`Path style ${style}`}
style={{
background: pathStyle === style ? '#00d4ff22' : '#21262d',
color: pathStyle === style ? '#00d4ff' : '#8b949e',
@@ -133,7 +135,9 @@ export function EdgeModal({ open, onClose, onSubmit, onDelete, onClearWaypoints,
key={mode}
type="button"
onClick={() => setAnimation(mode)}
className="flex-1 py-1 text-xs capitalize transition-colors"
className="flex-1 py-1 text-xs capitalize transition-colors cursor-pointer"
tabIndex={0}
aria-label={`Animation mode ${mode}`}
style={{
background: animation === mode ? '#00d4ff22' : '#21262d',
color: animation === mode ? '#00d4ff' : '#8b949e',
@@ -162,6 +166,8 @@ export function EdgeModal({ open, onClose, onSubmit, onDelete, onClearWaypoints,
<label
className="relative flex items-center gap-2.5 px-2.5 h-8 rounded-md border cursor-pointer"
style={{ borderColor: customColor ? effectiveColor : '#30363d', background: '#21262d' }}
tabIndex={0}
aria-label="Edge color picker"
>
<input
type="color"
+14 -6
View File
@@ -96,7 +96,7 @@ export function NodeModal({ open, onClose, onSubmit, initial, title = 'Add Node'
<div className="flex flex-col gap-1.5">
<Label className="text-xs text-muted-foreground">Type</Label>
<Select value={form.type} onValueChange={(v) => set('type', v as NodeType)}>
<SelectTrigger className="bg-[#21262d] border-[#30363d] text-sm h-8 w-full">
<SelectTrigger className="bg-[#21262d] border-[#30363d] text-sm h-8 w-full cursor-pointer" aria-label="Node type selector">
<SelectValue>{NODE_TYPE_LABELS[(form.type ?? 'server') as NodeType]}</SelectValue>
</SelectTrigger>
<SelectContent className="bg-[#21262d] border-[#30363d]">
@@ -137,7 +137,9 @@ export function NodeModal({ open, onClose, onSubmit, initial, title = 'Add Node'
<button
type="button"
onClick={() => setIconPickerOpen((o) => !o)}
className="flex items-center justify-between gap-2 h-8 px-3 rounded-md bg-[#21262d] border border-[#30363d] text-sm hover:border-[#8b949e] transition-colors w-full"
className="flex items-center justify-between gap-2 h-8 px-3 rounded-md bg-[#21262d] border border-[#30363d] text-sm hover:border-[#8b949e] transition-colors w-full cursor-pointer"
tabIndex={0}
aria-label="Icon picker trigger"
>
<span className="flex items-center gap-2 min-w-0">
{(() => {
@@ -182,7 +184,9 @@ export function NodeModal({ open, onClose, onSubmit, initial, title = 'Add Node'
type="button"
title={entry.label}
onClick={() => { set('custom_icon', isSelected ? undefined : entry.key); setIconPickerOpen(false) }}
className="flex items-center justify-center w-7 h-7 rounded transition-colors"
className="flex items-center justify-center w-7 h-7 rounded transition-colors cursor-pointer"
tabIndex={0}
aria-label={`Select icon ${entry.label}`}
style={{
background: isSelected ? '#00d4ff22' : 'transparent',
border: isSelected ? '1px solid #00d4ff88' : '1px solid transparent',
@@ -241,7 +245,7 @@ export function NodeModal({ open, onClose, onSubmit, initial, title = 'Add Node'
<div className="flex flex-col gap-1.5">
<Label className="text-xs text-muted-foreground">Check Method</Label>
<Select value={form.check_method ?? 'ping'} onValueChange={(v) => set('check_method', v as CheckMethod)}>
<SelectTrigger className="bg-[#21262d] border-[#30363d] text-sm h-8">
<SelectTrigger className="bg-[#21262d] border-[#30363d] text-sm h-8 cursor-pointer" aria-label="Parent container selector">
<SelectValue>{CHECK_METHOD_LABELS[(form.check_method ?? 'ping') as CheckMethod]}</SelectValue>
</SelectTrigger>
<SelectContent className="bg-[#21262d] border-[#30363d]">
@@ -271,7 +275,7 @@ export function NodeModal({ open, onClose, onSubmit, initial, title = 'Add Node'
value={form.parent_id ?? 'none'}
onValueChange={(v) => set('parent_id', v === 'none' ? undefined : v)}
>
<SelectTrigger className="bg-[#21262d] border-[#30363d] text-sm h-8">
<SelectTrigger className="bg-[#21262d] border-[#30363d] text-sm h-8 cursor-pointer" aria-label="Parent container selector">
<SelectValue placeholder="None (standalone)">
{form.parent_id
? (filteredParentNodes.find((n) => n.id === form.parent_id)?.label ?? 'None (standalone)')
@@ -301,6 +305,8 @@ export function NodeModal({ open, onClose, onSubmit, initial, title = 'Add Node'
aria-checked={!!form.container_mode}
onClick={() => set('container_mode', !form.container_mode)}
className="relative inline-flex h-5 w-9 shrink-0 cursor-pointer rounded-full transition-colors focus:outline-none"
tabIndex={0}
aria-label="Toggle container mode"
style={{ background: form.container_mode ? '#ff6e00' : '#30363d' }}
>
<span
@@ -336,6 +342,8 @@ export function NodeModal({ open, onClose, onSubmit, initial, title = 'Add Node'
className="relative w-full h-7 rounded-md border cursor-pointer overflow-hidden transition-all"
style={{ borderColor: isCustom ? currentValue : '#30363d' }}
title={`${key.charAt(0).toUpperCase() + key.slice(1)}: ${currentValue}`}
tabIndex={0}
aria-label={`Color picker for ${key}`}
>
<input
type="color"
@@ -363,7 +371,7 @@ export function NodeModal({ open, onClose, onSubmit, initial, title = 'Add Node'
value={String(form.bottom_handles ?? 1)}
onValueChange={(v) => set('bottom_handles', parseInt(v ?? '1', 10))}
>
<SelectTrigger className="bg-[#21262d] border-[#30363d] text-sm h-8">
<SelectTrigger className="bg-[#21262d] border-[#30363d] text-sm h-8 cursor-pointer" aria-label="Bottom connection points selector">
<SelectValue />
</SelectTrigger>
<SelectContent className="bg-[#21262d] border-[#30363d]">