Răsfoiți Sursa

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

Kit Langton 2 săptămâni în urmă
părinte
comite
27c8a08144

+ 8 - 1
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"

+ 19 - 10
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>