Skip to content

Commit

Permalink
- Add Floating UI library to tooltip package.
Browse files Browse the repository at this point in the history
- Update Tooltip to use Floating UI instead of Tippy.

# Breaking
- Tooltip no longer supports props `trigger` and `disabled`.
  • Loading branch information
mattias800 committed Aug 21, 2024
1 parent da344c5 commit 9eca44e
Show file tree
Hide file tree
Showing 5 changed files with 238 additions and 158 deletions.
1 change: 1 addition & 0 deletions packages/tooltip/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"deploy": "gh-pages -d example/build"
},
"dependencies": {
"@floating-ui/react": "^0.26.22",
"@stenajs-webui/core": "20.17.4",
"@stenajs-webui/elements": "20.17.4",
"@stenajs-webui/theme": "20.17.4",
Expand Down
7 changes: 5 additions & 2 deletions packages/tooltip/src/components/tooltip/Tooltip.module.css
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
.tooltip {
.floating {
display: flex;
width: fit-content;
flex-direction: row;
align-items: center;
background: #333;
color: white;
border-radius: var(--swui-border-radius);
padding: var(--swui-metrics-spacing) calc(var(--swui-metrics-indent) * 2);

&.withIcon {
padding: calc(var(--swui-metrics-spacing) * 0.5);
padding-right: calc(var(--swui-metrics-indent) * 2);
}

}

.iconWrapper {
Expand Down
39 changes: 1 addition & 38 deletions packages/tooltip/src/components/tooltip/Tooltip.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { Column, Row, Spacing, Text, useBoolean } from "@stenajs-webui/core";
import { PrimaryButton } from "@stenajs-webui/elements";
import { Column, Row, Text } from "@stenajs-webui/core";
import { cssColor } from "@stenajs-webui/theme";
import * as React from "react";
import { useEffect } from "react";
import { Tooltip } from "./Tooltip";

export default {
Expand Down Expand Up @@ -31,22 +29,6 @@ export const Standard = () => (
</>
);

export const ClickTrigger = () => (
<Row justifyContent={"space-between"} spacing={10}>
<Tooltip label={"Way to go!"} trigger={"click"}>
<Text>Click me</Text>
</Tooltip>
</Row>
);

export const WithButton = () => (
<Column justifyContent={"flex-start"} width={"fit-content"} spacing={10}>
<Tooltip label={"Big success!"} trigger={"click"}>
<PrimaryButton label={"Click me"} />
</Tooltip>
</Column>
);

export const Variants = () => (
<Column alignItems={"flex-start"} spacing={10} gap={5}>
<Tooltip label={"Standard"}>
Expand Down Expand Up @@ -115,22 +97,3 @@ export const Variants = () => (
</Tooltip>
</Column>
);

export const Disabled = () => {
const [disabled, , , toggle] = useBoolean(false);

useEffect(() => {
const r = setInterval(toggle, 2000);
return () => clearInterval(r);
}, [toggle]);

return (
<Column justifyContent={"flex-start"} width={"fit-content"} spacing={10}>
<Tooltip label={"Big success!"} disabled={disabled}>
<PrimaryButton label={"Hover me"} />
</Tooltip>
<Spacing />
<Text>Disabled={disabled ? "true" : "false"}</Text>
</Column>
);
};
148 changes: 108 additions & 40 deletions packages/tooltip/src/components/tooltip/Tooltip.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,34 @@
import { Text, Space } from "@stenajs-webui/core";
import { Space, Text } from "@stenajs-webui/core";
import * as React from "react";
import { CSSProperties, PropsWithChildren, useRef, useState } from "react";
import {
arrow,
autoUpdate,
flip,
FloatingArrow,
offset,
shift,
useFloating,
useHover,
useInteractions,
useTransitionStyles,
} from "@floating-ui/react";
import moduleStyles from "./Tooltip.module.css";
import { cssColor } from "@stenajs-webui/theme";
import cx from "classnames";
import {
Icon,
stenaExclamationCircle,
stenaExclamationTriangle,
stenaInfoCircle,
} from "@stenajs-webui/elements";
import cx from "classnames";
import * as React from "react";
import styles from "./Tooltip.module.css";
import { Popover, PopoverProps } from "../popover/Popover";
import { cssColor } from "@stenajs-webui/theme";

export interface TooltipProps extends PropsWithChildren {
placement?: Placement;
label: string;
variant?: TooltipVariant;
maxWidth?: CSSProperties["maxWidth"];
}

type TooltipVariant = "info" | "warning" | "error";

Expand All @@ -19,44 +38,93 @@ const variantIcons = {
error: stenaExclamationTriangle,
};

export interface TooltipProps extends Omit<PopoverProps, "theme" | "render"> {
label: string;
variant?: TooltipVariant;
children: JSX.Element;
}
const ARROW_WIDTH = 12;
const ARROW_HEIGHT = 8;
const GAP = 2;

const TooltipText: React.FC<{ label: string }> = ({ label }) => (
<Text color={cssColor("--lhds-color-ui-50")} size={"small"} variant="bold">
{label}
</Text>
);
export type Placement = "top" | "right" | "bottom" | "left";

export const Tooltip: React.FC<TooltipProps> = ({
children,
placement,
label,
variant,
children,
...popoverProps
}) => (
<Popover
theme="dark"
{...popoverProps}
disablePadding
content={
<div className={cx(styles.tooltip, variant ? styles.withIcon : null)}>
{variant ? (
<>
<div className={cx(styles.iconWrapper, styles[variant])}>
<Icon icon={variantIcons[variant]} size={16} />
</div>
<Space />
<TooltipText label={label} />
</>
) : (
<TooltipText label={label} />
)}
maxWidth = "500px",
}) => {
const [isOpen, setIsOpen] = useState(false);

const arrowRef = useRef(null);

const { refs, floatingStyles, context } = useFloating({
placement,
open: isOpen,
onOpenChange: setIsOpen,
middleware: [
offset(ARROW_HEIGHT + GAP),
flip({ padding: 5 }),
shift({ padding: 5 }),
arrow({ element: arrowRef }),
],
whileElementsMounted: autoUpdate,
});

const { isMounted, styles } = useTransitionStyles(context, {
initial: {
opacity: 0,
},
});

const hover = useHover(context);

const { getReferenceProps } = useInteractions([hover]);

return (
<>
<div ref={refs.setReference} {...getReferenceProps()}>
{children}
</div>
}
>
{children}
</Popover>

{isMounted && (
<div ref={refs.setFloating} style={floatingStyles}>
<div
style={{ maxWidth, ...styles }}
className={cx(
moduleStyles.floating,
variant && moduleStyles.withIcon
)}
>
{variant ? (
<>
<div
className={cx(
moduleStyles.iconWrapper,
moduleStyles[variant]
)}
>
<Icon icon={variantIcons[variant]} size={16} />
</div>
<Space />
<TooltipText label={label} />
</>
) : (
<TooltipText label={label} />
)}

<FloatingArrow
ref={arrowRef}
context={context}
width={ARROW_WIDTH}
height={ARROW_HEIGHT}
/>
</div>
</div>
)}
</>
);
};

const TooltipText: React.FC<{ label: string }> = ({ label }) => (
<Text color={cssColor("--lhds-color-ui-50")} size={"small"} variant="bold">
{label}
</Text>
);
Loading

0 comments on commit 9eca44e

Please sign in to comment.