summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorKit Langton <[email protected]>2026-02-08 12:37:59 -0500
committerGitHub <[email protected]>2026-02-08 11:37:59 -0600
commit27c8a0814465fbcbb61fbe6b1dd149675d7046e8 (patch)
tree81981485260e7e86ded054896255969dc59fa8c7
parent80c1c59ed34cd19119bbb53f40e5214cae35ad29 (diff)
downloadopencode-27c8a0814465fbcbb61fbe6b1dd149675d7046e8.tar.gz
opencode-27c8a0814465fbcbb61fbe6b1dd149675d7046e8.zip
ui: default TextField copy affordance to clipboard (#12714)
-rw-r--r--packages/app/src/components/session/session-header.tsx9
-rw-r--r--packages/ui/src/components/text-field.tsx29
2 files changed, 27 insertions, 11 deletions
diff --git a/packages/app/src/components/session/session-header.tsx b/packages/app/src/components/session/session-header.tsx
index 7eaafc854..fcba47004 100644
--- a/packages/app/src/components/session/session-header.tsx
+++ b/packages/app/src/components/session/session-header.tsx
@@ -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"
diff --git a/packages/ui/src/components/text-field.tsx b/packages/ui/src/components/text-field.tsx
index 56e849664..1e9bcadd2 100644
--- a/packages/ui/src/components/text-field.tsx
+++ b/packages/ui/src/components/text-field.tsx
@@ -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>