wrap chain source, rescan and wallet-rename fields in real forms
three input sites lived in a div instead of a form, so pressing enter did nothing and the button was the only way in. chain source url, rescan search depth, and the inline wallet-rename field all get a <form onSubmit>, with every non-submit button in each marked type="button" (the rescan card's reset button was previously untyped, which would have submitted the form once wrapped). CoinsView.tsx has no text inputs (checkbox + buttons only) and SeedPhraseInput.tsx deliberately hijacks enter to advance between word boxes rather than submit, so both are left alone. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -80,7 +80,9 @@ export const ChainSourceCard = () => {
|
|||||||
const busy = save.isPending || forget.isPending;
|
const busy = save.isPending || forget.isPending;
|
||||||
const meta = KINDS[kind];
|
const meta = KINDS[kind];
|
||||||
|
|
||||||
const submit = async () => {
|
const submit = async (ev?: React.FormEvent) => {
|
||||||
|
ev?.preventDefault();
|
||||||
|
if (!trimmed || !dirty || busy) return;
|
||||||
setError(null);
|
setError(null);
|
||||||
setHeight(null);
|
setHeight(null);
|
||||||
try {
|
try {
|
||||||
@@ -111,7 +113,8 @@ export const ChainSourceCard = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="max-w-2xl rounded-xl border border-border p-4">
|
// Typing a URL and pressing return is what anyone does; a div full of inputs swallows it silently.
|
||||||
|
<form onSubmit={submit} className="max-w-2xl rounded-xl border border-border p-4">
|
||||||
<h3 className="mb-2 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground">Chain source</h3>
|
<h3 className="mb-2 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground">Chain source</h3>
|
||||||
<p className="mb-3 text-xs text-muted-foreground">
|
<p className="mb-3 text-xs text-muted-foreground">
|
||||||
Where on-chain wallets read balances and history. It sees every address this wallet asks about, so your own node
|
Where on-chain wallets read balances and history. It sees every address this wallet asks about, so your own node
|
||||||
@@ -144,9 +147,6 @@ export const ChainSourceCard = () => {
|
|||||||
<Input
|
<Input
|
||||||
value={url}
|
value={url}
|
||||||
onChange={(ev) => setUrl(ev.target.value)}
|
onChange={(ev) => setUrl(ev.target.value)}
|
||||||
onKeyDown={(ev) => {
|
|
||||||
if (ev.key === 'Enter' && trimmed && dirty && !busy) void submit();
|
|
||||||
}}
|
|
||||||
placeholder={meta.placeholder}
|
placeholder={meta.placeholder}
|
||||||
disabled={isLoading || busy}
|
disabled={isLoading || busy}
|
||||||
className="h-8 font-mono text-xs"
|
className="h-8 font-mono text-xs"
|
||||||
@@ -155,12 +155,12 @@ export const ChainSourceCard = () => {
|
|||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
/>
|
/>
|
||||||
<div className="flex shrink-0 gap-2">
|
<div className="flex shrink-0 gap-2">
|
||||||
<Button size="sm" onClick={submit} disabled={!trimmed || !dirty || busy}>
|
<Button type="submit" size="sm" disabled={!trimmed || !dirty || busy}>
|
||||||
{save.isPending ? <Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin" /> : null}
|
{save.isPending ? <Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin" /> : null}
|
||||||
{save.isPending ? 'Connecting…' : 'Save & connect'}
|
{save.isPending ? 'Connecting…' : 'Save & connect'}
|
||||||
</Button>
|
</Button>
|
||||||
{data?.custom && (
|
{data?.custom && (
|
||||||
<Button size="sm" variant="outline" onClick={reset} disabled={busy} title="Back to the public default">
|
<Button type="button" size="sm" variant="outline" onClick={reset} disabled={busy} title="Back to the public default">
|
||||||
<RotateCcw className="mr-1.5 h-3.5 w-3.5" />
|
<RotateCcw className="mr-1.5 h-3.5 w-3.5" />
|
||||||
Reset
|
Reset
|
||||||
</Button>
|
</Button>
|
||||||
@@ -188,6 +188,6 @@ export const ChainSourceCard = () => {
|
|||||||
: `Using the built-in default (${data?.defaultUrl ?? '—'}), which rate-limits and can see every address you look up.`}{' '}
|
: `Using the built-in default (${data?.defaultUrl ?? '—'}), which rate-limits and can see every address you look up.`}{' '}
|
||||||
{meta.hint}
|
{meta.hint}
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</form>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
+9
-3
@@ -37,8 +37,14 @@ export const RescanCard = ({ walletId }: RescanCardProps) => {
|
|||||||
const parsed = Number(gapLimit);
|
const parsed = Number(gapLimit);
|
||||||
const depth = gapLimit.trim() && Number.isInteger(parsed) && parsed > 0 ? parsed : null;
|
const depth = gapLimit.trim() && Number.isInteger(parsed) && parsed > 0 ? parsed : null;
|
||||||
|
|
||||||
|
const submit = (ev?: React.FormEvent) => {
|
||||||
|
ev?.preventDefault();
|
||||||
|
if (running || rescan.isPending) return;
|
||||||
|
rescan.mutate(depth ? { gapLimit: depth } : {});
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="max-w-2xl rounded-xl border border-border p-4">
|
<form onSubmit={submit} className="max-w-2xl rounded-xl border border-border p-4">
|
||||||
<h3 className="mb-2 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground">
|
<h3 className="mb-2 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground">
|
||||||
Find missing coins
|
Find missing coins
|
||||||
</h3>
|
</h3>
|
||||||
@@ -50,9 +56,9 @@ export const RescanCard = ({ walletId }: RescanCardProps) => {
|
|||||||
|
|
||||||
<div className="flex flex-wrap items-center gap-2">
|
<div className="flex flex-wrap items-center gap-2">
|
||||||
<Button
|
<Button
|
||||||
|
type="submit"
|
||||||
size="sm"
|
size="sm"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
onClick={() => rescan.mutate(depth ? { gapLimit: depth } : {})}
|
|
||||||
disabled={running || rescan.isPending}
|
disabled={running || rescan.isPending}
|
||||||
>
|
>
|
||||||
{running || rescan.isPending ? (
|
{running || rescan.isPending ? (
|
||||||
@@ -82,7 +88,7 @@ export const RescanCard = ({ walletId }: RescanCardProps) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{state && <Status state={state} />}
|
{state && <Status state={state} />}
|
||||||
</section>
|
</form>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -206,7 +206,8 @@ const WalletNameField = ({ wallet, onSave, isPending }: WalletNameFieldProps) =>
|
|||||||
const trimmed = draft.trim();
|
const trimmed = draft.trim();
|
||||||
const dirty = trimmed !== wallet.name;
|
const dirty = trimmed !== wallet.name;
|
||||||
|
|
||||||
const commit = async () => {
|
const commit = async (ev?: React.FormEvent) => {
|
||||||
|
ev?.preventDefault();
|
||||||
if (!trimmed || !dirty) {
|
if (!trimmed || !dirty) {
|
||||||
setDraft(wallet.name);
|
setDraft(wallet.name);
|
||||||
setEditing(false);
|
setEditing(false);
|
||||||
@@ -242,7 +243,7 @@ const WalletNameField = ({ wallet, onSave, isPending }: WalletNameFieldProps) =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex min-w-0 items-center gap-1.5">
|
<form onSubmit={commit} className="flex min-w-0 items-center gap-1.5">
|
||||||
<Input
|
<Input
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
autoFocus
|
autoFocus
|
||||||
@@ -251,7 +252,6 @@ const WalletNameField = ({ wallet, onSave, isPending }: WalletNameFieldProps) =>
|
|||||||
disabled={isPending}
|
disabled={isPending}
|
||||||
onChange={(ev) => setDraft(ev.target.value)}
|
onChange={(ev) => setDraft(ev.target.value)}
|
||||||
onKeyDown={(ev) => {
|
onKeyDown={(ev) => {
|
||||||
if (ev.key === 'Enter') void commit();
|
|
||||||
if (ev.key === 'Escape') cancel();
|
if (ev.key === 'Escape') cancel();
|
||||||
}}
|
}}
|
||||||
className="h-7 max-w-56 text-sm font-semibold"
|
className="h-7 max-w-56 text-sm font-semibold"
|
||||||
@@ -259,13 +259,13 @@ const WalletNameField = ({ wallet, onSave, isPending }: WalletNameFieldProps) =>
|
|||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
/>
|
/>
|
||||||
<Button size="icon" variant="ghost" className="h-7 w-7" onClick={commit} disabled={isPending || !trimmed}>
|
<Button type="submit" size="icon" variant="ghost" className="h-7 w-7" disabled={isPending || !trimmed}>
|
||||||
<Check className="h-3.5 w-3.5" />
|
<Check className="h-3.5 w-3.5" />
|
||||||
</Button>
|
</Button>
|
||||||
<Button size="icon" variant="ghost" className="h-7 w-7" onClick={cancel} disabled={isPending}>
|
<Button type="button" size="icon" variant="ghost" className="h-7 w-7" onClick={cancel} disabled={isPending}>
|
||||||
<X className="h-3.5 w-3.5" />
|
<X className="h-3.5 w-3.5" />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</form>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user