EARHORNMUSIC UPnP · Android TV · Phones · Android Auto · GNU/Linux
Release 0.5.0

StaveFocus.kt

package dev.stave.ui.theme

import androidx.compose.foundation.border
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsFocusedAsState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp

/**
 * Earhorn's keyboard-focus visual, ported from Android's `staveFocusable`: a
 * 2dp [FocusRing] border while focused, nothing otherwise (the caller paints its
 * own background and hover wash). Amber on SurfaceBase is 8.50:1, well over the
 * 3:1 WCAG 2.4.11 asks of a focus indicator; a translucent amber wash is ~1.3:1.
 *
 * Pass the same [interactionSource] to the clickable/toggleable/selectable that
 * makes the element focusable.
 */
@Composable
fun Modifier.staveFocusRing(
    interactionSource: MutableInteractionSource,
    cornerRadiusDp: Int = 8,
): Modifier {
    val focused by interactionSource.collectIsFocusedAsState()
    val shape = remember(cornerRadiusDp) { RoundedCornerShape(cornerRadiusDp.dp) }
    return this
        .clip(shape)
        .then(if (focused) Modifier.border(2.dp, FocusRing, shape) else Modifier)
}