ui: default TextField copy affordance to clipboard (#12714)
This commit is contained in:
@@ -420,7 +420,14 @@ export function SessionHeader() {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div class="flex flex-col gap-2">
|
<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">
|
<div class="grid grid-cols-2 gap-2">
|
||||||
<Button
|
<Button
|
||||||
size="large"
|
size="large"
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ import { IconButton } from "./icon-button"
|
|||||||
import { Tooltip } from "./tooltip"
|
import { Tooltip } from "./tooltip"
|
||||||
|
|
||||||
export interface TextFieldProps
|
export interface TextFieldProps
|
||||||
extends ComponentProps<typeof Kobalte.Input>,
|
extends
|
||||||
|
ComponentProps<typeof Kobalte.Input>,
|
||||||
Partial<
|
Partial<
|
||||||
Pick<
|
Pick<
|
||||||
ComponentProps<typeof Kobalte>,
|
ComponentProps<typeof Kobalte>,
|
||||||
@@ -27,6 +28,7 @@ export interface TextFieldProps
|
|||||||
error?: string
|
error?: string
|
||||||
variant?: "normal" | "ghost"
|
variant?: "normal" | "ghost"
|
||||||
copyable?: boolean
|
copyable?: boolean
|
||||||
|
copyKind?: "clipboard" | "link"
|
||||||
multiline?: boolean
|
multiline?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,10 +51,23 @@ export function TextField(props: TextFieldProps) {
|
|||||||
"error",
|
"error",
|
||||||
"variant",
|
"variant",
|
||||||
"copyable",
|
"copyable",
|
||||||
|
"copyKind",
|
||||||
"multiline",
|
"multiline",
|
||||||
])
|
])
|
||||||
const [copied, setCopied] = createSignal(false)
|
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() {
|
async function handleCopy() {
|
||||||
const value = local.value ?? local.defaultValue ?? ""
|
const value = local.value ?? local.defaultValue ?? ""
|
||||||
await navigator.clipboard.writeText(value)
|
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} />
|
<Kobalte.TextArea {...others} autoResize data-slot="input-input" class={local.class} />
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={local.copyable}>
|
<Show when={local.copyable}>
|
||||||
<Tooltip
|
<Tooltip value={label()} placement="top" gutter={4} forceOpen={copied()} skipDelayDuration={0}>
|
||||||
value={copied() ? i18n.t("ui.textField.copied") : i18n.t("ui.textField.copyLink")}
|
|
||||||
placement="top"
|
|
||||||
gutter={4}
|
|
||||||
forceOpen={copied()}
|
|
||||||
skipDelayDuration={0}
|
|
||||||
>
|
|
||||||
<IconButton
|
<IconButton
|
||||||
type="button"
|
type="button"
|
||||||
icon={copied() ? "check" : "link"}
|
icon={icon()}
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
onClick={handleCopy}
|
onClick={handleCopy}
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
data-slot="input-copy-button"
|
data-slot="input-copy-button"
|
||||||
aria-label={copied() ? i18n.t("ui.textField.copied") : i18n.t("ui.textField.copyLink")}
|
aria-label={label()}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Show>
|
</Show>
|
||||||
|
|||||||
Reference in New Issue
Block a user