[jewel] JEWEL-756 Investigate a11y limitations and missing features

(cherry picked from commit e63c84cc9ccf08cd3380c03c445709c887b470ec)


(cherry picked from commit 099b0a45cda4bc91cef53e9ff14e0ca49aa57ec7)

IJ-MR-155570

GitOrigin-RevId: ae31f2e241050a065d3390383ba0b18e1d140246
This commit is contained in:
Ivan Morgillo
2025-01-21 11:22:04 +01:00
committed by intellij-monorepo-bot
parent 400b6dd762
commit 7a31be480d
12 changed files with 55 additions and 52 deletions

View File

@@ -206,7 +206,7 @@ private fun RowScope.ColumnOne() {
Tooltip(
tooltip = {
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
Icon(key = AllIconsKeys.General.ShowInfos, contentDescription = null)
Icon(key = AllIconsKeys.General.ShowInfos, contentDescription = "Show Info icon")
Text("This is a tooltip")
}
}
@@ -237,7 +237,7 @@ private fun RowScope.ColumnOne() {
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt",
actionIcons = {
IconButton(onClick = { clickLabel = "Error Inline Action Icon clicked" }) {
Icon(AllIconsKeys.General.Close, null)
Icon(AllIconsKeys.General.Close, "Close icon")
}
},
)
@@ -260,10 +260,10 @@ private fun RowScope.ColumnOne() {
},
actionIcons = {
IconButton(onClick = { clickLabel = "Error Close Icon clicked" }) {
Icon(AllIconsKeys.General.Close, null)
Icon(AllIconsKeys.General.Close, "Close button")
}
IconButton(onClick = { clickLabel = "Error Gear Icon clicked" }) {
Icon(AllIconsKeys.General.Gear, null)
Icon(AllIconsKeys.General.Gear, "Settings button")
}
},
)

View File

@@ -176,7 +176,7 @@ internal class SwingComparisonTabPanel : BorderLayoutPanel() {
compose {
Icon(
key = IdeSampleIconKeys.jewelToolWindow,
contentDescription = null,
contentDescription = "Jewel Tool Window Icon",
modifier = Modifier.border(1.dp, Color.Red),
)
}

View File

@@ -243,7 +243,9 @@ private fun SearchBar(service: ReleasesSampleService, modifier: Modifier = Modif
TextField(
state = state,
modifier = modifier.focusRequester(focusRequester),
leadingIcon = { Icon(AllIconsKeys.Actions.Find, contentDescription = null, Modifier.padding(end = 8.dp)) },
leadingIcon = {
Icon(AllIconsKeys.Actions.Find, contentDescription = "Find icon", Modifier.padding(end = 8.dp))
},
trailingIcon = {
if (filterText.isNotBlank()) {
CloseIconButton(service)
@@ -344,7 +346,7 @@ private fun OverflowMenu(currentContentSource: ContentSource<*>, onContentSource
verticalAlignment = Alignment.CenterVertically,
) {
if (it.isSameAs(currentContentSource)) {
Icon(AllIconsKeys.Actions.Checked, null)
Icon(AllIconsKeys.Actions.Checked, "Checked icon")
} else {
Spacer(Modifier.width(16.dp))
}

View File

@@ -122,7 +122,7 @@ public fun Banners() {
text = LONG_IPSUM,
actionIcons = {
IconButton(onClick = { clickLabel = "Info inline no icon Action Icon clicked" }) {
Icon(AllIconsKeys.General.Close, null)
Icon(AllIconsKeys.General.Close, "Close button")
}
},
)
@@ -143,7 +143,7 @@ public fun Banners() {
text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt",
actionIcons = {
IconButton(onClick = { clickLabel = "Info inline no icon Action Icon clicked" }) {
Icon(AllIconsKeys.General.Close, null)
Icon(AllIconsKeys.General.Close, "Close button")
}
},
actions = {
@@ -161,7 +161,7 @@ public fun Banners() {
text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt",
actionIcons = {
IconButton(onClick = { clickLabel = "Error Inline Action Icon clicked" }) {
Icon(AllIconsKeys.General.Close, null)
Icon(AllIconsKeys.General.Close, "Close button")
}
},
)
@@ -182,10 +182,10 @@ public fun Banners() {
},
actionIcons = {
IconButton(onClick = { clickLabel = "Error Close Icon clicked" }) {
Icon(AllIconsKeys.General.Close, null)
Icon(AllIconsKeys.General.Close, "Close button")
}
IconButton(onClick = { clickLabel = "Error Gear Icon clicked" }) {
Icon(AllIconsKeys.General.Gear, null)
Icon(AllIconsKeys.General.Gear, "Settings button")
}
},
)
@@ -195,10 +195,10 @@ public fun Banners() {
actions = { Link("Action A", onClick = { clickLabel = "Warning Inline Action A clicked" }) },
actionIcons = {
IconButton(onClick = { clickLabel = "Error Close Icon clicked" }) {
Icon(AllIconsKeys.General.Close, null)
Icon(AllIconsKeys.General.Close, "Close button")
}
IconButton(onClick = { clickLabel = "Error Gear Icon clicked" }) {
Icon(AllIconsKeys.General.Gear, null)
Icon(AllIconsKeys.General.Gear, "Settings button")
}
},
)

View File

@@ -16,7 +16,9 @@ import org.jetbrains.jewel.ui.component.TriStateCheckboxRow
@Composable
public fun Checkboxes() {
Row(horizontalArrangement = Arrangement.spacedBy(10.dp), verticalAlignment = Alignment.CenterVertically) {
var checked by remember { mutableStateOf(ToggleableState.On) }
var checked by remember { mutableStateOf(ToggleableState.Off) }
var checked2 by remember { mutableStateOf(ToggleableState.Off) }
var checked3 by remember { mutableStateOf(ToggleableState.Off) }
TriStateCheckboxRow(
"Checkbox",
checked,
@@ -31,10 +33,10 @@ public fun Checkboxes() {
)
TriStateCheckboxRow(
"Error",
checked,
checked2,
onClick = {
checked =
when (checked) {
checked2 =
when (checked2) {
ToggleableState.On -> ToggleableState.Off
ToggleableState.Off -> ToggleableState.Indeterminate
ToggleableState.Indeterminate -> ToggleableState.On
@@ -44,10 +46,10 @@ public fun Checkboxes() {
)
TriStateCheckboxRow(
"Warning",
checked,
checked3,
onClick = {
checked =
when (checked) {
checked3 =
when (checked3) {
ToggleableState.On -> ToggleableState.Off
ToggleableState.Off -> ToggleableState.Indeterminate
ToggleableState.Indeterminate -> ToggleableState.On

View File

@@ -288,19 +288,6 @@ private fun CheckboxImpl(
}
}
val wrapperModifier =
modifier.triStateToggleable(
state = state,
onClick = {
onClick()
state
},
enabled = enabled,
role = Role.Checkbox,
interactionSource = interactionSource,
indication = null,
)
val outlineModifier =
Modifier.size(metrics.outlineSizeFor(checkboxState).value)
.outline(
@@ -324,14 +311,23 @@ private fun CheckboxImpl(
val checkboxBoxModifier = Modifier.size(metrics.checkboxSize)
val toggleableModifier =
modifier.triStateToggleable(
state = state,
onClick = { onClick() },
enabled = enabled,
role = Role.Checkbox,
interactionSource = interactionSource,
indication = null,
)
if (content == null) {
Box(wrapperModifier.then(checkboxBoxModifier), contentAlignment = Alignment.TopStart) {
Box(modifier = toggleableModifier.then(checkboxBoxModifier), contentAlignment = Alignment.TopStart) {
CheckBoxImage(checkboxPainter)
Box(outlineModifier.align(Alignment.Center))
}
} else {
Row(
wrapperModifier,
modifier = toggleableModifier,
horizontalArrangement = Arrangement.spacedBy(metrics.iconContentGap),
verticalAlignment = verticalAlignment,
) {

View File

@@ -110,7 +110,7 @@ public fun Dropdown(
skipNextClick = false
},
enabled = enabled,
role = Role.Button,
role = Role.DropdownList,
interactionSource = interactionSource,
indication = null,
)

View File

@@ -56,7 +56,6 @@ import androidx.compose.ui.input.key.type
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalInputModeManager
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
@@ -381,7 +380,6 @@ internal fun MenuItem(
menuManager.closeAll(localInputModeManager.inputMode, true)
},
enabled = enabled,
role = Role.Button,
interactionSource = interactionSource,
indication = null,
)
@@ -519,7 +517,6 @@ public fun MenuSubmenuItem(
.clickable(
onClick = { itemState = itemState.copy(selected = !itemState.isSelected) },
enabled = enabled,
role = Role.Button,
interactionSource = interactionSource,
indication = null,
)

View File

@@ -25,6 +25,9 @@ import androidx.compose.ui.draw.paint
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.takeOrElse
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.semantics.focused
import androidx.compose.ui.semantics.role
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.TextStyle
import org.jetbrains.jewel.foundation.Stroke
import org.jetbrains.jewel.foundation.state.CommonStateBitMask.Active
@@ -163,14 +166,19 @@ private fun RadioButtonImpl(
}
val wrapperModifier =
modifier.selectable(
selected = selected,
onClick = onClick,
enabled = enabled,
role = Role.RadioButton,
interactionSource = interactionSource,
indication = null,
)
modifier
.selectable(
selected = selected,
onClick = onClick,
enabled = enabled,
role = Role.RadioButton,
interactionSource = interactionSource,
indication = null,
)
.semantics(mergeDescendants = true) {
role = Role.RadioButton
focused = radioButtonState.isFocused
}
val colors = style.colors
val metrics = style.metrics

View File

@@ -149,7 +149,6 @@ public class SegmentedControlButtonData(
@Immutable
@JvmInline
public value class SegmentedControlState(public val state: ULong) : FocusableComponentState {
override val isActive: Boolean
get() = state and CommonStateBitMask.Active != 0UL
@@ -179,7 +178,6 @@ public value class SegmentedControlState(public val state: ULong) : FocusableCom
"isPressed=$isPressed, isActive=$isActive)"
public companion object {
public fun of(
enabled: Boolean = true,
focused: Boolean = false,

View File

@@ -93,7 +93,7 @@ internal fun SegmentedControlButton(
interactionSource = interactionSource,
enabled = enabled,
indication = null,
role = Role.Button,
role = Role.RadioButton,
onClick = segmentedControlButtonData.onSelect,
)
.background(backgroundColor, shape)

View File

@@ -109,9 +109,9 @@ public fun TabContentScope.SimpleTabContent(
@Composable
internal fun TabImpl(
modifier: Modifier = Modifier,
isActive: Boolean,
tabData: TabData,
modifier: Modifier = Modifier,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
) {
val tabStyle =