Skip to content

Commit

Permalink
chore(ui): transfer ToolTip to Typescript (#306)
Browse files Browse the repository at this point in the history
* chore(ui): add typescript to ToolTip

* chore(ui): add license checker

* chore(ui): optimize Tooltip stories

* chore(ui): fix tooltip component

* chore(ui): add changeset
  • Loading branch information
barsukov authored Sep 6, 2024
1 parent 1a85ed9 commit 990af5a
Show file tree
Hide file tree
Showing 16 changed files with 217 additions and 228 deletions.
5 changes: 5 additions & 0 deletions .changeset/spotty-buses-behave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cloudoperators/juno-ui-components": patch
---

Introduce a ToolTip typescript version along with storybook doc type support
3 changes: 3 additions & 0 deletions packages/ui-components/.storybook/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ const config = {
"@storybook/addon-webpack5-compiler-babel",
"@storybook/addon-postcss",
],
typescript: {
reactDocgen: "react-docgen-typescript",
},
staticDirs: ["../public"],
webpackFinal: async (config) => {
const fileLoaderRule = config.module.rules.find((rule) => rule.test && rule.test.test(".svg"))
Expand Down
20 changes: 20 additions & 0 deletions packages/ui-components/src/components/Tooltip/ToolTip.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
* SPDX-License-Identifier: Apache-2.0
*/

export type TooltipPlacement =
| "top"
| "top-start"
| "top-end"
| "right"
| "right-start"
| "right-end"
| "bottom"
| "bottom-start"
| "bottom-end"
| "left"
| "left-start"
| "left-end"

export type ToolTipVariant = "info" | "warning" | "danger" | "error" | "success"
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,13 @@
*/

import React from "react"
import PropTypes from "prop-types"
import { useTooltip } from "./useTooltip"
import { useTooltip, UseTooltipProps } from "./useTooltip"
import { ToolTipVariant, TooltipPlacement } from "./ToolTip.types"

export const tooltipPlacementOptions = [
"top",
"top-start",
"top-end",
"right",
"right-start",
"right-end",
"bottom",
"bottom-start",
"bottom-end",
"left",
"left-start",
"left-end",
]
// Define a type for TooltipContext, which holds the return value of useTooltip
type TooltipContextType = ReturnType<typeof useTooltip> | null

export const tooltipVariants = ["info", "warning", "danger", "error", "success"]

const TooltipContext = React.createContext(null)
const TooltipContext = React.createContext<TooltipContextType>(null)

/**
* This hook holds the TooltipContext.
Expand All @@ -41,6 +27,24 @@ export const useTooltipState = () => {
return context
}

interface TooltipProps {
// /** The semantic variant of the tooltip, or `plain` */
variant?: ToolTipVariant
/** Uncontrolled Tooltip: Choose which event should trigger the opening of the tooltip (click or hover) */
triggerEvent?: "click" | "hover"
/** Tooltip placement in relation to trigger, default is top */
placement?: TooltipPlacement
/** Disable the tooltip. If this is true, the uncontrolled tooltip can't be opened anymore and the cursor hovered over the trigger will be the default cursor instead of the pointer cursor */
disabled?: boolean
/** Set whether tooltip should be initially rendered opened or closed. This is only evaluated if Tooltip is in uncontrolled mode */
initialOpen?: boolean
/** Whether the Tooltip is open. By passing this prop you turn the Tooltip into a controlled component, which means
* you also have to take care of opening and closing it. In this case the triggerEvent prop is ignored since you're handling the trigger yourself */
open?: boolean
/** Pass the TooltipTrigger and TooltipContent elements as children */
children?: React.ReactNode
}

/**
* A tooltip component that optionally comes in the various semantic flavors (e.g. info, warning, ...). It can be used as an uncontrolled component where
* you configure the event type that should open the tooltip (click or hover) or alternatively you can use it as a controlled component where you set the
Expand All @@ -56,7 +60,7 @@ export function Tooltip({
disabled = false,
children = null,
...props
}) {
}: TooltipProps) {
// This can accept any floating ui props as options, e.g. `placement`,
// or other positioning options.
const tooltip = useTooltip({
Expand All @@ -67,27 +71,6 @@ export function Tooltip({
triggerEvent,
disabled,
props,
})
} as UseTooltipProps)
return <TooltipContext.Provider value={tooltip}>{children}</TooltipContext.Provider>
}

// /** tooltip state from useTooltipState hook, needs to be passed to both anchor and tooltip itself */
// state: PropTypes.object,

Tooltip.propTypes = {
// /** The semantic variant of the tooltip, or `plain` */
variant: PropTypes.oneOf(tooltipVariants),
/** Uncontrolled Tooltip: Choose which event should trigger the opening of the tooltip (click or hover) */
triggerEvent: PropTypes.oneOf(["click", "hover"]),
/** Tooltip placement in relation to trigger, default is top */
placement: PropTypes.oneOf(tooltipPlacementOptions),
/** Disable the tooltip. If this is true, the uncontrolled tooltip can't be opened anymore and the cursor hovered over the trigger will be the default cursor instead of the pointer cursor */
disabled: PropTypes.bool,
/** Set whether tooltip should be initially rendered opened or closed. This is only evaluated if Tooltip is in uncontrolled mode */
initialOpen: PropTypes.bool,
/** Whether the Tooltip is open. By passing this prop you turn the Tooltip into a controlled component, which means
* you also have to take care of opening and closing it. In this case the triggerEvent prop is ignored since you're handling the trigger yourself */
open: PropTypes.bool,
/** Pass the TooltipTrigger and TooltipContent elements as children */
children: PropTypes.node,
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@
*/

import React from "react"
import PropTypes from "prop-types"
import { Tooltip } from "./index.js"
import { TooltipContent } from "../TooltipContent/index.js"
import { TooltipTrigger } from "../TooltipTrigger/index.js"
import { Icon } from "../Icon/index.js"
import { Button } from "../Button/index.js"
import { Tooltip } from "./index"
import { TooltipContent } from "../TooltipContent/index"
import { TooltipTrigger } from "../TooltipTrigger/index"
import { Icon } from "../Icon/index"
import { ToolTipVariant, TooltipPlacement } from "./ToolTip.types"

export default {
title: "Components/Tooltip/Tooltip",
Expand All @@ -30,15 +29,36 @@ export default {
},
},
decorators: [
(Story) => (
(Story: React.FC) => (
<div className="jn-my-6 jn-flex jn-justify-center">
<Story />
</div>
),
],
}

const Template = ({ placement, variant, initialOpen, open, triggerEvent, disabled, text, triggerText, ...args }) => {
interface TemplateProps {
placement?: TooltipPlacement
variant?: ToolTipVariant
initialOpen?: boolean
open?: boolean
triggerEvent?: "click" | "hover"
disabled?: boolean
text?: string
triggerText?: string
}

const Template = ({
placement,
variant,
initialOpen,
open,
triggerEvent,
disabled,
text,
triggerText,
...args
}: TemplateProps) => {
return (
<Tooltip
initialOpen={initialOpen}
Expand All @@ -48,25 +68,25 @@ const Template = ({ placement, variant, initialOpen, open, triggerEvent, disable
triggerEvent={triggerEvent}
disabled={disabled}
>
<TooltipTrigger>{triggerText}</TooltipTrigger>
<TooltipTrigger>
{/* Wrap the triggerText in a JSX element */}
<span key="tooltip-trigger-text">{triggerText}</span>
</TooltipTrigger>
<TooltipContent {...args}>{text}</TooltipContent>
</Tooltip>
)
}

// define available prop types
Template.propTypes = {
placement: PropTypes.oneOf(["top", "bottom", "left", "right"]),
variant: PropTypes.oneOf(["info", "warning", "error", "danger", "success"]),
initialOpen: PropTypes.bool,
open: PropTypes.bool,
triggerEvent: PropTypes.oneOf(["click", "hover"]),
disabled: PropTypes.bool,
text: PropTypes.string,
triggerText: PropTypes.string,
}

const TemplateAsChildAnchor = ({ initialOpen, placement, variant, open, triggerEvent, disabled, text, ...args }) => {
const TemplateAsChildAnchor = ({
initialOpen,
placement,
variant,
open,
triggerEvent,
disabled,
text,
...args
}: TemplateProps) => {
return (
<Tooltip
initialOpen={initialOpen}
Expand All @@ -84,17 +104,6 @@ const TemplateAsChildAnchor = ({ initialOpen, placement, variant, open, triggerE
)
}

// define available prop types
TemplateAsChildAnchor.propTypes = {
placement: PropTypes.oneOf(["top", "bottom", "left", "right"]),
variant: PropTypes.oneOf(["info", "warning", "error", "danger", "success"]),
initialOpen: PropTypes.bool,
open: PropTypes.bool,
triggerEvent: PropTypes.oneOf(["click", "hover"]),
disabled: PropTypes.bool,
text: PropTypes.string,
}

const TemplateButtonAsChildAnchor = ({
initialOpen,
placement,
Expand All @@ -104,7 +113,7 @@ const TemplateButtonAsChildAnchor = ({
disabled,
text,
...args
}) => {
}: TemplateProps) => {
return (
<Tooltip
initialOpen={initialOpen}
Expand All @@ -115,24 +124,16 @@ const TemplateButtonAsChildAnchor = ({
disabled={disabled}
>
<TooltipTrigger asChild={true}>
<Button label="hover me" />
<TooltipTrigger>
{/* Wrap the triggerText in a JSX element */}
<button>hover me</button>
</TooltipTrigger>
</TooltipTrigger>
<TooltipContent {...args}>{text}</TooltipContent>
</Tooltip>
)
}

// define available prop types
TemplateButtonAsChildAnchor.propTypes = {
placement: PropTypes.oneOf(["top", "bottom", "left", "right"]),
variant: PropTypes.oneOf(["info", "warning", "error", "danger", "success"]),
initialOpen: PropTypes.bool,
open: PropTypes.bool,
triggerEvent: PropTypes.oneOf(["click", "hover"]),
disabled: PropTypes.bool,
text: PropTypes.string,
}

export const Default = {
render: Template,

Expand Down
Loading

0 comments on commit 990af5a

Please sign in to comment.