I’m new to the compose-web. Wanted to see if it wo...
# compose-web
m
I’m new to the compose-web. Wanted to see if it would be a nice option to start creating applications in although the first component I want to create is already giving issues. The component is a text field with a drop down. Sadly I either have just the JVM working with the up and down arrows for selection with the enter key and WASMJS failing on the enter part and when I add onPreviewKeyEvent plus focusable on the dropdown itself it makes the up and down arrows on both not work correctly anymore (need to press it a few times before it works) Since I am not a great wizard in compose I would love to hear your input. Code in the thread
Copy code
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SuggestedTextField(
    suggestions: List<String>,
    modifier: Modifier = Modifier
) {
    var statement by remember { mutableStateOf("") }
    var expanded by remember { mutableStateOf(false) }
    val filteredSuggestions = suggestions.filter {
        it.contains(statement, ignoreCase = true)
    }

    ExposedDropdownMenuBox(
        expanded = expanded,
        onExpandedChange = { expanded = it },
    ) {
        TextField(
            value = statement,
            onValueChange = {
                statement = it
                expanded = true
            },
            label = { Text("Statement") },
            modifier = modifier
                .testTag("SuggestedTextField")
                .onFocusChanged { expanded = it.isFocused }
                .onPreviewKeyEvent { e ->
                    if (!expanded) return@onPreviewKeyEvent false
                    when (e.key) {
                        Key.DirectionDown -> {
                            if (filteredSuggestions.isEmpty()) return@onPreviewKeyEvent false
                            val currentIndex =
                                filteredSuggestions.indexOfFirst { it.equals(statement, ignoreCase = true) }
                            val nextIndex = if (currentIndex >= 0) (currentIndex + 1) % filteredSuggestions.size else 0
                            statement = filteredSuggestions[nextIndex]
                            true
                        }

                        Key.DirectionUp -> {
                            if (filteredSuggestions.isEmpty()) return@onPreviewKeyEvent false
                            val currentIndex =
                                filteredSuggestions.indexOfFirst { it.equals(statement, ignoreCase = true) }
                            val prevIndex =
                                if (currentIndex >= 0) (currentIndex - 1 + filteredSuggestions.size) % filteredSuggestions.size else filteredSuggestions.lastIndex
                            statement = filteredSuggestions[prevIndex]
                            true
                        }

                        else -> false
                    }
                }
                .menuAnchor(),
            trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded) },
        )

        ExposedDropdownMenu(
            expanded = expanded && filteredSuggestions.isNotEmpty(),
            onDismissRequest = { expanded = false },
            modifier = Modifier.testTag("DropdownMenu")
        ) {
            filteredSuggestions.forEachIndexed { index, suggestion ->
                DropdownMenuItem(
                    text = { Text(suggestion) },
                    onClick = {
                        statement = suggestion
                        expanded = false
                    },
                    modifier = Modifier.testTag("DropdownMenu$index")
                        .focusable()
                        .onPreviewKeyEvent { e ->
                            when (e.key) {
                                Key.Enter -> {
                                    statement = suggestion
                                    expanded = false
                                    true
                                }
                                else -> false
                            }
                        }
                )
            }
        }
    }
}
Funny thing I have written a test I think should be testing the case that when pressing the enter key that the textfield should have the the item selected although when manually testing it just gives the selection animation and does nothing. Tests passes 😢 Would have preferred that the test failed if it doesn’t work
Copy code
@Test
    fun `enter key selects dropdown item`() = runComposeUiTest {
        setContent { SuggestedTextField(items) }
        val textField = onNodeWithTag("SuggestedTextField")
        textField.performClick()

        textField.performKeyInput { keyDown(Key.DirectionDown); keyUp(Key.DirectionDown) }
        onNode(hasText(items[0]) and hasAnyAncestor(hasTestTag("DropdownMenu"))).assertIsFocused()

        textField.performKeyInput { keyDown(Key.Enter); keyUp(Key.Enter) }

        onNodeWithTag("SuggestedTextField").assert(hasText(items[0]))
        onNodeWithTag("DropdownMenu").assertDoesNotExist()
    }