fix(canvas): add focus-visible rings to final 5 component files
- A2AEdge.tsx: edge label pill button - OrgCancelButton.tsx: cancel trigger + confirm Yes/No - AttachmentTextPreview.tsx: download, show-all, truncated-dl buttons - form-inputs.tsx: tag remove (red) + section toggle (accent) - secrets-section.tsx: SecretRow/CustomSecretRow remove (red), update, save, scope toggle (amber for global), add-variable buttons - settings-panel.css: UnsavedChangesGuard keep/discard buttons Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
cd0207b224
commit
ee8eec8213
@ -119,7 +119,7 @@ function A2AEdgeImpl({
|
||||
onClick={handleClick}
|
||||
aria-label={ariaLabel}
|
||||
title="Open source workspace's activity feed"
|
||||
className={`px-2 py-0.5 rounded-full bg-surface-sunken/95 border ${accent} ${accentText} text-[10px] font-medium shadow-md shadow-black/40 backdrop-blur-sm hover:bg-surface-card hover:border-opacity-100 transition-colors cursor-pointer`}
|
||||
className={`px-2 py-0.5 rounded-full bg-surface-sunken/95 border ${accent} ${accentText} text-[10px] font-medium shadow-md shadow-black/40 backdrop-blur-sm hover:bg-surface-card hover:border-opacity-100 transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1`}
|
||||
>
|
||||
{labelText}
|
||||
</button>
|
||||
|
||||
@ -122,7 +122,7 @@ export function OrgCancelButton({ rootId, rootName, workspaceCount }: Props) {
|
||||
type="button"
|
||||
onClick={handleCancel}
|
||||
disabled={submitting}
|
||||
className="mol-deploy-cancel px-2 py-0.5 rounded text-[10px] font-semibold"
|
||||
className="mol-deploy-cancel px-2 py-0.5 rounded text-[10px] font-semibold focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-red-500 focus-visible:ring-offset-1"
|
||||
>
|
||||
{submitting ? "Deleting…" : "Yes"}
|
||||
</button>
|
||||
@ -130,7 +130,7 @@ export function OrgCancelButton({ rootId, rootName, workspaceCount }: Props) {
|
||||
type="button"
|
||||
onClick={() => setConfirming(false)}
|
||||
disabled={submitting}
|
||||
className="px-2 py-0.5 rounded bg-surface-card/80 hover:bg-surface-card text-[10px] text-ink"
|
||||
className="px-2 py-0.5 rounded bg-surface-card/80 hover:bg-surface-card text-[10px] text-ink focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1"
|
||||
>
|
||||
No
|
||||
</button>
|
||||
@ -148,7 +148,7 @@ export function OrgCancelButton({ rootId, rootName, workspaceCount }: Props) {
|
||||
e.stopPropagation();
|
||||
setConfirming(true);
|
||||
}}
|
||||
className="nodrag mol-deploy-cancel mol-deploy-cancel-pulse absolute -top-7 right-1 z-20 flex items-center gap-1 rounded-full px-2.5 py-0.5 text-[10px] font-semibold shadow-md"
|
||||
className="nodrag mol-deploy-cancel mol-deploy-cancel-pulse absolute -top-7 right-1 z-20 flex items-center gap-1 rounded-full px-2.5 py-0.5 text-[10px] font-semibold shadow-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-red-500 focus-visible:ring-offset-1"
|
||||
aria-label={`Cancel deployment of ${rootName}`}
|
||||
>
|
||||
<svg width="10" height="10" viewBox="0 0 16 16" aria-hidden="true">
|
||||
|
||||
@ -148,7 +148,7 @@ export function AttachmentTextPreview({ workspaceId, attachment, onDownload, ton
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onDownload(attachment)}
|
||||
className="text-ink-mid hover:text-ink"
|
||||
className="text-ink-mid hover:text-ink focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1"
|
||||
title={`Download ${attachment.name}`}
|
||||
aria-label={`Download ${attachment.name}`}
|
||||
>
|
||||
@ -162,7 +162,7 @@ export function AttachmentTextPreview({ workspaceId, attachment, onDownload, ton
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setExpanded(true)}
|
||||
className="block w-full text-center text-[10px] text-ink-mid hover:text-ink py-1 border-t border-line/40"
|
||||
className="block w-full text-center text-[10px] text-ink-mid hover:text-ink py-1 border-t border-line/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1"
|
||||
>
|
||||
Show all {lines.length} lines
|
||||
</button>
|
||||
@ -173,7 +173,7 @@ export function AttachmentTextPreview({ workspaceId, attachment, onDownload, ton
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onDownload(attachment)}
|
||||
className="underline"
|
||||
className="underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1"
|
||||
>
|
||||
download full file
|
||||
</button>
|
||||
|
||||
@ -102,7 +102,7 @@ export function TagList({ label, values, onChange, placeholder }: { label: strin
|
||||
{values.map((v, i) => (
|
||||
<span key={i} className="inline-flex items-center gap-1 px-1.5 py-0.5 bg-surface-card border border-line rounded text-[10px] text-ink-mid font-mono">
|
||||
{v}
|
||||
<button type="button" aria-label={`Remove tag ${v}`} onClick={() => onChange(values.filter((_, j) => j !== i))} className="text-ink-mid hover:text-bad">×</button>
|
||||
<button type="button" aria-label={`Remove tag ${v}`} onClick={() => onChange(values.filter((_, j) => j !== i))} className="text-ink-mid hover:text-bad focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-red-500 focus-visible:ring-offset-1">×</button>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
@ -129,7 +129,7 @@ export function Section({ title, children, defaultOpen = true }: { title: string
|
||||
const [open, setOpen] = useState(defaultOpen);
|
||||
return (
|
||||
<div className="border border-line rounded mb-2">
|
||||
<button type="button" onClick={() => setOpen(!open)} className="w-full flex items-center justify-between px-3 py-1.5 text-[10px] text-ink-mid hover:text-ink bg-surface-sunken/50">
|
||||
<button type="button" onClick={() => setOpen(!open)} className="w-full flex items-center justify-between px-3 py-1.5 text-[10px] text-ink-mid hover:text-ink bg-surface-sunken/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1">
|
||||
<span className="font-medium uppercase tracking-wider">{title}</span>
|
||||
<span>{open ? "▾" : "▸"}</span>
|
||||
</button>
|
||||
|
||||
@ -113,9 +113,9 @@ function SecretRow({ label, secretKey, isSet, scope, globalMode, onSave, onDelet
|
||||
{isSet && <span className="text-[10px] text-good bg-green-900/30 px-1.5 py-0.5 rounded">Set</span>}
|
||||
{scope && <ScopeBadge scope={scope} />}
|
||||
{!editing && isSet && (globalMode || scope !== "global") && (
|
||||
<button type="button" onClick={onDelete} className="text-[11px] text-bad hover:text-bad">Remove</button>
|
||||
<button type="button" onClick={onDelete} className="text-[11px] text-bad hover:text-bad focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-red-500 focus-visible:ring-offset-1">Remove</button>
|
||||
)}
|
||||
<button type="button" onClick={() => setEditing(!editing)} className="text-[11px] text-accent hover:text-accent">
|
||||
<button type="button" onClick={() => setEditing(!editing)} className="text-[11px] text-accent hover:text-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1">
|
||||
{actionLabel()}
|
||||
</button>
|
||||
</div>
|
||||
@ -131,7 +131,7 @@ function SecretRow({ label, secretKey, isSet, scope, globalMode, onSave, onDelet
|
||||
<button type="button"
|
||||
onClick={() => { onSave(value); setEditing(false); setValue(""); }}
|
||||
disabled={!value}
|
||||
className="px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-white disabled:opacity-30"
|
||||
className="px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-white disabled:opacity-30 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1"
|
||||
>Save</button>
|
||||
</div>
|
||||
)}
|
||||
@ -165,10 +165,10 @@ function CustomSecretRow({ secretKey, scope, globalMode, onSave, onDelete }: {
|
||||
<span className="text-[10px] text-good">Set</span>
|
||||
{!globalMode && <ScopeBadge scope={scope} />}
|
||||
{canDelete && !editing && (
|
||||
<button type="button" onClick={onDelete} className="text-[11px] text-bad hover:text-bad">Remove</button>
|
||||
<button type="button" onClick={onDelete} className="text-[11px] text-bad hover:text-bad focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-red-500 focus-visible:ring-offset-1">Remove</button>
|
||||
)}
|
||||
{(canDelete || showOverride) && (
|
||||
<button type="button" onClick={() => setEditing(!editing)} className="text-[11px] text-accent hover:text-accent">
|
||||
<button type="button" onClick={() => setEditing(!editing)} className="text-[11px] text-accent hover:text-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1">
|
||||
{editing ? "Cancel" : showOverride ? "Override" : "Update"}
|
||||
</button>
|
||||
)}
|
||||
@ -184,7 +184,7 @@ function CustomSecretRow({ secretKey, scope, globalMode, onSave, onDelete }: {
|
||||
<button type="button"
|
||||
onClick={() => { onSave(value); setEditing(false); setValue(""); }}
|
||||
disabled={!value}
|
||||
className="px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-white disabled:opacity-30"
|
||||
className="px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-white disabled:opacity-30 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1"
|
||||
>Save</button>
|
||||
</div>
|
||||
)}
|
||||
@ -297,7 +297,7 @@ export function SecretsSection({ workspaceId, requiredEnv }: { workspaceId: stri
|
||||
<div className="flex items-center gap-2 pb-1">
|
||||
<button
|
||||
onClick={() => setGlobalMode(false)}
|
||||
className={`text-[10px] px-2 py-0.5 rounded transition-colors ${
|
||||
className={`text-[10px] px-2 py-0.5 rounded transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1 ${
|
||||
!globalMode ? "bg-accent-strong/20 text-accent border border-accent/30" : "text-white-soft hover:text-white-mid"
|
||||
}`}
|
||||
>
|
||||
@ -305,7 +305,7 @@ export function SecretsSection({ workspaceId, requiredEnv }: { workspaceId: stri
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setGlobalMode(true)}
|
||||
className={`text-[10px] px-2 py-0.5 rounded transition-colors ${
|
||||
className={`text-[10px] px-2 py-0.5 rounded transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-amber-400 focus-visible:ring-offset-1 ${
|
||||
globalMode ? "bg-amber-600/20 text-warm border border-amber-500/30" : "text-white-soft hover:text-white-mid"
|
||||
}`}
|
||||
>
|
||||
@ -356,15 +356,15 @@ export function SecretsSection({ workspaceId, requiredEnv }: { workspaceId: stri
|
||||
className="w-full bg-surface-sunken border border-line rounded px-2 py-1 text-[10px] text-ink focus:outline-none focus:border-accent" />
|
||||
<div className="flex gap-2">
|
||||
<button type="button" onClick={() => { if (newKey && newValue) handleSave(newKey, newValue); }} disabled={!newKey || !newValue}
|
||||
className="px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-white disabled:opacity-30">
|
||||
className="px-2 py-1 bg-accent-strong hover:bg-accent text-[10px] rounded text-white disabled:opacity-30 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1">
|
||||
Save{globalMode ? " (Global)" : ""}
|
||||
</button>
|
||||
<button type="button" onClick={() => { setShowAdd(false); setNewKey(""); setNewValue(""); }}
|
||||
className="px-2 py-1 bg-surface-card hover:bg-surface-card text-[10px] rounded text-ink-mid">Cancel</button>
|
||||
className="px-2 py-1 bg-surface-card hover:bg-surface-card text-[10px] rounded text-ink-mid focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<button type="button" onClick={() => setShowAdd(true)} className="text-[10px] text-accent hover:text-accent">
|
||||
<button type="button" onClick={() => setShowAdd(true)} className="text-[10px] text-accent hover:text-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1">
|
||||
+ Add {globalMode ? "Global " : ""}Variable
|
||||
</button>
|
||||
)}
|
||||
|
||||
@ -684,6 +684,11 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.guard-dialog__keep-btn:focus-visible {
|
||||
outline: var(--focus-ring);
|
||||
outline-offset: var(--focus-ring-offset);
|
||||
}
|
||||
|
||||
.guard-dialog__discard-btn {
|
||||
background: #2563eb;
|
||||
color: #ffffff;
|
||||
@ -693,6 +698,11 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.guard-dialog__discard-btn:focus-visible {
|
||||
outline: var(--focus-ring);
|
||||
outline-offset: var(--focus-ring-offset);
|
||||
}
|
||||
|
||||
/* ── Settings button (top bar) ─────────────────────── */
|
||||
|
||||
.settings-button {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user