Skip to content

Commit

Permalink
Merge pull request #5 from matheusrocha89/custom-icons
Browse files Browse the repository at this point in the history
Custom icons
  • Loading branch information
matheusrocha89 authored Jan 15, 2025
2 parents fea4cf1 + d4486a0 commit bd041e7
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 13 deletions.
36 changes: 25 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ https://github.com/user-attachments/assets/a5882c1a-441e-4c6a-acb4-f0b611aaca58
- [Without Icons](#without-icons)
- [With Custom Styling](#with-custom-styling)
- [With Copy Feedback](#with-copy-feedback)
- [With Custom Icons](#with-custom-icons)
- [Installation](#installation)
- [Usage](#usage)
- [Props](#props)
Expand Down Expand Up @@ -73,6 +74,17 @@ const [copied, setCopied] = useState(false);
/>;
```

### With Custom Icons

> Note: You can use icons from any package. This example uses Feather icons (`react-icons/fi`),
> while the default icons come from Font Awesome (`react-icons/fa6`).
```jsx
import { FiCopy, FiCheck } from "react-icons/fi";

<CopyText text="Copy this text" copyIcon={FiCopy} copiedIcon={FiCheck} />;
```

A simple and customizable React component for copying text to the clipboard.

## Installation
Expand Down Expand Up @@ -109,17 +121,19 @@ function App() {
## Props
| Prop | Type | Default | Description |
| ------------------- | -------- | ---------- | --------------------------------------------- |
| `text` | string | (required) | The text to be copied |
| `copied` | boolean | `false` | Indicates if the text has been copied |
| `onClick` | function | `() => {}` | Callback function called after text is copied |
| `buttonClassName` | string | - | Additional CSS class for the button |
| `className` | string | - | Additional CSS class for the wrapper |
| `textClassName` | string | - | Additional CSS class for the text element |
| `showIcon` | boolean | `true` | Whether to show copy/copied icons |
| `copyButtonLabel` | string | "Copy" | Label for the copy button |
| `copiedButtonLabel` | string | "Copied" | Label for the copied state |
| Prop | Type | Default | Description |
| ------------------- | ----------------- | -------------- | --------------------------------------------- |
| `text` | string | (required) | The text to be copied |
| `copied` | boolean | `false` | Indicates if the text has been copied |
| `onClick` | function | `() => {}` | Callback function called after text is copied |
| `buttonClassName` | string | - | Additional CSS class for the button |
| `className` | string | - | Additional CSS class for the wrapper |
| `textClassName` | string | - | Additional CSS class for the text element |
| `showIcon` | boolean | `true` | Whether to show copy/copied icons |
| `copyButtonLabel` | string | "Copy" | Label for the copy button |
| `copiedButtonLabel` | string | "Copied" | Label for the copied state |
| `copyIcon` | React.ElementType | FaRegClipboard | Custom icon for copy state |
| `copiedIcon` | React.ElementType | FaCheck | Custom icon for copied state |
## Features
Expand Down
30 changes: 30 additions & 0 deletions src/CopyText/CopyText.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,36 @@ describe("CopyText", () => {
expect(screen.getByText("Hello")).toHaveClass("custom-text");
});

it("should render custom copyIcon when provided", () => {
const CustomIcon = () => <span data-testid="custom-copy-icon">Custom</span>;
render(<CopyText text="Hello" copyIcon={CustomIcon} />);
expect(screen.getByTestId("custom-copy-icon")).toBeInTheDocument();
expect(screen.getByText("Custom")).toBeInTheDocument();
});

it("should render custom copiedIcon when provided and copied is true", () => {
const CustomIcon = () => (
<span data-testid="custom-copied-icon">Custom</span>
);
render(<CopyText text="Hello" copiedIcon={CustomIcon} copied />);
expect(screen.getByTestId("custom-copied-icon")).toBeInTheDocument();
expect(screen.getByText("Custom")).toBeInTheDocument();
});

it("should not render custom icons when showIcon is false", () => {
const CustomIcon = () => <span data-testid="custom-icon">Custom</span>;
render(
<CopyText
text="Hello"
copyIcon={CustomIcon}
copiedIcon={CustomIcon}
showIcon={false}
/>
);
expect(screen.queryByTestId("custom-icon")).not.toBeInTheDocument();
expect(screen.queryByText("Custom")).not.toBeInTheDocument();
});

describe("behavior", () => {
it("should copy the text when the button is clicked", async () => {
render(<CopyText text="Let's copy text" />);
Expand Down
10 changes: 8 additions & 2 deletions src/CopyText/CopyText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ type CopyTextProps = {
onClick?: () => void;
text: string;
textClassName?: string;
copyIcon?: React.ElementType;
copiedIcon?: React.ElementType;
};

const CopyText = ({
Expand All @@ -25,24 +27,28 @@ const CopyText = ({
copiedButtonLabel = "Copied",
copyButtonLabel = "Copy",
textClassName,
copyIcon,
copiedIcon,
}: CopyTextProps) => {
const copyText = async () => {
await navigator.clipboard.writeText(text);
onClick();
};
const CopyIcon = copyIcon || FaRegClipboard;
const CopiedIcon = copiedIcon || FaCheck;

return (
<span className={cx(styles.wrapper, className)}>
<span className={textClassName}>{text}</span>
<button className={cx(styles.button, buttonClassName)} onClick={copyText}>
{copied ? (
<>
{showIcon && <FaCheck data-testid="copied-icon" />}
{showIcon && <CopiedIcon data-testid="copied-icon" />}
{copiedButtonLabel}
</>
) : (
<>
{showIcon && <FaRegClipboard data-testid="copy-icon" />}
{showIcon && <CopyIcon data-testid="copy-icon" />}
{copyButtonLabel}
</>
)}
Expand Down

0 comments on commit bd041e7

Please sign in to comment.