ListDetailPaneScaffold — el patrón más común

El patrón list-detail (lista a la izquierda, detalle a la derecha) es el más usado en tablets. En teléfono, la lista y el detalle se muestran en pantallas separadas con navegación entre ellas. En tablet, ambas se muestran simultáneamente.

// implementation("androidx.compose.material3.adaptive:adaptive:1.0.0")
// implementation("androidx.compose.material3.adaptive:adaptive-layout:1.0.0")
// implementation("androidx.compose.material3.adaptive:adaptive-navigation:1.0.0")

@Composable
fun PantallaProductos() {
    val navigator = rememberListDetailPaneScaffoldNavigator<Producto>()

    // Manejar el botón Back del sistema:
    BackHandler(navigator.canNavigateBack()) {
        navigator.navigateBack()
    }

    ListDetailPaneScaffold(
        directive = navigator.scaffoldDirective,
        value = navigator.scaffoldValue,
        listPane = {
            AnimatedPane {
                ListaProductos(
                    onProductoClick = { producto ->
                        // Navegar al detalle — en teléfono hace push,
                        // en tablet simplemente muestra el panel derecho
                        navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, producto)
                    }
                )
            }
        },
        detailPane = {
            AnimatedPane {
                val producto = navigator.currentDestination?.contentKey
                if (producto != null) {
                    DetalleProducto(producto = producto)
                } else {
                    // Estado vacío cuando no hay producto seleccionado (solo en tablet)
                    Box(
                        modifier = Modifier.fillMaxSize(),
                        contentAlignment = Alignment.Center
                    ) {
                        Text("Seleccioná un producto")
                    }
                }
            }
        }
    )
}

Back navigation adaptativa

El comportamiento del botón Back difiere entre teléfono y tablet en el patrón list-detail:

// En TELÉFONO:
// → Lista (pantalla 1) → click → Detalle (pantalla 2)
// → Back desde Detalle → vuelve a Lista
// → Back desde Lista → sale de la app

// En TABLET:
// → Lista y Detalle se muestran simultáneamente
// → Back NO navega entre paneles (ya están visibles los dos)
// → Back sale de la pantalla completa

// El navigator maneja esto automáticamente:
BackHandler(navigator.canNavigateBack()) {
    navigator.navigateBack()
}
// canNavigateBack() retorna true solo en teléfono cuando está en el detalle
// En tablet siempre retorna false (no hay back entre paneles)

AdaptiveScaffold completo con navegación

// El patrón más completo: navegación adaptativa + list-detail
@Composable
fun AppCompleta() {
    var destinoActual by remember { mutableStateOf(Destino.PRODUCTOS) }
    val navigator = rememberListDetailPaneScaffoldNavigator<Any>()

    NavigationSuiteScaffold(
        navigationSuiteItems = {
            Destino.values().forEach { destino ->
                item(
                    icon = { Icon(destino.icono, contentDescription = destino.label) },
                    label = { Text(destino.label) },
                    selected = destinoActual == destino,
                    onClick = { destinoActual = destino }
                )
            }
        }
    ) {
        // El contenido cambia según el destino activo
        when (destinoActual) {
            Destino.PRODUCTOS -> PantallaProductos()      // usa ListDetailPaneScaffold
            Destino.BUSCAR    -> PantallaBuscar()         // pantalla simple
            Destino.PERFIL    -> PantallaPerfil()         // pantalla simple
        }
    }
}

SupportingPaneScaffold — panel de apoyo

Cuando el panel secundario no es "el detalle" sino información de apoyo (un panel de propiedades, filtros, chat lateral), SupportingPaneScaffold es la herramienta correcta:

@Composable
fun EditorConPropiedades() {
    val navigator = rememberSupportingPaneScaffoldNavigator()

    SupportingPaneScaffold(
        directive = navigator.scaffoldDirective,
        value = navigator.scaffoldValue,
        mainPane = {
            AnimatedPane {
                AreaEdicion(
                    onMostrarPropiedades = {
                        navigator.navigateTo(SupportingPaneScaffoldRole.Supporting)
                    }
                )
            }
        },
        supportingPane = {
            AnimatedPane {
                PanelPropiedades(
                    onCerrar = { navigator.navigateBack() }
                )
            }
        }
    )
    // En teléfono: el panel de propiedades aparece como overlay o pantalla separada
    // En tablet: aparece a la derecha del área de edición permanentemente
}

BoxWithConstraints para casos custom

// Cuando los scaffolds no cubren tu caso específico,
// BoxWithConstraints da acceso directo al tamaño disponible:
@Composable
fun LayoutCustomAdaptativo() {
    BoxWithConstraints(modifier = Modifier.fillMaxSize()) {
        // maxWidth y maxHeight son el espacio disponible real
        when {
            maxWidth > 840.dp -> {
                // Pantalla grande — layout de dos columnas
                Row {
                    Column(modifier = Modifier.weight(1f)) { PanelIzquierdo() }
                    Column(modifier = Modifier.weight(1f)) { PanelDerecho() }
                }
            }
            maxWidth > 600.dp -> {
                // Pantalla media — layout de dos columnas compacto
                Row {
                    Column(modifier = Modifier.weight(2f)) { PanelIzquierdo() }
                    Column(modifier = Modifier.weight(3f)) { PanelDerecho() }
                }
            }
            else -> {
                // Teléfono — layout de una columna
                Column { PanelUnico() }
            }
        }
    }
}

// BoxWithConstraints es más flexible pero también más manual que los scaffolds
// Usarlo cuando ningún scaffold existente cubre el caso