Skip to content

Commit cf77488

Browse files
authored
feat(focus): implement focus event proxy (#1132)
1 parent 4fa6573 commit cf77488

2 files changed

Lines changed: 50 additions & 4 deletions

File tree

‎Sources/OpenSwiftUI/Event/Focus/FocusEventProxy.swift‎

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,58 @@
33
// OpenSwiftUI
44
//
55
// Audited for 6.5.4
6-
// Status: WIP
6+
// Status: Complete
77
// ID: 220887A402CE7023D01D5BCC1E080716 (SwiftUI)
88

9+
import OpenAttributeGraphShims
910
@_spi(ForOpenSwiftUIOnly)
1011
import OpenSwiftUICore
1112

12-
// MARK: - FocusEventProxyResponder [TBA]
13+
// MARK: - FocusEventProxyResponder
1314

14-
class FocusEventProxyResponder: DefaultLayoutViewResponder {}
15+
private class FocusEventProxyResponder: DefaultLayoutViewResponder {}
16+
17+
@inline(__always)
18+
func asFocusEventProxyResponder(_ responder: ResponderNode) -> ViewResponder? {
19+
responder as? FocusEventProxyResponder
20+
}
21+
22+
#if os(iOS) || os(visionOS)
23+
// MARK: - FocusEventProxyModifier
24+
25+
struct FocusEventProxyModifier: MultiViewModifier, PrimitiveViewModifier {
26+
static func _makeView(
27+
modifier: _GraphValue<Self>,
28+
inputs: _ViewInputs,
29+
body: @escaping (_Graph, _ViewInputs) -> _ViewOutputs
30+
) -> _ViewOutputs {
31+
var outputs = body(_Graph(), inputs)
32+
guard IOSFocusEnabledFlag.evaluate(inputs: inputs.base),
33+
inputs.preferences.requiresViewResponders else {
34+
return outputs
35+
}
36+
outputs.preferences.viewResponders = Attribute(FocusEventProxyResponderFilter(
37+
children: outputs.viewResponders(),
38+
responder: FocusEventProxyResponder(inputs: inputs)
39+
))
40+
return outputs
41+
}
42+
}
43+
44+
// MARK: - FocusEventProxyResponderFilter
45+
46+
private struct FocusEventProxyResponderFilter: StatefulRule {
47+
@Attribute var children: [ViewResponder]
48+
49+
let responder: FocusEventProxyResponder
50+
51+
typealias Value = [ViewResponder]
52+
53+
mutating func updateValue() {
54+
responder.updateChildren($children.changedValue())
55+
if !hasValue {
56+
value = [responder]
57+
}
58+
}
59+
}
60+
#endif

‎Sources/OpenSwiftUI/Event/Focus/Focusable.swift‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ private class FocusableViewResponder: DefaultLayoutViewResponder, FocusResponder
403403
var focusProxyResponder: ViewResponder? {
404404
var result: ViewResponder?
405405
visit { responder in
406-
guard let responder = responder as? FocusEventProxyResponder else { return .next }
406+
guard let responder = asFocusEventProxyResponder(responder) else { return .next }
407407
result = responder
408408
return .cancel
409409
}

0 commit comments

Comments
 (0)