Skip to content

Commit

Permalink
feat: Add tooltip support
Browse files Browse the repository at this point in the history
  • Loading branch information
Sidnioulz committed Nov 6, 2024
1 parent 4ce1bd1 commit 9d10d64
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 25 deletions.
31 changes: 22 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
- [Default Config](#-default-config)
- [Usage](#-usage)
- [Customise Badge Config](#️-customise-badge-config)
- [Sidebar Label Customisations](#️sidebar-label-customisations)
- [Workflow Examples](#-workflow-examples)
- [Limitations](#-limitations)
- [Contributing](#-contributing)
Expand Down Expand Up @@ -243,13 +242,14 @@ The `badge` property defines the appearance and content of the badge to display.

The object has the following properties:

| Name | Type | Description | Example |
| --------------- | --------- | ----------------------------------------------------------------- | ------------------------ |
| **text** | `string` | The text displayed in the badge (required). | 'New' |
| **bgColor** | `string?` | The CSS property passed to `background-color`. | '#aea' |
| **fgColor** | `string?` | The CSS property passed to `color`. | '#2f2' |
| **borderColor** | `string?` | A border colour, rendered as a CSS box-shadow. | '#2f2' |
| **tooltip** | `string?` | A tooltip text shown when clicking the badge in the toolbar only. | 'This component is new!' |
| Name | Type | Description | Example |
| --------------- | -------------------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| **text** | `string` | The text displayed in the badge (required). | 'New' |
| **bgColor** | `string?` | The CSS property passed to `background-color`. | '#aea' |
| **fgColor** | `string?` | The CSS property passed to `color`. | '#2f2' |
| **borderColor** | `string?` | A border colour, rendered as a CSS box-shadow. | '#2f2' |
| **tooltip** | `string \| TooltipMessageProps?` | A tooltip shown on click in the toolbar only. | `'This component is new!'` or `{ title: 'New Component', desc: 'Recently added to the library' }` |


#### Dynamic Badge Functions

Expand Down Expand Up @@ -288,7 +288,20 @@ addons.setConfig({
})
```

## Sidebar Label Customisations
### Tooltip

Badges may have a tooltip when displayed in the toolbar. The tooltip is disabled in the sidebar to avoid conflicting with the sidebar's function, though feedback is welcome on this.

You may pass a string to tooltips for a simple tooltip. You may also pass the same objects used by [Storybook's `TooltipMessage`](https://5ccbc373887ca40020446347-idzavsdems.chromatic.com/?path=/docs/tooltip-tooltipmessage--docs):

* `title`: The title of the tooltip *[string]*
* `desc`: Secondary text for the tooltip *[string]*
* `links`: An optional array of link objects displayed as buttons *[object[]]*
* `title`: The title of the link
* `href`: The URL to which the link points (navigates in-place)
* `onClick`: A callback when the link is clicked (can be used to navigate in a new browser tab)

### Sidebar Label Customisations

This addon uses the [sidebar `renderLabel` feature](https://storybook.js.org/docs/configure/user-interface/sidebar-and-urls) to display badges in the sidebar. If you define it for other purposes in your Storybook instance, it will conflict with this addon and sidebar badges won't show.

Expand Down
44 changes: 42 additions & 2 deletions src/components/Badge.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ const meta: Meta<typeof Badge> = {
options: ['sidebar', 'toolbar'],
description: 'Whether the badge renders in the sidebar or toolbar',
},
tooltip: {
description: 'Tooltip content; either as string or TooltipMessage props',
control: false,
},
},
tags: ['autodocs'],
parameters: {
Expand Down Expand Up @@ -62,10 +66,46 @@ export const ColorAndBorders: Story = {
},
}

export const Tooltip: Story = {
export const SimpleTooltip: Story = {
args: {
context: 'toolbar',
text: 'Text',
tooltip: 'This badge has a simple string tooltip!',
},
}

export const RichTooltip: Story = {
args: {
context: 'toolbar',
text: 'Text',
tooltip: {
title: 'Rich Tooltip',
desc: 'This badge uses a TooltipMessage component with title and description',
},
},
}

export const RichTooltipWithLink: Story = {
args: {
context: 'toolbar',
text: 'Text',
tooltip: 'This badge has a tooltip!',
tooltip: {
title: 'Rich Tooltip',
desc: 'This badge uses a TooltipMessage component with title and description',
links: [
{
title: 'Storybook',
href: 'https://storybook.js.org/',
},
],
},
},
}

export const SidebarBadge: Story = {
args: {
context: 'sidebar',
text: 'Text',
tooltip: 'Tooltips are disabled in the sidebar',
},
}
23 changes: 11 additions & 12 deletions src/components/Badge.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,15 @@
import React, { Fragment } from 'react'
import type { HashEntry } from '@storybook/manager-api'
import { WithTooltip } from '@storybook/components'
import { WithTooltip, TooltipMessage } from '@storybook/components'
import { styled, useTheme } from '@storybook/theming'

import type { BadgeOrBadgeFn } from '../types/Badge'
import type { Badge as BadgeConfigType, BadgeOrBadgeFn } from '../types/Badge'
import { getTagParts, getTagPrefix, getTagSuffix } from '../utils/tag'

interface BadgeProps {
interface BadgeProps extends BadgeConfigType {
context: 'sidebar' | 'toolbar'
/**
* The content of the Badge
*/
text: string
bgColor?: string
borderColor?: string
fgColor?: string
tooltip?: string
}

interface WithBadgeProps {
config: BadgeOrBadgeFn
entry: HashEntry
Expand Down Expand Up @@ -74,7 +67,13 @@ export const Badge: React.FC<BadgeProps> = ({
<WithTooltipPatched
closeOnOutsideClick
placement={'bottom'}
tooltip={<TooltipUI>{tooltip}</TooltipUI>}
tooltip={
typeof tooltip === 'string' ? (
<TooltipUI>{tooltip}</TooltipUI>
) : (
<TooltipMessage {...tooltip} />
)
}
>
<BadgeUI as="button" {...restProps} context={context} theme={theme}>
{text}
Expand Down
15 changes: 14 additions & 1 deletion src/components/__tests__/Badge.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ describe('Badge', () => {
expect(badge).toBeInTheDocument()
})

it('renders as a button in the toolbar when tooltip is set', async () => {
it('renders as a button in the toolbar when tooltip is set as string', async () => {
const text = 'Tooltip Badge'
const tooltip = 'This is a tooltip'
renderWithTheme(<Badge context="toolbar" text={text} tooltip={tooltip} />)
Expand All @@ -58,6 +58,19 @@ describe('Badge', () => {
expect(badge.tagName).toBe('BUTTON')
})

it('renders as a button in the toolbar when tooltip is set as TooltipMessage props', async () => {
const text = 'Tooltip Badge'
const tooltip = {
title: 'Tooltip Title',
desc: 'Tooltip Description',
}
renderWithTheme(<Badge context="toolbar" text={text} tooltip={tooltip} />)

const badge = await screen.findByText(text)
expect(badge).toBeInTheDocument()
expect(badge.tagName).toBe('BUTTON')
})

it('ignores tooltip in the sidebar', async () => {
const text = 'Tooltip Badge'
const tooltip = 'This is a tooltip'
Expand Down
4 changes: 3 additions & 1 deletion src/types/Badge.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { ComponentProps } from 'react'
import type { TooltipMessage } from '@storybook/components'
import type { HashEntry } from '@storybook/manager-api'
import { getTagParts, getTagPrefix, getTagSuffix } from 'src/utils/tag'

Expand All @@ -14,7 +16,7 @@ export interface Badge {
/** The foreground (text) colour of the badge (optional). */
fgColor?: string
/** The tooltip text to display when hovering over the badge (optional). */
tooltip?: string
tooltip?: string | ComponentProps<typeof TooltipMessage>
}

/**
Expand Down

0 comments on commit 9d10d64

Please sign in to comment.