diff --git a/.changeset/silly-parks-give.md b/.changeset/silly-parks-give.md new file mode 100644 index 00000000000..aaf865164d0 --- /dev/null +++ b/.changeset/silly-parks-give.md @@ -0,0 +1,5 @@ +--- +'@primer/react': patch +--- + +Adds `sx` prop back to TextInput diff --git a/e2e/components/TextInput.test.ts b/e2e/components/TextInput.test.ts index 114854866b2..fceb98ca879 100644 --- a/e2e/components/TextInput.test.ts +++ b/e2e/components/TextInput.test.ts @@ -219,6 +219,24 @@ 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, () => { @@ -236,4 +254,22 @@ 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`) + }) + }) + } + }) }) diff --git a/packages/react/src/SelectPanel/SelectPanel.module.css b/packages/react/src/SelectPanel/SelectPanel.module.css index 28fc342bfa7..3a999ad1a60 100644 --- a/packages/react/src/SelectPanel/SelectPanel.module.css +++ b/packages/react/src/SelectPanel/SelectPanel.module.css @@ -52,11 +52,6 @@ color: var(--fgColor-muted); } -.FilterInputWrapper { - margin: var(--base-size-8); - width: auto; -} - .Notice { margin-top: var(--base-size-4); margin-right: var(--base-size-8); @@ -235,3 +230,7 @@ inset: 0; background-color: var(--overlay-backdrop-bgColor); } + +.TextInput { + margin: var(--base-size-8); +} diff --git a/packages/react/src/SelectPanel/SelectPanel.tsx b/packages/react/src/SelectPanel/SelectPanel.tsx index c4457c787ee..4c7dae093d9 100644 --- a/packages/react/src/SelectPanel/SelectPanel.tsx +++ b/packages/react/src/SelectPanel/SelectPanel.tsx @@ -648,7 +648,7 @@ function Panel({ const extendedTextInputProps: Partial = useMemo(() => { return { - className: classes.FilterInputWrapper, + className: classes.TextInput, contrast: true, leadingVisual: SearchIcon, 'aria-label': inputLabel, diff --git a/packages/react/src/TextInput/TextInput.dev.stories.tsx b/packages/react/src/TextInput/TextInput.dev.stories.tsx index ebcf5fc62cd..356f21970c3 100644 --- a/packages/react/src/TextInput/TextInput.dev.stories.tsx +++ b/packages/react/src/TextInput/TextInput.dev.stories.tsx @@ -18,3 +18,21 @@ export const WithCSS = () => ( ) + +export const WithSx = () => ( +
+ + Default label + + +
+) + +export const WithSxAndCSS = () => ( +
+ + Default label + + +
+) diff --git a/packages/react/src/TextInput/TextInput.docs.json b/packages/react/src/TextInput/TextInput.docs.json index 2360d1590dc..66de3f3ac0a 100644 --- a/packages/react/src/TextInput/TextInput.docs.json +++ b/packages/react/src/TextInput/TextInput.docs.json @@ -140,6 +140,27 @@ "deprecated": true, "description": "(Use size) Creates a smaller or larger input than the default." }, + { + "name": "width", + "type": "string | number | Array", + "defaultValue": "", + "deprecated": true, + "description": "(Use sx prop) Set the width of the input" + }, + { + "name": "maxWidth", + "type": "string | number | Array", + "defaultValue": "", + "deprecated": true, + "description": "(Use sx prop) Set the maximum width of the input" + }, + { + "name": "minWidth", + "type": "string | number | Array", + "defaultValue": "", + "deprecated": true, + "description": "(Use sx prop) Set the minimum width of the input" + }, { "name": "icon", "type": "React.ComponentType", diff --git a/packages/react/src/TextInput/TextInput.tsx b/packages/react/src/TextInput/TextInput.tsx index 2aa6c615451..9062b461411 100644 --- a/packages/react/src/TextInput/TextInput.tsx +++ b/packages/react/src/TextInput/TextInput.tsx @@ -40,7 +40,20 @@ export type TextInputNonPassthroughProps = { */ trailingAction?: React.ReactElement> } & Partial< - Pick + Pick< + StyledWrapperProps, + | 'block' + | 'contrast' + | 'disabled' + | 'monospace' + | 'sx' + | 'width' + | 'maxWidth' + | 'minWidth' + | 'variant' + | 'size' + | 'validationStatus' + > > export type TextInputProps = Merge, TextInputNonPassthroughProps> @@ -62,10 +75,14 @@ const TextInput = React.forwardRef( loaderText = 'Loading', monospace, validationStatus, + sx: sxProp, size: sizeProp, onFocus, onBlur, // start deprecated props + width: widthProp, + minWidth: minWidthProp, + maxWidth: maxWidthProp, variant: variantProp, // end deprecated props type = 'text', @@ -120,7 +137,11 @@ const TextInput = React.forwardRef( contrast={contrast} disabled={disabled} monospace={monospace} + sx={sxProp} size={sizeProp} + width={widthProp} + minWidth={minWidthProp} + maxWidth={maxWidthProp} variant={variantProp} hasLeadingVisual={Boolean(LeadingVisual || showLeadingLoadingIndicator)} hasTrailingVisual={Boolean(TrailingVisual || showTrailingLoadingIndicator)} diff --git a/packages/react/src/TextInputWithTokens/TextInputWithTokens.tsx b/packages/react/src/TextInputWithTokens/TextInputWithTokens.tsx index c5786604548..a0f3b0a2954 100644 --- a/packages/react/src/TextInputWithTokens/TextInputWithTokens.tsx +++ b/packages/react/src/TextInputWithTokens/TextInputWithTokens.tsx @@ -83,6 +83,7 @@ function TextInputWithTokensInnerComponent {IconComponent && !LeadingVisual && } +} & TextareaHTMLAttributes & + SxProp /** * An accessible, native textarea component that supports validation states. @@ -56,6 +58,7 @@ const Textarea = React.forwardRef( { value, disabled, + sx: sxProp, required, validationStatus, rows = DEFAULT_TEXTAREA_ROWS, @@ -73,6 +76,7 @@ const Textarea = React.forwardRef( ): ReactElement => { return ( + /** @deprecated Update `min-width` using CSS modules or style. */ + minWidth?: string | number | ResponsiveValue + /** @deprecated Update `max-width` using CSS modules or style. */ + maxWidth?: string | number | ResponsiveValue +} & SxProp type StyledTextInputWrapperProps = { hasLeadingVisual?: boolean @@ -33,6 +41,7 @@ export const TextInputBaseWrapper = React.forwardRef ) diff --git a/packages/styled-react/src/components/Autocomplete.tsx b/packages/styled-react/src/components/Autocomplete.tsx deleted file mode 100644 index a27a2715589..00000000000 --- a/packages/styled-react/src/components/Autocomplete.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { - Autocomplete as PrimerAutocomplete, - type AutocompleteInputProps as PrimerAutocompleteInputProps, - Box, -} from '@primer/react' -import {forwardRef, type PropsWithChildren} from 'react' -import type {SxProp} from '../sx' - -type AutocompleteProps = PropsWithChildren[0]> & SxProp - -const AutocompleteImpl = forwardRef(function Autocomplete(props, ref) { - return -}) - -type AutocompleteInputProps = PropsWithChildren & SxProp - -const AutocompleteInput = forwardRef(function AutocompleteInput(props, ref) { - return -}) - -// Type annotation needed because Autocomplete's subcomponents use `@primer/react` internals -const Autocomplete: typeof AutocompleteImpl & { - Input: typeof AutocompleteInput - Menu: typeof PrimerAutocomplete.Menu - Overlay: typeof PrimerAutocomplete.Overlay -} = Object.assign(AutocompleteImpl, { - Input: AutocompleteInput, - Menu: PrimerAutocomplete.Menu, - Overlay: PrimerAutocomplete.Overlay, -}) - -export {Autocomplete} -export type {AutocompleteProps} diff --git a/packages/styled-react/src/components/Select.tsx b/packages/styled-react/src/components/Select.tsx deleted file mode 100644 index 3ff96611563..00000000000 --- a/packages/styled-react/src/components/Select.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import {Box, Select as PrimerSelect, type SelectProps as PrimerSelectProps} from '@primer/react' -import {forwardRef, type PropsWithChildren} from 'react' -import type {SxProp} from '../sx' - -type SelectProps = PropsWithChildren & SxProp - -const SelectImpl: React.ForwardRefExoticComponent> = forwardRef< - HTMLSelectElement, - SelectProps ->(function Select(props, ref) { - return -}) - -// Type annotation needed because Select uses `@primer/react` internals: -// `TextInputWrapper` component and `FormValidationStatus` type -const Select: typeof SelectImpl & { - Option: typeof PrimerSelect.Option - OptGroup: typeof PrimerSelect.OptGroup -} = Object.assign(SelectImpl, { - Option: PrimerSelect.Option, - OptGroup: PrimerSelect.OptGroup, -}) - -export {Select} -export type {SelectProps} diff --git a/packages/styled-react/src/components/TextInput.tsx b/packages/styled-react/src/components/TextInput.tsx deleted file mode 100644 index 85752b03be4..00000000000 --- a/packages/styled-react/src/components/TextInput.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import {Box, TextInput as PrimerTextInput, type TextInputProps as PrimerTextInputProps} from '@primer/react' -import {forwardRef, type PropsWithChildren} from 'react' -import type {SxProp} from '../sx' - -type TextInputProps = PropsWithChildren & SxProp - -const TextInputImpl: React.ForwardRefExoticComponent> = - forwardRef(function TextInput(props, ref) { - return - }) - -// Type annotation needed because TextInput uses `@primer/react` internals: -// `TextInputWrapper` component and `FormValidationStatus` type -const TextInput: typeof TextInputImpl & { - Action: typeof PrimerTextInput.Action -} = Object.assign(TextInputImpl, { - Action: PrimerTextInput.Action, -}) - -export {TextInput} -export type {TextInputProps} diff --git a/packages/styled-react/src/index.tsx b/packages/styled-react/src/index.tsx index 6bb625118f4..66763c5389a 100644 --- a/packages/styled-react/src/index.tsx +++ b/packages/styled-react/src/index.tsx @@ -1,5 +1,3 @@ -import type React from 'react' -import {forwardRef, type PropsWithChildren} from 'react' import { type BetterSystemStyleObject, Box, @@ -10,8 +8,6 @@ import { SubNav as PrimerSubNav, type SubNavProps as PrimerSubNavProps, type SubNavLinkProps as PrimerSubNavLinkProps, - Textarea as PrimerTextarea, - type TextareaProps as PrimerTextareaProps, ToggleSwitch as PrimerToggleSwitch, type ToggleSwitchProps as PrimerToggleSwitchProps, type SegmentedControlProps as PrimerSegmentedControlProps, @@ -19,6 +15,7 @@ import { type SegmentedControlButtonProps as PrimerSegmentedControlButtonProps, type SegmentedControlIconButtonProps as PrimerSegmentedControlIconButtonProps, } from '@primer/react' +import React, {forwardRef, type PropsWithChildren} from 'react' import type { BackgroundProps, BorderProps, @@ -31,9 +28,6 @@ import type { SpaceProps, TypographyProps, } from 'styled-system' -import {Autocomplete} from './components/Autocomplete' -import {Select} from './components/Select' -import {TextInput} from './components/TextInput' type StyledProps = SxProp & SpaceProps & @@ -96,21 +90,12 @@ const ToggleSwitch = forwardRef(function T return }) -type TextareaProps = PropsWithChildren & SxProp - -// Type annotation needed because TextInput uses `FormValidationStatus` internal type -const Textarea: React.ForwardRefExoticComponent> = forwardRef< - HTMLTextAreaElement, - TextareaProps ->(function Textarea(props, ref) { - return -}) - -export {Autocomplete, SegmentedControl, Select, StateLabel, SubNav, TextInput, Textarea, ToggleSwitch} +export {SegmentedControl, StateLabel, SubNav, ToggleSwitch} export { ActionList, ActionMenu, + Autocomplete, Avatar, Breadcrumbs, Button, @@ -135,8 +120,11 @@ export { ProgressBar, RadioGroup, RelativeTime, + Select, Spinner, Text, + Textarea, + TextInput, Timeline, Token, Tooltip, diff --git a/packages/styled-react/src/sx.ts b/packages/styled-react/src/sx.ts deleted file mode 100644 index e3ff0277f10..00000000000 --- a/packages/styled-react/src/sx.ts +++ /dev/null @@ -1,8 +0,0 @@ -import css from '@styled-system/css' -import type {SxProp} from '@primer/react' - -export const sx = (props: SxProp) => { - return css(props.sx) -} - -export type {SxProp}