fixed accessibility and keyboard navigation for edit node and connection modals
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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]">
|
||||
|
||||
Reference in New Issue
Block a user