Correctifs RGAA (#2416)

* fix: id et for manquants, role img sur svg

* feat: Ajoute une confirmation sur le bouton de suppression des données

* fix: Ajoute un id et un label sur le champ select caché

* fix: Ajoute id et label

* fix: Corrige title

* fix: Hierarchie titre
pull/2428/head
Benjamin Arias 2022-12-16 12:41:23 +01:00 committed by GitHub
parent be031035f6
commit 5dff6b1fa2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 82 additions and 38 deletions

View File

@ -44,7 +44,8 @@ export default function ChiffreAffairesActivitéMixte({
}, [dispatch])
return (
<fieldset aria-label={t("Chiffre d'affaires")}>
<fieldset>
<legend className="sr-only">{t("Chiffre d'affaires")}</legend>
<SimulationGoal
appear={false}
onUpdateSituation={clearChiffreAffaireMixte}

View File

@ -28,6 +28,8 @@ export default function SearchButton() {
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden
role="img"
>
<path
strokeLinecap="square"

View File

@ -152,14 +152,21 @@ export default function AnswerList({ onClose, children }: AnswerListProps) {
<Body>
Les réponses liées à l'entreprise sont automatiquement
sauvegardées d'une simulation à l'autre.{' '}
<Link
onPress={() => {
<PopoverConfirm
small
trigger={(buttonProps) => (
<Link {...buttonProps}>
<Trans>Supprimer les données sauvegardées.</Trans>{' '}
</Link>
)}
onConfirm={() => {
dispatch(resetSimulation())
dispatch(resetCompany())
}}
>
<Trans>Supprimer les données sauvegardées.</Trans>{' '}
</Link>
title={t(
'Attention, vos données sauvegardées seront supprimées de manière définitive.'
)}
></PopoverConfirm>
</Body>
</Message>
</div>

View File

@ -28,7 +28,7 @@ import {
} from '@/design-system'
import { Item, Select } from '@/design-system/field/Select'
import { Spacing } from '@/design-system/layout'
import { H4 } from '@/design-system/typography/heading'
import { H3, H4 } from '@/design-system/typography/heading'
import { ExplicableRule } from './Explicable'
import { InputProps } from './RuleInput'
@ -174,12 +174,16 @@ function RadioChoice<Names extends string = DottedName>({
) ? null : 'children' in node ? (
<div
role="group"
aria-labelledby={node.dottedName + '-legend'}
aria-labelledby={
node.dottedName.replace(/\s|\./g, '') + '-legend'
}
css={`
margin-top: -1rem;
`}
>
<H4 id={node.dottedName + '-legend'}>{node.title}</H4>
<H4 as={H3} id={node.dottedName + '-legend'}>
{node.title}
</H4>
<Spacing lg />
<StyledSubRadioGroup>
<RadioChoice
@ -212,6 +216,10 @@ function RadioChoice<Names extends string = DottedName>({
rootDottedName,
node.dottedName
)}'`}
id={`radio-input-${relativeDottedName(
rootDottedName,
node.dottedName
).replace(/\s|\./g, '')}`}
>
{node.title}{' '}
{node.rawNode.icônes && <Emoji emoji={node.rawNode.icônes} />}
@ -264,11 +272,19 @@ export function OuiNonInput<Names extends string = DottedName>(
value={currentSelection ?? undefined}
>
{/* eslint-disable-next-line jsx-a11y/no-autofocus */}
<Radio value="oui" autoFocus={props.autoFocus && defaultValue === 'oui'}>
<Radio
value="oui"
id={`input-oui-${props.id || ''}`}
autoFocus={props.autoFocus && defaultValue === 'oui'}
>
<Trans>Oui</Trans>
</Radio>
{/* eslint-disable-next-line jsx-a11y/no-autofocus */}
<Radio value="non" autoFocus={props.autoFocus && defaultValue === 'non'}>
<Radio
value="non"
id={`input-non-${props.id || ''}`}
autoFocus={props.autoFocus && defaultValue === 'non'}
>
<Trans>Non</Trans>
</Radio>
</ToggleGroup>

View File

@ -115,6 +115,11 @@ export default function Conversation({
</H3>
</div>
<fieldset>
<legend className="sr-only">
{t(
'Répondez à quelques questions additionnelles afin de préciser votre résultat.'
)}
</legend>
<RuleInput
dottedName={currentQuestion}
onChange={onChange}
@ -127,6 +132,7 @@ export default function Conversation({
<button
aria-hidden
className="sr-only"
aria-label={t('Valider')}
type="submit"
tabIndex={-1}
/>

View File

@ -19,6 +19,8 @@ export const SearchBox = connectSearchBox(
'recherche-globale.placeholder',
'Mot-clé ou acronyme (ex : CSG)'
)}
aria-label={t('Rechercher une règle de calcul dans la documentation')}
id="input-recherche-globale"
isSearchStalled={isSearchStalled}
{...props}
/>

View File

@ -34,7 +34,13 @@ export default function ButtonHelp({
{...buttonProps}
{...props}
>
<CircleIcon aria-hidden width="24" height="24" viewBox="0 0 24 24">
<CircleIcon
aria-hidden
width="24"
height="24"
viewBox="0 0 24 24"
role="img"
>
{type === 'info' ? (
<path
fillRule="evenodd"

View File

@ -15,12 +15,12 @@ type RadioProps = AriaRadioProps & {
}
export function Radio(props: RadioProps) {
const { hideRadio, children } = props
const { hideRadio, children, id } = props
return (
<RadioSkeleton role="radio" aria-atomic {...props}>
{!hideRadio && <RadioPoint />}
<LabelBody as="span" $hideRadio={hideRadio}>
<LabelBody as="span" for={id} $hideRadio={hideRadio}>
{children}
</LabelBody>
</RadioSkeleton>
@ -28,7 +28,7 @@ export function Radio(props: RadioProps) {
}
export const RadioSkeleton = (props: RadioProps) => {
const { hideRadio, ...ariaProps } = props
const { hideRadio, id, ...ariaProps } = props
const { children } = ariaProps
const state = useContext(RadioContext)
if (!state) {
@ -39,8 +39,8 @@ export const RadioSkeleton = (props: RadioProps) => {
const { inputProps } = useRadio(ariaProps, state, ref)
return (
<Label $hideRadio={hideRadio} className={props.className}>
<InputRadio {...inputProps} className="sr-only" ref={ref} />
<Label $hideRadio={hideRadio} for={id} className={props.className}>
<InputRadio {...inputProps} className="sr-only" ref={ref} id={id} />
<VisibleRadio>{children}</VisibleRadio>
</Label>
)
@ -53,7 +53,7 @@ export const RadioPoint = ({ className }: { className?: string }) => (
</RadioButton>
)
const Label = styled.label<{ $hideRadio?: boolean }>`
const Label = styled.label<{ $hideRadio?: boolean; for?: string }>`
${({ $hideRadio }) =>
$hideRadio &&
css`
@ -129,7 +129,7 @@ export const VisibleRadio = styled.span`
}
`
export const LabelBody = styled(Body)<{ $hideRadio?: boolean }>`
export const LabelBody = styled(Body)<{ $hideRadio?: boolean; for?: string }>`
margin: ${({ theme }) => theme.spacings.xs} 0px;
margin-left: ${({ theme }) => theme.spacings.xxs};
${({ $hideRadio }) =>

View File

@ -9,6 +9,7 @@ import { useTranslation } from 'react-i18next'
import styled, { css } from 'styled-components'
import { CarretDown } from '@/design-system/icons/carret-down'
import { omit } from '@/utils'
import { ListBox } from './ListBox'
import { Popover } from './PopOver'
@ -225,6 +226,17 @@ export function Select<T extends Record<string, unknown>>(
})
}, [])
// Fix : Asqatasun détecte 2 violations au niveau du hidden select
// pas moyen d'accéder aux props de manière plus propre rapidement
useEffect(() => {
const selectInput = wrapperRef?.current?.querySelector('input')
if (selectInput) {
selectInput.setAttribute('id', buttonProps.id || '')
selectInput.setAttribute('aria-label', 'Hidden select input')
}
}, [])
return (
<Wrapper
ref={wrapperRef}
@ -244,7 +256,7 @@ export function Select<T extends Record<string, unknown>>(
</Label>
)}
<Button
{...mergeProps(buttonProps, focusProps)}
{...mergeProps(omit(buttonProps, 'id'), focusProps)}
ref={ref}
isFocusVisible={isFocusVisible}
>

View File

@ -49,7 +49,7 @@ export default function PopoverConfirm({
<Button
onPress={() => {
closePopover()
onConfirm()
setTimeout(() => onConfirm())
}}
>
{confirmLabel}

View File

@ -31,14 +31,11 @@ export default function Créer() {
<TrackPage name="accueil" />
<Meta
page="créer"
title="Créer"
title={t('créer.titre', 'Créer une entreprise')}
description="Créer une entreprise"
ogImage={créerSvg}
/>
<DefaultHelmet>
<title>{t('créer.titre', 'Créer une entreprise')}</title>
</DefaultHelmet>
<PageHeader
titre={<Trans i18nKey="créer.titre">Créer une entreprise</Trans>}
picture={créerSvg}

View File

@ -32,13 +32,10 @@ export default function Simulateurs() {
<TrackPage chapter1="simulateurs" name="accueil" />
<Meta
page="simulateurs"
title="simulateurs"
title={titre}
description="Tous les simulateurs sur ce site sont maintenus à jour avec les dernières évolutions législatives."
ogImage={simulatorSvg}
/>
<DefaultHelmet>
<title>{titre}</title>
</DefaultHelmet>
<PageHeader titre={titre} picture={simulatorSvg}>
<Intro>
<Trans i18nKey="pages.simulateurs.accueil.header">

View File

@ -490,6 +490,7 @@ function SimulateursChoice(props: {
}}
defaultSelectedKey={props.value}
label={'Sélectionner la fonctionnalité'}
id="simulator-choice-input"
>
{[
<Item key={''} textValue="Tout le site">

View File

@ -2,7 +2,6 @@ import { utils } from 'publicodes'
import { Trans, useTranslation } from 'react-i18next'
import Value, { Condition } from '@/components/EngineValue'
import RuleLink from '@/components/RuleLink'
import { FromTop } from '@/components/ui/animate'
import Emoji from '@/components/utils/Emoji'
import { useEngine } from '@/components/utils/EngineContext'
@ -80,14 +79,12 @@ export default function ResultatsSimples() {
</Condition>{' '}
</H3>
<Intro>
<RuleLink dottedName={r.dottedName}>
<Value
expression={r.dottedName}
displayedUnit="€"
unit="€/an"
precision={0}
/>
</RuleLink>
<Value
expression={r.dottedName}
displayedUnit="€"
unit="€/an"
precision={0}
/>
</Intro>
{r.rawNode.description && (