KiteSelectionMenu

fun BoxScope.KiteSelectionMenu(state: KiteDocViewState, items: List<KiteSelectionMenuItem>, modifier: Modifier = Modifier, highlightColors: List<Color> = emptyList(), onHighlightColorPicked: (KiteTextSelection, Color) -> Unit? = null, clearSelectionOnColorPick: Boolean = true, alignment: Alignment = Alignment.TopCenter, showWhileSelecting: Boolean = false, containerColor: Color = KiteSelectionMenuDefaults.ContainerColor, contentColor: Color = KiteSelectionMenuDefaults.ContentColor, container: @Composable (selection: KiteTextSelection, content: @Composable () -> Unit) -> Unit? = null, itemContent: @Composable (item: KiteSelectionMenuItem, selection: KiteTextSelection) -> Unit? = null, colorSwatch: @Composable (color: Color, onPick: () -> Unit) -> Unit? = null)

The selection context menu: place it in KiteDocView's overlay slot and it appears whenever text is selected, listing items and, when highlightColors is non-empty, a wrapping row of colour swatches.

It waits for the finger to lift. While KiteDocViewState.selectionInProgress is true the menu stays hidden, because a popup over the page mid-drag covers the very words being chosen; it appears the moment the drag ends.

Every visual layer is replaceable:

KiteDocView(state, overlay = {
KiteSelectionMenu(
state = state,
items = listOf(
KiteSelectionMenuItem("Copy") { clipboard.setText(AnnotatedString(it.text)) },
KiteSelectionMenuItem("Highlight") { marks.add(it) },
),
highlightColors = listOf(Color.Yellow, Color.Green, Color.Cyan),
onHighlightColorPicked = { sel, color -> marks.add(sel, color) },
)
})