Skip to content

Commit

Permalink
Merge branch 'master' into mp/feat/fullscreen-modal-content-fill-height
Browse files Browse the repository at this point in the history
  • Loading branch information
mperrotti authored Sep 13, 2019
2 parents 33fb2e6 + 75edba7 commit 1dafe38
Show file tree
Hide file tree
Showing 18 changed files with 871 additions and 8 deletions.
10 changes: 4 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"@types/chartist": "^0.9.46",
"@types/react-tabs": "^2.3.1",
"chartist": "^0.11.0",
"copy-to-clipboard": "3.2.0",
"downshift": "3.2.10",
"emotion": "9.2.12",
"emotion-theming": "9.2.9",
Expand Down
3 changes: 3 additions & 0 deletions packages/clicktocopybutton/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# ClickToCopyButton

The `ClickToCopyButton` is used to give users a shortcut to copy text to their clipboard. It is most commonly used to copy code snippets, or configuration content.
42 changes: 42 additions & 0 deletions packages/clicktocopybutton/components/ClickToCopy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import copy from "copy-to-clipboard";

interface ChildProps {
onClick: () => void;
}

export interface ClickToCopyBaseProps {
/**
* This is what will end up on the user's clipboard
*/
textToCopy: string;

/**
* Function to execute after text has been copied
*/
onCopy?: () => void;
}

interface ClickToCopyProps extends ClickToCopyBaseProps {
/**
* Render prop to display content and trigger copy using onClick prop
*/
children: (props: ChildProps) => JSX.Element;
}

/**
* Consumers of this component should provide a child render prop function
* that takes a function parameter and returns a component that executes that function using
* a trigger element such as a button with an onClick handler.
*/
const ClickToCopy = ({ textToCopy, onCopy, children }: ClickToCopyProps) => {
const onClick = () => {
copy(textToCopy);
if (onCopy && typeof onCopy === "function") {
onCopy();
}
};

return children({ onClick });
};

export default ClickToCopy;
39 changes: 39 additions & 0 deletions packages/clicktocopybutton/components/ClickToCopyButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import * as React from "react";
import ClickToCopy, { ClickToCopyBaseProps } from "./ClickToCopy";
import { Box } from "../../styleUtils/modifiers";
import Clickable from "../../clickable/components/clickable";
import Icon from "../../icon/components/Icon";
import { SystemIcons } from "../../icons/dist/system-icons-enum";
import { tintContent } from "../../shared/styles/styleUtils";

interface ClickToCopyButtonProps extends ClickToCopyBaseProps {
children?: React.ReactNode;
/**
* Color of the clipboard icon or button content
*/
color?: React.CSSProperties["color"];
}

const ClickToCopyButton = ({
children,
color,
...other
}: ClickToCopyButtonProps) => {
return (
<ClickToCopy {...other}>
{({ onClick }) => (
<Clickable action={onClick} tabIndex={0}>
{children ? (
<div className={tintContent(color)}>{children}</div>
) : (
<Box display="inline-block" tag="span">
<Icon shape={SystemIcons.Clipboard} color={color} />
</Box>
)}
</Clickable>
)}
</ClickToCopy>
);
};

export default ClickToCopyButton;
1 change: 1 addition & 0 deletions packages/clicktocopybutton/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as ClickToCopyButton } from "./components/ClickToCopyButton";
37 changes: 37 additions & 0 deletions packages/clicktocopybutton/stories/ClickToCopyButton.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import * as React from "react";
import { storiesOf } from "@storybook/react";
import { withReadme } from "storybook-readme";
import { ClickToCopyButton } from "../index";
import Tooltip from "../../tooltip/components/Tooltip";
import ClickToCopyTooltipHelper from "./helpers/ClickToCopyTooltipHelper";
import { Box } from "../../styleUtils/modifiers";

const readme = require("../README.md");
const textToCopy = "Nobody likes a copycat";

storiesOf("ClickToCopyButton", module)
.addDecorator(withReadme([readme]))
.add("default", () => <ClickToCopyButton textToCopy={textToCopy} />)
.add("show tooltip onCopy", () => (
<ClickToCopyTooltipHelper>
{({ onCopy, tooltipIsVisible }) => (
<Box display="inline-block">
<Tooltip
id="tooltipDemo"
trigger={
<ClickToCopyButton textToCopy={textToCopy} onCopy={onCopy} />
}
open={tooltipIsVisible}
suppress={true}
>
"{textToCopy}" copied
</Tooltip>
</Box>
)}
</ClickToCopyTooltipHelper>
))
.add("custom children", () => (
<ClickToCopyButton textToCopy={textToCopy}>
<div>{`Click here to copy the text: "${textToCopy}"`}</div>
</ClickToCopyButton>
));
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import * as React from "react";

interface RenderProps {
tooltipIsVisible: boolean;
onCopy: () => void;
}

interface CTCButtonTooltipHelperProps {
children: (renderProps: RenderProps) => React.ReactNode;
}

interface CTCButtonTooltipHelperState {
tooltipIsVisible: boolean;
}

class ClickToCopyButtonTooltipHelper extends React.PureComponent<
CTCButtonTooltipHelperProps,
CTCButtonTooltipHelperState
> {
constructor(props) {
super(props);

this.state = {
tooltipIsVisible: false
};

this.handleOnCopy = this.handleOnCopy.bind(this);
}

public render() {
return this.props.children({
onCopy: this.handleOnCopy,
tooltipIsVisible: this.state.tooltipIsVisible
});
}

private handleOnCopy() {
this.setState({ tooltipIsVisible: true });
setTimeout(() => {
this.setState({ tooltipIsVisible: false });
}, 2000);
}
}

export default ClickToCopyButtonTooltipHelper;
40 changes: 40 additions & 0 deletions packages/clicktocopybutton/tests/ClickToCopyButton.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from "react";
import * as emotion from "emotion";
import { createSerializer } from "jest-emotion";
import { mount } from "enzyme";
import toJson from "enzyme-to-json";

import { ClickToCopyButton } from "../";

expect.addSnapshotSerializer(createSerializer(emotion));

const textToCopy = "text to copy";

jest.mock("copy-to-clipboard", () => jest.fn());

describe("ClickToCopyButton", () => {
it("renders default", () => {
const component = mount(<ClickToCopyButton textToCopy={textToCopy} />);

expect(toJson(component)).toMatchSnapshot();
});
it("renders with custom children", () => {
const component = mount(
<ClickToCopyButton textToCopy={textToCopy}>
custom children
</ClickToCopyButton>
);

expect(toJson(component)).toMatchSnapshot();
});
it("calls onCopy when clicked ", () => {
const onCopyFn = jest.fn();
const component = mount(
<ClickToCopyButton textToCopy={textToCopy} onCopy={onCopyFn} />
);

expect(onCopyFn).not.toHaveBeenCalled();
component.simulate("click");
expect(onCopyFn).toHaveBeenCalled();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`ClickToCopyButton renders default 1`] = `
.emotion-2 {
cursor: pointer;
}
.emotion-1 {
background-repeat: no-repeat;
display: inline-block;
cursor: pointer;
}
.emotion-0 {
vertical-align: middle;
fill: currentColor;
}
.emotion-0 use {
pointer-events: none;
}
<ClickToCopyButton
textToCopy="text to copy"
>
<ClickToCopy
textToCopy="text to copy"
>
<Clickable
action={[Function]}
disableFocusOutline={false}
role="button"
tabIndex={0}
>
<Box
bgImageOptions={
Object {
"position": undefined,
"repeat": undefined,
"size": undefined,
}
}
className="emotion-2"
dataCy="box"
display="inline-block"
onClick={[Function]}
onKeyPress={[Function]}
role="button"
tabIndex={0}
tag="span"
>
<span
className="emotion-1"
onClick={[Function]}
onKeyPress={[Function]}
role="button"
tabIndex={0}
>
<Icon
shape="system-clipboard"
>
<svg
aria-label="system-clipboard icon"
className="emotion-0"
data-cy="icon"
height={24}
preserveAspectRatio="xMinYMin meet"
role="img"
viewBox="0 0 24 24"
width={24}
>
<use
xlinkHref="#system-clipboard"
/>
</svg>
</Icon>
</span>
</Box>
</Clickable>
</ClickToCopy>
</ClickToCopyButton>
`;

exports[`ClickToCopyButton renders with custom children 1`] = `
.emotion-0 {
cursor: pointer;
}
<ClickToCopyButton
textToCopy="text to copy"
>
<ClickToCopy
textToCopy="text to copy"
>
<Clickable
action={[Function]}
disableFocusOutline={false}
role="button"
tabIndex={0}
>
<div
className="emotion-0"
onClick={[Function]}
onKeyPress={[Function]}
role="button"
tabIndex={0}
>
custom children
</div>
</Clickable>
</ClickToCopy>
</ClickToCopyButton>
`;
3 changes: 3 additions & 0 deletions packages/codesnippet/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# CodeSnippet

The `CodeSnippet` component is used to visually separate code from other content in the UI, and sets the code in a monospace font to make it easier to read.
Loading

0 comments on commit 1dafe38

Please sign in to comment.