Skip to content

Commit

Permalink
feat: implement tooltip base functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
abelflopes committed Jun 7, 2024
1 parent aa46133 commit f60642f
Show file tree
Hide file tree
Showing 4 changed files with 186 additions and 36 deletions.
126 changes: 121 additions & 5 deletions packages/components/_provisional/src/tooltip/index.module.scss
Original file line number Diff line number Diff line change
@@ -1,17 +1,133 @@
@import "@react-ck/theme";
@import "@react-ck/elevation";
@import "@react-ck/text";

$padding-v: #{get-spacing(0.5)};
$outer-spacing: get-spacing(1);
$inner-spacing-y: get-spacing(1);
$inner-spacing-x: get-spacing(2);
$caret-spacing: get-spacing(1.66);

@mixin animation-initial {
opacity: 0;
}

@keyframes appear {
from {
@include animation-initial;
}
to {
opacity: 1;
}
}

.container {
padding: #{$padding-v} 0;
@include define-css-var(tooltip, max-height, var(--pe-max-height));
@include define-css-var(tooltip, max-width, var(--pe-max-width));
@include define-css-var(tooltip, container-padding-x, 0);
@include define-css-var(tooltip, container-padding-y, 0);

padding: #{get-css-var(tooltip, container-padding-y)} #{get-css-var(tooltip, container-padding-x)};
box-sizing: border-box;
z-index: map-get-strict($elevation, popup);

@include animation-initial;

will-change: opacity;
animation: appear 0.2s ease forwards;

// Apply vertical spacing
&[class*="top"],
&[class*="bottom"] {
@include define-css-var(tooltip, container-padding-y, $outer-spacing);
@include define-css-var(
tooltip,
max-height,
calc(var(--pe-max-height) - #{$outer-spacing} * 2)
);

&[class*="start"] .content::before {
left: $caret-spacing;
}

&[class*="center"] .content::before {
left: 50%;
transform: translateX(-50%);
}

&[class*="end"] .content::before {
right: $caret-spacing;
}
}

&[class*="left"],
&[class*="right"] {
@include define-css-var(tooltip, container-padding-x, $outer-spacing);
@include define-css-var(tooltip, max-width, calc(var(--pe-max-width) - #{$outer-spacing} * 2));

&[class*="start"] .content::before {
top: $caret-spacing;
}

&[class*="center"] .content::before {
top: 50%;
transform: translateY(-50%);
}

&[class*="end"] .content::before {
bottom: $caret-spacing;
}
}

&[class*="top"] {
.content::before {
top: 100%;
border-color: get-color(neutral-light-1) transparent transparent transparent;
filter: drop-shadow(0 3px 2px get-color(neutral-light-3));
}
}

&[class*="bottom"] {
.content::before {
bottom: 100%;
border-color: transparent transparent get-color(neutral-light-1) transparent;
filter: drop-shadow(0 -3px 2px get-color(neutral-light-3));
}
}

&[class*="left"] {
.content::before {
left: 100%;
border-color: transparent transparent transparent get-color(neutral-light-1);
filter: drop-shadow(3px 0 2px get-color(neutral-light-3));
}
}

&[class*="right"] {
.content::before {
right: 100%;
border-color: transparent get-color(neutral-light-1) transparent transparent;
filter: drop-shadow(-3px 0 2px get-color(neutral-light-3));
}
}
}

.content {
padding: get-spacing(2);
max-height: calc(var(--pe-max-height) - #{$padding-v} * 2);
max-width: var(--pe-max-width);
@include text-base;
@include text-variation(extra-small);

position: relative;
padding: #{$inner-spacing-y} #{$inner-spacing-x};
max-height: get-css-var(tooltip, max-height);
max-width: get-css-var(tooltip, max-width);
box-sizing: border-box;

&::before {
content: "";
position: absolute;
display: block;
border-style: solid;
border-width: get-spacing(0.66);
width: 0px;
height: 0px;
}
}
81 changes: 61 additions & 20 deletions packages/components/_provisional/src/tooltip/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import React from "react";
import styles from "./index.module.scss";
import React, { useEffect, useState } from "react";
import { Layer } from "@react-ck/layers";
import { PositionEngine, type PositionEngineProps } from "../position-engine";
import { ScrollableContainer } from "../scrollable-container";
import { Card } from "@react-ck/card";
import styles from "./index.module.scss";
import classNames from "classnames";

export interface TooltipProps {
anchor: PositionEngineProps["anchorRef"];
position?: PositionEngineProps["position"];
children?: React.ReactNode;
/**
* The tooltip will open/close on hover by default,
* if you pass true/false, this behavior will be overridden and should be managed by the consumer
*/
open?: boolean;
}

Expand All @@ -17,22 +22,58 @@ export const Tooltip = ({
position = "auto",
open,
children,
}: Readonly<TooltipProps>): React.ReactNode =>
open && (
<PositionEngine
exclude={["left", "right", "end"]}
position={position}
anchorRef={anchor}
render={({ style }) => (
<Layer elevation="popup">
<div style={style} className={styles.container}>
<Card skin="shadowed" spacing="none" className={styles.card}>
<ScrollableContainer horizontal={false} className={styles.content}>
{children}
</ScrollableContainer>
</Card>
</div>
</Layer>
)}
/>
}: Readonly<TooltipProps>): React.ReactNode => {
const [internalOpen, setInternalOpen] = useState(open);

useEffect(() => {
const ref = anchor.current;

if (open !== undefined) {
setInternalOpen(open);
return;
}

if (!ref) throw new Error("Tooltip anchor ref is required");

let to: ReturnType<typeof setTimeout> | undefined = undefined;

function handleMouseEnter(): void {
clearTimeout(to);
to = setTimeout(() => {
setInternalOpen(true);
}, 300);
}

function handleMouseLeave(): void {
clearTimeout(to);
setInternalOpen(false);
}

ref.addEventListener("mouseenter", handleMouseEnter);
ref.addEventListener("mouseleave", handleMouseLeave);

return () => {
clearTimeout(to);
ref.removeEventListener("mouseenter", handleMouseEnter);
ref.removeEventListener("mouseleave", handleMouseLeave);
};
}, [anchor, open]);

return (
internalOpen && (
<PositionEngine
position={position}
anchorRef={anchor}
render={({ style, position }) => (
<Layer elevation="popup">
<div style={style} className={classNames(styles.container, position)}>
<Card skin="shadowed" spacing="none" className={styles.card}>
<div className={styles.content}>{children}</div>
</Card>
</div>
</Layer>
)}
/>
)
);
};
1 change: 0 additions & 1 deletion packages/components/card/src/styles/index.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

background-color: get-color(neutral-light-1);
border-radius: get-css-var(card, border-radius);
overflow: hidden;

// Skins

Expand Down
14 changes: 4 additions & 10 deletions packages/docs/stories/src/tooltip.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Manager } from "@react-ck/manager";
import { configureStory } from "@react-ck/story-config";
import { Tooltip } from "@react-ck/provisional/src";
import { Button } from "@react-ck/button";
import { faker } from "@faker-js/faker";

type Story = StoryObj<typeof Tooltip>;

Expand All @@ -29,7 +30,8 @@ export default meta;

export const Component: Story = {
args: {
open: true,
open: undefined,
position: undefined,
},
render: ({ open, position }): React.ReactElement => {
// eslint-disable-next-line react-hooks/rules-of-hooks -- exception for storybook
Expand All @@ -39,15 +41,7 @@ export const Component: Story = {
<>
<Button rootRef={buttonRef}>Button</Button>
<Tooltip anchor={buttonRef} open={open} position={position}>
Content Lorem ipsum dolor sit amet consectetur adipisicing elit. Ratione nulla est, quidem
enim a molestias accusantium quo officia provident maxime voluptatem, beatae delectus
aliquid ipsa perferendis accusamus! Eius, laborum quisquam. Eius soluta deserunt
aspernatur tenetur, laudantium quod corrupti natus facilis est ab esse sunt dolore magni
cum accusamus nemo. Optio adipisci itaque exercitationem quo nulla, odit eligendi natus
est cupiditate aperiam nemo, vero explicabo. Non eveniet ipsum, dolores suscipit sit
deserunt doloribus. Dolorum aspernatur iusto, aliquid officiis illo modi vitae.
Exercitationem laudantium inventore nemo harum commodi doloribus totam porro aliquam. Quae
aliquam iusto neque ipsam non? Consequuntur saepe inventore aliquam!
{faker.lorem.sentence(5)}
</Tooltip>
</>
);
Expand Down

0 comments on commit f60642f

Please sign in to comment.