fix(settings): fix Tavily key label cursor and reunite the apply link - #3821
Conversation
Two UI papercuts in Settings → Web search's Tavily key field:
- The key label ("Tavily 密钥") showed a hand cursor on hover but
forwards no click. Astryx FieldLabel renders an InputGroup label as a
bare <span class="astryx-field-label"> (isGroupLabel), which carries
StyleX cursor:pointer; native-cursor.css only neutralized real <label>
elements, so the span slipped through. Match the stable themeProps
class so group-label spans get cursor:default like every other field
label (app-wide — the same shared PasswordInput backs bot tokens,
provider keys, and the proxy password).
- "申请地址:" rendered above the input as the field description while the
tavily.com link rendered below it, so the key input split the label
from its URL. Fold the link into the description as a ReactNode so
"申请地址:tavily.com" reads as one unit above the input — a pattern
Astryx FieldLabel supports (its click forwarding skips nested
interactive content); only InputGroup/Field under-declare the prop as
string, papered over by one cast in PasswordInput.
Generated-by: Claude Code (Opus 4.8)
4df006b to
2310d75
Compare
Astro-Han
left a comment
There was a problem hiding this comment.
Approving.
Both diagnoses check out against the installed Astryx. FieldLabel.js:120 is const LabelElement = isGroupLabel ? 'span' : 'label', which is exactly why the label selector missed it, and .astryx-field-label is a naming.ts externally-observable class — matching it is stable and consistent with the existing .astryx-lightbox / .astryx-empty-state rules in this repo.
The nested link is safer than your note suggests: forwardsDescriptionClick = !isGroupLabel && inputID != null, so an InputGroup description forwards no clicks at all. The "skips nested interactive content" path is not even reached here.
Two things worth pushing upstream so these become deletable rather than permanent:
FieldLabeltypesdescriptionasReactNodewhileInputGroupandFieldtype it asstring. That inconsistency is what forces the cast here.- A group label that forwards no click arguably should not carry
cursor: pointer— fixing that removes the need for the CSS rule in every consumer, not just ours.
Astryx turns this kind of thing around quickly. Not blocking either way.
AI use: Claude Code assisted with source and issue investigation; the analysis and conclusions are my own.
简体中文
通过。
两处诊断对照已安装的 Astryx 都成立。FieldLabel.js:120 是 const LabelElement = isGroupLabel ? 'span' : 'label',这正是 label 选择器漏掉它的原因;而 .astryx-field-label 是 naming.ts 声明的对外可见类,匹配它是稳定的,也与本仓库既有的 .astryx-lightbox、.astryx-empty-state 规则一致。
嵌套链接比你注释里说的更安全:forwardsDescriptionClick = !isGroupLabel && inputID != null,所以 InputGroup 的 description 根本不转发点击,「跳过嵌套交互内容」那条路径在这里都不会走到。
有两件事值得推到上游,让这些变通可以被删掉而不是长期留着:
FieldLabel把description声明为ReactNode,而InputGroup和Field声明为string。正是这个不一致逼出了这里的类型断言。- 一个不转发点击的 group label 本就不该带
cursor: pointer;上游修掉之后,每个使用方都不再需要这条 CSS 规则,而不只是我们。
Astryx 对这类改动接得很快。两条都不阻塞。
Summary
Two small UI papercuts in Settings → Web search's Tavily key field:
FieldLabelrenders anInputGrouplabel as a bare<span class="astryx-field-label">(isGroupLabel), which carries StyleXcursor: pointer;native-cursor.css(the single owner of the "hand cursor is for links only" convention) only neutralized real<label>elements, so the span slipped through. Match the stablethemePropsclass (.astryx-field-label) so group-label spans getcursor: defaultlike every other field label. This is app-wide by design — the same sharedPasswordInputbacks bot tokens, provider API keys, and the proxy password.tavily.comlink rendered on its own line below the input, so the key input split the label from its URL. Fold the link into the description as aReactNodeso "申请地址:tavily.com" reads as one unit above the input — a pattern AstryxFieldLabelsupports (its click forwarding skips nested interactive content); onlyInputGroup/Fieldunder-declare thedescriptionprop asstring, papered over by one cast inPasswordInput.Fixes #3820
Verification
tsc -p tsconfig.renderer.json --noEmit— passesbiome linton the changed files — passesBefore / after (Tavily key field):
before
after

Review focus
The cursor fix in
native-cursor.cssis intentionally app-wide: it neutralizes the hand cursor on everyInputGroupgroup-label span, not just this page.AI use
Select exactly one:
Tool(s) and scope: Claude Code (Opus 4.8) — investigated the root cause, wrote the code changes, and drafted this PR. Reviewed by the author. The squash commit carries a
Generated-bytrailer.Checklist
Does this PR entail a change in behavior?