From 4efc95d8a887ac6957fe3f0c5aa57275bf63ed11 Mon Sep 17 00:00:00 2001 From: Armagan Ersoz Date: Wed, 15 Mar 2023 14:07:30 +1000 Subject: [PATCH 01/30] Refactor tooltip markup without styled components and apply a11y remediations --- src/Tooltip2.tsx | 109 ++++++++++++++++++++++++++++++++ src/stories/Tooltip.stories.tsx | 46 ++++++++++++-- 2 files changed, 151 insertions(+), 4 deletions(-) create mode 100644 src/Tooltip2.tsx diff --git a/src/Tooltip2.tsx b/src/Tooltip2.tsx new file mode 100644 index 00000000000..f5653f4ef17 --- /dev/null +++ b/src/Tooltip2.tsx @@ -0,0 +1,109 @@ +import React, {Children} from 'react' +import Box from './Box' +import {BetterSystemStyleObject, merge, SxProp} from './sx' +import {Button} from './Button' +import {IconButton} from './Button/IconButton' + +export type Tooltip2Props = { + direction?: 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w' | 'nw' + text?: string + noDelay?: boolean + align?: 'left' | 'right' + wrap?: boolean + type?: 'label' | 'description' +} & SxProp + +const tooltipClasses = ({direction, noDelay, align, wrap}: Omit) => ({ + position: 'relative', + display: 'inline-block', + '& > span': { + position: 'absolute', + zIndex: '1000001', + display: 'none', + padding: '0.5em 0.75em', + fontSize: 0, + color: 'fg.onEmphasis', + textAlign: 'center', + textDecoration: 'none', + textShadow: 'none', + textTransform: 'none', + letterSpacing: 'normal', + wordWrap: 'break-word', + whiteSpace: 'pre', + pointerEvents: 'none', + backgroundColor: 'neutral.emphasisPlus', + borderRadius: '3px', // use theme value radii.1' + opacity: 0, + }, + '&:hover, &:focus, &:active, &:focus-within': { + '& > span': { + display: 'inline-block', + opacity: 1, + // conditionally render styles depending on direction + ...(direction === 'n' && { + right: '50%', + transform: 'translateX(50%)', + bottom: '100%', + marginBottom: '6px', + }), + }, + '&::before': { + display: 'inline-block', + textDecoration: 'none', + }, + }, +}) + +const Tooltip2: React.FC> = ({ + direction = 'n', + text, + noDelay, + align, + wrap, + sx = {}, + children, + type = 'label', + ...props +}) => { + children && Children.only(children) // make sure there is only one child + const isInteractive = React.isValidElement(children) && (children.type === Button || children.type === IconButton) + if (!isInteractive) { + // eslint-disable-next-line no-console + console.error('Tooltip trigger must be an interactive React element (e.g. Button)') + } + + const child = React.cloneElement( + children as React.ReactElement<{ + 'aria-describedby'?: string + 'aria-labelledby'?: string + 'aria-label'?: string + }>, + { + // use aria-describedby if the type is description + 'aria-describedby': type === 'description' ? 'tooltip-id-random-id' : undefined, + // use aria-label if the child is a button + 'aria-labelledby': type === 'description' ? undefined : 'tooltip-id-random-id', + // remove aria-label if the child has an aria-labelledby + 'aria-label': type === 'label' ? undefined : (children as React.ReactElement).props['aria-label'], + }, + ) + + return ( + (tooltipClasses({direction, noDelay, align, wrap}), sx)} {...props}> + {isInteractive && child} + + + {text || (children as React.ReactElement).props['aria-label']} + + + ) +} + +export default Tooltip2 diff --git a/src/stories/Tooltip.stories.tsx b/src/stories/Tooltip.stories.tsx index 316b0f469b3..9bdba992c10 100644 --- a/src/stories/Tooltip.stories.tsx +++ b/src/stories/Tooltip.stories.tsx @@ -1,9 +1,10 @@ import React from 'react' import {Meta} from '@storybook/react' -import {BaseStyles, ThemeProvider, IconButton} from '..' -import Box from '../Box' +import {BaseStyles, ThemeProvider, IconButton, Button} from '..' import Tooltip from '../Tooltip' +import Tooltip2 from '../Tooltip2' import {SearchIcon} from '@primer/octicons-react' +import Box from '../Box' export default { title: 'Components/Tooltip/Default', @@ -22,10 +23,47 @@ export default { ], } as Meta -export const IconButtonTooltip = () => ( +export const CurrentTooltip = () => ( - + ) + +// As a label for an IconButton +export const Tooltip2LabelTypeTooltip = () => ( + + + + + +) + +// As a supplementary description for a button +export const Tooltip2DescriptionTypeTooltip = () => ( + + + + + +) + +// As a supplementary description for an IconButton +export const Tooltip2IconButtonWithDescription = () => ( + + + + + +) + +// As a supplementary description for a button +export const MultipleChildren = () => ( + + + + + + +) From e2b140bc4c29a11e6386da6f25b30f1e95a107b6 Mon Sep 17 00:00:00 2001 From: Armagan Ersoz Date: Thu, 16 Mar 2023 09:18:05 +1000 Subject: [PATCH 02/30] experiment tooltip --- src/Tooltip2.tsx | 17 +++++++++-------- src/stories/Tooltip.stories.tsx | 3 +-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Tooltip2.tsx b/src/Tooltip2.tsx index f5653f4ef17..fc3b942efd9 100644 --- a/src/Tooltip2.tsx +++ b/src/Tooltip2.tsx @@ -11,9 +11,11 @@ export type Tooltip2Props = { align?: 'left' | 'right' wrap?: boolean type?: 'label' | 'description' + // Only allow interactive elements ?? How would that work with PropsWithChildren?? + children: React.ReactElement> // how can I type it with native HTML elements? } & SxProp -const tooltipClasses = ({direction, noDelay, align, wrap}: Omit) => ({ +const tooltipClasses = ({direction, noDelay, align, wrap}: Omit) => ({ position: 'relative', display: 'inline-block', '& > span': { @@ -66,7 +68,7 @@ const Tooltip2: React.FC> = ({ ...props }) => { children && Children.only(children) // make sure there is only one child - const isInteractive = React.isValidElement(children) && (children.type === Button || children.type === IconButton) + const isInteractive = React.isValidElement(children) //&& (children.type === Button || children.type === IconButton) if (!isInteractive) { // eslint-disable-next-line no-console console.error('Tooltip trigger must be an interactive React element (e.g. Button)') @@ -79,19 +81,18 @@ const Tooltip2: React.FC> = ({ 'aria-label'?: string }>, { - // use aria-describedby if the type is description + // if it is a type description, we use tooltip to describe the trigger 'aria-describedby': type === 'description' ? 'tooltip-id-random-id' : undefined, - // use aria-label if the child is a button - 'aria-labelledby': type === 'description' ? undefined : 'tooltip-id-random-id', - // remove aria-label if the child has an aria-labelledby - 'aria-label': type === 'label' ? undefined : (children as React.ReactElement).props['aria-label'], + // If it is a type description, we should keep the aria label if it exists, otherwise we remove it because we will use aria-labelledby + 'aria-label': type === 'description' ? (children as React.ReactElement).props['aria-label'] : undefined, + // If it is a label type, we use tooltip to label the trigger + 'aria-labelledby': type === 'label' ? 'tooltip-id-random-id' : undefined, }, ) return ( (tooltipClasses({direction, noDelay, align, wrap}), sx)} {...props}> {isInteractive && child} - ( export const MultipleChildren = () => ( - - + one button ) From 84d93ebd020b5de2a9ad11189e16b42acaf22e58 Mon Sep 17 00:00:00 2001 From: Armagan Ersoz Date: Thu, 16 Mar 2023 16:51:02 +1000 Subject: [PATCH 03/30] checking interactive elements and clean the code a bit --- src/Tooltip2.tsx | 109 ++++++++++++++++++++------------ src/stories/Tooltip.stories.tsx | 38 +++++++++-- 2 files changed, 104 insertions(+), 43 deletions(-) diff --git a/src/Tooltip2.tsx b/src/Tooltip2.tsx index fc3b942efd9..fab2a4da56a 100644 --- a/src/Tooltip2.tsx +++ b/src/Tooltip2.tsx @@ -1,8 +1,8 @@ -import React, {Children} from 'react' +import React, {Children, useEffect, useRef} from 'react' import Box from './Box' import {BetterSystemStyleObject, merge, SxProp} from './sx' -import {Button} from './Button' -import {IconButton} from './Button/IconButton' +import {useId} from './hooks/useId' +import {isFocusable} from '@primer/behaviors/utils' export type Tooltip2Props = { direction?: 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w' | 'nw' @@ -11,10 +11,14 @@ export type Tooltip2Props = { align?: 'left' | 'right' wrap?: boolean type?: 'label' | 'description' - // Only allow interactive elements ?? How would that work with PropsWithChildren?? - children: React.ReactElement> // how can I type it with native HTML elements? } & SxProp +export type TriggerPropsType = { + 'aria-describedby'?: string + 'aria-labelledby'?: string + 'aria-label'?: string +} + const tooltipClasses = ({direction, noDelay, align, wrap}: Omit) => ({ position: 'relative', display: 'inline-block', @@ -37,21 +41,48 @@ const tooltipClasses = ({direction, noDelay, align, wrap}: Omit span': { display: 'inline-block', opacity: 1, // conditionally render styles depending on direction - ...(direction === 'n' && { + ...((direction === 'n' || direction === 'ne' || direction === 'nw') && { right: '50%', - transform: 'translateX(50%)', bottom: '100%', marginBottom: '6px', }), + // only for n direction + ...(direction === 'n' && { + transform: 'translateX(50%)', + }), + ...((direction === 's' || direction === 'se' || direction === 'sw') && {}), }, '&::before': { display: 'inline-block', textDecoration: 'none', + opacity: 1, + // conditionally render styles depending on direction + ...((direction === 'n' || direction === 'ne' || direction === 'nw') && { + borderTopColor: 'neutral.emphasisPlus', + top: '-7px', + bottom: 'auto', + right: '50%', + marginRight: '-6px', + }), }, }, }) @@ -67,41 +98,41 @@ const Tooltip2: React.FC> = ({ type = 'label', ...props }) => { - children && Children.only(children) // make sure there is only one child - const isInteractive = React.isValidElement(children) //&& (children.type === Button || children.type === IconButton) - if (!isInteractive) { - // eslint-disable-next-line no-console - console.error('Tooltip trigger must be an interactive React element (e.g. Button)') - } + const id = useId() + const tooltipRef = useRef(null) + const child = Children.only(children) // make sure there is only one child - const child = React.cloneElement( - children as React.ReactElement<{ - 'aria-describedby'?: string - 'aria-labelledby'?: string - 'aria-label'?: string - }>, - { - // if it is a type description, we use tooltip to describe the trigger - 'aria-describedby': type === 'description' ? 'tooltip-id-random-id' : undefined, - // If it is a type description, we should keep the aria label if it exists, otherwise we remove it because we will use aria-labelledby - 'aria-label': type === 'description' ? (children as React.ReactElement).props['aria-label'] : undefined, - // If it is a label type, we use tooltip to label the trigger - 'aria-labelledby': type === 'label' ? 'tooltip-id-random-id' : undefined, - }, - ) + // we need this check for every render + useEffect(() => { + if (tooltipRef.current) { + const childNode = tooltipRef.current.children[0] // For now, I assume it has one node but that is not true + if (!isFocusable(childNode as HTMLElement)) { + throw new Error('Tooltip2: The child element must be focusable') + } + } + }) + const triggerProps = { + // if it is a type description, we use tooltip to describe the trigger + 'aria-describedby': type === 'description' ? id : undefined, + // If it is a type description, we should keep the aria label if it exists, otherwise we remove it because we will use aria-labelledby + 'aria-label': type === 'description' ? (children as React.ReactElement).props['aria-label'] : undefined, + // If it is a label type, we use tooltip to label the trigger + 'aria-labelledby': type === 'label' ? id : undefined, + } + // Only need tooltip role if the tooltip is a description for supplementary information + const role = type === 'description' ? 'tooltip' : undefined + // aria-hidden true only if the tooltip is a label type + const ariaHidden = type === 'label' ? true : undefined return ( - (tooltipClasses({direction, noDelay, align, wrap}), sx)} {...props}> - {isInteractive && child} - - {text || (children as React.ReactElement).props['aria-label']} + (tooltipClasses({direction, noDelay, align, wrap}), sx)} + {...props} + > + {React.cloneElement(child as React.ReactElement, triggerProps)} + + {text || (child as React.ReactElement).props['aria-label']} ) diff --git a/src/stories/Tooltip.stories.tsx b/src/stories/Tooltip.stories.tsx index 7184b71809e..10e17f01743 100644 --- a/src/stories/Tooltip.stories.tsx +++ b/src/stories/Tooltip.stories.tsx @@ -43,7 +43,7 @@ export const Tooltip2LabelTypeTooltip = () => ( // As a supplementary description for a button export const Tooltip2DescriptionTypeTooltip = () => ( - + @@ -52,7 +52,7 @@ export const Tooltip2DescriptionTypeTooltip = () => ( // As a supplementary description for an IconButton export const Tooltip2IconButtonWithDescription = () => ( - + @@ -61,8 +61,38 @@ export const Tooltip2IconButtonWithDescription = () => ( // As a supplementary description for a button export const MultipleChildren = () => ( - - one button + + + + + +) + +export const WithDirection = () => ( + + + + + + + + + + + + + + + + + + + + + + + + ) From 842f50e2b1bd5b52906d055972fa755618678bcd Mon Sep 17 00:00:00 2001 From: Armagan Ersoz Date: Thu, 16 Mar 2023 18:13:40 +1000 Subject: [PATCH 04/30] add another story --- src/stories/Tooltip.stories.tsx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/stories/Tooltip.stories.tsx b/src/stories/Tooltip.stories.tsx index 10e17f01743..e7f60747965 100644 --- a/src/stories/Tooltip.stories.tsx +++ b/src/stories/Tooltip.stories.tsx @@ -40,6 +40,15 @@ export const Tooltip2LabelTypeTooltip = () => ( ) +// As a label for an IconButton +export const Tooltip2CustomIcon = () => ( + + + + + +) + // As a supplementary description for a button export const Tooltip2DescriptionTypeTooltip = () => ( From f052247aef1a06cafe50993a4284abbe4da7afbb Mon Sep 17 00:00:00 2001 From: Armagan Ersoz Date: Mon, 20 Mar 2023 12:56:11 +1000 Subject: [PATCH 05/30] style fixes and more stories --- src/Tooltip2.tsx | 178 ++++++++++++++++++++++++++------ src/stories/Tooltip.stories.tsx | 96 ++++++++++++++++- 2 files changed, 242 insertions(+), 32 deletions(-) diff --git a/src/Tooltip2.tsx b/src/Tooltip2.tsx index fab2a4da56a..3c593cf29a2 100644 --- a/src/Tooltip2.tsx +++ b/src/Tooltip2.tsx @@ -19,15 +19,35 @@ export type TriggerPropsType = { 'aria-label'?: string } +const TOOLTIP_ARROW_EDGE_OFFSET = '16' + const tooltipClasses = ({direction, noDelay, align, wrap}: Omit) => ({ position: 'relative', display: 'inline-block', + // The caret + '&::before': { + position: 'absolute', + zIndex: '1000001', + display: 'none', + content: '""', + width: 0, + height: 0, + color: 'neutral.onEmphasis', + pointerEvents: 'none', + borderStyle: 'solid', + borderWidth: '6px', + borderColor: 'transparent', + opacity: 0, + }, + // popover '& > span': { position: 'absolute', zIndex: '1000001', display: 'none', padding: '0.5em 0.75em', fontSize: 0, + // font: normal normal 11px/1.5 ${get('fonts.normal')}; + // -webkit-font-smoothing: subpixel-antialiased; color: 'fg.onEmphasis', textAlign: 'center', textDecoration: 'none', @@ -38,43 +58,105 @@ const tooltipClasses = ({direction, noDelay, align, wrap}: Omit span': { + '&:hover, &:active, &:focus, &:focus-within': { + '&::before, & > span': { display: 'inline-block', - opacity: 1, + textDecoration: 'none', + animationName: 'tooltip-appear', + animationDuration: '0.1s', + animationFillMode: 'forwards', + animationTimingFunction: 'ease-in', + animationDelay: noDelay ? '0s' : '0.4s', + }, + '& > span': { + // Left align tooltips with align prop + ...(align === 'left' && { + left: '0', + marginLeft: '0', + }), + // Right align tooltips with align prop + ...(align === 'right' && { + right: '0', + marginRight: '0', + }), // conditionally render styles depending on direction ...((direction === 'n' || direction === 'ne' || direction === 'nw') && { right: '50%', bottom: '100%', marginBottom: '6px', }), - // only for n direction - ...(direction === 'n' && { + ...(direction === 'ne' && { + right: 'auto', + left: '50%', + marginLeft: `-${TOOLTIP_ARROW_EDGE_OFFSET}px`, // space.3? + }), + ...(direction === 'nw' && { + marginRight: `-${TOOLTIP_ARROW_EDGE_OFFSET}px`, // space.3? + }), + ...((direction === 's' || direction === 'se' || direction === 'sw') && { + top: '100%', + right: '50%', + marginTop: '6px', + }), + ...(direction === 'se' && { + right: 'auto', + left: '50%', + marginLeft: `-${TOOLTIP_ARROW_EDGE_OFFSET}px`, // space.3? + }), + ...(direction === 'sw' && { + marginRight: `-${TOOLTIP_ARROW_EDGE_OFFSET}px`, // space.3? + }), + ...(direction === 'e' && { + left: '100%', + bottom: '50%', + marginLeft: '6px', + transform: 'translateY(50%)', + }), + ...(direction === 'w' && { + right: '100%', + bottom: '50%', + marginRight: '6px', + transform: 'translateY(50%)', + }), + // only for s and n direction to move the popover bovy to the center of the trigger + ...((direction === 'n' || direction === 's') && { transform: 'translateX(50%)', }), - ...((direction === 's' || direction === 'se' || direction === 'sw') && {}), + // Multiline tooltips with wrap prop + ...(wrap && { + display: 'table-cell', + width: 'max-content', + maxWidth: '250px', + wordWrap: 'break-word', + whiteSpace: 'pre-line', + borderCollapse: 'separate', + }), + // Some styles of the directions need to be overriden when wrap is true + ...(wrap && + (direction === 's' || direction === 'n') && { + right: 'auto', + left: '50%', + transform: 'translateX(-50%)', + }), + ...(wrap && + (direction === 'w' || direction === 'e') && { + right: '100%', + }), }, '&::before': { display: 'inline-block', textDecoration: 'none', - opacity: 1, + // Left align tooltips with align prop + ...(align === 'left' && { + left: '10px', + }), + // Right align tooltips with align prop + ...(align === 'right' && { + right: '15px', + }), // conditionally render styles depending on direction ...((direction === 'n' || direction === 'ne' || direction === 'nw') && { borderTopColor: 'neutral.emphasisPlus', @@ -83,6 +165,27 @@ const tooltipClasses = ({direction, noDelay, align, wrap}: Omit> = ({ const ariaHidden = type === 'label' ? true : undefined return ( - (tooltipClasses({direction, noDelay, align, wrap}), sx)} - {...props} - > - {React.cloneElement(child as React.ReactElement, triggerProps)} - - {text || (child as React.ReactElement).props['aria-label']} + <> + + (tooltipClasses({direction, noDelay, align, wrap}), sx)} + {...props} + > + {React.cloneElement(child as React.ReactElement, triggerProps)} + + {text || (child as React.ReactElement).props['aria-label']} + - + ) } diff --git a/src/stories/Tooltip.stories.tsx b/src/stories/Tooltip.stories.tsx index e7f60747965..9502505148e 100644 --- a/src/stories/Tooltip.stories.tsx +++ b/src/stories/Tooltip.stories.tsx @@ -77,7 +77,61 @@ export const MultipleChildren = () => ( ) -export const WithDirection = () => ( +export const CurrentTooltipVariations = () => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {/* Align left seems to be broken */} + + + + + + + + +) + +export const Tooltip2WithDirection = () => ( @@ -103,5 +157,45 @@ export const WithDirection = () => ( + + + + +) + +export const Tooltip2WithAlign = () => ( + + + + + + + + +) + +export const Tooltip2WithWrap = () => ( + + + + + + + ) From fff246f887581147a825de76bfb5a161d59d3996 Mon Sep 17 00:00:00 2001 From: Armagan Ersoz Date: Mon, 20 Mar 2023 19:40:56 +1000 Subject: [PATCH 06/30] refactor it to use internal open state and make css presudo classes redundant --- src/Tooltip2.tsx | 169 ++++++++++++++++++++++++++++------------------- 1 file changed, 102 insertions(+), 67 deletions(-) diff --git a/src/Tooltip2.tsx b/src/Tooltip2.tsx index 3c593cf29a2..af46cf0e642 100644 --- a/src/Tooltip2.tsx +++ b/src/Tooltip2.tsx @@ -1,4 +1,4 @@ -import React, {Children, useEffect, useRef} from 'react' +import React, {Children, useEffect, useRef, useState} from 'react' import Box from './Box' import {BetterSystemStyleObject, merge, SxProp} from './sx' import {useId} from './hooks/useId' @@ -17,14 +17,25 @@ export type TriggerPropsType = { 'aria-describedby'?: string 'aria-labelledby'?: string 'aria-label'?: string + onFocus?: (event: React.FocusEventHandler) => void + onBlur?: (event: React.FocusEventHandler) => void + onMouseEnter?: (event: React.MouseEvent) => void + onMouseLeave?: (event: React.MouseEvent) => void + onKeyDown?: (event: React.KeyboardEvent) => void } const TOOLTIP_ARROW_EDGE_OFFSET = '16' -const tooltipClasses = ({direction, noDelay, align, wrap}: Omit) => ({ +const tooltipStyle = ({ + direction, + noDelay, + align, + wrap, + open, +}: Pick & {open: boolean}) => ({ position: 'relative', display: 'inline-block', - // The caret + '&::before': { position: 'absolute', zIndex: '1000001', @@ -38,6 +49,47 @@ const tooltipClasses = ({direction, noDelay, align, wrap}: Omit span': { @@ -60,28 +112,7 @@ const tooltipClasses = ({direction, noDelay, align, wrap}: Omit span': { - display: 'inline-block', - textDecoration: 'none', - animationName: 'tooltip-appear', - animationDuration: '0.1s', - animationFillMode: 'forwards', - animationTimingFunction: 'ease-in', - animationDelay: noDelay ? '0s' : '0.4s', - }, - '& > span': { - // Left align tooltips with align prop - ...(align === 'left' && { - left: '0', - marginLeft: '0', - }), - // Right align tooltips with align prop - ...(align === 'right' && { - right: '0', - marginRight: '0', - }), + ...(open && { // conditionally render styles depending on direction ...((direction === 'n' || direction === 'ne' || direction === 'nw') && { right: '50%', @@ -125,6 +156,16 @@ const tooltipClasses = ({direction, noDelay, align, wrap}: Omit span': { + ...(open && { display: 'inline-block', textDecoration: 'none', - // Left align tooltips with align prop - ...(align === 'left' && { - left: '10px', - }), - // Right align tooltips with align prop - ...(align === 'right' && { - right: '15px', - }), - // conditionally render styles depending on direction - ...((direction === 'n' || direction === 'ne' || direction === 'nw') && { - borderTopColor: 'neutral.emphasisPlus', - top: '-7px', - bottom: 'auto', - right: '50%', - marginRight: '-6px', - }), - ...((direction === 's' || direction === 'se' || direction === 'sw') && { - borderBottomColor: 'neutral.emphasisPlus', - top: 'auto', - bottom: '-7px', - right: '50%', - marginRight: '-6px', - }), - ...(direction === 'e' && { - borderRightColor: 'neutral.emphasisPlus', - top: '50%', - right: '-7px', - bottom: '50%', - marginTop: '-6px', - }), - ...(direction === 'w' && { - borderLeftColor: 'neutral.emphasisPlus', - top: '50%', - bottom: '50%', - left: '-7px', - marginTop: '-6px', - }), - }, + animationName: 'tooltip-appear', + animationDuration: '0.1s', + animationFillMode: 'forwards', + animationTimingFunction: 'ease-in', + animationDelay: noDelay ? '0s' : '0.4s', + }), }, }) @@ -204,6 +216,7 @@ const Tooltip2: React.FC> = ({ const id = useId() const tooltipRef = useRef(null) const child = Children.only(children) // make sure there is only one child + const [open, setOpen] = useState(false) // we need this check for every render useEffect(() => { @@ -222,6 +235,7 @@ const Tooltip2: React.FC> = ({ // If it is a label type, we use tooltip to label the trigger 'aria-labelledby': type === 'label' ? id : undefined, } + // Only need tooltip role if the tooltip is a description for supplementary information const role = type === 'description' ? 'tooltip' : undefined // aria-hidden true only if the tooltip is a label type @@ -242,10 +256,31 @@ const Tooltip2: React.FC> = ({ (tooltipClasses({direction, noDelay, align, wrap}), sx)} + sx={merge(tooltipStyle({direction, noDelay, align, wrap, open}), sx)} {...props} > - {React.cloneElement(child as React.ReactElement, triggerProps)} + {React.cloneElement(child as React.ReactElement, { + ...triggerProps, + // Optimise this? + onFocus: () => { + setOpen(true) + }, + // onBlur: () => { + // setOpen(false) + // }, + onMouseEnter: () => { + setOpen(true) + }, + // onMouseLeave: () => { + // setOpen(false) + // }, + onKeyDown: (e: React.KeyboardEvent) => { + if (open && e.key === 'Escape') { + e.stopPropagation() + setOpen(false) + } + }, + })} {text || (child as React.ReactElement).props['aria-label']} From 16a82583ca4473c66ff23c131cba3ef5bdbd4add Mon Sep 17 00:00:00 2001 From: Armagan Ersoz Date: Tue, 21 Mar 2023 12:31:32 +1000 Subject: [PATCH 07/30] apply code review feedback --- src/Tooltip2.tsx | 123 ++++++++++++++++++++------------ src/stories/Tooltip.stories.tsx | 12 +++- 2 files changed, 88 insertions(+), 47 deletions(-) diff --git a/src/Tooltip2.tsx b/src/Tooltip2.tsx index af46cf0e642..6610fdf3fff 100644 --- a/src/Tooltip2.tsx +++ b/src/Tooltip2.tsx @@ -3,6 +3,7 @@ import Box from './Box' import {BetterSystemStyleObject, merge, SxProp} from './sx' import {useId} from './hooks/useId' import {isFocusable} from '@primer/behaviors/utils' +import {invariant} from './utils/invariant' export type Tooltip2Props = { direction?: 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w' | 'nw' @@ -11,17 +12,13 @@ export type Tooltip2Props = { align?: 'left' | 'right' wrap?: boolean type?: 'label' | 'description' + 'aria-label'?: React.AriaAttributes['aria-label'] } & SxProp export type TriggerPropsType = { 'aria-describedby'?: string 'aria-labelledby'?: string 'aria-label'?: string - onFocus?: (event: React.FocusEventHandler) => void - onBlur?: (event: React.FocusEventHandler) => void - onMouseEnter?: (event: React.MouseEvent) => void - onMouseLeave?: (event: React.MouseEvent) => void - onKeyDown?: (event: React.KeyboardEvent) => void } const TOOLTIP_ARROW_EDGE_OFFSET = '16' @@ -204,7 +201,10 @@ const tooltipStyle = ({ const Tooltip2: React.FC> = ({ direction = 'n', + // used for description type text, + // used for label type + 'aria-label': label, noDelay, align, wrap, @@ -219,27 +219,66 @@ const Tooltip2: React.FC> = ({ const [open, setOpen] = useState(false) // we need this check for every render - useEffect(() => { - if (tooltipRef.current) { - const childNode = tooltipRef.current.children[0] // For now, I assume it has one node but that is not true - if (!isFocusable(childNode as HTMLElement)) { - throw new Error('Tooltip2: The child element must be focusable') + if (__DEV__) { + // Practically, this is not a conditional hook, it is a compile time check + // eslint-disable-next-line react-hooks/rules-of-hooks + useEffect(() => { + if (tooltipRef.current) { + const childNode = tooltipRef.current.children[0] // For now, I assume it has one node but that is not true + invariant( + isFocusable(childNode as HTMLElement), + 'The `Tooltip2` component expects a single React element that contains interactive content. Consider using a ` @@ -168,6 +168,12 @@ export const Tooltip2WithDirection = () => ( ) +export const Tooltip2Single = () => ( + + + +) + export const Tooltip2WithAlign = () => ( From 8be4e6c8e303bb50504745f6465584bf3cb375a5 Mon Sep 17 00:00:00 2001 From: Armagan Ersoz Date: Wed, 22 Mar 2023 13:06:35 +1000 Subject: [PATCH 08/30] Refactor the styles to use data-attr and styled-components --- src/Tooltip2.tsx | 226 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 183 insertions(+), 43 deletions(-) diff --git a/src/Tooltip2.tsx b/src/Tooltip2.tsx index 6610fdf3fff..31f098dd1ae 100644 --- a/src/Tooltip2.tsx +++ b/src/Tooltip2.tsx @@ -1,9 +1,11 @@ import React, {Children, useEffect, useRef, useState} from 'react' import Box from './Box' -import {BetterSystemStyleObject, merge, SxProp} from './sx' +import sx, {SxProp} from './sx' import {useId} from './hooks/useId' import {isFocusable} from '@primer/behaviors/utils' import {invariant} from './utils/invariant' +import styled from 'styled-components' +import {get} from './constants' export type Tooltip2Props = { direction?: 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w' | 'nw' @@ -23,6 +25,165 @@ export type TriggerPropsType = { const TOOLTIP_ARROW_EDGE_OFFSET = '16' +const TooltipBase = styled.div` + position: relative; + display: inline-block; + + &::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; + } + + & > span { + 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; + } + } + + &[data-state='open'] { + &::before, + & > span { + 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: ${props => (props.noDelay ? '0s' : '0.4s')}; + + } + + &[data-direction='s'], + &[data-direction='se'], + &[data-direction='sw'] { + & > span { + top: 100%; + right: 50%; + margin-top: 6px; + } + &::before { + top: auto; + right: 50%; + bottom: -7px; + margin-right: -6px; + border-bottom-color: ${get('colors.neutral.emphasisPlus')}; + } + } + &[data-direction='se'] > span { + right: auto; + left: 50%; + margin-left: -${get('space.3')}; + } + + &[data-direction='sw'] > span { + margin-right: -${get('space.3')}; + } + + &[data-direction='n'], + &[data-direction='ne'], + &[data-direction='nw'] { + & > span { + right: 50%; + bottom: 100%; + margin-bottom: 6px; + } + &::before { + top: -7px; + right: 50%; + bottom: auto; + margin-right: -6px; + border-top-color: ${get('colors.neutral.emphasisPlus')}; + } + } + + &[data-direction='ne'] > span { + right: auto; + left: 50%; + margin-left: -${get('space.3')}; + } + + &[data-direction='nw'] > span { + margin-right: -${get('space.3')}; + } + + &[data-direction='n'], + &[data-direction='s'] { + & > span { + transform: translateX(50%); + } + } + + &[data-direction='e'] { + & > span { + 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')}; + } + } + + &[data-direction='w'] { + & > span { + 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')}; + } + } + + ${sx}; +` + const tooltipStyle = ({ direction, noDelay, @@ -205,13 +366,9 @@ const Tooltip2: React.FC> = ({ text, // used for label type 'aria-label': label, - noDelay, - align, - wrap, - sx = {}, children, type = 'label', - ...props + ...rest }) => { const id = useId() const tooltipRef = useRef(null) @@ -281,46 +438,29 @@ const Tooltip2: React.FC> = ({ } return ( - <> - + + {React.cloneElement(child as React.ReactElement, { + ...{ + // if it is a type description, we use tooltip to describe the trigger + 'aria-describedby': type === 'description' ? id : undefined, + // If it is a type description, we should keep the aria label if it exists, otherwise we remove it because we will use aria-labelledby + 'aria-label': type === 'description' ? (children as React.ReactElement).props['aria-label'] : undefined, + // If it is a label type, we use tooltip to label the trigger + 'aria-labelledby': type === 'label' ? id : undefined, + }, + ...composeEventHandlers(child as React.ReactElement), + })} (tooltipStyle({direction, noDelay, align, wrap, open}), sx)} - {...props} + as="span" + // Only need tooltip role if the tooltip is a description for supplementary information + role={type === 'description' ? 'tooltip' : undefined} + // stop AT from announcing the tooltip twice when it is a label type because it will be announced with "aria-labelledby" + aria-hidden={type === 'label' ? true : undefined} + id={id} > - {React.cloneElement(child as React.ReactElement, { - ...{ - // if it is a type description, we use tooltip to describe the trigger - 'aria-describedby': type === 'description' ? id : undefined, - // If it is a type description, we should keep the aria label if it exists, otherwise we remove it because we will use aria-labelledby - // 'aria-label': type === 'description' ? (children as React.ReactElement).props['aria-label'] : undefined, - // If it is a label type, we use tooltip to label the trigger - 'aria-labelledby': type === 'label' ? id : undefined, - }, - ...composeEventHandlers(child as React.ReactElement), - })} - - {text || label} - + {text || label} - + ) } From 03a081a2acd6dc489066568da745625b642a2c94 Mon Sep 17 00:00:00 2001 From: Armagan Ersoz Date: Wed, 22 Mar 2023 15:05:51 +1000 Subject: [PATCH 09/30] update events --- src/Tooltip2.tsx | 45 ++++++++++++++++++++------------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/src/Tooltip2.tsx b/src/Tooltip2.tsx index 31f098dd1ae..dd2e16c565c 100644 --- a/src/Tooltip2.tsx +++ b/src/Tooltip2.tsx @@ -32,7 +32,7 @@ const TooltipBase = styled.div` &::before { position: absolute; z-index: 1000001; - display: none; + width: 0px; height: 0px; color: ${get('colors.neutral.emphasisPlus')}; @@ -45,7 +45,7 @@ const TooltipBase = styled.div` & > span { 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; @@ -393,25 +393,14 @@ const Tooltip2: React.FC> = ({ const triggerEvtHandlers = { onFocus: () => setOpen(true), onBlur: () => setOpen(false), - onMouseEnter: () => setOpen(true), - onMouseLeave: () => setOpen(false), - onKeyDown: (e: React.KeyboardEvent) => { - if (open && e.key === 'Escape') { - e.stopPropagation() - setOpen(false) - } + onMouseEnter: () => { + setOpen(true) }, } // Make sure to compose the default event handlers for tooltip trigger with the ones that are passed in function composeEventHandlers(child: React.ReactElement) { - const { - onBlur: _onBlur, - onFocus: _onFocus, - onMouseEnter: _onMouseEnter, - onMouseLeave: _onMouseLeave, - onKeyDown: _onKeyDown, - } = child.props + const {onBlur: _onBlur, onFocus: _onFocus, onMouseEnter: _onMouseEnter} = child.props return { onBlur: () => { @@ -426,19 +415,25 @@ const Tooltip2: React.FC> = ({ _onMouseEnter && _onMouseEnter() triggerEvtHandlers.onMouseEnter() }, - onMouseLeave: () => { - _onMouseLeave && _onMouseLeave() - triggerEvtHandlers.onMouseLeave() - }, - onKeyDown: (evt: React.KeyboardEvent) => { - _onKeyDown && _onKeyDown() - triggerEvtHandlers.onKeyDown(evt) - }, + } + } + + function onKeyDown(e: React.KeyboardEvent) { + if (open && e.key === 'Escape') { + e.stopPropagation() + setOpen(false) } } return ( - + setOpen(false)} + onKeyDown={onKeyDown} + {...rest} + > {React.cloneElement(child as React.ReactElement, { ...{ // if it is a type description, we use tooltip to describe the trigger From 55d5f0f5c6b600d3d5d2f93676059c542033e705 Mon Sep 17 00:00:00 2001 From: Armagan Ersoz Date: Thu, 23 Mar 2023 18:57:16 +1000 Subject: [PATCH 10/30] align and wrap styles with data attr --- src/Tooltip2.tsx | 238 ++++++++------------------------ src/stories/Tooltip.stories.tsx | 6 +- 2 files changed, 62 insertions(+), 182 deletions(-) diff --git a/src/Tooltip2.tsx b/src/Tooltip2.tsx index dd2e16c565c..7a251e66d06 100644 --- a/src/Tooltip2.tsx +++ b/src/Tooltip2.tsx @@ -84,10 +84,15 @@ const TooltipBase = styled.div` animation-duration: 0.1s; animation-fill-mode: forwards; animation-timing-function: ease-in; - animation-delay: ${props => (props.noDelay ? '0s' : '0.4s')}; - + animation-delay: 0.4s; } + &[data-delay='true'] { + &::before, + & > span { + animation-delay: 0s; + } + } &[data-direction='s'], &[data-direction='se'], &[data-direction='sw'] { @@ -180,185 +185,54 @@ const TooltipBase = styled.div` border-left-color: ${get('colors.neutral.emphasisPlus')}; } } + &[data-align='left'] { + & > span { + right: 100%; + margin-left: 0; + } + &::before { + left: 10px; + } + } + &[data-align='right'] { + & > span { + right: 0; + margin-right: 0; + } + &::before { + right: 15px; + } + } + &[data-wrap='true'] { + & > span { + display: table-cell; + width: max-content; + max-width: 250px; + word-wrap: break-word; + white-space: pre-line; + border-collapse: separate; + } + } - ${sx}; -` - -const tooltipStyle = ({ - direction, - noDelay, - align, - wrap, - open, -}: Pick & {open: boolean}) => ({ - position: 'relative', - display: 'inline-block', + &[data-wrap='true'][data-direction='n'], + &[data-wrap='true'][data-direction='s']{ + & > span { + transform: translateX(-50%); + right: auto; + left: 50%; + } + } - '&::before': { - position: 'absolute', - zIndex: '1000001', - display: 'none', - content: '""', - width: 0, - height: 0, - color: 'neutral.onEmphasis', - pointerEvents: 'none', - borderStyle: 'solid', - borderWidth: '6px', - borderColor: 'transparent', - opacity: 0, - ...(open && { - display: 'inline-block', - textDecoration: 'none', - // conditionally render styles depending on direction - ...((direction === 'n' || direction === 'ne' || direction === 'nw') && { - borderTopColor: 'neutral.emphasisPlus', - top: '-7px', - bottom: 'auto', - right: '50%', - marginRight: '-6px', - }), - ...((direction === 's' || direction === 'se' || direction === 'sw') && { - borderBottomColor: 'neutral.emphasisPlus', - top: 'auto', - bottom: '-7px', - right: '50%', - marginRight: '-6px', - }), - ...(direction === 'e' && { - borderRightColor: 'neutral.emphasisPlus', - top: '50%', - right: '-7px', - bottom: '50%', - marginTop: '-6px', - }), - ...(direction === 'w' && { - borderLeftColor: 'neutral.emphasisPlus', - top: '50%', - bottom: '50%', - left: '-7px', - marginTop: '-6px', - }), - // Left align tooltips with align prop - ...(align === 'left' && { - left: '10px', - }), - // Right align tooltips with align prop - ...(align === 'right' && { - right: '15px', - }), - }), - }, - // popover - '& > span': { - position: 'absolute', - zIndex: '1000001', - display: 'none', - padding: '0.5em 0.75em', - fontSize: 0, - // font: normal normal 11px/1.5 ${get('fonts.normal')}; - // -webkit-font-smoothing: subpixel-antialiased; - color: 'fg.onEmphasis', - textAlign: 'center', - textDecoration: 'none', - textShadow: 'none', - textTransform: 'none', - letterSpacing: 'normal', - wordWrap: 'break-word', - whiteSpace: 'pre', - pointerEvents: 'none', - backgroundColor: 'neutral.emphasisPlus', - borderRadius: '3px', // radii.2 - opacity: 0, - ...(open && { - // conditionally render styles depending on direction - ...((direction === 'n' || direction === 'ne' || direction === 'nw') && { - right: '50%', - bottom: '100%', - marginBottom: '6px', - }), - ...(direction === 'ne' && { - right: 'auto', - left: '50%', - marginLeft: `-${TOOLTIP_ARROW_EDGE_OFFSET}px`, // space.3? - }), - ...(direction === 'nw' && { - marginRight: `-${TOOLTIP_ARROW_EDGE_OFFSET}px`, // space.3? - }), - ...((direction === 's' || direction === 'se' || direction === 'sw') && { - top: '100%', - right: '50%', - marginTop: '6px', - }), - ...(direction === 'se' && { - right: 'auto', - left: '50%', - marginLeft: `-${TOOLTIP_ARROW_EDGE_OFFSET}px`, // space.3? - }), - ...(direction === 'sw' && { - marginRight: `-${TOOLTIP_ARROW_EDGE_OFFSET}px`, // space.3? - }), - ...(direction === 'e' && { - left: '100%', - bottom: '50%', - marginLeft: '6px', - transform: 'translateY(50%)', - }), - ...(direction === 'w' && { - right: '100%', - bottom: '50%', - marginRight: '6px', - transform: 'translateY(50%)', - }), - // only for s and n direction to move the popover bovy to the center of the trigger - ...((direction === 'n' || direction === 's') && { - transform: 'translateX(50%)', - }), - // Left align tooltips with align prop - ...(align === 'left' && { - right: '100%', - marginLeft: '0', - }), - // Right align tooltips with align prop - ...(align === 'right' && { - right: '0', - marginRight: '0', - }), - // Multiline tooltips with wrap prop - ...(wrap && { - display: 'table-cell', - width: 'max-content', - maxWidth: '250px', - wordWrap: 'break-word', - whiteSpace: 'pre-line', - borderCollapse: 'separate', - }), - // Some styles of the directions need to be overriden when wrap is true - ...(wrap && - (direction === 's' || direction === 'n') && { - right: 'auto', - left: '50%', - transform: 'translateX(-50%)', - }), - ...(wrap && - (direction === 'w' || direction === 'e') && { - right: '100%', - }), - }), - }, + &[data-wrap='true'][data-direction='w'], + &[data-wrap='true'][data-direction='e']{ + & > span { + right: 100%; + + } + } - '&::before, & > span': { - ...(open && { - display: 'inline-block', - textDecoration: 'none', - animationName: 'tooltip-appear', - animationDuration: '0.1s', - animationFillMode: 'forwards', - animationTimingFunction: 'ease-in', - animationDelay: noDelay ? '0s' : '0.4s', - }), - }, -}) + ${sx}; +` const Tooltip2: React.FC> = ({ direction = 'n', @@ -366,8 +240,11 @@ const Tooltip2: React.FC> = ({ text, // used for label type 'aria-label': label, - children, + align, + wrap, + noDelay, type = 'label', + children, ...rest }) => { const id = useId() @@ -430,6 +307,9 @@ const Tooltip2: React.FC> = ({ ref={tooltipRef} data-direction={direction} data-state={open ? 'open' : undefined} + data-align={align} + data-wrap={wrap} + data-delay={noDelay} onMouseLeave={() => setOpen(false)} onKeyDown={onKeyDown} {...rest} diff --git a/src/stories/Tooltip.stories.tsx b/src/stories/Tooltip.stories.tsx index f1a2e8e0dff..8a0cbf6e03b 100644 --- a/src/stories/Tooltip.stories.tsx +++ b/src/stories/Tooltip.stories.tsx @@ -80,7 +80,7 @@ export const MultipleChildren = () => ( export const CurrentTooltipVariations = () => ( - + @@ -168,8 +168,8 @@ export const Tooltip2WithDirection = () => ( ) -export const Tooltip2Single = () => ( - +export const Tooltip2NoDelay = () => ( + ) From 20960014b2d16032dd5bc36fb7a6f551e5fa6d3a Mon Sep 17 00:00:00 2001 From: Armagan Ersoz Date: Fri, 24 Mar 2023 12:45:08 +1000 Subject: [PATCH 11/30] remove unused var --- src/Tooltip2.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tooltip2.tsx b/src/Tooltip2.tsx index 7a251e66d06..df00009c754 100644 --- a/src/Tooltip2.tsx +++ b/src/Tooltip2.tsx @@ -23,8 +23,6 @@ export type TriggerPropsType = { 'aria-label'?: string } -const TOOLTIP_ARROW_EDGE_OFFSET = '16' - const TooltipBase = styled.div` position: relative; display: inline-block; From a1f908ffa7e7dfe83737ef2f8b76756a4c974a75 Mon Sep 17 00:00:00 2001 From: Armagan Ersoz Date: Mon, 27 Mar 2023 16:42:32 +1000 Subject: [PATCH 12/30] restructure markup and make tooltip hoverable --- src/Tooltip2.tsx | 343 ++++++++++++++++++++++++----------------------- 1 file changed, 178 insertions(+), 165 deletions(-) diff --git a/src/Tooltip2.tsx b/src/Tooltip2.tsx index df00009c754..3743f4cec17 100644 --- a/src/Tooltip2.tsx +++ b/src/Tooltip2.tsx @@ -6,6 +6,7 @@ import {isFocusable} from '@primer/behaviors/utils' import {invariant} from './utils/invariant' import styled from 'styled-components' import {get} from './constants' +import VisuallyHidden from './_VisuallyHidden' export type Tooltip2Props = { direction?: 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w' | 'nw' @@ -23,43 +24,44 @@ export type TriggerPropsType = { 'aria-label'?: string } -const TooltipBase = styled.div` - position: relative; - display: inline-block; +const Tooltip = styled.div` + // tooltip element itself + position: absolute; + z-index: 1000000; + 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: normal; + background: ${get('colors.neutral.emphasisPlus')}; + border-radius: ${get('radii.1')}; + width: max-content; + opacity: 0; + // the caret &::before { position: absolute; z-index: 1000001; - - width: 0px; - height: 0px; color: ${get('colors.neutral.emphasisPlus')}; - pointer-events: none; content: ''; border: 6px solid transparent; opacity: 0; } - & > span { + // This is needed to keep the tooltip open when the user leaves the trigger element to hover tooltip + &::after { position: absolute; - z-index: 1000000; - - 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; + display: block; + right: 0; + left: 0; + height: 8px; + content: ''; } // delay animation for tooltip @@ -67,167 +69,171 @@ const TooltipBase = styled.div` from { opacity: 0; } - to { opacity: 1; } } - &[data-state='open'] { - &::before, - & > span { - 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; - } + &[data-state='open'], + &[data-state='open']::before { + animation-name: tooltip-appear; + animation-duration: 0.1s; + animation-fill-mode: forwards; + animation-timing-function: ease-in; + animation-delay: 0.4s; + } - &[data-delay='true'] { - &::before, - & > span { - animation-delay: 0s; - } + &[data-direction='n']:before, + &[data-direction='s']:before { + right: 50%; + margin-right: -6px; + } + + &[data-direction='s']::before, + &[data-direction='se']::before, + &[data-direction='sw']::before { + bottom: 100%; + border-bottom-color: ${get('colors.neutral.emphasisPlus')}; + } + + &[data-direction='s']::after, + &[data-direction='se']::after, + &[data-direction='sw']::after { + bottom: 100%; + } + + &[data-direction='n']::before, + &[data-direction='ne']::before, + &[data-direction='nw']::before { + top: 100%; + border-top-color: ${get('colors.neutral.emphasisPlus')}; + } + + &[data-direction='n']::after, + &[data-direction='ne']::after, + &[data-direction='nw']::after { + top: 100%; + } + + &[data-direction='se']::before, + &[data-direction='ne']::before { + left: 0; + margin-left: 6px; + } + + &[data-direction='sw']::before, + &[data-direction='nw']::before { + right: 0; + margin-right: 6px; + } + + &[data-direction='w']::before { + top: 50%; + bottom: 50%; + left: 100%; + margin-top: -6px; + border-left-color: ${get('colors.neutral.emphasisPlus')}; + } + + &[data-direction='e']::before { + top: 50%; + bottom: 50%; + right: 100%; + margin-top: -6px; + border-right-color: ${get('colors.neutral.emphasisPlus')}; + } + + &[data-state='open'] { + &[data-delay='true'], + &[data-delay='true']::before { + animation-delay: 0s; } &[data-direction='s'], &[data-direction='se'], &[data-direction='sw'] { - & > span { - top: 100%; - right: 50%; - margin-top: 6px; - } - &::before { - top: auto; - right: 50%; - bottom: -7px; - margin-right: -6px; - border-bottom-color: ${get('colors.neutral.emphasisPlus')}; - } - } - &[data-direction='se'] > span { - right: auto; - left: 50%; - margin-left: -${get('space.3')}; - } - - &[data-direction='sw'] > span { - margin-right: -${get('space.3')}; + top: 100%; + right: 50%; + margin-top: 6px; } &[data-direction='n'], &[data-direction='ne'], &[data-direction='nw'] { - & > span { - right: 50%; - bottom: 100%; - margin-bottom: 6px; - } - &::before { - top: -7px; - right: 50%; - bottom: auto; - margin-right: -6px; - border-top-color: ${get('colors.neutral.emphasisPlus')}; - } + bottom: 100%; + margin-bottom: 6px; + right: 50%; + } + + &[data-direction='n'], + &[data-direction='s'] { + transform: translateX(50%); } - &[data-direction='ne'] > span { + &[data-direction='se'] { right: auto; left: 50%; margin-left: -${get('space.3')}; } - - &[data-direction='nw'] > span { - margin-right: -${get('space.3')}; + &[data-direction='ne'] { + right: auto; + left: 50%; + margin-left: -${get('space.3')}; } - &[data-direction='n'], - &[data-direction='s'] { - & > span { - transform: translateX(50%); - } + &[data-direction='sw'] { + margin-right: -${get('space.3')}; } &[data-direction='e'] { - & > span { - 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')}; - } + bottom: 50%; + left: 100%; + margin-left: 6px; + transform: translateY(50%); } &[data-direction='w'] { - & > span { - 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')}; - } + bottom: 50%; + right: 100%; + margin-right: 6px; + transform: translateY(50%); } + &[data-align='left'] { - & > span { - right: 100%; - margin-left: 0; - } - &::before { - left: 10px; - } + right: 100%; + margin-left: 0; + } + &[data-align='left']::before { + right: 40px; } &[data-align='right'] { - & > span { - right: 0; - margin-right: 0; - } - &::before { - right: 15px; - } + right: 0; + margin-right: 0; } + &[data-align='right']::before { + right: 72px; + } + &[data-wrap='true'] { - & > span { - display: table-cell; - width: max-content; - max-width: 250px; - word-wrap: break-word; - white-space: pre-line; - border-collapse: separate; - } + display: table-cell; + width: max-content; + max-width: 250px; + word-wrap: break-word; + white-space: pre-line; + border-collapse: separate; } &[data-wrap='true'][data-direction='n'], - &[data-wrap='true'][data-direction='s']{ - & > span { - transform: translateX(-50%); - right: auto; - left: 50%; - } + &[data-wrap='true'][data-direction='s'] { + transform: translateX(-50%); + right: auto; + left: 50%; } &[data-wrap='true'][data-direction='w'], - &[data-wrap='true'][data-direction='e']{ - & > span { - right: 100%; - - } + &[data-wrap='true'][data-direction='e'] { + right: 100%; } + } ${sx}; ` @@ -267,7 +273,9 @@ const Tooltip2: React.FC> = ({ const triggerEvtHandlers = { onFocus: () => setOpen(true), - onBlur: () => setOpen(false), + onBlur: () => { + setOpen(false) + }, onMouseEnter: () => { setOpen(true) }, @@ -301,16 +309,13 @@ const Tooltip2: React.FC> = ({ } return ( - setOpen(false)} + sx={{position: 'relative', display: 'inline-block'}} onKeyDown={onKeyDown} - {...rest} + onMouseLeave={() => { + setOpen(false) + }} > {React.cloneElement(child as React.ReactElement, { ...{ @@ -323,17 +328,25 @@ const Tooltip2: React.FC> = ({ }, ...composeEventHandlers(child as React.ReactElement), })} - - {text || label} - - + {/* Render the tooltip component visually hidden when it is not open*/} + + + {text || label} + + + ) } From 25872691592e613ced874341f88d3b44baa703b9 Mon Sep 17 00:00:00 2001 From: Armagan Ersoz Date: Tue, 28 Mar 2023 12:12:41 +1000 Subject: [PATCH 13/30] wrap up, clean up, interactive children --- src/Tooltip2.tsx | 159 +++++++++++++++++++++----------- src/stories/Tooltip.stories.tsx | 4 +- 2 files changed, 106 insertions(+), 57 deletions(-) diff --git a/src/Tooltip2.tsx b/src/Tooltip2.tsx index 3743f4cec17..467fa64a7dc 100644 --- a/src/Tooltip2.tsx +++ b/src/Tooltip2.tsx @@ -6,7 +6,6 @@ import {isFocusable} from '@primer/behaviors/utils' import {invariant} from './utils/invariant' import styled from 'styled-components' import {get} from './constants' -import VisuallyHidden from './_VisuallyHidden' export type Tooltip2Props = { direction?: 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w' | 'nw' @@ -43,6 +42,20 @@ const Tooltip = styled.div` border-radius: ${get('radii.1')}; width: max-content; opacity: 0; + max-width: 250px; + + /* tooltip element should be rendered visually hidden when it is not opened. */ + &:not([data-state='open']) { + /* Visually hidden styles */ + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; + } // the caret &::before { @@ -74,19 +87,13 @@ const Tooltip = styled.div` } } - &[data-state='open'], - &[data-state='open']::before { - animation-name: tooltip-appear; - animation-duration: 0.1s; - animation-fill-mode: forwards; - animation-timing-function: ease-in; - animation-delay: 0.4s; - } + /* South, East, Southeast, Southwest before */ - &[data-direction='n']:before, - &[data-direction='s']:before { - right: 50%; - margin-right: -6px; + &[data-direction='n']::before, + &[data-direction='ne']::before, + &[data-direction='nw']::before { + top: 100%; + border-top-color: ${get('colors.neutral.emphasisPlus')}; } &[data-direction='s']::before, @@ -96,36 +103,39 @@ const Tooltip = styled.div` border-bottom-color: ${get('colors.neutral.emphasisPlus')}; } - &[data-direction='s']::after, - &[data-direction='se']::after, - &[data-direction='sw']::after { - bottom: 100%; + &[data-direction='n']:before, + &[data-direction='s']:before { + right: 50%; + margin-right: -6px; } - &[data-direction='n']::before, &[data-direction='ne']::before, + &[data-direction='se']::before { + left: 0; + margin-left: 6px; + } + + &[data-direction='sw']::before, &[data-direction='nw']::before { - top: 100%; - border-top-color: ${get('colors.neutral.emphasisPlus')}; + right: 0; + margin-right: 6px; } + /* South, East, Southeast, Southwest after */ + &[data-direction='n']::after, &[data-direction='ne']::after, &[data-direction='nw']::after { top: 100%; } - &[data-direction='se']::before, - &[data-direction='ne']::before { - left: 0; - margin-left: 6px; + &[data-direction='s']::after, + &[data-direction='se']::after, + &[data-direction='sw']::after { + bottom: 100%; } - &[data-direction='sw']::before, - &[data-direction='nw']::before { - right: 0; - margin-right: 6px; - } + /* West before and after */ &[data-direction='w']::before { top: 50%; @@ -135,6 +145,29 @@ const Tooltip = styled.div` border-left-color: ${get('colors.neutral.emphasisPlus')}; } + &[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='e']::before { top: 50%; bottom: 50%; @@ -143,6 +176,19 @@ const Tooltip = styled.div` border-right-color: ${get('colors.neutral.emphasisPlus')}; } + /* Animation styles */ + + &[data-state='open'], + &[data-state='open']::before { + animation-name: tooltip-appear; + animation-duration: 0.1s; + animation-fill-mode: forwards; + animation-timing-function: ease-in; + animation-delay: 0.4s; + } + + /* Position of the tooltip element when it is opened. */ + &[data-state='open'] { &[data-delay='true'], &[data-delay='true']::before { @@ -198,6 +244,8 @@ const Tooltip = styled.div` transform: translateY(50%); } + /* Align and wrap styles */ + &[data-align='left'] { right: 100%; margin-left: 0; @@ -252,7 +300,7 @@ const Tooltip2: React.FC> = ({ ...rest }) => { const id = useId() - const tooltipRef = useRef(null) + const containerRef = useRef(null) const child = Children.only(children) // make sure there is only one child const [open, setOpen] = useState(false) @@ -261,10 +309,15 @@ const Tooltip2: React.FC> = ({ // Practically, this is not a conditional hook, it is a compile time check // eslint-disable-next-line react-hooks/rules-of-hooks useEffect(() => { - if (tooltipRef.current) { - const childNode = tooltipRef.current.children[0] // For now, I assume it has one node but that is not true + if (containerRef.current) { + // First child is the trigger element + const triggerEl = containerRef.current.children[0] + const triggerChildren = triggerEl.childNodes + const isTriggerInteractive = isFocusable(triggerEl as HTMLElement) + // Has trigger element or any of its children interactive elements? + const hasInteractiveChild = Array.from(triggerChildren).some(child => isFocusable(child as HTMLElement)) invariant( - isFocusable(childNode as HTMLElement), + isTriggerInteractive || hasInteractiveChild, 'The `Tooltip2` component expects a single React element that contains interactive content. Consider using a ` + ( text="Random long text that needs to be wrapped and be multipline and have some paddings around" type="description" > - + ) From dff06a94972c6db18180b852893de2c545e62cc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arma=C4=9Fan?= Date: Wed, 29 Mar 2023 12:57:57 +1000 Subject: [PATCH 14/30] Apply suggestions from code review Co-authored-by: Josh Black --- src/Tooltip2.tsx | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/Tooltip2.tsx b/src/Tooltip2.tsx index 467fa64a7dc..d88708bb6e1 100644 --- a/src/Tooltip2.tsx +++ b/src/Tooltip2.tsx @@ -301,7 +301,7 @@ const Tooltip2: React.FC> = ({ }) => { const id = useId() const containerRef = useRef(null) - const child = Children.only(children) // make sure there is only one child + const child = Children.only(children) const [open, setOpen] = useState(false) // we need this check for every render @@ -369,14 +369,12 @@ const Tooltip2: React.FC> = ({ onMouseLeave={() => setOpen(false)} > {React.cloneElement(child as React.ReactElement, { - ...{ - // if it is a type description, we use tooltip to describe the trigger - 'aria-describedby': type === 'description' ? id : undefined, - // If it is a type description, we should keep the aria label if it exists, otherwise we remove it because we will use aria-labelledby - 'aria-label': type === 'description' ? (children as React.ReactElement).props['aria-label'] : undefined, - // If it is a label type, we use tooltip to label the trigger - 'aria-labelledby': type === 'label' ? id : undefined, - }, + // if it is a type description, we use tooltip to describe the trigger + 'aria-describedby': type === 'description' ? id : undefined, + // If it is a type description, we should keep the aria label if it exists, otherwise we remove it because we will use aria-labelledby + 'aria-label': type === 'description' ? (children as React.ReactElement).props['aria-label'] : undefined, + // If it is a label type, we use tooltip to label the trigger + 'aria-labelledby': type === 'label' ? id : undefined, ...composeEventHandlers(child as React.ReactElement), })} @@ -393,7 +391,7 @@ const Tooltip2: React.FC> = ({ aria-hidden={type === 'label' ? true : undefined} id={id} > - {text || label} + {text ?? label} ) From 2e9e18cd815fc9d1f53bb342179a6976408553db Mon Sep 17 00:00:00 2001 From: Armagan Ersoz Date: Wed, 29 Mar 2023 19:08:40 +1000 Subject: [PATCH 15/30] code review feedback --- src/Tooltip2.tsx | 63 ++++++++++++++++++------------------------------ 1 file changed, 24 insertions(+), 39 deletions(-) diff --git a/src/Tooltip2.tsx b/src/Tooltip2.tsx index d88708bb6e1..4c7674262c7 100644 --- a/src/Tooltip2.tsx +++ b/src/Tooltip2.tsx @@ -21,6 +21,9 @@ export type TriggerPropsType = { 'aria-describedby'?: string 'aria-labelledby'?: string 'aria-label'?: string + onBlur?: React.FocusEventHandler + onFocus?: React.FocusEventHandler + onMouseEnter?: React.MouseEventHandler } const Tooltip = styled.div` @@ -324,36 +327,6 @@ const Tooltip2: React.FC> = ({ }) } - const triggerEvtHandlers = { - onFocus: () => setOpen(true), - onBlur: () => { - setOpen(false) - }, - onMouseEnter: () => { - setOpen(true) - }, - } - - // Make sure to compose the default event handlers for tooltip trigger with the ones that are passed in - function composeEventHandlers(child: React.ReactElement) { - const {onBlur: _onBlur, onFocus: _onFocus, onMouseEnter: _onMouseEnter} = child.props - - return { - onBlur: () => { - _onBlur && _onBlur() - triggerEvtHandlers.onBlur() - }, - onFocus: () => { - _onFocus && _onFocus() - triggerEvtHandlers.onFocus() - }, - onMouseEnter: () => { - _onMouseEnter && _onMouseEnter() - triggerEvtHandlers.onMouseEnter() - }, - } - } - function onKeyDown(e: React.KeyboardEvent) { if (open && e.key === 'Escape') { e.stopPropagation() @@ -368,15 +341,27 @@ const Tooltip2: React.FC> = ({ onKeyDown={onKeyDown} onMouseLeave={() => setOpen(false)} > - {React.cloneElement(child as React.ReactElement, { - // if it is a type description, we use tooltip to describe the trigger - 'aria-describedby': type === 'description' ? id : undefined, - // If it is a type description, we should keep the aria label if it exists, otherwise we remove it because we will use aria-labelledby - 'aria-label': type === 'description' ? (children as React.ReactElement).props['aria-label'] : undefined, - // If it is a label type, we use tooltip to label the trigger - 'aria-labelledby': type === 'label' ? id : undefined, - ...composeEventHandlers(child as React.ReactElement), - })} + {React.isValidElement(child) && + React.cloneElement(child as React.ReactElement, { + // if it is a type description, we use tooltip to describe the trigger + 'aria-describedby': type === 'description' ? id : undefined, + // If it is a type description, we should keep the aria label if it exists, otherwise we remove it because we will use aria-labelledby + 'aria-label': type === 'description' ? (children as React.ReactElement).props['aria-label'] : undefined, + // If it is a label type, we use tooltip to label the trigger + 'aria-labelledby': type === 'label' ? id : undefined, + onBlur: (event: React.FocusEvent) => { + setOpen(false) + child.props.onBlur?.(event) + }, + onFocus: (event: React.FocusEvent) => { + setOpen(true) + child.props.onFocus?.(event) + }, + onMouseEnter: (event: React.MouseEvent) => { + setOpen(true) + child.props.onMouseEnter?.(event) + }, + })} Date: Mon, 3 Apr 2023 12:17:34 +1000 Subject: [PATCH 16/30] add outline for force-color media --- src/Tooltip2.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Tooltip2.tsx b/src/Tooltip2.tsx index 4c7674262c7..90ff47c3735 100644 --- a/src/Tooltip2.tsx +++ b/src/Tooltip2.tsx @@ -46,6 +46,9 @@ const Tooltip = styled.div` width: max-content; opacity: 0; max-width: 250px; + @media (forced-colors: active) { + outline: 1px solid transparent; + } /* tooltip element should be rendered visually hidden when it is not opened. */ &:not([data-state='open']) { From f3116bba7e94fb4affa26b76f819e13a8e332c57 Mon Sep 17 00:00:00 2001 From: Armagan Ersoz Date: Mon, 3 Apr 2023 15:17:49 +1000 Subject: [PATCH 17/30] Add unit tests --- src/Tooltip2.tsx | 6 +-- src/__tests__/Tooltip.test.tsx | 93 +++++++++++++++++++++++++++++++++- 2 files changed, 95 insertions(+), 4 deletions(-) diff --git a/src/Tooltip2.tsx b/src/Tooltip2.tsx index 90ff47c3735..2560af33f7b 100644 --- a/src/Tooltip2.tsx +++ b/src/Tooltip2.tsx @@ -196,8 +196,8 @@ const Tooltip = styled.div` /* Position of the tooltip element when it is opened. */ &[data-state='open'] { - &[data-delay='true'], - &[data-delay='true']::before { + &[data-no-delay='true'], + &[data-no-delay='true']::before { animation-delay: 0s; } &[data-direction='s'], @@ -371,7 +371,7 @@ const Tooltip2: React.FC> = ({ data-state={open ? 'open' : undefined} data-align={align} data-wrap={wrap} - data-delay={noDelay} + data-no-delay={noDelay} {...rest} // Only need tooltip role if the tooltip is a description for supplementary information role={type === 'description' ? 'tooltip' : undefined} diff --git a/src/__tests__/Tooltip.test.tsx b/src/__tests__/Tooltip.test.tsx index 2f96bfb1728..e60144a87be 100644 --- a/src/__tests__/Tooltip.test.tsx +++ b/src/__tests__/Tooltip.test.tsx @@ -1,8 +1,12 @@ import React from 'react' import Tooltip, {TooltipProps} from '../Tooltip' +import Tooltip2, {Tooltip2Props} from '../Tooltip2' import {render, renderClasses, rendersClass, behavesAsComponent, checkExports} from '../utils/testing' -import {render as HTMLRender} from '@testing-library/react' +import {render as HTMLRender, act} from '@testing-library/react' import {axe, toHaveNoViolations} from 'jest-axe' +import {IconButton} from '../Button' +import {SearchIcon} from '@primer/octicons-react' +import {userEvent} from '@storybook/testing-library' expect.extend(toHaveNoViolations) @@ -49,3 +53,90 @@ describe('Tooltip', () => { expect(rendersClass(, 'tooltipped-multiline')).toBe(true) }) }) + +const TooltipComponent = (props: Tooltip2Props) => ( + + + +) + +describe('Tooltip2', () => { + it('renders `data-direction="n"` by default', () => { + const {getByText} = HTMLRender() + expect(getByText('label type tooltip')).toHaveAttribute('data-direction', 'n') + }) + it('renders `data-direction` attribute with the correct value when the `direction` prop is specified', () => { + const {getByText} = HTMLRender() + expect(getByText('label type tooltip')).toHaveAttribute('data-direction', 's') + }) + + it('renders `data-no-delay` attribute with the correct value when the `noDelay` prop is specified', () => { + const {getByText} = HTMLRender() + expect(getByText('label type tooltip')).toHaveAttribute('data-no-delay', 'true') + }) + + it('renders `data-wrap` attribute with the correct value when the `wrap` prop is specified', () => { + const {getByText} = HTMLRender() + expect(getByText('label type tooltip')).toHaveAttribute('data-wrap', 'true') + }) + it('renders `data-align` attribute with the correct value when the `align` prop is specified', () => { + const {getByText} = HTMLRender() + expect(getByText('label type tooltip')).toHaveAttribute('data-align', 'right') + }) + it('should label the trigger element by its tooltip when the tooltip type is label', () => { + const {getByRole, getByText} = HTMLRender() + const triggerEL = getByRole('button') + const tooltipEl = getByText('label type tooltip') + expect(triggerEL).toHaveAttribute('aria-labelledby', tooltipEl.id) + }) + it('should render aria-hidden on the tooltip element when the tooltip is label type', () => { + const {getByText} = HTMLRender() + expect(getByText('label type tooltip')).toHaveAttribute('aria-hidden', 'true') + }) + it('should describe the trigger element by its tooltip when the tooltip type is describe', () => { + const {getByRole, getByText} = HTMLRender( + , + ) + const triggerEL = getByRole('button') + const tooltipEl = getByText('This is description for the trigger element') + expect(triggerEL).toHaveAttribute('aria-describedby', tooltipEl.id) + }) + it('should render the tooltip element with role="tooltip" when the tooltip type is describe', () => { + const {getByText} = HTMLRender( + , + ) + expect(getByText('This is description for the trigger element')).toHaveAttribute('role', 'tooltip') + }) + it('should display the tooltip when the trigger element is hovered', () => { + const {getByRole, getByText} = HTMLRender() + const triggerEL = getByRole('button') + userEvent.hover(triggerEL) + expect(getByText('label type tooltip')).toHaveAttribute('data-state', 'open') + }) + it('should display the tooltip when the trigger element is focused', () => { + const {getByRole, getByText} = HTMLRender() + const triggerEL = getByRole('button') + act(() => { + triggerEL.focus() + }) + expect(getByText('label type tooltip')).toHaveAttribute('data-state', 'open') + }) + it('should hide the tooltip when the trigger element is blurred', () => { + const {getByRole, getByText} = HTMLRender() + const triggerEL = getByRole('button') + act(() => { + triggerEL.focus() + }) + userEvent.tab() + expect(getByText('label type tooltip')).not.toHaveAttribute('data-state', 'open') + }) + it('should hide the tooltip when the ESC key is pressed', () => { + const {getByRole, getByText} = HTMLRender() + const triggerEL = getByRole('button') + act(() => { + triggerEL.focus() + }) + userEvent.type(triggerEL, '{esc}') + expect(getByText('label type tooltip')).not.toHaveAttribute('data-state', 'open') + }) +}) From 8e83bb62129597eabb96dd2760dd2b6fb9a65d3a Mon Sep 17 00:00:00 2001 From: Armagan Ersoz Date: Wed, 5 Apr 2023 10:35:55 +1000 Subject: [PATCH 18/30] check the trigger element's content for label --- src/Tooltip2.tsx | 43 ++++++++++++++++++--------------- src/stories/Tooltip.stories.tsx | 18 +++----------- 2 files changed, 28 insertions(+), 33 deletions(-) diff --git a/src/Tooltip2.tsx b/src/Tooltip2.tsx index 2560af33f7b..3920e1a9960 100644 --- a/src/Tooltip2.tsx +++ b/src/Tooltip2.tsx @@ -24,6 +24,7 @@ export type TriggerPropsType = { onBlur?: React.FocusEventHandler onFocus?: React.FocusEventHandler onMouseEnter?: React.MouseEventHandler + ref?: React.RefObject } const Tooltip = styled.div` @@ -306,7 +307,7 @@ const Tooltip2: React.FC> = ({ ...rest }) => { const id = useId() - const containerRef = useRef(null) + const triggerRef = useRef(null) const child = Children.only(children) const [open, setOpen] = useState(false) @@ -315,17 +316,28 @@ const Tooltip2: React.FC> = ({ // Practically, this is not a conditional hook, it is a compile time check // eslint-disable-next-line react-hooks/rules-of-hooks useEffect(() => { - if (containerRef.current) { - // First child is the trigger element - const triggerEl = containerRef.current.children[0] - const triggerChildren = triggerEl.childNodes - const isTriggerInteractive = isFocusable(triggerEl as HTMLElement) + if (triggerRef.current) { // Has trigger element or any of its children interactive elements? - const hasInteractiveChild = Array.from(triggerChildren).some(child => isFocusable(child as HTMLElement)) + const isTriggerInteractive = isFocusable(triggerRef.current) + const triggerChildren = triggerRef.current.childNodes + const hasInteractiveChild = Array.from(triggerChildren).some(child => { + return child instanceof HTMLElement && isFocusable(child) + }) invariant( isTriggerInteractive || hasInteractiveChild, - 'The `Tooltip2` component expects a single React element that contains interactive content. Consider using a ` ) // As a label for an IconButton -export const Tooltip2CustomIcon = () => ( +export const Tooltip2NativeHTMLButton = () => ( - + @@ -67,16 +67,6 @@ export const Tooltip2IconButtonWithDescription = () => ( ) -// As a supplementary description for a button -export const MultipleChildren = () => ( - - - - - - -) - export const CurrentTooltipVariations = () => ( From d5077cbed710ad27c03ce561786ffcc06cfe80c7 Mon Sep 17 00:00:00 2001 From: Armagan Ersoz Date: Wed, 5 Apr 2023 10:48:28 +1000 Subject: [PATCH 19/30] useOnEscapePress hook to close the tooltip when mouse is hovering over the trigger element --- src/Tooltip2.tsx | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/Tooltip2.tsx b/src/Tooltip2.tsx index 3920e1a9960..4d252df158c 100644 --- a/src/Tooltip2.tsx +++ b/src/Tooltip2.tsx @@ -6,6 +6,7 @@ import {isFocusable} from '@primer/behaviors/utils' import {invariant} from './utils/invariant' import styled from 'styled-components' import {get} from './constants' +import {useOnEscapePress} from './hooks/useOnEscapePress' export type Tooltip2Props = { direction?: 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w' | 'nw' @@ -342,15 +343,19 @@ const Tooltip2: React.FC> = ({ }) } - function onKeyDown(e: React.KeyboardEvent) { - if (open && e.key === 'Escape') { - e.stopPropagation() - setOpen(false) - } - } + // Opting in using useOnEscapePress hook instead of onKeydown event to be able to close the tooltip when the mouse is hovering on the trigger element + useOnEscapePress( + (e: KeyboardEvent) => { + if (open) { + e.stopPropagation() + setOpen(false) + } + }, + [open], + ) return ( - setOpen(false)}> + setOpen(false)}> {React.isValidElement(child) && React.cloneElement(child as React.ReactElement, { ref: triggerRef, From d2400d412fd03f36b58ef1538bbffd8551d6b42d Mon Sep 17 00:00:00 2001 From: Armagan Ersoz Date: Wed, 5 Apr 2023 11:29:35 +1000 Subject: [PATCH 20/30] fix tests --- src/__tests__/Tooltip.test.tsx | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/__tests__/Tooltip.test.tsx b/src/__tests__/Tooltip.test.tsx index e60144a87be..d11ebe966f9 100644 --- a/src/__tests__/Tooltip.test.tsx +++ b/src/__tests__/Tooltip.test.tsx @@ -4,9 +4,9 @@ import Tooltip2, {Tooltip2Props} from '../Tooltip2' import {render, renderClasses, rendersClass, behavesAsComponent, checkExports} from '../utils/testing' import {render as HTMLRender, act} from '@testing-library/react' import {axe, toHaveNoViolations} from 'jest-axe' -import {IconButton} from '../Button' +import {Button} from '../Button' import {SearchIcon} from '@primer/octicons-react' -import {userEvent} from '@storybook/testing-library' +import userEvent from '@testing-library/user-event' expect.extend(toHaveNoViolations) @@ -56,7 +56,9 @@ describe('Tooltip', () => { const TooltipComponent = (props: Tooltip2Props) => ( - + ) @@ -107,10 +109,11 @@ describe('Tooltip2', () => { ) expect(getByText('This is description for the trigger element')).toHaveAttribute('role', 'tooltip') }) - it('should display the tooltip when the trigger element is hovered', () => { + it('should display the tooltip when the trigger element is hovered', async () => { const {getByRole, getByText} = HTMLRender() const triggerEL = getByRole('button') - userEvent.hover(triggerEL) + const user = userEvent.setup() + await user.hover(triggerEL) expect(getByText('label type tooltip')).toHaveAttribute('data-state', 'open') }) it('should display the tooltip when the trigger element is focused', () => { @@ -121,22 +124,24 @@ describe('Tooltip2', () => { }) expect(getByText('label type tooltip')).toHaveAttribute('data-state', 'open') }) - it('should hide the tooltip when the trigger element is blurred', () => { + it('should hide the tooltip when the trigger element is blurred', async () => { const {getByRole, getByText} = HTMLRender() const triggerEL = getByRole('button') + const user = userEvent.setup() act(() => { triggerEL.focus() }) - userEvent.tab() + await user.keyboard('{TAB}') expect(getByText('label type tooltip')).not.toHaveAttribute('data-state', 'open') }) - it('should hide the tooltip when the ESC key is pressed', () => { + it('should hide the tooltip when the ESC key is pressed', async () => { const {getByRole, getByText} = HTMLRender() const triggerEL = getByRole('button') + const user = userEvent.setup() act(() => { triggerEL.focus() }) - userEvent.type(triggerEL, '{esc}') + await user.keyboard('{Escape}') expect(getByText('label type tooltip')).not.toHaveAttribute('data-state', 'open') }) }) From dd7da3beabf6845d8308fc60ff58fc58fa614e54 Mon Sep 17 00:00:00 2001 From: Armagan Ersoz Date: Wed, 5 Apr 2023 12:23:06 +1000 Subject: [PATCH 21/30] docs and move tooltip into folder --- docs/content/Tooltip.mdx | 83 ++- src/Tooltip.tsx | 266 --------- src/{ => Tooltip}/Tooltip.docs.json | 14 +- src/Tooltip/Tooltip.features.stories.tsx | 134 +++++ src/Tooltip/Tooltip.stories.tsx | 31 + src/{__tests__ => Tooltip}/Tooltip.test.tsx | 69 +-- src/{Tooltip2.tsx => Tooltip/Tooltip.tsx} | 24 +- .../__snapshots__/Tooltip.test.tsx.snap | 542 ++++++++++++++++++ src/Tooltip/index.ts | 1 + .../__snapshots__/Tooltip.test.tsx.snap | 232 -------- src/stories/Tooltip.stories.tsx | 197 ------- 11 files changed, 827 insertions(+), 766 deletions(-) delete mode 100644 src/Tooltip.tsx rename src/{ => Tooltip}/Tooltip.docs.json (56%) create mode 100644 src/Tooltip/Tooltip.features.stories.tsx create mode 100644 src/Tooltip/Tooltip.stories.tsx rename src/{__tests__ => Tooltip}/Tooltip.test.tsx (71%) rename src/{Tooltip2.tsx => Tooltip/Tooltip.tsx} (95%) create mode 100644 src/Tooltip/__snapshots__/Tooltip.test.tsx.snap create mode 100644 src/Tooltip/index.ts delete mode 100644 src/__tests__/__snapshots__/Tooltip.test.tsx.snap delete mode 100644 src/stories/Tooltip.stories.tsx diff --git a/docs/content/Tooltip.mdx b/docs/content/Tooltip.mdx index c50776cae4c..90dab885ac8 100644 --- a/docs/content/Tooltip.mdx +++ b/docs/content/Tooltip.mdx @@ -4,7 +4,7 @@ title: Tooltip status: Alpha --- -import data from '../../src/Tooltip.docs.json' +import data from '../../src/Tooltip/Tooltip.docs.json' The Tooltip component adds a tooltip to add context to interactive elements on the page. @@ -20,10 +20,85 @@ A tooltip may only be used on an element that is interactive such as a button or ## Examples +### Default (As a label type) + +```jsx live + + + +``` + +### As a description type + +```jsx live + + + +``` + +### With direction + ```jsx live - - - + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +### With wrap + +```jsx live + + + +``` + +### With no delay + +```jsx live + + + +``` + +### With align + +```jsx live + + + + + + ``` diff --git a/src/Tooltip.tsx b/src/Tooltip.tsx deleted file mode 100644 index 28fb1c8645f..00000000000 --- a/src/Tooltip.tsx +++ /dev/null @@ -1,266 +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, - &:focus-within { - &::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, - &.tooltipped-no-delay:focus-within { - &::before, - &::after { - animation-delay: 0s; - } - } - - &.tooltipped-multiline:hover, - &.tooltipped-multiline:active, - &.tooltipped-multiline:focus, - &.tooltipped-multiline:focus-within { - &::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.docs.json b/src/Tooltip/Tooltip.docs.json similarity index 56% rename from src/Tooltip.docs.json rename to src/Tooltip/Tooltip.docs.json index d4b88a8c6ec..e31ae49f8c8 100644 --- a/src/Tooltip.docs.json +++ b/src/Tooltip/Tooltip.docs.json @@ -9,6 +9,11 @@ "name": "align", "type": "'left' | 'right'" }, + { + "name": "aria-label", + "type": "string", + "description": "Should be utilised for label type tooltips and it is going to be used to label the tooltip trigger." + }, { "name": "direction", "type": "'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w' | 'nw'", @@ -20,9 +25,14 @@ "description": "When set to `true`, tooltip appears without any delay." }, { - "name": "aria-label", + "name": "text", "type": "string", - "description": "Text used in `aria-label` (for accessibility)" + "description": "Should be utilised for description type tooltips and it is going to be used to describe the tooltip trigger." + }, + { + "name": "type", + "type": "'label' | 'description'", + "description": "The type of tooltip. `label` is used for labelling the element that triggers tooltip. `description` is used for describing or adding a suplementary information to the element that triggers the tooltip." }, { "name": "wrap", diff --git a/src/Tooltip/Tooltip.features.stories.tsx b/src/Tooltip/Tooltip.features.stories.tsx new file mode 100644 index 00000000000..2a5a6ebec44 --- /dev/null +++ b/src/Tooltip/Tooltip.features.stories.tsx @@ -0,0 +1,134 @@ +import React from 'react' +import {Meta} from '@storybook/react' +import {BaseStyles, ThemeProvider, IconButton, Button} from '..' +import {Tooltip} from '.' +import {SearchIcon} from '@primer/octicons-react' +import Box from '../Box' + +export default { + title: 'Components/Tooltip/Features', + component: Tooltip, + + decorators: [ + Story => { + return ( + + + + + + ) + }, + ], +} as Meta + +// As a label for an IconButton +export const TooltipLabelTypeTooltip = () => ( + + + + + +) + +// As a label for an IconButton +export const TooltipNativeHTMLButton = () => ( + + + + + +) + +// As a supplementary description for a button +export const TooltipDescriptionTypeTooltip = () => ( + + + + + +) + +// As a supplementary description for an IconButton +export const TooltipIconButtonWithDescription = () => ( + + + + + +) + +export const TooltipWithDirection = () => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +) + +export const TooltipNoDelay = () => ( + + + +) + +export const TooltipWithAlign = () => ( + + + + + + + + +) + +export const TooltipWithWrap = () => ( + + + + + + + + +) diff --git a/src/Tooltip/Tooltip.stories.tsx b/src/Tooltip/Tooltip.stories.tsx new file mode 100644 index 00000000000..e51629f8e05 --- /dev/null +++ b/src/Tooltip/Tooltip.stories.tsx @@ -0,0 +1,31 @@ +import React from 'react' +import {Meta} from '@storybook/react' +import {BaseStyles, ThemeProvider, Button} from '..' +import {Tooltip} from '../Tooltip' +import Box from '../Box' + +export default { + title: 'Components/Tooltip', + component: Tooltip, + + decorators: [ + Story => { + return ( + + + + + + ) + }, + ], +} as Meta + +// As a label for an IconButton +export const Default = () => ( + + + + + +) diff --git a/src/__tests__/Tooltip.test.tsx b/src/Tooltip/Tooltip.test.tsx similarity index 71% rename from src/__tests__/Tooltip.test.tsx rename to src/Tooltip/Tooltip.test.tsx index d11ebe966f9..f68116f941b 100644 --- a/src/__tests__/Tooltip.test.tsx +++ b/src/Tooltip/Tooltip.test.tsx @@ -1,68 +1,33 @@ import React from 'react' -import Tooltip, {TooltipProps} from '../Tooltip' -import Tooltip2, {Tooltip2Props} from '../Tooltip2' -import {render, renderClasses, rendersClass, behavesAsComponent, checkExports} from '../utils/testing' +import {Tooltip, TooltipProps} from '.' +import {checkStoriesForAxeViolations, behavesAsComponent, checkExports} from '../utils/testing' import {render as HTMLRender, act} from '@testing-library/react' -import {axe, toHaveNoViolations} from 'jest-axe' import {Button} from '../Button' import {SearchIcon} from '@primer/octicons-react' import userEvent from '@testing-library/user-event' -expect.extend(toHaveNoViolations) +const TooltipComponent = (props: TooltipProps) => ( + + + +) describe('Tooltip', () => { - behavesAsComponent({Component: Tooltip}) - - checkExports('Tooltip', { - default: Tooltip, - }) - - it('should have no axe violations', async () => { - const {container} = HTMLRender() - const results = await axe(container) - expect(results).toHaveNoViolations() - }) - - 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) + behavesAsComponent({ + Component: Tooltip, + options: {skipAs: true, skipSx: true}, + toRender: () => , }) - 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('respects the "wrap" prop', () => { - expect(rendersClass(, 'tooltipped-multiline')).toBe(true) + checkExports('Tooltip', { + default: undefined, + Tooltip, }) -}) -const TooltipComponent = (props: Tooltip2Props) => ( - - - -) + checkStoriesForAxeViolations('Tooltip.features', '../Tooltip/') -describe('Tooltip2', () => { it('renders `data-direction="n"` by default', () => { const {getByText} = HTMLRender() expect(getByText('label type tooltip')).toHaveAttribute('data-direction', 'n') diff --git a/src/Tooltip2.tsx b/src/Tooltip/Tooltip.tsx similarity index 95% rename from src/Tooltip2.tsx rename to src/Tooltip/Tooltip.tsx index 4d252df158c..9be7dbf95f7 100644 --- a/src/Tooltip2.tsx +++ b/src/Tooltip/Tooltip.tsx @@ -1,14 +1,14 @@ import React, {Children, useEffect, useRef, useState} from 'react' -import Box from './Box' -import sx, {SxProp} from './sx' -import {useId} from './hooks/useId' +import Box from '../Box' +import sx, {SxProp} from '../sx' +import {useId} from '../hooks/useId' import {isFocusable} from '@primer/behaviors/utils' -import {invariant} from './utils/invariant' +import {invariant} from '../utils/invariant' import styled from 'styled-components' -import {get} from './constants' -import {useOnEscapePress} from './hooks/useOnEscapePress' +import {get} from '../constants' +import {useOnEscapePress} from '../hooks/useOnEscapePress' -export type Tooltip2Props = { +export type TooltipProps = { direction?: 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w' | 'nw' text?: string noDelay?: boolean @@ -28,7 +28,7 @@ export type TriggerPropsType = { ref?: React.RefObject } -const Tooltip = styled.div` +const TooltipEL = styled.div` // tooltip element itself position: absolute; z-index: 1000000; @@ -294,7 +294,7 @@ const Tooltip = styled.div` ${sx}; ` -const Tooltip2: React.FC> = ({ +export const Tooltip: React.FC> = ({ direction = 'n', // used for description type text, @@ -376,7 +376,7 @@ const Tooltip2: React.FC> = ({ child.props.onMouseEnter?.(event) }, })} - > = ({ id={id} > {text ?? label} - + ) } - -export default Tooltip2 diff --git a/src/Tooltip/__snapshots__/Tooltip.test.tsx.snap b/src/Tooltip/__snapshots__/Tooltip.test.tsx.snap new file mode 100644 index 00000000000..b901aa91802 --- /dev/null +++ b/src/Tooltip/__snapshots__/Tooltip.test.tsx.snap @@ -0,0 +1,542 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Tooltip renders consistently 1`] = ` +.c0 { + position: relative; + display: inline-block; +} + +.c2 { + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; +} + +.c1 { + border-radius: 6px; + border: 1px solid; + border-color: rgba(27,31,36,0.15); + font-family: inherit; + font-weight: 500; + font-size: 14px; + cursor: pointer; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-text-decoration: none; + text-decoration: none; + text-align: center; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + -ms-flex-pack: justify; + justify-content: space-between; + height: 32px; + padding: 0 12px; + gap: 8px; + min-width: -webkit-max-content; + min-width: -moz-max-content; + min-width: max-content; + -webkit-transition: 80ms cubic-bezier(0.65,0,0.35,1); + transition: 80ms cubic-bezier(0.65,0,0.35,1); + -webkit-transition-property: color,fill,background-color,border-color; + transition-property: color,fill,background-color,border-color; + color: #24292f; + background-color: #f6f8fa; + box-shadow: 0 1px 0 rgba(27,31,36,0.04),inset 0 1px 0 rgba(255,255,255,0.25); +} + +.c1:focus:not(:disabled) { + box-shadow: none; + outline: 2px solid #0969da; + outline-offset: -2px; +} + +.c1:focus:not(:disabled):not(:focus-visible) { + outline: solid 1px transparent; +} + +.c1:focus-visible:not(:disabled) { + box-shadow: none; + outline: 2px solid #0969da; + outline-offset: -2px; +} + +.c1[href] { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; +} + +.c1[href]:hover { + -webkit-text-decoration: none; + text-decoration: none; +} + +.c1:hover { + -webkit-transition-duration: 80ms; + transition-duration: 80ms; +} + +.c1:active { + -webkit-transition: none; + transition: none; +} + +.c1:disabled { + cursor: not-allowed; + box-shadow: none; + color: #8c959f; +} + +.c1:disabled [data-component=ButtonCounter] { + color: inherit; +} + +.c1 [data-component=ButtonCounter] { + font-size: 14px; +} + +.c1[data-component=IconButton] { + display: inline-grid; + padding: unset; + place-content: center; + width: 32px; + min-width: unset; +} + +.c1[data-size="small"] { + padding: 0 8px; + height: 28px; + gap: 4px; + font-size: 12px; +} + +.c1[data-size="small"] [data-component="text"] { + line-height: calc(20 / 12); +} + +.c1[data-size="small"] [data-component=ButtonCounter] { + font-size: 12px; +} + +.c1[data-size="small"] [data-component="buttonContent"] > :not(:last-child) { + margin-right: 4px; +} + +.c1[data-size="small"][data-component=IconButton] { + width: 28px; + padding: unset; +} + +.c1[data-size="large"] { + padding: 0 16px; + height: 40px; + gap: 8px; +} + +.c1[data-size="large"] [data-component="buttonContent"] > :not(:last-child) { + margin-right: 8px; +} + +.c1[data-size="large"][data-component=IconButton] { + width: 40px; + padding: unset; +} + +.c1[data-block="block"] { + width: 100%; +} + +.c1 [data-component="leadingVisual"] { + grid-area: leadingVisual; +} + +.c1 [data-component="text"] { + grid-area: text; + line-height: calc(20/14); + white-space: nowrap; +} + +.c1 [data-component="trailingVisual"] { + grid-area: trailingVisual; +} + +.c1 [data-component="trailingAction"] { + margin-right: -4px; +} + +.c1 [data-component="buttonContent"] { + -webkit-flex: 1 0 auto; + -ms-flex: 1 0 auto; + flex: 1 0 auto; + display: grid; + grid-template-areas: "leadingVisual text trailingVisual"; + grid-template-columns: min-content minmax(0,auto) min-content; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-align-content: center; + -ms-flex-line-pack: center; + align-content: center; +} + +.c1 [data-component="buttonContent"] > :not(:last-child) { + margin-right: 8px; +} + +.c1:hover:not([disabled]) { + background-color: #f3f4f6; + border-color: rgba(27,31,36,0.15); +} + +.c1:active:not([disabled]) { + background-color: hsla(220,14%,93%,1); + border-color: rgba(27,31,36,0.15); +} + +.c1[aria-expanded=true] { + background-color: hsla(220,14%,93%,1); + border-color: rgba(27,31,36,0.15); +} + +.c3 { + position: absolute; + z-index: 1000000; + padding: 0.5em 0.75em; + font: normal normal 11px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",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: normal; + background: #24292f; + border-radius: 3px; + width: -webkit-max-content; + width: -moz-max-content; + width: max-content; + opacity: 0; + max-width: 250px; +} + +.c3:not([data-state='open']) { + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + -webkit-clip: rect(0,0,0,0); + clip: rect(0,0,0,0); + white-space: nowrap; + border-width: 0; +} + +.c3::before { + position: absolute; + z-index: 1000001; + color: #24292f; + content: ''; + border: 6px solid transparent; + opacity: 0; +} + +.c3::after { + position: absolute; + display: block; + right: 0; + left: 0; + height: 8px; + content: ''; +} + +.c3[data-direction='n']::before, +.c3[data-direction='ne']::before, +.c3[data-direction='nw']::before { + top: 100%; + border-top-color: #24292f; +} + +.c3[data-direction='s']::before, +.c3[data-direction='se']::before, +.c3[data-direction='sw']::before { + bottom: 100%; + border-bottom-color: #24292f; +} + +.c3[data-direction='n']:before, +.c3[data-direction='s']:before { + right: 50%; + margin-right: -6px; +} + +.c3[data-direction='ne']::before, +.c3[data-direction='se']::before { + left: 0; + margin-left: 6px; +} + +.c3[data-direction='sw']::before, +.c3[data-direction='nw']::before { + right: 0; + margin-right: 6px; +} + +.c3[data-direction='n']::after, +.c3[data-direction='ne']::after, +.c3[data-direction='nw']::after { + top: 100%; +} + +.c3[data-direction='s']::after, +.c3[data-direction='se']::after, +.c3[data-direction='sw']::after { + bottom: 100%; +} + +.c3[data-direction='w']::before { + top: 50%; + bottom: 50%; + left: 100%; + margin-top: -6px; + border-left-color: #24292f; +} + +.c3[data-direction='w']::after { + position: absolute; + display: block; + height: 100%; + width: 8px; + content: ''; + bottom: 0; + left: 100%; +} + +.c3[data-direction='e']::after { + position: absolute; + display: block; + height: 100%; + width: 8px; + content: ''; + bottom: 0; + right: 100%; + margin-left: -8px; +} + +.c3[data-direction='e']::before { + top: 50%; + bottom: 50%; + right: 100%; + margin-top: -6px; + border-right-color: #24292f; +} + +.c3[data-state='open'], +.c3[data-state='open']::before { + -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[data-state='open'][data-no-delay='true'], +.c3[data-state='open'][data-no-delay='true']::before { + -webkit-animation-delay: 0s; + animation-delay: 0s; +} + +.c3[data-state='open'][data-direction='s'], +.c3[data-state='open'][data-direction='se'], +.c3[data-state='open'][data-direction='sw'] { + top: 100%; + right: 50%; + margin-top: 6px; +} + +.c3[data-state='open'][data-direction='n'], +.c3[data-state='open'][data-direction='ne'], +.c3[data-state='open'][data-direction='nw'] { + bottom: 100%; + margin-bottom: 6px; + right: 50%; +} + +.c3[data-state='open'][data-direction='n'], +.c3[data-state='open'][data-direction='s'] { + -webkit-transform: translateX(50%); + -ms-transform: translateX(50%); + transform: translateX(50%); +} + +.c3[data-state='open'][data-direction='se'] { + right: auto; + left: 50%; + margin-left: -16px; +} + +.c3[data-state='open'][data-direction='ne'] { + right: auto; + left: 50%; + margin-left: -16px; +} + +.c3[data-state='open'][data-direction='sw'] { + margin-right: -16px; +} + +.c3[data-state='open'][data-direction='e'] { + bottom: 50%; + left: 100%; + margin-left: 6px; + -webkit-transform: translateY(50%); + -ms-transform: translateY(50%); + transform: translateY(50%); +} + +.c3[data-state='open'][data-direction='w'] { + bottom: 50%; + right: 100%; + margin-right: 6px; + -webkit-transform: translateY(50%); + -ms-transform: translateY(50%); + transform: translateY(50%); +} + +.c3[data-state='open'][data-align='left'] { + right: 100%; + margin-left: 0; +} + +.c3[data-state='open'][data-align='left']::before { + right: 40px; +} + +.c3[data-state='open'][data-align='right'] { + right: 0; + margin-right: 0; +} + +.c3[data-state='open'][data-align='right']::before { + right: 72px; +} + +.c3[data-state='open'][data-wrap='true'] { + display: table-cell; + 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[data-state='open'][data-wrap='true'][data-direction='n'], +.c3[data-state='open'][data-wrap='true'][data-direction='s'] { + -webkit-transform: translateX(-50%); + -ms-transform: translateX(-50%); + transform: translateX(-50%); + right: auto; + left: 50%; +} + +.c3[data-state='open'][data-wrap='true'][data-direction='w'], +.c3[data-state='open'][data-wrap='true'][data-direction='e'] { + right: 100%; +} + +@media (forced-colors:active) { + .c1:focus { + outline: solid 1px transparent; + } +} + +@media (forced-colors:active) { + .c3 { + outline: 1px solid transparent; + } +} + +
+ +
+ label type tooltip +
+
+`; diff --git a/src/Tooltip/index.ts b/src/Tooltip/index.ts new file mode 100644 index 00000000000..ba15f407377 --- /dev/null +++ b/src/Tooltip/index.ts @@ -0,0 +1 @@ +export * from './Tooltip' diff --git a/src/__tests__/__snapshots__/Tooltip.test.tsx.snap b/src/__tests__/__snapshots__/Tooltip.test.tsx.snap deleted file mode 100644 index d461c34404c..00000000000 --- a/src/__tests__/__snapshots__/Tooltip.test.tsx.snap +++ /dev/null @@ -1,232 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Tooltip renders consistently 1`] = ` -.c0 { - position: relative; -} - -.c0::before { - position: absolute; - z-index: 1000001; - display: none; - width: 0px; - height: 0px; - color: #24292f; - pointer-events: none; - content: ''; - border: 6px solid transparent; - 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","Noto Sans",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; -} - -.c0:hover::before, -.c0:active::before, -.c0:focus::before, -.c0:focus-within::before, -.c0:hover::after, -.c0:active::after, -.c0:focus::after, -.c0:focus-within::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:focus-within::before, -.c0.tooltipped-no-delay:hover::after, -.c0.tooltipped-no-delay:active::after, -.c0.tooltipped-no-delay:focus::after, -.c0.tooltipped-no-delay:focus-within::after { - -webkit-animation-delay: 0s; - animation-delay: 0s; -} - -.c0.tooltipped-multiline:hover::after, -.c0.tooltipped-multiline:active::after, -.c0.tooltipped-multiline:focus::after, -.c0.tooltipped-multiline:focus-within::after { - display: table-cell; -} - -.c0.tooltipped-s::after, -.c0.tooltipped-se::after, -.c0.tooltipped-sw::after { - 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; - border-bottom-color: #24292f; -} - -.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; - border-left-color: #24292f; -} - -.c0.tooltipped-e::after { - bottom: 50%; - 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; - border-right-color: #24292f; -} - -.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; -} - -.c0.tooltipped-align-left-2::after { - left: 0; - margin-left: 0; -} - -.c0.tooltipped-align-left-2::before { - left: 10px; -} - - -`; diff --git a/src/stories/Tooltip.stories.tsx b/src/stories/Tooltip.stories.tsx deleted file mode 100644 index 44e1422ccf0..00000000000 --- a/src/stories/Tooltip.stories.tsx +++ /dev/null @@ -1,197 +0,0 @@ -import React from 'react' -import {Meta} from '@storybook/react' -import {BaseStyles, ThemeProvider, IconButton, Button} from '..' -import Tooltip from '../Tooltip' -import Tooltip2 from '../Tooltip2' -import {SearchIcon} from '@primer/octicons-react' -import Box from '../Box' - -export default { - title: 'Components/Tooltip/Default', - component: Tooltip, - - decorators: [ - Story => { - return ( - - - - - - ) - }, - ], -} as Meta - -export const CurrentTooltip = () => ( - - - - - -) - -// As a label for an IconButton -export const Tooltip2LabelTypeTooltip = () => ( - - - - - -) - -// As a label for an IconButton -export const Tooltip2NativeHTMLButton = () => ( - - - - - -) - -// As a supplementary description for a button -export const Tooltip2DescriptionTypeTooltip = () => ( - - - - - -) - -// As a supplementary description for an IconButton -export const Tooltip2IconButtonWithDescription = () => ( - - - - - -) - -export const CurrentTooltipVariations = () => ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {/* Align left seems to be broken */} - - - - - - - - -) - -export const Tooltip2WithDirection = () => ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -) - -export const Tooltip2NoDelay = () => ( - - - -) - -export const Tooltip2WithAlign = () => ( - - - - - - - - -) - -export const Tooltip2WithWrap = () => ( - - - - - - - - -) From 87df7b53f694bcd3a38fbffee49f7fdb80fc0eb5 Mon Sep 17 00:00:00 2001 From: broccolinisoup Date: Wed, 5 Apr 2023 02:24:46 +0000 Subject: [PATCH 22/30] Update generated/components.json --- generated/components.json | 91 +++++++++++++++++++++++---------------- 1 file changed, 53 insertions(+), 38 deletions(-) diff --git a/generated/components.json b/generated/components.json index 6d3a67ca306..1d97cb88014 100644 --- a/generated/components.json +++ b/generated/components.json @@ -469,44 +469,6 @@ ], "subcomponents": [] }, - "tooltip": { - "id": "tooltip", - "name": "Tooltip", - "status": "alpha", - "a11yReviewed": false, - "stories": [], - "props": [ - { - "name": "align", - "type": "'left' | 'right'" - }, - { - "name": "direction", - "type": "'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w' | 'nw'", - "description": "Sets where the tooltip renders in relation to the target." - }, - { - "name": "noDelay", - "type": "boolean", - "description": "When set to `true`, tooltip appears without any delay." - }, - { - "name": "aria-label", - "type": "string", - "description": "Text used in `aria-label` (for accessibility)" - }, - { - "name": "wrap", - "type": "boolean", - "description": "Use `true` to allow text within tooltip to wrap." - }, - { - "name": "sx", - "type": "SystemStyleObject" - } - ], - "subcomponents": [] - }, "truncate": { "id": "truncate", "name": "Truncate", @@ -4647,6 +4609,59 @@ } ] }, + "tooltip": { + "id": "tooltip", + "name": "Tooltip", + "status": "alpha", + "a11yReviewed": false, + "stories": [ + { + "id": "components-tooltip--default", + "code": "() => (\n \n \n \n \n
\n)" + } + ], + "props": [ + { + "name": "align", + "type": "'left' | 'right'" + }, + { + "name": "aria-label", + "type": "string", + "description": "Should be utilised for label type tooltips and it is going to be used to label the tooltip trigger." + }, + { + "name": "direction", + "type": "'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w' | 'nw'", + "description": "Sets where the tooltip renders in relation to the target." + }, + { + "name": "noDelay", + "type": "boolean", + "description": "When set to `true`, tooltip appears without any delay." + }, + { + "name": "text", + "type": "string", + "description": "Should be utilised for description type tooltips and it is going to be used to describe the tooltip trigger." + }, + { + "name": "type", + "type": "'label' | 'description'", + "description": "The type of tooltip. `label` is used for labelling the element that triggers tooltip. `description` is used for describing or adding a suplementary information to the element that triggers the tooltip." + }, + { + "name": "wrap", + "type": "boolean", + "description": "Use `true` to allow text within tooltip to wrap." + }, + { + "name": "sx", + "type": "SystemStyleObject" + } + ], + "subcomponents": [] + }, "tree_view": { "id": "tree_view", "name": "TreeView", From 1a3a456802655a25fb4bb889e359ad125338dbcc Mon Sep 17 00:00:00 2001 From: Armagan Ersoz Date: Wed, 5 Apr 2023 12:25:58 +1000 Subject: [PATCH 23/30] add changeset --- .changeset/flat-drinks-retire.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/flat-drinks-retire.md diff --git a/.changeset/flat-drinks-retire.md b/.changeset/flat-drinks-retire.md new file mode 100644 index 00000000000..74e8856b1c9 --- /dev/null +++ b/.changeset/flat-drinks-retire.md @@ -0,0 +1,5 @@ +--- +'@primer/react': minor +--- + +Tooltip: Address accessibility remediations and refactor styles towards more static styling From 16fc7b1b6dff4f497c0173e50c247b2449c06054 Mon Sep 17 00:00:00 2001 From: Armagan Ersoz Date: Wed, 5 Apr 2023 14:29:46 +1000 Subject: [PATCH 24/30] fix imports --- src/_TextInputInnerAction.tsx | 2 +- src/__tests__/Tooltip.types.test.tsx | 2 +- src/index.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/_TextInputInnerAction.tsx b/src/_TextInputInnerAction.tsx index 492ceb8a96a..dbbe086d3ac 100644 --- a/src/_TextInputInnerAction.tsx +++ b/src/_TextInputInnerAction.tsx @@ -2,7 +2,7 @@ import React, {forwardRef} from 'react' import {IconProps} from '@primer/octicons-react' import Box from './Box' import {Button, IconButton, ButtonProps} from './Button' -import Tooltip from './Tooltip' +import {Tooltip} from './Tooltip' import {BetterSystemStyleObject, merge, SxProp} from './sx' type TextInputActionProps = Omit< diff --git a/src/__tests__/Tooltip.types.test.tsx b/src/__tests__/Tooltip.types.test.tsx index c9280121588..7714238ff20 100644 --- a/src/__tests__/Tooltip.types.test.tsx +++ b/src/__tests__/Tooltip.types.test.tsx @@ -1,5 +1,5 @@ import React from 'react' -import Tooltip from '../Tooltip' +import {Tooltip} from '../Tooltip' export function shouldAcceptCallWithNoProps() { return diff --git a/src/index.ts b/src/index.ts index f8db192ecec..392bb7237a5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -168,7 +168,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 c7dd301538147e0933980206d73fb7383cab7dc6 Mon Sep 17 00:00:00 2001 From: Armagan Ersoz Date: Wed, 5 Apr 2023 14:41:58 +1000 Subject: [PATCH 25/30] update snapshot --- src/Tooltip/__snapshots__/Tooltip.test.tsx.snap | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Tooltip/__snapshots__/Tooltip.test.tsx.snap b/src/Tooltip/__snapshots__/Tooltip.test.tsx.snap index b901aa91802..f8679eb0a92 100644 --- a/src/Tooltip/__snapshots__/Tooltip.test.tsx.snap +++ b/src/Tooltip/__snapshots__/Tooltip.test.tsx.snap @@ -489,7 +489,7 @@ exports[`Tooltip renders consistently 1`] = ` onMouseLeave={[Function]} > - +
+ iconLabel +
+ `; @@ -2046,7 +2102,7 @@ exports[`TextInput renders trailingAction text button 1`] = ` .c3 [data-component="leadingVisual"] { grid-area: leadingVisual; - color: #656d76; + color: #57606a; } .c3 [data-component="text"] { @@ -2061,7 +2117,7 @@ exports[`TextInput renders trailingAction text button 1`] = ` .c3 [data-component="trailingAction"] { margin-right: -4px; - color: #656d76; + color: #57606a; } .c3 [data-component="buttonContent"] { @@ -2097,7 +2153,7 @@ exports[`TextInput renders trailingAction text button 1`] = ` } .c3[data-component="IconButton"][data-no-visuals] { - color: #656d76; + color: #57606a; } .c3[data-no-visuals] { @@ -2124,7 +2180,7 @@ exports[`TextInput renders trailingAction text button 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -2184,7 +2240,7 @@ exports[`TextInput renders trailingAction text button 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -2290,6 +2346,11 @@ exports[`TextInput renders trailingAction text button with a tooltip 1`] = ` justify-content: center; } +.c3 { + position: relative; + display: inline-block; +} + .c4 { border-radius: 6px; border: 1px solid; @@ -2440,7 +2501,7 @@ exports[`TextInput renders trailingAction text button with a tooltip 1`] = ` .c4 [data-component="leadingVisual"] { grid-area: leadingVisual; - color: #656d76; + color: #57606a; } .c4 [data-component="text"] { @@ -2455,7 +2516,7 @@ exports[`TextInput renders trailingAction text button with a tooltip 1`] = ` .c4 [data-component="trailingAction"] { margin-right: -4px; - color: #656d76; + color: #57606a; } .c4 [data-component="buttonContent"] { @@ -2491,7 +2552,7 @@ exports[`TextInput renders trailingAction text button with a tooltip 1`] = ` } .c4[data-component="IconButton"][data-no-visuals] { - color: #656d76; + color: #57606a; } .c4[data-no-visuals] { @@ -2518,7 +2579,7 @@ exports[`TextInput renders trailingAction text button with a tooltip 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -2578,7 +2639,7 @@ exports[`TextInput renders trailingAction text button with a tooltip 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -2604,28 +2665,9 @@ 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 { +.c6 { position: absolute; z-index: 1000000; - display: none; padding: 0.5em 0.75em; font: normal normal 11px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"; -webkit-font-smoothing: subpixel-antialiased; @@ -2640,25 +2682,130 @@ exports[`TextInput renders trailingAction text button with a tooltip 1`] = ` -ms-letter-spacing: normal; letter-spacing: normal; word-wrap: break-word; - white-space: pre; - pointer-events: none; - content: attr(aria-label); + white-space: normal; background: #24292f; border-radius: 3px; + width: -webkit-max-content; + width: -moz-max-content; + width: max-content; opacity: 0; + max-width: 250px; + display: inline-block; } -.c3:hover::before, -.c3:active::before, -.c3:focus::before, -.c3:focus-within::before, -.c3:hover::after, -.c3:active::after, -.c3:focus::after, -.c3:focus-within::after { - display: inline-block; - -webkit-text-decoration: none; - text-decoration: none; +.c6:not([data-state='open']) { + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + -webkit-clip: rect(0,0,0,0); + clip: rect(0,0,0,0); + white-space: nowrap; + border-width: 0; +} + +.c6::before { + position: absolute; + z-index: 1000001; + color: #24292f; + content: ''; + border: 6px solid transparent; + opacity: 0; +} + +.c6::after { + position: absolute; + display: block; + right: 0; + left: 0; + height: 8px; + content: ''; +} + +.c6[data-direction='n']::before, +.c6[data-direction='ne']::before, +.c6[data-direction='nw']::before { + top: 100%; + border-top-color: #24292f; +} + +.c6[data-direction='s']::before, +.c6[data-direction='se']::before, +.c6[data-direction='sw']::before { + bottom: 100%; + border-bottom-color: #24292f; +} + +.c6[data-direction='n']:before, +.c6[data-direction='s']:before { + right: 50%; + margin-right: -6px; +} + +.c6[data-direction='ne']::before, +.c6[data-direction='se']::before { + left: 0; + margin-left: 6px; +} + +.c6[data-direction='sw']::before, +.c6[data-direction='nw']::before { + right: 0; + margin-right: 6px; +} + +.c6[data-direction='n']::after, +.c6[data-direction='ne']::after, +.c6[data-direction='nw']::after { + top: 100%; +} + +.c6[data-direction='s']::after, +.c6[data-direction='se']::after, +.c6[data-direction='sw']::after { + bottom: 100%; +} + +.c6[data-direction='w']::before { + top: 50%; + bottom: 50%; + left: 100%; + margin-top: -6px; + border-left-color: #24292f; +} + +.c6[data-direction='w']::after { + position: absolute; + display: block; + height: 100%; + width: 8px; + content: ''; + bottom: 0; + left: 100%; +} + +.c6[data-direction='e']::after { + position: absolute; + display: block; + height: 100%; + width: 8px; + content: ''; + bottom: 0; + right: 100%; + margin-left: -8px; +} + +.c6[data-direction='e']::before { + top: 50%; + bottom: 50%; + right: 100%; + margin-top: -6px; + border-right-color: #24292f; +} + +.c6[data-state='open'], +.c6[data-state='open']::before { -webkit-animation-name: tooltip-appear; animation-name: tooltip-appear; -webkit-animation-duration: 0.1s; @@ -2671,123 +2818,89 @@ exports[`TextInput renders trailingAction text button with a tooltip 1`] = ` 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:focus-within::before, -.c3.tooltipped-no-delay:hover::after, -.c3.tooltipped-no-delay:active::after, -.c3.tooltipped-no-delay:focus::after, -.c3.tooltipped-no-delay:focus-within::after { +.c6[data-state='open'][data-no-delay='true'], +.c6[data-state='open'][data-no-delay='true']::before { -webkit-animation-delay: 0s; animation-delay: 0s; } -.c3.tooltipped-multiline:hover::after, -.c3.tooltipped-multiline:active::after, -.c3.tooltipped-multiline:focus::after, -.c3.tooltipped-multiline:focus-within::after { - display: table-cell; -} - -.c3.tooltipped-s::after, -.c3.tooltipped-se::after, -.c3.tooltipped-sw::after { +.c6[data-state='open'][data-direction='s'], +.c6[data-state='open'][data-direction='se'], +.c6[data-state='open'][data-direction='sw'] { top: 100%; right: 50%; margin-top: 6px; } -.c3.tooltipped-s::before, -.c3.tooltipped-se::before, -.c3.tooltipped-sw::before { - top: auto; +.c6[data-state='open'][data-direction='n'], +.c6[data-state='open'][data-direction='ne'], +.c6[data-state='open'][data-direction='nw'] { + bottom: 100%; + margin-bottom: 6px; right: 50%; - bottom: -7px; - margin-right: -6px; - border-bottom-color: #24292f; } -.c3.tooltipped-se::after { +.c6[data-state='open'][data-direction='n'], +.c6[data-state='open'][data-direction='s'] { + -webkit-transform: translateX(50%); + -ms-transform: translateX(50%); + transform: translateX(50%); +} + +.c6[data-state='open'][data-direction='se'] { 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 { +.c6[data-state='open'][data-direction='ne'] { right: auto; left: 50%; margin-left: -16px; } -.c3.tooltipped-nw::after { +.c6[data-state='open'][data-direction='sw'] { margin-right: -16px; } -.c3.tooltipped-s::after, -.c3.tooltipped-n::after { - -webkit-transform: translateX(50%); - -ms-transform: translateX(50%); - transform: translateX(50%); +.c6[data-state='open'][data-direction='e'] { + bottom: 50%; + left: 100%; + margin-left: 6px; + -webkit-transform: translateY(50%); + -ms-transform: translateY(50%); + transform: translateY(50%); } -.c3.tooltipped-w::after { - right: 100%; +.c6[data-state='open'][data-direction='w'] { bottom: 50%; + right: 100%; 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; +.c6[data-state='open'][data-align='left'] { + right: 100%; + margin-left: 0; } -.c3.tooltipped-e::after { - bottom: 50%; - left: 100%; - margin-left: 6px; - -webkit-transform: translateY(50%); - -ms-transform: translateY(50%); - transform: translateY(50%); +.c6[data-state='open'][data-align='left']::before { + right: 40px; } -.c3.tooltipped-e::before { - top: 50%; - right: -7px; - bottom: 50%; - margin-top: -6px; - border-right-color: #24292f; +.c6[data-state='open'][data-align='right'] { + right: 0; + margin-right: 0; +} + +.c6[data-state='open'][data-align='right']::before { + right: 72px; } -.c3.tooltipped-multiline::after { +.c6[data-state='open'][data-wrap='true'] { + display: table-cell; width: -webkit-max-content; width: -moz-max-content; width: max-content; @@ -2797,38 +2910,20 @@ exports[`TextInput renders trailingAction text button with a tooltip 1`] = ` border-collapse: separate; } -.c3.tooltipped-multiline.tooltipped-s::after, -.c3.tooltipped-multiline.tooltipped-n::after { - right: auto; - left: 50%; +.c6[data-state='open'][data-wrap='true'][data-direction='n'], +.c6[data-state='open'][data-wrap='true'][data-direction='s'] { -webkit-transform: translateX(-50%); -ms-transform: translateX(-50%); transform: translateX(-50%); + right: auto; + left: 50%; } -.c3.tooltipped-multiline.tooltipped-w::after, -.c3.tooltipped-multiline.tooltipped-e::after { +.c6[data-state='open'][data-wrap='true'][data-direction='w'], +.c6[data-state='open'][data-wrap='true'][data-direction='e'] { 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; @@ -2855,6 +2950,12 @@ exports[`TextInput renders trailingAction text button with a tooltip 1`] = ` } } +@media (forced-colors:active) { + .c6 { + outline: 1px solid transparent; + } +} + - - +
+ Clear input +
+
`; @@ -2905,7 +3017,7 @@ exports[`TextInput renders trailingVisual 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -2971,7 +3083,7 @@ exports[`TextInput renders trailingVisual 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -3051,7 +3163,7 @@ exports[`TextInput renders warning 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -3071,7 +3183,7 @@ exports[`TextInput renders warning 1`] = ` background-position: right 8px center; padding-left: 0; padding-right: 0; - border-color: #9a6700; + border-color: #bf8700; } .c0 input, @@ -3118,7 +3230,7 @@ exports[`TextInput renders warning 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -3192,7 +3304,7 @@ exports[`TextInput renders with a loading indicator 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -3258,7 +3370,7 @@ exports[`TextInput renders with a loading indicator 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -3365,7 +3477,7 @@ exports[`TextInput renders with a loading indicator 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -3431,7 +3543,7 @@ exports[`TextInput renders with a loading indicator 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -3570,7 +3682,7 @@ exports[`TextInput renders with a loading indicator 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -3636,7 +3748,7 @@ exports[`TextInput renders with a loading indicator 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -3752,7 +3864,7 @@ exports[`TextInput renders with a loading indicator 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -3818,7 +3930,7 @@ exports[`TextInput renders with a loading indicator 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -4003,7 +4115,7 @@ exports[`TextInput renders with a loading indicator 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -4069,7 +4181,7 @@ exports[`TextInput renders with a loading indicator 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -4254,7 +4366,7 @@ exports[`TextInput renders with a loading indicator 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -4320,7 +4432,7 @@ exports[`TextInput renders with a loading indicator 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -4499,7 +4611,7 @@ exports[`TextInput renders with a loading indicator 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -4565,7 +4677,7 @@ exports[`TextInput renders with a loading indicator 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -4712,7 +4824,7 @@ exports[`TextInput renders with a loading indicator 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -4778,7 +4890,7 @@ exports[`TextInput renders with a loading indicator 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -4957,7 +5069,7 @@ exports[`TextInput renders with a loading indicator 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -5023,7 +5135,7 @@ exports[`TextInput renders with a loading indicator 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -5179,7 +5291,7 @@ exports[`TextInput renders with a loading indicator 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -5253,7 +5365,7 @@ exports[`TextInput renders with a loading indicator 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -5479,7 +5591,7 @@ exports[`TextInput renders with a loading indicator 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -5545,7 +5657,7 @@ exports[`TextInput renders with a loading indicator 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -5770,7 +5882,7 @@ exports[`TextInput renders with a loading indicator 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -5842,7 +5954,7 @@ exports[`TextInput renders with a loading indicator 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -6034,7 +6146,7 @@ exports[`TextInput should render a password input 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -6100,7 +6212,7 @@ exports[`TextInput should render a password input 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; diff --git a/src/__tests__/__snapshots__/TextInputWithTokens.test.tsx.snap b/src/__tests__/__snapshots__/TextInputWithTokens.test.tsx.snap index 74fb09e3715..dfd5e6076bd 100644 --- a/src/__tests__/__snapshots__/TextInputWithTokens.test.tsx.snap +++ b/src/__tests__/__snapshots__/TextInputWithTokens.test.tsx.snap @@ -55,7 +55,7 @@ exports[`TextInputWithTokens renders a leadingVisual and trailingVisual 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -128,7 +128,7 @@ exports[`TextInputWithTokens renders a leadingVisual and trailingVisual 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -180,10 +180,10 @@ exports[`TextInputWithTokens renders a leadingVisual and trailingVisual 1`] = ` padding-top: 0; padding-bottom: 0; background-color: rgba(234,238,242,0.5); - border-color: rgba(31,35,40,0.15); + border-color: rgba(27,31,36,0.15); border-style: solid; border-width: 1px; - color: #656d76; + color: #57606a; max-width: 100%; padding-right: 0; } @@ -191,7 +191,7 @@ exports[`TextInputWithTokens renders a leadingVisual and trailingVisual 1`] = ` .c4:hover { background-color: rgba(175,184,193,0.2); box-shadow: 0 3px 6px rgba(140,149,159,0.15); - color: #1F2328; + color: #24292f; } .c7 { @@ -826,13 +826,13 @@ exports[`TextInputWithTokens renders a truncated set of tokens 1`] = ` .c8 { font-size: 16px; - color: #656d76; + color: #57606a; } .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -905,7 +905,7 @@ exports[`TextInputWithTokens renders a truncated set of tokens 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -957,10 +957,10 @@ exports[`TextInputWithTokens renders a truncated set of tokens 1`] = ` padding-top: 0; padding-bottom: 0; background-color: rgba(234,238,242,0.5); - border-color: rgba(31,35,40,0.15); + border-color: rgba(27,31,36,0.15); border-style: solid; border-width: 1px; - color: #656d76; + color: #57606a; max-width: 100%; padding-right: 0; } @@ -968,7 +968,7 @@ exports[`TextInputWithTokens renders a truncated set of tokens 1`] = ` .c4:hover { background-color: rgba(175,184,193,0.2); box-shadow: 0 3px 6px rgba(140,149,159,0.15); - color: #1F2328; + color: #24292f; } .c7 { @@ -1241,7 +1241,7 @@ exports[`TextInputWithTokens renders as block layout 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -1332,7 +1332,7 @@ exports[`TextInputWithTokens renders as block layout 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -1445,7 +1445,7 @@ exports[`TextInputWithTokens renders at a maximum height when specified 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -1522,7 +1522,7 @@ exports[`TextInputWithTokens renders at a maximum height when specified 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -1574,10 +1574,10 @@ exports[`TextInputWithTokens renders at a maximum height when specified 1`] = ` padding-top: 0; padding-bottom: 0; background-color: rgba(234,238,242,0.5); - border-color: rgba(31,35,40,0.15); + border-color: rgba(27,31,36,0.15); border-style: solid; border-width: 1px; - color: #656d76; + color: #57606a; max-width: 100%; padding-right: 0; } @@ -1585,7 +1585,7 @@ exports[`TextInputWithTokens renders at a maximum height when specified 1`] = ` .c4:hover { background-color: rgba(175,184,193,0.2); box-shadow: 0 3px 6px rgba(140,149,159,0.15); - color: #1F2328; + color: #24292f; } .c7 { @@ -2169,7 +2169,7 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -2249,7 +2249,7 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -2299,10 +2299,10 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 1`] = ` padding-left: 4px; padding-right: 4px; background-color: rgba(234,238,242,0.5); - border-color: rgba(31,35,40,0.15); + border-color: rgba(27,31,36,0.15); border-style: solid; border-width: 1px; - color: #656d76; + color: #57606a; max-width: 100%; padding-right: 0; } @@ -2310,7 +2310,7 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 1`] = ` .c4:hover { background-color: rgba(175,184,193,0.2); box-shadow: 0 3px 6px rgba(140,149,159,0.15); - color: #1F2328; + color: #24292f; } .c7 { @@ -2894,7 +2894,7 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 2`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -2974,7 +2974,7 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 2`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -3024,10 +3024,10 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 2`] = ` padding-left: 8px; padding-right: 8px; background-color: rgba(234,238,242,0.5); - border-color: rgba(31,35,40,0.15); + border-color: rgba(27,31,36,0.15); border-style: solid; border-width: 1px; - color: #656d76; + color: #57606a; max-width: 100%; padding-right: 0; } @@ -3035,7 +3035,7 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 2`] = ` .c4:hover { background-color: rgba(175,184,193,0.2); box-shadow: 0 3px 6px rgba(140,149,159,0.15); - color: #1F2328; + color: #24292f; } .c7 { @@ -3619,7 +3619,7 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 3`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -3692,7 +3692,7 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 3`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -3742,10 +3742,10 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 3`] = ` padding-left: 8px; padding-right: 8px; background-color: rgba(234,238,242,0.5); - border-color: rgba(31,35,40,0.15); + border-color: rgba(27,31,36,0.15); border-style: solid; border-width: 1px; - color: #656d76; + color: #57606a; max-width: 100%; padding-right: 0; } @@ -3753,7 +3753,7 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 3`] = ` .c4:hover { background-color: rgba(175,184,193,0.2); box-shadow: 0 3px 6px rgba(140,149,159,0.15); - color: #1F2328; + color: #24292f; } .c7 { @@ -4337,7 +4337,7 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 4`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -4410,7 +4410,7 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 4`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -4462,10 +4462,10 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 4`] = ` padding-top: 0; padding-bottom: 0; background-color: rgba(234,238,242,0.5); - border-color: rgba(31,35,40,0.15); + border-color: rgba(27,31,36,0.15); border-style: solid; border-width: 1px; - color: #656d76; + color: #57606a; max-width: 100%; padding-right: 0; } @@ -4473,7 +4473,7 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 4`] = ` .c4:hover { background-color: rgba(175,184,193,0.2); box-shadow: 0 3px 6px rgba(140,149,159,0.15); - color: #1F2328; + color: #24292f; } .c7 { @@ -5057,7 +5057,7 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 5`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -5130,7 +5130,7 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 5`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -5182,10 +5182,10 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 5`] = ` padding-top: 0; padding-bottom: 0; background-color: rgba(234,238,242,0.5); - border-color: rgba(31,35,40,0.15); + border-color: rgba(27,31,36,0.15); border-style: solid; border-width: 1px; - color: #656d76; + color: #57606a; max-width: 100%; padding-right: 0; } @@ -5193,7 +5193,7 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 5`] = ` .c4:hover { background-color: rgba(175,184,193,0.2); box-shadow: 0 3px 6px rgba(140,149,159,0.15); - color: #1F2328; + color: #24292f; } .c7 { @@ -5777,7 +5777,7 @@ exports[`TextInputWithTokens renders tokens on a single line when specified 1`] .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -5852,7 +5852,7 @@ exports[`TextInputWithTokens renders tokens on a single line when specified 1`] -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -5904,10 +5904,10 @@ exports[`TextInputWithTokens renders tokens on a single line when specified 1`] padding-top: 0; padding-bottom: 0; background-color: rgba(234,238,242,0.5); - border-color: rgba(31,35,40,0.15); + border-color: rgba(27,31,36,0.15); border-style: solid; border-width: 1px; - color: #656d76; + color: #57606a; max-width: 100%; padding-right: 0; } @@ -5915,7 +5915,7 @@ exports[`TextInputWithTokens renders tokens on a single line when specified 1`] .c4:hover { background-color: rgba(175,184,193,0.2); box-shadow: 0 3px 6px rgba(140,149,159,0.15); - color: #1F2328; + color: #24292f; } .c7 { @@ -6499,7 +6499,7 @@ exports[`TextInputWithTokens renders tokens without a remove button when specifi .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -6572,7 +6572,7 @@ exports[`TextInputWithTokens renders tokens without a remove button when specifi -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -6624,17 +6624,17 @@ exports[`TextInputWithTokens renders tokens without a remove button when specifi padding-top: 0; padding-bottom: 0; background-color: rgba(234,238,242,0.5); - border-color: rgba(31,35,40,0.15); + border-color: rgba(27,31,36,0.15); border-style: solid; border-width: 1px; - color: #656d76; + color: #57606a; max-width: 100%; } .c4:hover { background-color: rgba(175,184,193,0.2); box-shadow: 0 3px 6px rgba(140,149,159,0.15); - color: #1F2328; + color: #24292f; } .c5 { @@ -6944,7 +6944,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -7017,7 +7017,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -7069,10 +7069,10 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` padding-top: 0; padding-bottom: 0; background-color: rgba(234,238,242,0.5); - border-color: rgba(31,35,40,0.15); + border-color: rgba(27,31,36,0.15); border-style: solid; border-width: 1px; - color: #656d76; + color: #57606a; max-width: 100%; padding-right: 0; } @@ -7080,7 +7080,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` .c4:hover { background-color: rgba(175,184,193,0.2); box-shadow: 0 3px 6px rgba(140,149,159,0.15); - color: #1F2328; + color: #24292f; } .c7 { @@ -7719,7 +7719,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -7792,7 +7792,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -7844,10 +7844,10 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` padding-top: 0; padding-bottom: 0; background-color: rgba(234,238,242,0.5); - border-color: rgba(31,35,40,0.15); + border-color: rgba(27,31,36,0.15); border-style: solid; border-width: 1px; - color: #656d76; + color: #57606a; max-width: 100%; padding-right: 0; } @@ -7855,7 +7855,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` .c6:hover { background-color: rgba(175,184,193,0.2); box-shadow: 0 3px 6px rgba(140,149,159,0.15); - color: #1F2328; + color: #24292f; } .c9 { @@ -8526,7 +8526,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -8599,7 +8599,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -8651,10 +8651,10 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` padding-top: 0; padding-bottom: 0; background-color: rgba(234,238,242,0.5); - border-color: rgba(31,35,40,0.15); + border-color: rgba(27,31,36,0.15); border-style: solid; border-width: 1px; - color: #656d76; + color: #57606a; max-width: 100%; padding-right: 0; } @@ -8662,7 +8662,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` .c4:hover { background-color: rgba(175,184,193,0.2); box-shadow: 0 3px 6px rgba(140,149,159,0.15); - color: #1F2328; + color: #24292f; } .c7 { @@ -9310,7 +9310,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -9383,7 +9383,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -9435,10 +9435,10 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` padding-top: 0; padding-bottom: 0; background-color: rgba(234,238,242,0.5); - border-color: rgba(31,35,40,0.15); + border-color: rgba(27,31,36,0.15); border-style: solid; border-width: 1px; - color: #656d76; + color: #57606a; max-width: 100%; padding-right: 0; } @@ -9446,7 +9446,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` .c7:hover { background-color: rgba(175,184,193,0.2); box-shadow: 0 3px 6px rgba(140,149,159,0.15); - color: #1F2328; + color: #24292f; } .c10 { @@ -10163,7 +10163,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -10236,7 +10236,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -10288,10 +10288,10 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` padding-top: 0; padding-bottom: 0; background-color: rgba(234,238,242,0.5); - border-color: rgba(31,35,40,0.15); + border-color: rgba(27,31,36,0.15); border-style: solid; border-width: 1px; - color: #656d76; + color: #57606a; max-width: 100%; padding-right: 0; } @@ -10299,7 +10299,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` .c7:hover { background-color: rgba(175,184,193,0.2); box-shadow: 0 3px 6px rgba(140,149,159,0.15); - color: #1F2328; + color: #24292f; } .c10 { @@ -11016,7 +11016,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -11089,7 +11089,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -11141,10 +11141,10 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` padding-top: 0; padding-bottom: 0; background-color: rgba(234,238,242,0.5); - border-color: rgba(31,35,40,0.15); + border-color: rgba(27,31,36,0.15); border-style: solid; border-width: 1px; - color: #656d76; + color: #57606a; max-width: 100%; padding-right: 0; } @@ -11152,7 +11152,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` .c7:hover { background-color: rgba(175,184,193,0.2); box-shadow: 0 3px 6px rgba(140,149,159,0.15); - color: #1F2328; + color: #24292f; } .c10 { @@ -11863,7 +11863,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -11936,7 +11936,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -11988,10 +11988,10 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` padding-top: 0; padding-bottom: 0; background-color: rgba(234,238,242,0.5); - border-color: rgba(31,35,40,0.15); + border-color: rgba(27,31,36,0.15); border-style: solid; border-width: 1px; - color: #656d76; + color: #57606a; max-width: 100%; padding-right: 0; } @@ -11999,7 +11999,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` .c4:hover { background-color: rgba(175,184,193,0.2); box-shadow: 0 3px 6px rgba(140,149,159,0.15); - color: #1F2328; + color: #24292f; } .c7 { @@ -12678,7 +12678,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -12751,7 +12751,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -12803,10 +12803,10 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` padding-top: 0; padding-bottom: 0; background-color: rgba(234,238,242,0.5); - border-color: rgba(31,35,40,0.15); + border-color: rgba(27,31,36,0.15); border-style: solid; border-width: 1px; - color: #656d76; + color: #57606a; max-width: 100%; padding-right: 0; } @@ -12814,7 +12814,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` .c6:hover { background-color: rgba(175,184,193,0.2); box-shadow: 0 3px 6px rgba(140,149,159,0.15); - color: #1F2328; + color: #24292f; } .c9 { @@ -13525,7 +13525,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -13598,7 +13598,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -13650,10 +13650,10 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` padding-top: 0; padding-bottom: 0; background-color: rgba(234,238,242,0.5); - border-color: rgba(31,35,40,0.15); + border-color: rgba(27,31,36,0.15); border-style: solid; border-width: 1px; - color: #656d76; + color: #57606a; max-width: 100%; padding-right: 0; } @@ -13661,7 +13661,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` .c4:hover { background-color: rgba(175,184,193,0.2); box-shadow: 0 3px 6px rgba(140,149,159,0.15); - color: #1F2328; + color: #24292f; } .c7 { @@ -14349,7 +14349,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -14429,7 +14429,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -14479,10 +14479,10 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` padding-left: 4px; padding-right: 4px; background-color: rgba(234,238,242,0.5); - border-color: rgba(31,35,40,0.15); + border-color: rgba(27,31,36,0.15); border-style: solid; border-width: 1px; - color: #656d76; + color: #57606a; max-width: 100%; padding-right: 0; } @@ -14490,7 +14490,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` .c7:hover { background-color: rgba(175,184,193,0.2); box-shadow: 0 3px 6px rgba(140,149,159,0.15); - color: #1F2328; + color: #24292f; } .c10 { @@ -15247,7 +15247,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -15320,7 +15320,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -15372,10 +15372,10 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` padding-top: 0; padding-bottom: 0; background-color: rgba(234,238,242,0.5); - border-color: rgba(31,35,40,0.15); + border-color: rgba(27,31,36,0.15); border-style: solid; border-width: 1px; - color: #656d76; + color: #57606a; max-width: 100%; padding-right: 0; } @@ -15383,7 +15383,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` .c7:hover { background-color: rgba(175,184,193,0.2); box-shadow: 0 3px 6px rgba(140,149,159,0.15); - color: #1F2328; + color: #24292f; } .c10 { @@ -16140,7 +16140,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -16213,7 +16213,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -16263,10 +16263,10 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` padding-left: 8px; padding-right: 8px; background-color: rgba(234,238,242,0.5); - border-color: rgba(31,35,40,0.15); + border-color: rgba(27,31,36,0.15); border-style: solid; border-width: 1px; - color: #656d76; + color: #57606a; max-width: 100%; padding-right: 0; } @@ -16274,7 +16274,7 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = ` .c7:hover { background-color: rgba(175,184,193,0.2); box-shadow: 0 3px 6px rgba(140,149,159,0.15); - color: #1F2328; + color: #24292f; } .c10 { @@ -16997,7 +16997,7 @@ exports[`TextInputWithTokens renders with tokens 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -17070,7 +17070,7 @@ exports[`TextInputWithTokens renders with tokens 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -17122,10 +17122,10 @@ exports[`TextInputWithTokens renders with tokens 1`] = ` padding-top: 0; padding-bottom: 0; background-color: rgba(234,238,242,0.5); - border-color: rgba(31,35,40,0.15); + border-color: rgba(27,31,36,0.15); border-style: solid; border-width: 1px; - color: #656d76; + color: #57606a; max-width: 100%; padding-right: 0; } @@ -17133,7 +17133,7 @@ exports[`TextInputWithTokens renders with tokens 1`] = ` .c4:hover { background-color: rgba(175,184,193,0.2); box-shadow: 0 3px 6px rgba(140,149,159,0.15); - color: #1F2328; + color: #24292f; } .c7 { @@ -17704,7 +17704,7 @@ exports[`TextInputWithTokens renders with tokens using a custom token component .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -17777,7 +17777,7 @@ exports[`TextInputWithTokens renders with tokens using a custom token component -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -18378,7 +18378,7 @@ exports[`TextInputWithTokens renders without tokens 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #1F2328; + color: #24292f; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -18451,7 +18451,7 @@ exports[`TextInputWithTokens renders without tokens 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #656d76; + color: #57606a; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; From 5861cac22fea84e6c2e18a83326ad584eae121c6 Mon Sep 17 00:00:00 2001 From: Armagan Ersoz Date: Tue, 11 Apr 2023 10:09:34 +1000 Subject: [PATCH 27/30] default value to the docs --- src/Tooltip/Tooltip.docs.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Tooltip/Tooltip.docs.json b/src/Tooltip/Tooltip.docs.json index e31ae49f8c8..d964fadd4ae 100644 --- a/src/Tooltip/Tooltip.docs.json +++ b/src/Tooltip/Tooltip.docs.json @@ -17,6 +17,7 @@ { "name": "direction", "type": "'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w' | 'nw'", + "defaultValue": "n", "description": "Sets where the tooltip renders in relation to the target." }, { @@ -32,6 +33,7 @@ { "name": "type", "type": "'label' | 'description'", + "defaultValue": "label", "description": "The type of tooltip. `label` is used for labelling the element that triggers tooltip. `description` is used for describing or adding a suplementary information to the element that triggers the tooltip." }, { From ca9c135d760ff89b4384e0fcf12e422ef5e1d664 Mon Sep 17 00:00:00 2001 From: broccolinisoup Date: Tue, 11 Apr 2023 00:45:04 +0000 Subject: [PATCH 28/30] Update generated/components.json --- generated/components.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/generated/components.json b/generated/components.json index af5abcf1487..3642c0f6b7b 100644 --- a/generated/components.json +++ b/generated/components.json @@ -4648,6 +4648,7 @@ { "name": "direction", "type": "'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w' | 'nw'", + "defaultValue": "n", "description": "Sets where the tooltip renders in relation to the target." }, { @@ -4663,6 +4664,7 @@ { "name": "type", "type": "'label' | 'description'", + "defaultValue": "label", "description": "The type of tooltip. `label` is used for labelling the element that triggers tooltip. `description` is used for describing or adding a suplementary information to the element that triggers the tooltip." }, { From 2042dd74a567a032f1f13b735a8303d9fd8c48fe Mon Sep 17 00:00:00 2001 From: Armagan Ersoz Date: Tue, 11 Apr 2023 10:57:18 +1000 Subject: [PATCH 29/30] snaps --- .../__snapshots__/Tooltip.test.tsx.snap | 542 ------------------ src/Tooltip/{ => __tests__}/Tooltip.test.tsx | 12 +- .../__tests__/Tooltip.types.test.tsx | 2 +- .../__snapshots__/TextInput.test.tsx.snap | 140 ++--- .../TextInputWithTokens.test.tsx.snap | 244 ++++---- 5 files changed, 196 insertions(+), 744 deletions(-) delete mode 100644 src/Tooltip/__snapshots__/Tooltip.test.tsx.snap rename src/Tooltip/{ => __tests__}/Tooltip.test.tsx (93%) rename src/{ => Tooltip}/__tests__/Tooltip.types.test.tsx (87%) diff --git a/src/Tooltip/__snapshots__/Tooltip.test.tsx.snap b/src/Tooltip/__snapshots__/Tooltip.test.tsx.snap deleted file mode 100644 index f8679eb0a92..00000000000 --- a/src/Tooltip/__snapshots__/Tooltip.test.tsx.snap +++ /dev/null @@ -1,542 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Tooltip renders consistently 1`] = ` -.c0 { - position: relative; - display: inline-block; -} - -.c2 { - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; -} - -.c1 { - border-radius: 6px; - border: 1px solid; - border-color: rgba(27,31,36,0.15); - font-family: inherit; - font-weight: 500; - font-size: 14px; - cursor: pointer; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - -webkit-text-decoration: none; - text-decoration: none; - text-align: center; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - -webkit-box-pack: justify; - -webkit-justify-content: space-between; - -ms-flex-pack: justify; - justify-content: space-between; - height: 32px; - padding: 0 12px; - gap: 8px; - min-width: -webkit-max-content; - min-width: -moz-max-content; - min-width: max-content; - -webkit-transition: 80ms cubic-bezier(0.65,0,0.35,1); - transition: 80ms cubic-bezier(0.65,0,0.35,1); - -webkit-transition-property: color,fill,background-color,border-color; - transition-property: color,fill,background-color,border-color; - color: #24292f; - background-color: #f6f8fa; - box-shadow: 0 1px 0 rgba(27,31,36,0.04),inset 0 1px 0 rgba(255,255,255,0.25); -} - -.c1:focus:not(:disabled) { - box-shadow: none; - outline: 2px solid #0969da; - outline-offset: -2px; -} - -.c1:focus:not(:disabled):not(:focus-visible) { - outline: solid 1px transparent; -} - -.c1:focus-visible:not(:disabled) { - box-shadow: none; - outline: 2px solid #0969da; - outline-offset: -2px; -} - -.c1[href] { - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; -} - -.c1[href]:hover { - -webkit-text-decoration: none; - text-decoration: none; -} - -.c1:hover { - -webkit-transition-duration: 80ms; - transition-duration: 80ms; -} - -.c1:active { - -webkit-transition: none; - transition: none; -} - -.c1:disabled { - cursor: not-allowed; - box-shadow: none; - color: #8c959f; -} - -.c1:disabled [data-component=ButtonCounter] { - color: inherit; -} - -.c1 [data-component=ButtonCounter] { - font-size: 14px; -} - -.c1[data-component=IconButton] { - display: inline-grid; - padding: unset; - place-content: center; - width: 32px; - min-width: unset; -} - -.c1[data-size="small"] { - padding: 0 8px; - height: 28px; - gap: 4px; - font-size: 12px; -} - -.c1[data-size="small"] [data-component="text"] { - line-height: calc(20 / 12); -} - -.c1[data-size="small"] [data-component=ButtonCounter] { - font-size: 12px; -} - -.c1[data-size="small"] [data-component="buttonContent"] > :not(:last-child) { - margin-right: 4px; -} - -.c1[data-size="small"][data-component=IconButton] { - width: 28px; - padding: unset; -} - -.c1[data-size="large"] { - padding: 0 16px; - height: 40px; - gap: 8px; -} - -.c1[data-size="large"] [data-component="buttonContent"] > :not(:last-child) { - margin-right: 8px; -} - -.c1[data-size="large"][data-component=IconButton] { - width: 40px; - padding: unset; -} - -.c1[data-block="block"] { - width: 100%; -} - -.c1 [data-component="leadingVisual"] { - grid-area: leadingVisual; -} - -.c1 [data-component="text"] { - grid-area: text; - line-height: calc(20/14); - white-space: nowrap; -} - -.c1 [data-component="trailingVisual"] { - grid-area: trailingVisual; -} - -.c1 [data-component="trailingAction"] { - margin-right: -4px; -} - -.c1 [data-component="buttonContent"] { - -webkit-flex: 1 0 auto; - -ms-flex: 1 0 auto; - flex: 1 0 auto; - display: grid; - grid-template-areas: "leadingVisual text trailingVisual"; - grid-template-columns: min-content minmax(0,auto) min-content; - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - -webkit-align-content: center; - -ms-flex-line-pack: center; - align-content: center; -} - -.c1 [data-component="buttonContent"] > :not(:last-child) { - margin-right: 8px; -} - -.c1:hover:not([disabled]) { - background-color: #f3f4f6; - border-color: rgba(27,31,36,0.15); -} - -.c1:active:not([disabled]) { - background-color: hsla(220,14%,93%,1); - border-color: rgba(27,31,36,0.15); -} - -.c1[aria-expanded=true] { - background-color: hsla(220,14%,93%,1); - border-color: rgba(27,31,36,0.15); -} - -.c3 { - position: absolute; - z-index: 1000000; - padding: 0.5em 0.75em; - font: normal normal 11px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",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: normal; - background: #24292f; - border-radius: 3px; - width: -webkit-max-content; - width: -moz-max-content; - width: max-content; - opacity: 0; - max-width: 250px; -} - -.c3:not([data-state='open']) { - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - -webkit-clip: rect(0,0,0,0); - clip: rect(0,0,0,0); - white-space: nowrap; - border-width: 0; -} - -.c3::before { - position: absolute; - z-index: 1000001; - color: #24292f; - content: ''; - border: 6px solid transparent; - opacity: 0; -} - -.c3::after { - position: absolute; - display: block; - right: 0; - left: 0; - height: 8px; - content: ''; -} - -.c3[data-direction='n']::before, -.c3[data-direction='ne']::before, -.c3[data-direction='nw']::before { - top: 100%; - border-top-color: #24292f; -} - -.c3[data-direction='s']::before, -.c3[data-direction='se']::before, -.c3[data-direction='sw']::before { - bottom: 100%; - border-bottom-color: #24292f; -} - -.c3[data-direction='n']:before, -.c3[data-direction='s']:before { - right: 50%; - margin-right: -6px; -} - -.c3[data-direction='ne']::before, -.c3[data-direction='se']::before { - left: 0; - margin-left: 6px; -} - -.c3[data-direction='sw']::before, -.c3[data-direction='nw']::before { - right: 0; - margin-right: 6px; -} - -.c3[data-direction='n']::after, -.c3[data-direction='ne']::after, -.c3[data-direction='nw']::after { - top: 100%; -} - -.c3[data-direction='s']::after, -.c3[data-direction='se']::after, -.c3[data-direction='sw']::after { - bottom: 100%; -} - -.c3[data-direction='w']::before { - top: 50%; - bottom: 50%; - left: 100%; - margin-top: -6px; - border-left-color: #24292f; -} - -.c3[data-direction='w']::after { - position: absolute; - display: block; - height: 100%; - width: 8px; - content: ''; - bottom: 0; - left: 100%; -} - -.c3[data-direction='e']::after { - position: absolute; - display: block; - height: 100%; - width: 8px; - content: ''; - bottom: 0; - right: 100%; - margin-left: -8px; -} - -.c3[data-direction='e']::before { - top: 50%; - bottom: 50%; - right: 100%; - margin-top: -6px; - border-right-color: #24292f; -} - -.c3[data-state='open'], -.c3[data-state='open']::before { - -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[data-state='open'][data-no-delay='true'], -.c3[data-state='open'][data-no-delay='true']::before { - -webkit-animation-delay: 0s; - animation-delay: 0s; -} - -.c3[data-state='open'][data-direction='s'], -.c3[data-state='open'][data-direction='se'], -.c3[data-state='open'][data-direction='sw'] { - top: 100%; - right: 50%; - margin-top: 6px; -} - -.c3[data-state='open'][data-direction='n'], -.c3[data-state='open'][data-direction='ne'], -.c3[data-state='open'][data-direction='nw'] { - bottom: 100%; - margin-bottom: 6px; - right: 50%; -} - -.c3[data-state='open'][data-direction='n'], -.c3[data-state='open'][data-direction='s'] { - -webkit-transform: translateX(50%); - -ms-transform: translateX(50%); - transform: translateX(50%); -} - -.c3[data-state='open'][data-direction='se'] { - right: auto; - left: 50%; - margin-left: -16px; -} - -.c3[data-state='open'][data-direction='ne'] { - right: auto; - left: 50%; - margin-left: -16px; -} - -.c3[data-state='open'][data-direction='sw'] { - margin-right: -16px; -} - -.c3[data-state='open'][data-direction='e'] { - bottom: 50%; - left: 100%; - margin-left: 6px; - -webkit-transform: translateY(50%); - -ms-transform: translateY(50%); - transform: translateY(50%); -} - -.c3[data-state='open'][data-direction='w'] { - bottom: 50%; - right: 100%; - margin-right: 6px; - -webkit-transform: translateY(50%); - -ms-transform: translateY(50%); - transform: translateY(50%); -} - -.c3[data-state='open'][data-align='left'] { - right: 100%; - margin-left: 0; -} - -.c3[data-state='open'][data-align='left']::before { - right: 40px; -} - -.c3[data-state='open'][data-align='right'] { - right: 0; - margin-right: 0; -} - -.c3[data-state='open'][data-align='right']::before { - right: 72px; -} - -.c3[data-state='open'][data-wrap='true'] { - display: table-cell; - 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[data-state='open'][data-wrap='true'][data-direction='n'], -.c3[data-state='open'][data-wrap='true'][data-direction='s'] { - -webkit-transform: translateX(-50%); - -ms-transform: translateX(-50%); - transform: translateX(-50%); - right: auto; - left: 50%; -} - -.c3[data-state='open'][data-wrap='true'][data-direction='w'], -.c3[data-state='open'][data-wrap='true'][data-direction='e'] { - right: 100%; -} - -@media (forced-colors:active) { - .c1:focus { - outline: solid 1px transparent; - } -} - -@media (forced-colors:active) { - .c3 { - outline: 1px solid transparent; - } -} - -
- -
- label type tooltip -
-
-`; diff --git a/src/Tooltip/Tooltip.test.tsx b/src/Tooltip/__tests__/Tooltip.test.tsx similarity index 93% rename from src/Tooltip/Tooltip.test.tsx rename to src/Tooltip/__tests__/Tooltip.test.tsx index f68116f941b..aad43bc85d4 100644 --- a/src/Tooltip/Tooltip.test.tsx +++ b/src/Tooltip/__tests__/Tooltip.test.tsx @@ -1,8 +1,8 @@ import React from 'react' -import {Tooltip, TooltipProps} from '.' -import {checkStoriesForAxeViolations, behavesAsComponent, checkExports} from '../utils/testing' +import {Tooltip, TooltipProps} from '..' +import {checkStoriesForAxeViolations, checkExports} from '../../utils/testing' import {render as HTMLRender, act} from '@testing-library/react' -import {Button} from '../Button' +import {Button} from '../../Button' import {SearchIcon} from '@primer/octicons-react' import userEvent from '@testing-library/user-event' @@ -15,12 +15,6 @@ const TooltipComponent = (props: TooltipProps) => ( ) describe('Tooltip', () => { - behavesAsComponent({ - Component: Tooltip, - options: {skipAs: true, skipSx: true}, - toRender: () => , - }) - checkExports('Tooltip', { default: undefined, Tooltip, diff --git a/src/__tests__/Tooltip.types.test.tsx b/src/Tooltip/__tests__/Tooltip.types.test.tsx similarity index 87% rename from src/__tests__/Tooltip.types.test.tsx rename to src/Tooltip/__tests__/Tooltip.types.test.tsx index 7714238ff20..65d27666df2 100644 --- a/src/__tests__/Tooltip.types.test.tsx +++ b/src/Tooltip/__tests__/Tooltip.types.test.tsx @@ -1,5 +1,5 @@ import React from 'react' -import {Tooltip} from '../Tooltip' +import {Tooltip} from '..' export function shouldAcceptCallWithNoProps() { return diff --git a/src/__tests__/__snapshots__/TextInput.test.tsx.snap b/src/__tests__/__snapshots__/TextInput.test.tsx.snap index 76832576457..3e03a89b1b0 100644 --- a/src/__tests__/__snapshots__/TextInput.test.tsx.snap +++ b/src/__tests__/__snapshots__/TextInput.test.tsx.snap @@ -4,7 +4,7 @@ exports[`TextInput renders 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #24292f; + color: #1F2328; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -70,7 +70,7 @@ exports[`TextInput renders 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #57606a; + color: #656d76; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -123,7 +123,7 @@ exports[`TextInput renders block 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #24292f; + color: #1F2328; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -197,7 +197,7 @@ exports[`TextInput renders block 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #57606a; + color: #656d76; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -250,7 +250,7 @@ exports[`TextInput renders consistently 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #24292f; + color: #1F2328; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -316,7 +316,7 @@ exports[`TextInput renders consistently 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #57606a; + color: #656d76; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -368,7 +368,7 @@ exports[`TextInput renders contrast 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #24292f; + color: #1F2328; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -435,7 +435,7 @@ exports[`TextInput renders contrast 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #57606a; + color: #656d76; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -488,7 +488,7 @@ exports[`TextInput renders error 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #24292f; + color: #1F2328; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -561,7 +561,7 @@ exports[`TextInput renders error 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #57606a; + color: #656d76; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -614,7 +614,7 @@ exports[`TextInput renders large 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #24292f; + color: #1F2328; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -686,7 +686,7 @@ exports[`TextInput renders large 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #57606a; + color: #656d76; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -740,7 +740,7 @@ exports[`TextInput renders leadingVisual 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #24292f; + color: #1F2328; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -806,7 +806,7 @@ exports[`TextInput renders leadingVisual 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #57606a; + color: #656d76; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -886,7 +886,7 @@ exports[`TextInput renders monospace 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #24292f; + color: #1F2328; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -953,7 +953,7 @@ exports[`TextInput renders monospace 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #57606a; + color: #656d76; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -1006,7 +1006,7 @@ exports[`TextInput renders placeholder 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #24292f; + color: #1F2328; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -1072,7 +1072,7 @@ exports[`TextInput renders placeholder 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #57606a; + color: #656d76; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -1126,7 +1126,7 @@ exports[`TextInput renders small 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #24292f; + color: #1F2328; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -1200,7 +1200,7 @@ exports[`TextInput renders small 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #57606a; + color: #656d76; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -1412,7 +1412,7 @@ exports[`TextInput renders trailingAction icon button 1`] = ` .c4 [data-component="leadingVisual"] { grid-area: leadingVisual; - color: #57606a; + color: #656d76; } .c4 [data-component="text"] { @@ -1427,7 +1427,7 @@ exports[`TextInput renders trailingAction icon button 1`] = ` .c4 [data-component="trailingAction"] { margin-right: -4px; - color: #57606a; + color: #656d76; } .c4 [data-component="buttonContent"] { @@ -1463,7 +1463,7 @@ exports[`TextInput renders trailingAction icon button 1`] = ` } .c4[data-component="IconButton"][data-no-visuals] { - color: #57606a; + color: #656d76; } .c4[data-no-visuals] { @@ -1490,7 +1490,7 @@ exports[`TextInput renders trailingAction icon button 1`] = ` .c0 { font-size: 14px; line-height: 20px; - color: #24292f; + color: #1F2328; vertical-align: middle; background-color: #ffffff; border: 1px solid #d0d7de; @@ -1550,7 +1550,7 @@ exports[`TextInput renders trailingAction icon button 1`] = ` -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; - color: #57606a; + color: #656d76; -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0; @@ -1890,7 +1890,7 @@ exports[`TextInput renders trailingAction icon button 1`] = ` > -
- iconLabel -
- - - -`; - -exports[`TextInput renders trailingAction text button 1`] = ` -.c2 { - margin-left: 4px; - margin-right: 4px; - line-height: 0; -} - -.c4 { - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; -} - -.c3 { - border-radius: 6px; - border: 1px solid; - border-color: transparent; - font-family: inherit; - font-weight: 500; - font-size: 14px; - cursor: pointer; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - -webkit-text-decoration: none; - text-decoration: none; - text-align: center; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - -webkit-box-pack: justify; - -webkit-justify-content: space-between; - -ms-flex-pack: justify; - justify-content: space-between; - height: 32px; - padding: 0 12px; - gap: 8px; - min-width: -webkit-max-content; - min-width: -moz-max-content; - min-width: max-content; - -webkit-transition: 80ms cubic-bezier(0.65,0,0.35,1); - transition: 80ms cubic-bezier(0.65,0,0.35,1); - -webkit-transition-property: color,fill,background-color,border-color; - transition-property: color,fill,background-color,border-color; - color: #0969da; - background-color: transparent; - box-shadow: none; -} - -.c3:focus:not(:disabled) { - box-shadow: none; - outline: 2px solid #0969da; - outline-offset: -2px; -} - -.c3:focus:not(:disabled):not(:focus-visible) { - outline: solid 1px transparent; -} - -.c3:focus-visible:not(:disabled) { - box-shadow: none; - outline: 2px solid #0969da; - outline-offset: -2px; -} - -.c3[href] { - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; -} - -.c3[href]:hover { - -webkit-text-decoration: none; - text-decoration: none; -} - -.c3:hover { - -webkit-transition-duration: 80ms; - transition-duration: 80ms; -} - -.c3:active { - -webkit-transition: none; - transition: none; -} - -.c3:disabled { - cursor: not-allowed; - box-shadow: none; - color: #8c959f; -} - -.c3:disabled [data-component=ButtonCounter] { - color: inherit; -} - -.c3 [data-component=ButtonCounter] { - font-size: 14px; -} - -.c3[data-component=IconButton] { - display: inline-grid; - padding: unset; - place-content: center; - width: 32px; - min-width: unset; -} - -.c3[data-size="small"] { - padding: 0 8px; - height: 28px; - gap: 4px; - font-size: 12px; -} - -.c3[data-size="small"] [data-component="text"] { - line-height: calc(20 / 12); -} - -.c3[data-size="small"] [data-component=ButtonCounter] { - font-size: 12px; -} - -.c3[data-size="small"] [data-component="buttonContent"] > :not(:last-child) { - margin-right: 4px; -} - -.c3[data-size="small"][data-component=IconButton] { - width: 28px; - padding: unset; -} - -.c3[data-size="large"] { - padding: 0 16px; - height: 40px; - gap: 8px; -} - -.c3[data-size="large"] [data-component="buttonContent"] > :not(:last-child) { - margin-right: 8px; -} - -.c3[data-size="large"][data-component=IconButton] { - width: 40px; - padding: unset; -} - -.c3[data-block="block"] { - width: 100%; -} - -.c3 [data-component="leadingVisual"] { - grid-area: leadingVisual; - color: #656d76; -} - -.c3 [data-component="text"] { - grid-area: text; - line-height: calc(20/14); - white-space: nowrap; -} - -.c3 [data-component="trailingVisual"] { - grid-area: trailingVisual; -} - -.c3 [data-component="trailingAction"] { - margin-right: -4px; - color: #656d76; -} - -.c3 [data-component="buttonContent"] { - -webkit-flex: 1 0 auto; - -ms-flex: 1 0 auto; - flex: 1 0 auto; - display: grid; - grid-template-areas: "leadingVisual text trailingVisual"; - grid-template-columns: min-content minmax(0,auto) min-content; - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - -webkit-align-content: center; - -ms-flex-line-pack: center; - align-content: center; -} - -.c3 [data-component="buttonContent"] > :not(:last-child) { - margin-right: 8px; -} - -.c3:hover:not([disabled]) { - background-color: #f3f4f6; -} - -.c3:active:not([disabled]) { - background-color: hsla(220,14%,94%,1); -} - -.c3[aria-expanded=true] { - background-color: hsla(220,14%,94%,1); -} - -.c3[data-component="IconButton"][data-no-visuals] { - color: #656d76; -} - -.c3[data-no-visuals] { - color: #0969da; -} - -.c3:has([data-component="ButtonCounter"]) { - color: #0969da; -} - -.c3[data-no-visuals="true"] { - padding-top: 2px; - padding-right: 4px; - padding-bottom: 2px; - padding-left: 4px; - position: relative; -} - -.c3[data-no-visuals="true"][data-component="IconButton"] { - width: var(--inner-action-size); - height: var(--inner-action-size); -} - -.c0 { - font-size: 14px; - line-height: 20px; - color: #1F2328; - vertical-align: middle; - background-color: #ffffff; - border: 1px solid #d0d7de; - border-radius: 6px; - outline: none; - box-shadow: inset 0 1px 0 rgba(208,215,222,0.2); - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; - -webkit-align-items: stretch; - -webkit-box-align: stretch; - -ms-flex-align: stretch; - align-items: stretch; - min-height: 32px; - background-repeat: no-repeat; - background-position: right 8px center; - padding-left: 0; - padding-right: 0; -} - -.c0 input, -.c0 textarea { - cursor: text; -} - -.c0 select { - cursor: pointer; -} - -.c0::-webkit-input-placeholder { - color: #6e7781; -} - -.c0::-moz-placeholder { - color: #6e7781; -} - -.c0:-ms-input-placeholder { - color: #6e7781; -} - -.c0::placeholder { - color: #6e7781; -} - -.c0 > textarea { - padding: 12px; -} - -.c0 > :not(:last-child) { - margin-right: 8px; -} - -.c0 .TextInput-icon, -.c0 .TextInput-action { - -webkit-align-self: center; - -ms-flex-item-align: center; - align-self: center; - color: #656d76; - -webkit-flex-shrink: 0; - -ms-flex-negative: 0; - flex-shrink: 0; -} - -.c0 > input, -.c0 > select { - padding-left: 12px; - padding-right: 0; -} - -.c1 { - border: 0; - font-size: inherit; - font-family: inherit; - background-color: transparent; - -webkit-appearance: none; - color: inherit; - width: 100%; -} - -.c1:focus { - outline: 0; -} - -@media (forced-colors:active) { - .c3:focus { - outline: solid 1px transparent; - } -} - -@media (pointer:coarse) { - .c3[data-no-visuals="true"]:after { - content: ""; - position: absolute; - left: 0; - right: 0; - -webkit-transform: translateY(-50%); - -ms-transform: translateY(-50%); - transform: translateY(-50%); - top: 50%; - min-height: 44px; - } -} - -@media (min-width:768px) { - .c0 { - font-size: 14px; - } -} - - - - - - - -`; - -exports[`TextInput renders trailingAction text button with a tooltip 1`] = ` +exports[`TextInput renders trailingAction text button 1`] = ` .c2 { margin-left: 4px; margin-right: 4px; line-height: 0; } -.c5 { +.c4 { -webkit-box-pack: center; -webkit-justify-content: center; -ms-flex-pack: center; @@ -2347,11 +1265,6 @@ exports[`TextInput renders trailingAction text button with a tooltip 1`] = ` } .c3 { - position: relative; - display: inline-block; -} - -.c4 { border-radius: 6px; border: 1px solid; border-color: transparent; @@ -2396,59 +1309,59 @@ exports[`TextInput renders trailingAction text button with a tooltip 1`] = ` box-shadow: none; } -.c4:focus:not(:disabled) { +.c3:focus:not(:disabled) { box-shadow: none; outline: 2px solid #0969da; outline-offset: -2px; } -.c4:focus:not(:disabled):not(:focus-visible) { +.c3:focus:not(:disabled):not(:focus-visible) { outline: solid 1px transparent; } -.c4:focus-visible:not(:disabled) { +.c3:focus-visible:not(:disabled) { box-shadow: none; outline: 2px solid #0969da; outline-offset: -2px; } -.c4[href] { +.c3[href] { display: -webkit-inline-box; display: -webkit-inline-flex; display: -ms-inline-flexbox; display: inline-flex; } -.c4[href]:hover { +.c3[href]:hover { -webkit-text-decoration: none; text-decoration: none; } -.c4:hover { +.c3:hover { -webkit-transition-duration: 80ms; transition-duration: 80ms; } -.c4:active { +.c3:active { -webkit-transition: none; transition: none; } -.c4:disabled { +.c3:disabled { cursor: not-allowed; box-shadow: none; color: #8c959f; } -.c4:disabled [data-component=ButtonCounter] { +.c3:disabled [data-component=ButtonCounter] { color: inherit; } -.c4 [data-component=ButtonCounter] { +.c3 [data-component=ButtonCounter] { font-size: 14px; } -.c4[data-component=IconButton] { +.c3[data-component=IconButton] { display: inline-grid; padding: unset; place-content: center; @@ -2456,70 +1369,70 @@ exports[`TextInput renders trailingAction text button with a tooltip 1`] = ` min-width: unset; } -.c4[data-size="small"] { +.c3[data-size="small"] { padding: 0 8px; height: 28px; gap: 4px; font-size: 12px; } -.c4[data-size="small"] [data-component="text"] { +.c3[data-size="small"] [data-component="text"] { line-height: calc(20 / 12); } -.c4[data-size="small"] [data-component=ButtonCounter] { +.c3[data-size="small"] [data-component=ButtonCounter] { font-size: 12px; } -.c4[data-size="small"] [data-component="buttonContent"] > :not(:last-child) { +.c3[data-size="small"] [data-component="buttonContent"] > :not(:last-child) { margin-right: 4px; } -.c4[data-size="small"][data-component=IconButton] { +.c3[data-size="small"][data-component=IconButton] { width: 28px; padding: unset; } -.c4[data-size="large"] { +.c3[data-size="large"] { padding: 0 16px; height: 40px; gap: 8px; } -.c4[data-size="large"] [data-component="buttonContent"] > :not(:last-child) { +.c3[data-size="large"] [data-component="buttonContent"] > :not(:last-child) { margin-right: 8px; } -.c4[data-size="large"][data-component=IconButton] { +.c3[data-size="large"][data-component=IconButton] { width: 40px; padding: unset; } -.c4[data-block="block"] { +.c3[data-block="block"] { width: 100%; } -.c4 [data-component="leadingVisual"] { +.c3 [data-component="leadingVisual"] { grid-area: leadingVisual; color: #656d76; } -.c4 [data-component="text"] { +.c3 [data-component="text"] { grid-area: text; line-height: calc(20/14); white-space: nowrap; } -.c4 [data-component="trailingVisual"] { +.c3 [data-component="trailingVisual"] { grid-area: trailingVisual; } -.c4 [data-component="trailingAction"] { +.c3 [data-component="trailingAction"] { margin-right: -4px; color: #656d76; } -.c4 [data-component="buttonContent"] { +.c3 [data-component="buttonContent"] { -webkit-flex: 1 0 auto; -ms-flex: 1 0 auto; flex: 1 0 auto; @@ -2535,35 +1448,35 @@ exports[`TextInput renders trailingAction text button with a tooltip 1`] = ` align-content: center; } -.c4 [data-component="buttonContent"] > :not(:last-child) { +.c3 [data-component="buttonContent"] > :not(:last-child) { margin-right: 8px; } -.c4:hover:not([disabled]) { +.c3:hover:not([disabled]) { background-color: #f3f4f6; } -.c4:active:not([disabled]) { +.c3:active:not([disabled]) { background-color: hsla(220,14%,94%,1); } -.c4[aria-expanded=true] { +.c3[aria-expanded=true] { background-color: hsla(220,14%,94%,1); } -.c4[data-component="IconButton"][data-no-visuals] { +.c3[data-component="IconButton"][data-no-visuals] { color: #656d76; } -.c4[data-no-visuals] { +.c3[data-no-visuals] { color: #0969da; } -.c4:has([data-component="ButtonCounter"]) { +.c3:has([data-component="ButtonCounter"]) { color: #0969da; } -.c4[data-no-visuals="true"] { +.c3[data-no-visuals="true"] { padding-top: 2px; padding-right: 4px; padding-bottom: 2px; @@ -2571,7 +1484,7 @@ exports[`TextInput renders trailingAction text button with a tooltip 1`] = ` position: relative; } -.c4[data-no-visuals="true"][data-component="IconButton"] { +.c3[data-no-visuals="true"][data-component="IconButton"] { width: var(--inner-action-size); height: var(--inner-action-size); } @@ -2665,273 +1578,14 @@ exports[`TextInput renders trailingAction text button with a tooltip 1`] = ` outline: 0; } -.c6 { - position: absolute; - z-index: 1000000; - padding: 0.5em 0.75em; - font: normal normal 11px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",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: normal; - background: #24292f; - border-radius: 3px; - width: -webkit-max-content; - width: -moz-max-content; - width: max-content; - opacity: 0; - max-width: 250px; - display: inline-block; -} - -.c6:not([data-state='open']) { - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - -webkit-clip: rect(0,0,0,0); - clip: rect(0,0,0,0); - white-space: nowrap; - border-width: 0; -} - -.c6::before { - position: absolute; - z-index: 1000001; - color: #24292f; - content: ''; - border: 6px solid transparent; - opacity: 0; -} - -.c6::after { - position: absolute; - display: block; - right: 0; - left: 0; - height: 8px; - content: ''; -} - -.c6[data-direction='n']::before, -.c6[data-direction='ne']::before, -.c6[data-direction='nw']::before { - top: 100%; - border-top-color: #24292f; -} - -.c6[data-direction='s']::before, -.c6[data-direction='se']::before, -.c6[data-direction='sw']::before { - bottom: 100%; - border-bottom-color: #24292f; -} - -.c6[data-direction='n']:before, -.c6[data-direction='s']:before { - right: 50%; - margin-right: -6px; -} - -.c6[data-direction='ne']::before, -.c6[data-direction='se']::before { - left: 0; - margin-left: 6px; -} - -.c6[data-direction='sw']::before, -.c6[data-direction='nw']::before { - right: 0; - margin-right: 6px; -} - -.c6[data-direction='n']::after, -.c6[data-direction='ne']::after, -.c6[data-direction='nw']::after { - top: 100%; -} - -.c6[data-direction='s']::after, -.c6[data-direction='se']::after, -.c6[data-direction='sw']::after { - bottom: 100%; -} - -.c6[data-direction='w']::before { - top: 50%; - bottom: 50%; - left: 100%; - margin-top: -6px; - border-left-color: #24292f; -} - -.c6[data-direction='w']::after { - position: absolute; - display: block; - height: 100%; - width: 8px; - content: ''; - bottom: 0; - left: 100%; -} - -.c6[data-direction='e']::after { - position: absolute; - display: block; - height: 100%; - width: 8px; - content: ''; - bottom: 0; - right: 100%; - margin-left: -8px; -} - -.c6[data-direction='e']::before { - top: 50%; - bottom: 50%; - right: 100%; - margin-top: -6px; - border-right-color: #24292f; -} - -.c6[data-state='open'], -.c6[data-state='open']::before { - -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; -} - -.c6[data-state='open'][data-no-delay='true'], -.c6[data-state='open'][data-no-delay='true']::before { - -webkit-animation-delay: 0s; - animation-delay: 0s; -} - -.c6[data-state='open'][data-direction='s'], -.c6[data-state='open'][data-direction='se'], -.c6[data-state='open'][data-direction='sw'] { - top: 100%; - right: 50%; - margin-top: 6px; -} - -.c6[data-state='open'][data-direction='n'], -.c6[data-state='open'][data-direction='ne'], -.c6[data-state='open'][data-direction='nw'] { - bottom: 100%; - margin-bottom: 6px; - right: 50%; -} - -.c6[data-state='open'][data-direction='n'], -.c6[data-state='open'][data-direction='s'] { - -webkit-transform: translateX(50%); - -ms-transform: translateX(50%); - transform: translateX(50%); -} - -.c6[data-state='open'][data-direction='se'] { - right: auto; - left: 50%; - margin-left: -16px; -} - -.c6[data-state='open'][data-direction='ne'] { - right: auto; - left: 50%; - margin-left: -16px; -} - -.c6[data-state='open'][data-direction='sw'] { - margin-right: -16px; -} - -.c6[data-state='open'][data-direction='e'] { - bottom: 50%; - left: 100%; - margin-left: 6px; - -webkit-transform: translateY(50%); - -ms-transform: translateY(50%); - transform: translateY(50%); -} - -.c6[data-state='open'][data-direction='w'] { - bottom: 50%; - right: 100%; - margin-right: 6px; - -webkit-transform: translateY(50%); - -ms-transform: translateY(50%); - transform: translateY(50%); -} - -.c6[data-state='open'][data-align='left'] { - right: 100%; - margin-left: 0; -} - -.c6[data-state='open'][data-align='left']::before { - right: 40px; -} - -.c6[data-state='open'][data-align='right'] { - right: 0; - margin-right: 0; -} - -.c6[data-state='open'][data-align='right']::before { - right: 72px; -} - -.c6[data-state='open'][data-wrap='true'] { - display: table-cell; - 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; -} - -.c6[data-state='open'][data-wrap='true'][data-direction='n'], -.c6[data-state='open'][data-wrap='true'][data-direction='s'] { - -webkit-transform: translateX(-50%); - -ms-transform: translateX(-50%); - transform: translateX(-50%); - right: auto; - left: 50%; -} - -.c6[data-state='open'][data-wrap='true'][data-direction='w'], -.c6[data-state='open'][data-wrap='true'][data-direction='e'] { - right: 100%; -} - @media (forced-colors:active) { - .c4:focus { + .c3:focus { outline: solid 1px transparent; } } @media (pointer:coarse) { - .c4[data-no-visuals="true"]:after { + .c3[data-no-visuals="true"]:after { content: ""; position: absolute; left: 0; @@ -2950,12 +1604,6 @@ exports[`TextInput renders trailingAction text button with a tooltip 1`] = ` } } -@media (forced-colors:active) { - .c6 { - outline: 1px solid transparent; - } -} - -
- -
- Clear input -
-
+
+ `;