Skip to content

Commit 2a3bae6

Browse files
committed
Added Molecules Tooltip
1 parent 865aa5c commit 2a3bae6

8 files changed

Lines changed: 181 additions & 0 deletions

File tree

package-lock.json

Lines changed: 22 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
},
2323
"dependencies": {
2424
"@reach/menu-button": "0.10.2",
25+
"@tippyjs/react": "4.0.2",
2526
"@types/react": "16.9.11",
2627
"@types/react-dom": "16.9.3",
2728
"@types/react-router-dom": "5.1.5",

src/assets/scss/6-components/molecules/__molecules.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@
77
@import "form-fields";
88
@import "forms";
99
@import "radio-list";
10+
@import "tooltip";
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
.c-tooltip {
2+
@include box-shadow(0, 7px, 20px, rgba(0, 26, 57, 0.3));
3+
@include font-style($size: "small");
4+
@include padding(12px);
5+
background-color: get-color-neutral("90");
6+
color: get-color-neutral("white");
7+
border-radius: $border-radius-small;
8+
9+
.tippy-content {
10+
div {
11+
word-break: break-word;
12+
}
13+
}
14+
15+
&__arrow {
16+
position: absolute;
17+
bottom: rem(-8px);
18+
width: rem(16px);
19+
height: rem(16px);
20+
background-color: get-color-neutral("90");
21+
left: 50%;
22+
transform: translateX(-50%) rotate(45deg);
23+
}
24+
}

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ export { DropdownButton } from "./molecules/dropdown-button/dropdown-button";
6565
export { ErrorBanner } from "./molecules/errors/error-banner";
6666
export { Form } from "./molecules/forms/form";
6767
export { RadioList } from "./molecules/lists/radio-list";
68+
export { Tooltip } from "./molecules/tooltips/tooltip";
6869
export { UnorderedList } from "./molecules/lists/unordered-list";
6970

7071
// Form Fields
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { boolean, text } from "@storybook/addon-knobs";
2+
import { Button } from "../../atoms/buttons/button";
3+
import React from "react";
4+
import { Tooltip } from "./tooltip";
5+
6+
export default {
7+
component: Tooltip,
8+
title: "Molecules | Tooltip",
9+
};
10+
11+
export const tooltipKnobs = () => (
12+
<Tooltip
13+
content={text(
14+
"Tooltip Contents",
15+
"I am a tooltip, based on @tippyjs/react!"
16+
)}
17+
visible={boolean("Force Visibility", false) ?? undefined}>
18+
<Button>Hover Me!</Button>
19+
</Tooltip>
20+
);
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import React from "react";
2+
import { render } from "@testing-library/react";
3+
import { Tooltip } from "./tooltip";
4+
import faker from "faker";
5+
6+
describe("Tooltip", () => {
7+
test("when default props, renders children", () => {
8+
// Arrange
9+
const expected = faker.random.words();
10+
11+
// Act
12+
const { getByText } = render(
13+
<Tooltip content={<span>content</span>}>
14+
<span>{expected}</span>
15+
</Tooltip>
16+
);
17+
18+
// Assert
19+
expect(getByText(expected)).not.toBeNull();
20+
});
21+
});

src/molecules/tooltips/tooltip.tsx

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import Tippy from "@tippyjs/react";
2+
import { followCursor } from "tippy.js";
3+
import React from "react";
4+
import { StringUtils } from "andculturecode-javascript-core";
5+
6+
// -------------------------------------------------------------------------------------------------
7+
// #region Interfaces
8+
// -------------------------------------------------------------------------------------------------
9+
10+
export interface TooltipProps {
11+
/**
12+
* Required. The element that triggers the tooltip on hovering.
13+
* Surround the trigger with the `<Tooltip>` component.
14+
*/
15+
children: React.ReactElement;
16+
/**
17+
* The content of the tooltip itself.
18+
*/
19+
content: React.ReactChild | React.ReactChild[];
20+
cssClassName?: string;
21+
/**
22+
* Delay to wait before showing tooltip, in ms. Defaults to 500.
23+
*/
24+
delay?: number;
25+
/**
26+
* Disable the tooltip. For example, if you have overflowing text,
27+
* and you only want to show if the text is actually truncated with ...
28+
* you can get a ref to the HTML element and set
29+
* disabled={elRef.offsetWidth < elRef.scrollWidth}
30+
* @see resource-subtext-label.tsx for an example of how to achieve this behavior
31+
*/
32+
disabled?: boolean;
33+
/**
34+
* True by default. If true, the tooltip will appear at the cursor's location.
35+
*/
36+
showOnCursor?: boolean;
37+
/**
38+
* Manually control tooltip visibility.
39+
* Useful for debugging styles.
40+
*/
41+
visible?: boolean;
42+
}
43+
44+
// #endregion Interfaces
45+
46+
// -------------------------------------------------------------------------------------------------
47+
// #region Component
48+
// -------------------------------------------------------------------------------------------------
49+
50+
const Tooltip: React.FC<TooltipProps> = (props: TooltipProps) => {
51+
const CSS_CLASS_NAME = "c-tooltip";
52+
const classNames = [CSS_CLASS_NAME];
53+
54+
if (StringUtils.hasValue(props.cssClassName)) {
55+
classNames.push(props.cssClassName!);
56+
}
57+
58+
const getContent = () => (
59+
<React.Fragment>
60+
{props.content}
61+
<div className={`${CSS_CLASS_NAME}__arrow`} />
62+
</React.Fragment>
63+
);
64+
65+
if (props.disabled === true) {
66+
return props.children;
67+
}
68+
69+
return (
70+
<Tippy
71+
className={classNames.join(" ")}
72+
content={getContent()}
73+
delay={props.delay ?? 500}
74+
followCursor={props.showOnCursor === false ? undefined : "initial"}
75+
hideOnClick={false}
76+
plugins={[followCursor]}
77+
visible={props.visible}>
78+
{props.children}
79+
</Tippy>
80+
);
81+
};
82+
83+
// #endregion Component
84+
85+
// -------------------------------------------------------------------------------------------------
86+
// #region Exports
87+
// -------------------------------------------------------------------------------------------------
88+
89+
export { Tooltip };
90+
91+
// #endregion Exports

0 commit comments

Comments
 (0)