Skip to content

Commit 4e93079

Browse files
authored
Merge pull request #4886 from element-hq/feature/bma/a11yRichTextEditor
a11y: improve accessibility on rich text editor options.
2 parents 6c84482 + f95b38d commit 4e93079

File tree

2 files changed

+38
-4
lines changed

2 files changed

+38
-4
lines changed

libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/FormattingOption.kt

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
1313
import androidx.compose.foundation.layout.Box
1414
import androidx.compose.foundation.layout.Row
1515
import androidx.compose.foundation.layout.size
16+
import androidx.compose.foundation.selection.toggleable
1617
import androidx.compose.foundation.shape.RoundedCornerShape
1718
import androidx.compose.material3.ripple
1819
import androidx.compose.runtime.Composable
@@ -21,6 +22,8 @@ import androidx.compose.ui.Alignment
2122
import androidx.compose.ui.Modifier
2223
import androidx.compose.ui.graphics.Color
2324
import androidx.compose.ui.graphics.vector.ImageVector
25+
import androidx.compose.ui.semantics.clearAndSetSemantics
26+
import androidx.compose.ui.semantics.contentDescription
2427
import androidx.compose.ui.unit.dp
2528
import io.element.android.compound.theme.ElementTheme
2629
import io.element.android.compound.tokens.generated.CompoundIcons
@@ -32,9 +35,10 @@ import io.element.android.libraries.designsystem.theme.iconSuccessPrimaryBackgro
3235
@Composable
3336
internal fun FormattingOption(
3437
state: FormattingOptionState,
38+
toggleable: Boolean,
3539
onClick: () -> Unit,
3640
imageVector: ImageVector,
37-
contentDescription: String?,
41+
contentDescription: String,
3842
modifier: Modifier = Modifier,
3943
) {
4044
val backgroundColor = when (state) {
@@ -52,13 +56,28 @@ internal fun FormattingOption(
5256
modifier = modifier
5357
.clickable(
5458
onClick = onClick,
59+
enabled = state != FormattingOptionState.Disabled,
5560
interactionSource = remember { MutableInteractionSource() },
5661
indication = ripple(
5762
bounded = false,
5863
radius = 20.dp,
5964
),
6065
)
6166
.size(48.dp)
67+
.then(
68+
if (toggleable) {
69+
Modifier.toggleable(
70+
value = state == FormattingOptionState.Selected,
71+
enabled = state != FormattingOptionState.Disabled,
72+
onValueChange = { onClick() },
73+
)
74+
} else {
75+
Modifier
76+
}
77+
)
78+
.clearAndSetSemantics {
79+
this.contentDescription = contentDescription
80+
}
6281
) {
6382
Box(
6483
modifier = Modifier
@@ -84,21 +103,24 @@ internal fun FormattingOptionPreview() = ElementPreview {
84103
Row {
85104
FormattingOption(
86105
state = FormattingOptionState.Default,
106+
toggleable = false,
87107
onClick = { },
88108
imageVector = CompoundIcons.Bold(),
89-
contentDescription = null,
109+
contentDescription = "",
90110
)
91111
FormattingOption(
92112
state = FormattingOptionState.Selected,
113+
toggleable = true,
93114
onClick = { },
94115
imageVector = CompoundIcons.Italic(),
95-
contentDescription = null,
116+
contentDescription = "",
96117
)
97118
FormattingOption(
98119
state = FormattingOptionState.Disabled,
120+
toggleable = false,
99121
onClick = { },
100122
imageVector = CompoundIcons.Underline(),
101-
contentDescription = null,
123+
contentDescription = "",
102124
)
103125
}
104126
}

libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/TextFormatting.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,24 +104,28 @@ internal fun TextFormatting(
104104
) {
105105
FormattingOption(
106106
state = state.actions[ComposerAction.BOLD].toButtonState(),
107+
toggleable = true,
107108
onClick = { onInlineFormatClick(InlineFormat.Bold) },
108109
imageVector = CompoundIcons.Bold(),
109110
contentDescription = stringResource(R.string.rich_text_editor_format_bold)
110111
)
111112
FormattingOption(
112113
state = state.actions[ComposerAction.ITALIC].toButtonState(),
114+
toggleable = true,
113115
onClick = { onInlineFormatClick(InlineFormat.Italic) },
114116
imageVector = CompoundIcons.Italic(),
115117
contentDescription = stringResource(R.string.rich_text_editor_format_italic)
116118
)
117119
FormattingOption(
118120
state = state.actions[ComposerAction.UNDERLINE].toButtonState(),
121+
toggleable = true,
119122
onClick = { onInlineFormatClick(InlineFormat.Underline) },
120123
imageVector = CompoundIcons.Underline(),
121124
contentDescription = stringResource(R.string.rich_text_editor_format_underline)
122125
)
123126
FormattingOption(
124127
state = state.actions[ComposerAction.STRIKE_THROUGH].toButtonState(),
128+
toggleable = true,
125129
onClick = { onInlineFormatClick(InlineFormat.StrikeThrough) },
126130
imageVector = CompoundIcons.Strikethrough(),
127131
contentDescription = stringResource(R.string.rich_text_editor_format_strikethrough)
@@ -141,49 +145,57 @@ internal fun TextFormatting(
141145

142146
FormattingOption(
143147
state = state.actions[ComposerAction.LINK].toButtonState(),
148+
toggleable = true,
144149
onClick = { linkDialogAction = state.linkAction },
145150
imageVector = CompoundIcons.Link(),
146151
contentDescription = stringResource(R.string.rich_text_editor_link)
147152
)
148153

149154
FormattingOption(
150155
state = state.actions[ComposerAction.UNORDERED_LIST].toButtonState(),
156+
toggleable = true,
151157
onClick = { onToggleListClick(ordered = false) },
152158
imageVector = CompoundIcons.ListBulleted(),
153159
contentDescription = stringResource(R.string.rich_text_editor_bullet_list)
154160
)
155161
FormattingOption(
156162
state = state.actions[ComposerAction.ORDERED_LIST].toButtonState(),
163+
toggleable = true,
157164
onClick = { onToggleListClick(ordered = true) },
158165
imageVector = CompoundIcons.ListNumbered(),
159166
contentDescription = stringResource(R.string.rich_text_editor_numbered_list)
160167
)
161168
FormattingOption(
162169
state = state.actions[ComposerAction.INDENT].toButtonState(),
170+
toggleable = false,
163171
onClick = { onIndentClick() },
164172
imageVector = CompoundIcons.IndentIncrease(),
165173
contentDescription = stringResource(R.string.rich_text_editor_indent)
166174
)
167175
FormattingOption(
168176
state = state.actions[ComposerAction.UNINDENT].toButtonState(),
177+
toggleable = false,
169178
onClick = { onUnindentClick() },
170179
imageVector = CompoundIcons.IndentDecrease(),
171180
contentDescription = stringResource(R.string.rich_text_editor_unindent)
172181
)
173182
FormattingOption(
174183
state = state.actions[ComposerAction.INLINE_CODE].toButtonState(),
184+
toggleable = true,
175185
onClick = { onInlineFormatClick(InlineFormat.InlineCode) },
176186
imageVector = CompoundIcons.InlineCode(),
177187
contentDescription = stringResource(R.string.rich_text_editor_inline_code)
178188
)
179189
FormattingOption(
180190
state = state.actions[ComposerAction.CODE_BLOCK].toButtonState(),
191+
toggleable = true,
181192
onClick = { onCodeBlockClick() },
182193
imageVector = CompoundIcons.Code(),
183194
contentDescription = stringResource(R.string.rich_text_editor_code_block)
184195
)
185196
FormattingOption(
186197
state = state.actions[ComposerAction.QUOTE].toButtonState(),
198+
toggleable = true,
187199
onClick = { onQuoteClick() },
188200
imageVector = CompoundIcons.Quote(),
189201
contentDescription = stringResource(R.string.rich_text_editor_quote)

0 commit comments

Comments
 (0)