Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
48181d7
chore(TextInput): remove sx
francinelucca Sep 30, 2025
75c5b50
Remove sx prop from TextInput component
francinelucca Sep 30, 2025
bc30458
Merge branch 'main' into chore/remove-sx-from-text-input
francinelucca Oct 1, 2025
3d10343
type fix
francinelucca Oct 1, 2025
607edd3
remove sx from TextInputWIthTokens
francinelucca Oct 1, 2025
a573acd
Merge branch 'main' into chore/remove-sx-from-text-input
francinelucca Oct 1, 2025
1b33c3d
remove unnecessary stories
francinelucca Oct 1, 2025
4b20d80
Merge branch 'chore/remove-sx-from-text-input' of github.com:primer/r…
francinelucca Oct 1, 2025
05785b5
remove sx prop from Textarea
francinelucca Oct 1, 2025
7f53ab9
fix exports
francinelucca Oct 1, 2025
07be57e
fix import
francinelucca Oct 1, 2025
beb0fb1
Merge branch 'main' of github.com:primer/react into chore/remove-sx-f…
francinelucca Oct 1, 2025
a251708
remove sx stories snapshots
francinelucca Oct 1, 2025
b55c591
use component name instead of component reference to associate FormCo…
francinelucca Oct 1, 2025
b03bc50
Revert "use component name instead of component reference to associat…
francinelucca Oct 1, 2025
c3f6d97
Merge branch 'main' into chore/remove-sx-from-text-input
francinelucca Oct 1, 2025
6cc3368
Merge branch 'main' into chore/remove-sx-from-text-input
francinelucca Oct 1, 2025
d98b6c6
Merge branch 'main' of github.com:primer/react into chore/remove-sx-f…
francinelucca Oct 1, 2025
861ffc8
memoize style
francinelucca Oct 1, 2025
55488c7
remove sx from TextInput.Action
francinelucca Oct 1, 2025
d52d8b7
update snapshot
francinelucca Oct 1, 2025
f09d16f
chore: remove sx prop import
francinelucca Oct 6, 2025
f81329e
TextInputWrapper: remove responsive value
francinelucca Oct 6, 2025
aab2106
Merge branch 'main' into chore/remove-sx-from-text-input
francinelucca Oct 6, 2025
f524327
styled-react select component
francinelucca Oct 6, 2025
8f0bdff
Merge branch 'chore/remove-sx-from-text-input' of github.com:primer/r…
francinelucca Oct 6, 2025
b249971
Merge branch 'main' of github.com:primer/react into chore/remove-sx-f…
francinelucca Oct 6, 2025
9418ca0
Merge branch 'main' into chore/remove-sx-from-text-input
francinelucca Oct 7, 2025
b3808a3
Merge branch 'main' into chore/remove-sx-from-text-input
francinelucca Oct 7, 2025
f5a18ab
use styled() wrappr in TextInput
francinelucca Oct 7, 2025
94bad6f
Merge branch 'main' into chore/remove-sx-from-text-input
francinelucca Oct 8, 2025
5dbabf9
use styled wrapper instead of Box in TextInputAction
francinelucca Oct 8, 2025
44d0471
Merge branch 'chore/remove-sx-from-text-input' of github.com:primer/r…
francinelucca Oct 8, 2025
b1732d1
Merge branch 'main' of github.com:primer/react into chore/remove-sx-f…
francinelucca Oct 11, 2025
3a0cb7a
Merge branch 'main' into chore/remove-sx-from-text-input
francinelucca Oct 11, 2025
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/spicy-items-watch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@primer/react": patch
"@primer/styled-react": patch
---

chore(TextInput): remove sx
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
36 changes: 0 additions & 36 deletions e2e/components/TextInput.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,24 +219,6 @@ test.describe('TextInput', () => {
}
})

test.describe('Dev: With Sx', () => {
for (const theme of themes) {
test.describe(theme, () => {
test('default @vrt', async ({page}) => {
await visit(page, {
id: 'components-textinput-dev--with-sx',
globals: {
colorScheme: theme,
},
})

// Default state
expect(await page.screenshot()).toMatchSnapshot(`TextInput.Dev.WithSx.${theme}.png`)
})
})
}
})

test.describe('Dev: With CSS', () => {
for (const theme of themes) {
test.describe(theme, () => {
Expand All @@ -254,22 +236,4 @@ test.describe('TextInput', () => {
})
}
})

test.describe('Dev: With Sx and CSS', () => {
for (const theme of themes) {
test.describe(theme, () => {
test('default @vrt', async ({page}) => {
await visit(page, {
id: 'components-textinput-dev--with-sx-and-css',
globals: {
colorScheme: theme,
},
})

// Default state
expect(await page.screenshot()).toMatchSnapshot(`TextInput.Dev.WithSxAndCSS.${theme}.png`)
})
})
}
})
})
18 changes: 0 additions & 18 deletions packages/react/src/TextInput/TextInput.dev.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,3 @@ export const WithCSS = () => (
</FormControl>
</form>
)

export const WithSx = () => (
<form>
<FormControl>
<FormControl.Label>Default label</FormControl.Label>
<TextInput sx={{borderColor: 'red'}} />
</FormControl>
</form>
)

export const WithSxAndCSS = () => (
<form>
<FormControl>
<FormControl.Label>Default label</FormControl.Label>
<TextInput sx={{borderColor: 'red'}} className="testCustomClassnameBorderColor" />
</FormControl>
</form>
)
3 changes: 0 additions & 3 deletions packages/react/src/TextInput/TextInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ export type TextInputNonPassthroughProps = {
| 'contrast'
| 'disabled'
| 'monospace'
| 'sx'
| 'width'
| 'maxWidth'
| 'minWidth'
Expand Down Expand Up @@ -75,7 +74,6 @@ const TextInput = React.forwardRef<HTMLInputElement, TextInputProps>(
loaderText = 'Loading',
monospace,
validationStatus,
sx: sxProp,
size: sizeProp,
onFocus,
onBlur,
Expand Down Expand Up @@ -137,7 +135,6 @@ const TextInput = React.forwardRef<HTMLInputElement, TextInputProps>(
contrast={contrast}
disabled={disabled}
monospace={monospace}
sx={sxProp}
size={sizeProp}
width={widthProp}
minWidth={minWidthProp}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ exports[`TextInput > renders trailingAction icon button 1`] = `
<button
aria-describedby=":r23:-loading-announcement"
aria-labelledby=":r22:"
class="sc-gEvEer dEeFcy prc-Button-ButtonBase-Eb8-K prc-components-Invisible-6q42n prc-Button-IconButton-GE6m6"
class="prc-Button-ButtonBase-Eb8-K prc-components-Invisible-6q42n prc-Button-IconButton-GE6m6"
data-component="IconButton"
data-loading="false"
data-no-visuals="true"
Expand Down Expand Up @@ -352,15 +352,16 @@ exports[`TextInput > renders trailingAction text button 1`] = `
>
<button
aria-describedby=":r1p:-loading-announcement"
class="sc-gEvEer dEeFcy prc-Button-ButtonBase-Eb8-K prc-components-Invisible-6q42n"
class="prc-Button-ButtonBase-Eb8-K prc-components-Invisible-6q42n"
data-loading="false"
data-no-visuals="true"
data-size="medium"
data-variant="invisible"
type="button"
>
<span
class="sc-gEvEer bLWYQi prc-Button-ButtonContent-KZ5Bz"
class="prc-Button-ButtonContent-KZ5Bz"
data-align="center"
data-component="buttonContent"
>
<span
Expand Down Expand Up @@ -395,15 +396,16 @@ exports[`TextInput > renders trailingAction text button with a tooltip 1`] = `
>
<button
aria-describedby=":r1u:-loading-announcement :r1t:"
class="sc-gEvEer dEeFcy prc-Button-ButtonBase-Eb8-K prc-components-Invisible-6q42n"
class="prc-Button-ButtonBase-Eb8-K prc-components-Invisible-6q42n"
data-loading="false"
data-no-visuals="true"
data-size="medium"
data-variant="invisible"
type="button"
>
<span
class="sc-gEvEer bLWYQi prc-Button-ButtonContent-KZ5Bz"
class="prc-Button-ButtonContent-KZ5Bz"
data-align="center"
data-component="buttonContent"
>
<span
Expand Down
1 change: 1 addition & 0 deletions packages/react/src/TextInput/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export {default} from './TextInput'
export type {TextInputProps, TextInputNonPassthroughProps} from './TextInput'
export type {TextInputActionProps} from '../internal/components/TextInputInnerAction'
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ function TextInputWithTokensInnerComponent<TokenComponentType extends AnyReactCo
className,
block,
disabled,
sx: sxProp,
tokens,
onTokenRemove,
tokenComponent: TokenComponent = Token,
Expand Down Expand Up @@ -273,7 +272,6 @@ function TextInputWithTokensInnerComponent<TokenComponentType extends AnyReactCo
data-token-wrapping={Boolean(preventTokenWrapping || maxHeight) || undefined}
className={clsx(className, styles.TextInputWrapper)}
style={maxHeight ? {maxHeight, ...style} : style}
sx={sxProp}
>
{IconComponent && !LeadingVisual && <IconComponent className="TextInput-icon" />}
<TextInputInnerVisualSlot
Expand Down
6 changes: 1 addition & 5 deletions packages/react/src/Textarea/Textarea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import type {TextareaHTMLAttributes, ReactElement} from 'react'
import React from 'react'
import {TextInputBaseWrapper} from '../internal/components/TextInputWrapper'
import type {FormValidationStatus} from '../utils/types/FormValidationStatus'
import type {SxProp} from '../sx'
import classes from './TextArea.module.css'
import type {WithSlotMarker} from '../utils/types'

Expand Down Expand Up @@ -47,8 +46,7 @@ export type TextareaProps = {
* CSS styles to apply to the Textarea
*/
style?: React.CSSProperties
} & TextareaHTMLAttributes<HTMLTextAreaElement> &
SxProp
} & TextareaHTMLAttributes<HTMLTextAreaElement>

/**
* An accessible, native textarea component that supports validation states.
Expand All @@ -59,7 +57,6 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
{
value,
disabled,
sx: sxProp,
required,
validationStatus,
rows = DEFAULT_TEXTAREA_ROWS,
Expand All @@ -77,7 +74,6 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
): ReactElement => {
return (
<TextInputBaseWrapper
sx={sxProp}
validationStatus={validationStatus}
disabled={disabled}
block={block}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ exports[`@primer/react > should not update exports without a semver change 1`] =
"Textarea",
"type TextareaProps",
"TextInput",
"type TextInputActionProps",
"type TextInputProps",
"TextInputWithTokens",
"type TextInputWithTokensProps",
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ export type {SubNavProps, SubNavLinkProps, SubNavLinksProps} from './SubNav'
export {default as ToggleSwitch} from './ToggleSwitch'
export type {ToggleSwitchProps} from './ToggleSwitch'
export {default as TextInput} from './TextInput'
export type {TextInputProps} from './TextInput'
export type {TextInputProps, TextInputActionProps} from './TextInput'
export {default as TextInputWithTokens} from './TextInputWithTokens'
export type {TextInputWithTokensProps} from './TextInputWithTokens'
export {default as Text} from './Text'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@ import type {IconProps} from '@primer/octicons-react'
import {Button, IconButton} from '../../Button'
import {Tooltip} from '../../TooltipV2'
import type {ButtonProps} from '../../Button'
import type {SxProp} from '../../sx'
import {clsx} from 'clsx'

import styles from './TextInputInnerAction.module.css'

type TextInputActionProps = Omit<
export type TextInputActionProps = Omit<
React.ButtonHTMLAttributes<HTMLButtonElement>,
'aria-label' | 'size' | 'tooltipDirection'
> & {
Expand All @@ -26,7 +25,7 @@ type TextInputActionProps = Omit<
* Determine's the styles on a button one of 'default' | 'primary' | 'invisible' | 'danger'
*/
variant?: ButtonProps['variant']
} & SxProp
}

const ConditionalTooltip: React.FC<
React.PropsWithChildren<{
Expand Down Expand Up @@ -54,14 +53,13 @@ const TextInputAction = forwardRef<HTMLButtonElement, TextInputActionProps>(
tooltipDirection,
children,
icon,
sx: sxProp,
className,
variant = 'invisible',
...rest
},
forwardedRef,
) => {
const styleProps = {className: clsx(variant === 'invisible' && styles.Invisible, className), sx: sxProp || {}}
const styleProps = {className: clsx(variant === 'invisible' && styles.Invisible, className)}

if ((icon && !ariaLabel) || (!children && !ariaLabel)) {
// eslint-disable-next-line no-console
Expand Down
18 changes: 12 additions & 6 deletions packages/react/src/internal/components/TextInputWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import React, {type ComponentProps} from 'react'
import type {SxProp} from '../../sx'
import type {FormValidationStatus} from '../../utils/types/FormValidationStatus'
import {clsx} from 'clsx'

import styles from './TextInputWrapper.module.css'
import {BoxWithFallback} from './BoxWithFallback'

export type TextInputSizes = 'small' | 'medium' | 'large'

Expand All @@ -29,7 +27,7 @@ type StyledTextInputBaseWrapperProps = {
minWidth?: string | number
/** @deprecated Update `max-width` using CSS modules or style. */
maxWidth?: string | number
} & SxProp
}

type StyledTextInputWrapperProps = {
hasLeadingVisual?: boolean
Expand Down Expand Up @@ -57,9 +55,17 @@ export const TextInputBaseWrapper = React.forwardRef<HTMLElement, StyledTextInpu
},
forwardRef,
) {
const memoizedStyle = React.useMemo(() => {
return {
...(width ? {width} : {}),
...(minWidth ? {minWidth} : {}),
...(maxWidth ? {maxWidth} : {}),
...style,
}
}, [width, minWidth, maxWidth, style])

return (
<BoxWithFallback
as="span"
<span
ref={forwardRef}
className={clsx(className, styles.TextInputBaseWrapper)}
data-block={block || undefined}
Expand All @@ -71,7 +77,7 @@ export const TextInputBaseWrapper = React.forwardRef<HTMLElement, StyledTextInpu
data-trailing-action={hasTrailingAction || undefined}
data-validation={validationStatus || undefined}
data-variant={variant || undefined}
style={width || minWidth || maxWidth ? {width, maxWidth, minWidth, ...style} : style}
style={memoizedStyle}
{...restProps}
/>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,7 @@ describe('@primer/react', () => {
expect(window.getComputedStyle(container.firstElementChild!).backgroundColor).toBe('rgb(255, 0, 0)')
})

test.skip('Select supports `sx` prop', () => {
test('Select supports `sx` prop', () => {
render(<Select as="select" data-testid="component" sx={{background: 'red'}} required />)
expect(window.getComputedStyle(screen.getByTestId('component')).backgroundColor).toBe('rgb(255, 0, 0)')
expect(screen.getByTestId('component')).toHaveAttribute('required')
Expand Down
13 changes: 11 additions & 2 deletions packages/styled-react/src/components/Autocomplete.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
Autocomplete as PrimerAutocomplete,
type AutocompleteOverlayProps as PrimerAutocompleteOverlayProps,
type AutocompleteInputProps as PrimerAutocompleteInputProps,
type SlotMarker,
} from '@primer/react'
import {sx, type SxProp} from '../sx'
Expand All @@ -17,17 +18,25 @@ const AutocompleteOverlay: React.ComponentType<AutocompleteOverlayProps> & SlotM
${sx}
`

export type AutocompleteInputProps = PrimerAutocompleteInputProps & SxProp

const AutocompleteInput: React.ComponentType<AutocompleteInputProps> = styled(PrimerAutocomplete.Input).withConfig({
shouldForwardProp: prop => (prop as keyof AutocompleteInputProps) !== 'sx',
})<AutocompleteInputProps>`
${sx}
`

interface AutocompleteExport {
(props: ComponentProps<typeof PrimerAutocomplete>): React.ReactNode
Context: typeof PrimerAutocomplete.Context
Input: typeof PrimerAutocomplete.Input
Input: typeof AutocompleteInput
Menu: typeof PrimerAutocomplete.Menu
Overlay: typeof AutocompleteOverlay
}

const Autocomplete: AutocompleteExport = Object.assign(PrimerAutocomplete, {
Context: PrimerAutocomplete.Context,
Input: PrimerAutocomplete.Input,
Input: AutocompleteInput,
Menu: PrimerAutocomplete.Menu,
Overlay: AutocompleteOverlay,
})
Expand Down
17 changes: 17 additions & 0 deletions packages/styled-react/src/components/Select.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import {Select as PrimerSelect, type SelectProps as PrimerSelectProps} from '@primer/react'
import {sx, type SxProp} from '../sx'
import type {ForwardRefComponent} from '../polymorphic'
import styled from 'styled-components'

type SelectProps = PrimerSelectProps & SxProp & {as?: React.ElementType}

const StyledSelect: ForwardRefComponent<'select', SelectProps> = styled(PrimerSelect).withConfig({
shouldForwardProp: prop => (prop as keyof SelectProps) !== 'sx',
})<SelectProps>`
${sx}
`
const Select = ({as, ...props}: SelectProps) => {
return <StyledSelect {...props} {...(as ? {forwardedAs: as as React.ElementType} : {})} />
}

export {Select, type SelectProps}
Loading
Loading