From 278937f589d02fb4debe2e9b135bdaca655ef167 Mon Sep 17 00:00:00 2001 From: Jan Hassel Date: Fri, 13 Jan 2023 10:28:02 +0100 Subject: [PATCH 1/2] feat(toggle): allow to be labelled by another element --- .../__snapshots__/PublicAPI-test.js.snap | 8 ++--- .../src/components/Toggle/Toggle-test.js | 22 ++++++++++-- .../react/src/components/Toggle/Toggle.js | 35 +++++++++++++++---- 3 files changed, 52 insertions(+), 13 deletions(-) diff --git a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap index fb3d438c5ef4..3c08f604347b 100644 --- a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap +++ b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap @@ -8498,6 +8498,9 @@ Map { }, "Toggle" => Object { "propTypes": Object { + "aria-labelledby": Object { + "type": "string", + }, "className": Object { "type": "string", }, @@ -8520,10 +8523,7 @@ Map { "labelB": Object { "type": "node", }, - "labelText": Object { - "isRequired": true, - "type": "node", - }, + "labelText": [Function], "onClick": Object { "type": "func", }, diff --git a/packages/react/src/components/Toggle/Toggle-test.js b/packages/react/src/components/Toggle/Toggle-test.js index d652d1019184..8a7ec415028f 100644 --- a/packages/react/src/components/Toggle/Toggle-test.js +++ b/packages/react/src/components/Toggle/Toggle-test.js @@ -88,10 +88,28 @@ describe('Toggle', () => { .classList.contains(`${prefix}--visually-hidden`) ).toBe(true); expect( - wrapper.container.querySelector(`.${prefix}--toggle__label-text`) - .textContent + wrapper.container.querySelector(`.${prefix}--toggle__text`).textContent ).toBe(props.labelText); }); + + it("doesn't render sideLabel if props.hideLabel and props['aria-labelledby'] are provided", () => { + const externalElementId = 'external-element-id'; + wrapper.rerender( + + ); + + expect( + wrapper.container.querySelector(`.${prefix}--toggle__text`) + ).toBeNull(); + + expect(wrapper.getByRole('switch').getAttribute('aria-labelledby')).toBe( + externalElementId + ); + + expect( + wrapper.container.querySelector(`.${prefix}--toggle__label`).tagName + ).toBe('DIV'); + }); }); describe('behaves as expected', () => { diff --git a/packages/react/src/components/Toggle/Toggle.js b/packages/react/src/components/Toggle/Toggle.js index b66c3bbaa12e..aa63927d56d5 100644 --- a/packages/react/src/components/Toggle/Toggle.js +++ b/packages/react/src/components/Toggle/Toggle.js @@ -12,6 +12,7 @@ import { useControllableState } from '../../internal/useControllableState'; import { usePrefix } from '../../internal/usePrefix'; export function Toggle({ + 'aria-labelledby': ariaLabelledby, className, defaultToggled = false, disabled = false, @@ -45,6 +46,8 @@ export function Toggle({ const isSm = size === 'sm'; const sideLabel = hideLabel ? labelText : checked ? labelB : labelA; + const renderSideLabel = !(hideLabel && ariaLabelledby); + const LabelComponent = ariaLabelledby ? 'div' : 'label'; const wrapperClasses = classNames( `${prefix}--toggle`, @@ -76,10 +79,13 @@ export function Toggle({ role="switch" type="button" aria-checked={checked} + aria-labelledby={ariaLabelledby} disabled={disabled} onClick={handleClick} /> - + ); } Toggle.propTypes = { + /** + * Specify another element's id to be used as the label for this toggle + */ + 'aria-labelledby': PropTypes.string, + /** * Specify a custom className to apply to the form-item node */ @@ -140,9 +153,17 @@ Toggle.propTypes = { /** * Provide the text that will be read by a screen reader when visiting this - * control + * control. This is required unless 'aria-labelledby' is provided instead */ - labelText: PropTypes.node.isRequired, + labelText: (props, ...rest) => { + if (!props['aria-labelledby'] && !props.labelText) { + return new Error( + 'labelText property is required if no aria-labelledby is provided.' + ); + } + + return PropTypes.node(props, ...rest); + }, /** * Provide an event listener that is called when the control is clicked From 4fdb2197a9519c72162616970ef5d888980a154f Mon Sep 17 00:00:00 2001 From: Jan Hassel Date: Fri, 13 Jan 2023 10:40:14 +0100 Subject: [PATCH 2/2] fix(toggle): don't render label element when no labelText is provided --- packages/react/src/components/Toggle/Toggle.js | 2 +- packages/react/src/components/Toggle/Toggle.stories.js | 9 +-------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/packages/react/src/components/Toggle/Toggle.js b/packages/react/src/components/Toggle/Toggle.js index aa63927d56d5..1d1072091506 100644 --- a/packages/react/src/components/Toggle/Toggle.js +++ b/packages/react/src/components/Toggle/Toggle.js @@ -86,7 +86,7 @@ export function Toggle({ - {labelText} + {labelText && {labelText}}
{isSm && ( diff --git a/packages/react/src/components/Toggle/Toggle.stories.js b/packages/react/src/components/Toggle/Toggle.stories.js index e017b4e749aa..a7b6a7990f33 100644 --- a/packages/react/src/components/Toggle/Toggle.stories.js +++ b/packages/react/src/components/Toggle/Toggle.stories.js @@ -35,14 +35,7 @@ export const SmallToggle = () => ( ); export const Playground = (args) => ( - + ); Playground.argTypes = {