a11y: improve accessibility on rich text editor options.

This commit is contained in:
Benoit Marty
2025-06-16 16:56:59 +02:00
parent 4f9784c47a
commit 3db179edcf
2 changed files with 38 additions and 4 deletions

View File

@@ -13,6 +13,7 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.selection.toggleable
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ripple
import androidx.compose.runtime.Composable
@@ -21,6 +22,8 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.semantics.clearAndSetSemantics
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons
@@ -32,9 +35,10 @@ import io.element.android.libraries.designsystem.theme.iconSuccessPrimaryBackgro
@Composable
internal fun FormattingOption(
state: FormattingOptionState,
toggleable: Boolean,
onClick: () -> Unit,
imageVector: ImageVector,
contentDescription: String?,
contentDescription: String,
modifier: Modifier = Modifier,
) {
val backgroundColor = when (state) {
@@ -52,6 +56,7 @@ internal fun FormattingOption(
modifier = modifier
.clickable(
onClick = onClick,
enabled = state != FormattingOptionState.Disabled,
interactionSource = remember { MutableInteractionSource() },
indication = ripple(
bounded = false,
@@ -59,6 +64,20 @@ internal fun FormattingOption(
),
)
.size(48.dp)
.then(
if (toggleable) {
Modifier.toggleable(
value = state == FormattingOptionState.Selected,
enabled = state != FormattingOptionState.Disabled,
onValueChange = { onClick() },
)
} else {
Modifier
}
)
.clearAndSetSemantics {
this.contentDescription = contentDescription
}
) {
Box(
modifier = Modifier
@@ -84,21 +103,24 @@ internal fun FormattingOptionPreview() = ElementPreview {
Row {
FormattingOption(
state = FormattingOptionState.Default,
toggleable = false,
onClick = { },
imageVector = CompoundIcons.Bold(),
contentDescription = null,
contentDescription = "",
)
FormattingOption(
state = FormattingOptionState.Selected,
toggleable = true,
onClick = { },
imageVector = CompoundIcons.Italic(),
contentDescription = null,
contentDescription = "",
)
FormattingOption(
state = FormattingOptionState.Disabled,
toggleable = false,
onClick = { },
imageVector = CompoundIcons.Underline(),
contentDescription = null,
contentDescription = "",
)
}
}

View File

@@ -104,24 +104,28 @@ internal fun TextFormatting(
) {
FormattingOption(
state = state.actions[ComposerAction.BOLD].toButtonState(),
toggleable = true,
onClick = { onInlineFormatClick(InlineFormat.Bold) },
imageVector = CompoundIcons.Bold(),
contentDescription = stringResource(R.string.rich_text_editor_format_bold)
)
FormattingOption(
state = state.actions[ComposerAction.ITALIC].toButtonState(),
toggleable = true,
onClick = { onInlineFormatClick(InlineFormat.Italic) },
imageVector = CompoundIcons.Italic(),
contentDescription = stringResource(R.string.rich_text_editor_format_italic)
)
FormattingOption(
state = state.actions[ComposerAction.UNDERLINE].toButtonState(),
toggleable = true,
onClick = { onInlineFormatClick(InlineFormat.Underline) },
imageVector = CompoundIcons.Underline(),
contentDescription = stringResource(R.string.rich_text_editor_format_underline)
)
FormattingOption(
state = state.actions[ComposerAction.STRIKE_THROUGH].toButtonState(),
toggleable = true,
onClick = { onInlineFormatClick(InlineFormat.StrikeThrough) },
imageVector = CompoundIcons.Strikethrough(),
contentDescription = stringResource(R.string.rich_text_editor_format_strikethrough)
@@ -141,6 +145,7 @@ internal fun TextFormatting(
FormattingOption(
state = state.actions[ComposerAction.LINK].toButtonState(),
toggleable = true,
onClick = { linkDialogAction = state.linkAction },
imageVector = CompoundIcons.Link(),
contentDescription = stringResource(R.string.rich_text_editor_link)
@@ -148,42 +153,49 @@ internal fun TextFormatting(
FormattingOption(
state = state.actions[ComposerAction.UNORDERED_LIST].toButtonState(),
toggleable = true,
onClick = { onToggleListClick(ordered = false) },
imageVector = CompoundIcons.ListBulleted(),
contentDescription = stringResource(R.string.rich_text_editor_bullet_list)
)
FormattingOption(
state = state.actions[ComposerAction.ORDERED_LIST].toButtonState(),
toggleable = true,
onClick = { onToggleListClick(ordered = true) },
imageVector = CompoundIcons.ListNumbered(),
contentDescription = stringResource(R.string.rich_text_editor_numbered_list)
)
FormattingOption(
state = state.actions[ComposerAction.INDENT].toButtonState(),
toggleable = false,
onClick = { onIndentClick() },
imageVector = CompoundIcons.IndentIncrease(),
contentDescription = stringResource(R.string.rich_text_editor_indent)
)
FormattingOption(
state = state.actions[ComposerAction.UNINDENT].toButtonState(),
toggleable = false,
onClick = { onUnindentClick() },
imageVector = CompoundIcons.IndentDecrease(),
contentDescription = stringResource(R.string.rich_text_editor_unindent)
)
FormattingOption(
state = state.actions[ComposerAction.INLINE_CODE].toButtonState(),
toggleable = true,
onClick = { onInlineFormatClick(InlineFormat.InlineCode) },
imageVector = CompoundIcons.InlineCode(),
contentDescription = stringResource(R.string.rich_text_editor_inline_code)
)
FormattingOption(
state = state.actions[ComposerAction.CODE_BLOCK].toButtonState(),
toggleable = true,
onClick = { onCodeBlockClick() },
imageVector = CompoundIcons.Code(),
contentDescription = stringResource(R.string.rich_text_editor_code_block)
)
FormattingOption(
state = state.actions[ComposerAction.QUOTE].toButtonState(),
toggleable = true,
onClick = { onQuoteClick() },
imageVector = CompoundIcons.Quote(),
contentDescription = stringResource(R.string.rich_text_editor_quote)