From 855205e6927c7fce26b087520f564f4915e29aea Mon Sep 17 00:00:00 2001 From: Kim Allen Date: Wed, 17 Apr 2024 12:09:55 -0700 Subject: [PATCH] fix: add a statusText prop to StepIndicator to allow for i18n for the sr-only element Closes #2857 (#2888) --- .../StepIndicator/StepIndicator.stories.tsx | 21 ++++++++---- .../StepIndicator/StepIndicator.test.tsx | 22 +++++++++++++ .../StepIndicator/StepIndicator.tsx | 13 +++++++- .../StepIndicatorStep.test.tsx | 32 ++++++++++++++++--- .../StepIndicatorStep/StepIndicatorStep.tsx | 17 ++++++++-- 5 files changed, 90 insertions(+), 15 deletions(-) diff --git a/src/components/stepindicator/StepIndicator/StepIndicator.stories.tsx b/src/components/stepindicator/StepIndicator/StepIndicator.stories.tsx index 2c556101e7..06ab7ef5c8 100644 --- a/src/components/stepindicator/StepIndicator/StepIndicator.stories.tsx +++ b/src/components/stepindicator/StepIndicator/StepIndicator.stories.tsx @@ -1,6 +1,6 @@ import React from 'react' import { StepIndicatorStep } from '../StepIndicatorStep/StepIndicatorStep' -import { StepIndicator } from '../StepIndicator/StepIndicator' +import { StepIndicator, StepStatusText } from '../StepIndicator/StepIndicator' export default { title: 'Components/Step Indicator', @@ -35,6 +35,7 @@ Updates users on their progress through a multi-step process. type StorybookArguments = { stepText: string ofText: string + statusText: StepStatusText } export const DefaultStepIndicator = ( @@ -43,7 +44,8 @@ export const DefaultStepIndicator = ( + stepText={args.stepText} + statusText={args.statusText}> @@ -57,7 +59,8 @@ export const NoLabels = (args: StorybookArguments): React.ReactElement => ( showLabels={false} headingLevel="h4" ofText={args.ofText} - stepText={args.stepText}> + stepText={args.stepText} + statusText={args.statusText}> @@ -71,7 +74,8 @@ export const Centered = (args: StorybookArguments): React.ReactElement => ( centered headingLevel="h4" ofText={args.ofText} - stepText={args.stepText}> + stepText={args.stepText} + statusText={args.statusText}> @@ -85,7 +89,8 @@ export const Counters = (args: StorybookArguments): React.ReactElement => ( counters="default" headingLevel="h4" ofText={args.ofText} - stepText={args.stepText}> + stepText={args.stepText} + statusText={args.statusText}> @@ -99,7 +104,8 @@ export const SmallCounters = (args: StorybookArguments): React.ReactElement => ( counters="small" headingLevel="h4" ofText={args.ofText} - stepText={args.stepText}> + stepText={args.stepText} + statusText={args.statusText}> @@ -114,7 +120,8 @@ export const DifferentHeadingLevel = ( + stepText={args.stepText} + statusText={args.statusText}> diff --git a/src/components/stepindicator/StepIndicator/StepIndicator.test.tsx b/src/components/stepindicator/StepIndicator/StepIndicator.test.tsx index 178434d118..57cdf580fc 100644 --- a/src/components/stepindicator/StepIndicator/StepIndicator.test.tsx +++ b/src/components/stepindicator/StepIndicator/StepIndicator.test.tsx @@ -196,4 +196,26 @@ describe('StepIndicator component', () => { const stepSrOnly = within(stepIndicator).queryByText(stepText) expect(stepSrOnly).toHaveClass('usa-sr-only') }) + it('renders properly with translated statusText for screen reader', () => { + const statusText = { complete: 'completado', incomplete: 'no completado' } + + const { getByTestId } = render( + + + + + + ) + const stepIndicator = getByTestId('step-indicator') + + const completedStatusSrOnly = within(stepIndicator).queryByText( + statusText.complete + ) + expect(completedStatusSrOnly).toHaveClass('usa-sr-only') + + const incompleteStatusSrOnly = within(stepIndicator).queryByText( + statusText.incomplete + ) + expect(incompleteStatusSrOnly).toHaveClass('usa-sr-only') + }) }) diff --git a/src/components/stepindicator/StepIndicator/StepIndicator.tsx b/src/components/stepindicator/StepIndicator/StepIndicator.tsx index 9dd839083b..72dc4b7d5d 100644 --- a/src/components/stepindicator/StepIndicator/StepIndicator.tsx +++ b/src/components/stepindicator/StepIndicator/StepIndicator.tsx @@ -3,6 +3,11 @@ import classnames from 'classnames' import { StepIndicatorStepProps } from '../StepIndicatorStep/StepIndicatorStep' import { HeadingLevel } from '../../../types/headingLevel' +export type StepStatusText = { + complete: string + incomplete: string +} + type StepIndicatorProps = { showLabels?: boolean counters?: 'none' | 'default' | 'small' @@ -18,6 +23,7 @@ type StepIndicatorProps = { headingLevel: HeadingLevel stepText?: string ofText?: string + statusText?: StepStatusText } export const StepIndicator = ( props: StepIndicatorProps @@ -34,6 +40,7 @@ export const StepIndicator = ( headingLevel, stepText = 'Step', ofText = 'of', + statusText = { complete: 'completed', incomplete: 'not completed' }, } = props const Heading = headingLevel @@ -76,6 +83,10 @@ export const StepIndicator = ( const currentStepLabel = children[parseInt(`${currentStepIndex}`)].props.label const totalNumberOfSteps = children.length + const stepChildren = React.Children.map(children, (child) => + React.cloneElement(child, { statusText: statusText }) + ) + return (
    - {children} + {stepChildren}
diff --git a/src/components/stepindicator/StepIndicatorStep/StepIndicatorStep.test.tsx b/src/components/stepindicator/StepIndicatorStep/StepIndicatorStep.test.tsx index 66a28f81a2..603adf9ecb 100644 --- a/src/components/stepindicator/StepIndicatorStep/StepIndicatorStep.test.tsx +++ b/src/components/stepindicator/StepIndicatorStep/StepIndicatorStep.test.tsx @@ -12,14 +12,26 @@ describe('Step component', () => { }) it('renders with incomplete status', () => { - const { getByRole, queryByText } = render( + const { getByRole, queryByText, queryByTestId } = render( ) expect(queryByText('Test Step')).toBeInTheDocument() - expect(queryByText('not completed')).toHaveClass('usa-sr-only') + expect(queryByTestId('srStatusText')).toHaveClass('usa-sr-only') + expect(queryByTestId('srStatusText')).toHaveTextContent('not completed') expect(getByRole('listitem')).toHaveClass('usa-step-indicator__segment') }) + it('renders incomplete status with alternative language in screen reader element', () => { + const { queryByTestId } = render( + + ) + expect(queryByTestId('srStatusText')).toHaveTextContent('no completado') + }) + it('renders with current status', () => { const { getByRole, queryByText } = render( @@ -31,13 +43,25 @@ describe('Step component', () => { }) it('renders with complete status', () => { - const { getByRole, queryByText } = render( + const { getByRole, queryByText, queryByTestId } = render( ) expect(queryByText('Test Step')).toBeInTheDocument() - expect(queryByText('completed')).toHaveClass('usa-sr-only') + expect(queryByTestId('srStatusText')).toHaveClass('usa-sr-only') + expect(queryByTestId('srStatusText')).toHaveTextContent('completed') expect(getByRole('listitem')).toHaveClass( 'usa-step-indicator__segment usa-step-indicator__segment--complete' ) }) + + it('renders complete status with alternative language in screen reader element', () => { + const { queryByTestId } = render( + + ) + expect(queryByTestId('srStatusText')).toHaveTextContent('completado') + }) }) diff --git a/src/components/stepindicator/StepIndicatorStep/StepIndicatorStep.tsx b/src/components/stepindicator/StepIndicatorStep/StepIndicatorStep.tsx index 8f29df0c46..ac157bb106 100644 --- a/src/components/stepindicator/StepIndicatorStep/StepIndicatorStep.tsx +++ b/src/components/stepindicator/StepIndicatorStep/StepIndicatorStep.tsx @@ -1,16 +1,25 @@ import classnames from 'classnames' import React from 'react' +import { StepStatusText } from '../StepIndicator/StepIndicator' + export interface StepIndicatorStepProps { label: string status?: 'complete' | 'current' | 'incomplete' + statusText?: StepStatusText className?: string } export const StepIndicatorStep = ( props: StepIndicatorStepProps & JSX.IntrinsicElements['li'] ): React.ReactElement => { - const { label, status = 'incomplete', className, ...liProps } = props + const { + label, + status = 'incomplete', + statusText = { complete: 'completed', incomplete: 'not completed' }, + className, + ...liProps + } = props const classes = classnames( 'usa-step-indicator__segment', @@ -30,8 +39,10 @@ export const StepIndicatorStep = ( {label}   {status !== 'current' && ( - - {status === 'complete' ? 'completed' : 'not completed'} + + {status === 'complete' + ? statusText.complete + : statusText.incomplete} )}