Skip to content

Commit

Permalink
Added labelProps prop to [EuiSwitch, EuiRadio, EuiCheckbox] (elasti…
Browse files Browse the repository at this point in the history
  • Loading branch information
akashgp09 authored Feb 18, 2021
1 parent 1297cd4 commit db3ddc1
Show file tree
Hide file tree
Showing 10 changed files with 155 additions and 8 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
- Added `truncate` prop to `EuiSideNav` ([#4488](https://github.com/elastic/eui/pull/4488))
- Added support for all `color`s of `EuiPanel` ([#4504](https://github.com/elastic/eui/pull/4504))
- Added `hasBorder` prop to `EuiPanel` ([#4504](https://github.com/elastic/eui/pull/4504))
- Added `labelProps` prop to `EuiRadio`, `EuiSwitch` and `EuiCheckbox` ([#4516](https://github.com/elastic/eui/pull/4516))

**Bug fixes**

Expand Down
23 changes: 23 additions & 0 deletions src/components/form/checkbox/__snapshots__/checkbox.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,29 @@ exports[`EuiCheckbox props label is rendered 1`] = `
</div>
`;

exports[`EuiCheckbox props labelProps is rendered 1`] = `
<div
class="euiCheckbox"
>
<input
class="euiCheckbox__input"
id="id"
type="checkbox"
/>
<div
class="euiCheckbox__square"
/>
<label
aria-label="aria-label"
class="euiCheckbox__label testClass1 testClass2"
data-test-subj="test subject string"
for="id"
>
Label
</label>
</div>
`;

exports[`EuiCheckbox props type inList is rendered 1`] = `
<div
class="euiCheckbox euiCheckbox--inList euiCheckbox--noLabel"
Expand Down
11 changes: 11 additions & 0 deletions src/components/form/checkbox/checkbox.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,17 @@ describe('EuiCheckbox', () => {
expect(component).toMatchSnapshot();
});

test('labelProps is rendered', () => {
const component = render(
<EuiCheckbox
{...checkboxRequiredProps}
label="Label"
labelProps={requiredProps}
/>
);

expect(component).toMatchSnapshot();
});
describe('type', () => {
TYPES.forEach((value) => {
test(`${value} is rendered`, () => {
Expand Down
13 changes: 11 additions & 2 deletions src/components/form/checkbox/checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import React, {
ChangeEventHandler,
ReactNode,
InputHTMLAttributes,
LabelHTMLAttributes,
} from 'react';
import classNames from 'classnames';

Expand Down Expand Up @@ -50,6 +51,10 @@ export interface EuiCheckboxProps
*/
compressed?: boolean;
indeterminate?: boolean;
/**
* Object of props passed to the <label/>
*/
labelProps?: CommonProps & LabelHTMLAttributes<HTMLLabelElement>;
}

export class EuiCheckbox extends Component<EuiCheckboxProps> {
Expand Down Expand Up @@ -82,6 +87,7 @@ export class EuiCheckbox extends Component<EuiCheckboxProps> {
compressed,
indeterminate,
inputRef,
labelProps,
...rest
} = this.props;

Expand All @@ -94,12 +100,15 @@ export class EuiCheckbox extends Component<EuiCheckboxProps> {
},
className
);

const labelClasses = classNames(
'euiCheckbox__label',
labelProps?.className
);
let optionalLabel;

if (label) {
optionalLabel = (
<label className="euiCheckbox__label" htmlFor={id}>
<label {...labelProps} className={labelClasses} htmlFor={id}>
{label}
</label>
);
Expand Down
23 changes: 23 additions & 0 deletions src/components/form/radio/__snapshots__/radio.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,29 @@ exports[`EuiRadio props label is rendered 1`] = `
</div>
`;

exports[`EuiRadio props labelProps is rendered 1`] = `
<div
class="euiRadio"
>
<input
class="euiRadio__input"
id="id"
type="radio"
/>
<div
class="euiRadio__circle"
/>
<label
aria-label="aria-label"
class="euiRadio__label testClass1 testClass2"
data-test-subj="test subject string"
for="id"
>
Label
</label>
</div>
`;

exports[`EuiRadio props value is rendered 1`] = `
<div
class="euiRadio euiRadio--noLabel"
Expand Down
13 changes: 13 additions & 0 deletions src/components/form/radio/radio.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,18 @@ describe('EuiRadio', () => {

expect(component).toMatchSnapshot();
});

test('labelProps is rendered', () => {
const component = render(
<EuiRadio
id="id"
onChange={() => {}}
label="Label"
labelProps={requiredProps}
/>
);

expect(component).toMatchSnapshot();
});
});
});
11 changes: 8 additions & 3 deletions src/components/form/radio/radio.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import React, {
FunctionComponent,
ChangeEventHandler,
HTMLAttributes,
LabelHTMLAttributes,
ReactNode,
} from 'react';
import classNames from 'classnames';
Expand All @@ -37,6 +38,10 @@ export interface RadioProps {
checked?: boolean;
disabled?: boolean;
onChange: ChangeEventHandler<HTMLInputElement>;
/**
* Object of props passed to the <label/>
*/
labelProps?: CommonProps & LabelHTMLAttributes<HTMLLabelElement>;
}

interface idWithLabel extends RadioProps {
Expand All @@ -63,6 +68,7 @@ export const EuiRadio: FunctionComponent<EuiRadioProps> = ({
disabled,
compressed,
autoFocus,
labelProps,
...rest
}) => {
const classes = classNames(
Expand All @@ -73,12 +79,12 @@ export const EuiRadio: FunctionComponent<EuiRadioProps> = ({
},
className
);

const labelClasses = classNames('euiRadio__label', labelProps?.className);
let optionalLabel;

if (label) {
optionalLabel = (
<label className="euiRadio__label" htmlFor={id}>
<label {...labelProps} className={labelClasses} htmlFor={id}>
{label}
</label>
);
Expand All @@ -97,7 +103,6 @@ export const EuiRadio: FunctionComponent<EuiRadioProps> = ({
disabled={disabled}
autoFocus={autoFocus}
/>

<div className="euiRadio__circle" />

{optionalLabel}
Expand Down
43 changes: 43 additions & 0 deletions src/components/form/switch/__snapshots__/switch.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,46 @@ exports[`EuiSwitch is rendered 1`] = `
</span>
</div>
`;

exports[`EuiSwitch labelProps is rendered 1`] = `
<div
class="euiSwitch"
>
<button
aria-checked="false"
aria-labelledby="generated-id"
class="euiSwitch__button"
id="generated-id"
role="switch"
type="button"
>
<span
class="euiSwitch__body"
>
<span
class="euiSwitch__thumb"
/>
<span
class="euiSwitch__track"
>
<span
class="euiSwitch__icon"
data-euiicon-type="cross"
/>
<span
class="euiSwitch__icon euiSwitch__icon--checked"
data-euiicon-type="check"
/>
</span>
</span>
</button>
<span
aria-label="aria-label"
class="euiSwitch__label testClass1 testClass2"
data-test-subj="test subject string"
id="generated-id"
>
Label
</span>
</div>
`;
9 changes: 9 additions & 0 deletions src/components/form/switch/switch.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,13 @@ describe('EuiSwitch', () => {

expect(component).toMatchSnapshot();
});
describe('labelProps', () => {
it('is rendered', () => {
const component = render(
<EuiSwitch {...props} labelProps={requiredProps} />
);

expect(component).toMatchSnapshot();
});
});
});
16 changes: 13 additions & 3 deletions src/components/form/switch/switch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import React, {
ButtonHTMLAttributes,
HTMLAttributes,
FunctionComponent,
ReactNode,
useState,
Expand Down Expand Up @@ -56,6 +57,10 @@ export type EuiSwitchProps = CommonProps &
disabled?: boolean;
compressed?: boolean;
type?: 'submit' | 'reset' | 'button';
/**
* Object of props passed to the label's <span/>
*/
labelProps?: CommonProps & HTMLAttributes<HTMLSpanElement>;
};

export const EuiSwitch: FunctionComponent<EuiSwitchProps> = ({
Expand All @@ -68,10 +73,11 @@ export const EuiSwitch: FunctionComponent<EuiSwitchProps> = ({
className,
showLabel = true,
type = 'button',
labelProps,
...rest
}) => {
const [switchId] = useState(id || htmlIdGenerator()());
const [labelId] = useState(htmlIdGenerator()());
const [labelId] = useState(labelProps?.id || htmlIdGenerator()());

const onClick = useCallback(
(e: React.MouseEvent<HTMLButtonElement | HTMLParagraphElement>) => {
Expand All @@ -93,7 +99,7 @@ export const EuiSwitch: FunctionComponent<EuiSwitchProps> = ({
},
className
);

const labelClasses = classNames('euiSwitch__label', labelProps?.className);
if (showLabel === false && typeof label !== 'string') {
console.warn(
'EuiSwitch `label` must be a string when `showLabel` is false.'
Expand Down Expand Up @@ -135,7 +141,11 @@ export const EuiSwitch: FunctionComponent<EuiSwitchProps> = ({
// <button> + <label> has poor screen reader support.
// Click handler added to simulate natural, secondary <label> interactivity.
// eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions
<span className="euiSwitch__label" id={labelId} onClick={onClick}>
<span
{...labelProps}
className={labelClasses}
id={labelId}
onClick={onClick}>
{label}
</span>
)}
Expand Down

0 comments on commit db3ddc1

Please sign in to comment.