react-native-platform-components 1.4.0 → 1.5.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 (598) hide show
  1. package/PlatformComponents.podspec +1 -1
  2. package/README.md +33 -31
  3. package/android/src/main/java/com/platformcomponents/PCButtonGroupView.kt +175 -9
  4. package/android/src/main/java/com/platformcomponents/PCButtonGroupViewManager.kt +52 -2
  5. package/android/src/main/java/com/platformcomponents/PCButtonSupport.kt +44 -12
  6. package/android/src/main/java/com/platformcomponents/PCButtonView.kt +187 -5
  7. package/android/src/main/java/com/platformcomponents/PCButtonViewManager.kt +85 -7
  8. package/android/src/main/java/com/platformcomponents/PCContextMenuView.kt +41 -151
  9. package/android/src/main/java/com/platformcomponents/PCContextMenuViewManager.kt +7 -63
  10. package/android/src/main/java/com/platformcomponents/PCDatePickerView.kt +310 -115
  11. package/android/src/main/java/com/platformcomponents/PCDatePickerViewManager.kt +23 -3
  12. package/android/src/main/java/com/platformcomponents/PCExpressive.kt +6 -1
  13. package/android/src/main/java/com/platformcomponents/PCFloatingActionButtonView.kt +485 -0
  14. package/android/src/main/java/com/platformcomponents/PCFloatingActionButtonViewManager.kt +109 -0
  15. package/android/src/main/java/com/platformcomponents/PCFloatingToolbarView.kt +132 -0
  16. package/android/src/main/java/com/platformcomponents/PCFloatingToolbarViewManager.kt +8 -0
  17. package/android/src/main/java/com/platformcomponents/PCHaptics.kt +46 -0
  18. package/android/src/main/java/com/platformcomponents/PCImageLoader.kt +42 -7
  19. package/android/src/main/java/com/platformcomponents/PCLiquidGlassContainerView.kt +32 -0
  20. package/android/src/main/java/com/platformcomponents/PCLiquidGlassContainerViewManager.kt +31 -0
  21. package/android/src/main/java/com/platformcomponents/PCLiquidGlassView.kt +32 -6
  22. package/android/src/main/java/com/platformcomponents/PCLiquidGlassViewManager.kt +4 -0
  23. package/android/src/main/java/com/platformcomponents/PCMenuSupport.kt +280 -0
  24. package/android/src/main/java/com/platformcomponents/PCNavigationBarSupport.kt +332 -0
  25. package/android/src/main/java/com/platformcomponents/PCNavigationRailView.kt +448 -0
  26. package/android/src/main/java/com/platformcomponents/PCNavigationRailViewManager.kt +176 -0
  27. package/android/src/main/java/com/platformcomponents/PCSegmentedControlView.kt +24 -14
  28. package/android/src/main/java/com/platformcomponents/PCSegmentedControlViewManager.kt +14 -2
  29. package/android/src/main/java/com/platformcomponents/PCSelectionMenuView.kt +371 -39
  30. package/android/src/main/java/com/platformcomponents/PCSelectionMenuViewManager.kt +18 -4
  31. package/android/src/main/java/com/platformcomponents/PCTabBarView.kt +397 -0
  32. package/android/src/main/java/com/platformcomponents/PCTabBarViewManager.kt +182 -0
  33. package/android/src/main/java/com/platformcomponents/PCTextFieldView.kt +415 -40
  34. package/android/src/main/java/com/platformcomponents/PCTextFieldViewManager.kt +109 -3
  35. package/android/src/main/java/com/platformcomponents/PCThemeSupport.kt +37 -0
  36. package/android/src/main/java/com/platformcomponents/PlatformComponentsPackage.kt +4 -0
  37. package/android/src/main/res/drawable/pc_ic_search.xml +12 -0
  38. package/android/src/main/res/values/ids.xml +5 -0
  39. package/android/src/main/res/values/styles.xml +24 -0
  40. package/ios/PCButton.mm +122 -7
  41. package/ios/PCButtonGroup.mm +68 -1
  42. package/ios/PCButtonGroupView.swift +225 -6
  43. package/ios/PCButtonSupport.swift +181 -10
  44. package/ios/PCButtonView.swift +297 -14
  45. package/ios/PCConstants.swift +23 -2
  46. package/ios/PCContextMenu.mm +28 -110
  47. package/ios/PCContextMenu.swift +106 -167
  48. package/ios/PCDatePicker.mm +21 -9
  49. package/ios/PCDatePickerView.swift +94 -20
  50. package/ios/PCFloatingActionButton.h +10 -0
  51. package/ios/PCFloatingActionButton.mm +177 -0
  52. package/ios/PCFloatingActionButtonView.swift +426 -0
  53. package/ios/PCFloatingToolbar.mm +27 -0
  54. package/ios/PCFloatingToolbarView.swift +241 -0
  55. package/ios/PCHaptics.swift +91 -0
  56. package/ios/PCImageLoader.swift +76 -12
  57. package/ios/PCLiquidGlass.mm +36 -0
  58. package/ios/PCLiquidGlass.swift +221 -114
  59. package/ios/PCLiquidGlassContainer.h +10 -0
  60. package/ios/PCLiquidGlassContainer.mm +84 -0
  61. package/ios/PCLiquidGlassContainer.swift +69 -0
  62. package/ios/PCMenuItems.h +76 -0
  63. package/ios/PCMenuSupport.swift +350 -0
  64. package/ios/PCNavigationRail.h +10 -0
  65. package/ios/PCNavigationRail.mm +270 -0
  66. package/ios/PCNavigationRailView.swift +415 -0
  67. package/ios/PCSegmentedControl.mm +17 -2
  68. package/ios/PCSegmentedControl.swift +57 -7
  69. package/ios/PCSelectionMenu.mm +36 -8
  70. package/ios/PCSelectionMenu.swift +224 -48
  71. package/ios/PCTabBar.h +10 -0
  72. package/ios/PCTabBar.mm +285 -0
  73. package/ios/PCTabBarAccessory.h +10 -0
  74. package/ios/PCTabBarAccessory.mm +93 -0
  75. package/ios/PCTabBarAccessoryView.swift +96 -0
  76. package/ios/PCTabBarView.swift +671 -0
  77. package/ios/PCTextField.mm +159 -4
  78. package/ios/PCTextFieldView.swift +603 -57
  79. package/lib/commonjs/Button.js +73 -1
  80. package/lib/commonjs/Button.js.map +1 -1
  81. package/lib/commonjs/ButtonGroup.js +13 -3
  82. package/lib/commonjs/ButtonGroup.js.map +1 -1
  83. package/lib/commonjs/ButtonGroupNativeComponent.ts +74 -4
  84. package/lib/commonjs/ButtonNativeComponent.ts +119 -3
  85. package/lib/commonjs/ContextMenu.js +9 -48
  86. package/lib/commonjs/ContextMenu.js.map +1 -1
  87. package/lib/commonjs/ContextMenuNativeComponent.ts +47 -49
  88. package/lib/commonjs/DatePicker.js +98 -2
  89. package/lib/commonjs/DatePicker.js.map +1 -1
  90. package/lib/commonjs/DatePickerNativeComponent.ts +19 -2
  91. package/lib/commonjs/FloatingActionButton.js +60 -0
  92. package/lib/commonjs/FloatingActionButton.js.map +1 -0
  93. package/lib/commonjs/FloatingActionButtonNativeComponent.ts +58 -0
  94. package/lib/commonjs/FloatingToolbar.js +9 -1
  95. package/lib/commonjs/FloatingToolbar.js.map +1 -1
  96. package/lib/commonjs/FloatingToolbarNativeComponent.ts +16 -0
  97. package/lib/commonjs/LiquidGlass.js +7 -1
  98. package/lib/commonjs/LiquidGlass.js.map +1 -1
  99. package/lib/commonjs/LiquidGlassContainer.js +32 -0
  100. package/lib/commonjs/LiquidGlassContainer.js.map +1 -0
  101. package/lib/commonjs/LiquidGlassContainerNativeComponent.ts +17 -0
  102. package/lib/commonjs/LiquidGlassNativeComponent.ts +8 -0
  103. package/lib/commonjs/NavigationRail.js +104 -0
  104. package/lib/commonjs/NavigationRail.js.map +1 -0
  105. package/lib/commonjs/NavigationRailNativeComponent.ts +107 -0
  106. package/lib/commonjs/PlatformComponentsProvider.js +18 -0
  107. package/lib/commonjs/PlatformComponentsProvider.js.map +1 -0
  108. package/lib/commonjs/SegmentedControl.js +7 -0
  109. package/lib/commonjs/SegmentedControl.js.map +1 -1
  110. package/lib/commonjs/SegmentedControlNativeComponent.ts +11 -0
  111. package/lib/commonjs/SelectionMenu.js +27 -3
  112. package/lib/commonjs/SelectionMenu.js.map +1 -1
  113. package/lib/commonjs/SelectionMenuNativeComponent.ts +26 -4
  114. package/lib/commonjs/SplitButton.js +98 -0
  115. package/lib/commonjs/SplitButton.js.map +1 -0
  116. package/lib/commonjs/TabBar.js +203 -0
  117. package/lib/commonjs/TabBar.js.map +1 -0
  118. package/lib/commonjs/TabBarAccessoryNativeComponent.ts +19 -0
  119. package/lib/commonjs/TabBarNativeComponent.ts +145 -0
  120. package/lib/commonjs/TextField.js +171 -8
  121. package/lib/commonjs/TextField.js.map +1 -1
  122. package/lib/commonjs/TextFieldNativeComponent.ts +110 -4
  123. package/lib/commonjs/focusRegistry.js +2 -1
  124. package/lib/commonjs/focusRegistry.js.map +1 -1
  125. package/lib/commonjs/haptics.js +2 -0
  126. package/lib/commonjs/haptics.js.map +1 -0
  127. package/lib/commonjs/icons.js +15 -1
  128. package/lib/commonjs/icons.js.map +1 -1
  129. package/lib/commonjs/index.js +77 -0
  130. package/lib/commonjs/index.js.map +1 -1
  131. package/lib/commonjs/index.web.js +156 -92
  132. package/lib/commonjs/index.web.js.map +1 -1
  133. package/lib/commonjs/jest.js +910 -0
  134. package/lib/commonjs/jest.js.map +1 -0
  135. package/lib/commonjs/menuItems.js +68 -0
  136. package/lib/commonjs/menuItems.js.map +1 -0
  137. package/lib/commonjs/selectionIdentifiers.js +18 -0
  138. package/lib/commonjs/selectionIdentifiers.js.map +1 -0
  139. package/lib/commonjs/submitBehavior.js +19 -0
  140. package/lib/commonjs/submitBehavior.js.map +1 -0
  141. package/lib/commonjs/tabItems.js +49 -0
  142. package/lib/commonjs/tabItems.js.map +1 -0
  143. package/lib/commonjs/web/Button.js +170 -0
  144. package/lib/commonjs/web/Button.js.map +1 -0
  145. package/lib/commonjs/web/ButtonGroup.js +119 -0
  146. package/lib/commonjs/web/ButtonGroup.js.map +1 -0
  147. package/lib/commonjs/web/DatePicker.js +168 -0
  148. package/lib/commonjs/web/DatePicker.js.map +1 -0
  149. package/lib/commonjs/web/DateRangePicker.js +137 -0
  150. package/lib/commonjs/web/DateRangePicker.js.map +1 -0
  151. package/lib/commonjs/web/Dialog.js +54 -0
  152. package/lib/commonjs/web/Dialog.js.map +1 -0
  153. package/lib/commonjs/web/FloatingActionButton.js +98 -0
  154. package/lib/commonjs/web/FloatingActionButton.js.map +1 -0
  155. package/lib/commonjs/web/Icon.js +34 -0
  156. package/lib/commonjs/web/Icon.js.map +1 -0
  157. package/lib/commonjs/web/NativeTheme.js +28 -0
  158. package/lib/commonjs/web/NativeTheme.js.map +1 -0
  159. package/lib/commonjs/web/NavigationRail.js +139 -0
  160. package/lib/commonjs/web/NavigationRail.js.map +1 -0
  161. package/lib/commonjs/web/PlatformComponentsProvider.js +51 -0
  162. package/lib/commonjs/web/PlatformComponentsProvider.js.map +1 -0
  163. package/lib/commonjs/web/SegmentedControl.js +117 -0
  164. package/lib/commonjs/web/SegmentedControl.js.map +1 -0
  165. package/lib/commonjs/web/SelectionMenu.js +142 -0
  166. package/lib/commonjs/web/SelectionMenu.js.map +1 -0
  167. package/lib/commonjs/web/SplitButton.js +35 -0
  168. package/lib/commonjs/web/SplitButton.js.map +1 -0
  169. package/lib/commonjs/web/TabBar.js +131 -0
  170. package/lib/commonjs/web/TabBar.js.map +1 -0
  171. package/lib/commonjs/web/TextField.js +322 -0
  172. package/lib/commonjs/web/TextField.js.map +1 -0
  173. package/lib/commonjs/web/components.js +36 -0
  174. package/lib/commonjs/web/components.js.map +1 -0
  175. package/lib/commonjs/web/containers.js +121 -0
  176. package/lib/commonjs/web/containers.js.map +1 -0
  177. package/lib/commonjs/web/dateInput.js +116 -0
  178. package/lib/commonjs/web/dateInput.js.map +1 -0
  179. package/lib/commonjs/web/shared.js +192 -0
  180. package/lib/commonjs/web/shared.js.map +1 -0
  181. package/lib/commonjs/webComponents.js +6 -0
  182. package/lib/commonjs/webComponents.js.map +1 -0
  183. package/lib/module/Button.js +74 -2
  184. package/lib/module/Button.js.map +1 -1
  185. package/lib/module/ButtonGroup.js +13 -3
  186. package/lib/module/ButtonGroup.js.map +1 -1
  187. package/lib/module/ButtonGroupNativeComponent.ts +74 -4
  188. package/lib/module/ButtonNativeComponent.ts +119 -3
  189. package/lib/module/ContextMenu.js +9 -48
  190. package/lib/module/ContextMenu.js.map +1 -1
  191. package/lib/module/ContextMenuNativeComponent.ts +47 -49
  192. package/lib/module/DatePicker.js +98 -4
  193. package/lib/module/DatePicker.js.map +1 -1
  194. package/lib/module/DatePickerNativeComponent.ts +19 -2
  195. package/lib/module/FloatingActionButton.js +53 -0
  196. package/lib/module/FloatingActionButton.js.map +1 -0
  197. package/lib/module/FloatingActionButtonNativeComponent.ts +58 -0
  198. package/lib/module/FloatingToolbar.js +9 -1
  199. package/lib/module/FloatingToolbar.js.map +1 -1
  200. package/lib/module/FloatingToolbarNativeComponent.ts +16 -0
  201. package/lib/module/LiquidGlass.js +7 -1
  202. package/lib/module/LiquidGlass.js.map +1 -1
  203. package/lib/module/LiquidGlassContainer.js +26 -0
  204. package/lib/module/LiquidGlassContainer.js.map +1 -0
  205. package/lib/module/LiquidGlassContainerNativeComponent.ts +17 -0
  206. package/lib/module/LiquidGlassNativeComponent.ts +8 -0
  207. package/lib/module/NavigationRail.js +99 -0
  208. package/lib/module/NavigationRail.js.map +1 -0
  209. package/lib/module/NavigationRailNativeComponent.ts +107 -0
  210. package/lib/module/PlatformComponentsProvider.js +13 -0
  211. package/lib/module/PlatformComponentsProvider.js.map +1 -0
  212. package/lib/module/SegmentedControl.js +9 -1
  213. package/lib/module/SegmentedControl.js.map +1 -1
  214. package/lib/module/SegmentedControlNativeComponent.ts +11 -0
  215. package/lib/module/SelectionMenu.js +27 -3
  216. package/lib/module/SelectionMenu.js.map +1 -1
  217. package/lib/module/SelectionMenuNativeComponent.ts +26 -4
  218. package/lib/module/SplitButton.js +91 -0
  219. package/lib/module/SplitButton.js.map +1 -0
  220. package/lib/module/TabBar.js +196 -0
  221. package/lib/module/TabBar.js.map +1 -0
  222. package/lib/module/TabBarAccessoryNativeComponent.ts +19 -0
  223. package/lib/module/TabBarNativeComponent.ts +145 -0
  224. package/lib/module/TextField.js +172 -9
  225. package/lib/module/TextField.js.map +1 -1
  226. package/lib/module/TextFieldNativeComponent.ts +110 -4
  227. package/lib/module/focusRegistry.js +1 -0
  228. package/lib/module/focusRegistry.js.map +1 -1
  229. package/lib/module/haptics.js +2 -0
  230. package/lib/module/haptics.js.map +1 -0
  231. package/lib/module/icons.js +15 -1
  232. package/lib/module/icons.js.map +1 -1
  233. package/lib/module/index.js +7 -0
  234. package/lib/module/index.js.map +1 -1
  235. package/lib/module/index.web.js +12 -87
  236. package/lib/module/index.web.js.map +1 -1
  237. package/lib/module/jest.js +840 -0
  238. package/lib/module/jest.js.map +1 -0
  239. package/lib/module/menuItems.js +65 -0
  240. package/lib/module/menuItems.js.map +1 -0
  241. package/lib/module/selectionIdentifiers.js +14 -0
  242. package/lib/module/selectionIdentifiers.js.map +1 -0
  243. package/lib/module/submitBehavior.js +15 -0
  244. package/lib/module/submitBehavior.js.map +1 -0
  245. package/lib/module/tabItems.js +45 -0
  246. package/lib/module/tabItems.js.map +1 -0
  247. package/lib/module/web/Button.js +164 -0
  248. package/lib/module/web/Button.js.map +1 -0
  249. package/lib/module/web/ButtonGroup.js +113 -0
  250. package/lib/module/web/ButtonGroup.js.map +1 -0
  251. package/lib/module/web/DatePicker.js +162 -0
  252. package/lib/module/web/DatePicker.js.map +1 -0
  253. package/lib/module/web/DateRangePicker.js +131 -0
  254. package/lib/module/web/DateRangePicker.js.map +1 -0
  255. package/lib/module/web/Dialog.js +48 -0
  256. package/lib/module/web/Dialog.js.map +1 -0
  257. package/lib/module/web/FloatingActionButton.js +94 -0
  258. package/lib/module/web/FloatingActionButton.js.map +1 -0
  259. package/lib/module/web/Icon.js +29 -0
  260. package/lib/module/web/Icon.js.map +1 -0
  261. package/lib/module/web/NativeTheme.js +23 -0
  262. package/lib/module/web/NativeTheme.js.map +1 -0
  263. package/lib/module/web/NavigationRail.js +133 -0
  264. package/lib/module/web/NavigationRail.js.map +1 -0
  265. package/lib/module/web/PlatformComponentsProvider.js +44 -0
  266. package/lib/module/web/PlatformComponentsProvider.js.map +1 -0
  267. package/lib/module/web/SegmentedControl.js +112 -0
  268. package/lib/module/web/SegmentedControl.js.map +1 -0
  269. package/lib/module/web/SelectionMenu.js +137 -0
  270. package/lib/module/web/SelectionMenu.js.map +1 -0
  271. package/lib/module/web/SplitButton.js +30 -0
  272. package/lib/module/web/SplitButton.js.map +1 -0
  273. package/lib/module/web/TabBar.js +126 -0
  274. package/lib/module/web/TabBar.js.map +1 -0
  275. package/lib/module/web/TextField.js +316 -0
  276. package/lib/module/web/TextField.js.map +1 -0
  277. package/lib/module/web/components.js +33 -0
  278. package/lib/module/web/components.js.map +1 -0
  279. package/lib/module/web/containers.js +112 -0
  280. package/lib/module/web/containers.js.map +1 -0
  281. package/lib/module/web/dateInput.js +109 -0
  282. package/lib/module/web/dateInput.js.map +1 -0
  283. package/lib/module/web/shared.js +179 -0
  284. package/lib/module/web/shared.js.map +1 -0
  285. package/lib/module/webComponents.js +4 -0
  286. package/lib/module/webComponents.js.map +1 -0
  287. package/lib/typescript/commonjs/docs/sidebars.d.ts.map +1 -1
  288. package/lib/typescript/commonjs/src/Button.d.ts +111 -3
  289. package/lib/typescript/commonjs/src/Button.d.ts.map +1 -1
  290. package/lib/typescript/commonjs/src/ButtonGroup.d.ts +21 -6
  291. package/lib/typescript/commonjs/src/ButtonGroup.d.ts.map +1 -1
  292. package/lib/typescript/commonjs/src/ButtonGroupNativeComponent.d.ts +64 -3
  293. package/lib/typescript/commonjs/src/ButtonGroupNativeComponent.d.ts.map +1 -1
  294. package/lib/typescript/commonjs/src/ButtonNativeComponent.d.ts +94 -3
  295. package/lib/typescript/commonjs/src/ButtonNativeComponent.d.ts.map +1 -1
  296. package/lib/typescript/commonjs/src/ContextMenu.d.ts +20 -33
  297. package/lib/typescript/commonjs/src/ContextMenu.d.ts.map +1 -1
  298. package/lib/typescript/commonjs/src/ContextMenuNativeComponent.d.ts +45 -47
  299. package/lib/typescript/commonjs/src/ContextMenuNativeComponent.d.ts.map +1 -1
  300. package/lib/typescript/commonjs/src/DatePicker.d.ts +74 -1
  301. package/lib/typescript/commonjs/src/DatePicker.d.ts.map +1 -1
  302. package/lib/typescript/commonjs/src/DatePickerNativeComponent.d.ts +16 -1
  303. package/lib/typescript/commonjs/src/DatePickerNativeComponent.d.ts.map +1 -1
  304. package/lib/typescript/commonjs/src/FloatingActionButton.d.ts +67 -0
  305. package/lib/typescript/commonjs/src/FloatingActionButton.d.ts.map +1 -0
  306. package/lib/typescript/commonjs/src/FloatingActionButtonNativeComponent.d.ts +43 -0
  307. package/lib/typescript/commonjs/src/FloatingActionButtonNativeComponent.d.ts.map +1 -0
  308. package/lib/typescript/commonjs/src/FloatingToolbar.d.ts +30 -0
  309. package/lib/typescript/commonjs/src/FloatingToolbar.d.ts.map +1 -1
  310. package/lib/typescript/commonjs/src/FloatingToolbarNativeComponent.d.ts +12 -0
  311. package/lib/typescript/commonjs/src/FloatingToolbarNativeComponent.d.ts.map +1 -1
  312. package/lib/typescript/commonjs/src/LiquidGlass.d.ts +17 -0
  313. package/lib/typescript/commonjs/src/LiquidGlass.d.ts.map +1 -1
  314. package/lib/typescript/commonjs/src/LiquidGlassContainer.d.ts +27 -0
  315. package/lib/typescript/commonjs/src/LiquidGlassContainer.d.ts.map +1 -0
  316. package/lib/typescript/commonjs/src/LiquidGlassContainerNativeComponent.d.ts +13 -0
  317. package/lib/typescript/commonjs/src/LiquidGlassContainerNativeComponent.d.ts.map +1 -0
  318. package/lib/typescript/commonjs/src/LiquidGlassNativeComponent.d.ts +7 -0
  319. package/lib/typescript/commonjs/src/LiquidGlassNativeComponent.d.ts.map +1 -1
  320. package/lib/typescript/commonjs/src/NavigationRail.d.ts +86 -0
  321. package/lib/typescript/commonjs/src/NavigationRail.d.ts.map +1 -0
  322. package/lib/typescript/commonjs/src/NavigationRailNativeComponent.d.ts +81 -0
  323. package/lib/typescript/commonjs/src/NavigationRailNativeComponent.d.ts.map +1 -0
  324. package/lib/typescript/commonjs/src/PlatformComponentsProvider.d.ts +6 -0
  325. package/lib/typescript/commonjs/src/PlatformComponentsProvider.d.ts.map +1 -0
  326. package/lib/typescript/commonjs/src/SegmentedControl.d.ts +18 -1
  327. package/lib/typescript/commonjs/src/SegmentedControl.d.ts.map +1 -1
  328. package/lib/typescript/commonjs/src/SegmentedControlNativeComponent.d.ts +9 -0
  329. package/lib/typescript/commonjs/src/SegmentedControlNativeComponent.d.ts.map +1 -1
  330. package/lib/typescript/commonjs/src/SelectionMenu.d.ts +44 -2
  331. package/lib/typescript/commonjs/src/SelectionMenu.d.ts.map +1 -1
  332. package/lib/typescript/commonjs/src/SelectionMenuNativeComponent.d.ts +20 -4
  333. package/lib/typescript/commonjs/src/SelectionMenuNativeComponent.d.ts.map +1 -1
  334. package/lib/typescript/commonjs/src/SplitButton.d.ts +83 -0
  335. package/lib/typescript/commonjs/src/SplitButton.d.ts.map +1 -0
  336. package/lib/typescript/commonjs/src/TabBar.d.ts +144 -0
  337. package/lib/typescript/commonjs/src/TabBar.d.ts.map +1 -0
  338. package/lib/typescript/commonjs/src/TabBarAccessoryNativeComponent.d.ts +13 -0
  339. package/lib/typescript/commonjs/src/TabBarAccessoryNativeComponent.d.ts.map +1 -0
  340. package/lib/typescript/commonjs/src/TabBarNativeComponent.d.ts +110 -0
  341. package/lib/typescript/commonjs/src/TabBarNativeComponent.d.ts.map +1 -0
  342. package/lib/typescript/commonjs/src/TextField.d.ts +166 -8
  343. package/lib/typescript/commonjs/src/TextField.d.ts.map +1 -1
  344. package/lib/typescript/commonjs/src/TextFieldNativeComponent.d.ts +81 -3
  345. package/lib/typescript/commonjs/src/TextFieldNativeComponent.d.ts.map +1 -1
  346. package/lib/typescript/commonjs/src/focusRegistry.d.ts.map +1 -1
  347. package/lib/typescript/commonjs/src/haptics.d.ts +20 -0
  348. package/lib/typescript/commonjs/src/haptics.d.ts.map +1 -0
  349. package/lib/typescript/commonjs/src/icons.d.ts +7 -1
  350. package/lib/typescript/commonjs/src/icons.d.ts.map +1 -1
  351. package/lib/typescript/commonjs/src/index.d.ts +7 -0
  352. package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
  353. package/lib/typescript/commonjs/src/index.web.d.ts +25 -254
  354. package/lib/typescript/commonjs/src/index.web.d.ts.map +1 -1
  355. package/lib/typescript/commonjs/src/jest.d.ts +139 -0
  356. package/lib/typescript/commonjs/src/jest.d.ts.map +1 -0
  357. package/lib/typescript/commonjs/src/menuItems.d.ts +100 -0
  358. package/lib/typescript/commonjs/src/menuItems.d.ts.map +1 -0
  359. package/lib/typescript/commonjs/src/selectionIdentifiers.d.ts +3 -0
  360. package/lib/typescript/commonjs/src/selectionIdentifiers.d.ts.map +1 -0
  361. package/lib/typescript/commonjs/src/submitBehavior.d.ts +9 -0
  362. package/lib/typescript/commonjs/src/submitBehavior.d.ts.map +1 -0
  363. package/lib/typescript/commonjs/src/tabItems.d.ts +55 -0
  364. package/lib/typescript/commonjs/src/tabItems.d.ts.map +1 -0
  365. package/lib/typescript/commonjs/src/web/Button.d.ts +9 -0
  366. package/lib/typescript/commonjs/src/web/Button.d.ts.map +1 -0
  367. package/lib/typescript/commonjs/src/web/ButtonGroup.d.ts +11 -0
  368. package/lib/typescript/commonjs/src/web/ButtonGroup.d.ts.map +1 -0
  369. package/lib/typescript/commonjs/src/web/DatePicker.d.ts +14 -0
  370. package/lib/typescript/commonjs/src/web/DatePicker.d.ts.map +1 -0
  371. package/lib/typescript/commonjs/src/web/DateRangePicker.d.ts +11 -0
  372. package/lib/typescript/commonjs/src/web/DateRangePicker.d.ts.map +1 -0
  373. package/lib/typescript/commonjs/src/web/Dialog.d.ts +12 -0
  374. package/lib/typescript/commonjs/src/web/Dialog.d.ts.map +1 -0
  375. package/lib/typescript/commonjs/src/web/FloatingActionButton.d.ts +8 -0
  376. package/lib/typescript/commonjs/src/web/FloatingActionButton.d.ts.map +1 -0
  377. package/lib/typescript/commonjs/src/web/Icon.d.ts +12 -0
  378. package/lib/typescript/commonjs/src/web/Icon.d.ts.map +1 -0
  379. package/lib/typescript/commonjs/src/web/NativeTheme.d.ts +10 -0
  380. package/lib/typescript/commonjs/src/web/NativeTheme.d.ts.map +1 -0
  381. package/lib/typescript/commonjs/src/web/NavigationRail.d.ts +8 -0
  382. package/lib/typescript/commonjs/src/web/NavigationRail.d.ts.map +1 -0
  383. package/lib/typescript/commonjs/src/web/PlatformComponentsProvider.d.ts +10 -0
  384. package/lib/typescript/commonjs/src/web/PlatformComponentsProvider.d.ts.map +1 -0
  385. package/lib/typescript/commonjs/src/web/SegmentedControl.d.ts +8 -0
  386. package/lib/typescript/commonjs/src/web/SegmentedControl.d.ts.map +1 -0
  387. package/lib/typescript/commonjs/src/web/SelectionMenu.d.ts +10 -0
  388. package/lib/typescript/commonjs/src/web/SelectionMenu.d.ts.map +1 -0
  389. package/lib/typescript/commonjs/src/web/SplitButton.d.ts +9 -0
  390. package/lib/typescript/commonjs/src/web/SplitButton.d.ts.map +1 -0
  391. package/lib/typescript/commonjs/src/web/TabBar.d.ts +9 -0
  392. package/lib/typescript/commonjs/src/web/TabBar.d.ts.map +1 -0
  393. package/lib/typescript/commonjs/src/web/TextField.d.ts +9 -0
  394. package/lib/typescript/commonjs/src/web/TextField.d.ts.map +1 -0
  395. package/lib/typescript/commonjs/src/web/components.d.ts +17 -0
  396. package/lib/typescript/commonjs/src/web/components.d.ts.map +1 -0
  397. package/lib/typescript/commonjs/src/web/containers.d.ts +24 -0
  398. package/lib/typescript/commonjs/src/web/containers.d.ts.map +1 -0
  399. package/lib/typescript/commonjs/src/web/dateInput.d.ts +20 -0
  400. package/lib/typescript/commonjs/src/web/dateInput.d.ts.map +1 -0
  401. package/lib/typescript/commonjs/src/web/shared.d.ts +43 -0
  402. package/lib/typescript/commonjs/src/web/shared.d.ts.map +1 -0
  403. package/lib/typescript/commonjs/src/webComponents.d.ts +43 -0
  404. package/lib/typescript/commonjs/src/webComponents.d.ts.map +1 -0
  405. package/lib/typescript/module/docs/sidebars.d.ts.map +1 -1
  406. package/lib/typescript/module/src/Button.d.ts +111 -3
  407. package/lib/typescript/module/src/Button.d.ts.map +1 -1
  408. package/lib/typescript/module/src/ButtonGroup.d.ts +21 -6
  409. package/lib/typescript/module/src/ButtonGroup.d.ts.map +1 -1
  410. package/lib/typescript/module/src/ButtonGroupNativeComponent.d.ts +64 -3
  411. package/lib/typescript/module/src/ButtonGroupNativeComponent.d.ts.map +1 -1
  412. package/lib/typescript/module/src/ButtonNativeComponent.d.ts +94 -3
  413. package/lib/typescript/module/src/ButtonNativeComponent.d.ts.map +1 -1
  414. package/lib/typescript/module/src/ContextMenu.d.ts +20 -33
  415. package/lib/typescript/module/src/ContextMenu.d.ts.map +1 -1
  416. package/lib/typescript/module/src/ContextMenuNativeComponent.d.ts +45 -47
  417. package/lib/typescript/module/src/ContextMenuNativeComponent.d.ts.map +1 -1
  418. package/lib/typescript/module/src/DatePicker.d.ts +74 -1
  419. package/lib/typescript/module/src/DatePicker.d.ts.map +1 -1
  420. package/lib/typescript/module/src/DatePickerNativeComponent.d.ts +16 -1
  421. package/lib/typescript/module/src/DatePickerNativeComponent.d.ts.map +1 -1
  422. package/lib/typescript/module/src/FloatingActionButton.d.ts +67 -0
  423. package/lib/typescript/module/src/FloatingActionButton.d.ts.map +1 -0
  424. package/lib/typescript/module/src/FloatingActionButtonNativeComponent.d.ts +43 -0
  425. package/lib/typescript/module/src/FloatingActionButtonNativeComponent.d.ts.map +1 -0
  426. package/lib/typescript/module/src/FloatingToolbar.d.ts +30 -0
  427. package/lib/typescript/module/src/FloatingToolbar.d.ts.map +1 -1
  428. package/lib/typescript/module/src/FloatingToolbarNativeComponent.d.ts +12 -0
  429. package/lib/typescript/module/src/FloatingToolbarNativeComponent.d.ts.map +1 -1
  430. package/lib/typescript/module/src/LiquidGlass.d.ts +17 -0
  431. package/lib/typescript/module/src/LiquidGlass.d.ts.map +1 -1
  432. package/lib/typescript/module/src/LiquidGlassContainer.d.ts +27 -0
  433. package/lib/typescript/module/src/LiquidGlassContainer.d.ts.map +1 -0
  434. package/lib/typescript/module/src/LiquidGlassContainerNativeComponent.d.ts +13 -0
  435. package/lib/typescript/module/src/LiquidGlassContainerNativeComponent.d.ts.map +1 -0
  436. package/lib/typescript/module/src/LiquidGlassNativeComponent.d.ts +7 -0
  437. package/lib/typescript/module/src/LiquidGlassNativeComponent.d.ts.map +1 -1
  438. package/lib/typescript/module/src/NavigationRail.d.ts +86 -0
  439. package/lib/typescript/module/src/NavigationRail.d.ts.map +1 -0
  440. package/lib/typescript/module/src/NavigationRailNativeComponent.d.ts +81 -0
  441. package/lib/typescript/module/src/NavigationRailNativeComponent.d.ts.map +1 -0
  442. package/lib/typescript/module/src/PlatformComponentsProvider.d.ts +6 -0
  443. package/lib/typescript/module/src/PlatformComponentsProvider.d.ts.map +1 -0
  444. package/lib/typescript/module/src/SegmentedControl.d.ts +18 -1
  445. package/lib/typescript/module/src/SegmentedControl.d.ts.map +1 -1
  446. package/lib/typescript/module/src/SegmentedControlNativeComponent.d.ts +9 -0
  447. package/lib/typescript/module/src/SegmentedControlNativeComponent.d.ts.map +1 -1
  448. package/lib/typescript/module/src/SelectionMenu.d.ts +44 -2
  449. package/lib/typescript/module/src/SelectionMenu.d.ts.map +1 -1
  450. package/lib/typescript/module/src/SelectionMenuNativeComponent.d.ts +20 -4
  451. package/lib/typescript/module/src/SelectionMenuNativeComponent.d.ts.map +1 -1
  452. package/lib/typescript/module/src/SplitButton.d.ts +83 -0
  453. package/lib/typescript/module/src/SplitButton.d.ts.map +1 -0
  454. package/lib/typescript/module/src/TabBar.d.ts +144 -0
  455. package/lib/typescript/module/src/TabBar.d.ts.map +1 -0
  456. package/lib/typescript/module/src/TabBarAccessoryNativeComponent.d.ts +13 -0
  457. package/lib/typescript/module/src/TabBarAccessoryNativeComponent.d.ts.map +1 -0
  458. package/lib/typescript/module/src/TabBarNativeComponent.d.ts +110 -0
  459. package/lib/typescript/module/src/TabBarNativeComponent.d.ts.map +1 -0
  460. package/lib/typescript/module/src/TextField.d.ts +166 -8
  461. package/lib/typescript/module/src/TextField.d.ts.map +1 -1
  462. package/lib/typescript/module/src/TextFieldNativeComponent.d.ts +81 -3
  463. package/lib/typescript/module/src/TextFieldNativeComponent.d.ts.map +1 -1
  464. package/lib/typescript/module/src/focusRegistry.d.ts.map +1 -1
  465. package/lib/typescript/module/src/haptics.d.ts +20 -0
  466. package/lib/typescript/module/src/haptics.d.ts.map +1 -0
  467. package/lib/typescript/module/src/icons.d.ts +7 -1
  468. package/lib/typescript/module/src/icons.d.ts.map +1 -1
  469. package/lib/typescript/module/src/index.d.ts +7 -0
  470. package/lib/typescript/module/src/index.d.ts.map +1 -1
  471. package/lib/typescript/module/src/index.web.d.ts +25 -254
  472. package/lib/typescript/module/src/index.web.d.ts.map +1 -1
  473. package/lib/typescript/module/src/jest.d.ts +139 -0
  474. package/lib/typescript/module/src/jest.d.ts.map +1 -0
  475. package/lib/typescript/module/src/menuItems.d.ts +100 -0
  476. package/lib/typescript/module/src/menuItems.d.ts.map +1 -0
  477. package/lib/typescript/module/src/selectionIdentifiers.d.ts +3 -0
  478. package/lib/typescript/module/src/selectionIdentifiers.d.ts.map +1 -0
  479. package/lib/typescript/module/src/submitBehavior.d.ts +9 -0
  480. package/lib/typescript/module/src/submitBehavior.d.ts.map +1 -0
  481. package/lib/typescript/module/src/tabItems.d.ts +55 -0
  482. package/lib/typescript/module/src/tabItems.d.ts.map +1 -0
  483. package/lib/typescript/module/src/web/Button.d.ts +9 -0
  484. package/lib/typescript/module/src/web/Button.d.ts.map +1 -0
  485. package/lib/typescript/module/src/web/ButtonGroup.d.ts +11 -0
  486. package/lib/typescript/module/src/web/ButtonGroup.d.ts.map +1 -0
  487. package/lib/typescript/module/src/web/DatePicker.d.ts +14 -0
  488. package/lib/typescript/module/src/web/DatePicker.d.ts.map +1 -0
  489. package/lib/typescript/module/src/web/DateRangePicker.d.ts +11 -0
  490. package/lib/typescript/module/src/web/DateRangePicker.d.ts.map +1 -0
  491. package/lib/typescript/module/src/web/Dialog.d.ts +12 -0
  492. package/lib/typescript/module/src/web/Dialog.d.ts.map +1 -0
  493. package/lib/typescript/module/src/web/FloatingActionButton.d.ts +8 -0
  494. package/lib/typescript/module/src/web/FloatingActionButton.d.ts.map +1 -0
  495. package/lib/typescript/module/src/web/Icon.d.ts +12 -0
  496. package/lib/typescript/module/src/web/Icon.d.ts.map +1 -0
  497. package/lib/typescript/module/src/web/NativeTheme.d.ts +10 -0
  498. package/lib/typescript/module/src/web/NativeTheme.d.ts.map +1 -0
  499. package/lib/typescript/module/src/web/NavigationRail.d.ts +8 -0
  500. package/lib/typescript/module/src/web/NavigationRail.d.ts.map +1 -0
  501. package/lib/typescript/module/src/web/PlatformComponentsProvider.d.ts +10 -0
  502. package/lib/typescript/module/src/web/PlatformComponentsProvider.d.ts.map +1 -0
  503. package/lib/typescript/module/src/web/SegmentedControl.d.ts +8 -0
  504. package/lib/typescript/module/src/web/SegmentedControl.d.ts.map +1 -0
  505. package/lib/typescript/module/src/web/SelectionMenu.d.ts +10 -0
  506. package/lib/typescript/module/src/web/SelectionMenu.d.ts.map +1 -0
  507. package/lib/typescript/module/src/web/SplitButton.d.ts +9 -0
  508. package/lib/typescript/module/src/web/SplitButton.d.ts.map +1 -0
  509. package/lib/typescript/module/src/web/TabBar.d.ts +9 -0
  510. package/lib/typescript/module/src/web/TabBar.d.ts.map +1 -0
  511. package/lib/typescript/module/src/web/TextField.d.ts +9 -0
  512. package/lib/typescript/module/src/web/TextField.d.ts.map +1 -0
  513. package/lib/typescript/module/src/web/components.d.ts +17 -0
  514. package/lib/typescript/module/src/web/components.d.ts.map +1 -0
  515. package/lib/typescript/module/src/web/containers.d.ts +24 -0
  516. package/lib/typescript/module/src/web/containers.d.ts.map +1 -0
  517. package/lib/typescript/module/src/web/dateInput.d.ts +20 -0
  518. package/lib/typescript/module/src/web/dateInput.d.ts.map +1 -0
  519. package/lib/typescript/module/src/web/shared.d.ts +43 -0
  520. package/lib/typescript/module/src/web/shared.d.ts.map +1 -0
  521. package/lib/typescript/module/src/webComponents.d.ts +43 -0
  522. package/lib/typescript/module/src/webComponents.d.ts.map +1 -0
  523. package/package.json +32 -2
  524. package/plugin/build/index.d.ts +3 -2
  525. package/plugin/build/index.d.ts.map +1 -1
  526. package/react-native.config.js +3 -0
  527. package/shared/PCFloatingActionButtonComponentDescriptors-custom.h +22 -0
  528. package/shared/PCFloatingActionButtonShadowNode-custom.cpp +48 -0
  529. package/shared/PCFloatingActionButtonShadowNode-custom.h +54 -0
  530. package/shared/PCFloatingActionButtonState-custom.h +61 -0
  531. package/shared/PCNavigationRailComponentDescriptors-custom.h +47 -0
  532. package/shared/PCNavigationRailShadowNode-custom.h +42 -0
  533. package/shared/PCNavigationRailState-custom.h +62 -0
  534. package/shared/PCTabBarComponentDescriptors-custom.h +22 -0
  535. package/shared/PCTabBarShadowNode-custom.cpp +54 -0
  536. package/shared/PCTabBarShadowNode-custom.h +54 -0
  537. package/shared/PCTabBarState-custom.h +62 -0
  538. package/shared/react/renderer/components/PlatformComponentsViewSpec/ComponentDescriptors.h +3 -0
  539. package/src/Button.tsx +222 -7
  540. package/src/ButtonGroup.tsx +29 -11
  541. package/src/ButtonGroupNativeComponent.ts +74 -4
  542. package/src/ButtonNativeComponent.ts +119 -3
  543. package/src/ContextMenu.tsx +34 -81
  544. package/src/ContextMenuNativeComponent.ts +47 -49
  545. package/src/DatePicker.tsx +182 -4
  546. package/src/DatePickerNativeComponent.ts +19 -2
  547. package/src/FloatingActionButton.tsx +121 -0
  548. package/src/FloatingActionButtonNativeComponent.ts +58 -0
  549. package/src/FloatingToolbar.tsx +54 -3
  550. package/src/FloatingToolbarNativeComponent.ts +16 -0
  551. package/src/LiquidGlass.tsx +24 -1
  552. package/src/LiquidGlassContainer.tsx +42 -0
  553. package/src/LiquidGlassContainerNativeComponent.ts +17 -0
  554. package/src/LiquidGlassNativeComponent.ts +8 -0
  555. package/src/NavigationRail.tsx +203 -0
  556. package/src/NavigationRailNativeComponent.ts +107 -0
  557. package/src/PlatformComponentsProvider.tsx +15 -0
  558. package/src/SegmentedControl.tsx +31 -1
  559. package/src/SegmentedControlNativeComponent.ts +11 -0
  560. package/src/SelectionMenu.tsx +81 -6
  561. package/src/SelectionMenuNativeComponent.ts +26 -4
  562. package/src/SplitButton.tsx +198 -0
  563. package/src/TabBar.tsx +373 -0
  564. package/src/TabBarAccessoryNativeComponent.ts +19 -0
  565. package/src/TabBarNativeComponent.ts +145 -0
  566. package/src/TextField.tsx +428 -14
  567. package/src/TextFieldNativeComponent.ts +110 -4
  568. package/src/focusRegistry.ts +1 -0
  569. package/src/haptics.ts +31 -0
  570. package/src/icons.ts +28 -1
  571. package/src/index.tsx +7 -0
  572. package/src/index.web.tsx +51 -391
  573. package/src/jest.tsx +958 -0
  574. package/src/menuItems.ts +152 -0
  575. package/src/selectionIdentifiers.ts +17 -0
  576. package/src/submitBehavior.ts +16 -0
  577. package/src/tabItems.ts +113 -0
  578. package/src/web/Button.tsx +201 -0
  579. package/src/web/ButtonGroup.tsx +154 -0
  580. package/src/web/DatePicker.tsx +204 -0
  581. package/src/web/DateRangePicker.tsx +135 -0
  582. package/src/web/Dialog.tsx +54 -0
  583. package/src/web/FloatingActionButton.tsx +76 -0
  584. package/src/web/Icon.tsx +33 -0
  585. package/src/web/NativeTheme.ts +23 -0
  586. package/src/web/NavigationRail.tsx +148 -0
  587. package/src/web/PlatformComponentsProvider.tsx +48 -0
  588. package/src/web/SegmentedControl.tsx +127 -0
  589. package/src/web/SelectionMenu.tsx +149 -0
  590. package/src/web/SplitButton.tsx +32 -0
  591. package/src/web/TabBar.tsx +150 -0
  592. package/src/web/TextField.tsx +361 -0
  593. package/src/web/components.tsx +71 -0
  594. package/src/web/containers.tsx +130 -0
  595. package/src/web/dateInput.ts +137 -0
  596. package/src/web/shared.ts +176 -0
  597. package/src/webComponents.ts +45 -0
  598. package/android/src/main/java/com/platformcomponents/DateConstraints.kt +0 -83
@@ -11,7 +11,7 @@ Pod::Spec.new do |s|
11
11
  s.authors = package["author"]
12
12
 
13
13
  s.platforms = { :ios => min_ios_version_supported }
14
- s.source = { :git => "https://github.com/JarX-Concepts/react-native-platform-components.git", :tag => "#{s.version}" }
14
+ s.source = { :git => "https://github.com/JarX-Concepts/react-native-platform-components.git", :tag => "v#{s.version}" }
15
15
 
16
16
  s.source_files = ["ios/**/*.{h,m,mm,swift,cpp}", "shared/**/*.{h,m,mm,swift,cpp}"]
17
17
  s.private_header_files = ["ios/**/*.h", "shared/**/*.h"]
package/README.md CHANGED
@@ -5,20 +5,20 @@
5
5
  [![CI](https://github.com/JarX-Concepts/react-native-platform-components/actions/workflows/ci.yml/badge.svg)](https://github.com/JarX-Concepts/react-native-platform-components/actions/workflows/ci.yml)
6
6
  [![license](https://img.shields.io/npm/l/react-native-platform-components.svg)](./LICENSE)
7
7
 
8
- Native **TextField**, **DatePicker**, **ContextMenu**, **SelectionMenu**, **SegmentedControl**, **Button**, **ButtonGroup**, **FloatingToolbar** and **LiquidGlass** for React Native. Every component is the real platform widget on both iOS and Android (UIKit and SwiftUI on iOS, Material 3 Expressive on Android), behind one typed, declarative API. No JavaScript re-implementations.
8
+ Native **TextField**, **DatePicker**, **ContextMenu**, **SelectionMenu**, **SegmentedControl**, **TabBar**, **NavigationRail**, **Button**, **ButtonGroup**, **FloatingActionButton**, **FloatingToolbar** and **LiquidGlass** for React Native. Every component is the real platform widget on both iOS and Android (UIKit on iOS, Material 3 Expressive on Android), behind one typed, declarative API. No JavaScript re-implementations.
9
9
 
10
10
  <p align="center">
11
11
  <a href="https://jarx-concepts.github.io/react-native-platform-components">
12
12
  <picture>
13
13
  <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/hero-dark.webp" />
14
- <img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/hero-light.webp" alt="DatePicker, TextField, SegmentedControl, Button, ContextMenu, LiquidGlass, FloatingToolbar and SelectionMenu on iOS and Android, and the dark mode from useNativeTheme" />
14
+ <img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/hero-light.webp" alt="DatePicker, TextField, SegmentedControl, Button, TabBar, NavigationRail, FloatingActionButton, ContextMenu, LiquidGlass, FloatingToolbar and SelectionMenu on iOS and Android, and the dark mode from useNativeTheme" />
15
15
  </picture>
16
16
  </a>
17
17
  </p>
18
18
  <p align="center"><sub>Every tile is the platform's own widget, captured from the example app. The <a href="https://jarx-concepts.github.io/react-native-platform-components">docs site</a> has full recordings of each component on both platforms; <a href="https://jarx-concepts.github.io/react-native-platform-components/components/liquidglass">LiquidGlass</a> is iOS 26 only.</sub></p>
19
19
 
20
20
  <p align="center">
21
- <a href="https://jarx-concepts.github.io/react-native-platform-components"><img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/showreel.gif" width="640" alt="Showreel: the native theme changing brand color and switching to dark mode, then DatePicker, TextField, SegmentedControl, Button, ContextMenu, SelectionMenu, FloatingToolbar and LiquidGlass in use, iOS on the left and Android on the right" /></a>
21
+ <a href="https://jarx-concepts.github.io/react-native-platform-components"><img src="https://raw.githubusercontent.com/JarX-Concepts/react-native-platform-components/main/assets/showreel.gif" width="640" alt="Showreel: the native theme changing brand color and switching to dark mode, then DatePicker, TextField, SegmentedControl, TabBar, NavigationRail, Button, FloatingActionButton, ContextMenu, SelectionMenu, FloatingToolbar and LiquidGlass in use, iOS on the left and Android on the right" /></a>
22
22
  </p>
23
23
  <p align="center"><sub>iOS on the left, Android on the right. Recorded by the Detox suite in <code>example/</code>.</sub></p>
24
24
 
@@ -41,32 +41,24 @@ import { SegmentedControl } from 'react-native-platform-components';
41
41
 
42
42
  That renders `UISegmentedControl` on iOS and Material 3 segmented buttons (`MaterialButtonToggleGroup`) on Android. The library needs the New Architecture: React Native 0.81+, or Expo SDK 54+ with a dev client (not Expo Go). See [Installation](#installation) and the [documentation site](https://jarx-concepts.github.io/react-native-platform-components).
43
43
 
44
- ## Why this library
45
-
46
- | You need | This library | Common alternative |
47
- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
48
- | Text field | Material 3 `TextInputLayout` on Android (floating label, outlined or filled, supporting text, error state, icons, counter); `UITextField` on iOS with Writing Tools, inline predictions and smart punctuation. Same `value` / `onChangeText` contract as `TextInput`. | `TextInput`: a bare `EditText` on Android, no Material field; the iOS 17 and 18 text traits are not exposed. `react-native-paper`: Material 3 drawn in JavaScript. |
49
- | Date and time pickers | `UIDatePicker` on iOS; `MaterialDatePicker` / `MaterialTimePicker` or the AppCompat dialogs on Android. Declarative `visible` prop, modal or embedded. | `@react-native-community/datetimepicker`: platform dialogs on Android; Material 3 pickers are an [open request](https://github.com/react-native-datetimepicker/datetimepicker/issues/790). |
50
- | Segmented control | `UISegmentedControl` on iOS; Material 3 segmented buttons on Android. Icons and badges on both. | `@react-native-segmented-control/segmented-control`: native on iOS, drawn in JavaScript on Android. |
51
- | Context menu | `UIContextMenuInteraction` on iOS; `PopupMenu` on Android. Long-press gesture or modal trigger, icons on both. | `zeego`: native on both platforms, through two additional native dependencies (`react-native-ios-context-menu`, `@react-native-menu/menu`). |
52
- | Selection menu | System menus on iOS; Material exposed dropdown or `Spinner` on Android. Headless or inline. | `@react-native-picker/picker`: wheel picker on iOS, dialog or dropdown `Spinner` on Android; no menu-style presentation. |
53
- | Buttons and toolbars | Material 3 Expressive `MaterialButton`, button groups and `FloatingToolbarLayout` on Android (five sizes, shape morphing); `UIButton` configurations and a Liquid Glass toolbar on iOS. | `react-native-paper`: Material 3 (not Expressive) drawn in JavaScript on both platforms. |
54
- | Liquid glass | `UIGlassEffect` on iOS 26+, a fallback `View` elsewhere, `isLiquidGlassSupported` flag. | `@callstack/liquid-glass`, `expo-glass-effect`: same idea on iOS; here it ships with the components above. |
55
- | All of the above | One package, one API shape (platform-only props under `ios={{ }}` and `android={{ }}`), Fabric + Codegen typed bindings, Expo config plugin, TypeScript. | Four or five packages with different conventions, install steps and upgrade cadences. |
56
-
57
44
  ## Components
58
45
 
59
- | Component | iOS | Android | Docs |
60
- | -------------------- | -------------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
61
- | **TextField** | `UITextField` / `UITextView` | `TextInputLayout` (Material 3: outlined or filled, label, supporting text, icons, counter) | [TextField](https://jarx-concepts.github.io/react-native-platform-components/components/textfield) |
62
- | **DatePicker** | `UIDatePicker` | `MaterialDatePicker` / `MaterialTimePicker` or AppCompat dialogs | [DatePicker](https://jarx-concepts.github.io/react-native-platform-components/components/datepicker) |
63
- | **ContextMenu** | `UIContextMenuInteraction` | `PopupMenu` | [ContextMenu](https://jarx-concepts.github.io/react-native-platform-components/components/contextmenu) |
64
- | **SelectionMenu** | System menus | Material exposed dropdown or `Spinner` | [SelectionMenu](https://jarx-concepts.github.io/react-native-platform-components/components/selectionmenu) |
65
- | **SegmentedControl** | `UISegmentedControl` | `MaterialButtonToggleGroup` (Material 3 Expressive connected buttons, or classic) | [SegmentedControl](https://jarx-concepts.github.io/react-native-platform-components/components/segmentedcontrol) |
66
- | **Button** | `UIButton` (configurations) | `MaterialButton` (Material 3 Expressive: five sizes, round or square, shape morph) | [Button](https://jarx-concepts.github.io/react-native-platform-components/components/button) |
67
- | **ButtonGroup** | Row of `UIButton`s | `MaterialButtonGroup` / `MaterialButtonToggleGroup` (Material 3 Expressive) | [ButtonGroup](https://jarx-concepts.github.io/react-native-platform-components/components/buttongroup) |
68
- | **FloatingToolbar** | `UIGlassEffect` capsule (iOS 26+), blur below | `FloatingToolbarLayout` (Material 3 Expressive) | [FloatingToolbar](https://jarx-concepts.github.io/react-native-platform-components/components/floatingtoolbar) |
69
- | **LiquidGlass** | `UIGlassEffect` (iOS 26+) | Fallback `View` | [LiquidGlass](https://jarx-concepts.github.io/react-native-platform-components/components/liquidglass) |
46
+ | Component | iOS | Android | Instead of |
47
+ | ---------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
48
+ | [**TextField**](https://jarx-concepts.github.io/react-native-platform-components/components/textfield) | `UITextField` / `UITextView`, with Writing Tools and the iOS 17–18 text traits | Material 3 `TextInputLayout`: outlined or filled, floating label, supporting text, counter | `TextInput` (a bare `EditText` on Android); `react-native-paper` (drawn in JavaScript) |
49
+ | [**DatePicker**](https://jarx-concepts.github.io/react-native-platform-components/components/datepicker) | `UIDatePicker`, modal or embedded | `MaterialDatePicker` / `MaterialTimePicker`, or the AppCompat dialogs | `@react-native-community/datetimepicker` (no Material 3 pickers) |
50
+ | [**SelectionMenu**](https://jarx-concepts.github.io/react-native-platform-components/components/selectionmenu) | System menus | Material exposed dropdown or `Spinner` | `@react-native-picker/picker` (wheel or dialog, no menu) |
51
+ | [**ContextMenu**](https://jarx-concepts.github.io/react-native-platform-components/components/contextmenu) | `UIContextMenuInteraction` | `PopupMenu` | `zeego` (through two more native packages) |
52
+ | [**SegmentedControl**](https://jarx-concepts.github.io/react-native-platform-components/components/segmentedcontrol) | `UISegmentedControl` | Material 3 Expressive connected buttons, or classic segmented buttons | `@react-native-segmented-control/segmented-control` (JavaScript on Android) |
53
+ | [**TabBar**](https://jarx-concepts.github.io/react-native-platform-components/components/tabbar) | `UITabBar`, the floating Liquid Glass bar on iOS 26 | Material 3 navigation bar | React Navigation's bottom tabs (JavaScript); `react-native-bottom-tabs` (tied to its navigator) |
54
+ | [**NavigationRail**](https://jarx-concepts.github.io/react-native-platform-components/components/navigationrail) | A column of tab-style `UIButton`s (iOS has no rail; use TabBar on iPhone) | Material 3 Expressive `NavigationRailView`: header, badges, menu gravity, expanded rail | React Navigation's drawer or a custom view (JavaScript) |
55
+ | [**Button**](https://jarx-concepts.github.io/react-native-platform-components/components/button) | `UIButton` configurations, Liquid Glass variants on iOS 26 | Material 3 Expressive `MaterialButton`: five sizes, shape morph | `react-native-paper` (Material 3, not Expressive, in JavaScript) |
56
+ | [**ButtonGroup**](https://jarx-concepts.github.io/react-native-platform-components/components/buttongroup) | A row of `UIButton`s with a "…" overflow menu; SplitButton: a button and a chevron `UIMenu` button | Material 3 Expressive button groups, single or multiple selection, overflow menu; `MaterialSplitButton` | `react-native-paper` segmented buttons (JavaScript) |
57
+ | [**FloatingActionButton**](https://jarx-concepts.github.io/react-native-platform-components/components/floatingactionbutton) | A round prominent `UIButton`, Liquid Glass on iOS 26 (iOS has no FAB) | Material `FloatingActionButton` / `ExtendedFloatingActionButton`: four sizes, shrink on scroll | `react-native-paper` FAB (drawn in JavaScript) |
58
+ | [**FloatingToolbar**](https://jarx-concepts.github.io/react-native-platform-components/components/floatingtoolbar) | Liquid Glass capsule on iOS 26, blur before | Material 3 Expressive `FloatingToolbarLayout` | A custom view |
59
+ | [**LiquidGlass**](https://jarx-concepts.github.io/react-native-platform-components/components/liquidglass) | `UIGlassEffect` on iOS 26+; `LiquidGlassContainer` merges and morphs it (`UIGlassContainerEffect`) | A fallback `View` | `@callstack/liquid-glass`, `expo-glass-effect` |
60
+
61
+ One package and one API shape: platform-only props go under `ios={{ }}` and `android={{ }}`, with Fabric + Codegen typed bindings, an Expo config plugin and TypeScript, instead of four or five packages with their own conventions, install steps and upgrade cadences.
70
62
 
71
63
  **Have a component request?** If there's a native UI component you'd like to see added, [open an issue](https://github.com/JarX-Concepts/react-native-platform-components/issues/new) describing the component and its native APIs on iOS and Android.
72
64
 
@@ -74,6 +66,16 @@ That renders `UISegmentedControl` on iOS and Material 3 segmented buttons (`Mate
74
66
 
75
67
  ---
76
68
 
69
+ ## Web
70
+
71
+ Connect your existing web UI through `PlatformComponentsProvider`: register typed
72
+ web adapters once, then keep the same component imports, props and callbacks in
73
+ shared screens. Override only the controls you need; the others keep the existing
74
+ web fallbacks. iOS and Android continue using their native widgets.
75
+
76
+ See the [web integration guide](https://jarx-concepts.github.io/react-native-platform-components/guides/web)
77
+ for setup, adapter examples, field refs and current fallback limitations.
78
+
77
79
  ## Installation
78
80
 
79
81
  ```sh
@@ -122,10 +124,10 @@ The library is built for the New Architecture (Fabric + Codegen) and does not su
122
124
  | iOS | 15.1 (LiquidGlass needs iOS 26) |
123
125
  | Android | API 24 (Android 7.0); Material Components 1.14 is bundled |
124
126
 
125
- iOS sets that minimum. LiquidGlass uses iOS 26 APIs, so the library has to be
126
- built with Xcode 26, and React Native's bundled `fmt` only compiles under Xcode
127
- 26 from 0.81 on. The Android code itself builds against React Native 0.76, and
128
- CI keeps it that way.
127
+ React Native 0.81 / Expo SDK 54 is the supported minimum. CI builds that
128
+ combination with both Xcode 26 and Xcode 16.4; Liquid Glass is compiled out
129
+ when the iOS 26 SDK is unavailable. Android is also built against React
130
+ Native 0.76 in CI to check native compatibility below the supported minimum.
129
131
 
130
132
  Full details: [Installation](https://jarx-concepts.github.io/react-native-platform-components/installation).
131
133
 
@@ -1,24 +1,31 @@
1
1
  package com.platformcomponents
2
2
 
3
3
  import android.content.Context
4
+ import android.content.res.ColorStateList
4
5
  import android.text.TextUtils
5
6
  import android.view.ContextThemeWrapper
7
+ import android.view.Gravity
6
8
  import android.view.View
7
9
  import android.view.ViewGroup.MarginLayoutParams
8
10
  import android.widget.FrameLayout
11
+ import androidx.appcompat.widget.PopupMenu
12
+ import androidx.core.content.ContextCompat
9
13
  import com.facebook.react.bridge.WritableNativeMap
10
14
  import com.facebook.react.uimanager.PixelUtil
11
15
  import com.facebook.react.uimanager.ReactCompoundViewGroup
12
16
  import com.facebook.react.uimanager.StateWrapper
13
17
  import com.facebook.react.views.scroll.ReactScrollViewHelper
18
+ import com.google.android.material.R as MaterialR
14
19
  import com.google.android.material.button.MaterialButton
15
20
  import com.google.android.material.button.MaterialButtonGroup
16
21
  import com.google.android.material.button.MaterialButtonToggleGroup
22
+ import com.google.android.material.button.MaterialSplitButton
17
23
 
18
24
  /**
19
25
  * A Material 3 Expressive button group: MaterialButtonGroup for plain actions,
20
- * MaterialButtonToggleGroup for single / multiple selection. Rebuilt whenever
21
- * a prop the widgets read at construction changes.
26
+ * MaterialButtonToggleGroup for single / multiple selection, and
27
+ * MaterialSplitButton in split mode (SplitButton). Rebuilt whenever a prop the
28
+ * widgets read at construction changes.
22
29
  */
23
30
  class PCButtonGroupView(context: Context) :
24
31
  FrameLayout(context),
@@ -38,6 +45,9 @@ class PCButtonGroupView(context: Context) :
38
45
 
39
46
  companion object {
40
47
  private const val TAG = "PCButtonGroup"
48
+
49
+ /** Minimum width of the split button's buttons (the touch target size). */
50
+ private const val SPLIT_MIN_WIDTH_DP = 48
41
51
  }
42
52
 
43
53
  // --- State Wrapper for Fabric state updates ---
@@ -59,6 +69,10 @@ class PCButtonGroupView(context: Context) :
59
69
  var interactivity: String = "enabled" // "enabled" | "disabled"
60
70
  var overflow: String = "none" // "none" | "menu" | "wrap"
61
71
  var expressive: Boolean = true // android.material: "expressive" | "m3"
72
+ var split: Boolean = false // MaterialSplitButton: the first button and a menu button
73
+ /** The split button's flattened menu items (see PCMenuSupport) */
74
+ var menuItems: List<PCMenuSupport.Item> = emptyList()
75
+ var menuAccessibilityLabel: String = ""
62
76
 
63
77
  // --- Styling (null / empty = Material theme default) ---
64
78
  var containerColor: Int? = null
@@ -70,12 +84,19 @@ class PCButtonGroupView(context: Context) :
70
84
  var labelFontWeight: String = ""
71
85
  var labelFontStyle: String = ""
72
86
 
87
+ /** The `haptics` prop: the manager plays it on a press (an overflow pick included), the split menu on a pick. */
88
+ var haptics: String = ""
89
+
73
90
  // --- Events ---
74
91
  var onPress: ((index: Int, value: String) -> Unit)? = null
75
92
  var onSelectionChange: ((values: List<String>) -> Unit)? = null
93
+ var onMenuSelect: ((id: String, title: String) -> Unit)? = null
94
+ var onMenuOpen: (() -> Unit)? = null
95
+ var onMenuClose: (() -> Unit)? = null
76
96
 
77
97
  // --- UI ---
78
98
  private var group: MaterialButtonGroup? = null
99
+ private var popupMenu: PopupMenu? = null
79
100
  private val buttonIdToIndex: MutableMap<Int, Int> = mutableMapOf()
80
101
  private var suppressCallbacks = false
81
102
  private var selectionEmitPending = false
@@ -176,6 +197,22 @@ class PCButtonGroupView(context: Context) :
176
197
  rebuildUI()
177
198
  }
178
199
 
200
+ fun applySplit(value: Boolean) {
201
+ if (split == value) return
202
+ split = value
203
+ rebuildUI()
204
+ }
205
+
206
+ fun applyMenu(value: List<PCMenuSupport.Item>) {
207
+ menuItems = value
208
+ }
209
+
210
+ fun applyMenuAccessibilityLabel(value: String) {
211
+ if (menuAccessibilityLabel == value) return
212
+ menuAccessibilityLabel = value
213
+ splitMenuButton()?.contentDescription = value.ifEmpty { null }
214
+ }
215
+
179
216
  fun applyMaterial(value: String?) {
180
217
  val parsed = PCExpressive.parseExpressive(value)
181
218
  if (expressive == parsed) return
@@ -221,6 +258,7 @@ class PCButtonGroupView(context: Context) :
221
258
 
222
259
  override fun onDetachedFromWindow() {
223
260
  PCNativeTheme.removeListener(nativeThemeListener)
261
+ popupMenu?.dismiss()
224
262
  super.onDetachedFromWindow()
225
263
  }
226
264
 
@@ -251,7 +289,14 @@ class PCButtonGroupView(context: Context) :
251
289
  val groupContext = if (overlay != 0) ContextThemeWrapper(base, overlay) else base
252
290
 
253
291
  val g: MaterialButtonGroup =
254
- if (toggle) {
292
+ if (split) {
293
+ // Material's split button style (a small gap and inner corners that
294
+ // round while the menu is open) over the Expressive widget styles
295
+ MaterialSplitButton(if (expressive) ContextThemeWrapper(base, R.style.PCExpressiveOverlay) else base).apply {
296
+ // Laid out like the other groups, without the style's vertical padding
297
+ setPadding(0, 0, 0, 0)
298
+ }
299
+ } else if (toggle) {
255
300
  MaterialButtonToggleGroup(groupContext).apply {
256
301
  isSingleSelection = selection == "single"
257
302
  isSelectionRequired = selectionRequired
@@ -266,12 +311,14 @@ class PCButtonGroupView(context: Context) :
266
311
  g.spacing = (spacing * resources.displayMetrics.density).toInt()
267
312
  }
268
313
  g.overflowMode = when (overflow) {
269
- "menu" -> MaterialButtonGroup.OVERFLOW_MODE_MENU
270
- "wrap" -> MaterialButtonGroup.OVERFLOW_MODE_WRAP
314
+ "menu" -> if (split) MaterialButtonGroup.OVERFLOW_MODE_NONE else MaterialButtonGroup.OVERFLOW_MODE_MENU
315
+ "wrap" -> if (split) MaterialButtonGroup.OVERFLOW_MODE_NONE else MaterialButtonGroup.OVERFLOW_MODE_WRAP
271
316
  else -> MaterialButtonGroup.OVERFLOW_MODE_NONE
272
317
  }
273
318
 
274
- for ((index, item) in items.withIndex()) {
319
+ // A split button is one button and its menu button
320
+ val shown = if (split) items.take(1) else items
321
+ for ((index, item) in shown.withIndex()) {
275
322
  val iconOnly = item.label.isEmpty() && item.icon.isPresent
276
323
 
277
324
  val button = PCExpressive.createButton(
@@ -308,6 +355,8 @@ class PCButtonGroupView(context: Context) :
308
355
  g.addView(button, params)
309
356
  }
310
357
 
358
+ if (split && shown.isNotEmpty()) addSplitMenuButton(g as MaterialSplitButton, base, g.getChildAt(0) as MaterialButton)
359
+
311
360
  if (g is MaterialButtonToggleGroup) {
312
361
  g.addOnButtonCheckedListener { _, _, _ ->
313
362
  if (suppressCallbacks) return@addOnButtonCheckedListener
@@ -325,6 +374,113 @@ class PCButtonGroupView(context: Context) :
325
374
  requestLayout()
326
375
  }
327
376
 
377
+ // ---- Split button ----
378
+
379
+ /**
380
+ * The trailing button of a split button: Material's chevron in a button of
381
+ * the leading button's style, which MaterialSplitButton makes checkable.
382
+ * Checking it opens the menu and turns the chevron; closing the menu
383
+ * unchecks it. It keeps the leading button's colors while checked, as
384
+ * Material's split button styles do, so only the chevron and the inner
385
+ * corners change.
386
+ */
387
+ private fun addSplitMenuButton(g: MaterialSplitButton, base: Context, leading: MaterialButton) {
388
+ val metrics = splitMetrics(if (expressive) size else "small")
389
+ val density = resources.displayMetrics.density
390
+ fun dp(value: Int) = (value * density).toInt()
391
+
392
+ val menuButton = PCExpressive.createButton(base, variant, size, "round", false, 0, expressive).apply {
393
+ id = View.generateViewId()
394
+ icon = ContextCompat.getDrawable(context, MaterialR.drawable.m3_split_button_chevron_avd)
395
+ iconSize = dp(metrics.iconSize)
396
+ iconPadding = 0
397
+ iconGravity = MaterialButton.ICON_GRAVITY_TEXT_START
398
+ setPaddingRelative(dp(metrics.menuStart), paddingTop, dp(metrics.menuEnd), paddingBottom)
399
+ // The touch target size, as Material's split button styles set, in
400
+ // place of the button styles' minimum width
401
+ minWidth = dp(SPLIT_MIN_WIDTH_DP)
402
+ minimumWidth = dp(SPLIT_MIN_WIDTH_DP)
403
+ contentDescription = menuAccessibilityLabel.ifEmpty { null }
404
+ isEnabled = interactivity == "enabled"
405
+ }
406
+ leading.setPaddingRelative(dp(metrics.leadingStart), leading.paddingTop, dp(metrics.leadingEnd), leading.paddingBottom)
407
+ leading.minWidth = dp(SPLIT_MIN_WIDTH_DP)
408
+ leading.minimumWidth = dp(SPLIT_MIN_WIDTH_DP)
409
+
410
+ g.addView(menuButton, MaterialButtonGroup.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 0f))
411
+ menuButton.backgroundTintList = uncheckable(leading.backgroundTintList)
412
+ menuButton.iconTint = uncheckable(leading.iconTint ?: leading.textColors)
413
+ menuButton.strokeColor = uncheckable(leading.strokeColor)
414
+ menuButton.strokeWidth = leading.strokeWidth
415
+ menuButton.rippleColor = leading.rippleColor
416
+ menuButton.addOnCheckedChangeListener { button, checked -> if (checked) showSplitMenu(button) }
417
+ }
418
+
419
+ /**
420
+ * A button's enabled and disabled colors, without the checked states the
421
+ * Material toggle colors add, so a checkable button keeps them.
422
+ */
423
+ private fun uncheckable(colors: ColorStateList?): ColorStateList? {
424
+ colors ?: return null
425
+ val disabled = intArrayOf(-android.R.attr.state_enabled)
426
+ return ColorStateList(
427
+ arrayOf(disabled, intArrayOf()),
428
+ intArrayOf(
429
+ colors.getColorForState(disabled, colors.defaultColor),
430
+ colors.getColorForState(intArrayOf(android.R.attr.state_enabled), colors.defaultColor)
431
+ )
432
+ )
433
+ }
434
+
435
+ private fun splitMenuButton(): MaterialButton? =
436
+ (group as? MaterialSplitButton)?.getChildAt(1) as? MaterialButton
437
+
438
+ /** Spacing and icon size of the split button sizes, in dp (Material 1.14 tokens). */
439
+ private data class SplitMetrics(
440
+ val leadingStart: Int,
441
+ val leadingEnd: Int,
442
+ val iconSize: Int,
443
+ val menuStart: Int,
444
+ val menuEnd: Int
445
+ )
446
+
447
+ private fun splitMetrics(size: String): SplitMetrics = when (size) {
448
+ "xsmall" -> SplitMetrics(12, 10, 22, 13, 13)
449
+ "medium" -> SplitMetrics(24, 24, 26, 15, 15)
450
+ "large" -> SplitMetrics(48, 48, 38, 29, 29)
451
+ "xlarge" -> SplitMetrics(64, 64, 50, 43, 43)
452
+ else -> SplitMetrics(16, 12, 22, 13, 13)
453
+ }
454
+
455
+ /** A PopupMenu anchored to the menu button, built like ContextMenu's. */
456
+ private fun showSplitMenu(anchor: MaterialButton) {
457
+ if (popupMenu != null) return
458
+ val items = menuItems
459
+ // Aligned to the split button's end edge
460
+ val popup = PopupMenu(context, anchor, Gravity.END)
461
+ popupMenu = popup
462
+ val hasIcons = PCMenuSupport.populate(context, popup.menu, items) { popupMenu === popup }
463
+ popup.setForceShowIcon(hasIcons)
464
+
465
+ popup.setOnMenuItemClickListener { menuItem ->
466
+ // Submenu headers open their submenu; they aren't picks
467
+ val item = PCMenuSupport.itemFor(menuItem, items)
468
+ if (item == null || !item.isAction) return@setOnMenuItemClickListener false
469
+ PCHaptics.perform(this, item.haptics.ifEmpty { haptics })
470
+ onMenuSelect?.invoke(item.id, item.title)
471
+ true
472
+ }
473
+ popup.setOnDismissListener {
474
+ if (popupMenu === popup) popupMenu = null
475
+ // Turns the chevron back
476
+ anchor.isChecked = false
477
+ onMenuClose?.invoke()
478
+ }
479
+
480
+ onMenuOpen?.invoke()
481
+ popup.show()
482
+ }
483
+
328
484
  private fun scheduleSelectionEmit() {
329
485
  if (selectionEmitPending) return
330
486
  selectionEmitPending = true
@@ -341,14 +497,23 @@ class PCButtonGroupView(context: Context) :
341
497
  .sorted()
342
498
  .map { items[it].value }
343
499
  onSelectionChange?.invoke(values)
500
+ // Keep the prop authoritative even when the parent declines the edit and
501
+ // React therefore has no changed selection prop to send back.
502
+ updateSelection()
344
503
  }
345
504
 
346
505
  private fun updateSelection() {
347
506
  val g = group as? MaterialButtonToggleGroup ?: return
348
507
  suppressCallbacks = true
349
- for ((id, index) in buttonIdToIndex) {
350
- val checked = selectedValues.contains(items[index].value)
351
- if (checked) g.check(id) else g.uncheck(id)
508
+ val selectedIds = buttonIdToIndex.filterValues { selectedValues.contains(items[it].value) }.keys
509
+ if (selectedIds.isEmpty()) {
510
+ // clearChecked also permits a controlled empty selection when user
511
+ // deselection is disabled by selectionRequired.
512
+ g.clearChecked()
513
+ } else {
514
+ // Check first so selectionRequired does not retain the previous last item.
515
+ selectedIds.forEach { g.check(it) }
516
+ for (id in buttonIdToIndex.keys) if (id !in selectedIds) g.uncheck(id)
352
517
  }
353
518
  suppressCallbacks = false
354
519
  }
@@ -363,6 +528,7 @@ class PCButtonGroupView(context: Context) :
363
528
  val index = buttonIdToIndex[button.id] ?: continue
364
529
  button.isEnabled = enabled && !items[index].disabled
365
530
  }
531
+ splitMenuButton()?.isEnabled = enabled
366
532
  }
367
533
 
368
534
  // ---- Layout ----
@@ -3,6 +3,7 @@ package com.platformcomponents
3
3
  import com.facebook.react.bridge.Arguments
4
4
  import com.facebook.react.bridge.ReadableArray
5
5
  import com.facebook.react.bridge.ReadableMap
6
+ import com.facebook.react.bridge.WritableMap
6
7
  import com.facebook.react.uimanager.ReactStylesDiffMap
7
8
  import com.facebook.react.uimanager.SimpleViewManager
8
9
  import com.facebook.react.uimanager.StateWrapper
@@ -53,11 +54,23 @@ class PCButtonGroupViewManager :
53
54
  val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, view.id)
54
55
 
55
56
  view.onPress = { index, value ->
57
+ PCHaptics.perform(view, view.haptics)
56
58
  dispatcher?.dispatchEvent(PressEvent(view.id, index, value))
57
59
  }
58
60
  view.onSelectionChange = { values ->
59
61
  dispatcher?.dispatchEvent(SelectionEvent(view.id, values))
60
62
  }
63
+ fun dispatch(name: String, fill: WritableMap.() -> Unit = {}) {
64
+ dispatcher?.dispatchEvent(MenuEvent(UIManagerHelper.getSurfaceId(view), view.id, name, fill))
65
+ }
66
+ view.onMenuSelect = { id, title ->
67
+ dispatch("topMenuSelect") {
68
+ putString("id", id)
69
+ putString("title", title)
70
+ }
71
+ }
72
+ view.onMenuOpen = { dispatch("topMenuOpen") }
73
+ view.onMenuClose = { dispatch("topMenuClose") }
61
74
  }
62
75
 
63
76
  // buttons: array of {label, value, disabled, iconType, iconName, iconUri,
@@ -152,9 +165,32 @@ class PCButtonGroupViewManager :
152
165
  )
153
166
  }
154
167
 
155
- // android: {overflow, material}
168
+ // "none" | "menu" | "wrap"
169
+ override fun setOverflow(view: PCButtonGroupView, value: String?) {
170
+ view.applyOverflow(value)
171
+ }
172
+
173
+ // "true" | "false": MaterialSplitButton
174
+ override fun setSplit(view: PCButtonGroupView, value: String?) {
175
+ view.applySplit(value == "true")
176
+ }
177
+
178
+ // menu: the split button's flattened menu items
179
+ override fun setMenu(view: PCButtonGroupView, value: ReadableArray?) {
180
+ view.applyMenu(PCMenuSupport.parseItems(value))
181
+ }
182
+
183
+ override fun setMenuAccessibilityLabel(view: PCButtonGroupView, value: String?) {
184
+ view.applyMenuAccessibilityLabel(value ?: "")
185
+ }
186
+
187
+ // "" (none added) | "none" | "selection" | "light" | "medium" | "heavy" | "success" | "warning" | "error"
188
+ override fun setHaptics(view: PCButtonGroupView, value: String?) {
189
+ view.haptics = PCHaptics.configure(view, value)
190
+ }
191
+
192
+ // android: {material}
156
193
  override fun setAndroid(view: PCButtonGroupView, value: ReadableMap?) {
157
- view.applyOverflow(value?.stringOr("overflow", "none"))
158
194
  view.applyMaterial(value?.stringOr("material", "expressive"))
159
195
  }
160
196
 
@@ -174,6 +210,20 @@ class PCButtonGroupViewManager :
174
210
  }
175
211
  }
176
212
 
213
+ private class MenuEvent(
214
+ surfaceId: Int,
215
+ viewTag: Int,
216
+ private val name: String,
217
+ private val fill: WritableMap.() -> Unit
218
+ ) : Event<MenuEvent>(surfaceId, viewTag) {
219
+ override fun canCoalesce(): Boolean = false
220
+
221
+ override fun getEventName(): String = name
222
+
223
+ // Fabric reads the payload from here
224
+ override fun getEventData(): WritableMap = Arguments.createMap().apply(fill)
225
+ }
226
+
177
227
  private class SelectionEvent(
178
228
  surfaceId: Int,
179
229
  private val values: List<String>
@@ -3,6 +3,7 @@ package com.platformcomponents
3
3
  import android.content.res.ColorStateList
4
4
  import android.graphics.Color
5
5
  import android.graphics.drawable.BitmapDrawable
6
+ import android.os.Build
6
7
  import android.util.TypedValue
7
8
  import android.widget.TextView
8
9
  import com.facebook.react.bridge.ReadableMap
@@ -18,7 +19,8 @@ object PCButtonSupport {
18
19
  val name: String,
19
20
  val uri: String,
20
21
  val scale: Float,
21
- val tinted: Boolean
22
+ val tinted: Boolean,
23
+ val request: String = ""
22
24
  ) {
23
25
  val isPresent: Boolean get() = type == "drawable" || type == "image"
24
26
  }
@@ -40,7 +42,8 @@ object PCButtonSupport {
40
42
  name = map.stringOr("iconName", ""),
41
43
  uri = map.stringOr("iconUri", ""),
42
44
  scale = if (scale > 0) scale.toFloat() else 1f,
43
- tinted = map.stringOr("iconTinted", "true") != "false"
45
+ tinted = map.stringOr("iconTinted", "true") != "false",
46
+ request = map.stringOr("iconRequest", "")
44
47
  )
45
48
  }
46
49
 
@@ -64,7 +67,7 @@ object PCButtonSupport {
64
67
  if (!uri.contains(':')) {
65
68
  button.icon = ResourceDrawableIdHelper.instance.getResourceDrawable(context, uri)
66
69
  } else {
67
- PCImageLoader.load(context, uri, icon.scale) { bitmap ->
70
+ PCImageLoader.load(context, uri, icon.scale, icon.request) { bitmap ->
68
71
  if (bitmap == null || !isCurrent()) return@load
69
72
  button.icon = BitmapDrawable(context.resources, bitmap)
70
73
  onLoaded()
@@ -91,8 +94,28 @@ object PCButtonSupport {
91
94
  }
92
95
 
93
96
  /**
94
- * Applies the color props on top of the style's colors, keeping the style's
95
- * disabled colors.
97
+ * Caps the label's font scaling at [maxMultiplier] times its unscaled size,
98
+ * as React Native's maxFontSizeMultiplier does; below 1 means no cap. Call
99
+ * after the font size is set.
100
+ */
101
+ fun applyMaxFontSizeMultiplier(button: TextView, maxMultiplier: Float) {
102
+ if (maxMultiplier < 1f) return
103
+ val metrics = button.resources.displayMetrics
104
+ // The sp size back from pixels; Android 14+ scales large text non-linearly
105
+ val sp = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
106
+ TypedValue.deriveDimension(TypedValue.COMPLEX_UNIT_SP, button.textSize, metrics)
107
+ } else {
108
+ button.textSize / (metrics.density * button.resources.configuration.fontScale)
109
+ }
110
+ val cap = sp * metrics.density * maxMultiplier
111
+ if (button.textSize > cap) {
112
+ button.setTextSize(TypedValue.COMPLEX_UNIT_PX, cap)
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Applies the color props on top of the style's colors. Unset disabled
118
+ * colors keep the style's; unset enabled colors keep the style's too.
96
119
  */
97
120
  fun applyColors(
98
121
  button: MaterialButton,
@@ -100,21 +123,30 @@ object PCButtonSupport {
100
123
  foreground: Int?,
101
124
  ripple: Int?,
102
125
  stroke: Int?,
103
- iconTinted: Boolean
126
+ iconTinted: Boolean,
127
+ disabledContainer: Int? = null,
128
+ disabledForeground: Int? = null
104
129
  ) {
105
130
  val disabledState = intArrayOf(-android.R.attr.state_enabled)
131
+ val enabledState = intArrayOf(android.R.attr.state_enabled)
106
132
  val states = arrayOf(disabledState, intArrayOf())
107
133
 
108
- container?.let { color ->
134
+ if (container != null || disabledContainer != null) {
109
135
  val theme = button.backgroundTintList
110
- val disabled = theme?.getColorForState(disabledState, theme.defaultColor) ?: Color.TRANSPARENT
111
- button.backgroundTintList = ColorStateList(states, intArrayOf(disabled, color))
136
+ val disabled = disabledContainer
137
+ ?: theme?.getColorForState(disabledState, theme.defaultColor)
138
+ ?: Color.TRANSPARENT
139
+ val enabled = container
140
+ ?: theme?.getColorForState(enabledState, theme.defaultColor)
141
+ ?: Color.TRANSPARENT
142
+ button.backgroundTintList = ColorStateList(states, intArrayOf(disabled, enabled))
112
143
  }
113
144
 
114
- foreground?.let { color ->
145
+ if (foreground != null || disabledForeground != null) {
115
146
  val theme = button.textColors
116
- val disabled = theme.getColorForState(disabledState, theme.defaultColor)
117
- val tint = ColorStateList(states, intArrayOf(disabled, color))
147
+ val disabled = disabledForeground ?: theme.getColorForState(disabledState, theme.defaultColor)
148
+ val enabled = foreground ?: theme.getColorForState(enabledState, theme.defaultColor)
149
+ val tint = ColorStateList(states, intArrayOf(disabled, enabled))
118
150
  button.setTextColor(tint)
119
151
  if (iconTinted) {
120
152
  button.iconTint = tint