1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-07-19 13:29:41 +02:00

refactor(app): move react components to react codebase [EE-3179] (#6971)

This commit is contained in:
Chaim Lev-Ari 2022-06-17 19:18:42 +03:00 committed by GitHub
parent 212400c283
commit 18252ab854
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
346 changed files with 642 additions and 644 deletions

View file

@ -0,0 +1,45 @@
.fadeout {
animation: fadeOut 2.5s;
animation-fill-mode: forwards;
}
.container {
display: flex;
align-items: baseline;
margin-top: 10px;
}
.display-text {
opacity: 0;
margin-left: 7px;
color: #23ae89;
}
@-webkit-keyframes fadeOut {
0% {
opacity: 1;
}
50% {
opacity: 0.8;
}
99% {
opacity: 0.01;
}
100% {
opacity: 0;
}
}
@keyframes fadeOut {
0% {
opacity: 1;
}
50% {
opacity: 0.8;
}
99% {
opacity: 0.01;
}
100% {
opacity: 0;
}
}

View file

@ -0,0 +1,34 @@
import { Meta, Story } from '@storybook/react';
import { PropsWithChildren } from 'react';
import { CopyButton, Props } from './CopyButton';
export default {
component: CopyButton,
title: 'Components/Buttons/CopyButton',
} as Meta;
function Template({
copyText,
displayText,
children,
}: JSX.IntrinsicAttributes & PropsWithChildren<Props>) {
return (
<CopyButton copyText={copyText} displayText={displayText}>
{children}
</CopyButton>
);
}
export const Primary: Story<PropsWithChildren<Props>> = Template.bind({});
Primary.args = {
children: 'Copy to clipboard',
copyText: 'this will be copied to clipboard',
};
export const NoCopyText: Story<PropsWithChildren<Props>> = Template.bind({});
NoCopyText.args = {
children: 'Copy to clipboard without copied text',
copyText: 'clipboard override',
displayText: '',
};

View file

@ -0,0 +1,37 @@
import { fireEvent, render } from '@testing-library/react';
import { CopyButton } from './CopyButton';
test('should display a CopyButton with children', async () => {
const children = 'test button children';
const { findByText } = render(
<CopyButton copyText="">{children}</CopyButton>
);
const button = await findByText(children);
expect(button).toBeTruthy();
});
test('CopyButton should copy text to clipboard', async () => {
// override navigator.clipboard.writeText (to test copy to clipboard functionality)
let clipboardText = '';
const writeText = jest.fn((text) => {
clipboardText = text;
});
Object.assign(navigator, {
clipboard: { writeText },
});
const children = 'button';
const copyText = 'text successfully copied to clipboard';
const { findByText } = render(
<CopyButton copyText={copyText}>{children}</CopyButton>
);
const button = await findByText(children);
expect(button).toBeTruthy();
fireEvent.click(button);
expect(clipboardText).toBe(copyText);
expect(writeText).toHaveBeenCalled();
});

View file

@ -0,0 +1,49 @@
import { PropsWithChildren } from 'react';
import clsx from 'clsx';
import { Button } from '../Button';
import styles from './CopyButton.module.css';
import { useCopy } from './useCopy';
export interface Props {
copyText: string;
fadeDelay?: number;
displayText?: string;
className?: string;
}
export function CopyButton({
copyText,
fadeDelay = 1000,
displayText = 'copied',
className,
children,
}: PropsWithChildren<Props>) {
const { handleCopy, copiedSuccessfully } = useCopy(copyText, fadeDelay);
return (
<div className={styles.container}>
<Button
className={className}
size="small"
onClick={handleCopy}
title="Copy Value"
type="button"
>
<i className="fa fa-copy space-right" aria-hidden="true" /> {children}
</Button>
<span
className={clsx(
copiedSuccessfully && styles.fadeout,
styles.displayText,
'space-left'
)}
>
<i className="fa fa-check" aria-hidden="true" />
{displayText && <span className="space-left">{displayText}</span>}
</span>
</div>
);
}

View file

@ -0,0 +1 @@
export { CopyButton } from './CopyButton';

View file

@ -0,0 +1,36 @@
import { useEffect, useState } from 'react';
export function useCopy(copyText: string, fadeDelay = 1000) {
const [copiedSuccessfully, setCopiedSuccessfully] = useState(false);
useEffect(() => {
const fadeoutTime = setTimeout(
() => setCopiedSuccessfully(false),
fadeDelay
);
// clear timeout when component unmounts
return () => {
clearTimeout(fadeoutTime);
};
}, [copiedSuccessfully, fadeDelay]);
function handleCopy() {
// https://developer.mozilla.org/en-US/docs/Web/API/Clipboard
// https://caniuse.com/?search=clipboard
if (navigator.clipboard) {
navigator.clipboard.writeText(copyText);
} else {
// https://stackoverflow.com/a/57192718
const inputEl = document.createElement('textarea');
inputEl.value = copyText;
document.body.appendChild(inputEl);
inputEl.select();
document.execCommand('copy');
inputEl.hidden = true;
document.body.removeChild(inputEl);
}
setCopiedSuccessfully(true);
}
return { handleCopy, copiedSuccessfully };
}