From d1f650721488727a272f3494152e0fcd386fc463 Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Mon, 4 Nov 2024 18:37:09 +0000 Subject: [PATCH 1/5] Convert Tooltip to CSS modules behind team flag --- .../react/src/TooltipV2/Tooltip.module.css | 117 ++++++++++ packages/react/src/TooltipV2/Tooltip.tsx | 202 ++++++++++-------- 2 files changed, 224 insertions(+), 95 deletions(-) create mode 100644 packages/react/src/TooltipV2/Tooltip.module.css diff --git a/packages/react/src/TooltipV2/Tooltip.module.css b/packages/react/src/TooltipV2/Tooltip.module.css new file mode 100644 index 00000000000..5710113f4e4 --- /dev/null +++ b/packages/react/src/TooltipV2/Tooltip.module.css @@ -0,0 +1,117 @@ +.Tooltip { + /* Overriding the default popover styles */ + display: none; + + &[popover] { + position: absolute; + width: max-content; + max-width: 250px; + padding: 0.5em 0.75em; + margin: auto; + + /* for scrollbar */ + overflow: visible; + clip: auto; + font: var(--text-body-shorthand-small); + 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%; + margin-left: -8px; + content: ''; + } + + /* Animation definition */ + @keyframes tooltip-appear { + from { + opacity: 0; + } + + to { + opacity: 1; + } + } + + /* 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; + } +} diff --git a/packages/react/src/TooltipV2/Tooltip.tsx b/packages/react/src/TooltipV2/Tooltip.tsx index 7a1eebf66a3..e63f70b49dd 100644 --- a/packages/react/src/TooltipV2/Tooltip.tsx +++ b/packages/react/src/TooltipV2/Tooltip.tsx @@ -10,6 +10,12 @@ 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; @@ -19,109 +25,113 @@ 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< @@ -187,11 +197,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) const tooltipElRef = useRef(null) + const enabled = useFeatureFlag(CSS_MODULE_FEATURE_FLAG) const [calculatedDirection, setCalculatedDirection] = useState(direction) @@ -355,6 +366,7 @@ export const Tooltip = React.forwardRef( }, })} Date: Mon, 4 Nov 2024 15:06:50 -0800 Subject: [PATCH 2/5] Create lazy-mugs-care.md --- .changeset/lazy-mugs-care.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/lazy-mugs-care.md diff --git a/.changeset/lazy-mugs-care.md b/.changeset/lazy-mugs-care.md new file mode 100644 index 00000000000..f02e4272bbc --- /dev/null +++ b/.changeset/lazy-mugs-care.md @@ -0,0 +1,5 @@ +--- +"@primer/react": minor +--- + +feat(Tooltip): Convert Tooltip to CSS modules behind team flag From e03625de6842c718046a369747df2c99f3758c10 Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Thu, 7 Nov 2024 18:02:53 +0000 Subject: [PATCH 3/5] Moving the animation out and fixing the font Co-authored-by: Keith Cirkel --- .../react/src/TooltipV2/Tooltip.module.css | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/packages/react/src/TooltipV2/Tooltip.module.css b/packages/react/src/TooltipV2/Tooltip.module.css index 5710113f4e4..6508dc39fc7 100644 --- a/packages/react/src/TooltipV2/Tooltip.module.css +++ b/packages/react/src/TooltipV2/Tooltip.module.css @@ -1,3 +1,14 @@ +/* Animation definition */ +@keyframes tooltip-appear { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} + .Tooltip { /* Overriding the default popover styles */ display: none; @@ -6,13 +17,15 @@ 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; - font: var(--text-body-shorthand-small); + /* 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; @@ -80,21 +93,11 @@ display: block; width: 8px; height: 100%; + /* stylelint-disable-next-line primer/spacing */ margin-left: -8px; content: ''; } - /* Animation definition */ - @keyframes tooltip-appear { - from { - opacity: 0; - } - - to { - opacity: 1; - } - } - /* Animation styles */ &:popover-open, &:popover-open::before { From 03a33aa1074672fcd7d720dc05c710d98f43ee35 Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Thu, 7 Nov 2024 18:24:35 +0000 Subject: [PATCH 4/5] Fix types --- packages/react/src/TooltipV2/Tooltip.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/react/src/TooltipV2/Tooltip.tsx b/packages/react/src/TooltipV2/Tooltip.tsx index e63f70b49dd..dbdd27c2564 100644 --- a/packages/react/src/TooltipV2/Tooltip.tsx +++ b/packages/react/src/TooltipV2/Tooltip.tsx @@ -139,9 +139,9 @@ export type TooltipProps = React.PropsWithChildren< direction?: TooltipDirection text: string type?: 'label' | 'description' - } & SxProp & - ComponentProps -> + } & SxProp +> & + React.HTMLAttributes type TriggerPropsType = { 'aria-describedby'?: string From 8526ec20082ae6c33fd384157d4d68b3ddf2fea4 Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Thu, 7 Nov 2024 18:28:38 +0000 Subject: [PATCH 5/5] Lint --- packages/react/src/TooltipV2/Tooltip.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/react/src/TooltipV2/Tooltip.tsx b/packages/react/src/TooltipV2/Tooltip.tsx index dbdd27c2564..ba265568501 100644 --- a/packages/react/src/TooltipV2/Tooltip.tsx +++ b/packages/react/src/TooltipV2/Tooltip.tsx @@ -6,7 +6,6 @@ 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'