Skip to content

Commit

Permalink
feat(Tooltip): Convert Tooltip to CSS modules behind team flag (#5228)
Browse files Browse the repository at this point in the history
* Convert Tooltip to CSS modules behind team flag

* Create lazy-mugs-care.md

* Moving the animation out and fixing the font

Co-authored-by: Keith Cirkel <keithamus@users.noreply.github.com>

* Fix types

* Lint

---------

Co-authored-by: Keith Cirkel <keithamus@users.noreply.github.com>
  • Loading branch information
jonrohan and keithamus authored Nov 7, 2024
1 parent f743717 commit 2da7336
Show file tree
Hide file tree
Showing 3 changed files with 235 additions and 99 deletions.
5 changes: 5 additions & 0 deletions .changeset/lazy-mugs-care.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@primer/react": minor
---

feat(Tooltip): Convert Tooltip to CSS modules behind team flag
120 changes: 120 additions & 0 deletions packages/react/src/TooltipV2/Tooltip.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/* Animation definition */
@keyframes tooltip-appear {
from {
opacity: 0;
}

to {
opacity: 1;
}
}

.Tooltip {
/* Overriding the default popover styles */
display: none;

&[popover] {
position: absolute;
width: max-content;
max-width: 250px;
/* stylelint-disable-next-line primer/spacing */
padding: 0.5em 0.75em;
margin: auto;

/* for scrollbar */
overflow: visible;
clip: auto;
/* stylelint-disable-next-line primer/typography */
font: normal normal 11px/1.5 var(--fontStack-system);
color: var(--tooltip-fgColor);
text-align: center;
word-wrap: break-word;
white-space: normal;
background: var(--tooltip-bgColor);
border: 0;
border-radius: var(--borderRadius-medium);
opacity: 0;
-webkit-font-smoothing: subpixel-antialiased;
inset: auto;
}

/* class name in chrome is :popover-open */
&[popover]:popover-open {
display: block;
}

/* class name in firefox and safari is \:popover-open */
&[popover].\\:popover-open {
display: block;
}

@media (forced-colors: active) {
outline: 1px solid transparent;
}

/* This is needed to keep the tooltip open when the user leaves the trigger element to hover tooltip */
&::after {
position: absolute;
right: 0;
left: 0;
display: block;
height: var(--overlay-offset);
content: '';
}

/* South, East, Southeast, Southwest after */
&[data-direction='n']::after,
&[data-direction='ne']::after,
&[data-direction='nw']::after {
top: 100%;
}

&[data-direction='s']::after,
&[data-direction='se']::after,
&[data-direction='sw']::after {
bottom: 100%;
}

&[data-direction='w']::after {
position: absolute;
bottom: 0;
left: 100%;
display: block;
width: 8px;
height: 100%;
content: '';
}

/* East before and after */
&[data-direction='e']::after {
position: absolute;
right: 100%;
bottom: 0;
display: block;
width: 8px;
height: 100%;
/* stylelint-disable-next-line primer/spacing */
margin-left: -8px;
content: '';
}

/* Animation styles */
&:popover-open,
&:popover-open::before {
animation-name: tooltip-appear;
animation-duration: 0.1s;
animation-fill-mode: forwards;
animation-timing-function: ease-in;
animation-delay: 0s;
}

/* Animation styles */
&.\\:popover-open,
&.\\:popover-open::before {
animation-name: tooltip-appear;
animation-duration: 0.1s;
animation-fill-mode: forwards;
animation-timing-function: ease-in;
animation-delay: 0s;
}
}
209 changes: 110 additions & 99 deletions packages/react/src/TooltipV2/Tooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,15 @@ import {invariant} from '../utils/invariant'
import {warning} from '../utils/warning'
import styled from 'styled-components'
import {get} from '../constants'
import type {ComponentProps} from '../utils/types'
import {getAnchoredPosition} from '@primer/behaviors'
import type {AnchorSide, AnchorAlignment} from '@primer/behaviors'
import {isSupported, apply} from '@oddbird/popover-polyfill/fn'
import {toggleStyledComponent} from '../internal/utils/toggleStyledComponent'
import {clsx} from 'clsx'
import classes from './Tooltip.module.css'
import {useFeatureFlag} from '../FeatureFlags'

const CSS_MODULE_FEATURE_FLAG = 'primer_react_css_modules_team'

const animationStyles = `
animation-name: tooltip-appear;
Expand All @@ -19,119 +24,123 @@ const animationStyles = `
animation-delay: 0s;
`

const StyledTooltip = styled.span`
/* Overriding the default popover styles */
display: none;
&[popover] {
position: absolute;
padding: 0.5em 0.75em;
width: max-content;
margin: auto;
clip: auto;
white-space: normal;
font: normal normal 11px/1.5 ${get('fonts.normal')};
-webkit-font-smoothing: subpixel-antialiased;
color: var(--tooltip-fgColor, ${get('colors.fg.onEmphasis')});
text-align: center;
word-wrap: break-word;
background: var(--tooltip-bgColor, ${get('colors.neutral.emphasisPlus')});
border-radius: ${get('radii.2')};
border: 0;
opacity: 0;
max-width: 250px;
inset: auto;
/* for scrollbar */
overflow: visible;
}
/* class name in chrome is :popover-open */
&[popover]:popover-open {
display: block;
}
/* class name in firefox and safari is \:popover-open */
&[popover].\\:popover-open {
display: block;
}
const StyledTooltip = toggleStyledComponent(
CSS_MODULE_FEATURE_FLAG,
'span',
styled.span`
/* Overriding the default popover styles */
display: none;
&[popover] {
position: absolute;
padding: 0.5em 0.75em;
width: max-content;
margin: auto;
clip: auto;
white-space: normal;
font: normal normal 11px/1.5 ${get('fonts.normal')};
-webkit-font-smoothing: subpixel-antialiased;
color: var(--tooltip-fgColor, ${get('colors.fg.onEmphasis')});
text-align: center;
word-wrap: break-word;
background: var(--tooltip-bgColor, ${get('colors.neutral.emphasisPlus')});
border-radius: ${get('radii.2')};
border: 0;
opacity: 0;
max-width: 250px;
inset: auto;
/* for scrollbar */
overflow: visible;
}
/* class name in chrome is :popover-open */
&[popover]:popover-open {
display: block;
}
/* class name in firefox and safari is \:popover-open */
&[popover].\\:popover-open {
display: block;
}
@media (forced-colors: active) {
outline: 1px solid transparent;
}
@media (forced-colors: active) {
outline: 1px solid transparent;
}
// This is needed to keep the tooltip open when the user leaves the trigger element to hover tooltip
&::after {
position: absolute;
display: block;
right: 0;
left: 0;
height: var(--overlay-offset, 0.25rem);
content: '';
}
// This is needed to keep the tooltip open when the user leaves the trigger element to hover tooltip
&::after {
position: absolute;
display: block;
right: 0;
left: 0;
height: var(--overlay-offset, 0.25rem);
content: '';
}
/* South, East, Southeast, Southwest after */
&[data-direction='n']::after,
&[data-direction='ne']::after,
&[data-direction='nw']::after {
top: 100%;
}
&[data-direction='s']::after,
&[data-direction='se']::after,
&[data-direction='sw']::after {
bottom: 100%;
}
/* South, East, Southeast, Southwest after */
&[data-direction='n']::after,
&[data-direction='ne']::after,
&[data-direction='nw']::after {
top: 100%;
}
&[data-direction='s']::after,
&[data-direction='se']::after,
&[data-direction='sw']::after {
bottom: 100%;
}
&[data-direction='w']::after {
position: absolute;
display: block;
height: 100%;
width: 8px;
content: '';
bottom: 0;
left: 100%;
}
/* East before and after */
&[data-direction='e']::after {
position: absolute;
display: block;
height: 100%;
width: 8px;
content: '';
bottom: 0;
right: 100%;
margin-left: -8px;
}
&[data-direction='w']::after {
position: absolute;
display: block;
height: 100%;
width: 8px;
content: '';
bottom: 0;
left: 100%;
}
/* East before and after */
&[data-direction='e']::after {
position: absolute;
display: block;
height: 100%;
width: 8px;
content: '';
bottom: 0;
right: 100%;
margin-left: -8px;
}
/* Animation definition */
@keyframes tooltip-appear {
from {
opacity: 0;
/* Animation definition */
@keyframes tooltip-appear {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
to {
opacity: 1;
/* Animation styles */
&:popover-open,
&:popover-open::before {
${animationStyles}
}
}
/* Animation styles */
&:popover-open,
&:popover-open::before {
${animationStyles}
}
/* Animation styles */
&.\\:popover-open,
&.\\:popover-open::before {
${animationStyles}
}
/* Animation styles */
&.\\:popover-open,
&.\\:popover-open::before {
${animationStyles}
}
${sx};
`
${sx};
`,
)

export type TooltipDirection = 'nw' | 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w'
export type TooltipProps = React.PropsWithChildren<
{
direction?: TooltipDirection
text: string
type?: 'label' | 'description'
} & SxProp &
ComponentProps<typeof StyledTooltip>
>
} & SxProp
> &
React.HTMLAttributes<HTMLElement>

type TriggerPropsType = {
'aria-describedby'?: string
Expand Down Expand Up @@ -187,11 +196,12 @@ const isInteractive = (element: HTMLElement) => {
export const TooltipContext = React.createContext<{tooltipId?: string}>({})

export const Tooltip = React.forwardRef(
({direction = 's', text, type = 'description', children, id, ...rest}: TooltipProps, forwardedRef) => {
({direction = 's', text, type = 'description', children, id, className, ...rest}: TooltipProps, forwardedRef) => {
const tooltipId = useId(id)
const child = Children.only(children)
const triggerRef = useProvidedRefOrCreate(forwardedRef as React.RefObject<HTMLElement>)
const tooltipElRef = useRef<HTMLDivElement>(null)
const enabled = useFeatureFlag(CSS_MODULE_FEATURE_FLAG)

const [calculatedDirection, setCalculatedDirection] = useState<TooltipDirection>(direction)

Expand Down Expand Up @@ -355,6 +365,7 @@ export const Tooltip = React.forwardRef(
},
})}
<StyledTooltip
className={clsx(className, {[classes.Tooltip]: enabled})}
ref={tooltipElRef}
data-direction={calculatedDirection}
{...rest}
Expand Down

0 comments on commit 2da7336

Please sign in to comment.