react-native-platform-components 1.2.0 → 1.4.0

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.
Files changed (242) hide show
  1. package/README.md +33 -31
  2. package/android/src/main/java/com/platformcomponents/PCButtonGroupView.kt +498 -0
  3. package/android/src/main/java/com/platformcomponents/PCButtonGroupViewManager.kt +191 -0
  4. package/android/src/main/java/com/platformcomponents/PCButtonSupport.kt +127 -0
  5. package/android/src/main/java/com/platformcomponents/PCButtonView.kt +345 -0
  6. package/android/src/main/java/com/platformcomponents/PCButtonViewManager.kt +126 -0
  7. package/android/src/main/java/com/platformcomponents/PCExpressive.kt +107 -0
  8. package/android/src/main/java/com/platformcomponents/PCFloatingToolbarView.kt +115 -0
  9. package/android/src/main/java/com/platformcomponents/PCFloatingToolbarViewManager.kt +65 -0
  10. package/android/src/main/java/com/platformcomponents/PCNativeThemeModule.kt +3 -0
  11. package/android/src/main/java/com/platformcomponents/PCSegmentedControlView.kt +13 -5
  12. package/android/src/main/java/com/platformcomponents/PCSegmentedControlViewManager.kt +6 -1
  13. package/android/src/main/java/com/platformcomponents/PCTextFieldView.kt +1018 -0
  14. package/android/src/main/java/com/platformcomponents/PCTextFieldViewManager.kt +248 -0
  15. package/android/src/main/java/com/platformcomponents/PlatformComponentsPackage.kt +13 -6
  16. package/android/src/main/jni/CMakeLists.txt +13 -1
  17. package/android/src/main/res/values/attrs.xml +13 -0
  18. package/android/src/main/res/values/styles.xml +183 -0
  19. package/ios/PCButton.h +10 -0
  20. package/ios/PCButton.mm +196 -0
  21. package/ios/PCButtonGroup.h +10 -0
  22. package/ios/PCButtonGroup.mm +256 -0
  23. package/ios/PCButtonGroupView.swift +254 -0
  24. package/ios/PCButtonSupport.swift +141 -0
  25. package/ios/PCButtonView.swift +155 -0
  26. package/ios/PCFloatingToolbar.h +10 -0
  27. package/ios/PCFloatingToolbar.mm +76 -0
  28. package/ios/PCFloatingToolbarView.swift +95 -0
  29. package/ios/PCNativeThemeModule.mm +13 -0
  30. package/ios/PCSelectionMenu.swift +9 -1
  31. package/ios/PCTextField.h +10 -0
  32. package/ios/PCTextField.mm +391 -0
  33. package/ios/PCTextFieldView.swift +1012 -0
  34. package/lib/commonjs/Button.js +77 -0
  35. package/lib/commonjs/Button.js.map +1 -0
  36. package/lib/commonjs/ButtonGroup.js +99 -0
  37. package/lib/commonjs/ButtonGroup.js.map +1 -0
  38. package/lib/commonjs/ButtonGroupNativeComponent.ts +121 -0
  39. package/lib/commonjs/ButtonNativeComponent.ts +76 -0
  40. package/lib/commonjs/ContextMenuNativeComponent.ts +5 -4
  41. package/lib/commonjs/DatePickerNativeComponent.ts +17 -11
  42. package/lib/commonjs/FloatingToolbar.js +69 -0
  43. package/lib/commonjs/FloatingToolbar.js.map +1 -0
  44. package/lib/commonjs/FloatingToolbarNativeComponent.ts +31 -0
  45. package/lib/commonjs/LiquidGlass.js +24 -4
  46. package/lib/commonjs/LiquidGlass.js.map +1 -1
  47. package/lib/commonjs/LiquidGlassNativeComponent.ts +6 -5
  48. package/lib/commonjs/NativePlatformComponentsTheme.js.map +1 -1
  49. package/lib/commonjs/SegmentedControl.js +11 -85
  50. package/lib/commonjs/SegmentedControl.js.map +1 -1
  51. package/lib/commonjs/SegmentedControlNativeComponent.ts +15 -11
  52. package/lib/commonjs/SelectionMenuNativeComponent.ts +6 -5
  53. package/lib/commonjs/TextField.js +195 -0
  54. package/lib/commonjs/TextField.js.map +1 -0
  55. package/lib/commonjs/TextFieldNativeComponent.ts +218 -0
  56. package/lib/commonjs/codegenTypes.js +6 -0
  57. package/lib/commonjs/codegenTypes.js.map +1 -0
  58. package/lib/commonjs/focusRegistry.js +78 -0
  59. package/lib/commonjs/focusRegistry.js.map +1 -0
  60. package/lib/commonjs/icons.js +92 -0
  61. package/lib/commonjs/icons.js.map +1 -0
  62. package/lib/commonjs/index.js +66 -0
  63. package/lib/commonjs/index.js.map +1 -1
  64. package/lib/commonjs/index.web.js +32 -2
  65. package/lib/commonjs/index.web.js.map +1 -1
  66. package/lib/commonjs/labelStyle.js +27 -0
  67. package/lib/commonjs/labelStyle.js.map +1 -0
  68. package/lib/commonjs/reactNativeInternals.d.js +2 -0
  69. package/lib/commonjs/reactNativeInternals.d.js.map +1 -0
  70. package/lib/module/Button.js +70 -0
  71. package/lib/module/Button.js.map +1 -0
  72. package/lib/module/ButtonGroup.js +92 -0
  73. package/lib/module/ButtonGroup.js.map +1 -0
  74. package/lib/module/ButtonGroupNativeComponent.ts +121 -0
  75. package/lib/module/ButtonNativeComponent.ts +76 -0
  76. package/lib/module/ContextMenuNativeComponent.ts +5 -4
  77. package/lib/module/DatePickerNativeComponent.ts +17 -11
  78. package/lib/module/FloatingToolbar.js +62 -0
  79. package/lib/module/FloatingToolbar.js.map +1 -0
  80. package/lib/module/FloatingToolbarNativeComponent.ts +31 -0
  81. package/lib/module/LiquidGlass.js +24 -4
  82. package/lib/module/LiquidGlass.js.map +1 -1
  83. package/lib/module/LiquidGlassNativeComponent.ts +6 -5
  84. package/lib/module/NativePlatformComponentsTheme.js.map +1 -1
  85. package/lib/module/SegmentedControl.js +12 -87
  86. package/lib/module/SegmentedControl.js.map +1 -1
  87. package/lib/module/SegmentedControlNativeComponent.ts +15 -11
  88. package/lib/module/SelectionMenuNativeComponent.ts +6 -5
  89. package/lib/module/TextField.js +189 -0
  90. package/lib/module/TextField.js.map +1 -0
  91. package/lib/module/TextFieldNativeComponent.ts +218 -0
  92. package/lib/module/codegenTypes.js +4 -0
  93. package/lib/module/codegenTypes.js.map +1 -0
  94. package/lib/module/focusRegistry.js +74 -0
  95. package/lib/module/focusRegistry.js.map +1 -0
  96. package/lib/module/icons.js +87 -0
  97. package/lib/module/icons.js.map +1 -0
  98. package/lib/module/index.js +6 -0
  99. package/lib/module/index.js.map +1 -1
  100. package/lib/module/index.web.js +28 -0
  101. package/lib/module/index.web.js.map +1 -1
  102. package/lib/module/labelStyle.js +23 -0
  103. package/lib/module/labelStyle.js.map +1 -0
  104. package/lib/module/reactNativeInternals.d.js +2 -0
  105. package/lib/module/reactNativeInternals.d.js.map +1 -0
  106. package/lib/typescript/commonjs/docs/sidebars.d.ts.map +1 -1
  107. package/lib/typescript/commonjs/src/Button.d.ts +76 -0
  108. package/lib/typescript/commonjs/src/Button.d.ts.map +1 -0
  109. package/lib/typescript/commonjs/src/ButtonGroup.d.ts +102 -0
  110. package/lib/typescript/commonjs/src/ButtonGroup.d.ts.map +1 -0
  111. package/lib/typescript/commonjs/src/ButtonGroupNativeComponent.d.ts +93 -0
  112. package/lib/typescript/commonjs/src/ButtonGroupNativeComponent.d.ts.map +1 -0
  113. package/lib/typescript/commonjs/src/ButtonNativeComponent.d.ts +57 -0
  114. package/lib/typescript/commonjs/src/ButtonNativeComponent.d.ts.map +1 -0
  115. package/lib/typescript/commonjs/src/ContextMenuNativeComponent.d.ts +5 -4
  116. package/lib/typescript/commonjs/src/ContextMenuNativeComponent.d.ts.map +1 -1
  117. package/lib/typescript/commonjs/src/DatePickerNativeComponent.d.ts +12 -11
  118. package/lib/typescript/commonjs/src/DatePickerNativeComponent.d.ts.map +1 -1
  119. package/lib/typescript/commonjs/src/FloatingToolbar.d.ts +45 -0
  120. package/lib/typescript/commonjs/src/FloatingToolbar.d.ts.map +1 -0
  121. package/lib/typescript/commonjs/src/FloatingToolbarNativeComponent.d.ts +24 -0
  122. package/lib/typescript/commonjs/src/FloatingToolbarNativeComponent.d.ts.map +1 -0
  123. package/lib/typescript/commonjs/src/LiquidGlass.d.ts +4 -3
  124. package/lib/typescript/commonjs/src/LiquidGlass.d.ts.map +1 -1
  125. package/lib/typescript/commonjs/src/LiquidGlassNativeComponent.d.ts +6 -5
  126. package/lib/typescript/commonjs/src/LiquidGlassNativeComponent.d.ts.map +1 -1
  127. package/lib/typescript/commonjs/src/NativePlatformComponentsTheme.d.ts +10 -2
  128. package/lib/typescript/commonjs/src/NativePlatformComponentsTheme.d.ts.map +1 -1
  129. package/lib/typescript/commonjs/src/SegmentedControl.d.ts +17 -46
  130. package/lib/typescript/commonjs/src/SegmentedControl.d.ts.map +1 -1
  131. package/lib/typescript/commonjs/src/SegmentedControlNativeComponent.d.ts +9 -6
  132. package/lib/typescript/commonjs/src/SegmentedControlNativeComponent.d.ts.map +1 -1
  133. package/lib/typescript/commonjs/src/SelectionMenuNativeComponent.d.ts +6 -5
  134. package/lib/typescript/commonjs/src/SelectionMenuNativeComponent.d.ts.map +1 -1
  135. package/lib/typescript/commonjs/src/TextField.d.ts +174 -0
  136. package/lib/typescript/commonjs/src/TextField.d.ts.map +1 -0
  137. package/lib/typescript/commonjs/src/TextFieldNativeComponent.d.ts +162 -0
  138. package/lib/typescript/commonjs/src/TextFieldNativeComponent.d.ts.map +1 -0
  139. package/lib/typescript/commonjs/src/codegenTypes.d.ts +12 -0
  140. package/lib/typescript/commonjs/src/codegenTypes.d.ts.map +1 -0
  141. package/lib/typescript/commonjs/src/focusRegistry.d.ts +13 -0
  142. package/lib/typescript/commonjs/src/focusRegistry.d.ts.map +1 -0
  143. package/lib/typescript/commonjs/src/icons.d.ts +52 -0
  144. package/lib/typescript/commonjs/src/icons.d.ts.map +1 -0
  145. package/lib/typescript/commonjs/src/index.d.ts +6 -0
  146. package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
  147. package/lib/typescript/commonjs/src/index.web.d.ts +121 -0
  148. package/lib/typescript/commonjs/src/index.web.d.ts.map +1 -1
  149. package/lib/typescript/commonjs/src/labelStyle.d.ts +20 -0
  150. package/lib/typescript/commonjs/src/labelStyle.d.ts.map +1 -0
  151. package/lib/typescript/commonjs/src/sharedTypes.d.ts +8 -3
  152. package/lib/typescript/commonjs/src/sharedTypes.d.ts.map +1 -1
  153. package/lib/typescript/module/docs/sidebars.d.ts.map +1 -1
  154. package/lib/typescript/module/src/Button.d.ts +76 -0
  155. package/lib/typescript/module/src/Button.d.ts.map +1 -0
  156. package/lib/typescript/module/src/ButtonGroup.d.ts +102 -0
  157. package/lib/typescript/module/src/ButtonGroup.d.ts.map +1 -0
  158. package/lib/typescript/module/src/ButtonGroupNativeComponent.d.ts +93 -0
  159. package/lib/typescript/module/src/ButtonGroupNativeComponent.d.ts.map +1 -0
  160. package/lib/typescript/module/src/ButtonNativeComponent.d.ts +57 -0
  161. package/lib/typescript/module/src/ButtonNativeComponent.d.ts.map +1 -0
  162. package/lib/typescript/module/src/ContextMenuNativeComponent.d.ts +5 -4
  163. package/lib/typescript/module/src/ContextMenuNativeComponent.d.ts.map +1 -1
  164. package/lib/typescript/module/src/DatePickerNativeComponent.d.ts +12 -11
  165. package/lib/typescript/module/src/DatePickerNativeComponent.d.ts.map +1 -1
  166. package/lib/typescript/module/src/FloatingToolbar.d.ts +45 -0
  167. package/lib/typescript/module/src/FloatingToolbar.d.ts.map +1 -0
  168. package/lib/typescript/module/src/FloatingToolbarNativeComponent.d.ts +24 -0
  169. package/lib/typescript/module/src/FloatingToolbarNativeComponent.d.ts.map +1 -0
  170. package/lib/typescript/module/src/LiquidGlass.d.ts +4 -3
  171. package/lib/typescript/module/src/LiquidGlass.d.ts.map +1 -1
  172. package/lib/typescript/module/src/LiquidGlassNativeComponent.d.ts +6 -5
  173. package/lib/typescript/module/src/LiquidGlassNativeComponent.d.ts.map +1 -1
  174. package/lib/typescript/module/src/NativePlatformComponentsTheme.d.ts +10 -2
  175. package/lib/typescript/module/src/NativePlatformComponentsTheme.d.ts.map +1 -1
  176. package/lib/typescript/module/src/SegmentedControl.d.ts +17 -46
  177. package/lib/typescript/module/src/SegmentedControl.d.ts.map +1 -1
  178. package/lib/typescript/module/src/SegmentedControlNativeComponent.d.ts +9 -6
  179. package/lib/typescript/module/src/SegmentedControlNativeComponent.d.ts.map +1 -1
  180. package/lib/typescript/module/src/SelectionMenuNativeComponent.d.ts +6 -5
  181. package/lib/typescript/module/src/SelectionMenuNativeComponent.d.ts.map +1 -1
  182. package/lib/typescript/module/src/TextField.d.ts +174 -0
  183. package/lib/typescript/module/src/TextField.d.ts.map +1 -0
  184. package/lib/typescript/module/src/TextFieldNativeComponent.d.ts +162 -0
  185. package/lib/typescript/module/src/TextFieldNativeComponent.d.ts.map +1 -0
  186. package/lib/typescript/module/src/codegenTypes.d.ts +12 -0
  187. package/lib/typescript/module/src/codegenTypes.d.ts.map +1 -0
  188. package/lib/typescript/module/src/focusRegistry.d.ts +13 -0
  189. package/lib/typescript/module/src/focusRegistry.d.ts.map +1 -0
  190. package/lib/typescript/module/src/icons.d.ts +52 -0
  191. package/lib/typescript/module/src/icons.d.ts.map +1 -0
  192. package/lib/typescript/module/src/index.d.ts +6 -0
  193. package/lib/typescript/module/src/index.d.ts.map +1 -1
  194. package/lib/typescript/module/src/index.web.d.ts +121 -0
  195. package/lib/typescript/module/src/index.web.d.ts.map +1 -1
  196. package/lib/typescript/module/src/labelStyle.d.ts +20 -0
  197. package/lib/typescript/module/src/labelStyle.d.ts.map +1 -0
  198. package/lib/typescript/module/src/sharedTypes.d.ts +8 -3
  199. package/lib/typescript/module/src/sharedTypes.d.ts.map +1 -1
  200. package/package.json +28 -6
  201. package/react-native.config.js +3 -0
  202. package/shared/PCButtonComponentDescriptors-custom.h +22 -0
  203. package/shared/PCButtonGroupComponentDescriptors-custom.h +22 -0
  204. package/shared/PCButtonGroupShadowNode-custom.cpp +48 -0
  205. package/shared/PCButtonGroupShadowNode-custom.h +55 -0
  206. package/shared/PCButtonGroupState-custom.h +61 -0
  207. package/shared/PCButtonShadowNode-custom.cpp +48 -0
  208. package/shared/PCButtonShadowNode-custom.h +55 -0
  209. package/shared/PCButtonState-custom.h +61 -0
  210. package/shared/PCDatePickerState-custom.h +2 -2
  211. package/shared/PCSegmentedControlState-custom.h +2 -2
  212. package/shared/PCSelectionMenuState-custom.h +2 -2
  213. package/shared/PCTextFieldComponentDescriptors-custom.h +22 -0
  214. package/shared/PCTextFieldShadowNode-custom.cpp +47 -0
  215. package/shared/PCTextFieldShadowNode-custom.h +55 -0
  216. package/shared/PCTextFieldState-custom.h +61 -0
  217. package/shared/react/renderer/components/PlatformComponentsViewSpec/ComponentDescriptors.h +3 -0
  218. package/src/Button.tsx +144 -0
  219. package/src/ButtonGroup.tsx +233 -0
  220. package/src/ButtonGroupNativeComponent.ts +121 -0
  221. package/src/ButtonNativeComponent.ts +76 -0
  222. package/src/ContextMenuNativeComponent.ts +5 -4
  223. package/src/DatePickerNativeComponent.ts +17 -11
  224. package/src/FloatingToolbar.tsx +113 -0
  225. package/src/FloatingToolbarNativeComponent.ts +31 -0
  226. package/src/LiquidGlass.tsx +24 -5
  227. package/src/LiquidGlassNativeComponent.ts +6 -5
  228. package/src/NativePlatformComponentsTheme.ts +11 -2
  229. package/src/SegmentedControl.tsx +26 -118
  230. package/src/SegmentedControlNativeComponent.ts +15 -11
  231. package/src/SelectionMenuNativeComponent.ts +6 -5
  232. package/src/TextField.tsx +494 -0
  233. package/src/TextFieldNativeComponent.ts +218 -0
  234. package/src/codegenTypes.ts +40 -0
  235. package/src/focusRegistry.ts +89 -0
  236. package/src/icons.ts +116 -0
  237. package/src/index.tsx +6 -0
  238. package/src/index.web.tsx +194 -0
  239. package/src/labelStyle.ts +36 -0
  240. package/src/reactNativeInternals.d.ts +22 -0
  241. package/src/sharedTypes.ts +9 -3
  242. /package/{app.plugin.cjs → app.plugin.js} +0 -0
@@ -0,0 +1,95 @@
1
+ import UIKit
2
+
3
+ /// The floating toolbar container: a Liquid Glass capsule on iOS 26, and a
4
+ /// blur-material capsule with a soft shadow on earlier versions, where a blur
5
+ /// over a flat background would otherwise have no edge.
6
+ @objcMembers
7
+ public final class PCFloatingToolbarView: UIView {
8
+ // MARK: - Props (set from ObjC++)
9
+
10
+ /// "regular" | "clear"
11
+ public var effectStyle: String = "regular" {
12
+ didSet { if oldValue != effectStyle { applyEffect() } }
13
+ }
14
+
15
+ /// Tint over the material; nil keeps the plain material
16
+ public var tintUIColor: UIColor? {
17
+ didSet { applyEffect() }
18
+ }
19
+
20
+ /// React children mount here
21
+ public var contentView: UIView { effectView.contentView }
22
+
23
+ // MARK: - Internal
24
+
25
+ private let effectView = UIVisualEffectView(effect: nil)
26
+
27
+ /// Liquid Glass needs both the iOS 26 SDK at build time and iOS 26 at runtime.
28
+ private static var glassAvailable: Bool {
29
+ #if compiler(>=6.2)
30
+ if #available(iOS 26.0, *) { return true }
31
+ #endif
32
+ return false
33
+ }
34
+
35
+ // MARK: - Init
36
+
37
+ public override init(frame: CGRect) {
38
+ super.init(frame: frame)
39
+ setup()
40
+ }
41
+
42
+ public required init?(coder: NSCoder) {
43
+ super.init(coder: coder)
44
+ setup()
45
+ }
46
+
47
+ private func setup() {
48
+ clipsToBounds = false
49
+ effectView.layer.cornerCurve = .continuous
50
+ addSubview(effectView)
51
+
52
+ if !Self.glassAvailable {
53
+ // The blur is clipped to the capsule; the shadow lives on this view
54
+ effectView.clipsToBounds = true
55
+ layer.shadowColor = UIColor.black.cgColor
56
+ layer.shadowOpacity = 0.12
57
+ layer.shadowRadius = 10
58
+ layer.shadowOffset = CGSize(width: 0, height: 4)
59
+ }
60
+ applyEffect()
61
+ }
62
+
63
+ // MARK: - Layout
64
+
65
+ public override func layoutSubviews() {
66
+ super.layoutSubviews()
67
+ effectView.frame = bounds
68
+ let radius = min(bounds.width, bounds.height) / 2
69
+ effectView.layer.cornerRadius = radius
70
+ if !Self.glassAvailable {
71
+ layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: radius).cgPath
72
+ }
73
+ }
74
+
75
+ // MARK: - Effect
76
+
77
+ private func applyEffect() {
78
+ #if compiler(>=6.2)
79
+ if #available(iOS 26.0, *) {
80
+ let glass = UIGlassEffect(style: effectStyle == "clear" ? .clear : .regular)
81
+ if let tintUIColor {
82
+ glass.tintColor = tintUIColor
83
+ }
84
+ effectView.effect = glass
85
+ effectView.contentView.backgroundColor = nil
86
+ return
87
+ }
88
+ #endif
89
+ effectView.effect = UIBlurEffect(
90
+ style: effectStyle == "clear" ? .systemUltraThinMaterial : .systemThinMaterial
91
+ )
92
+ // UIBlurEffect has no tint; wash the content area with the color instead
93
+ effectView.contentView.backgroundColor = tintUIColor?.withAlphaComponent(0.35)
94
+ }
95
+ }
@@ -27,6 +27,19 @@ RCT_EXPORT_MODULE(PlatformComponentsTheme)
27
27
  });
28
28
  }
29
29
 
30
+ /// Reports what this *build* can do, not just what the device runs: with an
31
+ /// older Xcode the glass code is compiled out (see PCLiquidGlass.swift), so
32
+ /// the iOS version alone would be a false positive.
33
+ - (NSNumber *)isLiquidGlassSupported
34
+ {
35
+ #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 260000
36
+ if (@available(iOS 26.0, *)) {
37
+ return @(PCLiquidGlassView.isSupported);
38
+ }
39
+ #endif
40
+ return @NO;
41
+ }
42
+
30
43
  - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
31
44
  (const facebook::react::ObjCTurboModule::InitParams &)params
32
45
  {
@@ -473,8 +473,12 @@ private class PCMenuViewController: UIViewController, UITableViewDelegate, UITab
473
473
  menuContainer.clipsToBounds = true
474
474
  view.addSubview(menuContainer)
475
475
 
476
- // Use liquid glass on iOS 26+, fall back to system material blur on older versions
476
+ // Use liquid glass on iOS 26+, fall back to system material blur on older
477
+ // versions. UIGlassEffect only exists in the iOS 26 SDK, so the branch is
478
+ // compiled out entirely on older toolchains — same guard as
479
+ // PCLiquidGlass.swift, which keeps the library buildable without Xcode 26.
477
480
  let effectView: UIVisualEffectView
481
+ #if compiler(>=6.2)
478
482
  if #available(iOS 26, *) {
479
483
  let glassEffect = UIGlassEffect()
480
484
  glassEffect.isInteractive = true
@@ -483,6 +487,10 @@ private class PCMenuViewController: UIViewController, UITableViewDelegate, UITab
483
487
  let blurEffect = UIBlurEffect(style: .systemMaterial)
484
488
  effectView = UIVisualEffectView(effect: blurEffect)
485
489
  }
490
+ #else
491
+ let blurEffect = UIBlurEffect(style: .systemMaterial)
492
+ effectView = UIVisualEffectView(effect: blurEffect)
493
+ #endif
486
494
  effectView.frame = menuContainer.bounds
487
495
  effectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
488
496
  menuContainer.addSubview(effectView)
@@ -0,0 +1,10 @@
1
+ // PCTextField.h
2
+
3
+ #import <React/RCTViewComponentView.h>
4
+
5
+ NS_ASSUME_NONNULL_BEGIN
6
+
7
+ @interface PCTextField : RCTViewComponentView
8
+ @end
9
+
10
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,391 @@
1
+ // PCTextField.mm
2
+
3
+ #import "PCTextField.h"
4
+
5
+ #import <React/RCTComponentViewFactory.h>
6
+ #import <React/RCTConversions.h>
7
+ #import <React/RCTFabricComponentsPlugins.h>
8
+ #import <React/RCTFont.h>
9
+
10
+ #import <react/renderer/components/PlatformComponentsViewSpec/ComponentDescriptors.h>
11
+ #import <react/renderer/components/PlatformComponentsViewSpec/EventEmitters.h>
12
+ #import <react/renderer/components/PlatformComponentsViewSpec/Props.h>
13
+ #import <react/renderer/components/PlatformComponentsViewSpec/RCTComponentViewHelpers.h>
14
+ #import <react/renderer/core/LayoutPrimitives.h>
15
+
16
+ #if __has_include(<PlatformComponents/PlatformComponents-Swift.h>)
17
+ #import <PlatformComponents/PlatformComponents-Swift.h>
18
+ #else
19
+ #import "PlatformComponents-Swift.h"
20
+ #endif
21
+
22
+ #import "PCTextFieldComponentDescriptors-custom.h"
23
+ #import "PCTextFieldShadowNode-custom.h"
24
+ #import "PCTextFieldState-custom.h"
25
+
26
+ using namespace facebook::react;
27
+
28
+ namespace {
29
+ static inline NSString *NSStringFromStd(const std::string &s, NSString *fallback) {
30
+ return s.empty() ? fallback : [NSString stringWithUTF8String:s.c_str()];
31
+ }
32
+
33
+ static inline bool IconEqual(const PCTextFieldLeadingIconStruct &a, const PCTextFieldLeadingIconStruct &b) {
34
+ return a.iconType == b.iconType && a.iconName == b.iconName && a.iconUri == b.iconUri &&
35
+ a.iconScale == b.iconScale && a.iconTinted == b.iconTinted;
36
+ }
37
+
38
+ static inline bool IconEqual(const PCTextFieldTrailingIconStruct &a, const PCTextFieldTrailingIconStruct &b) {
39
+ return a.iconType == b.iconType && a.iconName == b.iconName && a.iconUri == b.iconUri &&
40
+ a.iconScale == b.iconScale && a.iconTinted == b.iconTinted;
41
+ }
42
+
43
+ static inline bool TextStyleEqual(
44
+ const PCTextFieldTextStyleStruct &a,
45
+ const PCTextFieldTextStyleStruct &b) {
46
+ return a.fontFamily == b.fontFamily && a.fontSize == b.fontSize &&
47
+ a.fontWeight == b.fontWeight && a.fontStyle == b.fontStyle;
48
+ }
49
+
50
+ /// Builds the input font from RN-style font props, or nil when every field is
51
+ /// unset so the field keeps the body text style.
52
+ static UIFont *FontFromTextStyle(const PCTextFieldTextStyleStruct &style) {
53
+ if (style.fontFamily.empty() && style.fontSize <= 0 &&
54
+ style.fontWeight.empty() && style.fontStyle.empty()) {
55
+ return nil;
56
+ }
57
+ return [RCTFont updateFont:[UIFont preferredFontForTextStyle:UIFontTextStyleBody]
58
+ withFamily:NSStringFromStd(style.fontFamily, nil)
59
+ size:style.fontSize > 0 ? @(style.fontSize) : nil
60
+ weight:NSStringFromStd(style.fontWeight, nil)
61
+ style:NSStringFromStd(style.fontStyle, nil)
62
+ variant:nil
63
+ scaleMultiplier:1.0];
64
+ }
65
+ } // namespace
66
+
67
+ @interface PCTextField () <RCTPCTextFieldViewProtocol>
68
+
69
+ - (void)updateMeasurements;
70
+
71
+ @end
72
+
73
+ @implementation PCTextField {
74
+ PCTextFieldView *_view;
75
+ MeasuringPCTextFieldShadowNode::ConcreteState::Shared _state;
76
+ }
77
+
78
+ + (ComponentDescriptorProvider)componentDescriptorProvider {
79
+ return concreteComponentDescriptorProvider<MeasuringPCTextFieldComponentDescriptor>();
80
+ }
81
+
82
+ // A first responder with typed text is not something to hand to another
83
+ // element; keep every field its own view.
84
+ + (BOOL)shouldBeRecycled {
85
+ return NO;
86
+ }
87
+
88
+ - (instancetype)initWithFrame:(CGRect)frame {
89
+ if (self = [super initWithFrame:frame]) {
90
+ _view = [PCTextFieldView new];
91
+ self.contentView = _view;
92
+
93
+ __weak __typeof(self) weakSelf = self;
94
+
95
+ _view.onChange = ^(NSString *text, NSInteger eventCount) {
96
+ __typeof(self) strongSelf = weakSelf;
97
+ if (!strongSelf) return;
98
+
99
+ auto eventEmitter =
100
+ std::static_pointer_cast<const PCTextFieldEventEmitter>(strongSelf->_eventEmitter);
101
+ if (!eventEmitter) return;
102
+
103
+ PCTextFieldEventEmitter::OnFieldChange payload = {
104
+ .text = text.UTF8String,
105
+ .eventCount = (int)eventCount,
106
+ };
107
+ eventEmitter->onFieldChange(payload);
108
+ };
109
+
110
+ _view.onFocusChange = ^(BOOL focused, NSString *text) {
111
+ __typeof(self) strongSelf = weakSelf;
112
+ if (!strongSelf) return;
113
+
114
+ auto eventEmitter =
115
+ std::static_pointer_cast<const PCTextFieldEventEmitter>(strongSelf->_eventEmitter);
116
+ if (!eventEmitter) return;
117
+
118
+ if (focused) {
119
+ eventEmitter->onFieldFocus({.text = text.UTF8String});
120
+ } else {
121
+ eventEmitter->onFieldBlur({.text = text.UTF8String});
122
+ }
123
+ };
124
+
125
+ _view.onSubmit = ^(NSString *text) {
126
+ __typeof(self) strongSelf = weakSelf;
127
+ if (!strongSelf) return;
128
+
129
+ auto eventEmitter =
130
+ std::static_pointer_cast<const PCTextFieldEventEmitter>(strongSelf->_eventEmitter);
131
+ if (!eventEmitter) return;
132
+
133
+ eventEmitter->onFieldSubmit({.text = text.UTF8String});
134
+ };
135
+
136
+ _view.onTrailingIconPress = ^{
137
+ __typeof(self) strongSelf = weakSelf;
138
+ if (!strongSelf) return;
139
+
140
+ auto eventEmitter =
141
+ std::static_pointer_cast<const PCTextFieldEventEmitter>(strongSelf->_eventEmitter);
142
+ if (!eventEmitter) return;
143
+
144
+ eventEmitter->onTrailingIconPress({});
145
+ };
146
+
147
+ _view.onNeedsRemeasure = ^{
148
+ __typeof(self) strongSelf = weakSelf;
149
+ if (!strongSelf) return;
150
+ [strongSelf updateMeasurements];
151
+ };
152
+ }
153
+ return self;
154
+ }
155
+
156
+ - (void)updateProps:(Props::Shared const &)props
157
+ oldProps:(Props::Shared const &)oldProps {
158
+ const auto &newProps = *std::static_pointer_cast<const PCTextFieldProps>(props);
159
+ const auto prevProps = std::static_pointer_cast<const PCTextFieldProps>(oldProps);
160
+
161
+ // Only the first value counts; later text arrives through setText
162
+ if (!prevProps || newProps.initialText != prevProps->initialText) {
163
+ [_view applyInitialText:NSStringFromStd(newProps.initialText, @"")];
164
+ }
165
+
166
+ if (!prevProps || newProps.label != prevProps->label) {
167
+ _view.label = NSStringFromStd(newProps.label, @"");
168
+ }
169
+
170
+ if (!prevProps || newProps.placeholder != prevProps->placeholder) {
171
+ _view.placeholder = NSStringFromStd(newProps.placeholder, @"");
172
+ }
173
+
174
+ if (!prevProps || newProps.supportingText != prevProps->supportingText) {
175
+ _view.supportingText = NSStringFromStd(newProps.supportingText, @"");
176
+ }
177
+
178
+ if (!prevProps || newProps.errorState != prevProps->errorState) {
179
+ _view.errorState = NSStringFromStd(newProps.errorState, @"none");
180
+ }
181
+
182
+ if (!prevProps || newProps.errorText != prevProps->errorText) {
183
+ _view.errorText = NSStringFromStd(newProps.errorText, @"");
184
+ }
185
+
186
+ if (!prevProps || newProps.prefix != prevProps->prefix) {
187
+ _view.prefix = NSStringFromStd(newProps.prefix, @"");
188
+ }
189
+
190
+ if (!prevProps || newProps.suffix != prevProps->suffix) {
191
+ _view.suffix = NSStringFromStd(newProps.suffix, @"");
192
+ }
193
+
194
+ // icons: {iconType, iconName, iconUri, iconScale, iconTinted}
195
+ if (!prevProps || !IconEqual(newProps.leadingIcon, prevProps->leadingIcon)) {
196
+ const auto &icon = newProps.leadingIcon;
197
+ [_view setLeadingIconWithType:NSStringFromStd(icon.iconType, @"")
198
+ name:NSStringFromStd(icon.iconName, @"")
199
+ uri:NSStringFromStd(icon.iconUri, @"")
200
+ scale:icon.iconScale
201
+ tinted:(icon.iconTinted != "false")];
202
+ }
203
+
204
+ if (!prevProps || !IconEqual(newProps.trailingIcon, prevProps->trailingIcon)) {
205
+ const auto &icon = newProps.trailingIcon;
206
+ [_view setTrailingIconWithType:NSStringFromStd(icon.iconType, @"")
207
+ name:NSStringFromStd(icon.iconName, @"")
208
+ uri:NSStringFromStd(icon.iconUri, @"")
209
+ scale:icon.iconScale
210
+ tinted:(icon.iconTinted != "false")];
211
+ }
212
+
213
+ if (!prevProps || newProps.clearButtonMode != prevProps->clearButtonMode) {
214
+ _view.clearButtonMode = NSStringFromStd(newProps.clearButtonMode, @"never");
215
+ }
216
+
217
+ if (!prevProps || newProps.passwordToggle != prevProps->passwordToggle) {
218
+ _view.passwordToggle = newProps.passwordToggle == "shown";
219
+ }
220
+
221
+ if (!prevProps || newProps.characterCount != prevProps->characterCount) {
222
+ _view.characterCount = newProps.characterCount == "shown";
223
+ }
224
+
225
+ if (!prevProps || newProps.maxLength != prevProps->maxLength) {
226
+ _view.maxLength = newProps.maxLength;
227
+ }
228
+
229
+ if (!prevProps || newProps.keyboardType != prevProps->keyboardType) {
230
+ _view.keyboardType = NSStringFromStd(newProps.keyboardType, @"default");
231
+ }
232
+
233
+ if (!prevProps || newProps.returnKeyType != prevProps->returnKeyType) {
234
+ _view.returnKeyType = NSStringFromStd(newProps.returnKeyType, @"default");
235
+ }
236
+
237
+ if (!prevProps || newProps.autoCapitalize != prevProps->autoCapitalize) {
238
+ _view.autoCapitalize = NSStringFromStd(newProps.autoCapitalize, @"sentences");
239
+ }
240
+
241
+ if (!prevProps || newProps.autoCorrect != prevProps->autoCorrect) {
242
+ _view.autoCorrect = newProps.autoCorrect != "disabled";
243
+ }
244
+
245
+ if (!prevProps || newProps.secureTextEntry != prevProps->secureTextEntry) {
246
+ _view.secureTextEntry = newProps.secureTextEntry == "secure";
247
+ }
248
+
249
+ if (!prevProps || newProps.lines != prevProps->lines) {
250
+ _view.multiline = newProps.lines == "multiline";
251
+ }
252
+
253
+ if (!prevProps || newProps.interactivity != prevProps->interactivity) {
254
+ _view.interactivity = NSStringFromStd(newProps.interactivity, @"enabled");
255
+ }
256
+
257
+ if (!prevProps || newProps.selectTextOnFocus != prevProps->selectTextOnFocus) {
258
+ _view.selectTextOnFocus = newProps.selectTextOnFocus == "select";
259
+ }
260
+
261
+ if (!prevProps || newProps.autoComplete != prevProps->autoComplete) {
262
+ _view.autoComplete = NSStringFromStd(newProps.autoComplete, @"");
263
+ }
264
+
265
+ if (!prevProps || newProps.keyboardAppearance != prevProps->keyboardAppearance) {
266
+ _view.keyboardAppearance = NSStringFromStd(newProps.keyboardAppearance, @"default");
267
+ }
268
+
269
+ // textStyle: {fontFamily, fontSize, fontWeight, fontStyle}
270
+ if (!prevProps || !TextStyleEqual(newProps.textStyle, prevProps->textStyle)) {
271
+ _view.textFont = FontFromTextStyle(newProps.textStyle);
272
+ }
273
+
274
+ if (!prevProps || newProps.spokenLabel != prevProps->spokenLabel) {
275
+ _view.spokenLabel = NSStringFromStd(newProps.spokenLabel, @"");
276
+ }
277
+
278
+ // ios: the text traits
279
+ const auto &newIOS = newProps.ios;
280
+ const auto &oldIOS = prevProps ? prevProps->ios : PCTextFieldIosStruct{};
281
+ if (!prevProps || newIOS.writingTools != oldIOS.writingTools) {
282
+ _view.writingTools = NSStringFromStd(newIOS.writingTools, @"");
283
+ }
284
+ if (!prevProps || newIOS.inlinePrediction != oldIOS.inlinePrediction) {
285
+ _view.inlinePrediction = NSStringFromStd(newIOS.inlinePrediction, @"");
286
+ }
287
+ if (!prevProps || newIOS.smartQuotes != oldIOS.smartQuotes) {
288
+ _view.smartQuotes = NSStringFromStd(newIOS.smartQuotes, @"");
289
+ }
290
+ if (!prevProps || newIOS.smartDashes != oldIOS.smartDashes) {
291
+ _view.smartDashes = NSStringFromStd(newIOS.smartDashes, @"");
292
+ }
293
+ if (!prevProps || newIOS.smartInsertDelete != oldIOS.smartInsertDelete) {
294
+ _view.smartInsertDelete = NSStringFromStd(newIOS.smartInsertDelete, @"");
295
+ }
296
+ if (!prevProps || newIOS.mathExpressionCompletion != oldIOS.mathExpressionCompletion) {
297
+ _view.mathExpressionCompletion = NSStringFromStd(newIOS.mathExpressionCompletion, @"");
298
+ }
299
+ if (!prevProps || newIOS.borderStyle != oldIOS.borderStyle) {
300
+ _view.borderStyle = NSStringFromStd(newIOS.borderStyle, @"");
301
+ }
302
+ if (!prevProps || newIOS.labelPlacement != oldIOS.labelPlacement) {
303
+ _view.labelPlacement = NSStringFromStd(newIOS.labelPlacement, @"");
304
+ }
305
+ if (!prevProps || newIOS.labelWidth != oldIOS.labelWidth) {
306
+ _view.labelWidth = newIOS.labelWidth;
307
+ }
308
+
309
+ // autoFocus last, once the field is configured
310
+ if (!prevProps || newProps.autoFocus != prevProps->autoFocus) {
311
+ _view.autoFocus = newProps.autoFocus == "focus";
312
+ }
313
+
314
+ // android: Android only
315
+
316
+ [super updateProps:props oldProps:oldProps];
317
+
318
+ // Update measurements when props change that affect layout
319
+ [self updateMeasurements];
320
+ }
321
+
322
+ - (void)prepareForRecycle {
323
+ [super prepareForRecycle];
324
+ [_view resetForRecycle];
325
+ }
326
+
327
+ #pragma mark - Commands
328
+
329
+ - (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args {
330
+ RCTPCTextFieldHandleCommand(self, commandName, args);
331
+ }
332
+
333
+ - (void)focus {
334
+ [_view focus];
335
+ }
336
+
337
+ - (void)blur {
338
+ [_view blur];
339
+ }
340
+
341
+ - (void)clear {
342
+ [_view clear];
343
+ }
344
+
345
+ - (void)setText:(NSInteger)eventCount text:(NSString *)text {
346
+ [_view setText:text ?: @"" eventCount:eventCount];
347
+ }
348
+
349
+ #pragma mark - State (Measuring)
350
+
351
+ - (void)updateState:(const State::Shared &)state
352
+ oldState:(const State::Shared &)oldState {
353
+ _state = std::static_pointer_cast<const MeasuringPCTextFieldShadowNode::ConcreteState>(state);
354
+
355
+ if (oldState == nullptr) {
356
+ // First time: compute initial size.
357
+ [self updateMeasurements];
358
+ }
359
+
360
+ [super updateState:state oldState:oldState];
361
+ }
362
+
363
+ - (void)updateLayoutMetrics:(const LayoutMetrics &)layoutMetrics
364
+ oldLayoutMetrics:(const LayoutMetrics &)oldLayoutMetrics {
365
+ [super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics];
366
+ // A new width changes how multi-line text and supporting text wrap
367
+ if (layoutMetrics.frame.size.width != oldLayoutMetrics.frame.size.width) {
368
+ [self updateMeasurements];
369
+ }
370
+ }
371
+
372
+ - (void)updateMeasurements {
373
+ if (_state == nullptr)
374
+ return;
375
+
376
+ // The height the field needs at its current width; the width itself is
377
+ // whatever Yoga offers (see the shadow node).
378
+ CGSize size = [_view sizeForLayoutWithConstrainedTo:CGSizeMake(self.bounds.size.width, 0)];
379
+
380
+ PCTextFieldStateFrameSize next;
381
+ next.frameSize = {(Float)size.width, (Float)size.height};
382
+ if (_state->getData() != next) {
383
+ _state->updateState(std::move(next));
384
+ }
385
+ }
386
+
387
+ @end
388
+
389
+ Class<RCTComponentViewProtocol> PCTextFieldCls(void) {
390
+ return PCTextField.class;
391
+ }