From ec41d38086797d3b7475d51c802f24a94f0d1f7c Mon Sep 17 00:00:00 2001 From: Bastien DUMONT <bdumont@grandlyon.com> Date: Fri, 26 Jul 2024 07:30:27 +0000 Subject: [PATCH] fix(accessibility): remove graph shift when navigating with keyboard --- .../ConsumptionVisualizer.tsx | 17 ++++++++++++----- .../DataloadConsumptionVisualizer.tsx | 11 ++++++++++- .../ConsumptionVisualizer/DataloadNoValue.tsx | 8 +++++++- .../ConsumptionVisualizer/DataloadSection.tsx | 4 ++++ .../DataloadSectionDetail.tsx | 4 ++++ .../DataloadSectionValue.tsx | 3 +++ .../InfoDataConsumptionVisualizer.tsx | 14 ++++++++++++-- .../InfoDataConsumptionVisualizer.spec.tsx.snap | 2 +- src/components/FluidChart/FluidChartSlide.tsx | 5 ++++- src/components/FluidChart/FluidChartSwipe.tsx | 9 +++------ 10 files changed, 60 insertions(+), 17 deletions(-) diff --git a/src/components/ConsumptionVisualizer/ConsumptionVisualizer.tsx b/src/components/ConsumptionVisualizer/ConsumptionVisualizer.tsx index ab0e5d35e..34f248ca6 100644 --- a/src/components/ConsumptionVisualizer/ConsumptionVisualizer.tsx +++ b/src/components/ConsumptionVisualizer/ConsumptionVisualizer.tsx @@ -1,20 +1,25 @@ import DataloadConsumptionVisualizer from 'components/ConsumptionVisualizer/DataloadConsumptionVisualizer' import { FluidType } from 'enums' import { DateTime } from 'luxon' -import { Dataload } from 'models' import React from 'react' import { useAppSelector } from 'store/hooks' import InfoDataConsumptionVisualizer from './InfoDataConsumptionVisualizer' import './consumptionVisualizer.scss' -const ConsumptionVisualizer = ({ fluidType }: { fluidType: FluidType }) => { +const ConsumptionVisualizer = ({ + fluidType, + focusable, +}: { + fluidType: FluidType + focusable?: boolean +}) => { const { chart: { currentDatachart, currentDatachartIndex }, global: { fluidStatus, fluidTypes }, } = useAppSelector(state => state.ecolyo) - const dataload: Dataload = currentDatachart.actualData[currentDatachartIndex] - const compareDataload: Dataload | null = currentDatachart.comparisonData + const dataload = currentDatachart.actualData[currentDatachartIndex] + const compareDataload = currentDatachart.comparisonData ? currentDatachart.comparisonData[currentDatachartIndex] : null @@ -38,7 +43,7 @@ const ConsumptionVisualizer = ({ fluidType }: { fluidType: FluidType }) => { } return lastDay } - const lastDataDate: DateTime | null = getLastDataDate() + const lastDataDate = getLastDataDate() return ( <div className="consumptionvisualizer-root"> @@ -46,12 +51,14 @@ const ConsumptionVisualizer = ({ fluidType }: { fluidType: FluidType }) => { fluidType={fluidType} dataload={dataload} compareDataload={compareDataload} + focusable={focusable} /> <div className="consumptionvisualizer-info"> <InfoDataConsumptionVisualizer dataload={dataload} fluidType={fluidType} lastDataDate={lastDataDate} + focusable={focusable} /> </div> </div> diff --git a/src/components/ConsumptionVisualizer/DataloadConsumptionVisualizer.tsx b/src/components/ConsumptionVisualizer/DataloadConsumptionVisualizer.tsx index 6e38fa737..70162cd08 100644 --- a/src/components/ConsumptionVisualizer/DataloadConsumptionVisualizer.tsx +++ b/src/components/ConsumptionVisualizer/DataloadConsumptionVisualizer.tsx @@ -12,11 +12,13 @@ interface DataloadConsumptionVisualizerProps { fluidType: FluidType dataload: Dataload compareDataload: Dataload | null + focusable?: boolean } const DataloadConsumptionVisualizer = ({ fluidType, dataload, compareDataload, + focusable, }: DataloadConsumptionVisualizerProps) => { const { showCompare } = useAppSelector(state => state.ecolyo.chart) const [openEstimationModal, setOpenEstimationModal] = useState<boolean>(false) @@ -35,7 +37,11 @@ const DataloadConsumptionVisualizer = ({ ) { return ( <div className="dataloadvisualizer-root"> - <DataloadNoValue dataload={dataload} fluidType={fluidType} /> + <DataloadNoValue + dataload={dataload} + fluidType={fluidType} + focusable={focusable} + /> </div> ) } @@ -50,12 +56,14 @@ const DataloadConsumptionVisualizer = ({ fluidType={fluidType} dataloadSectionType={DataloadSectionType.LEFT} toggleEstimationModal={toggleEstimationModal} + focusable={focusable} /> <DataloadSection dataload={dataload} fluidType={fluidType} dataloadSectionType={DataloadSectionType.RIGHT} toggleEstimationModal={toggleEstimationModal} + focusable={focusable} /> </> ) : ( @@ -64,6 +72,7 @@ const DataloadConsumptionVisualizer = ({ fluidType={fluidType} dataloadSectionType={DataloadSectionType.NO_COMPARE} toggleEstimationModal={toggleEstimationModal} + focusable={focusable} /> )} </div> diff --git a/src/components/ConsumptionVisualizer/DataloadNoValue.tsx b/src/components/ConsumptionVisualizer/DataloadNoValue.tsx index 759881315..7de7e5c1b 100644 --- a/src/components/ConsumptionVisualizer/DataloadNoValue.tsx +++ b/src/components/ConsumptionVisualizer/DataloadNoValue.tsx @@ -11,9 +11,14 @@ import './consumptionVisualizer.scss' interface DataloadNoValueProps { dataload: Dataload fluidType: FluidType + focusable?: boolean } -const DataloadNoValue = ({ dataload, fluidType }: DataloadNoValueProps) => { +const DataloadNoValue = ({ + dataload, + fluidType, + focusable, +}: DataloadNoValueProps) => { const { t } = useI18n() const dispatch = useAppDispatch() const fluidName = getFluidName(fluidType) @@ -63,6 +68,7 @@ const DataloadNoValue = ({ dataload, fluidType }: DataloadNoValueProps) => { <Button onClick={handleToggleKonnectorCard} classes={{ root: 'btnText', label: 'text-22-normal' }} + tabIndex={focusable ? 0 : -1} > {t('consumption_visualizer.missing_data')} </Button> diff --git a/src/components/ConsumptionVisualizer/DataloadSection.tsx b/src/components/ConsumptionVisualizer/DataloadSection.tsx index 84a6185ee..2416505bb 100644 --- a/src/components/ConsumptionVisualizer/DataloadSection.tsx +++ b/src/components/ConsumptionVisualizer/DataloadSection.tsx @@ -13,12 +13,14 @@ interface DataloadSectionProps { fluidType: FluidType dataloadSectionType: DataloadSectionType toggleEstimationModal: () => void + focusable?: boolean } const DataloadSection = ({ dataload, fluidType, dataloadSectionType, toggleEstimationModal, + focusable, }: DataloadSectionProps) => { const { t } = useI18n() const isLeft = dataloadSectionType === DataloadSectionType.LEFT @@ -59,12 +61,14 @@ const DataloadSection = ({ fluidType={fluidType} dataloadSectionType={dataloadSectionType} toggleEstimationModal={toggleEstimationModal} + focusable={focusable} /> </div> <DataloadSectionDetail dataload={dataload} fluidType={fluidType} dataloadSectionType={dataloadSectionType} + focusable={focusable} /> </div> ) diff --git a/src/components/ConsumptionVisualizer/DataloadSectionDetail.tsx b/src/components/ConsumptionVisualizer/DataloadSectionDetail.tsx index 8be010a5e..e2644b135 100644 --- a/src/components/ConsumptionVisualizer/DataloadSectionDetail.tsx +++ b/src/components/ConsumptionVisualizer/DataloadSectionDetail.tsx @@ -13,12 +13,14 @@ interface DataloadSectionDetailProps { dataload: Dataload fluidType: FluidType dataloadSectionType: DataloadSectionType + focusable?: boolean } const DataloadSectionDetail = ({ dataload, fluidType, dataloadSectionType, + focusable, }: DataloadSectionDetailProps) => { const { t } = useI18n() const converterService = new ConverterService() @@ -71,6 +73,7 @@ const DataloadSectionDetail = ({ )} to={`/consumption/${FluidType[index].toLowerCase()}`} className="dataloadvisualizer-euro-link" + tabIndex={focusable ? 0 : -1} > <div className={classNames('dataloadvisualizer-euro-fluid', { @@ -104,6 +107,7 @@ const DataloadSectionDetail = ({ <NavLink to={`/consumption/${getFluidName(fluidType)}`} className="dataloadvisualizer-euro-link" + tabIndex={focusable ? 0 : -1} > <div className={`dataloadvisualizer-euro-fluid ${getFluidName(fluidType)}`} diff --git a/src/components/ConsumptionVisualizer/DataloadSectionValue.tsx b/src/components/ConsumptionVisualizer/DataloadSectionValue.tsx index 77e227da2..296992ea0 100644 --- a/src/components/ConsumptionVisualizer/DataloadSectionValue.tsx +++ b/src/components/ConsumptionVisualizer/DataloadSectionValue.tsx @@ -10,6 +10,7 @@ interface DataloadSectionValueProps { fluidType: FluidType dataloadSectionType: DataloadSectionType toggleEstimationModal: () => void + focusable?: boolean } const DataloadSectionValue = ({ @@ -17,6 +18,7 @@ const DataloadSectionValue = ({ fluidType, dataloadSectionType, toggleEstimationModal, + focusable, }: DataloadSectionValueProps) => { const { t } = useI18n() const FLUIDNAME = getFluidName(fluidType).toUpperCase() @@ -36,6 +38,7 @@ const DataloadSectionValue = ({ }} size="small" onClick={toggleEstimationModal} + tabIndex={focusable ? 0 : -1} > {t('consumption_visualizer.estimated')} </Button> diff --git a/src/components/ConsumptionVisualizer/InfoDataConsumptionVisualizer.tsx b/src/components/ConsumptionVisualizer/InfoDataConsumptionVisualizer.tsx index c3a9b1a08..a44539136 100644 --- a/src/components/ConsumptionVisualizer/InfoDataConsumptionVisualizer.tsx +++ b/src/components/ConsumptionVisualizer/InfoDataConsumptionVisualizer.tsx @@ -12,12 +12,14 @@ interface InfoDataConsumptionVisualizerProps { dataload: Dataload fluidType: FluidType lastDataDate: DateTime | null + focusable?: boolean } const InfoDataConsumptionVisualizer = ({ dataload, fluidType, lastDataDate, + focusable, }: InfoDataConsumptionVisualizerProps) => { const { t } = useI18n() const [openNoDataModal, setOpenNoDataModal] = useState<boolean>(false) @@ -41,7 +43,11 @@ const InfoDataConsumptionVisualizer = ({ ? 'last_valid_data_multi' : 'last_available_data' return ( - <Button className="btnText" onClick={moveToLatestDate}> + <Button + className="btnText" + onClick={moveToLatestDate} + tabIndex={focusable ? 0 : -1} + > {t(`consumption_visualizer.${key}`, { date: lastDate, })} @@ -56,7 +62,11 @@ const InfoDataConsumptionVisualizer = ({ ) { return ( <> - <Button className="btnText" onClick={() => setOpenNoDataModal(true)}> + <Button + className="btnText" + onClick={() => setOpenNoDataModal(true)} + tabIndex={focusable ? 0 : -1} + > <span className="text-16-normal underlined-error"> {t('consumption_visualizer.why_no_data')} </span> diff --git a/src/components/ConsumptionVisualizer/__snapshots__/InfoDataConsumptionVisualizer.spec.tsx.snap b/src/components/ConsumptionVisualizer/__snapshots__/InfoDataConsumptionVisualizer.spec.tsx.snap index 41ed4044a..f17d502b2 100644 --- a/src/components/ConsumptionVisualizer/__snapshots__/InfoDataConsumptionVisualizer.spec.tsx.snap +++ b/src/components/ConsumptionVisualizer/__snapshots__/InfoDataConsumptionVisualizer.spec.tsx.snap @@ -4,7 +4,7 @@ exports[`InfoDataConsumptionVisualizer component should render correctly when da <div> <button class="MuiButtonBase-root MuiButton-root MuiButton-text btnText" - tabindex="0" + tabindex="-1" type="button" > <span diff --git a/src/components/FluidChart/FluidChartSlide.tsx b/src/components/FluidChart/FluidChartSlide.tsx index ddeff8b14..334de391f 100644 --- a/src/components/FluidChart/FluidChartSlide.tsx +++ b/src/components/FluidChart/FluidChartSlide.tsx @@ -34,6 +34,9 @@ const FluidChartSlide = ({ global: { fluidStatus, fluidTypes }, } = useAppSelector(state => state.ecolyo) + /** Determines if child elements should be focusable */ + const focusable = currentIndex === index + const [chartData, setChartData] = useState<Datachart>({ actualData: [], comparisonData: null, @@ -117,7 +120,7 @@ const FluidChartSlide = ({ </div> ) : ( <> - <ConsumptionVisualizer fluidType={fluidType} /> + <ConsumptionVisualizer fluidType={fluidType} focusable={focusable} /> <BarChart chartData={chartData} fluidType={fluidType} diff --git a/src/components/FluidChart/FluidChartSwipe.tsx b/src/components/FluidChart/FluidChartSwipe.tsx index 846e0225e..ecd686e22 100644 --- a/src/components/FluidChart/FluidChartSwipe.tsx +++ b/src/components/FluidChart/FluidChartSwipe.tsx @@ -1,7 +1,6 @@ import FluidChartSlide from 'components/FluidChart/FluidChartSlide' import { useChartResize } from 'components/Hooks/useChartResize' import { FluidType } from 'enums' -import { DateTime } from 'luxon' import React, { useEffect, useRef, useState } from 'react' import SwipeableViews from 'react-swipeable-views' import { virtualize } from 'react-swipeable-views-utils' @@ -36,12 +35,12 @@ const FluidChartSwipe = ({ fluidType }: { fluidType: FluidType }) => { currentIndex ) } - const updatedDate: DateTime = dateChartService.incrementDate( + const updatedDate = dateChartService.incrementDate( currentTimeStep, selectedDate, increment ) - const updatedIndex: number = dateChartService.defineDateIndex( + const updatedIndex = dateChartService.defineDateIndex( currentTimeStep, updatedDate ) @@ -84,9 +83,7 @@ const FluidChartSwipe = ({ fluidType }: { fluidType: FluidType }) => { slideRenderer={({ key, index }) => slideRenderer(key, index)} enableMouseEvents onSwitching={!isSwitching ? () => setIsSwitching(true) : null} - onTransitionEnd={() => { - setIsSwitching(false) - }} + onTransitionEnd={() => setIsSwitching(false)} axis="x-reverse" /> </div> -- GitLab