compose-rust 0.0.1

Declarative UI in Rust, rendered by an AOT-compiled Compose Multiplatform engine.
Documentation
package dev.darkpyonix.composerust.foundation

import androidx.compose.foundation.text.selection.DisableSelection
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.Modifier

/**
 * Whether what is being drawn is inside a region whose text can be selected.
 *
 * Static because it changes only when a region is added or removed above a node, and every
 * node reads it.
 */
val LocalInSelectionRegion = staticCompositionLocalOf { false }

/**
 * A region whose text can be dragged over and copied, as one selection.
 *
 * This is Compose's own `SelectionContainer` and nothing on top of it. Every `Text` drawn
 * inside joins the same selection however deep it is, including text in a list that
 * scrolls sideways, and copying a selection that spans several of them puts a line break
 * between each, which is what Compose does when it gathers the selected text. The copy
 * shortcut, the context menu and the clipboard are the platform's, through Compose's
 * platform text handling, so nothing here reaches the Host: no event is sent while text
 * is selected or when it is copied, and the copied text never crosses the boundary.
 *
 * Text outside a region is not selectable, because nothing outside one is wrapped in this.
 */
@Composable
internal fun SelectableRegion(modifier: Modifier, content: @Composable () -> Unit) {
    SelectionContainer(modifier) {
        CompositionLocalProvider(LocalInSelectionRegion provides true, content = content)
    }
}

/**
 * Draws a control so that it is left out of the selection around it.
 *
 * A button's label is text, and inside a selectable region it would be dragged over and
 * copied with the paragraph next to it. A control is something to press, not something to
 * read, so it is excluded and keeps answering presses exactly as it does anywhere else.
 * Outside a region this adds nothing.
 */
@Composable
internal fun Unselectable(content: @Composable () -> Unit) {
    if (LocalInSelectionRegion.current) {
        DisableSelection(content)
    } else {
        content()
    }
}