mirror of
https://github.com/webstudio-is/webstudio.git
synced 2026-11-09 05:26:24 +09:00
fix: DNS copy buttons don't trigger/show tooltips like "Copied" (#4160)
## Description closes #4152 ## Steps for reproduction 1. click button 2. expect xyz ## Code Review - [ ] hi @kof, I need you to do - conceptual review (architecture, feature-correctness) - detailed review (read every line) - test it on preview ## Before requesting a review - [ ] made a self-review - [ ] added inline comments where things may be not obvious (the "why", not "what") ## Before merging - [ ] tested locally and on preview environment (preview dev login: 5de6) - [ ] updated [test cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md) document - [ ] added tests - [ ] if any new env variables are added, added them to `.env` file
This commit is contained in:
1 parent
329ddea871
commit
d7af39652a
4 files changed
+87
-58
No files matched your search
@@ -36,6 +36,7 @@ import { $publisherHost } from "~/shared/nano-states";
|
||||
import { extractCname } from "./cname";
|
||||
import { useEffectEvent } from "~/shared/hook-utils/effect-event";
|
||||
import DomainCheckbox from "./domain-checkbox";
|
||||
import { CopyToClipboard } from "~/builder/shared/copy-to-clipboard";
|
||||
|
||||
export type Domain = Project["domainsVirtual"][number];
|
||||
|
||||
@@ -45,21 +46,6 @@ const InputEllipsis = styled(InputField, {
|
||||
},
|
||||
});
|
||||
|
||||
const CopyToClipboard = (props: { text: string }) => {
|
||||
return (
|
||||
<Tooltip content={"Copy to clipboard"}>
|
||||
<NestedInputButton
|
||||
type="button"
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(props.text);
|
||||
}}
|
||||
>
|
||||
<CopyIcon />
|
||||
</NestedInputButton>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
export const getStatus = (projectDomain: Domain) =>
|
||||
projectDomain.verified
|
||||
? (`VERIFIED_${projectDomain.status}` as const)
|
||||
@@ -456,24 +442,48 @@ const DomainItem = (props: {
|
||||
<InputEllipsis
|
||||
readOnly
|
||||
value={cnameRecord.host}
|
||||
suffix={<CopyToClipboard text={cnameRecord.host} />}
|
||||
suffix={
|
||||
<CopyToClipboard text={cnameRecord.host}>
|
||||
<NestedInputButton type="button">
|
||||
<CopyIcon />
|
||||
</NestedInputButton>
|
||||
</CopyToClipboard>
|
||||
}
|
||||
/>
|
||||
<InputEllipsis
|
||||
readOnly
|
||||
value={cnameRecord.value}
|
||||
suffix={<CopyToClipboard text={cnameRecord.value} />}
|
||||
suffix={
|
||||
<CopyToClipboard text={cnameRecord.value}>
|
||||
<NestedInputButton type="button">
|
||||
<CopyIcon />
|
||||
</NestedInputButton>
|
||||
</CopyToClipboard>
|
||||
}
|
||||
/>
|
||||
|
||||
<InputEllipsis readOnly value="TXT" />
|
||||
<InputEllipsis
|
||||
readOnly
|
||||
value={txtRecord.host}
|
||||
suffix={<CopyToClipboard text={txtRecord.host} />}
|
||||
suffix={
|
||||
<CopyToClipboard text={txtRecord.host}>
|
||||
<NestedInputButton type="button">
|
||||
<CopyIcon />
|
||||
</NestedInputButton>
|
||||
</CopyToClipboard>
|
||||
}
|
||||
/>
|
||||
<InputEllipsis
|
||||
readOnly
|
||||
value={txtRecord.value}
|
||||
suffix={<CopyToClipboard text={txtRecord.value} />}
|
||||
suffix={
|
||||
<CopyToClipboard text={txtRecord.value}>
|
||||
<NestedInputButton type="button">
|
||||
<CopyIcon />
|
||||
</NestedInputButton>
|
||||
</CopyToClipboard>
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@ import { isFeatureEnabled } from "@webstudio-is/feature-flags";
|
||||
import type { Templates } from "@webstudio-is/sdk";
|
||||
import { formatDistance } from "date-fns/formatDistance";
|
||||
import DomainCheckbox, { domainToPublishName } from "./domain-checkbox";
|
||||
import { CopyToClipboard } from "~/builder/shared/copy-to-clipboard";
|
||||
|
||||
type ChangeProjectDomainProps = {
|
||||
project: Project;
|
||||
@@ -778,18 +779,11 @@ const ExportContent = (props: { projectId: Project["id"] }) => {
|
||||
value={npxCommand}
|
||||
/>
|
||||
|
||||
<Tooltip content={"Copy to clipboard"}>
|
||||
<Button
|
||||
type="button"
|
||||
color="neutral"
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(npxCommand);
|
||||
}}
|
||||
prefix={<CopyIcon />}
|
||||
>
|
||||
<CopyToClipboard text={npxCommand}>
|
||||
<Button type="button" color="neutral" prefix={<CopyIcon />}>
|
||||
Copy
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</CopyToClipboard>
|
||||
</Flex>
|
||||
</Grid>
|
||||
<Grid columns={1} gap={2}>
|
||||
@@ -820,21 +814,17 @@ const ExportContent = (props: { projectId: Project["id"] }) => {
|
||||
.trimStart()
|
||||
.replace(/ +$/, "")}
|
||||
/>
|
||||
<Tooltip content={"Copy to clipboard"}>
|
||||
|
||||
<CopyToClipboard text={deployTargets[deployTarget].command}>
|
||||
<Button
|
||||
type="button"
|
||||
css={{ flexShrink: 0 }}
|
||||
color="neutral"
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(
|
||||
deployTargets[deployTarget].command
|
||||
);
|
||||
}}
|
||||
prefix={<CopyIcon />}
|
||||
>
|
||||
Copy
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</CopyToClipboard>
|
||||
</Flex>
|
||||
</Grid>
|
||||
<Grid columns={1} gap={1}>
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import { Tooltip } from "@webstudio-is/design-system";
|
||||
import { useState } from "react";
|
||||
|
||||
export const CopyToClipboard = ({
|
||||
text,
|
||||
copyText = "Copy to clipboard",
|
||||
copiedText = "Copied",
|
||||
children,
|
||||
}: {
|
||||
text: string;
|
||||
copyText?: string;
|
||||
copiedText?: string;
|
||||
children: React.ReactNode;
|
||||
}) => {
|
||||
const [isCopied, setIsCopied] = useState(false);
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{ display: "contents" }}
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(text);
|
||||
setIsCopied(true);
|
||||
}}
|
||||
>
|
||||
<Tooltip
|
||||
// Tooltip sometimes receives onOpenChange with isOpen=false immediately after a click.
|
||||
// Changing the key seems like a workaround to address this issue.
|
||||
key={isCopied ? "copied" : "copy"}
|
||||
disableHoverableContent
|
||||
content={isCopied ? copiedText : copyText}
|
||||
open={isCopied === true ? true : undefined}
|
||||
onOpenChange={(isOpen) => {
|
||||
if (isOpen === false) {
|
||||
setIsCopied(false);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -31,6 +31,7 @@ import {
|
||||
} from "@webstudio-is/icons";
|
||||
import { Fragment, useState, type ComponentProps, type ReactNode } from "react";
|
||||
import { useIds } from "../form-utils";
|
||||
import { CopyToClipboard } from "~/builder/shared/copy-to-clipboard";
|
||||
|
||||
const Item = (props: ComponentProps<typeof Flex>) => (
|
||||
<Flex
|
||||
@@ -316,35 +317,21 @@ const SharedLinkItem = ({
|
||||
hasProPlan,
|
||||
}: SharedLinkItemType) => {
|
||||
const [currentName, setCurrentName] = useState(value.name);
|
||||
const [isCopied, setIsCopied] = useState(false);
|
||||
|
||||
return (
|
||||
<Box className={itemStyle()}>
|
||||
<Label css={{ flexGrow: 1 }}>{currentName}</Label>
|
||||
<Tooltip
|
||||
content={isCopied ? "Copied" : "Copy link"}
|
||||
open={isCopied === true ? true : undefined}
|
||||
onOpenChange={(isOpen) => {
|
||||
if (isOpen === false) {
|
||||
setIsCopied(false);
|
||||
}
|
||||
}}
|
||||
<CopyToClipboard
|
||||
text={builderUrl({
|
||||
authToken: value.token,
|
||||
mode: value.relation === "viewers" ? "preview" : "edit",
|
||||
})}
|
||||
copyText="Copy link"
|
||||
>
|
||||
<IconButton
|
||||
aria-label="Copy link"
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(
|
||||
builderUrl({
|
||||
authToken: value.token,
|
||||
mode: value.relation === "viewers" ? "preview" : "edit",
|
||||
})
|
||||
);
|
||||
setIsCopied(true);
|
||||
}}
|
||||
>
|
||||
<IconButton aria-label="Copy link">
|
||||
<CopyIcon aria-hidden />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</CopyToClipboard>
|
||||
<Menu
|
||||
name={currentName}
|
||||
value={value}
|
||||
|
||||
Reference in new issue
Block a user