diff --git a/.changeset/stale-snakes-cough.md b/.changeset/stale-snakes-cough.md new file mode 100644 index 00000000000..956fb3d4658 --- /dev/null +++ b/.changeset/stale-snakes-cough.md @@ -0,0 +1,5 @@ +--- +'@primer/react': minor +--- + +Remove the CSS modules feature flag from the Token component diff --git a/packages/react/src/Token/AvatarToken.tsx b/packages/react/src/Token/AvatarToken.tsx index 79e4204a914..de7da348425 100644 --- a/packages/react/src/Token/AvatarToken.tsx +++ b/packages/react/src/Token/AvatarToken.tsx @@ -1,13 +1,9 @@ import React, {forwardRef} from 'react' -import styled from 'styled-components' -import {get} from '../constants' -import type {TokenBaseProps, TokenSizeKeys} from './TokenBase' +import type {TokenBaseProps} from './TokenBase' import {defaultTokenSize, tokenSizes} from './TokenBase' import Token from './Token' import Avatar from '../Avatar' import type {ForwardRefComponent as PolymorphicForwardRefComponent} from '../utils/polymorphic' -import {toggleStyledComponent} from '../internal/utils/toggleStyledComponent' -import {useFeatureFlag} from '../FeatureFlags' import classes from './AvatarToken.module.css' import {clsx} from 'clsx' @@ -16,67 +12,21 @@ export interface AvatarTokenProps extends TokenBaseProps { avatarSrc: string } -const CSS_MODULES_FEATURE_FLAG = 'primer_react_css_modules_ga' - -const AvatarContainer = toggleStyledComponent( - CSS_MODULES_FEATURE_FLAG, - 'span', - styled.span<{avatarSize: TokenSizeKeys}>` - // 'space.1' is used because to match space from the left of the token to the left of the avatar - // '* 2' is done to account for the top and bottom - --spacing: calc(${get('space.1')} * 2); - - display: block; - height: ${props => `calc(${tokenSizes[props.avatarSize]} - var(--spacing))`}; - width: ${props => `calc(${tokenSizes[props.avatarSize]} - var(--spacing))`}; - `, -) - const AvatarToken = forwardRef(({avatarSrc, id, size = defaultTokenSize, className, ...rest}, forwardedRef) => { - const enabled = useFeatureFlag(CSS_MODULES_FEATURE_FLAG) - if (enabled) { - return ( - ( - - - - )} - size={size} - id={id?.toString()} - className={clsx(classes.Token, className)} - {...rest} - ref={forwardedRef} - /> - ) - } - return ( ( - - - + + + )} size={size} id={id?.toString()} - sx={{ - paddingLeft: get('space.1'), - }} - className={className} + className={clsx(classes.Token, className)} {...rest} ref={forwardedRef} /> ) }) as PolymorphicForwardRefComponent<'span' | 'a' | 'button', AvatarTokenProps> -AvatarToken.displayName = 'AvatarToken' - export default AvatarToken diff --git a/packages/react/src/Token/IssueLabelToken.tsx b/packages/react/src/Token/IssueLabelToken.tsx index ceb810670bd..072aaf8d067 100644 --- a/packages/react/src/Token/IssueLabelToken.tsx +++ b/packages/react/src/Token/IssueLabelToken.tsx @@ -9,7 +9,6 @@ import {useTheme} from '../ThemeProvider' import TokenTextContainer from './_TokenTextContainer' import type {ForwardRefComponent as PolymorphicForwardRefComponent} from '../utils/polymorphic' import classes from './IssueLabelToken.module.css' -import {useFeatureFlag} from '../FeatureFlags' import {clsx} from 'clsx' export interface IssueLabelTokenProps extends TokenBaseProps { @@ -19,7 +18,6 @@ export interface IssueLabelTokenProps extends TokenBaseProps { fillColor?: string } -const CSS_MODULES_FEATURE_FLAG = 'primer_react_css_modules_ga' const tokenBorderWidthPx = 1 const lightModeStyles = { @@ -47,8 +45,6 @@ const darkModeStyles = { } const IssueLabelToken = forwardRef((props, forwardedRef) => { - const enabled = useFeatureFlag(CSS_MODULES_FEATURE_FLAG) - const { as, fillColor = '#999', @@ -141,46 +137,16 @@ const IssueLabelToken = forwardRef((props, forwardedRef) => { } }, [fillColor, resolvedColorScheme, hideRemoveButton, onRemove, isSelected, props]) - if (enabled) { - return ( - - {text} - {!hideRemoveButton && onRemove ? ( - - ) : null} - - ) - } - return ( { size={size} aria-hidden={hasMultipleActionTargets ? 'true' : 'false'} isParentInteractive={isTokenInteractive(props)} - sx={ - hasMultipleActionTargets - ? { - position: 'relative', - zIndex: '1', - } - : {} - } + data-has-multiple-action-targets={hasMultipleActionTargets} + className={classes.RemoveButton} /> ) : null} ) }) as PolymorphicForwardRefComponent<'span' | 'a' | 'button', IssueLabelTokenProps> -IssueLabelToken.displayName = 'IssueLabelToken' - export default IssueLabelToken diff --git a/packages/react/src/Token/Token.tsx b/packages/react/src/Token/Token.tsx index 7c9a445a70f..fa5faa0643d 100644 --- a/packages/react/src/Token/Token.tsx +++ b/packages/react/src/Token/Token.tsx @@ -1,7 +1,7 @@ import type {MouseEventHandler} from 'react' import React, {forwardRef} from 'react' import Box from '../Box' -import {merge, type BetterSystemStyleObject, type SxProp} from '../sx' +import {type SxProp} from '../sx' import {defaultSxProp} from '../utils/defaultSxProp' import type {TokenBaseProps} from './TokenBase' import TokenBase, {defaultTokenSize, isTokenInteractive} from './TokenBase' @@ -9,7 +9,6 @@ import RemoveTokenButton from './_RemoveTokenButton' import TokenTextContainer from './_TokenTextContainer' import type {ForwardRefComponent as PolymorphicForwardRefComponent} from '../utils/polymorphic' import VisuallyHidden from '../_VisuallyHidden' -import {useFeatureFlag} from '../FeatureFlags' import classes from './Token.module.css' import {clsx} from 'clsx' @@ -23,8 +22,6 @@ export interface TokenProps extends TokenBaseProps, SxProp { leadingVisual?: React.ElementType } -const CSS_MODULES_FEATURE_FLAG = 'primer_react_css_modules_ga' - const tokenBorderWidthPx = 1 const LeadingVisualContainer: React.FC>> = ({children, size}) => ( @@ -40,8 +37,6 @@ const LeadingVisualContainer: React.FC { - const enabled = useFeatureFlag(CSS_MODULES_FEATURE_FLAG) - const { as, onRemove, @@ -68,79 +63,20 @@ const Token = forwardRef((props, forwardedRef) => { onClick, } - const mergedSx = merge( - { - backgroundColor: 'neutral.subtle', - borderColor: props.isSelected ? 'fg.default' : 'border.subtle', - borderStyle: 'solid', - borderWidth: `${tokenBorderWidthPx}px`, - color: props.isSelected ? 'fg.default' : 'fg.muted', - maxWidth: '100%', - paddingRight: !(hideRemoveButton || !onRemove) ? 0 : undefined, - ...(isTokenInteractive(props) - ? { - '&:hover': { - backgroundColor: 'neutral.muted', - boxShadow: 'shadow.medium', - color: 'fg.default', - }, - } - : {}), - }, - sxProp, - ) - - if (enabled) { - return ( - - {LeadingVisual ? ( - - - - ) : null} - - {text} - {onRemove && (press backspace or delete to remove)} - - - {!hideRemoveButton && onRemove ? ( - - ) : null} - - ) - } - return ( {LeadingVisual ? ( diff --git a/packages/react/src/Token/TokenBase.tsx b/packages/react/src/Token/TokenBase.tsx index f3a13dfd98a..6bd2029df29 100644 --- a/packages/react/src/Token/TokenBase.tsx +++ b/packages/react/src/Token/TokenBase.tsx @@ -1,15 +1,10 @@ import type {ComponentProps, KeyboardEvent} from 'react' import React from 'react' -import styled from 'styled-components' -import {variant} from 'styled-system' import {clsx} from 'clsx' -import {get} from '../constants' import type {SxProp} from '../sx' -import sx from '../sx' import type {ForwardRefComponent as PolymorphicForwardRefComponent} from '../utils/polymorphic' -import {useFeatureFlag} from '../FeatureFlags' import classes from './TokenBase.module.css' -import {toggleStyledComponent} from '../internal/utils/toggleStyledComponent' +import {BoxWithFallback} from '../internal/components/BoxWithFallback' export type TokenSizeKeys = 'small' | 'medium' | 'large' | 'xlarge' @@ -68,104 +63,11 @@ export const isTokenInteractive = ({ return Boolean(onFocus || onClick || tabIndex > -1 || ['a', 'button'].includes(as)) } -const xlargeVariantStyles = { - fontSize: 1, - height: tokenSizes.xlarge, - lineHeight: tokenSizes.xlarge, - paddingLeft: 3, - paddingRight: 3, - paddingTop: 0, - paddingBottom: 0, -} - -const variants = variant< - { - fontSize: number - height: string - lineHeight: string - paddingLeft: number - paddingRight: number - }, - TokenSizeKeys ->({ - prop: 'size', - variants: { - small: { - fontSize: 0, - height: tokenSizes.small, - // without setting lineHeight to match height, the "x" appears vertically mis-aligned - lineHeight: tokenSizes.small, - paddingLeft: 1, - paddingRight: 1, - }, - medium: { - fontSize: 0, - height: tokenSizes.medium, - lineHeight: tokenSizes.medium, - paddingLeft: 2, - paddingRight: 2, - }, - large: { - fontSize: 0, - height: tokenSizes.large, - lineHeight: tokenSizes.large, - paddingLeft: 2, - paddingRight: 2, - }, - xlarge: xlargeVariantStyles, - }, -}) - -const CSS_MODULES_FEATURE_FLAG = 'primer_react_css_modules_ga' - -const StyledTokenBase = toggleStyledComponent( - CSS_MODULES_FEATURE_FLAG, - 'span', - styled.span< - { - size?: TokenSizeKeys - } & SxProp - >` - align-items: center; - border-radius: 999px; - cursor: ${props => (isTokenInteractive(props) ? 'pointer' : 'auto')}; - display: inline-flex; - font-weight: ${get('fontWeights.bold')}; - font-family: inherit; - text-decoration: none; - position: relative; - white-space: nowrap; - ${variants} - ${sx} - `, -) - const TokenBase = React.forwardRef( - ({onRemove, onKeyDown, id, className, size = defaultTokenSize, ...rest}, forwardedRef) => { - const enabled = useFeatureFlag(CSS_MODULES_FEATURE_FLAG) - - if (enabled) { - return ( - ) => { - onKeyDown && onKeyDown(event) - - if ((event.key === 'Backspace' || event.key === 'Delete') && onRemove) { - onRemove() - } - }} - className={clsx(classes.TokenBase, className)} - data-cursor-is-interactive={isTokenInteractive(rest)} - data-size={size} - id={id?.toString()} - {...rest} - ref={forwardedRef} - /> - ) - } - + ({onRemove, onKeyDown, id, className, size = defaultTokenSize, as = 'span', isSelected, ...rest}, forwardedRef) => { return ( - ) => { onKeyDown && onKeyDown(event) @@ -173,9 +75,11 @@ const TokenBase = React.forwardRef diff --git a/packages/react/src/Token/_RemoveTokenButton.tsx b/packages/react/src/Token/_RemoveTokenButton.tsx index 1d97350a3eb..15e07e05920 100644 --- a/packages/react/src/Token/_RemoveTokenButton.tsx +++ b/packages/react/src/Token/_RemoveTokenButton.tsx @@ -1,16 +1,12 @@ import React from 'react' import {XIcon} from '@primer/octicons-react' -import styled, {css} from 'styled-components' -import {variant} from 'styled-system' import {clsx} from 'clsx' -import {get} from '../constants' -import sx, {type SxProp} from '../sx' +import {type SxProp} from '../sx' import type {TokenSizeKeys} from './TokenBase' import {tokenSizes, defaultTokenSize} from './TokenBase' -import {toggleStyledComponent} from '../internal/utils/toggleStyledComponent' -import {useFeatureFlag} from '../FeatureFlags' import classes from './_RemoveTokenButton.module.css' +import {BoxWithFallback} from '../internal/components/BoxWithFallback' interface TokenButtonProps extends SxProp { borderOffset?: number @@ -18,82 +14,8 @@ interface TokenButtonProps extends SxProp { isParentInteractive?: boolean } -const CSS_MODULES_FEATURE_FLAG = 'primer_react_css_modules_ga' - -const variants = variant<{height: string; width: string}, TokenSizeKeys>({ - prop: 'size', - variants: { - small: { - height: tokenSizes.small, - width: tokenSizes.small, - }, - medium: { - height: tokenSizes.medium, - width: tokenSizes.medium, - }, - large: { - height: tokenSizes.large, - width: tokenSizes.large, - }, - xlarge: { - height: tokenSizes.xlarge, - width: tokenSizes.xlarge, - }, - }, -}) - const getTokenButtonIconSize = (size?: TokenSizeKeys) => parseInt(tokenSizes[size || defaultTokenSize], 10) * 0.75 -const StyledTokenButton = toggleStyledComponent( - CSS_MODULES_FEATURE_FLAG, - 'span', - styled.span` - background-color: transparent; - font-family: inherit; - color: currentColor; - cursor: pointer; - display: inline-flex; - justify-content: center; - align-items: center; - user-select: none; - appearance: none; - text-decoration: none; - padding: 0; - transform: ${props => `translate(${props.borderOffset}px, -${props.borderOffset}px)`}; - align-self: baseline; - border: 0; - border-radius: 999px; - - ${props => { - switch (props.size) { - case 'large': - case 'xlarge': - return css` - margin-left: ${get('space.2')}; - ` - default: - return css` - margin-left: ${get('space.1')}; - ` - } - }} - - &:hover, - &:focus { - // TODO: choose a better functional color variable for this - background-color: ${get('colors.neutral.muted')}; - } - - &:active { - // TODO: choose a better functional color variable for this - background-color: ${get('colors.neutral.subtle')}; - } - - ${variants} - ${sx} - `, -) - type RemoveTokenButtonProps = TokenButtonProps & Omit, 'size'> const RemoveTokenButton = ({ @@ -101,31 +23,26 @@ const RemoveTokenButton = ({ isParentInteractive, size = defaultTokenSize, className, + borderOffset = 0, ...rest }: React.PropsWithChildren) => { delete rest.children - const enabled = useFeatureFlag(CSS_MODULES_FEATURE_FLAG) - return ( - - + ) } diff --git a/packages/react/src/Token/_TokenTextContainer.tsx b/packages/react/src/Token/_TokenTextContainer.tsx index d4c7b9ea1dc..9d443e89586 100644 --- a/packages/react/src/Token/_TokenTextContainer.tsx +++ b/packages/react/src/Token/_TokenTextContainer.tsx @@ -1,66 +1,30 @@ -import styled from 'styled-components' import type {TokenBaseProps} from './TokenBase' -import {toggleStyledComponent} from '../internal/utils/toggleStyledComponent' import React from 'react' import classes from './_TokenTextContainer.module.css' -import {useFeatureFlag} from '../FeatureFlags' import {clsx} from 'clsx' -const CSS_MODULES_FEATURE_FLAG = 'primer_react_css_modules_ga' - -const StyledTokenTextContainer = toggleStyledComponent( - CSS_MODULES_FEATURE_FLAG, - 'span', - styled('span')` - flex-grow: 1; - min-width: 0; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - - // reset button styles, make the cursor a pointer, and add line-height - background: transparent; - border: none; - color: inherit; - font: inherit; - margin: 0; - padding: 0; - width: auto; - -webkit-font-smoothing: inherit; - -moz-osx-font-smoothing: inherit; - -webkit-appearance: none; - line-height: normal; - - // reset anchor styles - color: currentColor; - text-decoration: none; - - // Position psuedo-element above text content, but below the - // remove button. - // This ensures the or