A design system in a box. hip-ui.tngl.io/docs/introduction
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

factor out copy to clipboard button

+215 -11
+79
apps/docs/src/components/copy-to-clipboard-button/index.tsx
··· 1 + "use client"; 2 + 3 + import * as stylex from "@stylexjs/stylex"; 4 + import { Copy } from "lucide-react"; 5 + import { useRef, useState } from "react"; 6 + 7 + import { IconButton } from "../icon-button"; 8 + import { StyleXComponentProps } from "../theme/types"; 9 + 10 + const defaultIcon = <Copy />; 11 + 12 + /** 13 + * Props for the CopyToClipboardButton component. 14 + */ 15 + export interface CopyToClipboardButtonProps extends StyleXComponentProps<{}> { 16 + /** 17 + * The text to copy to the clipboard when the button is clicked. 18 + */ 19 + text: string; 20 + /** 21 + * Optional icon to display. Defaults to a Copy icon. 22 + */ 23 + icon?: React.ReactNode; 24 + } 25 + 26 + /** 27 + * A button component that copies text to the clipboard when clicked. 28 + * Displays a tooltip that changes to "Copied ✓" after copying. 29 + */ 30 + export const CopyToClipboardButton = ({ 31 + style, 32 + text, 33 + icon = defaultIcon, 34 + }: CopyToClipboardButtonProps) => { 35 + const [tooltipText, setTooltipText] = useState("Copy to clipboard"); 36 + const [tooltipOpen, setTooltipOpen] = useState(false); 37 + const timeoutRef = useRef<NodeJS.Timeout | null>(null); 38 + const changeTextTimeoutRef = useRef<NodeJS.Timeout | null>(null); 39 + const handleCopy = () => { 40 + if (changeTextTimeoutRef.current) { 41 + clearTimeout(changeTextTimeoutRef.current); 42 + changeTextTimeoutRef.current = null; 43 + } 44 + if (timeoutRef.current) { 45 + clearTimeout(timeoutRef.current); 46 + timeoutRef.current = null; 47 + } 48 + void navigator.clipboard.writeText(text); 49 + setTooltipText("Copied ✓"); 50 + setTooltipOpen(true); 51 + timeoutRef.current = setTimeout(() => { 52 + timeoutRef.current = null; 53 + 54 + setTooltipOpen(false); 55 + 56 + changeTextTimeoutRef.current = setTimeout(() => { 57 + setTooltipText("Copy to clipboard"); 58 + changeTextTimeoutRef.current = null; 59 + }, 200); 60 + }, 2000); 61 + }; 62 + 63 + return ( 64 + <IconButton 65 + label={tooltipText} 66 + tooltipOpen={tooltipOpen} 67 + onTooltipOpenChange={(isOpen) => 68 + !timeoutRef.current && setTooltipOpen(isOpen) 69 + } 70 + variant="tertiary" 71 + style={style} 72 + size="sm" 73 + onClick={handleCopy} 74 + > 75 + {icon} 76 + </IconButton> 77 + ); 78 + }; 79 +
+38
apps/docs/src/docs/components/buttons/copy-to-clipboard-button.mdx
··· 1 + --- 2 + title: CopyToClipboardButton 3 + description: A button component that copies text to the clipboard when clicked, with visual feedback via a tooltip. 4 + --- 5 + 6 + import { PropDocs } from '../../../lib/PropDocs' 7 + import { Example } from '../../../lib/Example' 8 + import { Basic } from '../../../examples/copy-to-clipboard-button/basic' 9 + import { CustomIcon } from '../../../examples/copy-to-clipboard-button/custom-icon' 10 + 11 + <Example src={Basic} /> 12 + 13 + ## Installation 14 + 15 + Run the following command to add the copy to clipboard button component to your project. 16 + 17 + ```bash 18 + pnpm hip install copy-to-clipboard-button 19 + ``` 20 + 21 + ## Props 22 + 23 + <PropDocs components={["CopyToClipboardButton"]} /> 24 + 25 + ## Features 26 + 27 + ### Custom Icon 28 + 29 + You can customize the icon displayed on the button. 30 + 31 + <Example src={CustomIcon} /> 32 + 33 + ## Related Components 34 + 35 + - [IconButton](/docs/components/buttons/icon-button) - The base icon button component used by CopyToClipboardButton 36 + - [Button](/docs/components/buttons/button) - For buttons with text and icons 37 + - [Tooltip](/docs/components/overlays/tooltip) - For providing context on buttons 38 +
+26
apps/docs/src/examples/copy-to-clipboard-button/basic.tsx
··· 1 + import * as stylex from "@stylexjs/stylex"; 2 + 3 + import { CopyToClipboardButton } from "@/components/copy-to-clipboard-button"; 4 + import { Flex } from "@/components/flex"; 5 + 6 + import { spacing } from "../../components/theme/spacing.stylex"; 7 + 8 + const styles = stylex.create({ 9 + codeBlock: { 10 + backgroundColor: "rgba(0, 0, 0, 0.05)", 11 + borderRadius: 4, 12 + fontFamily: "monospace", 13 + padding: spacing["2"], 14 + }, 15 + }); 16 + 17 + export function Basic() { 18 + const codeToCopy = "npm install hip-ui"; 19 + 20 + return ( 21 + <Flex gap="1" align="center"> 22 + <div {...stylex.props(styles.codeBlock)}>{codeToCopy}</div> 23 + <CopyToClipboardButton text={codeToCopy} /> 24 + </Flex> 25 + ); 26 + }
+27
apps/docs/src/examples/copy-to-clipboard-button/custom-icon.tsx
··· 1 + import { Check } from "lucide-react"; 2 + 3 + import { CopyToClipboardButton } from "@/components/copy-to-clipboard-button"; 4 + import { Flex } from "@/components/flex"; 5 + 6 + import { spacing } from "../../components/theme/spacing.stylex"; 7 + import * as stylex from "@stylexjs/stylex"; 8 + 9 + const styles = stylex.create({ 10 + codeBlock: { 11 + backgroundColor: "rgba(0, 0, 0, 0.05)", 12 + borderRadius: 4, 13 + fontFamily: "monospace", 14 + padding: spacing["2"], 15 + }, 16 + }); 17 + 18 + export function CustomIcon() { 19 + const codeToCopy = "pnpm hip install copy-to-clipboard-button"; 20 + 21 + return ( 22 + <Flex gap="1" align="center"> 23 + <div {...stylex.props(styles.codeBlock)}>{codeToCopy}</div> 24 + <CopyToClipboardButton text={codeToCopy} icon={<Check />} /> 25 + </Flex> 26 + ); 27 + }
+27 -9
apps/docs/src/lib/CopyToClipboardButton.tsx packages/hip-ui/src/components/copy-to-clipboard-button/index.tsx
··· 1 + "use client"; 2 + 1 3 import * as stylex from "@stylexjs/stylex"; 2 4 import { Copy } from "lucide-react"; 3 5 import { useRef, useState } from "react"; 4 6 5 - import { IconButton } from "@/components/icon-button"; 7 + import { IconButton } from "../icon-button"; 8 + import { StyleXComponentProps } from "../theme/types"; 6 9 7 10 const defaultIcon = <Copy />; 8 11 9 - export function CopyToClipboardButton({ 12 + /** 13 + * Props for the CopyToClipboardButton component. 14 + */ 15 + export interface CopyToClipboardButtonProps extends StyleXComponentProps<{}> { 16 + /** 17 + * The text to copy to the clipboard when the button is clicked. 18 + */ 19 + text: string; 20 + /** 21 + * Optional icon to display. Defaults to a Copy icon. 22 + */ 23 + icon?: React.ReactNode; 24 + } 25 + 26 + /** 27 + * A button component that copies text to the clipboard when clicked. 28 + * Displays a tooltip that changes to "Copied ✓" after copying. 29 + */ 30 + export const CopyToClipboardButton = ({ 10 31 style, 11 32 text, 12 33 icon = defaultIcon, 13 - }: { 14 - style?: stylex.StyleXStyles; 15 - text: string; 16 - icon?: React.ReactNode; 17 - }) { 34 + }: CopyToClipboardButtonProps) => { 18 35 const [tooltipText, setTooltipText] = useState("Copy to clipboard"); 19 36 const [tooltipOpen, setTooltipOpen] = useState(false); 20 37 const timeoutRef = useRef<NodeJS.Timeout | null>(null); ··· 51 68 !timeoutRef.current && setTooltipOpen(isOpen) 52 69 } 53 70 variant="tertiary" 54 - style={[style]} 71 + style={style} 55 72 size="sm" 56 73 onClick={handleCopy} 57 74 > 58 75 {icon} 59 76 </IconButton> 60 77 ); 61 - } 78 + }; 79 +
+1 -1
apps/docs/src/lib/Example.tsx
··· 8 8 import { radius } from "../components/theme/radius.stylex"; 9 9 import { uiColor } from "../components/theme/color.stylex"; 10 10 import { spacing } from "../components/theme/spacing.stylex"; 11 - import { CopyToClipboardButton } from "./CopyToClipboardButton"; 11 + import { CopyToClipboardButton } from "@/components/copy-to-clipboard-button"; 12 12 13 13 const styles = stylex.create({ 14 14 card: {
+1 -1
apps/docs/src/routes/docs.$.tsx
··· 47 47 } from "@/components/typography"; 48 48 import { Text } from "@/components/typography/text"; 49 49 import { TableOfContents } from "@/components/table-of-contents"; 50 - import { CopyToClipboardButton } from "@/lib/CopyToClipboardButton"; 50 + import { CopyToClipboardButton } from "@/components/copy-to-clipboard-button"; 51 51 52 52 import { animationDuration } from "../components/theme/animations.stylex"; 53 53 import { radius } from "../components/theme/radius.stylex";
+2
packages/hip-ui/src/cli/install.tsx
··· 29 29 import { comboboxConfig } from "../components/combobox/combobox-config.js"; 30 30 import { commandMenuConfig } from "../components/command-menu/command-menu-config.js"; 31 31 import { contentConfig } from "../components/content/content-config.js"; 32 + import { copyToClipboardButtonConfig } from "../components/copy-to-clipboard-button/copy-to-clipboard-button-config.js"; 32 33 import { contextMenuConfig } from "../components/context-menu/context-menu-config.js"; 33 34 import { dateFieldConfig } from "../components/date-field/date-field-config.js"; 34 35 import { datePickerConfig } from "../components/date-picker/date-picker-config.js"; ··· 97 98 flexConfig, 98 99 typographyConfig, 99 100 contentConfig, 101 + copyToClipboardButtonConfig, 100 102 tooltipConfig, 101 103 iconButtonConfig, 102 104 popoverConfig,
+14
packages/hip-ui/src/components/copy-to-clipboard-button/copy-to-clipboard-button-config.ts
··· 1 + import { ComponentConfig } from "../../types"; 2 + 3 + export const copyToClipboardButtonConfig: ComponentConfig = { 4 + name: "copy-to-clipboard-button", 5 + filepath: "./index.tsx", 6 + hipDependencies: [ 7 + "../icon-button/index.tsx", 8 + "../theme/types.ts", 9 + ], 10 + dependencies: { 11 + "lucide-react": "^0.545.0", 12 + }, 13 + }; 14 +