-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create reusable FieldsetLegend component (#640)
* Create a component for fieldset legend * Replace logic in Checkbox and Radio Groups * Create fieldset legend storybook * Increase minor v * Add unit tests * Provide default value inside bracket * Add a note re: visually-hidden class * Remove confusing stories * Remove commented out code * fix version * Rename component + files
- Loading branch information
Showing
11 changed files
with
499 additions
and
337 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
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,89 @@ | ||
import React from 'react' | ||
import PropTypes from 'prop-types' | ||
import classnames from 'classnames' | ||
import { convertNameToLabel } from '../helpers' | ||
|
||
/** | ||
* | ||
* A legend representing a caption for the content of its parent field set element | ||
* | ||
* This component must be used as a direct child and the only legend of the <fieldset> element that groups related controls | ||
* | ||
* | ||
* The text of the legend is set using the following rules: | ||
* - If the `label` prop is set to `false`, the legend is hidden visually via a class. _Note: It's your responsibility to make sure your styling rules respect the `visually-hidden` class_ | ||
* - Else If the `label` prop is set to a string, the label will display that text | ||
* - Otherwise, the label will be set using the `name` prop. | ||
* | ||
* | ||
* @name FieldsetLegend | ||
* @type Function | ||
* @param {String} name - The name of the associated group | ||
* @param {String} [hint] - A usage hint for the associated input | ||
* @param {String|Boolean} [label] - Custom text for the legend | ||
* @param {Boolean} [required=false] - A boolean value to indicate whether the field is required | ||
* @param {String} [requiredIndicator=''] - Custom character to denote a field is required | ||
* @example | ||
* | ||
* | ||
* function ShippingAddress (props) { | ||
* const name = 'shippingAddress' | ||
* return ( | ||
* <fieldset> | ||
* <FieldsetLegend name={name} /> | ||
* <Input id={`${name}.name`} input={{name: 'name'}} /> | ||
* <Input id={`${name}.street`} input={{name: 'street'}} /> | ||
* <Input id={`${name}.city`}" input={{name: 'city'}} /> | ||
* <Input id={`${name}.state`} input={{name: 'state'}} /> | ||
* </fieldset> | ||
* ) | ||
* } | ||
* | ||
*/ | ||
|
||
const propTypes = { | ||
label: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), | ||
name: PropTypes.string.isRequired, | ||
required: PropTypes.bool, | ||
requiredIndicator: PropTypes.string, | ||
className: PropTypes.string, | ||
hint: PropTypes.string, | ||
} | ||
|
||
const defaultProps = { | ||
children: null, | ||
hint: '', | ||
label: '', | ||
required: false, | ||
requiredIndicator: '', | ||
className: '', | ||
} | ||
|
||
function FieldsetLegend({ | ||
label, | ||
name, | ||
required, | ||
requiredIndicator, | ||
className, | ||
hint, | ||
}) { | ||
return ( | ||
<legend | ||
className={classnames(className, { 'visually-hidden': label === false })} | ||
> | ||
{label || convertNameToLabel(name)} | ||
{required && requiredIndicator && ( | ||
<span className="required-indicator" aria-hidden="true"> | ||
{requiredIndicator} | ||
</span> | ||
)} | ||
{hint && <i>{hint}</i>} | ||
</legend> | ||
) | ||
} | ||
|
||
FieldsetLegend.propTypes = propTypes | ||
FieldsetLegend.defaultProps = defaultProps | ||
|
||
export default FieldsetLegend |
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,21 @@ | ||
import React from 'react' | ||
import { storiesOf } from '@storybook/react' | ||
import { FieldsetLegend } from 'src' | ||
|
||
storiesOf('FieldsetLegend', module) | ||
.add('with default label', () => <FieldsetLegend name="nameOfInput" />) | ||
.add('with custom label', () => ( | ||
<FieldsetLegend name="nameOfInput" label="Custom Label" /> | ||
)) | ||
.add('with no label', () => ( | ||
<FieldsetLegend name="nameOfInput" label={false} /> | ||
)) | ||
.add('with required true custom indicator', () => ( | ||
<FieldsetLegend | ||
name="nameOfInput" | ||
label="Custom Label" | ||
required={true} | ||
requiredIndicator={'*'} | ||
/> | ||
)) | ||
.add('with hint', () => <FieldsetLegend name="nameOfInput" hint="hint" />) |
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,45 @@ | ||
import React from 'react' | ||
import { render, screen } from '@testing-library/react' | ||
import { FieldsetLegend } from '../../../src/' | ||
|
||
const name = 'contactDetails' | ||
const formattedName = 'Contact Details' | ||
|
||
describe('FieldsetLegend', () => { | ||
test('renders label correctly when label prop is a string', () => { | ||
render(<FieldsetLegend name={name} label="Your Information" />) | ||
expect(screen.getByText('Your Information')).toBeInTheDocument() | ||
}) | ||
|
||
test('renders label correctly using name prop when label prop is not provided', () => { | ||
render(<FieldsetLegend name={name} />) | ||
expect(screen.getByText(formattedName)).toBeInTheDocument() | ||
}) | ||
|
||
test('renders label with class "visually-hidden" when label prop is false', () => { | ||
render(<FieldsetLegend name={name} label={false} />) | ||
expect(screen.getByText(formattedName)).toHaveClass('visually-hidden') | ||
}) | ||
|
||
test('does not show required indicator when no custom required indicator is provided', () => { | ||
render(<FieldsetLegend name={name} required />) | ||
expect(screen.getByText(formattedName).textContent).toEqual(formattedName) | ||
}) | ||
|
||
test('shows custom indicator when required is true and custom requiredIndicator is provided', () => { | ||
render(<FieldsetLegend name={name} required requiredIndicator={'*'} />) | ||
expect(screen.getByText('*')).toBeInTheDocument() | ||
}) | ||
|
||
test('hides custom indicator when required is false and custom requiredIndicator is provided', () => { | ||
render( | ||
<FieldsetLegend name={name} required={false} requiredIndicator={'*'} /> | ||
) | ||
expect(screen.queryByText('*')).not.toBeInTheDocument() | ||
}) | ||
|
||
test('shows hint when hint is provided', () => { | ||
render(<FieldsetLegend name={name} hint="hint" />) | ||
expect(screen.getByText(formattedName)).toHaveTextContent('hint') | ||
}) | ||
}) |