ui: default TextField copy affordance to clipboard (#12714)

This commit is contained in:
Kit Langton
2026-02-08 12:37:59 -05:00
committed by GitHub
parent 80c1c59ed3
commit 27c8a08144
2 changed files with 27 additions and 11 deletions

View File

@@ -420,7 +420,14 @@ export function SessionHeader() {
}
>
<div class="flex flex-col gap-2">
<TextField value={shareUrl() ?? ""} readOnly copyable tabIndex={-1} class="w-full" />
<TextField
value={shareUrl() ?? ""}
readOnly
copyable
copyKind="link"
tabIndex={-1}
class="w-full"
/>
<div class="grid grid-cols-2 gap-2">
<Button
size="large"

View File

@@ -6,7 +6,8 @@ import { IconButton } from "./icon-button"
import { Tooltip } from "./tooltip"
export interface TextFieldProps
extends ComponentProps<typeof Kobalte.Input>,
extends
ComponentProps<typeof Kobalte.Input>,
Partial<
Pick<
ComponentProps<typeof Kobalte>,
@@ -27,6 +28,7 @@ export interface TextFieldProps
error?: string
variant?: "normal" | "ghost"
copyable?: boolean
copyKind?: "clipboard" | "link"
multiline?: boolean
}
@@ -49,10 +51,23 @@ export function TextField(props: TextFieldProps) {
"error",
"variant",
"copyable",
"copyKind",
"multiline",
])
const [copied, setCopied] = createSignal(false)
const label = () => {
if (copied()) return i18n.t("ui.textField.copied")
if (local.copyKind === "link") return i18n.t("ui.textField.copyLink")
return i18n.t("ui.textField.copyToClipboard")
}
const icon = () => {
if (copied()) return "check"
if (local.copyKind === "link") return "link"
return "copy"
}
async function handleCopy() {
const value = local.value ?? local.defaultValue ?? ""
await navigator.clipboard.writeText(value)
@@ -92,21 +107,15 @@ export function TextField(props: TextFieldProps) {
<Kobalte.TextArea {...others} autoResize data-slot="input-input" class={local.class} />
</Show>
<Show when={local.copyable}>
<Tooltip
value={copied() ? i18n.t("ui.textField.copied") : i18n.t("ui.textField.copyLink")}
placement="top"
gutter={4}
forceOpen={copied()}
skipDelayDuration={0}
>
<Tooltip value={label()} placement="top" gutter={4} forceOpen={copied()} skipDelayDuration={0}>
<IconButton
type="button"
icon={copied() ? "check" : "link"}
icon={icon()}
variant="ghost"
onClick={handleCopy}
tabIndex={-1}
data-slot="input-copy-button"
aria-label={copied() ? i18n.t("ui.textField.copied") : i18n.t("ui.textField.copyLink")}
aria-label={label()}
/>
</Tooltip>
</Show>