@@ -237,30 +237,78 @@ major pieces of missing behaviour from the native `TextField` type.
237237### Observing the first responder state
238238
239239When initialised you can pass in a callback function using the parameter
240- ` onFirstResponderStateChanged: ` - this takes a closure that will be called
241- with the updated ` FirstResponderState ` whenever it changes, either as a result
240+ ` onFirstResponderStateChanged: ` - this takes a value of type
241+ ` FirstResponderStateChangeHandler ` , which wraps a closure that will be called
242+ with the updated first responder state whenever it changes, either as a result
242243of some user interaction or as the result of a change in the
243244` FirstResponderDemand ` (see below).
244245
246+ The first responder state is represented as a single ` Bool ` value where ` true `
247+ indicates that the text field has become first responder and ` false ` indicates
248+ that it has resigned first responder.
249+
250+ ``` swift
251+ struct ExampleView : View {
252+ var body: some View {
253+ ResponsiveTextField (
254+ placeholder : " Email address" ,
255+ text : $email,
256+ configuration : .emailField ,
257+ onFirstResponderStateChanged : .init { isFirstResponder in
258+ // do something with first responder state
259+ }
260+ )
261+ }
262+ }
263+
245264If you need to track this state you can store it in some external state, such as
246265an `@State ` property or an `@ObservableObject ` (like your view model):
247266
248267```swift
249268struct ExampleView : View {
250269 @State
251- var responderState: FirstResponderState = . notFirstResponder
270+ var isFirstResponder = false
252271
253272 var body: some View {
254273 ResponsiveTextField (
255274 placeholder : " Email address" ,
256275 text : $email,
257276 configuration : .emailField ,
258- onFirstResponderStateChanged : { responderState = $0 }
277+ onFirstResponderStateChanged : .init {
278+ isFirstResponder = $0
279+ }
259280 )
260281 }
261282}
262283```
263284
285+ If all you need to do is update some external state, you can use the built-in
286+ ` .updates ` state changed handler, passing in a binding to that state. The above
287+ example can be simplified to:
288+
289+ ``` swift
290+ struct ExampleView : View {
291+ @State
292+ var isFirstResponder = false
293+
294+ var body: some View {
295+ ResponsiveTextField (
296+ placeholder : " Email address" ,
297+ text : $email,
298+ configuration : .emailField ,
299+ onFirstResponderStateChanged : .updates ($isFirstResponder)
300+ )
301+ }
302+ }
303+ ```
304+
305+ ` FirstResponderStateChangeHandler ` can also be initialised with a
306+ ` canBecomeFirstResponder ` and ` canResignFirstResponder ` closures that both
307+ return a ` Bool ` - if provided, these will be called in the text field's
308+ ` shouldBeginEditing ` and ` shouldEndEditing ` delegate calls and provide flexible
309+ control over if the text field's responder state should change. If these
310+ closures are not provided these delegate methods will return ` true ` .
311+
264312### Progamatically controlling the first responder state
265313
266314` ResponsiveTextField ` also supports binding-based control over the field's
@@ -384,6 +432,12 @@ struct ExampleView: View {
384432}
385433```
386434
435+ When using programatic responder state demands and the ` canBecomeFirstResponder `
436+ and ` canResignFirstResponder ` closures on ` FirstResponderStateChangeHandler ` ,
437+ its important to note that the latter will take priority. If either of these
438+ closures return ` false ` , the demand will be ignored and marked as fulfilled,
439+ resetting it back to ` nil ` .
440+
387441## Licence
388442
389443This library is released under the Apache v2.0 license. See [ LICENSE] ( LICENSE )
0 commit comments