initial commit
This commit is contained in:
@ -0,0 +1,62 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { Fragment } from '@wordpress/element';
|
||||
import classNames from 'classnames';
|
||||
import type { ReactElement, HTMLProps } from 'react';
|
||||
|
||||
interface LabelProps extends HTMLProps< HTMLElement > {
|
||||
label?: string;
|
||||
screenReaderLabel?: string;
|
||||
wrapperElement?: string;
|
||||
wrapperProps?: HTMLProps< HTMLElement >;
|
||||
}
|
||||
|
||||
/**
|
||||
* Component used to render an accessible text given a label and/or a
|
||||
* screenReaderLabel. The wrapper element and wrapper props can also be
|
||||
* specified via props.
|
||||
*
|
||||
*/
|
||||
const Label = ( {
|
||||
label,
|
||||
screenReaderLabel,
|
||||
wrapperElement,
|
||||
wrapperProps = {},
|
||||
}: LabelProps ): ReactElement => {
|
||||
let Wrapper;
|
||||
|
||||
const hasLabel = typeof label !== 'undefined' && label !== null;
|
||||
const hasScreenReaderLabel =
|
||||
typeof screenReaderLabel !== 'undefined' && screenReaderLabel !== null;
|
||||
|
||||
if ( ! hasLabel && hasScreenReaderLabel ) {
|
||||
Wrapper = wrapperElement || 'span';
|
||||
wrapperProps = {
|
||||
...wrapperProps,
|
||||
className: classNames(
|
||||
wrapperProps.className,
|
||||
'screen-reader-text'
|
||||
),
|
||||
};
|
||||
|
||||
return <Wrapper { ...wrapperProps }>{ screenReaderLabel }</Wrapper>;
|
||||
}
|
||||
|
||||
Wrapper = wrapperElement || Fragment;
|
||||
|
||||
if ( hasLabel && hasScreenReaderLabel && label !== screenReaderLabel ) {
|
||||
return (
|
||||
<Wrapper { ...wrapperProps }>
|
||||
<span aria-hidden="true">{ label }</span>
|
||||
<span className="screen-reader-text">
|
||||
{ screenReaderLabel }
|
||||
</span>
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
|
||||
return <Wrapper { ...wrapperProps }>{ label }</Wrapper>;
|
||||
};
|
||||
|
||||
export default Label;
|
@ -0,0 +1,62 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Label with wrapperElement should render both label and screen reader label 1`] = `
|
||||
<label
|
||||
className="foo-bar"
|
||||
data-foo="bar"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
>
|
||||
Lorem
|
||||
</span>
|
||||
<span
|
||||
className="screen-reader-text"
|
||||
>
|
||||
Ipsum
|
||||
</span>
|
||||
</label>
|
||||
`;
|
||||
|
||||
exports[`Label with wrapperElement should render only the label 1`] = `
|
||||
<label
|
||||
className="foo-bar"
|
||||
data-foo="bar"
|
||||
>
|
||||
Lorem
|
||||
</label>
|
||||
`;
|
||||
|
||||
exports[`Label with wrapperElement should render only the screen reader label 1`] = `
|
||||
<label
|
||||
className="foo-bar screen-reader-text"
|
||||
data-foo="bar"
|
||||
>
|
||||
Ipsum
|
||||
</label>
|
||||
`;
|
||||
|
||||
exports[`Label without wrapperElement should render both label and screen reader label 1`] = `
|
||||
Array [
|
||||
<span
|
||||
aria-hidden="true"
|
||||
>
|
||||
Lorem
|
||||
</span>,
|
||||
<span
|
||||
className="screen-reader-text"
|
||||
>
|
||||
Ipsum
|
||||
</span>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`Label without wrapperElement should render only the label 1`] = `"Lorem"`;
|
||||
|
||||
exports[`Label without wrapperElement should render only the screen reader label 1`] = `
|
||||
<span
|
||||
className="screen-reader-text"
|
||||
>
|
||||
Ipsum
|
||||
</span>
|
||||
`;
|
@ -0,0 +1,83 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import TestRenderer from 'react-test-renderer';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import Label from '../';
|
||||
|
||||
describe( 'Label', () => {
|
||||
describe( 'without wrapperElement', () => {
|
||||
test( 'should render both label and screen reader label', () => {
|
||||
const component = TestRenderer.create(
|
||||
<Label label="Lorem" screenReaderLabel="Ipsum" />
|
||||
);
|
||||
|
||||
expect( component.toJSON() ).toMatchSnapshot();
|
||||
} );
|
||||
|
||||
test( 'should render only the label', () => {
|
||||
const component = TestRenderer.create( <Label label="Lorem" /> );
|
||||
|
||||
expect( component.toJSON() ).toMatchSnapshot();
|
||||
} );
|
||||
|
||||
test( 'should render only the screen reader label', () => {
|
||||
const component = TestRenderer.create(
|
||||
<Label screenReaderLabel="Ipsum" />
|
||||
);
|
||||
|
||||
expect( component.toJSON() ).toMatchSnapshot();
|
||||
} );
|
||||
} );
|
||||
|
||||
describe( 'with wrapperElement', () => {
|
||||
test( 'should render both label and screen reader label', () => {
|
||||
const component = TestRenderer.create(
|
||||
<Label
|
||||
label="Lorem"
|
||||
screenReaderLabel="Ipsum"
|
||||
wrapperElement="label"
|
||||
wrapperProps={ {
|
||||
className: 'foo-bar',
|
||||
'data-foo': 'bar',
|
||||
} }
|
||||
/>
|
||||
);
|
||||
|
||||
expect( component.toJSON() ).toMatchSnapshot();
|
||||
} );
|
||||
|
||||
test( 'should render only the label', () => {
|
||||
const component = TestRenderer.create(
|
||||
<Label
|
||||
label="Lorem"
|
||||
wrapperElement="label"
|
||||
wrapperProps={ {
|
||||
className: 'foo-bar',
|
||||
'data-foo': 'bar',
|
||||
} }
|
||||
/>
|
||||
);
|
||||
|
||||
expect( component.toJSON() ).toMatchSnapshot();
|
||||
} );
|
||||
|
||||
test( 'should render only the screen reader label', () => {
|
||||
const component = TestRenderer.create(
|
||||
<Label
|
||||
screenReaderLabel="Ipsum"
|
||||
wrapperElement="label"
|
||||
wrapperProps={ {
|
||||
className: 'foo-bar',
|
||||
'data-foo': 'bar',
|
||||
} }
|
||||
/>
|
||||
);
|
||||
|
||||
expect( component.toJSON() ).toMatchSnapshot();
|
||||
} );
|
||||
} );
|
||||
} );
|
Reference in New Issue
Block a user