Skip to content
Merged
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
5 changes: 5 additions & 0 deletions .changeset/cuddly-rice-march.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
---
'@primer/components': major
---

Removed system props support from `<TextInput>` and fixed its type definition.
12 changes: 1 addition & 11 deletions docs/content/TextInput.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,21 +11,11 @@ TextInput is a form component to add default styling to the native text input.
```jsx live
<TextInput aria-label="Zipcode" name="zipcode" placeholder="Zipcode" autoComplete="postal-code" />

<TextInput sx={{ml: 4}} aria-label="City" name="city" placeholder="City" contrast />
<TextInput sx={{ml: 4}} aria-label="City" name="city" placeholder="City" contrast />

<TextInput sx={{ml: 4}} icon={SearchIcon} aria-label="Zipcode" name="zipcode" placeholder="Find user" autoComplete="postal-code" />
```

## System props

<Note variant="warning">

System props are deprecated in all components except [Box](/Box). Please use the [`sx` prop](/overriding-styles) instead.

</Note>

TextInput components get `COMMON` system props. Read our [System Props](/system-props) doc page for a full list of available props.

## Component props

Native `<input>` attributes are forwarded to the underlying React `input` component and are not listed below.
Expand Down
56 changes: 38 additions & 18 deletions src/TextInput.tsx
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
import {omit, pick} from '@styled-system/props'
import classnames from 'classnames'
import React from 'react'
import styled, {css} from 'styled-components'
import {maxWidth, MaxWidthProps, minWidth, MinWidthProps, variant, width, WidthProps} from 'styled-system'
import {COMMON, get, SystemCommonProps} from './constants'
import {get} from './constants'
import sx, {SxProp} from './sx'
import {ComponentProps} from './utils/types'

Expand DownExpand Up@@ -43,8 +42,7 @@ type StyledWrapperProps = {
block?: boolean
contrast?: boolean
variant?: 'small' | 'large'
} & SystemCommonProps &
WidthProps &
} & WidthProps &
MinWidthProps &
MaxWidthProps &
SxProp
Expand DownExpand Up@@ -113,38 +111,60 @@ const Wrapper = styled.span<StyledWrapperProps>`
@media (min-width: ${get('breakpoints.1')}) {
font-size: ${get('fontSizes.1')};
}
${COMMON}
${width}
${minWidth}
${maxWidth}
${sizeVariants}
${sx};
`

type TextInputInternalProps = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
as?: any // This is a band-aid fix until we have better type support for the `as` prop
// Props that are not passed through to Input:
type NonPassthroughProps = {
className?: string
icon?: React.ComponentType<{className?: string}>
} & ComponentProps<typeof Wrapper> &
ComponentProps<typeof Input>
} & Pick<
ComponentProps<typeof Wrapper>,
'block' | 'contrast' | 'disabled' | 'sx' | 'theme' | 'width' | 'maxWidth' | 'minWidth' | 'variant'
>

type TextInputInternalProps = NonPassthroughProps &
// Note: using ComponentProps instead of ComponentPropsWithoutRef here would cause a type issue where `css` is a required prop.
Omit<React.ComponentPropsWithoutRef<typeof Input>, keyof NonPassthroughProps>

// using forwardRef is important so that other components (ex. SelectMenu) can autofocus the input
const TextInput = React.forwardRef<HTMLInputElement, TextInputInternalProps>(
({icon: IconComponent, contrast, className, block, disabled, theme, sx: sxProp, ...rest}, ref) => {
(
{
icon: IconComponent,
block,
className,
contrast,
disabled,
sx: sxProp,
theme,
width: widthProp,
minWidth: minWidthProp,
maxWidth: maxWidthProp,
variant: variantProp,
...inputProps
},
ref
) => {
// this class is necessary to style FilterSearch, plz no touchy!
const wrapperClasses = classnames(className, 'TextInput-wrapper')
const wrapperProps = pick(rest)
const inputProps = omit(rest)
return (
<Wrapper
className={wrapperClasses}
hasIcon={!!IconComponent}
block={block}
theme={theme}
disabled={disabled}
className={wrapperClasses}
contrast={contrast}
disabled={disabled}
hasIcon={!!IconComponent}
sx={sxProp}
{...wrapperProps}
theme={theme}
width={widthProp}
minWidth={minWidthProp}
maxWidth={maxWidthProp}
variant={variantProp}
>
{IconComponent && <IconComponent className="TextInput-icon" />}
<Input ref={ref} disabled={disabled} {...inputProps} />
Expand Down
2 changes: 1 addition & 1 deletion src/stories/DropdownMenu.stories.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -36,7 +36,7 @@ export function FavoriteColorStory(): JSX.Element {
return (
<>
<h1>Favorite Color</h1>
<TextInput placeholder="Input for focus testing" mb={2} />
<TextInput placeholder="Input for focus testing" sx={{mb: 2}} />
<div id="favorite-color-label">Please select your favorite color:</div>
<DropdownMenu
renderAnchor={({children, 'aria-labelledby': ariaLabelledBy, ...anchorProps}) => (
Expand Down