CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-compose-multiplatform

Declarative framework for sharing UIs across multiple platforms with Kotlin, including Gradle plugin, component libraries, and web support

Pending
Overview
Eval results
Files

component-libraries.mddocs/

Component Libraries

Compose Multiplatform component libraries provide cross-platform UI components and utilities with consistent APIs across all supported platforms. These libraries include resources management, layout components, media support, and development tooling.

Capabilities

Resources Library

Cross-platform resource management with localization support, automatic resource generation, and type-safe access to strings, images, fonts, and other assets.

/**
 * String resources with localization support
 */
@Immutable
class StringResource internal constructor(
    id: String, 
    val key: String, 
    items: Set<ResourceItem>
) : Resource(id, items)

/**
 * Load localized string resources
 */
@Composable fun stringResource(resource: StringResource): String
@Composable fun stringResource(resource: StringResource, vararg formatArgs: Any): String

/**
 * Suspend functions for non-Composable contexts
 */
suspend fun getString(resource: StringResource): String
suspend fun getString(
    environment: ResourceEnvironment, 
    resource: StringResource
): String
suspend fun getString(
    resource: StringResource, 
    vararg formatArgs: Any
): String

/**
 * Drawable resources (images, vectors, SVGs)
 */
@Immutable
class DrawableResource internal constructor(
    id: String, 
    items: Set<ResourceItem>
) : Resource(id, items)

/**
 * Load drawable resources as Compose painters and bitmaps
 */
@Composable fun painterResource(resource: DrawableResource): Painter
@Composable fun imageResource(resource: DrawableResource): ImageBitmap
@Composable fun vectorResource(resource: DrawableResource): ImageVector

/**
 * Font resources with variation settings
 */
@Immutable
class FontResource internal constructor(
    id: String, 
    items: Set<ResourceItem>
) : Resource(id, items)

/**
 * Load font resources (expect/actual implementation)
 */
@Composable expect fun Font(
    resource: FontResource,
    weight: FontWeight = FontWeight.Normal,
    style: FontStyle = FontStyle.Normal,
    variationSettings: FontVariation.Settings = FontVariation.Settings(weight, style)
): Font

Usage Examples:

// Basic resource usage
@Composable
fun MyScreen() {
    val appName = stringResource(Res.string.app_name)
    val welcomeMessage = stringResource(Res.string.welcome_message, "User")
    val icon = painterResource(Res.drawable.app_icon)
    val customFont = Font(Res.font.custom_font, FontWeight.Bold)
    
    Column {
        Text(appName, fontFamily = FontFamily(customFont))
        Text(welcomeMessage)
        Image(painter = icon, contentDescription = "App Icon")
    }
}

// Resource configuration in build.gradle.kts
compose {
    resources {
        publicResClass = false
        nameOfResClass = "Res"
        generateResClass = auto
        packageOfResClass = "com.example.resources"
    }
}

Plural and Array Resources

Handle quantity-based string resources and string arrays.

/**
 * Plural string resources following CLDR rules
 */
@Immutable
class PluralStringResource internal constructor(
    id: String,
    val key: String,
    items: Set<ResourceItem>
) : Resource(id, items)

/**
 * Load plural strings based on quantity
 */
@Composable fun pluralStringResource(
    resource: PluralStringResource, 
    quantity: Int
): String
@Composable fun pluralStringResource(
    resource: PluralStringResource, 
    quantity: Int, 
    vararg formatArgs: Any
): String

/**
 * String array resources
 */
@Immutable  
class StringArrayResource internal constructor(
    id: String,
    val key: String,
    items: Set<ResourceItem>
) : Resource(id, items)

/**
 * Load string arrays
 */
@Composable fun stringArrayResource(resource: StringArrayResource): List<String>
suspend fun getStringArray(resource: StringArrayResource): List<String>

Resource Environment

Control resource resolution based on locale, theme, and device characteristics.

/**
 * Environment context for resource resolution
 */
class ResourceEnvironment internal constructor(
    internal val language: LanguageQualifier,
    internal val region: RegionQualifier,
    internal val theme: ThemeQualifier,
    internal val density: DensityQualifier
)

/**
 * Get current resource environment
 */
@Composable fun rememberResourceEnvironment(): ResourceEnvironment
fun getSystemResourceEnvironment(): ResourceEnvironment

/**
 * Resource qualifiers for environment-specific selection
 */
interface Qualifier

class LanguageQualifier(val language: String) : Qualifier
class RegionQualifier(val region: String) : Qualifier

enum class ThemeQualifier : Qualifier {
    LIGHT, DARK;
    companion object {
        fun selectByValue(isDark: Boolean): ThemeQualifier
    }
}

enum class DensityQualifier(val dpi: Int) : Qualifier {
    LDPI(120), MDPI(160), HDPI(240), 
    XHDPI(320), XXHDPI(480), XXXHDPI(640);
    
    companion object {
        fun selectByValue(dpi: Int): DensityQualifier
        fun selectByDensity(density: Float): DensityQualifier
    }
}

SplitPane Library

Resizable split pane layouts with customizable splitters and drag handling.

/**
 * Vertical split pane with resizable divider
 */
@ExperimentalSplitPaneApi
@Composable fun VerticalSplitPane(
    modifier: Modifier = Modifier,
    splitPaneState: SplitPaneState = rememberSplitPaneState(),
    content: SplitPaneScope.() -> Unit
)

/**
 * Horizontal split pane with resizable divider
 */
@ExperimentalSplitPaneApi
@Composable fun HorizontalSplitPane(
    modifier: Modifier = Modifier,
    splitPaneState: SplitPaneState = rememberSplitPaneState(),
    content: SplitPaneScope.() -> Unit
)

/**
 * State management for split panes
 */
@ExperimentalSplitPaneApi
class SplitPaneState(
    initialPositionPercentage: Float,
    moveEnabled: Boolean
) {
    /** Whether the splitter can be moved */
    var moveEnabled: Boolean
    
    /** Current position as percentage (0.0 to 1.0) */
    var positionPercentage: Float
    
    /** Handle raw movement input */
    fun dispatchRawMovement(delta: Float)
}

/**
 * Remember split pane state
 */
@ExperimentalSplitPaneApi
@Composable fun rememberSplitPaneState(
    initialPositionPercentage: Float = 0f,
    moveEnabled: Boolean = true
): SplitPaneState

Usage Example:

@OptIn(ExperimentalSplitPaneApi::class)
@Composable
fun SplitPaneExample() {
    val splitPaneState = rememberSplitPaneState(initialPositionPercentage = 0.3f)
    
    VerticalSplitPane(
        splitPaneState = splitPaneState
    ) {
        first(minSize = 200.dp) {
            // Left pane content
            LazyColumn {
                items(100) { index ->
                    Text("Item $index")
                }
            }
        }
        
        second(minSize = 300.dp) {
            // Right pane content
            Text("Detail view")
        }
        
        splitter {
            visiblePart {
                Box(
                    Modifier
                        .width(4.dp)
                        .fillMaxHeight()
                        .background(Color.Gray)
                )
            }
            
            handle {
                Box(
                    Modifier
                        .markAsHandle()
                        .width(16.dp)
                        .fillMaxHeight()
                        .background(Color.Transparent)
                )
            }
        }
    }
}

SplitPane DSL

Domain-specific language for configuring split pane content and behavior.

/**
 * DSL scope for configuring split pane contents
 */
@ExperimentalSplitPaneApi
interface SplitPaneScope {
    /** Configure first pane with minimum size */
    fun first(minSize: Dp = 0.dp, content: @Composable () -> Unit)
    
    /** Configure second pane with minimum size */
    fun second(minSize: Dp = 0.dp, content: @Composable () -> Unit)
    
    /** Configure splitter appearance and behavior */
    fun splitter(block: SplitterScope.() -> Unit)
}

/**
 * DSL scope for configuring splitter
 */
@ExperimentalSplitPaneApi
interface SplitterScope {
    /** Configure visible part of splitter */
    fun visiblePart(content: @Composable () -> Unit)
    
    /** Configure drag handle */
    fun handle(
        alignment: SplitterHandleAlignment = SplitterHandleAlignment.ABOVE,
        content: @Composable HandleScope.() -> Unit
    )
}

/**
 * DSL scope for drag handles
 */
@ExperimentalSplitPaneApi
interface HandleScope {
    /** Mark composable as draggable handle */
    fun Modifier.markAsHandle(): Modifier
}

/**
 * Handle alignment options
 */
@ExperimentalSplitPaneApi
enum class SplitterHandleAlignment {
    BEFORE, ABOVE, AFTER
}

AnimatedImage Library

Cross-platform animated image support for GIF, WebP, and other animated formats.

/**
 * Animated image container (expect/actual implementation)
 */
expect class AnimatedImage

/**
 * Load animated image from file path
 */
expect suspend fun loadAnimatedImage(path: String): AnimatedImage

/**
 * Load animated image from application resources
 */
expect suspend fun loadResourceAnimatedImage(path: String): AnimatedImage

/**
 * Animate image and return current frame
 */
@Composable
expect fun AnimatedImage.animate(): ImageBitmap

/**
 * Blank image bitmap constant
 */
val ImageBitmap.Companion.Blank: ImageBitmap

Usage Example:

@Composable
fun AnimatedImageExample() {
    var animatedImage by remember { mutableStateOf<AnimatedImage?>(null) }
    
    LaunchedEffect(Unit) {
        animatedImage = loadResourceAnimatedImage("animations/loading.gif")
    }
    
    animatedImage?.let { image ->
        val currentFrame = image.animate()
        Image(
            bitmap = currentFrame,
            contentDescription = "Loading animation"
        )
    }
}

UI Tooling Preview

IDE preview support with parameter injection for development and design workflows.

/**
 * Mark Composable functions for IDE preview
 */
@MustBeDocumented
@Retention(AnnotationRetention.BINARY)
@Target(AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.FUNCTION)
@Repeatable
annotation class Preview

/**
 * Inject sample data into Preview function parameters
 */
annotation class PreviewParameter(
    val provider: KClass<out PreviewParameterProvider<*>>,
    val limit: Int = Int.MAX_VALUE
)

/**
 * Provide sample data for preview parameters (expect/actual)
 */
expect interface PreviewParameterProvider<T> {
    val values: Sequence<T>
    val count: Int
}

Usage Example:

// Sample data provider
class UserProvider : PreviewParameterProvider<User> {
    override val values = sequenceOf(
        User("Alice", 25),
        User("Bob", 30),
        User("Charlie", 35)
    )
}

// Preview with parameter injection
@Preview
@Composable
fun UserCardPreview(@PreviewParameter(UserProvider::class) user: User) {
    UserCard(user = user)
}

// Multiple preview configurations
@Preview(name = "Light Theme")
@Preview(name = "Dark Theme")
@Composable
fun ProfileScreenPreview() {
    ProfileScreen()
}

Experimental APIs

/**
 * Marks experimental resource APIs
 */
@RequiresOptIn("This API is experimental and is likely to change in the future.")
annotation class ExperimentalResourceApi

/**
 * Marks experimental split pane APIs
 */
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
annotation class ExperimentalSplitPaneApi

/**
 * Marks internal resource APIs
 */
@RequiresOptIn("This is internal API of the Compose gradle plugin.")
annotation class InternalResourceApi

Install with Tessl CLI

npx tessl i tessl/maven-compose-multiplatform

docs

component-libraries.md

gradle-plugin.md

html-web.md

index.md

tile.json