@@ -224,9 +224,8 @@ private fun RenderResolved(node: ViewNode) {
224224 val onTap = node.long(" onTap" )
225225 val tint = LocalTint .current
226226 Button (
227- // own disabled and any inherited `.disabled` both apply
228227 onClick = { onTap?.let { SwiftBridge .sink.invokeVoid(it) } },
229- enabled = ! node.isDisabled() && ! LocalInheritedDisabled .current ,
228+ enabled = node.isEnabled() ,
230229 colors = if (tint != null ) ButtonDefaults .buttonColors(containerColor = tint) else ButtonDefaults .buttonColors(),
231230 modifier = node.composeModifiers(),
232231 ) {
@@ -242,6 +241,7 @@ private fun RenderResolved(node: ViewNode) {
242241 Switch (
243242 checked = node.bool(" isOn" ) ? : false ,
244243 onCheckedChange = { onChange?.let { id -> SwiftBridge .sink.invokeBool(id, it) } },
244+ enabled = node.isEnabled(),
245245 colors = if (tint != null ) SwitchDefaults .colors(checkedTrackColor = tint) else SwitchDefaults .colors(),
246246 )
247247 }
@@ -349,6 +349,7 @@ private fun RenderResolved(node: ViewNode) {
349349 value = (node.double(" value" ) ? : 0.0 ).toFloat(),
350350 onValueChange = { onChange?.let { id -> SwiftBridge .sink.invokeDouble(id, it.toDouble()) } },
351351 valueRange = min.. max,
352+ enabled = node.isEnabled(),
352353 colors = if (tint != null ) SliderDefaults .colors(thumbColor = tint, activeTrackColor = tint) else SliderDefaults .colors(),
353354 modifier = node.composeModifiers().fillMaxWidth(),
354355 )
@@ -432,6 +433,7 @@ private fun RenderTextField(node: ViewNode) {
432433 }
433434 },
434435 label = { Text (node.string(" placeholder" ) ? : " " ) },
436+ enabled = node.isEnabled(),
435437 visualTransformation = if (node.bool(" secure" ) == true ) PasswordVisualTransformation () else VisualTransformation .None ,
436438 modifier = node.composeModifiers().fillMaxWidth(),
437439 )
@@ -442,11 +444,12 @@ private fun RenderTextField(node: ViewNode) {
442444private fun RenderStepper (node : ViewNode ) {
443445 val onIncrement = node.long(" onIncrement" )
444446 val onDecrement = node.long(" onDecrement" )
447+ val enabled = node.isEnabled()
445448 Row (verticalAlignment = Alignment .CenterVertically , modifier = node.composeModifiers().fillMaxWidth()) {
446449 RenderChildren (node)
447450 Spacer (modifier = Modifier .weight(1f ))
448- TextButton (onClick = { onDecrement?.let { SwiftBridge .sink.invokeVoid(it) } }) { Text (" −" , fontSize = 20 .sp) }
449- TextButton (onClick = { onIncrement?.let { SwiftBridge .sink.invokeVoid(it) } }) { Text (" +" , fontSize = 20 .sp) }
451+ TextButton (onClick = { onDecrement?.let { SwiftBridge .sink.invokeVoid(it) } }, enabled = enabled ) { Text (" −" , fontSize = 20 .sp) }
452+ TextButton (onClick = { onIncrement?.let { SwiftBridge .sink.invokeVoid(it) } }, enabled = enabled ) { Text (" +" , fontSize = 20 .sp) }
450453 }
451454}
452455
@@ -507,7 +510,7 @@ private fun RenderDatePicker(node: ViewNode) {
507510 Row (verticalAlignment = Alignment .CenterVertically , modifier = node.composeModifiers().fillMaxWidth()) {
508511 RenderChildren (node)
509512 Spacer (modifier = Modifier .weight(1f ))
510- TextButton (onClick = { showDialog = true }) { Text (formatDateMillis(millis)) }
513+ TextButton (onClick = { showDialog = true }, enabled = node.isEnabled() ) { Text (formatDateMillis(millis)) }
511514 }
512515 if (showDialog) {
513516 val state = rememberDatePickerState(initialSelectedDateMillis = millis)
@@ -543,7 +546,7 @@ private fun formatDateMillis(millis: Long): String {
543546private fun RenderMenu (node : ViewNode ) {
544547 var expanded by remember { mutableStateOf(false ) }
545548 Box {
546- TextButton (onClick = { expanded = true }) { Text (node.string(" label" ) ? : " " ) }
549+ TextButton (onClick = { expanded = true }, enabled = node.isEnabled() ) { Text (node.string(" label" ) ? : " " ) }
547550 DropdownMenu (expanded = expanded, onDismissRequest = { expanded = false }) {
548551 for (child in node.children) {
549552 if (child.isPresentation()) continue
@@ -575,7 +578,7 @@ private fun RenderPicker(node: ViewNode) {
575578 Row (modifier = node.composeModifiers().fillMaxWidth(), verticalAlignment = Alignment .CenterVertically ) {
576579 Text (node.string(" title" ) ? : " " )
577580 Spacer (modifier = Modifier .weight(1f ))
578- TextButton (onClick = { expanded = true }) { Text (currentLabel) }
581+ TextButton (onClick = { expanded = true }, enabled = node.isEnabled() ) { Text (currentLabel) }
579582 DropdownMenu (expanded = expanded, onDismissRequest = { expanded = false }) {
580583 for ((value, label) in options) {
581584 DropdownMenuItem (text = { Text (label) }, onClick = {
@@ -674,6 +677,11 @@ private fun RenderEffects(node: ViewNode) {
674677private fun ViewNode.isDisabled (): Boolean =
675678 modifiers.any { it.kind == " disabled" && (it.args[" value" ] as ? kotlinx.serialization.json.JsonPrimitive )?.content == " true" }
676679
680+ // A control is enabled unless its own `.disabled(true)` or an inherited one
681+ // (from an ancestor container) is in scope.
682+ @Composable
683+ private fun ViewNode.isEnabled (): Boolean = ! isDisabled() && ! LocalInheritedDisabled .current
684+
677685// A shape fills its (frame-derived) size with its fill color; without a frame
678686// it collapses to zero, matching this backend's no-layout-engine limitation.
679687@Composable
0 commit comments