one 2.0.0-beta.142.1 → 2.0.0-beta.145.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -45,8 +45,10 @@ private final class SecureFieldModel: ObservableObject {
45
45
  if syncStateId != 0 { OneNativeSyncRegistry.set(Int32(syncStateId), value: value as NSObject) }
46
46
  onChange?(value, controlled.eventCount, controlled.revision)
47
47
  }
48
+ var hasNativeFocus = false
48
49
  var onFocusChange: ((Bool, Int, Int) -> Void)?
49
50
  func changeFocus(_ value: Bool) {
51
+ hasNativeFocus = value
50
52
  guard active, !disabled, controlledFocus.value != value else { return }
51
53
  controlledFocus.change(value)
52
54
  onFocusChange?(value, controlledFocus.eventCount, controlledFocus.revision)
@@ -59,13 +61,14 @@ private final class SecureFieldModel: ObservableObject {
59
61
  onSubmit?(submitCount)
60
62
  }
61
63
  }
62
- @objcMembers public final class OneNativeSecureFieldView: UIView, OneNativeComposable {
64
+ @objcMembers public final class OneNativeSecureFieldView: UIView, OneNativeComposable, OneNativeFocusedContent {
63
65
  public var onSDKEvent: ((String, String) -> Void)?
64
66
 
65
67
  public var onChange: ((String, Int, Int) -> Void)?
66
68
  public var onFocusChange: ((Bool, Int, Int) -> Void)?
67
69
  public var onSubmit: ((Int) -> Void)?
68
70
  private var model = SecureFieldModel()
71
+ @nonobjc var containsComposedFocus: Bool { model.hasNativeFocus }
69
72
  public var onHeight: ((CGFloat) -> Void)?
70
73
  private var controller: OneNativeHostingController<OneNativeMeasuredStandalone<SecureFieldContent>>?
71
74
  public override init(frame: CGRect) { super.init(frame: frame) }
@@ -41,19 +41,22 @@ private final class TextEditorModel: ObservableObject {
41
41
  if syncStateId != 0 { OneNativeSyncRegistry.set(Int32(syncStateId), value: value as NSObject) }
42
42
  onChange?(value, controlled.eventCount, controlled.revision)
43
43
  }
44
+ var hasNativeFocus = false
44
45
  var onFocusChange: ((Bool, Int, Int) -> Void)?
45
46
  func changeFocus(_ value: Bool) {
47
+ hasNativeFocus = value
46
48
  guard active, !disabled, controlledFocus.value != value else { return }
47
49
  controlledFocus.change(value)
48
50
  onFocusChange?(value, controlledFocus.eventCount, controlledFocus.revision)
49
51
  }
50
52
  }
51
- @objcMembers public final class OneNativeTextEditorView: UIView, OneNativeComposable {
53
+ @objcMembers public final class OneNativeTextEditorView: UIView, OneNativeComposable, OneNativeFocusedContent {
52
54
  public var onSDKEvent: ((String, String) -> Void)?
53
55
 
54
56
  public var onChange: ((String, Int, Int) -> Void)?
55
57
  public var onFocusChange: ((Bool, Int, Int) -> Void)?
56
58
  private var model = TextEditorModel()
59
+ @nonobjc var containsComposedFocus: Bool { model.hasNativeFocus }
57
60
  private var controller: OneNativeHostingController<OneNativeStandalone<TextEditorContent>>?
58
61
  public override init(frame: CGRect) { super.init(frame: frame) }
59
62
  required init?(coder: NSCoder) { fatalError("init(coder:) is unavailable") }
@@ -46,8 +46,10 @@ private final class TextFieldModel: ObservableObject {
46
46
  if syncStateId != 0 { OneNativeSyncRegistry.set(Int32(syncStateId), value: value as NSObject) }
47
47
  onChange?(value, controlled.eventCount, controlled.revision)
48
48
  }
49
+ var hasNativeFocus = false
49
50
  var onFocusChange: ((Bool, Int, Int) -> Void)?
50
51
  func changeFocus(_ value: Bool) {
52
+ hasNativeFocus = value
51
53
  guard active, !disabled, controlledFocus.value != value else { return }
52
54
  controlledFocus.change(value)
53
55
  onFocusChange?(value, controlledFocus.eventCount, controlledFocus.revision)
@@ -60,13 +62,14 @@ private final class TextFieldModel: ObservableObject {
60
62
  onSubmit?(submitCount)
61
63
  }
62
64
  }
63
- @objcMembers public final class OneNativeTextFieldView: UIView, OneNativeComposable {
65
+ @objcMembers public final class OneNativeTextFieldView: UIView, OneNativeComposable, OneNativeFocusedContent {
64
66
  public var onSDKEvent: ((String, String) -> Void)?
65
67
 
66
68
  public var onChange: ((String, Int, Int) -> Void)?
67
69
  public var onFocusChange: ((Bool, Int, Int) -> Void)?
68
70
  public var onSubmit: ((Int) -> Void)?
69
71
  private var model = TextFieldModel()
72
+ @nonobjc var containsComposedFocus: Bool { model.hasNativeFocus }
70
73
  public var onHeight: ((CGFloat) -> Void)?
71
74
  private var controller: OneNativeHostingController<OneNativeMeasuredStandalone<TextFieldContent>>?
72
75
  public override init(frame: CGRect) { super.init(frame: frame) }
@@ -30,6 +30,12 @@ extension OneNativeComposable {
30
30
  public func propagateActive(_ active: Bool) {}
31
31
  }
32
32
 
33
+ // composed controls render in their parent's host, so their own uiview cannot
34
+ // resign the rendered field. this receipt identifies the subtree being removed.
35
+ protocol OneNativeFocusedContent: AnyObject {
36
+ var containsComposedFocus: Bool { get }
37
+ }
38
+
33
39
  // standalone, a control fills the Fabric view it was given. composed, it must take its
34
40
  // ideal size so the host can measure a stack of them, so the fill lives here rather than
35
41
  // inside the generated content.
@@ -119,7 +125,7 @@ final class OneNativeSchemeBridge: ObservableObject {
119
125
  // container it wraps them in, which it supplies at init. a container is composable
120
126
  // itself, so containers nest.
121
127
  @objcMembers public class OneNativeContainerView: UIView, OneNativeComposable,
122
- OneNativeCompositionParent
128
+ OneNativeCompositionParent, OneNativeFocusedContent
123
129
  {
124
130
  private let wrap: (OneNativeChildren, Bool) -> AnyView
125
131
  private let published = OneNativeChildren()
@@ -132,6 +138,21 @@ final class OneNativeSchemeBridge: ObservableObject {
132
138
 
133
139
  public var compositionActive: Bool { active }
134
140
 
141
+ @nonobjc var containsComposedFocus: Bool {
142
+ childViews.contains { ($0 as? OneNativeFocusedContent)?.containsComposedFocus == true }
143
+ }
144
+
145
+ @nonobjc private var compositionHost: UIView? {
146
+ if let parent = compositionParent as? OneNativeContainerView { return parent.compositionHost }
147
+ return (compositionParent as? UIView) ?? controller?.viewIfLoaded
148
+ }
149
+
150
+ @nonobjc private func resignComposedFocus(in child: UIView) {
151
+ guard (child as? OneNativeFocusedContent)?.containsComposedFocus == true else { return }
152
+ // keyboard layout must run while the focused row still belongs to the host.
153
+ compositionHost?.endEditing(true)
154
+ }
155
+
135
156
  @nonobjc init(wrap: @escaping (OneNativeChildren, _ standalone: Bool) -> AnyView) {
136
157
  self.wrap = wrap
137
158
  super.init(frame: .zero)
@@ -180,6 +201,7 @@ final class OneNativeSchemeBridge: ObservableObject {
180
201
  public func refreshRow(for child: UIView) {
181
202
  guard let index = childViews.firstIndex(where: { $0 === child }),
182
203
  let composable = child as? OneNativeComposable else { return }
204
+ resignComposedFocus(in: child)
183
205
  let identity = rowIdentity(for: child)
184
206
  identity.revision += 1
185
207
  published.items[index] = OneNativeComposedChild(
@@ -192,6 +214,7 @@ final class OneNativeSchemeBridge: ObservableObject {
192
214
 
193
215
  public func removeChild(_ child: UIView) {
194
216
  guard let index = childViews.firstIndex(where: { $0 === child }) else { return }
217
+ resignComposedFocus(in: child)
195
218
  childViews.remove(at: index)
196
219
  guard let composable = child as? OneNativeComposable else {
197
220
  preconditionFailure("One Native container child lost its composition capability")
@@ -229,6 +252,7 @@ final class OneNativeSchemeBridge: ObservableObject {
229
252
  }
230
253
 
231
254
  public func reset() {
255
+ resignComposedFocus(in: self)
232
256
  compositionParent = nil
233
257
  propagateActive(false)
234
258
  for child in childViews { (child as? OneNativeComposable)?.decompose() }
@@ -33,9 +33,19 @@ private struct SlotContent: View {
33
33
  }
34
34
 
35
35
  @objcMembers
36
- public final class OneNativeContainerSlotView: UIView, OneNativeComposable {
36
+ public final class OneNativeContainerSlotView: UIView, OneNativeComposable, OneNativeFocusedContent {
37
37
  private let model = SlotModel()
38
38
 
39
+ @nonobjc var containsComposedFocus: Bool {
40
+ guard let content = model.content, content.window != nil else { return false }
41
+ var pending = [content]
42
+ while let view = pending.popLast() {
43
+ if view.isFirstResponder { return true }
44
+ pending.append(contentsOf: view.subviews)
45
+ }
46
+ return false
47
+ }
48
+
39
49
  public var content: UIView? {
40
50
  get { model.content }
41
51
  set { model.content = newValue }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "one",
3
- "version": "2.0.0-beta.142.1",
3
+ "version": "2.0.0-beta.145.1",
4
4
  "description": "One is a React framework for web, iOS, and Android apps.",
5
5
  "license": "BSD-3-Clause",
6
6
  "sideEffects": [
@@ -209,18 +209,18 @@
209
209
  "@react-navigation/native-stack": "8.0.0-alpha.52",
210
210
  "@react-navigation/routers": "8.0.0-alpha.17",
211
211
  "@ungap/structured-clone": "^1.2.0",
212
- "@vxrn/color-scheme": "2.0.0-beta.142.1",
213
- "@vxrn/compiler": "2.0.0-beta.142.1",
214
- "@vxrn/resolve": "2.0.0-beta.142.1",
215
- "@vxrn/tslib-lite": "2.0.0-beta.142.1",
216
- "@vxrn/use-isomorphic-layout-effect": "2.0.0-beta.142.1",
217
- "@vxrn/utils": "2.0.0-beta.142.1",
218
- "@vxrn/vite-plugin-metro": "2.0.0-beta.142.1",
212
+ "@vxrn/color-scheme": "2.0.0-beta.145.1",
213
+ "@vxrn/compiler": "2.0.0-beta.145.1",
214
+ "@vxrn/resolve": "2.0.0-beta.145.1",
215
+ "@vxrn/tslib-lite": "2.0.0-beta.145.1",
216
+ "@vxrn/use-isomorphic-layout-effect": "2.0.0-beta.145.1",
217
+ "@vxrn/utils": "2.0.0-beta.145.1",
218
+ "@vxrn/vite-plugin-metro": "2.0.0-beta.145.1",
219
219
  "babel-dead-code-elimination": "1.0.10",
220
220
  "babel-plugin-module-resolver": "^5.0.2",
221
221
  "citty": "^0.1.6",
222
222
  "core-js": "^3.38.1",
223
- "create-vxrn": "2.0.0-beta.142.1",
223
+ "create-vxrn": "2.0.0-beta.145.1",
224
224
  "escape-string-regexp": "^5.0.0",
225
225
  "fast-deep-equal": "^3.1.3",
226
226
  "fast-glob": "^3.3.3",
@@ -242,7 +242,7 @@
242
242
  "tsconfig-paths": "^4",
243
243
  "use-latest-callback": "^0.2.3",
244
244
  "vite": "^8.2.2",
245
- "vxrn": "2.0.0-beta.142.1",
245
+ "vxrn": "2.0.0-beta.145.1",
246
246
  "web-streams-polyfill": "^4.3.0",
247
247
  "ws": "^8.21.0",
248
248
  "xxhashjs": "^0.2.2"