-
Notifications
You must be signed in to change notification settings - Fork 535
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: add TextArea component * chore: fix lint errors * fix: typos and content * chore: update docs * fix: tests * chore: remove width and height * chore: fix typo in docs * docs: add ref row to TextArea * chore: fix typo in docs * chore: remove defaultValue * feat: refactor TextInputWrapper to separate base styles and reuse in textarea * fix: tests * feat: rename TextArea to Textarea * fix: move not-allowed to base wrapper * fix: rename file properly
- Loading branch information
Showing
16 changed files
with
1,740 additions
and
427 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@primer/react': minor | ||
--- | ||
|
||
Add new Textarea component |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
--- | ||
componentId: textarea | ||
title: Textarea | ||
description: Use Textarea for multi-line text input form fields | ||
status: Alpha | ||
source: https://github.com/primer/react/blob/main/src/Textarea.tsx | ||
storybook: /react/storybook?path=/story/forms-textarea--default | ||
--- | ||
|
||
import {Textarea} from '@primer/react' | ||
|
||
<Box sx={{border: '1px solid', borderColor: 'border.default', borderRadius: 2, padding: 6, marginBottom: 3}}> | ||
<Textarea /> | ||
</Box> | ||
|
||
```js | ||
import {Textarea} from '@primer/react' | ||
``` | ||
|
||
## Examples | ||
|
||
<Note variant="warning"> | ||
|
||
Textarea components **must always** be accompanied by a corresponding label to improve support for assistive | ||
technologies. Examples below are provided for conciseness and may not reflect accessibility best practices. | ||
|
||
</Note> | ||
|
||
### Controlled mode | ||
|
||
```javascript live noinline | ||
const TextareaExample = () => { | ||
// Running in controlled mode (recommended) | ||
const [value, setValue] = React.useState('') | ||
|
||
const handleChange = event => { | ||
setValue(event.target.value) | ||
} | ||
|
||
return <Textarea placeholder="Enter a description" onChange={handleChange} value={value} /> | ||
} | ||
|
||
render(<TextareaExample />) | ||
``` | ||
|
||
### Uncontrolled mode | ||
|
||
```javascript live noinline | ||
const TextareaExample = () => { | ||
const ref = React.useRef() | ||
|
||
const handleSubmit = event => { | ||
event.preventDefault() | ||
if (!ref.current.value) { | ||
alert(`Enter a value into the Textarea and press submit`) | ||
return | ||
} | ||
|
||
alert(`Current Textarea value: ${ref.current.value}`) | ||
} | ||
|
||
return ( | ||
<form onSubmit={handleSubmit}> | ||
<Textarea | ||
cols={40} | ||
rows={8} | ||
ref={ref} | ||
defaultValue="Set the initial state in uncontrolled mode using the defaultValue prop" | ||
/> | ||
<br /> | ||
<Button type="submit">Submit</Button> | ||
</form> | ||
) | ||
} | ||
|
||
render(<TextareaExample />) | ||
``` | ||
|
||
### Displaying form validation state | ||
|
||
```jsx live | ||
<> | ||
<Box as="label" htmlFor="success-state" sx={{display: 'block'}}> | ||
Success state: | ||
</Box> | ||
<Textarea id="success-state" validationStatus="success" /> | ||
<Box as="label" htmlFor="error-state" sx={{display: 'block', mt: 5}}> | ||
Error state: | ||
</Box> | ||
<Textarea id="error-state" validationStatus="error" /> | ||
</> | ||
``` | ||
|
||
### Inactive | ||
|
||
```jsx live | ||
<> | ||
<Textarea disabled>This text is inactive</Textarea> | ||
</> | ||
``` | ||
|
||
### Resize | ||
|
||
By default, `Textarea` can be resized by the user vertically and horizontally. Resizing can be prevented by setting `resize` to `none` | ||
|
||
```jsx live | ||
<Textarea cols={40} resize="none" /> | ||
``` | ||
|
||
### Custom styling | ||
|
||
```jsx live | ||
<> | ||
<Textarea sx={{marginBottom: 2}} /> | ||
<p>Custom styles like `margin` and `padding` can be applied using the `sx` prop</p> | ||
</> | ||
``` | ||
|
||
## Props | ||
|
||
### Textarea | ||
|
||
<PropsTable> | ||
<PropsTableRow | ||
name="required" | ||
type="boolean" | ||
description="Indicates to the user and assistive technologies that the field value is required" | ||
/> | ||
<PropsTableRow | ||
name="cols" | ||
type="number" | ||
description="Specifies the visible width of a text area." | ||
/> | ||
<PropsTableRow | ||
name="rows" | ||
type="number" | ||
description="Specifies the visible height of a text area." | ||
/> | ||
<PropsTableRow | ||
name="block" | ||
type="boolean" | ||
defaultValue="false" | ||
description="Expands with width of the component to fill the parent elements" | ||
/> | ||
<PropsTableRow | ||
name="resize" | ||
type="'both' | 'horizontal' | 'vertical' | 'none'" | ||
defaultValue="'both'" | ||
description="Changes background color to a higher contrast color" | ||
/> | ||
<PropsTableRow name="validationStatus" | ||
type="'success' | 'error' | undefined" | ||
description="Style the textarea to match the current form validation status" | ||
/> | ||
<PropsTableRefRow | ||
elementType="textarea" | ||
refType="HTMLTextAreaElement" | ||
/> | ||
<PropsTablePassthroughPropsRow | ||
elementName="textarea" | ||
passthroughPropsLink={ | ||
<Link href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea#attributes">MDN</Link> | ||
} | ||
/> | ||
|
||
</PropsTable> | ||
|
||
## Status | ||
|
||
<ComponentChecklist | ||
items={{ | ||
propsDocumented: true, | ||
noUnnecessaryDeps: true, | ||
adaptsToThemes: true, | ||
adaptsToScreenSizes: true, | ||
fullTestCoverage: true, | ||
usedInProduction: false, | ||
usageExamplesDocumented: true, | ||
hasStorybookStories: true, | ||
designReviewed: false, | ||
a11yReviewed: false, | ||
stableApi: false, | ||
addressedApiFeedback: false, | ||
hasDesignGuidelines: false, | ||
hasFigmaComponent: false | ||
}} | ||
/> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
import styled, {css} from 'styled-components' | ||
import React, {TextareaHTMLAttributes, ReactElement} from 'react' | ||
import {TextInputBaseWrapper} from './_TextInputWrapper' | ||
import {FormValidationStatus} from './utils/types/FormValidationStatus' | ||
import sx, {SxProp} from './sx' | ||
|
||
export type TextareaProps = { | ||
/** | ||
* Apply inactive visual appearance to the Textarea | ||
*/ | ||
disabled?: boolean | ||
/** | ||
* Indicates whether the Textarea is a required form field | ||
*/ | ||
required?: boolean | ||
/** | ||
* Indicates whether the Textarea validation state | ||
*/ | ||
validationStatus?: FormValidationStatus | ||
/** | ||
* Block | ||
*/ | ||
block?: boolean | ||
/** | ||
* Allows resizing of the textarea | ||
*/ | ||
resize?: 'none' | 'both' | 'horizontal' | 'vertical' | ||
} & TextareaHTMLAttributes<HTMLTextAreaElement> & | ||
SxProp | ||
|
||
const StyledTextarea = styled.textarea<TextareaProps>` | ||
border: 0; | ||
font-size: inherit; | ||
font-family: inherit; | ||
background-color: transparent; | ||
-webkit-appearance: none; | ||
color: inherit; | ||
width: 100%; | ||
resize: both; | ||
&:focus { | ||
outline: 0; | ||
} | ||
${props => | ||
props.resize && | ||
css` | ||
resize: ${props.resize}; | ||
`} | ||
${props => | ||
props.disabled && | ||
css` | ||
resize: none; | ||
`} | ||
${sx}; | ||
` | ||
|
||
/** | ||
* An accessible, native textarea component that supports validation states. | ||
* This component accepts all native HTML <textarea> attributes as props. | ||
*/ | ||
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>( | ||
( | ||
{ | ||
value, | ||
disabled, | ||
sx: sxProp, | ||
required, | ||
validationStatus, | ||
rows = 7, | ||
cols = 30, | ||
resize = 'both', | ||
block, | ||
...rest | ||
}: TextareaProps, | ||
ref | ||
): ReactElement => { | ||
return ( | ||
<TextInputBaseWrapper sx={sxProp} validationStatus={validationStatus} disabled={disabled} block={block}> | ||
<StyledTextarea | ||
value={value} | ||
resize={resize} | ||
required={required} | ||
aria-required={required ? 'true' : 'false'} | ||
aria-invalid={validationStatus === 'error' ? 'true' : 'false'} | ||
ref={ref} | ||
disabled={disabled} | ||
rows={rows} | ||
cols={cols} | ||
{...rest} | ||
/> | ||
</TextInputBaseWrapper> | ||
) | ||
} | ||
) | ||
|
||
Textarea.displayName = 'Textarea' | ||
|
||
export default Textarea |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.