@@ -47,31 +47,41 @@ fun HtmlView(
4747 val root: Node = document.body?.shadowRoot ? : document.body!!
4848 val density = LocalDensity .current.density
4949 val focusManager = LocalFocusManager .current
50+ val htmlViewFocusRequester = remember { FocusRequester () }
5051
5152 val componentInfo = remember { ComponentInfo <HTMLIFrameElement >() }
5253 val focusSwitcher = remember { FocusSwitcher (componentInfo, focusManager) }
5354 val eventsInitialized = remember { mutableStateOf(false ) }
5455 val componentReady = remember { mutableStateOf(false ) }
5556
5657 Box (
57- modifier = modifier.onGloballyPositioned { coordinates ->
58- val location = coordinates.positionInWindow().round()
59- val size = coordinates.size
60- if (componentReady.value) {
61- val container = componentInfo.container as HTMLDivElement
62- container.style.width = " ${size.width / density} px"
63- container.style.height = " ${size.height / density} px"
64- container.style.left = " ${location.x / density} px"
65- container.style.top = " ${location.y / density} px"
58+ modifier = modifier
59+ .focusRequester(htmlViewFocusRequester)
60+ .onFocusChanged {
61+ if (it.isFocused) {
62+ element.value?.let (::requestFocus)
63+ }
64+ }
65+ .focusTarget()
66+ .onGloballyPositioned { coordinates ->
67+ val location = coordinates.positionInWindow().round()
68+ val size = coordinates.size
69+ if (componentReady.value) {
70+ val container = componentInfo.container as HTMLDivElement
71+ container.style.width = " ${size.width / density} px"
72+ container.style.height = " ${size.height / density} px"
73+ container.style.left = " ${location.x / density} px"
74+ container.style.top = " ${location.y / density} px"
75+ }
6676 }
67- }
6877 ) {
6978 focusSwitcher.Content ()
7079 }
7180
7281 DisposableEffect (Unit ) {
7382 componentInfo.container = document.createElement(" div" ) as HTMLDivElement
7483 componentInfo.component = document.createElement(" iframe" ) as HTMLIFrameElement
84+ componentInfo.component.tabIndex = 0
7585 componentReady.value = true
7686 val container = componentInfo.container as HTMLDivElement
7787
@@ -99,9 +109,38 @@ fun HtmlView(
99109 if (! eventsInitialized.value) {
100110 eventsInitialized.value = true
101111
112+ val syncFocusToIframe = {
113+ try {
114+ htmlViewFocusRequester.requestFocus()
115+ requestFocus(iframe)
116+ iframe.contentWindow?.focus()
117+ } catch (_: Throwable ) {
118+ }
119+ }
120+
102121 val loadCallback: (Event ) -> Unit = {
103122 state.loadingState = HtmlLoadingState .Finished ()
104123
124+ try {
125+ registerDomListener(iframe.contentWindow, " focus" ) {
126+ htmlViewFocusRequester.requestFocus()
127+ }
128+
129+ registerDomListener(iframe.contentDocument, " focusin" ) {
130+ htmlViewFocusRequester.requestFocus()
131+ }
132+
133+ registerDomListener(iframe.contentDocument, " pointerdown" ) {
134+ syncFocusToIframe()
135+ }
136+
137+ registerDomListener(iframe.contentDocument, " mousedown" ) {
138+ syncFocusToIframe()
139+ }
140+ } catch (_: Throwable ) {
141+ // Cross-origin iframe: cannot access contentDocument/contentWindow listeners
142+ }
143+
105144 when (val content = state.content) {
106145 is HtmlContent .Url -> {
107146 // Safe: use the URL requested, do not inspect iframe internals
@@ -137,14 +176,15 @@ fun HtmlView(
137176 )
138177 }
139178
140- iframe.addEventListener(
141- type = " load" ,
142- callback = loadCallback
143- )
144- iframe.addEventListener(
145- type = " error" ,
146- callback = errorCallback
147- )
179+ registerDomListener(iframe, " focus" ) {
180+ htmlViewFocusRequester.requestFocus()
181+ }
182+
183+ registerDomListener(iframe, " pointerdown" ) {
184+ syncFocusToIframe()
185+ }
186+ iframe.addEventListener(" load" , loadCallback)
187+ iframe.addEventListener(" error" , errorCallback)
148188
149189 scope.launch {
150190 navigator.handleNavigationEvents(iframe)
@@ -344,9 +384,7 @@ fun HtmlViewUrl(
344384 HtmlView (
345385 state = state,
346386 modifier = modifier,
347- navigator = navigator,
348- onCreated = {},
349- onDispose = {},
387+ navigator = navigator
350388 )
351389}
352390
0 commit comments