Skip to content

Commit 8a23778

Browse files
juliajforestiCopilot
andauthored
fix(a11y): ensure accessibility compliance in non-admin forms (RocketChat#40256)
Co-authored-by: Copilot <copilot@github.com>
1 parent 22c8d32 commit 8a23778

21 files changed

Lines changed: 364 additions & 575 deletions

File tree

apps/meteor/client/components/CreateDiscussion/CreateDiscussion.tsx

Lines changed: 24 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,21 @@
11
import type { IMessage, IRoom, IUser } from '@rocket.chat/core-typings';
2+
import { Icon, Box } from '@rocket.chat/fuselage';
23
import {
34
Field,
45
FieldGroup,
56
ToggleSwitch,
67
TextInput,
78
TextAreaInput,
8-
Icon,
9-
Box,
109
FieldHint,
1110
FieldLabel,
1211
FieldRow,
1312
FieldError,
14-
} from '@rocket.chat/fuselage';
13+
} from '@rocket.chat/fuselage-forms';
1514
import { useEffectEvent } from '@rocket.chat/fuselage-hooks';
1615
import { GenericModal } from '@rocket.chat/ui-client';
1716
import { useTranslation, useEndpoint } from '@rocket.chat/ui-contexts';
1817
import { useMutation } from '@tanstack/react-query';
19-
import { useId, useState } from 'react';
18+
import { useState } from 'react';
2019
import { useForm, Controller } from 'react-hook-form';
2120

2221
import { useEncryptedRoomDescription } from '../../navbar/NavBarPagesGroup/actions/useEncryptedRoomDescription';
@@ -105,13 +104,6 @@ const CreateDiscussion = ({
105104

106105
const getEncryptedHint = useEncryptedRoomDescription('discussion');
107106

108-
const parentRoomId = useId();
109-
const encryptedId = useId();
110-
const discussionNameId = useId();
111-
const membersId = useId();
112-
const firstMessageId = useId();
113-
const topicId = useId();
114-
115107
return (
116108
<GenericModal
117109
variant='warning'
@@ -126,141 +118,94 @@ const CreateDiscussion = ({
126118
<Box mbe={24}>{t('Discussion_description')}</Box>
127119
<FieldGroup>
128120
<Field>
129-
<FieldLabel htmlFor={parentRoomId} required>
130-
{t('Discussion_target_channel')}
131-
</FieldLabel>
121+
<FieldLabel required>{t('Discussion_target_channel')}</FieldLabel>
132122
<FieldRow>
133123
{defaultParentRoom && (
134124
<Controller
135125
control={control}
136126
name='parentRoom'
137-
render={() => <DefaultParentRoomField defaultParentRoom={defaultParentRoom} id={parentRoomId} />}
127+
render={({ field }) => <DefaultParentRoomField {...field} defaultParentRoom={defaultParentRoom} required={true} />}
138128
/>
139129
)}
140130
{!defaultParentRoom && (
141131
<Controller
142132
control={control}
143133
name='parentRoom'
144134
rules={{ required: t('Required_field', { field: t('Discussion_target_channel') }) }}
145-
render={({ field: { name, onBlur, onChange, value } }) => (
135+
render={({ field }) => (
146136
<RoomAutoComplete
147-
name={name}
148-
onBlur={onBlur}
149-
onChange={onChange}
150-
value={value}
151-
id={parentRoomId}
137+
{...field}
138+
error={Boolean(errors.parentRoom?.message)}
152139
placeholder={t('Search_options')}
153140
disabled={Boolean(defaultParentRoom)}
154-
aria-invalid={Boolean(errors.parentRoom)}
155141
aria-required='true'
156-
aria-describedby={`${parentRoomId}-error`}
157142
setSelectedRoom={onParentRoomChange}
158143
renderRoomIcon={({ encrypted }) => (encrypted ? <Icon name='key' /> : null)}
159144
/>
160145
)}
161146
/>
162147
)}
163148
</FieldRow>
164-
{errors.parentRoom && (
165-
<FieldError role='alert' id={`${parentRoomId}-error`}>
166-
{errors.parentRoom.message}
167-
</FieldError>
168-
)}
149+
{errors.parentRoom && <FieldError>{errors.parentRoom.message}</FieldError>}
169150
</Field>
170151
<Field>
171-
<FieldLabel htmlFor={discussionNameId} required>
172-
{t('Name')}
173-
</FieldLabel>
152+
<FieldLabel required>{t('Name')}</FieldLabel>
174153
<FieldRow>
175154
<Controller
176155
name='name'
177156
control={control}
178157
rules={{ required: t('Required_field', { field: t('Name') }) }}
179158
render={({ field }) => (
180-
<TextInput
181-
id={discussionNameId}
182-
{...field}
183-
aria-invalid={Boolean(errors.name)}
184-
aria-required='true'
185-
aria-describedby={errors.name ? `${discussionNameId}-error` : undefined}
186-
addon={<Icon name='baloons' size='x20' />}
187-
/>
159+
<TextInput {...field} aria-required='true' addon={<Icon name='baloons' size='x20' />} error={errors.name?.message} />
188160
)}
189161
/>
190162
</FieldRow>
191-
{errors.name && (
192-
<FieldError role='alert' id={`${discussionNameId}-error`}>
193-
{errors.name.message}
194-
</FieldError>
195-
)}
163+
{errors.name && <FieldError>{errors.name.message}</FieldError>}
196164
</Field>
197165
<Field>
198-
<FieldLabel htmlFor={topicId}>{t('Topic')}</FieldLabel>
166+
<FieldLabel>{t('Topic')}</FieldLabel>
199167
<FieldRow>
200-
<Controller
201-
name='topic'
202-
control={control}
203-
render={({ field }) => <TextInput id={topicId} {...field} aria-describedby={`${topicId}-hint`} />}
204-
/>
168+
<Controller name='topic' control={control} render={({ field }) => <TextInput {...field} error={errors.topic?.message} />} />
205169
</FieldRow>
206170
<FieldRow>
207-
<FieldHint id={`${topicId}-hint`}>{t('Displayed_next_to_name')}</FieldHint>
171+
<FieldHint>{t('Displayed_next_to_name')}</FieldHint>
208172
</FieldRow>
209173
</Field>
210174
<Field>
211-
<FieldLabel htmlFor={membersId}>{t('Members')}</FieldLabel>
175+
<FieldLabel>{t('Members')}</FieldLabel>
212176
<FieldRow>
213177
<Controller
214178
control={control}
215179
name='usernames'
216-
render={({ field: { name, onChange, value, onBlur } }) => (
217-
<UserAutoCompleteMultiple
218-
id={membersId}
219-
name={name}
220-
onChange={onChange}
221-
value={value}
222-
onBlur={onBlur}
223-
placeholder={t('Add_people')}
224-
/>
225-
)}
180+
render={({ field }) => <UserAutoCompleteMultiple {...field} placeholder={t('Add_people')} />}
226181
/>
227182
</FieldRow>
228183
</Field>
229184
<Field>
230-
<FieldLabel htmlFor={firstMessageId}>{t('Discussion_first_message_title')}</FieldLabel>
185+
<FieldLabel>{t('Discussion_first_message_title')}</FieldLabel>
231186
<FieldRow>
232187
<Controller
233188
control={control}
234189
name='firstMessage'
235-
render={({ field }) => (
236-
<TextAreaInput
237-
id={firstMessageId}
238-
{...field}
239-
rows={5}
240-
disabled={encrypted}
241-
aria-describedby={encrypted ? `${firstMessageId}-encrypted-hint` : `${firstMessageId}-hint`}
242-
/>
243-
)}
190+
render={({ field }) => <TextAreaInput {...field} rows={5} disabled={encrypted} />}
244191
/>
245192
</FieldRow>
246193
{encrypted ? (
247-
<FieldHint id={`${firstMessageId}-encrypted-hint`}>{t('Discussion_first_message_disabled_due_to_e2e')}</FieldHint>
194+
<FieldHint>{t('Discussion_first_message_disabled_due_to_e2e')}</FieldHint>
248195
) : (
249-
<FieldHint id={`${firstMessageId}-hint`}>{t('First_message_hint')}</FieldHint>
196+
<FieldHint>{t('First_message_hint')}</FieldHint>
250197
)}
251198
</Field>
252199
<Field>
253200
<FieldRow>
254-
<FieldLabel htmlFor={encryptedId}>{t('Encrypted')}</FieldLabel>
201+
<FieldLabel>{t('Encrypted')}</FieldLabel>
255202
<Controller
256203
control={control}
257204
name='encrypted'
258-
render={({ field: { value, ...field } }) => (
259-
<ToggleSwitch id={encryptedId} {...field} checked={value} disabled={encryptedDisabled} />
260-
)}
205+
render={({ field: { value, ...field } }) => <ToggleSwitch {...field} checked={value} disabled={encryptedDisabled} />}
261206
/>
262207
</FieldRow>
263-
<FieldHint id={`${encryptedId}-hint`}>{getEncryptedHint({ isPrivate: true, encrypted })}</FieldHint>
208+
<FieldHint>{getEncryptedHint({ isPrivate: true, encrypted })}</FieldHint>
264209
</Field>
265210
</FieldGroup>
266211
</GenericModal>

apps/meteor/client/components/CreateDiscussion/DefaultParentRoomField.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { Skeleton, TextInput, Callout } from '@rocket.chat/fuselage';
1+
import { Skeleton, Callout } from '@rocket.chat/fuselage';
2+
import { TextInput } from '@rocket.chat/fuselage-forms';
23
import { useTranslation, useEndpoint } from '@rocket.chat/ui-contexts';
34
import { useQuery } from '@tanstack/react-query';
45
import type { ComponentPropsWithoutRef } from 'react';

0 commit comments

Comments
 (0)