From f427dbfa53bde2742412ae2f8e0931fcd7ea9d31 Mon Sep 17 00:00:00 2001 From: Siddharth Kshetrapal Date: Wed, 30 Mar 2022 14:47:06 +0200 Subject: [PATCH 01/26] Add breaking story --- .../behaviors-anchored-position.stories.tsx | 178 ++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 src/stories/behaviors-anchored-position.stories.tsx diff --git a/src/stories/behaviors-anchored-position.stories.tsx b/src/stories/behaviors-anchored-position.stories.tsx new file mode 100644 index 00000000000..2e73c5f9af9 --- /dev/null +++ b/src/stories/behaviors-anchored-position.stories.tsx @@ -0,0 +1,178 @@ +import React from 'react' +import {Meta} from '@storybook/react' +import {SmileyIcon, KebabHorizontalIcon} from '@primer/octicons-react' +import {createGlobalStyle} from 'styled-components' +import {BaseStyles, Box, ThemeProvider, Text, IconButton, PageLayout, Heading} from '..' +import {useAnchoredPosition} from '../hooks' + +export default { + title: 'Behaviors/anchoredPosition', + decorators: [ + // Note: For some reason, if you use , + // the component gets unmounted from the root every time a control changes! + Story => { + return ( + + {Story()} + + ) + } + ] +} as Meta + +export const BoundaryCollisions = () => { + const reactionButtonRef = React.useRef(null) + const reactionTooltipRef = React.useRef(null) + + const {position: reactionTooltipPosition} = useAnchoredPosition({ + side: 'outside-bottom', + align: 'start', + anchorElementRef: reactionButtonRef, + floatingElementRef: reactionTooltipRef + }) + + const optionsButtonRef = React.useRef(null) + const optionsTooltipRef = React.useRef(null) + const {position: optionsTooltipPosition} = useAnchoredPosition({ + side: 'outside-bottom', + align: 'start', + anchorElementRef: optionsButtonRef, + floatingElementRef: optionsTooltipRef + }) + + return ( + <> + + + + + Input validation styles #1831 + + + + + + + + + + + Add reaction + + + + + + + + + + Assignees + No one – assign yourself + + + + Labels + None yet + + + + + + + + + + Input validation styles #1831 + + + + + + + + + + + + + Add reaction + + + + + + + + Assignees + No one – assign yourself + + + + Labels + None yet + + + + + + ) +} From 8772f31a52ce650d5e5b0ddfd2f3f06df840a0c9 Mon Sep 17 00:00:00 2001 From: Siddharth Kshetrapal Date: Wed, 30 Mar 2022 16:42:28 +0200 Subject: [PATCH 02/26] Add memex story --- .../behaviors-anchored-position.stories.tsx | 257 +++++++++++------- 1 file changed, 163 insertions(+), 94 deletions(-) diff --git a/src/stories/behaviors-anchored-position.stories.tsx b/src/stories/behaviors-anchored-position.stories.tsx index 2e73c5f9af9..90e18341453 100644 --- a/src/stories/behaviors-anchored-position.stories.tsx +++ b/src/stories/behaviors-anchored-position.stories.tsx @@ -1,8 +1,7 @@ import React from 'react' import {Meta} from '@storybook/react' -import {SmileyIcon, KebabHorizontalIcon} from '@primer/octicons-react' -import {createGlobalStyle} from 'styled-components' -import {BaseStyles, Box, ThemeProvider, Text, IconButton, PageLayout, Heading} from '..' +import {SmileyIcon, KebabHorizontalIcon, TriangleDownIcon} from '@primer/octicons-react' +import {BaseStyles, Box, ThemeProvider, Text, IconButton, PageLayout, Heading, ActionMenu, ActionList} from '..' import {useAnchoredPosition} from '../hooks' export default { @@ -20,17 +19,38 @@ export default { ] } as Meta -export const BoundaryCollisions = () => { - const reactionButtonRef = React.useRef(null) - const reactionTooltipRef = React.useRef(null) - - const {position: reactionTooltipPosition} = useAnchoredPosition({ - side: 'outside-bottom', - align: 'start', - anchorElementRef: reactionButtonRef, - floatingElementRef: reactionTooltipRef - }) +type TooltipProps = { + children: string + position?: {left: number; top: number} + defaultVisible?: boolean +} +const Tooltip = React.forwardRef(({defaultVisible, position, children}, ref) => { + return ( + + {children} + + ) +}) +export const Tooltips = () => { + const [optionsOpen, setOptionsOpen] = React.useState(false) const optionsButtonRef = React.useRef(null) const optionsTooltipRef = React.useRef(null) const {position: optionsTooltipPosition} = useAnchoredPosition({ @@ -40,6 +60,16 @@ export const BoundaryCollisions = () => { floatingElementRef: optionsTooltipRef }) + const [reactionsOpen, setReactionsOpen] = React.useState(false) + const reactionButtonRef = React.useRef(null) + const reactionTooltipRef = React.useRef(null) + const {position: reactionTooltipPosition} = useAnchoredPosition({ + side: 'outside-bottom', + align: 'start', + anchorElementRef: reactionButtonRef, + floatingElementRef: reactionTooltipRef + }) + return ( <> @@ -64,98 +94,66 @@ export const BoundaryCollisions = () => { alignItems: 'center' }} > - - - Add reaction + setReactionsOpen(!reactionsOpen)} + /> + + Add reaction + - - - - - - - - - Assignees - No one – assign yourself - - - - Labels - None yet - - - - - - - - - - Input validation styles #1831 - - - - - - - - - - + + + + {['👍', '👎', '😄', '🎉', '😕', '❤️', '🚀', '👀'].map(emoji => ( + {emoji} + ))} + + + - Add reaction + setOptionsOpen(!optionsOpen)} + /> + + Show options + + + + + Copy link + Quote reply + + Edit + + + @@ -176,3 +174,74 @@ export const BoundaryCollisions = () => { ) } + +export function MemexTableMenu(): JSX.Element { + return ( + <> + + + Primer teams backlog + + + + + + Title + Assignees + Status + Labels + Repository + + + + ) +} + +const TableHeader: React.FC<{style?: Record}> = props => { + return ( + + {props.children} + + + + + + + + Sort ascending (123...) + Sort descending (123...) + + Filter by values + Group by values + + Delete file + + + + + ) +} From b9cbf8c4ea585fc3916a9c52adba6ce80e83a2a6 Mon Sep 17 00:00:00 2001 From: Siddharth Kshetrapal Date: Wed, 30 Mar 2022 16:48:16 +0200 Subject: [PATCH 03/26] use behaviors deploy preview --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 149f5b67255..cf8097b2eaf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "35.1.0", "license": "MIT", "dependencies": { - "@primer/behaviors": "1.1.0", + "@primer/behaviors": "0.0.0-2022230144424", "@primer/octicons-react": "16.1.1", "@primer/primitives": "7.6.0", "@radix-ui/react-polymorphic": "0.0.14", @@ -5643,9 +5643,9 @@ } }, "node_modules/@primer/behaviors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@primer/behaviors/-/behaviors-1.1.0.tgz", - "integrity": "sha512-Ej2OUc3ZIFaR7WwIUqESO1DTzmpb7wc8xbTVRT9s52jZQDjN7g5iljoK3ocYZm+BIAcKn3MvcwB42hEk4Ga4xQ==" + "version": "0.0.0-2022230144424", + "resolved": "https://registry.npmjs.org/@primer/behaviors/-/behaviors-0.0.0-2022230144424.tgz", + "integrity": "sha512-lgPWBREqZLKe40RcYb5qKAoVFHPJbUoilaKWn5zxu1md0l0hOIJxMx4r6Mju2gxn8/QK+t+v40Pl/NF84UD1Lg==" }, "node_modules/@primer/octicons-react": { "version": "16.1.1", @@ -39281,9 +39281,9 @@ "dev": true }, "@primer/behaviors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@primer/behaviors/-/behaviors-1.1.0.tgz", - "integrity": "sha512-Ej2OUc3ZIFaR7WwIUqESO1DTzmpb7wc8xbTVRT9s52jZQDjN7g5iljoK3ocYZm+BIAcKn3MvcwB42hEk4Ga4xQ==" + "version": "0.0.0-2022230144424", + "resolved": "https://registry.npmjs.org/@primer/behaviors/-/behaviors-0.0.0-2022230144424.tgz", + "integrity": "sha512-lgPWBREqZLKe40RcYb5qKAoVFHPJbUoilaKWn5zxu1md0l0hOIJxMx4r6Mju2gxn8/QK+t+v40Pl/NF84UD1Lg==" }, "@primer/octicons-react": { "version": "16.1.1", diff --git a/package.json b/package.json index a131dec5295..b0718283113 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "npm": ">=7" }, "dependencies": { - "@primer/behaviors": "1.1.0", + "@primer/behaviors": "0.0.0-2022230144424", "@primer/octicons-react": "16.1.1", "@primer/primitives": "7.6.0", "@radix-ui/react-polymorphic": "0.0.14", From 3aaf1f4530e2ac48dd0d8baa10cfe588b0584cb7 Mon Sep 17 00:00:00 2001 From: Siddharth Kshetrapal Date: Wed, 30 Mar 2022 17:51:14 +0200 Subject: [PATCH 04/26] add tooltip triangle --- .../behaviors-anchored-position.stories.tsx | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/stories/behaviors-anchored-position.stories.tsx b/src/stories/behaviors-anchored-position.stories.tsx index 90e18341453..52e5a38f441 100644 --- a/src/stories/behaviors-anchored-position.stories.tsx +++ b/src/stories/behaviors-anchored-position.stories.tsx @@ -3,6 +3,7 @@ import {Meta} from '@storybook/react' import {SmileyIcon, KebabHorizontalIcon, TriangleDownIcon} from '@primer/octicons-react' import {BaseStyles, Box, ThemeProvider, Text, IconButton, PageLayout, Heading, ActionMenu, ActionList} from '..' import {useAnchoredPosition} from '../hooks' +import type {AnchorAlignment} from '@primer/behaviors' export default { title: 'Behaviors/anchoredPosition', @@ -21,7 +22,7 @@ export default { type TooltipProps = { children: string - position?: {left: number; top: number} + position?: {left: number; top: number; anchorAlign: AnchorAlignment} defaultVisible?: boolean } const Tooltip = React.forwardRef(({defaultVisible, position, children}, ref) => { @@ -44,6 +45,28 @@ const Tooltip = React.forwardRef(({defaultVisible, left: position?.left }} > + {children} ) @@ -99,7 +122,7 @@ export const Tooltips = () => { sx={{ mr: 2, ':hover': { - '[data-component=tooltip]': {visibility: 'visible'} + '[data-component=tooltip]': {visibility: reactionsOpen ? 'hidden' : 'visible'} } }} > From 67a5eedfaaa206acf1677ce29218b5cf20659dd6 Mon Sep 17 00:00:00 2001 From: Siddharth Kshetrapal Date: Mon, 4 Apr 2022 13:08:22 +0200 Subject: [PATCH 05/26] update snapshot --- src/__tests__/hooks/useAnchoredPosition.test.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/__tests__/hooks/useAnchoredPosition.test.tsx b/src/__tests__/hooks/useAnchoredPosition.test.tsx index 4038ca73c0e..4b7d38dc710 100644 --- a/src/__tests__/hooks/useAnchoredPosition.test.tsx +++ b/src/__tests__/hooks/useAnchoredPosition.test.tsx @@ -23,6 +23,7 @@ it('should should return a position', () => { expect(cb).toHaveBeenCalledTimes(2) expect(cb.mock.calls[1][0]['position']).toMatchInlineSnapshot(` Object { + "anchorAlign": "start", "anchorSide": "outside-bottom", "left": 0, "top": 4, From 3ad30cce99746f53322f634b573a2f0164af7294 Mon Sep 17 00:00:00 2001 From: Siddharth Kshetrapal Date: Tue, 12 Apr 2022 11:17:17 +0200 Subject: [PATCH 06/26] add label tooltips for story --- .../behaviors-anchored-position.stories.tsx | 78 ++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/src/stories/behaviors-anchored-position.stories.tsx b/src/stories/behaviors-anchored-position.stories.tsx index 52e5a38f441..b3dbae32676 100644 --- a/src/stories/behaviors-anchored-position.stories.tsx +++ b/src/stories/behaviors-anchored-position.stories.tsx @@ -1,7 +1,21 @@ import React from 'react' import {Meta} from '@storybook/react' import {SmileyIcon, KebabHorizontalIcon, TriangleDownIcon} from '@primer/octicons-react' -import {BaseStyles, Box, ThemeProvider, Text, IconButton, PageLayout, Heading, ActionMenu, ActionList} from '..' +import { + BaseStyles, + Box, + ThemeProvider, + Text, + IconButton, + PageLayout, + Heading, + ActionMenu, + ActionList, + Avatar, + Label, + LabelProps, + Link +} from '..' import {useAnchoredPosition} from '../hooks' import type {AnchorAlignment} from '@primer/behaviors' @@ -39,6 +53,8 @@ const Tooltip = React.forwardRef(({defaultVisible, paddingY: 1, paddingX: 2, width: 'fit-content', + maxWidth: '250px', + textAlign: 'center', position: 'absolute', zIndex: 2, top: position?.top, @@ -72,6 +88,40 @@ const Tooltip = React.forwardRef(({defaultVisible, ) }) +const LabelWithTooltip: React.FC = ({ + description, + defaultVisible = false, + ...props +}) => { + const labelRef = React.useRef(null) + const tooltipRef = React.useRef(null) + + const {position} = useAnchoredPosition({ + side: 'outside-bottom', + align: 'center', + anchorElementRef: labelRef, + floatingElementRef: tooltipRef + }) + + return ( + + + + {description} + + + ) +} + export const Tooltips = () => { const [optionsOpen, setOptionsOpen] = React.useState(false) const optionsButtonRef = React.useRef(null) @@ -179,6 +229,32 @@ export const Tooltips = () => { + + colebemis{' '} + added{' '} + + bug + + + collab + + + blocked + + + dependencies + + + dependencies + + From 5a91f96553bb32fa66c8b3a7505e500bd02f4cb0 Mon Sep 17 00:00:00 2001 From: Siddharth Kshetrapal Date: Tue, 19 Apr 2022 14:28:16 +0200 Subject: [PATCH 07/26] update @primer/behaviors to latest --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index cf8097b2eaf..471c9f64cc8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "35.1.0", "license": "MIT", "dependencies": { - "@primer/behaviors": "0.0.0-2022230144424", + "@primer/behaviors": "^1.1.2", "@primer/octicons-react": "16.1.1", "@primer/primitives": "7.6.0", "@radix-ui/react-polymorphic": "0.0.14", @@ -5643,9 +5643,9 @@ } }, "node_modules/@primer/behaviors": { - "version": "0.0.0-2022230144424", - "resolved": "https://registry.npmjs.org/@primer/behaviors/-/behaviors-0.0.0-2022230144424.tgz", - "integrity": "sha512-lgPWBREqZLKe40RcYb5qKAoVFHPJbUoilaKWn5zxu1md0l0hOIJxMx4r6Mju2gxn8/QK+t+v40Pl/NF84UD1Lg==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@primer/behaviors/-/behaviors-1.1.2.tgz", + "integrity": "sha512-gMlUDRc2boyme1th2Sr0tVeH6VyWjFGwuraHj08HDlkfulJ7a6VT0YU0wtSnK1FtC45ZsTXNWOSiLwXWYmLR9g==" }, "node_modules/@primer/octicons-react": { "version": "16.1.1", @@ -39281,9 +39281,9 @@ "dev": true }, "@primer/behaviors": { - "version": "0.0.0-2022230144424", - "resolved": "https://registry.npmjs.org/@primer/behaviors/-/behaviors-0.0.0-2022230144424.tgz", - "integrity": "sha512-lgPWBREqZLKe40RcYb5qKAoVFHPJbUoilaKWn5zxu1md0l0hOIJxMx4r6Mju2gxn8/QK+t+v40Pl/NF84UD1Lg==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@primer/behaviors/-/behaviors-1.1.2.tgz", + "integrity": "sha512-gMlUDRc2boyme1th2Sr0tVeH6VyWjFGwuraHj08HDlkfulJ7a6VT0YU0wtSnK1FtC45ZsTXNWOSiLwXWYmLR9g==" }, "@primer/octicons-react": { "version": "16.1.1", diff --git a/package.json b/package.json index b0718283113..33c50c6937d 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "npm": ">=7" }, "dependencies": { - "@primer/behaviors": "0.0.0-2022230144424", + "@primer/behaviors": "^1.1.2", "@primer/octicons-react": "16.1.1", "@primer/primitives": "7.6.0", "@radix-ui/react-polymorphic": "0.0.14", From ecfb54e76444903bd572765dd24dc2a7bee4fdc5 Mon Sep 17 00:00:00 2001 From: Siddharth Kshetrapal Date: Tue, 19 Apr 2022 14:32:18 +0200 Subject: [PATCH 08/26] lint: remove unused import --- src/stories/behaviors-anchored-position.stories.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/stories/behaviors-anchored-position.stories.tsx b/src/stories/behaviors-anchored-position.stories.tsx index b3dbae32676..2917b954022 100644 --- a/src/stories/behaviors-anchored-position.stories.tsx +++ b/src/stories/behaviors-anchored-position.stories.tsx @@ -13,8 +13,7 @@ import { ActionList, Avatar, Label, - LabelProps, - Link + LabelProps } from '..' import {useAnchoredPosition} from '../hooks' import type {AnchorAlignment} from '@primer/behaviors' From 8a872c56af799588dd53522d428161e240eb31eb Mon Sep 17 00:00:00 2001 From: Siddharth Kshetrapal Date: Thu, 28 Apr 2022 18:01:12 +0200 Subject: [PATCH 09/26] Refactor Tooltip --- src/Tooltip.tsx | 263 ----------------------- src/Tooltip/Tooltip.examples.stories.tsx | 62 ++++++ src/Tooltip/Tooltip.fixtures.stories.tsx | 61 ++++++ src/Tooltip/index.tsx | 135 ++++++++++++ src/stories/Tooltip.stories.tsx | 37 ---- 5 files changed, 258 insertions(+), 300 deletions(-) delete mode 100644 src/Tooltip.tsx create mode 100644 src/Tooltip/Tooltip.examples.stories.tsx create mode 100644 src/Tooltip/Tooltip.fixtures.stories.tsx create mode 100644 src/Tooltip/index.tsx delete mode 100644 src/stories/Tooltip.stories.tsx diff --git a/src/Tooltip.tsx b/src/Tooltip.tsx deleted file mode 100644 index 0e3baa22b2d..00000000000 --- a/src/Tooltip.tsx +++ /dev/null @@ -1,263 +0,0 @@ -import classnames from 'classnames' -import React from 'react' -import styled from 'styled-components' -import {get} from './constants' -import sx, {SxProp} from './sx' -import {ComponentProps} from './utils/types' - -const TooltipBase = styled.span` - position: relative; - - &::before { - position: absolute; - z-index: 1000001; - display: none; - width: 0px; - height: 0px; - color: ${get('colors.neutral.emphasisPlus')}; - pointer-events: none; - content: ''; - border: 6px solid transparent; - opacity: 0; - } - - &::after { - position: absolute; - z-index: 1000000; - display: none; - padding: 0.5em 0.75em; - font: normal normal 11px/1.5 ${get('fonts.normal')}; - -webkit-font-smoothing: subpixel-antialiased; - color: ${get('colors.fg.onEmphasis')}; - text-align: center; - text-decoration: none; - text-shadow: none; - text-transform: none; - letter-spacing: normal; - word-wrap: break-word; - white-space: pre; - pointer-events: none; - content: attr(aria-label); - background: ${get('colors.neutral.emphasisPlus')}; - border-radius: ${get('radii.1')}; - opacity: 0; - } - - // delay animation for tooltip - @keyframes tooltip-appear { - from { - opacity: 0; - } - - to { - opacity: 1; - } - } - - &:hover, - &:active, - &:focus { - &::before, - &::after { - display: inline-block; - text-decoration: none; - animation-name: tooltip-appear; - animation-duration: 0.1s; - animation-fill-mode: forwards; - animation-timing-function: ease-in; - animation-delay: 0.4s; - } - } - - &.tooltipped-no-delay:hover, - &.tooltipped-no-delay:active, - &.tooltipped-no-delay:focus { - &::before, - &::after { - animation-delay: 0s; - } - } - - &.tooltipped-multiline:hover, - &.tooltipped-multiline:active, - &.tooltipped-multiline:focus { - &::after { - display: table-cell; - } - } - - // Tooltipped south - &.tooltipped-s, - &.tooltipped-se, - &.tooltipped-sw { - &::after { - top: 100%; - right: 50%; - margin-top: 6px; - } - - &::before { - top: auto; - right: 50%; - bottom: -7px; - margin-right: -6px; - border-bottom-color: ${get('colors.neutral.emphasisPlus')}; - } - } - - &.tooltipped-se { - &::after { - right: auto; - left: 50%; - margin-left: -${get('space.3')}; - } - } - - &.tooltipped-sw::after { - margin-right: -${get('space.3')}; - } - - // Tooltips above the object - &.tooltipped-n, - &.tooltipped-ne, - &.tooltipped-nw { - &::after { - right: 50%; - bottom: 100%; - margin-bottom: 6px; - } - - &::before { - top: -7px; - right: 50%; - bottom: auto; - margin-right: -6px; - border-top-color: ${get('colors.neutral.emphasisPlus')}; - } - } - - &.tooltipped-ne { - &::after { - right: auto; - left: 50%; - margin-left: -${get('space.3')}; - } - } - - &.tooltipped-nw::after { - margin-right: -${get('space.3')}; - } - - // Move the tooltip body to the center of the object. - &.tooltipped-s::after, - &.tooltipped-n::after { - transform: translateX(50%); - } - - // Tooltipped to the left - &.tooltipped-w { - &::after { - right: 100%; - bottom: 50%; - margin-right: 6px; - transform: translateY(50%); - } - - &::before { - top: 50%; - bottom: 50%; - left: -7px; - margin-top: -6px; - border-left-color: ${get('colors.neutral.emphasisPlus')}; - } - } - - // tooltipped to the right - &.tooltipped-e { - &::after { - bottom: 50%; - left: 100%; - margin-left: 6px; - transform: translateY(50%); - } - - &::before { - top: 50%; - right: -7px; - bottom: 50%; - margin-top: -6px; - border-right-color: ${get('colors.neutral.emphasisPlus')}; - } - } - - &.tooltipped-multiline { - &::after { - width: max-content; - max-width: 250px; - word-wrap: break-word; - white-space: pre-line; - border-collapse: separate; - } - - &.tooltipped-s::after, - &.tooltipped-n::after { - right: auto; - left: 50%; - transform: translateX(-50%); - } - - &.tooltipped-w::after, - &.tooltipped-e::after { - right: 100%; - } - } - - &.tooltipped-align-right-2::after { - right: 0; - margin-right: 0; - } - - &.tooltipped-align-right-2::before { - right: 15px; - } - - &.tooltipped-align-left-2::after { - left: 0; - margin-left: 0; - } - - &.tooltipped-align-left-2::before { - left: 10px; - } - - ${sx}; -` - -export type TooltipProps = { - direction?: 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w' | 'nw' - text?: string - noDelay?: boolean - align?: 'left' | 'right' - wrap?: boolean -} & ComponentProps - -function Tooltip({direction = 'n', children, className, text, noDelay, align, wrap, ...rest}: TooltipProps) { - const classes = classnames( - className, - `tooltipped-${direction}`, - align && `tooltipped-align-${align}-2`, - noDelay && 'tooltipped-no-delay', - wrap && 'tooltipped-multiline' - ) - return ( - - {children} - - ) -} - -Tooltip.alignments = ['left', 'right'] - -Tooltip.directions = ['n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'] - -export default Tooltip diff --git a/src/Tooltip/Tooltip.examples.stories.tsx b/src/Tooltip/Tooltip.examples.stories.tsx new file mode 100644 index 00000000000..bb36aedec71 --- /dev/null +++ b/src/Tooltip/Tooltip.examples.stories.tsx @@ -0,0 +1,62 @@ +import React from 'react' +import {Meta} from '@storybook/react' +import {CodeIcon, CrossReferenceIcon, ImageIcon, MentionIcon} from '@primer/octicons-react' +import {IconButton, Box, IssueLabelToken} from '..' +import {Tooltip} from '.' + +export default {title: 'Composite components/Tooltip/examples', component: Tooltip} as Meta + +const IssueLabel = React.forwardRef(({text, fillColor}, ref) => { + return ( + + ) +}) + +export const TokenWithTooltip = () => { + return ( + + + + + + + + + + + + + + + ) +} + +export const ButtonWithTooltip = () => { + return ( + + + + + + + + + + + + + + + ) +} diff --git a/src/Tooltip/Tooltip.fixtures.stories.tsx b/src/Tooltip/Tooltip.fixtures.stories.tsx new file mode 100644 index 00000000000..8fbdddeab37 --- /dev/null +++ b/src/Tooltip/Tooltip.fixtures.stories.tsx @@ -0,0 +1,61 @@ +import React from 'react' +import {Meta} from '@storybook/react' +import {Box, IssueLabelToken} from '..' +import {Tooltip} from '.' + +export default {title: 'Composite components/Tooltip/fixtures', component: Tooltip} as Meta + +const IssueLabel = React.forwardRef(({text, fillColor}, ref) => { + return ( + + ) +}) + +export const Direction = () => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} diff --git a/src/Tooltip/index.tsx b/src/Tooltip/index.tsx new file mode 100644 index 00000000000..2b2ec9e89ee --- /dev/null +++ b/src/Tooltip/index.tsx @@ -0,0 +1,135 @@ +/** + * Add animations & noDelay + * wrap + * add align? + */ + +import React from 'react' +import {useSSRSafeId} from '@react-aria/ssr' +import type {AnchorPosition, AnchorSide, AnchorAlignment} from '@primer/behaviors' +import Box from '../Box' +import {useAnchoredPosition} from '../hooks' +import {SxProp, merge, BetterSystemStyleObject} from '../sx' + +type TooltipDirection = 'nw' | 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w' +type TooltipAlign = 'left' | 'right' +export type TooltipProps = { + /** The text content of the tooltip. This should be brief and no longer than a sentence. */ + text: string + /** @deprecated Use `text` instead */ + 'aria-label'?: string + /** Position relative to target */ + direction?: TooltipDirection + /** Position relative to target */ + align?: TooltipAlign + /** Use aria-describedby or aria-labelledby */ + type?: 'description' | 'label' + /** Tooltip target, single element */ + children: React.ReactElement +} & SxProp + +// map tooltip direction to anchoredPosition props +const directionToPosition: Record = { + nw: {side: 'outside-top', align: 'start'}, + n: {side: 'outside-top', align: 'center'}, + ne: {side: 'outside-top', align: 'end'}, + e: {side: 'outside-right', align: 'center'}, + se: {side: 'outside-bottom', align: 'end'}, + s: {side: 'outside-bottom', align: 'center'}, + sw: {side: 'outside-bottom', align: 'start'}, + w: {side: 'outside-left', align: 'center'} +} + +// map align to AnchorAlignment +const alignToAnchorAlignment: Record = {left: 'start', right: 'end'} + +export const TooltipContext = React.createContext<{tooltipId?: string}>({}) + +export const Tooltip: React.FC = ({text, children, direction = 'n', align, type = 'description'}) => { + const tooltipRef = React.useRef(null) + const anchorElementRef = React.useRef(null) + + const {position} = useAnchoredPosition({ + side: directionToPosition[direction].side, + // maintain backward compatibility + align: align ? alignToAnchorAlignment[align] : directionToPosition[direction].align, + floatingElementRef: tooltipRef, + anchorElementRef + }) + + const tooltipId = useSSRSafeId() + const child = React.cloneElement(React.Children.only(children), { + ref: anchorElementRef, + [type === 'description' ? 'aria-describedby' : 'aria-labelledby']: tooltipId + }) + + return ( + + {child} + + {text} + + + ) +} + +const FloatingTooltip = React.forwardRef< + HTMLDivElement, + {id: string; children: string; position?: AnchorPosition} & SxProp +>(({id, children, position, sx = {}}, ref) => { + const styles = { + visibility: 'hidden', + backgroundColor: 'neutral.emphasisPlus', + color: 'fg.onEmphasis', + borderRadius: 1, + fontSize: 0, + paddingY: 1, + paddingX: 2, + width: 'fit-content', + maxWidth: '250px', + textAlign: 'center', + position: 'absolute', + zIndex: 2, + top: position?.top, + left: position?.left + } + + return ( + (styles, sx)} + > + + {children} + + ) +}) diff --git a/src/stories/Tooltip.stories.tsx b/src/stories/Tooltip.stories.tsx deleted file mode 100644 index 59d034282f1..00000000000 --- a/src/stories/Tooltip.stories.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import React from 'react' -import {Meta} from '@storybook/react' -import {BaseStyles, ThemeProvider, IconButton} from '..' -import Box from '../Box' -import Tooltip from '../Tooltip' -import {SearchIcon} from '@primer/octicons-react' - -export default { - title: 'Tooltip/Default', - component: Tooltip, - - decorators: [ - Story => { - return ( - - - - - - ) - } - ] -} as Meta - -export const TextTooltip = () => ( - - Text with a tooltip - -) - -export const IconButtonTooltip = () => ( - - - - - -) From 98fdc4a2a2646a491cf25c24f10a8cb52b2ae59f Mon Sep 17 00:00:00 2001 From: Siddharth Kshetrapal Date: Thu, 28 Apr 2022 18:01:21 +0200 Subject: [PATCH 10/26] Use Tooltip in IconButton --- src/Button/Button.stories.tsx | 32 +++++++++++++++++++++++++++++++- src/Button/IconButton.tsx | 35 +++++++++++++++++++++++++++++------ src/Button/types.ts | 2 ++ 3 files changed, 62 insertions(+), 7 deletions(-) diff --git a/src/Button/Button.stories.tsx b/src/Button/Button.stories.tsx index 800915dc3a9..54f2dc79f3f 100644 --- a/src/Button/Button.stories.tsx +++ b/src/Button/Button.stories.tsx @@ -1,9 +1,10 @@ -import {EyeClosedIcon, EyeIcon, SearchIcon, TriangleDownIcon, XIcon} from '@primer/octicons-react' +import {BellIcon, EyeClosedIcon, EyeIcon, SearchIcon, TriangleDownIcon, XIcon} from '@primer/octicons-react' import {Meta} from '@storybook/react' import React, {useState} from 'react' import {Button, ButtonProps, IconButton} from '.' import {BaseStyles, ThemeProvider} from '..' import Box from '../Box' +import {Tooltip} from '../Tooltip' export default { title: 'Composite components/Button', @@ -93,6 +94,35 @@ export const iconButton = ({...args}: ButtonProps) => { ) } +export const iconButtonWithTooltip = ({...args}: ButtonProps) => { + return ( + <> + + Default tooltip + + + + Custom tooltip text + + + + + + Custom tooltip side + + + + + + Disable tooltip + + + + + + ) +} + export const WatchCounterButton = ({...args}: ButtonProps) => { const [count, setCount] = useState(0) return ( diff --git a/src/Button/IconButton.tsx b/src/Button/IconButton.tsx index 401650829fc..2a87d9becd2 100644 --- a/src/Button/IconButton.tsx +++ b/src/Button/IconButton.tsx @@ -4,23 +4,46 @@ import {useTheme} from '../ThemeProvider' import Box from '../Box' import {IconButtonProps, StyledButton} from './types' import {getBaseStyles, getSizeStyles, getVariantStyles} from './styles' +import {Tooltip, TooltipContext, TooltipProps} from '../Tooltip' const IconButton = forwardRef((props, forwardedRef): JSX.Element => { - const {variant = 'default', size = 'medium', sx: sxProp = {}, icon: Icon, ...rest} = props + const {variant = 'default', size = 'medium', sx: sxProp = {}, icon: Icon, disableTooltip = false, ...rest} = props const {theme} = useTheme() + const sxStyles = merge.all([ getBaseStyles(theme), getSizeStyles(size, variant, true), getVariantStyles(variant, theme), sxProp as SxProp ]) + return ( - - - - - + + + + + + + ) }) export {IconButton} + +const ConditionalTooltip: React.FC> = ({ + text, + disableTooltip, + children +}) => { + // If button is already wrapped in a Tooltip, + // do not add another. + const {tooltipId} = React.useContext(TooltipContext) + + if (tooltipId || disableTooltip) return children + + return ( + + {children} + + ) +} diff --git a/src/Button/types.ts b/src/Button/types.ts index 10c7188bc1a..29f2d704cfd 100644 --- a/src/Button/types.ts +++ b/src/Button/types.ts @@ -44,6 +44,8 @@ export type ButtonProps = { export type IconButtonProps = ButtonA11yProps & { icon: React.FunctionComponent + 'aria-label': string + disableTooltip?: boolean } & ButtonBaseProps // adopted from React.AnchorHTMLAttributes From 623f2b271679b1cfe9c472cf44074ca69b8b7b0e Mon Sep 17 00:00:00 2001 From: Siddharth Kshetrapal Date: Thu, 28 Apr 2022 19:14:56 +0200 Subject: [PATCH 11/26] Add triangle styles for all directions --- src/Tooltip/Tooltip.fixtures.stories.tsx | 28 +++---- src/Tooltip/index.tsx | 93 +++++++++++++++--------- 2 files changed, 74 insertions(+), 47 deletions(-) diff --git a/src/Tooltip/Tooltip.fixtures.stories.tsx b/src/Tooltip/Tooltip.fixtures.stories.tsx index 8fbdddeab37..07bbf60c2f0 100644 --- a/src/Tooltip/Tooltip.fixtures.stories.tsx +++ b/src/Tooltip/Tooltip.fixtures.stories.tsx @@ -22,38 +22,38 @@ export const Direction = () => { return ( - + - + - + - + - - + - + - + - + diff --git a/src/Tooltip/index.tsx b/src/Tooltip/index.tsx index 2b2ec9e89ee..4c4236ea3d1 100644 --- a/src/Tooltip/index.tsx +++ b/src/Tooltip/index.tsx @@ -1,4 +1,5 @@ /** + * triangle position * Add animations & noDelay * wrap * add align? @@ -18,9 +19,9 @@ export type TooltipProps = { text: string /** @deprecated Use `text` instead */ 'aria-label'?: string - /** Position relative to target */ + /** Direction relative to target */ direction?: TooltipDirection - /** Position relative to target */ + /** Alignment relative to target */ align?: TooltipAlign /** Use aria-describedby or aria-labelledby */ type?: 'description' | 'label' @@ -45,13 +46,19 @@ const alignToAnchorAlignment: Record = {left: 'st export const TooltipContext = React.createContext<{tooltipId?: string}>({}) -export const Tooltip: React.FC = ({text, children, direction = 'n', align, type = 'description'}) => { +export const Tooltip: React.FC = ({ + text, + children, + direction = 'n', + align, + type = 'description', + sx = {} +}) => { const tooltipRef = React.useRef(null) const anchorElementRef = React.useRef(null) const {position} = useAnchoredPosition({ side: directionToPosition[direction].side, - // maintain backward compatibility align: align ? alignToAnchorAlignment[align] : directionToPosition[direction].align, floatingElementRef: tooltipRef, anchorElementRef @@ -71,18 +78,16 @@ export const Tooltip: React.FC = ({text, children, direction = 'n' }} > {child} - - {text} - + ) } const FloatingTooltip = React.forwardRef< HTMLDivElement, - {id: string; children: string; position?: AnchorPosition} & SxProp ->(({id, children, position, sx = {}}, ref) => { - const styles = { + {id: string; text: string; position?: AnchorPosition} & SxProp +>(({id, text, position, sx = {}}, ref) => { + const styles: BetterSystemStyleObject = { visibility: 'hidden', backgroundColor: 'neutral.emphasisPlus', color: 'fg.onEmphasis', @@ -96,7 +101,48 @@ const FloatingTooltip = React.forwardRef< position: 'absolute', zIndex: 2, top: position?.top, - left: position?.left + left: position?.left, + + ':before': { + content: '""', + width: 0, + height: 0, + border: '5px solid transparent', + position: 'absolute' + }, + + '&[data-side=outside-top]::before': { + borderTop: '5px solid', + borderTopColor: 'neutral.emphasisPlus', + top: '100%' + }, + '&[data-side=outside-bottom]::before': { + borderBottom: '5px solid', + borderBottomColor: 'neutral.emphasisPlus', + top: '-10px' + }, + '&[data-side=outside-left]::before': { + borderLeft: '5px solid', + borderLeftColor: 'neutral.emphasisPlus', + top: 'calc(50% - 5px)', + left: '100%' + }, + '&[data-side=outside-right]::before': { + borderRight: '5px solid', + borderRightColor: 'neutral.emphasisPlus', + top: 'calc(50% - 5px)', + left: '-10px' + }, + + '&[data-align=start][data-side=outside-top]::before, &[data-align=start][data-side=outside-bottom]::before': { + left: '8px' + }, + '&[data-align=center][data-side=outside-top]::before, &[data-align=center][data-side=outside-bottom]::before': { + left: 'calc(50% - 4px)' + }, + '&[data-align=end][data-side=outside-top]::before, &[data-align=end][data-side=outside-bottom]::before': { + left: 'calc(100% - 16px)' + } } return ( @@ -105,31 +151,12 @@ const FloatingTooltip = React.forwardRef< id={id} aria-hidden data-component="tooltip" + data-side={position?.anchorSide} + data-align={position?.anchorAlign} ref={ref} sx={merge(styles, sx)} > - - {children} + {text} ) }) From c4c65fd52ffb667e2f4f39baa13de8f0def8db07 Mon Sep 17 00:00:00 2001 From: Siddharth Kshetrapal Date: Fri, 29 Apr 2022 16:00:12 +0200 Subject: [PATCH 12/26] Add docs --- docs/content/Tooltip.md | 34 ----- docs/content/Tooltip.mdx | 173 +++++++++++++++++++++++ src/Tooltip/Tooltip.fixtures.stories.tsx | 16 +-- src/index.ts | 2 +- 4 files changed, 182 insertions(+), 43 deletions(-) delete mode 100644 docs/content/Tooltip.md create mode 100644 docs/content/Tooltip.mdx diff --git a/docs/content/Tooltip.md b/docs/content/Tooltip.md deleted file mode 100644 index a8aea00bfa1..00000000000 --- a/docs/content/Tooltip.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -componentId: tooltip -title: Tooltip -status: Alpha ---- - -The Tooltip component adds a tooltip to add context to elements on the page. - -**_⚠️ Usage warning! ⚠️_** - -Tooltips as a UI pattern should be our last resort for conveying information because it is hidden by default and often with zero or little visual indicator of its existence. - -Before adding a tooltip, please consider: Is this information essential and necessary? Can the UI be made clearer? Can the information be shown on the page by default? - -**Attention:** we use aria-label for tooltip contents, because it is crucial that they are accessible to screen reader users. However, aria-label replaces the text content of an element in screen readers, so only use Tooltip on elements with no existing text content, or consider using `title` for supplemental information. - -## Default example - -```jsx live - - Text with a tooltip - -``` - -## Component props - -| Name | Type | Default | Description | -| :--------- | :---------------- | :-----: | :------------------------------------------------------------------------------------------------------------------ | -| align | String | | Can be either `left` or `right`. | -| direction | String | | Can be one of `n`, `ne`, `e`, `se`, `s`, `sw`, `w`, `nw`. Sets where the tooltip renders in relation to the target. | -| noDelay | Boolean | | When set to `true`, tooltip appears without any delay | -| aria-label | String | | Text used in `aria-label` (for accessibility). | -| wrap | Boolean | | Use `true` to allow text within tooltip to wrap. | -| sx | SystemStyleObject | {} | Style to be applied to the component | diff --git a/docs/content/Tooltip.mdx b/docs/content/Tooltip.mdx new file mode 100644 index 00000000000..23d8e07dd96 --- /dev/null +++ b/docs/content/Tooltip.mdx @@ -0,0 +1,173 @@ +--- +componentId: tooltip +title: Tooltip +status: Alpha +source: https://github.com/primer/react/tree/main/src/Tooltip +storybook: '/react/storybook?path=/story/composite-components-tooltip' +description: The Tooltip component adds a tooltip to add context to elements on the page. +--- + +Tooltip only appears on mouse hover or keyboard focus and contain a label or description text. Use tooltips sparingly and as a last resort. [Consider these alternatives](https://primer.style/design/accessibility/tooltip-alternatives). + +import {Tooltip, IconButton, Button} from '@primer/react' +import {BellIcon, MentionIcon} from '@primer/octicons-react' +import InlineCode from '@primer/gatsby-theme-doctocat/src/components/inline-code' + + + + + + + +When using a tooltip, follow the provided guidelines to avoid accessibility issues. + +- Tooltip text should be brief and to the point. +- Tooltips should contain only **non-essential text**. Tooltips can easily be missed and are not accessible on touch devices so never use tooltips to convey critical information. + +## Examples + +### As a description for icon-only button + +If the tooltip content provides supplementary description, wrap the target in a `Tooltip`. The trigger element should also have a concise accessible label via `aria-label`. + +```jsx live + + + +``` + +### As a description for a button with visible label + +```jsx live + + + +``` + +### With direction + +Set direction of tooltip with `direction`. The tooltip is responsive and will automatically adjust direction to avoid cutting off. + +```jsx live + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +## Props + + + + + + + Use text instead + + } + /> + + Use aria-describedby or aria-labelledby + + } + /> + + + + + +## Status + + + +## Further reading + +- [Tooltip alternatives](https://primer.style/design/accessibility/tooltip-alternatives) + +## Related components + +- [IconButton](/IconButton) diff --git a/src/Tooltip/Tooltip.fixtures.stories.tsx b/src/Tooltip/Tooltip.fixtures.stories.tsx index 07bbf60c2f0..939afd0df92 100644 --- a/src/Tooltip/Tooltip.fixtures.stories.tsx +++ b/src/Tooltip/Tooltip.fixtures.stories.tsx @@ -30,30 +30,30 @@ export const Direction = () => { '[data-component=tooltip]': {visibility: 'visible'} // see all tooltips }} > - + - + - + - + - + - + - + - + diff --git a/src/index.ts b/src/index.ts index f4ce005e4f7..435e8e9b295 100644 --- a/src/index.ts +++ b/src/index.ts @@ -143,7 +143,7 @@ export type { } from './Timeline' export {default as Token, IssueLabelToken, AvatarToken} from './Token' export type {TokenProps} from './Token' -export {default as Tooltip} from './Tooltip' +export {Tooltip} from './Tooltip' export type {TooltipProps} from './Tooltip' export {default as Truncate} from './Truncate' export type {TruncateProps} from './Truncate' From b9ed36c15077685354797fdcd691175547fad246 Mon Sep 17 00:00:00 2001 From: Siddharth Kshetrapal Date: Fri, 29 Apr 2022 16:27:36 +0200 Subject: [PATCH 13/26] Added delay --- docs/content/Tooltip.mdx | 8 ++++- src/Tooltip/Tooltip.fixtures.stories.tsx | 15 +++++++- src/Tooltip/index.tsx | 46 +++++++++++++++++------- 3 files changed, 55 insertions(+), 14 deletions(-) diff --git a/docs/content/Tooltip.mdx b/docs/content/Tooltip.mdx index 23d8e07dd96..cf412179dff 100644 --- a/docs/content/Tooltip.mdx +++ b/docs/content/Tooltip.mdx @@ -139,7 +139,13 @@ Set direction of tooltip with `direction`. The tooltip is responsive and will au defaultValue="n" description="Sets where the tooltip renders in relation to the target" /> - + + When set to true, tooltip appears without any delay + } /> + Use to allow text within tooltip to wrap. Deprecated: always set to true now. + } /> diff --git a/src/Tooltip/Tooltip.fixtures.stories.tsx b/src/Tooltip/Tooltip.fixtures.stories.tsx index 939afd0df92..6a85934701e 100644 --- a/src/Tooltip/Tooltip.fixtures.stories.tsx +++ b/src/Tooltip/Tooltip.fixtures.stories.tsx @@ -1,6 +1,6 @@ import React from 'react' import {Meta} from '@storybook/react' -import {Box, IssueLabelToken} from '..' +import {Box, Button, IssueLabelToken} from '..' import {Tooltip} from '.' export default {title: 'Composite components/Tooltip/fixtures', component: Tooltip} as Meta @@ -59,3 +59,16 @@ export const Direction = () => { ) } + +export const Delay = () => { + return ( + + + + + + + + + ) +} diff --git a/src/Tooltip/index.tsx b/src/Tooltip/index.tsx index 4c4236ea3d1..262e1d1eabd 100644 --- a/src/Tooltip/index.tsx +++ b/src/Tooltip/index.tsx @@ -1,8 +1,8 @@ /** - * triangle position - * Add animations & noDelay - * wrap - * add align? + * wrap - deprecate? + * use React.ReactNode instead of element + * backward compat for aria-label + * tests! */ import React from 'react' @@ -14,19 +14,25 @@ import {SxProp, merge, BetterSystemStyleObject} from '../sx' type TooltipDirection = 'nw' | 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w' type TooltipAlign = 'left' | 'right' + export type TooltipProps = { - /** The text content of the tooltip. This should be brief and no longer than a sentence. */ - text: string + /** The text content of the tooltip. This should be brief and no longer than a sentence. + * Marked as optional to support backward compatibility with aria-label. */ + text?: string /** @deprecated Use `text` instead */ 'aria-label'?: string /** Direction relative to target */ direction?: TooltipDirection - /** Alignment relative to target */ + /** @deprecated Use `direction` instead. Alignment relative to target. */ align?: TooltipAlign /** Use aria-describedby or aria-labelledby */ type?: 'description' | 'label' /** Tooltip target, single element */ children: React.ReactElement + /** When set to true, tooltip appears without any delay */ + noDelay?: boolean + /** @deprecated Always set to true now. */ + wrap?: boolean } & SxProp // map tooltip direction to anchoredPosition props @@ -52,13 +58,16 @@ export const Tooltip: React.FC = ({ direction = 'n', align, type = 'description', - sx = {} + noDelay = false, + sx = {}, + ...props }) => { const tooltipRef = React.useRef(null) const anchorElementRef = React.useRef(null) const {position} = useAnchoredPosition({ side: directionToPosition[direction].side, + // support both algin and direction for backward compatibility align: align ? alignToAnchorAlignment[align] : directionToPosition[direction].align, floatingElementRef: tooltipRef, anchorElementRef @@ -70,25 +79,38 @@ export const Tooltip: React.FC = ({ [type === 'description' ? 'aria-describedby' : 'aria-labelledby']: tooltipId }) + const tooltipText = text || props['aria-label'] + return ( {child} - + ) } const FloatingTooltip = React.forwardRef< HTMLDivElement, - {id: string; text: string; position?: AnchorPosition} & SxProp ->(({id, text, position, sx = {}}, ref) => { + Pick & {id: string; position?: AnchorPosition} & SxProp +>(({id, text, noDelay = false, position, sx = {}}, ref) => { const styles: BetterSystemStyleObject = { visibility: 'hidden', + opacity: 0, + transition: 'opacity 100ms ease-in', + transitionDelay: noDelay ? '0ms' : '400ms', + backgroundColor: 'neutral.emphasisPlus', color: 'fg.onEmphasis', borderRadius: 1, From 505c1a555336c87afd457daf6e9a1f0c580a5f77 Mon Sep 17 00:00:00 2001 From: Siddharth Kshetrapal Date: Fri, 29 Apr 2022 16:33:30 +0200 Subject: [PATCH 14/26] change ReactElement to ReactNode --- src/Tooltip/index.tsx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Tooltip/index.tsx b/src/Tooltip/index.tsx index 262e1d1eabd..d84c75ac0da 100644 --- a/src/Tooltip/index.tsx +++ b/src/Tooltip/index.tsx @@ -1,7 +1,4 @@ /** - * wrap - deprecate? - * use React.ReactNode instead of element - * backward compat for aria-label * tests! */ @@ -27,8 +24,8 @@ export type TooltipProps = { align?: TooltipAlign /** Use aria-describedby or aria-labelledby */ type?: 'description' | 'label' - /** Tooltip target, single element */ - children: React.ReactElement + /** Tooltip target */ + children: React.ReactNode /** When set to true, tooltip appears without any delay */ noDelay?: boolean /** @deprecated Always set to true now. */ @@ -74,7 +71,9 @@ export const Tooltip: React.FC = ({ }) const tooltipId = useSSRSafeId() - const child = React.cloneElement(React.Children.only(children), { + + if (!React.isValidElement(children)) return children + const child = React.cloneElement(children, { ref: anchorElementRef, [type === 'description' ? 'aria-describedby' : 'aria-labelledby']: tooltipId }) From 1e26ba1db1fbb4946764fbaedfdf6ef97d2ad16c Mon Sep 17 00:00:00 2001 From: Siddharth Kshetrapal Date: Fri, 29 Apr 2022 16:37:02 +0200 Subject: [PATCH 15/26] keep ReactElement --- src/Tooltip/index.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/Tooltip/index.tsx b/src/Tooltip/index.tsx index d84c75ac0da..8475de715a7 100644 --- a/src/Tooltip/index.tsx +++ b/src/Tooltip/index.tsx @@ -1,7 +1,3 @@ -/** - * tests! - */ - import React from 'react' import {useSSRSafeId} from '@react-aria/ssr' import type {AnchorPosition, AnchorSide, AnchorAlignment} from '@primer/behaviors' @@ -25,7 +21,7 @@ export type TooltipProps = { /** Use aria-describedby or aria-labelledby */ type?: 'description' | 'label' /** Tooltip target */ - children: React.ReactNode + children: React.ReactElement /** When set to true, tooltip appears without any delay */ noDelay?: boolean /** @deprecated Always set to true now. */ @@ -72,7 +68,6 @@ export const Tooltip: React.FC = ({ const tooltipId = useSSRSafeId() - if (!React.isValidElement(children)) return children const child = React.cloneElement(children, { ref: anchorElementRef, [type === 'description' ? 'aria-describedby' : 'aria-labelledby']: tooltipId From 24b01a44711fc90dffa8afa1ff6b989ad752a30c Mon Sep 17 00:00:00 2001 From: Siddharth Kshetrapal Date: Fri, 29 Apr 2022 17:47:34 +0200 Subject: [PATCH 16/26] Add tests! --- docs/content/Tooltip.mdx | 9 +- src/Tooltip/index.tsx | 4 +- src/__tests__/Tooltip.test.tsx | 63 ++--- src/__tests__/Tooltip.types.test.tsx | 5 +- .../__snapshots__/Tooltip.test.tsx.snap | 262 +++++------------- .../Tooltip/examples.stories.tsx} | 3 +- .../Tooltip/fixtures.stories.tsx} | 38 ++- 7 files changed, 142 insertions(+), 242 deletions(-) rename src/{Tooltip/Tooltip.examples.stories.tsx => stories/Tooltip/examples.stories.tsx} (96%) rename src/{Tooltip/Tooltip.fixtures.stories.tsx => stories/Tooltip/fixtures.stories.tsx} (70%) diff --git a/docs/content/Tooltip.mdx b/docs/content/Tooltip.mdx index cf412179dff..ce85d1ce99d 100644 --- a/docs/content/Tooltip.mdx +++ b/docs/content/Tooltip.mdx @@ -22,11 +22,10 @@ import InlineCode from '@primer/gatsby-theme-doctocat/src/components/inline-code borderRadius: 2, padding: 6, paddingTop: 8, - marginBottom: 3, - '[data-component=tooltip]': {visibility: 'visible'} + marginBottom: 3 }} > - + @@ -67,7 +66,7 @@ Set direction of tooltip with `direction`. The tooltip is responsive and will au flexDirection: 'column', gap: 8, marginY: 4, - '[data-component=tooltip]': {visibility: 'visible'} + '[data-component=tooltip]': {visibility: 'visible', opacity: 1} }} > @@ -157,7 +156,7 @@ Set direction of tooltip with `direction`. The tooltip is responsive and will au noUnnecessaryDeps: true, adaptsToThemes: true, adaptsToScreenSizes: true, - fullTestCoverage: false, + fullTestCoverage: true, usedInProduction: true, usageExamplesDocumented: true, hasStorybookStories: true, diff --git a/src/Tooltip/index.tsx b/src/Tooltip/index.tsx index 8475de715a7..7dc00b7049a 100644 --- a/src/Tooltip/index.tsx +++ b/src/Tooltip/index.tsx @@ -97,8 +97,8 @@ export const Tooltip: React.FC = ({ const FloatingTooltip = React.forwardRef< HTMLDivElement, - Pick & {id: string; position?: AnchorPosition} & SxProp ->(({id, text, noDelay = false, position, sx = {}}, ref) => { + Pick & {id: string; position?: AnchorPosition} +>(({id, text, noDelay, position, sx = {}}, ref) => { const styles: BetterSystemStyleObject = { visibility: 'hidden', opacity: 0, diff --git a/src/__tests__/Tooltip.test.tsx b/src/__tests__/Tooltip.test.tsx index 4a285eea46e..92ecbc0f8bb 100644 --- a/src/__tests__/Tooltip.test.tsx +++ b/src/__tests__/Tooltip.test.tsx @@ -1,52 +1,45 @@ import React from 'react' -import Tooltip, {TooltipProps} from '../Tooltip' -import {render, renderClasses, rendersClass, behavesAsComponent, checkExports} from '../utils/testing' +import 'babel-polyfill' +import {Tooltip, TooltipContext} from '../Tooltip' +import {SSRProvider} from '..' +import {behavesAsComponent, checkExports, checkStoriesForAxeViolations} from '../utils/testing' import {render as HTMLRender, cleanup} from '@testing-library/react' import {axe, toHaveNoViolations} from 'jest-axe' -import 'babel-polyfill' +import '@testing-library/jest-dom' expect.extend(toHaveNoViolations) -describe('Tooltip', () => { - behavesAsComponent({Component: Tooltip}) +const Fixture = () => { + return ( + + + + + + ) +} - checkExports('Tooltip', { - default: Tooltip +describe('Tooltip', () => { + behavesAsComponent({ + Component: Tooltip, + options: {skipAs: true, skipSx: true}, + toRender: () => }) + checkExports('Tooltip', {default: undefined, Tooltip, TooltipContext}) + it('should have no axe violations', async () => { - const {container} = HTMLRender() + const {container} = HTMLRender() const results = await axe(container) expect(results).toHaveNoViolations() cleanup() }) - it('renders a with the "tooltipped" class', () => { - expect(render().type).toEqual('span') - expect(renderClasses()).toContain('tooltipped-n') - }) - - it('respects the "align" prop', () => { - expect(rendersClass(, 'tooltipped-align-left-2')).toBe(true) - expect(rendersClass(, 'tooltipped-align-right-2')).toBe(true) - }) - - it('respects the "direction" prop', () => { - for (const direction of Tooltip.directions) { - expect( - rendersClass(, `tooltipped-${direction}`) - ).toBe(true) - } - }) - - it('respects the "noDelay" prop', () => { - expect(rendersClass(, 'tooltipped-no-delay')).toBe(true) - }) - - it('respects the "text" prop', () => { - expect(render().props['aria-label']).toEqual('hi') + it('tooltip should not be visible by default', () => { + const component = HTMLRender() + expect(component.getByText('tooltip text')).not.toBeVisible() + cleanup() }) - it('respects the "wrap" prop', () => { - expect(rendersClass(, 'tooltipped-multiline')).toBe(true) - }) + checkStoriesForAxeViolations('Tooltip/fixtures') + checkStoriesForAxeViolations('Tooltip/examples') }) diff --git a/src/__tests__/Tooltip.types.test.tsx b/src/__tests__/Tooltip.types.test.tsx index c9280121588..59c0e45ac54 100644 --- a/src/__tests__/Tooltip.types.test.tsx +++ b/src/__tests__/Tooltip.types.test.tsx @@ -1,7 +1,8 @@ import React from 'react' -import Tooltip from '../Tooltip' +import {Tooltip} from '../Tooltip' -export function shouldAcceptCallWithNoProps() { +export function shouldNotAcceptCallWithMissingProps() { + // @ts-expect-error props missing return } diff --git a/src/__tests__/__snapshots__/Tooltip.test.tsx.snap b/src/__tests__/__snapshots__/Tooltip.test.tsx.snap index 25e5a7b14ab..7ce9a0e71a6 100644 --- a/src/__tests__/__snapshots__/Tooltip.test.tsx.snap +++ b/src/__tests__/__snapshots__/Tooltip.test.tsx.snap @@ -1,227 +1,101 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Tooltip renders consistently 1`] = ` -.c0 { - position: relative; +.c0:hover [data-component=tooltip], +.c0:focus-within [data-component=tooltip] { + visibility: visible; + opacity: 1; } -.c0::before { - position: absolute; - z-index: 1000001; - display: none; - width: 0px; - height: 0px; - color: #24292f; - pointer-events: none; - content: ''; - border: 6px solid transparent; +.c1 { + visibility: hidden; opacity: 0; -} - -.c0::after { - position: absolute; - z-index: 1000000; - display: none; - padding: 0.5em 0.75em; - font: normal normal 11px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"; - -webkit-font-smoothing: subpixel-antialiased; + -webkit-transition: opacity 100ms ease-in; + transition: opacity 100ms ease-in; + -webkit-transition-delay: 400ms; + transition-delay: 400ms; + background-color: #24292f; color: #ffffff; - text-align: center; - -webkit-text-decoration: none; - text-decoration: none; - text-shadow: none; - text-transform: none; - -webkit-letter-spacing: normal; - -moz-letter-spacing: normal; - -ms-letter-spacing: normal; - letter-spacing: normal; - word-wrap: break-word; - white-space: pre; - pointer-events: none; - content: attr(aria-label); - background: #24292f; border-radius: 3px; - opacity: 0; -} - -.c0:hover::before, -.c0:active::before, -.c0:focus::before, -.c0:hover::after, -.c0:active::after, -.c0:focus::after { - display: inline-block; - -webkit-text-decoration: none; - text-decoration: none; - -webkit-animation-name: tooltip-appear; - animation-name: tooltip-appear; - -webkit-animation-duration: 0.1s; - animation-duration: 0.1s; - -webkit-animation-fill-mode: forwards; - animation-fill-mode: forwards; - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - -webkit-animation-delay: 0.4s; - animation-delay: 0.4s; -} - -.c0.tooltipped-no-delay:hover::before, -.c0.tooltipped-no-delay:active::before, -.c0.tooltipped-no-delay:focus::before, -.c0.tooltipped-no-delay:hover::after, -.c0.tooltipped-no-delay:active::after, -.c0.tooltipped-no-delay:focus::after { - -webkit-animation-delay: 0s; - animation-delay: 0s; + font-size: 12px; + padding-top: 4px; + padding-bottom: 4px; + padding-left: 8px; + padding-right: 8px; + width: -webkit-fit-content; + width: -moz-fit-content; + width: fit-content; + max-width: 250px; + text-align: center; + position: absolute; + z-index: 2; } -.c0.tooltipped-multiline:hover::after, -.c0.tooltipped-multiline:active::after, -.c0.tooltipped-multiline:focus::after { - display: table-cell; +.c1:before { + content: ""; + width: 0; + height: 0; + border: 5px solid transparent; + position: absolute; } -.c0.tooltipped-s::after, -.c0.tooltipped-se::after, -.c0.tooltipped-sw::after { +.c1[data-side=outside-top]::before { + border-top: 5px solid; + border-top-color: #24292f; top: 100%; - right: 50%; - margin-top: 6px; } -.c0.tooltipped-s::before, -.c0.tooltipped-se::before, -.c0.tooltipped-sw::before { - top: auto; - right: 50%; - bottom: -7px; - margin-right: -6px; +.c1[data-side=outside-bottom]::before { + border-bottom: 5px solid; border-bottom-color: #24292f; + top: -10px; } -.c0.tooltipped-se::after { - right: auto; - left: 50%; - margin-left: -16px; -} - -.c0.tooltipped-sw::after { - margin-right: -16px; -} - -.c0.tooltipped-n::after, -.c0.tooltipped-ne::after, -.c0.tooltipped-nw::after { - right: 50%; - bottom: 100%; - margin-bottom: 6px; -} - -.c0.tooltipped-n::before, -.c0.tooltipped-ne::before, -.c0.tooltipped-nw::before { - top: -7px; - right: 50%; - bottom: auto; - margin-right: -6px; - border-top-color: #24292f; -} - -.c0.tooltipped-ne::after { - right: auto; - left: 50%; - margin-left: -16px; -} - -.c0.tooltipped-nw::after { - margin-right: -16px; -} - -.c0.tooltipped-s::after, -.c0.tooltipped-n::after { - -webkit-transform: translateX(50%); - -ms-transform: translateX(50%); - transform: translateX(50%); -} - -.c0.tooltipped-w::after { - right: 100%; - bottom: 50%; - margin-right: 6px; - -webkit-transform: translateY(50%); - -ms-transform: translateY(50%); - transform: translateY(50%); -} - -.c0.tooltipped-w::before { - top: 50%; - bottom: 50%; - left: -7px; - margin-top: -6px; +.c1[data-side=outside-left]::before { + border-left: 5px solid; border-left-color: #24292f; -} - -.c0.tooltipped-e::after { - bottom: 50%; + top: calc(50% - 5px); left: 100%; - margin-left: 6px; - -webkit-transform: translateY(50%); - -ms-transform: translateY(50%); - transform: translateY(50%); } -.c0.tooltipped-e::before { - top: 50%; - right: -7px; - bottom: 50%; - margin-top: -6px; +.c1[data-side=outside-right]::before { + border-right: 5px solid; border-right-color: #24292f; + top: calc(50% - 5px); + left: -10px; } -.c0.tooltipped-multiline::after { - width: -webkit-max-content; - width: -moz-max-content; - width: max-content; - max-width: 250px; - word-wrap: break-word; - white-space: pre-line; - border-collapse: separate; -} - -.c0.tooltipped-multiline.tooltipped-s::after, -.c0.tooltipped-multiline.tooltipped-n::after { - right: auto; - left: 50%; - -webkit-transform: translateX(-50%); - -ms-transform: translateX(-50%); - transform: translateX(-50%); -} - -.c0.tooltipped-multiline.tooltipped-w::after, -.c0.tooltipped-multiline.tooltipped-e::after { - right: 100%; -} - -.c0.tooltipped-align-right-2::after { - right: 0; - margin-right: 0; -} - -.c0.tooltipped-align-right-2::before { - right: 15px; +.c1[data-align=start][data-side=outside-top]::before, +.c1[data-align=start][data-side=outside-bottom]::before { + left: 8px; } -.c0.tooltipped-align-left-2::after { - left: 0; - margin-left: 0; +.c1[data-align=center][data-side=outside-top]::before, +.c1[data-align=center][data-side=outside-bottom]::before { + left: calc(50% - 4px); } -.c0.tooltipped-align-left-2::before { - left: 10px; +.c1[data-align=end][data-side=outside-top]::before, +.c1[data-align=end][data-side=outside-bottom]::before { + left: calc(100% - 16px); } + className="c0" +> + + + `; diff --git a/src/Tooltip/Tooltip.examples.stories.tsx b/src/stories/Tooltip/examples.stories.tsx similarity index 96% rename from src/Tooltip/Tooltip.examples.stories.tsx rename to src/stories/Tooltip/examples.stories.tsx index bb36aedec71..5ac52ab00ae 100644 --- a/src/Tooltip/Tooltip.examples.stories.tsx +++ b/src/stories/Tooltip/examples.stories.tsx @@ -1,8 +1,7 @@ import React from 'react' import {Meta} from '@storybook/react' import {CodeIcon, CrossReferenceIcon, ImageIcon, MentionIcon} from '@primer/octicons-react' -import {IconButton, Box, IssueLabelToken} from '..' -import {Tooltip} from '.' +import {IconButton, Box, IssueLabelToken, Tooltip} from '../..' export default {title: 'Composite components/Tooltip/examples', component: Tooltip} as Meta diff --git a/src/Tooltip/Tooltip.fixtures.stories.tsx b/src/stories/Tooltip/fixtures.stories.tsx similarity index 70% rename from src/Tooltip/Tooltip.fixtures.stories.tsx rename to src/stories/Tooltip/fixtures.stories.tsx index 6a85934701e..401492fb3db 100644 --- a/src/Tooltip/Tooltip.fixtures.stories.tsx +++ b/src/stories/Tooltip/fixtures.stories.tsx @@ -1,7 +1,7 @@ import React from 'react' import {Meta} from '@storybook/react' -import {Box, Button, IssueLabelToken} from '..' -import {Tooltip} from '.' +import {MentionIcon} from '@primer/octicons-react' +import {Box, Button, IssueLabelToken, Tooltip} from '../..' export default {title: 'Composite components/Tooltip/fixtures', component: Tooltip} as Meta @@ -72,3 +72,37 @@ export const Delay = () => { ) } + +export const TypeLabel = () => { + return ( + + + + ) +} + +export const AcceptsSx = () => { + return ( + + + + ) +} + +export const BackwardCompatibility = () => { + return ( + + + + + + + + + + + + ) +} From 13461eac2ca961298fa166cb573966f41e8c2734 Mon Sep 17 00:00:00 2001 From: Siddharth Kshetrapal Date: Fri, 29 Apr 2022 17:52:20 +0200 Subject: [PATCH 17/26] compatible types :) --- src/_TextInputInnerAction.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/_TextInputInnerAction.tsx b/src/_TextInputInnerAction.tsx index a9382b0cf2e..7c4797f5616 100644 --- a/src/_TextInputInnerAction.tsx +++ b/src/_TextInputInnerAction.tsx @@ -21,7 +21,7 @@ const invisibleButtonStyleOverrides = { const ConditionalTooltip: React.FC<{ ['aria-label']?: string - children: React.ReactNode + children: React.ReactElement }> = ({'aria-label': ariaLabel, children}) => ( <> {ariaLabel ? ( From 36bf0fcca0bb32be80f640250c86667bdcbbf480 Mon Sep 17 00:00:00 2001 From: Siddharth Kshetrapal Date: Fri, 29 Apr 2022 17:58:36 +0200 Subject: [PATCH 18/26] Fix docs --- docs/content/Tooltip.mdx | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/docs/content/Tooltip.mdx b/docs/content/Tooltip.mdx index ce85d1ce99d..552482f5e93 100644 --- a/docs/content/Tooltip.mdx +++ b/docs/content/Tooltip.mdx @@ -139,12 +139,26 @@ Set direction of tooltip with `direction`. The tooltip is responsive and will au description="Sets where the tooltip renders in relation to the target" /> - When set to true, tooltip appears without any delay - } /> - Use to allow text within tooltip to wrap. Deprecated: always set to true now. - } /> + + When set to true, tooltip appears without any delay + + } + /> + + Use to allow text within tooltip to wrap. Deprecated: always set to true now. + + } + /> @@ -162,7 +176,7 @@ Set direction of tooltip with `direction`. The tooltip is responsive and will au hasStorybookStories: true, designReviewed: false, a11yReviewed: false, - stableApi: false, + stableApi: true, addressedApiFeedback: false, hasDesignGuidelines: false, hasFigmaComponent: true From 3aaf29ad9f2ad1db9600cbf9431d4c4e22c74c04 Mon Sep 17 00:00:00 2001 From: Siddharth Kshetrapal Date: Fri, 29 Apr 2022 18:07:26 +0200 Subject: [PATCH 19/26] update snapshots --- .../__snapshots__/Button.test.tsx.snap | 1 + .../__snapshots__/TextInput.test.tsx.snap | 626 +++++------------- 2 files changed, 182 insertions(+), 445 deletions(-) diff --git a/src/__tests__/__snapshots__/Button.test.tsx.snap b/src/__tests__/__snapshots__/Button.test.tsx.snap index 132275194b1..19c285f96d1 100644 --- a/src/__tests__/__snapshots__/Button.test.tsx.snap +++ b/src/__tests__/__snapshots__/Button.test.tsx.snap @@ -325,6 +325,7 @@ exports[`Button styles icon only button to make it a square 1`] = ` + @@ -1871,6 +1739,86 @@ exports[`TextInput renders trailingAction text button with a tooltip 1`] = ` margin: 4px; } +.c3:hover [data-component=tooltip], +.c3:focus-within [data-component=tooltip] { + visibility: visible; + opacity: 1; +} + +.c5 { + visibility: hidden; + opacity: 0; + -webkit-transition: opacity 100ms ease-in; + transition: opacity 100ms ease-in; + -webkit-transition-delay: 400ms; + transition-delay: 400ms; + background-color: #24292f; + color: #ffffff; + border-radius: 3px; + font-size: 12px; + padding-top: 4px; + padding-bottom: 4px; + padding-left: 8px; + padding-right: 8px; + width: -webkit-fit-content; + width: -moz-fit-content; + width: fit-content; + max-width: 250px; + text-align: center; + position: absolute; + z-index: 2; + display: inline-block; +} + +.c5:before { + content: ""; + width: 0; + height: 0; + border: 5px solid transparent; + position: absolute; +} + +.c5[data-side=outside-top]::before { + border-top: 5px solid; + border-top-color: #24292f; + top: 100%; +} + +.c5[data-side=outside-bottom]::before { + border-bottom: 5px solid; + border-bottom-color: #24292f; + top: -10px; +} + +.c5[data-side=outside-left]::before { + border-left: 5px solid; + border-left-color: #24292f; + top: calc(50% - 5px); + left: 100%; +} + +.c5[data-side=outside-right]::before { + border-right: 5px solid; + border-right-color: #24292f; + top: calc(50% - 5px); + left: -10px; +} + +.c5[data-align=start][data-side=outside-top]::before, +.c5[data-align=start][data-side=outside-bottom]::before { + left: 8px; +} + +.c5[data-align=center][data-side=outside-top]::before, +.c5[data-align=center][data-side=outside-bottom]::before { + left: calc(50% - 4px); +} + +.c5[data-align=end][data-side=outside-top]::before, +.c5[data-align=end][data-side=outside-bottom]::before { + left: calc(100% - 16px); +} + .c4 { border-radius: 6px; border: 0; @@ -2046,226 +1994,6 @@ exports[`TextInput renders trailingAction text button with a tooltip 1`] = ` outline: 0; } -.c3 { - position: relative; - display: inline-block; -} - -.c3::before { - position: absolute; - z-index: 1000001; - display: none; - width: 0px; - height: 0px; - color: #24292f; - pointer-events: none; - content: ''; - border: 6px solid transparent; - opacity: 0; -} - -.c3::after { - position: absolute; - z-index: 1000000; - display: none; - padding: 0.5em 0.75em; - font: normal normal 11px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"; - -webkit-font-smoothing: subpixel-antialiased; - color: #ffffff; - text-align: center; - -webkit-text-decoration: none; - text-decoration: none; - text-shadow: none; - text-transform: none; - -webkit-letter-spacing: normal; - -moz-letter-spacing: normal; - -ms-letter-spacing: normal; - letter-spacing: normal; - word-wrap: break-word; - white-space: pre; - pointer-events: none; - content: attr(aria-label); - background: #24292f; - border-radius: 3px; - opacity: 0; -} - -.c3:hover::before, -.c3:active::before, -.c3:focus::before, -.c3:hover::after, -.c3:active::after, -.c3:focus::after { - display: inline-block; - -webkit-text-decoration: none; - text-decoration: none; - -webkit-animation-name: tooltip-appear; - animation-name: tooltip-appear; - -webkit-animation-duration: 0.1s; - animation-duration: 0.1s; - -webkit-animation-fill-mode: forwards; - animation-fill-mode: forwards; - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - -webkit-animation-delay: 0.4s; - animation-delay: 0.4s; -} - -.c3.tooltipped-no-delay:hover::before, -.c3.tooltipped-no-delay:active::before, -.c3.tooltipped-no-delay:focus::before, -.c3.tooltipped-no-delay:hover::after, -.c3.tooltipped-no-delay:active::after, -.c3.tooltipped-no-delay:focus::after { - -webkit-animation-delay: 0s; - animation-delay: 0s; -} - -.c3.tooltipped-multiline:hover::after, -.c3.tooltipped-multiline:active::after, -.c3.tooltipped-multiline:focus::after { - display: table-cell; -} - -.c3.tooltipped-s::after, -.c3.tooltipped-se::after, -.c3.tooltipped-sw::after { - top: 100%; - right: 50%; - margin-top: 6px; -} - -.c3.tooltipped-s::before, -.c3.tooltipped-se::before, -.c3.tooltipped-sw::before { - top: auto; - right: 50%; - bottom: -7px; - margin-right: -6px; - border-bottom-color: #24292f; -} - -.c3.tooltipped-se::after { - right: auto; - left: 50%; - margin-left: -16px; -} - -.c3.tooltipped-sw::after { - margin-right: -16px; -} - -.c3.tooltipped-n::after, -.c3.tooltipped-ne::after, -.c3.tooltipped-nw::after { - right: 50%; - bottom: 100%; - margin-bottom: 6px; -} - -.c3.tooltipped-n::before, -.c3.tooltipped-ne::before, -.c3.tooltipped-nw::before { - top: -7px; - right: 50%; - bottom: auto; - margin-right: -6px; - border-top-color: #24292f; -} - -.c3.tooltipped-ne::after { - right: auto; - left: 50%; - margin-left: -16px; -} - -.c3.tooltipped-nw::after { - margin-right: -16px; -} - -.c3.tooltipped-s::after, -.c3.tooltipped-n::after { - -webkit-transform: translateX(50%); - -ms-transform: translateX(50%); - transform: translateX(50%); -} - -.c3.tooltipped-w::after { - right: 100%; - bottom: 50%; - margin-right: 6px; - -webkit-transform: translateY(50%); - -ms-transform: translateY(50%); - transform: translateY(50%); -} - -.c3.tooltipped-w::before { - top: 50%; - bottom: 50%; - left: -7px; - margin-top: -6px; - border-left-color: #24292f; -} - -.c3.tooltipped-e::after { - bottom: 50%; - left: 100%; - margin-left: 6px; - -webkit-transform: translateY(50%); - -ms-transform: translateY(50%); - transform: translateY(50%); -} - -.c3.tooltipped-e::before { - top: 50%; - right: -7px; - bottom: 50%; - margin-top: -6px; - border-right-color: #24292f; -} - -.c3.tooltipped-multiline::after { - width: -webkit-max-content; - width: -moz-max-content; - width: max-content; - max-width: 250px; - word-wrap: break-word; - white-space: pre-line; - border-collapse: separate; -} - -.c3.tooltipped-multiline.tooltipped-s::after, -.c3.tooltipped-multiline.tooltipped-n::after { - right: auto; - left: 50%; - -webkit-transform: translateX(-50%); - -ms-transform: translateX(-50%); - transform: translateX(-50%); -} - -.c3.tooltipped-multiline.tooltipped-w::after, -.c3.tooltipped-multiline.tooltipped-e::after { - right: 100%; -} - -.c3.tooltipped-align-right-2::after { - right: 0; - margin-right: 0; -} - -.c3.tooltipped-align-right-2::before { - right: 15px; -} - -.c3.tooltipped-align-left-2::after { - left: 0; - margin-left: 0; -} - -.c3.tooltipped-align-left-2::before { - left: 10px; -} - @media (forced-colors:active) { .c4:focus { outline: solid 1px transparent; @@ -2311,11 +2039,10 @@ exports[`TextInput renders trailingAction text button with a tooltip 1`] = ` className="c2 TextInput-action" > + From 8a98ac8f73d4b308599f8b1f3bdeb7ab1dd15323 Mon Sep 17 00:00:00 2001 From: Siddharth Kshetrapal Date: Mon, 9 May 2022 14:55:37 +0200 Subject: [PATCH 20/26] update behaviors to next minor --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index ffb546e756e..551e5b1367e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "35.2.0", "license": "MIT", "dependencies": { - "@primer/behaviors": "^1.1.2", + "@primer/behaviors": "^1.1.3", "@primer/octicons-react": "16.1.1", "@primer/primitives": "7.6.0", "@radix-ui/react-polymorphic": "0.0.14", @@ -5620,9 +5620,9 @@ } }, "node_modules/@primer/behaviors": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@primer/behaviors/-/behaviors-1.1.2.tgz", - "integrity": "sha512-gMlUDRc2boyme1th2Sr0tVeH6VyWjFGwuraHj08HDlkfulJ7a6VT0YU0wtSnK1FtC45ZsTXNWOSiLwXWYmLR9g==" + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@primer/behaviors/-/behaviors-1.1.3.tgz", + "integrity": "sha512-WpCcjAkXG7Lv3ZbaCUgASWKHnCi/pmuSEiyTmHHb6f5xhwk1mliixNL5ZZHtDN6RCcT3VnXUsyek4GopG2lbZQ==" }, "node_modules/@primer/octicons-react": { "version": "16.1.1", @@ -39292,9 +39292,9 @@ "dev": true }, "@primer/behaviors": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@primer/behaviors/-/behaviors-1.1.2.tgz", - "integrity": "sha512-gMlUDRc2boyme1th2Sr0tVeH6VyWjFGwuraHj08HDlkfulJ7a6VT0YU0wtSnK1FtC45ZsTXNWOSiLwXWYmLR9g==" + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@primer/behaviors/-/behaviors-1.1.3.tgz", + "integrity": "sha512-WpCcjAkXG7Lv3ZbaCUgASWKHnCi/pmuSEiyTmHHb6f5xhwk1mliixNL5ZZHtDN6RCcT3VnXUsyek4GopG2lbZQ==" }, "@primer/octicons-react": { "version": "16.1.1", diff --git a/package.json b/package.json index 9076b33d3ee..ad8bb480fc0 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ "npm": ">=7" }, "dependencies": { - "@primer/behaviors": "^1.1.2", + "@primer/behaviors": "^1.1.3", "@primer/octicons-react": "16.1.1", "@primer/primitives": "7.6.0", "@radix-ui/react-polymorphic": "0.0.14", From e228b091c9978aee371b3ead7e221d8c183a46d4 Mon Sep 17 00:00:00 2001 From: Siddharth Kshetrapal Date: Mon, 9 May 2022 14:57:28 +0200 Subject: [PATCH 21/26] update snapshots --- src/__tests__/__snapshots__/Button.test.tsx.snap | 2 +- src/__tests__/__snapshots__/TextInput.test.tsx.snap | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/__tests__/__snapshots__/Button.test.tsx.snap b/src/__tests__/__snapshots__/Button.test.tsx.snap index 19c285f96d1..a4f4d5fc709 100644 --- a/src/__tests__/__snapshots__/Button.test.tsx.snap +++ b/src/__tests__/__snapshots__/Button.test.tsx.snap @@ -325,7 +325,7 @@ exports[`Button styles icon only button to make it a square 1`] = ` + - + @@ -90,13 +90,13 @@ Set direction of tooltip with `direction`. The tooltip is responsive and will au - + - + @@ -104,6 +104,8 @@ Set direction of tooltip with `direction`. The tooltip is responsive and will au ## Props +### Tooltip + @@ -124,8 +126,8 @@ Set direction of tooltip with `direction`. The tooltip is responsive and will au /> Use aria-describedby or aria-labelledby @@ -134,11 +136,11 @@ Set direction of tooltip with `direction`. The tooltip is responsive and will au /> - + Date: Tue, 10 May 2022 15:07:16 +0200 Subject: [PATCH 26/26] fix alignment with span --- src/Tooltip/index.tsx | 3 ++- src/__tests__/__snapshots__/TextInput.test.tsx.snap | 8 ++++++++ src/__tests__/__snapshots__/Tooltip.test.tsx.snap | 4 ++++ src/stories/ActionMenu/fixtures.stories.tsx | 1 + 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Tooltip/index.tsx b/src/Tooltip/index.tsx index 7dc00b7049a..2716ac5caf5 100644 --- a/src/Tooltip/index.tsx +++ b/src/Tooltip/index.tsx @@ -79,7 +79,8 @@ export const Tooltip: React.FC = ({ {child} diff --git a/src/__tests__/__snapshots__/TextInput.test.tsx.snap b/src/__tests__/__snapshots__/TextInput.test.tsx.snap index 32438bb297c..f63eed90f8c 100644 --- a/src/__tests__/__snapshots__/TextInput.test.tsx.snap +++ b/src/__tests__/__snapshots__/TextInput.test.tsx.snap @@ -1250,6 +1250,10 @@ exports[`TextInput renders trailingAction icon button 1`] = ` margin: 4px; } +.c3 { + line-height: 1; +} + .c3:hover [data-component=tooltip], .c3:focus-within [data-component=tooltip] { visibility: visible; @@ -1846,6 +1850,10 @@ exports[`TextInput renders trailingAction text button with a tooltip 1`] = ` margin: 4px; } +.c3 { + line-height: 1; +} + .c3:hover [data-component=tooltip], .c3:focus-within [data-component=tooltip] { visibility: visible; diff --git a/src/__tests__/__snapshots__/Tooltip.test.tsx.snap b/src/__tests__/__snapshots__/Tooltip.test.tsx.snap index 7ce9a0e71a6..83b5ed41551 100644 --- a/src/__tests__/__snapshots__/Tooltip.test.tsx.snap +++ b/src/__tests__/__snapshots__/Tooltip.test.tsx.snap @@ -1,6 +1,10 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Tooltip renders consistently 1`] = ` +.c0 { + line-height: 1; +} + .c0:hover [data-component=tooltip], .c0:focus-within [data-component=tooltip] { visibility: visible; diff --git a/src/stories/ActionMenu/fixtures.stories.tsx b/src/stories/ActionMenu/fixtures.stories.tsx index 8e74c3677f9..0b077e45656 100644 --- a/src/stories/ActionMenu/fixtures.stories.tsx +++ b/src/stories/ActionMenu/fixtures.stories.tsx @@ -269,6 +269,7 @@ export function MemexTableMenu(): JSX.Element { width: 200, display: 'flex', justifyContent: 'space-between', + alignItems: 'center', p: 2, border: '1px solid', borderColor: 'border.default'