Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/cyan-panthers-shop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@primer/react": patch
"@primer/styled-react": patch
---

chore: remove unnecessary sx prop migrations
5 changes: 4 additions & 1 deletion packages/react/src/FormControl/FormControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,11 @@ export type FormControlProps = {
*/
layout?: 'horizontal' | 'vertical'
className?: string
style?: React.CSSProperties
}

const FormControl = React.forwardRef<HTMLDivElement, FormControlProps>(
({children, disabled: disabledProp, layout = 'vertical', id: idProp, required, className}, ref) => {
({children, disabled: disabledProp, layout = 'vertical', id: idProp, required, className, style}, ref) => {
const [slots, childrenWithoutSlots] = useSlots(children, {
caption: FormControlCaption,
label: FormControlLabel,
Expand Down Expand Up @@ -170,6 +171,7 @@ const FormControl = React.forwardRef<HTMLDivElement, FormControlProps>(
ref={ref}
data-has-leading-visual={slots.leadingVisual ? '' : undefined}
className={clsx(className, classes.ControlHorizontalLayout)}
style={style}
>
{InputChildren}
</div>
Expand All @@ -178,6 +180,7 @@ const FormControl = React.forwardRef<HTMLDivElement, FormControlProps>(
ref={ref}
data-has-label={!isLabelHidden ? '' : undefined}
className={clsx(className, classes.ControlVerticalLayout)}
style={style}
>
{slots.label}
{React.isValidElement(InputComponent) &&
Expand Down
4 changes: 3 additions & 1 deletion packages/react/src/FormControl/FormControlCaption.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,18 @@ import {useFormControlContext} from './_FormControlContext'
export type FormControlCaptionProps = React.PropsWithChildren<{
id?: string
className?: string
style?: React.CSSProperties
}>

function FormControlCaption({id, children, className}: FormControlCaptionProps) {
function FormControlCaption({id, children, className, style}: FormControlCaptionProps) {
const {captionId, disabled} = useFormControlContext()

return (
<Text
id={id ?? captionId}
className={clsx(className, classes.Caption)}
data-control-disabled={disabled ? '' : undefined}
style={style}
>
{children}
</Text>
Expand Down
16 changes: 15 additions & 1 deletion packages/react/src/FormControl/FormControlLabel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,23 @@ export type Props = {
requiredIndicator?: boolean
id?: string
className?: string
style?: React.CSSProperties
}

const FormControlLabel: React.FC<
React.PropsWithChildren<{htmlFor?: string} & React.ComponentProps<typeof InputLabel> & Props>
> = ({as, children, htmlFor, id, visuallyHidden, requiredIndicator = true, requiredText, className, ...props}) => {
> = ({
as,
children,
htmlFor,
id,
visuallyHidden,
requiredIndicator = true,
requiredText,
className,
style,
...props
}) => {
const {disabled, id: formControlId, required} = useFormControlContext()

/**
Expand All @@ -27,6 +39,7 @@ const FormControlLabel: React.FC<
as,
id,
className,
style,
visuallyHidden,
required,
requiredText,
Expand All @@ -38,6 +51,7 @@ const FormControlLabel: React.FC<
as,
id,
className,
style,
visuallyHidden,
htmlFor: htmlFor || formControlId,
required,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import type React from 'react'
import {useFormControlContext} from './_FormControlContext'
import classes from './FormControlLeadingVisual.module.css'
import type {HTMLAttributes} from 'react'

const FormControlLeadingVisual: React.FC<React.PropsWithChildren> = ({children}) => {
const FormControlLeadingVisual: React.FC<React.PropsWithChildren> & HTMLAttributes<HTMLDivElement> = ({
children,
...props
}) => {
const {disabled, captionId} = useFormControlContext()
return (
<div
className={classes.LeadingVisual}
data-control-disabled={disabled ? '' : undefined}
data-has-caption={captionId ? '' : undefined}
{...props}
>
{children}
</div>
Expand Down
13 changes: 9 additions & 4 deletions packages/react/src/FormControl/_FormControlValidation.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,30 @@
import type React from 'react'
import InputValidation from '../internal/components/InputValidation'
import type {SxProp} from '../sx'
import type {FormValidationStatus} from '../utils/types/FormValidationStatus'
import {useFormControlContext} from './_FormControlContext'

export type FormControlValidationProps = {
variant: FormValidationStatus
id?: string
className?: string
} & SxProp
style?: React.CSSProperties
}

const FormControlValidation: React.FC<React.PropsWithChildren<FormControlValidationProps>> = ({
children,
className,
variant,
sx,
id,
style,
}) => {
const {validationMessageId} = useFormControlContext()
return (
<InputValidation className={className} validationStatus={variant} id={id || validationMessageId || ''} sx={sx}>
<InputValidation
className={className}
validationStatus={variant}
id={id || validationMessageId || ''}
style={style}
>
{children}
</InputValidation>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
import React from 'react'
import InputValidation from '../InputValidation'
import type {SxProp} from '../../../sx'
import type {FormValidationStatus} from '../../../utils/types/FormValidationStatus'
import CheckboxOrRadioGroupContext from './CheckboxOrRadioGroupContext'

export type CheckboxOrRadioGroupValidationProps = {
/** Changes the visual style to match the validation status */
variant: FormValidationStatus
} & SxProp
}

const CheckboxOrRadioGroupValidation: React.FC<React.PropsWithChildren<CheckboxOrRadioGroupValidationProps>> = ({
children,
variant,
sx,
}) => {
const {validationMessageId = ''} = React.useContext(CheckboxOrRadioGroupContext)
return (
<InputValidation validationStatus={variant} id={validationMessageId} sx={sx}>
<InputValidation validationStatus={variant} id={validationMessageId}>
{children}
</InputValidation>
)
Expand Down
8 changes: 4 additions & 4 deletions packages/react/src/internal/components/InputLabel.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import {clsx} from 'clsx'
import type React from 'react'
import {type SxProp} from '../../sx'
import classes from './InputLabel.module.css'
import {BoxWithFallback} from './BoxWithFallback'

type BaseProps = SxProp & {
type BaseProps = {
disabled?: boolean
required?: boolean
requiredText?: string
requiredIndicator?: boolean
visuallyHidden?: boolean
id?: string
className?: string
style?: React.CSSProperties
}

export type LabelProps = BaseProps & {
Expand All @@ -35,16 +35,16 @@ function InputLabel({
requiredText,
requiredIndicator,
visuallyHidden,
sx,
as = 'label',
className,
style,
...props
}: Props) {
return (
// @ts-ignore weird typing issue with union for `as` prop
<BoxWithFallback
as={as}
sx={sx}
style={style}
data-control-disabled={disabled ? '' : undefined}
data-visually-hidden={visuallyHidden ? '' : undefined}
htmlFor={htmlFor}
Expand Down
18 changes: 14 additions & 4 deletions packages/react/src/internal/components/InputValidation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import type {IconProps} from '@primer/octicons-react'
import {AlertFillIcon, CheckCircleFillIcon} from '@primer/octicons-react'
import type React from 'react'
import Text from '../../Text'
import type {SxProp} from '../../sx'
import type {FormValidationStatus} from '../../utils/types/FormValidationStatus'
import classes from './InputValidation.module.css'
import {clsx} from 'clsx'
Expand All @@ -11,7 +10,8 @@ type Props = {
className?: string
id: string
validationStatus?: FormValidationStatus
} & SxProp
style?: React.CSSProperties
}

const validationIconMap: Record<
NonNullable<Props['validationStatus']>,
Expand All @@ -21,7 +21,13 @@ const validationIconMap: Record<
error: AlertFillIcon,
}

const InputValidation: React.FC<React.PropsWithChildren<Props>> = ({children, className, id, validationStatus}) => {
const InputValidation: React.FC<React.PropsWithChildren<Props>> = ({
children,
className,
id,
validationStatus,
style: inlineStyle,
}) => {
const IconComponent = validationStatus ? validationIconMap[validationStatus] : undefined

// TODO: use `text-caption-lineHeight` token as a custom property when it's available
Expand All @@ -31,7 +37,11 @@ const InputValidation: React.FC<React.PropsWithChildren<Props>> = ({children, cl
const iconBoxMinHeight = iconSize * captionLineHeight

return (
<Text className={clsx(className, classes.InputValidation)} data-validation-status={validationStatus}>
<Text
className={clsx(className, classes.InputValidation)}
data-validation-status={validationStatus}
style={inlineStyle}
>
{IconComponent ? (
<span
aria-hidden="true"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -346,11 +346,6 @@ describe('@primer/react', () => {
expect(window.getComputedStyle(container.firstElementChild!).backgroundColor).toBe('rgb(255, 0, 0)')
})

test('PageLayout.Header supports `sx` prop', () => {
const {container} = render(<PageLayout.Header data-testid="component" sx={{background: 'red'}} />)
expect(window.getComputedStyle(container.firstElementChild!).backgroundColor).toBe('rgb(255, 0, 0)')
})

test('PageLayout.Content supports `sx` prop', () => {
const {container} = render(
<PageLayout.Content as="section" data-testid="component" sx={{background: 'red'}} aria-labelledby="normal" />,
Expand All @@ -361,16 +356,6 @@ describe('@primer/react', () => {
expect(outerElement).toHaveAttribute('aria-labelledby', 'normal')
})

test('PageLayout.Pane supports `sx` prop', () => {
const {container} = render(<PageLayout.Pane data-testid="component" sx={{background: 'red'}} />)
expect(window.getComputedStyle(container.firstElementChild!).backgroundColor).toBe('rgb(255, 0, 0)')
})

test('PageLayout.Footer supports `sx` prop', () => {
const {container} = render(<PageLayout.Footer data-testid="component" sx={{background: 'red'}} />)
expect(window.getComputedStyle(container.firstElementChild!).backgroundColor).toBe('rgb(255, 0, 0)')
})

test('RadioGroup supports `sx` prop', () => {
const {container} = render(
<RadioGroup data-testid="component" name="test" sx={{background: 'red'}}>
Expand Down
29 changes: 6 additions & 23 deletions packages/styled-react/src/components/FormControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import {
Box,
FormControl as PrimerFormControl,
type FormControlProps as PrimerFormControlProps,
type FormControlCaptionProps as PrimerFormControlCaptionProps,
type FormControlValidationProps as PrimerFormControlValidationProps,
type SxProp,
} from '@primer/react'
import {forwardRef, type PropsWithChildren} from 'react'
Expand All @@ -14,30 +12,15 @@ const FormControlImpl = forwardRef<HTMLDivElement, FormControlProps>(function Fo
return <Box ref={ref} as={PrimerFormControl} {...props} />
})

type FormControlCaptionProps = PropsWithChildren<PrimerFormControlCaptionProps> & SxProp
const FormControlCaption = (props: FormControlCaptionProps) => {
return <Box as={PrimerFormControl.Caption} {...props} />
}

type FormControlValidationProps = PropsWithChildren<PrimerFormControlValidationProps> & SxProp

const FormControlValidation = (props: FormControlValidationProps) => {
return <Box as={PrimerFormControl.Validation} {...props} />
}

const FormControlLeadingVisual = (props: PropsWithChildren<SxProp>) => {
return <Box as={PrimerFormControl.LeadingVisual} {...props} />
}

const FormControl = Object.assign(FormControlImpl, {
Caption: FormControlCaption,
LeadingVisual: FormControlLeadingVisual,
Validation: FormControlValidation,
Caption: PrimerFormControl.Caption,
LeadingVisual: PrimerFormControl.LeadingVisual,
Validation: PrimerFormControl.Validation,
Label: PrimerFormControl.Label,
}) as typeof FormControlImpl & {
Caption: typeof FormControlCaption
LeadingVisual: typeof FormControlLeadingVisual
Validation: typeof FormControlValidation
Caption: typeof PrimerFormControl.Caption
LeadingVisual: typeof PrimerFormControl.LeadingVisual
Validation: typeof PrimerFormControl.Validation
Label: typeof PrimerFormControl.Label
}

Expand Down
20 changes: 2 additions & 18 deletions packages/styled-react/src/components/PageLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ import styled from 'styled-components'
import type {
PageLayoutProps as PrimerPageLayoutProps,
PageLayoutContentProps as PrimerPageLayoutContentProps,
PageLayoutHeaderProps as PrimerPageLayoutHeaderProps,
PageLayoutPaneProps as PrimerPageLayoutPaneProps,
PageLayoutFooterProps as PrimerPageLayoutFooterProps,
} from '@primer/react'
import {PageLayout as PrimerPageLayout} from '@primer/react'
import {sx, type SxProp} from '../sx'
Expand All @@ -27,31 +25,17 @@ const PageLayoutContent = React.forwardRef<HTMLDivElement, PageLayoutContentProp
return <Wrapper as={PrimerPageLayout.Content} ref={ref} {...props} />
})

type PageLayoutHeaderProps = PropsWithChildren<PrimerPageLayoutHeaderProps> & SxProp

const PageLayoutHeader = React.forwardRef<HTMLDivElement, PageLayoutHeaderProps>((props, ref) => {
// @ts-expect-error - PrimerPageLayout.Header is not recognized as a valid component type
return <Wrapper as={PrimerPageLayout.Header} ref={ref} {...props} />
})

type PageLayoutPaneProps = PropsWithChildren<PrimerPageLayoutPaneProps> & SxProp

const PageLayoutPane = React.forwardRef<HTMLDivElement, PageLayoutPaneProps>((props, ref) => {
return <Wrapper as={PrimerPageLayout.Pane} ref={ref} {...props} />
})

type PageLayoutFooterProps = PropsWithChildren<PrimerPageLayoutFooterProps> & SxProp

const PageLayoutFooter = React.forwardRef<HTMLDivElement, PageLayoutFooterProps>((props, ref) => {
// @ts-expect-error - PrimerPageLayout.Footer is not recognized as a valid component type
return <Wrapper as={PrimerPageLayout.Footer} ref={ref} {...props} />
})

const PageLayout = Object.assign(PageLayoutImpl, {
Content: PageLayoutContent,
Header: PageLayoutHeader,
Header: PrimerPageLayout.Header,
Pane: PageLayoutPane,
Footer: PageLayoutFooter,
Footer: PrimerPageLayout.Footer,
})

export {PageLayout, type PageLayoutProps}
Loading