1616
1717package androidx.compose.ui.input
1818
19+ import androidx.compose.foundation.layout.Box
1920import androidx.compose.foundation.layout.Column
21+ import androidx.compose.foundation.layout.fillMaxWidth
22+ import androidx.compose.foundation.layout.size
23+ import androidx.compose.foundation.text.BasicTextField
2024import androidx.compose.foundation.text.input.TextFieldLineLimits
2125import androidx.compose.foundation.text.input.rememberTextFieldState
2226import androidx.compose.material.TextField
27+ import androidx.compose.runtime.LaunchedEffect
2328import androidx.compose.ui.Modifier
2429import androidx.compose.ui.OnCanvasTests
30+ import androidx.compose.ui.background
2531import androidx.compose.ui.events.keyEvent
2632import androidx.compose.ui.focus.FocusRequester
2733import androidx.compose.ui.focus.FocusState
2834import androidx.compose.ui.focus.focusRequester
2935import androidx.compose.ui.focus.onFocusChanged
36+ import androidx.compose.ui.graphics.Color
3037import androidx.compose.ui.input.key.Key
38+ import androidx.compose.ui.platform.testTag
39+ import androidx.compose.ui.unit.dp
3140import kotlin.test.Test
3241import kotlin.test.assertEquals
3342import kotlin.test.assertFalse
3443import kotlin.test.assertNotNull
3544import kotlin.test.assertTrue
45+ import kotlinx.coroutines.Dispatchers
46+ import kotlinx.coroutines.delay
47+ import kotlinx.coroutines.withContext
3648import kotlinx.coroutines.yield
49+ import org.w3c.dom.HTMLDivElement
3750import org.w3c.dom.HTMLInputElement
3851import org.w3c.dom.events.Event
3952import org.w3c.dom.events.KeyboardEvent
53+ import org.w3c.dom.events.MouseEvent
54+ import org.w3c.dom.pointerevents.PointerEvent
55+ import org.w3c.dom.pointerevents.PointerEventInit
4056
4157class TextFieldFocusTest : OnCanvasTests {
4258
@@ -132,4 +148,79 @@ class TextFieldFocusTest : OnCanvasTests {
132148 assertTrue((lastKeydownEventOnRoot as KeyboardEvent ).shiftKey)
133149 assertTrue(lastKeydownEventOnRoot!! .defaultPrevented)
134150 }
151+
152+ private fun mouseDownPointerEvent (
153+ x : Int , y : Int ,
154+ ): PointerEvent = PointerEvent (
155+ " pointerdown" ,
156+ PointerEventInit (
157+ clientX = x, clientY = y,
158+ button = 0 , buttons = 1 ,
159+ pointerType = " mouse"
160+ )
161+ )
162+
163+ @Test
164+ fun mouseClickOutsideClearsFocusByDefault () = runApplicationTest {
165+ val focusRequester = FocusRequester ()
166+ var focusState: FocusState ? = null
167+
168+ createComposeWindow {
169+ Column (Modifier .size(300 .dp, 400 .dp)) {
170+ Box (Modifier .testTag(" box" ).size(100 .dp).background(Color .Gray ))
171+ BasicTextField (
172+ state = rememberTextFieldState(),
173+ modifier = Modifier
174+ .testTag(" textField" )
175+ .focusRequester(focusRequester)
176+ .onFocusChanged {
177+ focusState = it
178+ }
179+ )
180+ LaunchedEffect (Unit ) {
181+ focusRequester.requestFocus()
182+ }
183+ }
184+ }
185+ assertTrue(focusState!! .isFocused, " Expected to be focused after requestFocus" )
186+
187+ dispatchEvents(mouseDownPointerEvent(50 , 50 ))
188+ awaitIdle()
189+ assertFalse(focusState!! .isFocused, " Expected to lose focus after clicking outside" )
190+ }
191+
192+ @Test
193+ fun mouseClickOutsideDoesntClearsFocusWhenDisabled () = runApplicationTest {
194+ val focusRequester = FocusRequester ()
195+ var focusState: FocusState ? = null
196+
197+ createComposeWindow(
198+ configure = {
199+ isClearFocusOnMouseDownEnabled = false
200+ }
201+ ) {
202+ Column (Modifier .size(300 .dp, 400 .dp)) {
203+ Box (Modifier .testTag(" box" ).size(100 .dp).background(Color .Gray ))
204+ BasicTextField (
205+ state = rememberTextFieldState(),
206+ modifier = Modifier
207+ .testTag(" textField" )
208+ .focusRequester(focusRequester)
209+ .onFocusChanged {
210+ focusState = it
211+ }
212+ )
213+ LaunchedEffect (Unit ) {
214+ focusRequester.requestFocus()
215+ }
216+ }
217+ }
218+ assertTrue(focusState!! .isFocused, " Expected to be focused after requestFocus" )
219+
220+ dispatchEvents(mouseDownPointerEvent(50 , 50 ))
221+ awaitIdle()
222+ assertTrue(focusState!! .isFocused, " Expected to keep focus despite clicking outside" )
223+ }
224+
225+
135226}
0 commit comments