Skip to content

Commit

Permalink
feat: [GSFE-33] Writing a Tooltip Component. (#29)
Browse files Browse the repository at this point in the history
  • Loading branch information
luvhaeun committed Mar 17, 2023
1 parent b899074 commit cf1d7b4
Show file tree
Hide file tree
Showing 13 changed files with 337 additions and 2 deletions.
95 changes: 95 additions & 0 deletions .pnp.cjs

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

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
1 change: 1 addition & 0 deletions packages/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"dependencies": {
"@emotion/react": "11.10.6",
"@emotion/styled": "11.10.6",
"@floating-ui/react": "0.21.1",
"@gnoswap-labs/gno-client": "*",
"@tanstack/react-query": "4.26.1",
"axios": "1.3.4",
Expand Down
44 changes: 44 additions & 0 deletions packages/web/src/components/common/tooltip/Tooltip.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from "react";
import { ComponentStory, ComponentMeta } from "@storybook/react";

import Tooltip from "./Tooltip";

export default {
title: "common/Tooltip",
component: Tooltip,
} as ComponentMeta<typeof Tooltip>;

const Template: ComponentStory<typeof Tooltip> = ({ placement }) => (
<div
style={{
width: 200,
height: 300,
backgroundColor: "yellow",
overflowX: "hidden",
overflowY: "auto",
}}
>
<div
style={{
marginTop: 200,
height: 500,
}}
>
<Tooltip placement={placement} FloatingContent={<div>Hello Gnoswap</div>}>
<div
style={{
width: 200,
height: 100,
backgroundColor: "green",
textAlign: "center",
}}
/>
</Tooltip>
</div>
</div>
);

export const Default = Template.bind({});
Default.args = {
placement: "top",
};
11 changes: 11 additions & 0 deletions packages/web/src/components/common/tooltip/Tooltip.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import styled from "@emotion/styled";

export const Content = styled.div`
background-color: ${({ theme }) => theme.colors.brand90};
color: ${({ theme }) => theme.colors.gray10};
padding: 16px;
border-radius: 8px;
box-sizing: border-box;
width: max-content;
max-width: calc(100vw - 10px);
`;
125 changes: 125 additions & 0 deletions packages/web/src/components/common/tooltip/Tooltip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import React, { useMemo, useRef, useState } from "react";
import {
type Placement,
useHover,
useFocus,
useDismiss,
useRole,
useInteractions,
FloatingPortal,
useFloating,
autoUpdate,
offset,
shift,
useMergeRefs,
FloatingArrow,
arrow,
flip,
} from "@floating-ui/react";
import { Content } from "./Tooltip.styles";
import { useTheme } from "@emotion/react";

function useTooltip({ placement }: { placement: Placement }) {
const [open, setOpen] = useState(false);
const arrowRef = useRef(null);

const data = useFloating({
placement,
open,
onOpenChange: setOpen,
whileElementsMounted: autoUpdate,
middleware: [
offset(20),
flip({
fallbackAxisSideDirection: "start",
}),
shift(),
arrow({
element: arrowRef,
}),
],
});

const context = data.context;

const hover = useHover(context, {
move: false,
enabled: true,
});
const focus = useFocus(context, {
enabled: true,
});
const dismiss = useDismiss(context);
const role = useRole(context, { role: "tooltip" });

const interactions = useInteractions([hover, focus, dismiss, role]);

return useMemo(
() => ({
open,
setOpen,
arrowRef,
...interactions,
...data,
}),
[open, setOpen, interactions, data],
);
}

interface TooltipProps {
placement: Placement;
FloatingContent: React.ReactNode;
}

const Tooltip: React.FC<React.PropsWithChildren<TooltipProps>> = ({
children,
placement,
FloatingContent,
}) => {
const { open, refs, strategy, x, y, context, arrowRef } = useTooltip({
placement,
});
const childrenRef = useMergeRefs([refs.setReference]);
const floatingRef = useMergeRefs([refs.setFloating]);

const theme = useTheme();

return (
<>
<div
ref={childrenRef}
data-state={open ? "open" : "closed"}
style={{
display: "inline-block",
}}
>
{children}
</div>
<FloatingPortal>
{open && (
<div
ref={floatingRef}
style={{
position: strategy,
top: y ?? 0,
left: x ?? 0,
visibility: x == null ? "hidden" : "visible",
}}
>
<FloatingArrow
ref={arrowRef}
context={context}
fill={theme.colors.brand90}
width={20}
height={14}
tipRadius={4}
/>
<Content>{FloatingContent}</Content>
</div>
)}
</FloatingPortal>
</>
);
};

export default Tooltip;
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import SearchInput from "@components/common/searchInput/SearchInput";
import SearchInput from "@components/common/search-input/SearchInput";
import { POOL_TYPE } from "@containers/pool-list-container/PoolListContainer";
import { css } from "@emotion/react";
import React, { useCallback, useRef, useState } from "react";
import React, { useCallback, useState } from "react";

interface PoolListHeaderProps {
poolType: POOL_TYPE;
Expand Down
Loading

0 comments on commit cf1d7b4

Please sign in to comment.