From 31e56a4517edad49ca7169888e1e2283a9291911 Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Wed, 9 Jul 2025 17:46:09 +0000 Subject: [PATCH 1/2] Migrate from toggleSxComponent to BoxWithFallback --- .../react/src/Breadcrumbs/Breadcrumbs.tsx | 11 +- packages/react/src/PageHeader/PageHeader.tsx | 119 +++++------------- packages/react/src/Popover/Popover.tsx | 14 +-- packages/react/src/Text/Text.tsx | 5 +- packages/react/src/TooltipV2/Tooltip.tsx | 11 +- .../__tests__/toggleSxComponent.test.tsx | 39 ------ .../src/internal/utils/toggleSxComponent.tsx | 34 ----- script/styled-components-migration-status.mts | 4 - 8 files changed, 45 insertions(+), 192 deletions(-) delete mode 100644 packages/react/src/internal/utils/__tests__/toggleSxComponent.test.tsx delete mode 100644 packages/react/src/internal/utils/toggleSxComponent.tsx diff --git a/packages/react/src/Breadcrumbs/Breadcrumbs.tsx b/packages/react/src/Breadcrumbs/Breadcrumbs.tsx index e252f1b4e78..fe47e2307ec 100644 --- a/packages/react/src/Breadcrumbs/Breadcrumbs.tsx +++ b/packages/react/src/Breadcrumbs/Breadcrumbs.tsx @@ -5,7 +5,7 @@ import type {SxProp} from '../sx' import type {ComponentProps} from '../utils/types' import classes from './Breadcrumbs.module.css' import type {ForwardRefComponent as PolymorphicForwardRefComponent} from '../utils/polymorphic' -import {toggleSxComponent} from '../internal/utils/toggleSxComponent' +import {BoxWithFallback} from '../internal/components/BoxWithFallback' const SELECTED_CLASS = 'selected' @@ -19,13 +19,12 @@ const BreadcrumbsList = ({children}: React.PropsWithChildren) => { return
    {children}
} -const BreadcrumbsBaseComponent = toggleSxComponent('nav') as React.ComponentType function Breadcrumbs({className, children, sx: sxProp}: BreadcrumbsProps) { const wrappedChildren = React.Children.map(children, child =>
  • {child}
  • ) return ( - + {wrappedChildren} - + ) } @@ -37,10 +36,10 @@ type StyledBreadcrumbsItemProps = { React.HTMLAttributes & React.ComponentPropsWithRef<'a'> -const BreadcrumbsItemBaseComponent = toggleSxComponent('a') as React.ComponentType const BreadcrumbsItem = React.forwardRef(({selected, className, ...rest}, ref) => { return ( - > -> const Root = React.forwardRef>( ({children, className, sx = defaultSxProp, as = 'div', 'aria-label': ariaLabel, role, hasBorder}, forwardedRef) => { const rootRef = useProvidedRefOrCreate(forwardedRef as React.RefObject) @@ -109,7 +105,7 @@ const Root = React.forwardRef {children} - + ) }, ) as PolymorphicForwardRefComponent<'div', PageHeaderProps> -const ContextAreaBaseComponent = toggleSxComponent('div') as React.ComponentType< - React.PropsWithChildren> -> // PageHeader.ContextArea : Only visible on narrow viewports by default to provide user context of where they are at their journey. `hidden` prop available // to manage their custom visibility but consumers should be careful if they choose to hide this on narrow viewports. // PageHeader.ContextArea Sub Components: PageHeader.ParentLink, PageHeader.ContextBar, PageHeader.ContextAreaActions @@ -138,13 +131,9 @@ const ContextArea: React.FC> = ({ sx: sxProp = defaultSxProp, }) => { return ( - + {children} - + ) } type LinkProps = Pick< @@ -182,7 +171,7 @@ const ParentLink = React.forwardRef( href={href} > - {children} +
    {children}
    ) @@ -194,9 +183,6 @@ ParentLink.displayName = 'ParentLink' // Generic slot for any component above the title region. Use it for custom breadcrumbs and other navigation elements instead of ParentLink. // --------------------------------------------------------------------- -const ContextBarBaseComponent = toggleSxComponent('div') as React.ComponentType< - React.PropsWithChildren> -> const ContextBar: React.FC> = ({ children, className, @@ -204,19 +190,12 @@ const ContextBar: React.FC> = ({ hidden = hiddenOnRegularAndWide, }) => { return ( - + {children} - + ) } -const ContextAreaActionsBaseComponent = toggleSxComponent('div') as React.ComponentType< - React.PropsWithChildren> -> // ContextAreaActions // --------------------------------------------------------------------- const ContextAreaActions: React.FC> = ({ @@ -226,14 +205,14 @@ const ContextAreaActions: React.FC> = hidden = hiddenOnRegularAndWide, }) => { return ( - {children} - + ) } @@ -244,15 +223,12 @@ type TitleAreaProps = { // PageHeader.TitleArea Sub Components: PageHeader.LeadingVisual, PageHeader.Title, PageTitle.TrailingVisual // --------------------------------------------------------------------- -const TitleAreaBaseComponent = toggleSxComponent('div') as React.ComponentType< - React.PropsWithChildren> -> const TitleArea = React.forwardRef>( ({children, className, sx: sxProp = defaultSxProp, hidden = false, variant = 'medium'}, forwardedRef) => { const titleAreaRef = useProvidedRefOrCreate(forwardedRef as React.RefObject) const currentVariant = useResponsiveValue(variant, 'medium') return ( - {children} - + ) }, ) as PolymorphicForwardRefComponent<'div', TitleAreaProps> TitleArea.displayName = 'TitleArea' -const LeadingActionBaseComponent = toggleSxComponent('div') as React.ComponentType< - React.PropsWithChildren> & - React.HtmlHTMLAttributes -> // PageHeader.LeadingAction and PageHeader.TrailingAction should only be visible on regular viewports. // So they come as hidden on narrow viewports by default and their visibility can be managed by their `hidden` prop. const LeadingAction: React.FC> = ({ @@ -284,7 +256,7 @@ const LeadingAction: React.FC> = ({ const {height} = sxProp if (height) style['--custom-height'] = height return ( - > = ({ {...getHiddenDataAttributes(hidden)} > {children} - + ) } -const BreadcrumbsBaseComponent = toggleSxComponent('div') as React.ComponentType< - React.PropsWithChildren> -> // This is reserved for only breadcrumbs. const Breadcrumbs: React.FC> = ({ children, @@ -307,22 +276,17 @@ const Breadcrumbs: React.FC> = ({ hidden = false, }) => { return ( - {children} - + ) } -const LeadingVisualBaseComponent = toggleSxComponent('div') as React.ComponentType< - React.PropsWithChildren< - ChildrenPropTypes & React.RefAttributes & React.HtmlHTMLAttributes - > -> // PageHeader.LeadingVisual and PageHeader.TrailingVisual should remain visible on narrow viewports. const LeadingVisual: React.FC> = ({ children, @@ -335,7 +299,7 @@ const LeadingVisual: React.FC> = ({ const {height} = sxProp if (height) style['--custom-height'] = height return ( - > = ({ {...getHiddenDataAttributes(hidden)} > {children} - + ) } @@ -380,11 +344,6 @@ const Title: React.FC> = ({ ) } -const TrailingVisualBaseComponent = toggleSxComponent('div') as React.ComponentType< - React.PropsWithChildren< - ChildrenPropTypes & React.RefAttributes & React.HtmlHTMLAttributes - > -> // PageHeader.LeadingVisual and PageHeader.TrailingVisual should remain visible on narrow viewports. const TrailingVisual: React.FC> = ({ children, @@ -397,7 +356,7 @@ const TrailingVisual: React.FC> = ({ const {height} = sxProp if (height) style['--custom-height'] = height return ( - > = ({ {...getHiddenDataAttributes(hidden)} > {children} - + ) } -const TrailingActionBaseComponent = toggleSxComponent('div') as React.ComponentType< - React.PropsWithChildren< - ChildrenPropTypes & React.RefAttributes & React.HtmlHTMLAttributes - > -> const TrailingAction: React.FC> = ({ children, className, @@ -425,7 +379,7 @@ const TrailingAction: React.FC> = ({ const {height} = sxProp if (height) style['--custom-height'] = height return ( - > = ({ {...getHiddenDataAttributes(hidden)} > {children} - + ) } -const ActionsBaseComponent = toggleSxComponent('div') as React.ComponentType< - React.PropsWithChildren< - ChildrenPropTypes & React.RefAttributes & React.HtmlHTMLAttributes - > -> const Actions: React.FC> = ({ children, className, @@ -453,7 +402,7 @@ const Actions: React.FC> = ({ const {height} = sxProp if (height) style['--custom-height'] = height return ( - > = ({ {...getHiddenDataAttributes(hidden)} > {children} - + ) } -const DescriptionBaseComponent = toggleSxComponent('div') as React.ComponentType< - React.PropsWithChildren> -> - // PageHeader.Description: The description area of the header. Visible on all viewports const Description: React.FC> = ({ children, @@ -477,13 +422,9 @@ const Description: React.FC> = ({ hidden = false, }) => { return ( - + {children} - + ) } @@ -493,10 +434,6 @@ export type NavigationProps = { 'aria-labelledby'?: React.AriaAttributes['aria-labelledby'] } & ChildrenPropTypes -const NavigationBaseComponent = toggleSxComponent('div') as React.ComponentType< - React.PropsWithChildren> -> - // PageHeader.Navigation: The local navigation area of the header. Visible on all viewports const Navigation: React.FC> = ({ children, @@ -513,7 +450,7 @@ const Navigation: React.FC> = ({ ) return ( - > = ({ {...getHiddenDataAttributes(hidden)} > {children} - + ) } diff --git a/packages/react/src/Popover/Popover.tsx b/packages/react/src/Popover/Popover.tsx index 53147dba303..259846d5ea8 100644 --- a/packages/react/src/Popover/Popover.tsx +++ b/packages/react/src/Popover/Popover.tsx @@ -3,7 +3,7 @@ import type {SxProp} from '../sx' import classes from './Popover.module.css' import type {HTMLProps} from 'react' import React from 'react' -import {toggleSxComponent} from '../internal/utils/toggleSxComponent' +import {BoxWithFallback} from '../internal/components/BoxWithFallback' type CaretPosition = | 'top' @@ -31,18 +31,16 @@ type StyledPopoverProps = { export type PopoverProps = { /** Class name for custom styling */ className?: string + as?: React.ElementType } & StyledPopoverProps & HTMLProps -const PopoverBaseComponent = toggleSxComponent('div') as React.ComponentType< - PopoverProps & React.RefAttributes -> const Popover = React.forwardRef(function Popover( {className, caret = 'top', open, relative, ...props}, forwardRef, ) { return ( - (function Popover( }) Popover.displayName = 'Popover' -export type PopoverContentProps = {className?: string} & StyledPopoverProps & HTMLProps +export type PopoverContentProps = {className?: string; as?: React.ElementType} & StyledPopoverProps & + HTMLProps -const PopoverContentBaseComponent = toggleSxComponent('div') as React.ComponentType const PopoverContent: React.FC> = ({className, ...props}) => { - return + return } PopoverContent.displayName = 'Popover.Content' diff --git a/packages/react/src/Text/Text.tsx b/packages/react/src/Text/Text.tsx index 50043559b51..26a9cd1f41f 100644 --- a/packages/react/src/Text/Text.tsx +++ b/packages/react/src/Text/Text.tsx @@ -5,7 +5,7 @@ import type {SystemCommonProps, SystemTypographyProps} from '../constants' import type {SxProp} from '../sx' import {useRefObjectAsForwardedRef} from '../hooks' import classes from './Text.module.css' -import {toggleSxComponent} from '../internal/utils/toggleSxComponent' +import {BoxWithFallback} from '../internal/components/BoxWithFallback' type StyledTextProps = { // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -17,13 +17,12 @@ type StyledTextProps = { SxProp & React.HTMLAttributes -const TextBaseComponent = toggleSxComponent('span') as React.ComponentType const Text = forwardRef(({as: Component = 'span', className, size, weight, ...props}, forwardedRef) => { const innerRef = React.useRef(null) useRefObjectAsForwardedRef(forwardedRef, innerRef) return ( - { } export const TooltipContext = React.createContext<{tooltipId?: string}>({}) -const BaseComponent = toggleSxComponent('span') as React.ComponentType< - SxProp & React.HTMLAttributes & React.RefAttributes -> - export const Tooltip = React.forwardRef( ( {direction = 's', text, type = 'description', children, id, className, keybindingHint, ...rest}: TooltipProps, @@ -302,7 +298,8 @@ export const Tooltip = React.forwardRef( child.props.onMouseLeave?.(event) }, })} - + ) diff --git a/packages/react/src/internal/utils/__tests__/toggleSxComponent.test.tsx b/packages/react/src/internal/utils/__tests__/toggleSxComponent.test.tsx deleted file mode 100644 index a0b732e46f9..00000000000 --- a/packages/react/src/internal/utils/__tests__/toggleSxComponent.test.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import {render} from '@testing-library/react' -import type React from 'react' -import {describe, expect, test} from 'vitest' -import {toggleSxComponent} from '../toggleSxComponent' - -const customSx = {color: 'red', p: 2} - -describe('toggleSxComponent', () => { - test('renders the plain component when no sx', () => { - const TestComponent = toggleSxComponent('span') - const {container} = render() - expect(container.firstChild).toBeInstanceOf(HTMLSpanElement) - }) - - test('renders Box with `as` if `sx` is provided', () => { - const TestComponent = toggleSxComponent('div') - const {container} = render() - - expect(container.firstChild).toBeInstanceOf(HTMLButtonElement) - expect(container.firstChild).toHaveStyle('color: rgb(255, 0, 0)') - }) - - test('swaps out component if `sx` is not the default', () => { - const Label = toggleSxComponent('label') as React.ComponentType<{htmlFor: string}> - const {container} = render(