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,196 @@
1
+ // PCButton.mm
2
+
3
+ #import "PCButton.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/core/LayoutPrimitives.h>
14
+
15
+ #if __has_include(<PlatformComponents/PlatformComponents-Swift.h>)
16
+ #import <PlatformComponents/PlatformComponents-Swift.h>
17
+ #else
18
+ #import "PlatformComponents-Swift.h"
19
+ #endif
20
+
21
+ #import "PCButtonComponentDescriptors-custom.h"
22
+ #import "PCButtonShadowNode-custom.h"
23
+ #import "PCButtonState-custom.h"
24
+
25
+ using namespace facebook::react;
26
+
27
+ namespace {
28
+ static inline NSString *NSStringFromStd(const std::string &s, NSString *fallback) {
29
+ return s.empty() ? fallback : [NSString stringWithUTF8String:s.c_str()];
30
+ }
31
+
32
+ static inline bool IconEqual(const PCButtonIconStruct &a, const PCButtonIconStruct &b) {
33
+ return a.iconType == b.iconType && a.iconName == b.iconName && a.iconUri == b.iconUri &&
34
+ a.iconScale == b.iconScale && a.iconTinted == b.iconTinted;
35
+ }
36
+
37
+ static inline bool LabelStyleEqual(
38
+ const PCButtonLabelStyleStruct &a,
39
+ const PCButtonLabelStyleStruct &b) {
40
+ return a.fontFamily == b.fontFamily && a.fontSize == b.fontSize &&
41
+ a.fontWeight == b.fontWeight && a.fontStyle == b.fontStyle;
42
+ }
43
+
44
+ /// Builds the label font from RN-style font props, or nil when every field is
45
+ /// unset so the button keeps the configuration's font.
46
+ static UIFont *FontFromLabelStyle(const PCButtonLabelStyleStruct &style) {
47
+ if (style.fontFamily.empty() && style.fontSize <= 0 &&
48
+ style.fontWeight.empty() && style.fontStyle.empty()) {
49
+ return nil;
50
+ }
51
+ // UIButton titles default to the body text style; start there so a lone
52
+ // fontWeight or fontStyle doesn't change the size.
53
+ return [RCTFont updateFont:[UIFont preferredFontForTextStyle:UIFontTextStyleBody]
54
+ withFamily:NSStringFromStd(style.fontFamily, nil)
55
+ size:style.fontSize > 0 ? @(style.fontSize) : nil
56
+ weight:NSStringFromStd(style.fontWeight, nil)
57
+ style:NSStringFromStd(style.fontStyle, nil)
58
+ variant:nil
59
+ scaleMultiplier:1.0];
60
+ }
61
+ } // namespace
62
+
63
+ @interface PCButton ()
64
+
65
+ - (void)updateMeasurements;
66
+
67
+ @end
68
+
69
+ @implementation PCButton {
70
+ PCButtonView *_view;
71
+ MeasuringPCButtonShadowNode::ConcreteState::Shared _state;
72
+ }
73
+
74
+ + (ComponentDescriptorProvider)componentDescriptorProvider {
75
+ return concreteComponentDescriptorProvider<MeasuringPCButtonComponentDescriptor>();
76
+ }
77
+
78
+ - (instancetype)initWithFrame:(CGRect)frame {
79
+ if (self = [super initWithFrame:frame]) {
80
+ _view = [PCButtonView new];
81
+ self.contentView = _view;
82
+
83
+ __weak __typeof(self) weakSelf = self;
84
+
85
+ _view.onPress = ^{
86
+ __typeof(self) strongSelf = weakSelf;
87
+ if (!strongSelf) return;
88
+
89
+ auto eventEmitter =
90
+ std::static_pointer_cast<const PCButtonEventEmitter>(strongSelf->_eventEmitter);
91
+ if (!eventEmitter) return;
92
+
93
+ eventEmitter->onButtonPress({});
94
+ };
95
+
96
+ _view.onNeedsRemeasure = ^{
97
+ __typeof(self) strongSelf = weakSelf;
98
+ if (!strongSelf) return;
99
+ [strongSelf updateMeasurements];
100
+ };
101
+ }
102
+ return self;
103
+ }
104
+
105
+ - (void)updateProps:(Props::Shared const &)props
106
+ oldProps:(Props::Shared const &)oldProps {
107
+ const auto &newProps = *std::static_pointer_cast<const PCButtonProps>(props);
108
+ const auto prevProps = std::static_pointer_cast<const PCButtonProps>(oldProps);
109
+
110
+ if (!prevProps || newProps.label != prevProps->label) {
111
+ _view.label = NSStringFromStd(newProps.label, @"");
112
+ }
113
+
114
+ // icon: {iconType, iconName, iconUri, iconScale, iconTinted}
115
+ if (!prevProps || !IconEqual(newProps.icon, prevProps->icon)) {
116
+ const auto &icon = newProps.icon;
117
+ [_view setIconWithType:NSStringFromStd(icon.iconType, @"")
118
+ name:NSStringFromStd(icon.iconName, @"")
119
+ uri:NSStringFromStd(icon.iconUri, @"")
120
+ scale:icon.iconScale
121
+ tinted:(icon.iconTinted != "false")];
122
+ }
123
+
124
+ if (!prevProps || newProps.variant != prevProps->variant) {
125
+ _view.variant = NSStringFromStd(newProps.variant, @"filled");
126
+ }
127
+
128
+ if (!prevProps || newProps.size != prevProps->size) {
129
+ _view.size = NSStringFromStd(newProps.size, @"small");
130
+ }
131
+
132
+ if (!prevProps || newProps.shape != prevProps->shape) {
133
+ _view.shape = NSStringFromStd(newProps.shape, @"");
134
+ }
135
+
136
+ if (!prevProps || newProps.interactivity != prevProps->interactivity) {
137
+ _view.interactivity = NSStringFromStd(newProps.interactivity, @"enabled");
138
+ }
139
+
140
+ // Colors arrive as SharedColor (already processed by React Native)
141
+ if (!prevProps || newProps.color != prevProps->color) {
142
+ _view.containerColor = RCTUIColorFromSharedColor(newProps.color);
143
+ }
144
+
145
+ if (!prevProps || newProps.foregroundColor != prevProps->foregroundColor) {
146
+ _view.foregroundColor = RCTUIColorFromSharedColor(newProps.foregroundColor);
147
+ }
148
+
149
+ // labelStyle: {fontFamily, fontSize, fontWeight, fontStyle}
150
+ if (!prevProps || !LabelStyleEqual(newProps.labelStyle, prevProps->labelStyle)) {
151
+ _view.labelFont = FontFromLabelStyle(newProps.labelStyle);
152
+ }
153
+
154
+ if (!prevProps || newProps.spokenLabel != prevProps->spokenLabel) {
155
+ _view.spokenLabel = NSStringFromStd(newProps.spokenLabel, @"");
156
+ }
157
+
158
+ // androidRippleColor / androidStrokeColor: Android only
159
+
160
+ [super updateProps:props oldProps:oldProps];
161
+
162
+ // Update measurements when props change that affect layout
163
+ [self updateMeasurements];
164
+ }
165
+
166
+ #pragma mark - State (Measuring)
167
+
168
+ - (void)updateState:(const State::Shared &)state
169
+ oldState:(const State::Shared &)oldState {
170
+ _state = std::static_pointer_cast<const MeasuringPCButtonShadowNode::ConcreteState>(state);
171
+
172
+ if (oldState == nullptr) {
173
+ // First time: compute initial size.
174
+ [self updateMeasurements];
175
+ }
176
+
177
+ [super updateState:state oldState:oldState];
178
+ }
179
+
180
+ - (void)updateMeasurements {
181
+ if (_state == nullptr)
182
+ return;
183
+
184
+ // The button's natural size; Yoga clamps it to the available width
185
+ CGSize size = [_view sizeForLayoutWithConstrainedTo:CGSizeZero];
186
+
187
+ PCButtonStateFrameSize next;
188
+ next.frameSize = {(Float)size.width, (Float)size.height};
189
+ _state->updateState(std::move(next));
190
+ }
191
+
192
+ @end
193
+
194
+ Class<RCTComponentViewProtocol> PCButtonCls(void) {
195
+ return PCButton.class;
196
+ }
@@ -0,0 +1,10 @@
1
+ // PCButtonGroup.h
2
+
3
+ #import <React/RCTViewComponentView.h>
4
+
5
+ NS_ASSUME_NONNULL_BEGIN
6
+
7
+ @interface PCButtonGroup : RCTViewComponentView
8
+ @end
9
+
10
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,256 @@
1
+ // PCButtonGroup.mm
2
+
3
+ #import "PCButtonGroup.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/core/LayoutPrimitives.h>
14
+
15
+ #if __has_include(<PlatformComponents/PlatformComponents-Swift.h>)
16
+ #import <PlatformComponents/PlatformComponents-Swift.h>
17
+ #else
18
+ #import "PlatformComponents-Swift.h"
19
+ #endif
20
+
21
+ #import "PCButtonGroupComponentDescriptors-custom.h"
22
+ #import "PCButtonGroupShadowNode-custom.h"
23
+ #import "PCButtonGroupState-custom.h"
24
+
25
+ using namespace facebook::react;
26
+
27
+ namespace {
28
+ static inline bool ButtonsEqual(
29
+ const std::vector<PCButtonGroupButtonsStruct> &a,
30
+ const std::vector<PCButtonGroupButtonsStruct> &b) {
31
+ if (a.size() != b.size()) return false;
32
+ for (size_t i = 0; i < a.size(); i++) {
33
+ if (a[i].label != b[i].label) return false;
34
+ if (a[i].value != b[i].value) return false;
35
+ if (a[i].disabled != b[i].disabled) return false;
36
+ if (a[i].iconType != b[i].iconType) return false;
37
+ if (a[i].iconName != b[i].iconName) return false;
38
+ if (a[i].iconUri != b[i].iconUri) return false;
39
+ if (a[i].iconScale != b[i].iconScale) return false;
40
+ if (a[i].iconTinted != b[i].iconTinted) return false;
41
+ if (a[i].accessibilityLabel != b[i].accessibilityLabel) return false;
42
+ }
43
+ return true;
44
+ }
45
+
46
+ static inline NSString *NSStringFromStd(const std::string &s, NSString *fallback) {
47
+ return s.empty() ? fallback : [NSString stringWithUTF8String:s.c_str()];
48
+ }
49
+
50
+ static inline NSArray<NSString *> *NSArrayFromStd(const std::vector<std::string> &values) {
51
+ NSMutableArray<NSString *> *arr = [NSMutableArray arrayWithCapacity:values.size()];
52
+ for (const auto &value : values) {
53
+ [arr addObject:NSStringFromStd(value, @"")];
54
+ }
55
+ return arr;
56
+ }
57
+
58
+ static inline bool LabelStyleEqual(
59
+ const PCButtonGroupLabelStyleStruct &a,
60
+ const PCButtonGroupLabelStyleStruct &b) {
61
+ return a.fontFamily == b.fontFamily && a.fontSize == b.fontSize &&
62
+ a.fontWeight == b.fontWeight && a.fontStyle == b.fontStyle;
63
+ }
64
+
65
+ /// Builds the label font from RN-style font props, or nil when every field is
66
+ /// unset so the buttons keep the configuration's font.
67
+ static UIFont *FontFromLabelStyle(const PCButtonGroupLabelStyleStruct &style) {
68
+ if (style.fontFamily.empty() && style.fontSize <= 0 &&
69
+ style.fontWeight.empty() && style.fontStyle.empty()) {
70
+ return nil;
71
+ }
72
+ return [RCTFont updateFont:[UIFont preferredFontForTextStyle:UIFontTextStyleBody]
73
+ withFamily:NSStringFromStd(style.fontFamily, nil)
74
+ size:style.fontSize > 0 ? @(style.fontSize) : nil
75
+ weight:NSStringFromStd(style.fontWeight, nil)
76
+ style:NSStringFromStd(style.fontStyle, nil)
77
+ variant:nil
78
+ scaleMultiplier:1.0];
79
+ }
80
+ } // namespace
81
+
82
+ @interface PCButtonGroup ()
83
+
84
+ - (void)updateMeasurements;
85
+
86
+ @end
87
+
88
+ @implementation PCButtonGroup {
89
+ PCButtonGroupView *_view;
90
+ MeasuringPCButtonGroupShadowNode::ConcreteState::Shared _state;
91
+ }
92
+
93
+ + (ComponentDescriptorProvider)componentDescriptorProvider {
94
+ return concreteComponentDescriptorProvider<MeasuringPCButtonGroupComponentDescriptor>();
95
+ }
96
+
97
+ - (instancetype)initWithFrame:(CGRect)frame {
98
+ if (self = [super initWithFrame:frame]) {
99
+ _view = [PCButtonGroupView new];
100
+ self.contentView = _view;
101
+
102
+ __weak __typeof(self) weakSelf = self;
103
+
104
+ _view.onPress = ^(NSInteger index, NSString *value) {
105
+ __typeof(self) strongSelf = weakSelf;
106
+ if (!strongSelf) return;
107
+
108
+ auto eventEmitter =
109
+ std::static_pointer_cast<const PCButtonGroupEventEmitter>(strongSelf->_eventEmitter);
110
+ if (!eventEmitter) return;
111
+
112
+ PCButtonGroupEventEmitter::OnButtonPress payload = {
113
+ .index = (int)index,
114
+ .value = value.UTF8String,
115
+ };
116
+ eventEmitter->onButtonPress(payload);
117
+ };
118
+
119
+ _view.onSelectionChange = ^(NSArray<NSString *> *values) {
120
+ __typeof(self) strongSelf = weakSelf;
121
+ if (!strongSelf) return;
122
+
123
+ auto eventEmitter =
124
+ std::static_pointer_cast<const PCButtonGroupEventEmitter>(strongSelf->_eventEmitter);
125
+ if (!eventEmitter) return;
126
+
127
+ PCButtonGroupEventEmitter::OnGroupSelectionChange payload;
128
+ for (NSString *value in values) {
129
+ payload.values.push_back(value.UTF8String);
130
+ }
131
+ eventEmitter->onGroupSelectionChange(payload);
132
+ };
133
+
134
+ _view.onNeedsRemeasure = ^{
135
+ __typeof(self) strongSelf = weakSelf;
136
+ if (!strongSelf) return;
137
+ [strongSelf updateMeasurements];
138
+ };
139
+ }
140
+ return self;
141
+ }
142
+
143
+ - (void)updateProps:(Props::Shared const &)props
144
+ oldProps:(Props::Shared const &)oldProps {
145
+ const auto &newProps = *std::static_pointer_cast<const PCButtonGroupProps>(props);
146
+ const auto prevProps = std::static_pointer_cast<const PCButtonGroupProps>(oldProps);
147
+
148
+ // buttons: [{label, value, disabled, iconType, iconName, iconUri, iconScale,
149
+ // iconTinted, accessibilityLabel}]
150
+ if (!prevProps || !ButtonsEqual(newProps.buttons, prevProps->buttons)) {
151
+ NSMutableArray *arr = [NSMutableArray new];
152
+ for (const auto &button : newProps.buttons) {
153
+ [arr addObject:@{
154
+ @"label": NSStringFromStd(button.label, @""),
155
+ @"value": NSStringFromStd(button.value, @""),
156
+ @"disabled": NSStringFromStd(button.disabled, @"enabled"),
157
+ @"iconType": NSStringFromStd(button.iconType, @""),
158
+ @"iconName": NSStringFromStd(button.iconName, @""),
159
+ @"iconUri": NSStringFromStd(button.iconUri, @""),
160
+ @"iconScale": @(button.iconScale),
161
+ @"iconTinted": NSStringFromStd(button.iconTinted, @"true"),
162
+ @"accessibilityLabel": NSStringFromStd(button.accessibilityLabel, @""),
163
+ }];
164
+ }
165
+ _view.buttons = arr;
166
+ }
167
+
168
+ if (!prevProps || newProps.variant != prevProps->variant) {
169
+ _view.variant = NSStringFromStd(newProps.variant, @"outlined");
170
+ }
171
+
172
+ if (!prevProps || newProps.size != prevProps->size) {
173
+ _view.size = NSStringFromStd(newProps.size, @"small");
174
+ }
175
+
176
+ if (!prevProps || newProps.shape != prevProps->shape) {
177
+ _view.shape = NSStringFromStd(newProps.shape, @"");
178
+ }
179
+
180
+ if (!prevProps || newProps.connected != prevProps->connected) {
181
+ _view.connected = (newProps.connected == "true");
182
+ }
183
+
184
+ if (!prevProps || newProps.spacing != prevProps->spacing) {
185
+ _view.spacing = newProps.spacing;
186
+ }
187
+
188
+ if (!prevProps || newProps.selection != prevProps->selection) {
189
+ _view.selection = NSStringFromStd(newProps.selection, @"none");
190
+ }
191
+
192
+ if (!prevProps || newProps.selectedValues != prevProps->selectedValues) {
193
+ _view.selectedValues = NSArrayFromStd(newProps.selectedValues);
194
+ }
195
+
196
+ if (!prevProps || newProps.selectionRequired != prevProps->selectionRequired) {
197
+ _view.selectionRequired = (newProps.selectionRequired == "true");
198
+ }
199
+
200
+ if (!prevProps || newProps.interactivity != prevProps->interactivity) {
201
+ _view.interactivity = NSStringFromStd(newProps.interactivity, @"enabled");
202
+ }
203
+
204
+ // Colors arrive as SharedColor (already processed by React Native)
205
+ if (!prevProps || newProps.color != prevProps->color) {
206
+ _view.containerColor = RCTUIColorFromSharedColor(newProps.color);
207
+ }
208
+
209
+ if (!prevProps || newProps.foregroundColor != prevProps->foregroundColor) {
210
+ _view.foregroundColor = RCTUIColorFromSharedColor(newProps.foregroundColor);
211
+ }
212
+
213
+ // labelStyle: {fontFamily, fontSize, fontWeight, fontStyle}
214
+ if (!prevProps || !LabelStyleEqual(newProps.labelStyle, prevProps->labelStyle)) {
215
+ _view.labelFont = FontFromLabelStyle(newProps.labelStyle);
216
+ }
217
+
218
+ // androidRippleColor / androidStrokeColor / android: Android only
219
+
220
+ [super updateProps:props oldProps:oldProps];
221
+
222
+ // Update measurements when props change that affect layout
223
+ [self updateMeasurements];
224
+ }
225
+
226
+ #pragma mark - State (Measuring)
227
+
228
+ - (void)updateState:(const State::Shared &)state
229
+ oldState:(const State::Shared &)oldState {
230
+ _state = std::static_pointer_cast<const MeasuringPCButtonGroupShadowNode::ConcreteState>(state);
231
+
232
+ if (oldState == nullptr) {
233
+ // First time: compute initial size.
234
+ [self updateMeasurements];
235
+ }
236
+
237
+ [super updateState:state oldState:oldState];
238
+ }
239
+
240
+ - (void)updateMeasurements {
241
+ if (_state == nullptr)
242
+ return;
243
+
244
+ // The group's natural size; Yoga clamps it to the available width
245
+ CGSize size = [_view sizeForLayoutWithConstrainedTo:CGSizeZero];
246
+
247
+ PCButtonGroupStateFrameSize next;
248
+ next.frameSize = {(Float)size.width, (Float)size.height};
249
+ _state->updateState(std::move(next));
250
+ }
251
+
252
+ @end
253
+
254
+ Class<RCTComponentViewProtocol> PCButtonGroupCls(void) {
255
+ return PCButtonGroup.class;
256
+ }