react-native-platform-components 1.4.0 → 1.6.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 (600) 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.cjs +79 -6
  525. package/plugin/build/index.d.ts +27 -2
  526. package/plugin/build/index.d.ts.map +1 -1
  527. package/plugin/tsconfig.json +2 -1
  528. package/react-native.config.js +3 -0
  529. package/shared/PCFloatingActionButtonComponentDescriptors-custom.h +22 -0
  530. package/shared/PCFloatingActionButtonShadowNode-custom.cpp +48 -0
  531. package/shared/PCFloatingActionButtonShadowNode-custom.h +54 -0
  532. package/shared/PCFloatingActionButtonState-custom.h +61 -0
  533. package/shared/PCNavigationRailComponentDescriptors-custom.h +47 -0
  534. package/shared/PCNavigationRailShadowNode-custom.h +42 -0
  535. package/shared/PCNavigationRailState-custom.h +62 -0
  536. package/shared/PCTabBarComponentDescriptors-custom.h +22 -0
  537. package/shared/PCTabBarShadowNode-custom.cpp +54 -0
  538. package/shared/PCTabBarShadowNode-custom.h +54 -0
  539. package/shared/PCTabBarState-custom.h +62 -0
  540. package/shared/react/renderer/components/PlatformComponentsViewSpec/ComponentDescriptors.h +3 -0
  541. package/src/Button.tsx +222 -7
  542. package/src/ButtonGroup.tsx +29 -11
  543. package/src/ButtonGroupNativeComponent.ts +74 -4
  544. package/src/ButtonNativeComponent.ts +119 -3
  545. package/src/ContextMenu.tsx +34 -81
  546. package/src/ContextMenuNativeComponent.ts +47 -49
  547. package/src/DatePicker.tsx +182 -4
  548. package/src/DatePickerNativeComponent.ts +19 -2
  549. package/src/FloatingActionButton.tsx +121 -0
  550. package/src/FloatingActionButtonNativeComponent.ts +58 -0
  551. package/src/FloatingToolbar.tsx +54 -3
  552. package/src/FloatingToolbarNativeComponent.ts +16 -0
  553. package/src/LiquidGlass.tsx +24 -1
  554. package/src/LiquidGlassContainer.tsx +42 -0
  555. package/src/LiquidGlassContainerNativeComponent.ts +17 -0
  556. package/src/LiquidGlassNativeComponent.ts +8 -0
  557. package/src/NavigationRail.tsx +203 -0
  558. package/src/NavigationRailNativeComponent.ts +107 -0
  559. package/src/PlatformComponentsProvider.tsx +15 -0
  560. package/src/SegmentedControl.tsx +31 -1
  561. package/src/SegmentedControlNativeComponent.ts +11 -0
  562. package/src/SelectionMenu.tsx +81 -6
  563. package/src/SelectionMenuNativeComponent.ts +26 -4
  564. package/src/SplitButton.tsx +198 -0
  565. package/src/TabBar.tsx +373 -0
  566. package/src/TabBarAccessoryNativeComponent.ts +19 -0
  567. package/src/TabBarNativeComponent.ts +145 -0
  568. package/src/TextField.tsx +428 -14
  569. package/src/TextFieldNativeComponent.ts +110 -4
  570. package/src/focusRegistry.ts +1 -0
  571. package/src/haptics.ts +31 -0
  572. package/src/icons.ts +28 -1
  573. package/src/index.tsx +7 -0
  574. package/src/index.web.tsx +51 -391
  575. package/src/jest.tsx +958 -0
  576. package/src/menuItems.ts +152 -0
  577. package/src/selectionIdentifiers.ts +17 -0
  578. package/src/submitBehavior.ts +16 -0
  579. package/src/tabItems.ts +113 -0
  580. package/src/web/Button.tsx +201 -0
  581. package/src/web/ButtonGroup.tsx +154 -0
  582. package/src/web/DatePicker.tsx +204 -0
  583. package/src/web/DateRangePicker.tsx +135 -0
  584. package/src/web/Dialog.tsx +54 -0
  585. package/src/web/FloatingActionButton.tsx +76 -0
  586. package/src/web/Icon.tsx +33 -0
  587. package/src/web/NativeTheme.ts +23 -0
  588. package/src/web/NavigationRail.tsx +148 -0
  589. package/src/web/PlatformComponentsProvider.tsx +48 -0
  590. package/src/web/SegmentedControl.tsx +127 -0
  591. package/src/web/SelectionMenu.tsx +149 -0
  592. package/src/web/SplitButton.tsx +32 -0
  593. package/src/web/TabBar.tsx +150 -0
  594. package/src/web/TextField.tsx +361 -0
  595. package/src/web/components.tsx +71 -0
  596. package/src/web/containers.tsx +130 -0
  597. package/src/web/dateInput.ts +137 -0
  598. package/src/web/shared.ts +176 -0
  599. package/src/webComponents.ts +45 -0
  600. package/android/src/main/java/com/platformcomponents/DateConstraints.kt +0 -83
@@ -1,30 +1,58 @@
1
1
  package com.platformcomponents
2
2
 
3
3
  import android.content.Context
4
+ import android.content.res.ColorStateList
5
+ import android.graphics.drawable.ColorDrawable
6
+ import android.graphics.drawable.Drawable
7
+ import android.graphics.drawable.RippleDrawable
4
8
  import android.text.InputType
9
+ import android.text.TextUtils
5
10
  import android.util.Log
11
+ import android.util.TypedValue
12
+ import android.view.Gravity
6
13
  import android.view.View
7
14
  import android.view.ViewGroup
8
15
  import android.view.ViewTreeObserver
16
+ import android.view.inputmethod.EditorInfo
17
+ import android.view.inputmethod.InputMethodManager
9
18
  import android.widget.AdapterView
10
19
  import android.widget.ArrayAdapter
20
+ import android.widget.BaseAdapter
21
+ import android.widget.Filter
22
+ import android.widget.Filterable
11
23
  import android.widget.FrameLayout
24
+ import android.widget.ImageView
12
25
  import android.widget.LinearLayout
13
26
  import android.widget.Spinner
27
+ import android.widget.TextView
14
28
  import androidx.appcompat.widget.PopupMenu
29
+ import androidx.core.widget.TextViewCompat
15
30
  import com.facebook.react.bridge.WritableNativeMap
16
31
  import com.facebook.react.uimanager.PixelUtil
17
32
  import com.facebook.react.uimanager.StateWrapper
18
33
  import com.facebook.react.views.scroll.ReactScrollViewHelper
34
+ import com.google.android.material.R as MaterialR
35
+ import com.google.android.material.color.MaterialColors
19
36
  import com.google.android.material.textfield.MaterialAutoCompleteTextView
20
37
  import com.google.android.material.textfield.TextInputLayout
38
+ import java.util.Locale
21
39
 
22
40
  class PCSelectionMenuView(context: Context) : FrameLayout(context), ReactScrollViewHelper.HasStateWrapper {
23
41
 
24
- data class Option(val label: String, val data: String)
42
+ data class Option(
43
+ val label: String,
44
+ val data: String,
45
+ val subtitle: String = "",
46
+ val icon: PCButtonSupport.Icon = PCButtonSupport.NO_ICON,
47
+ val disabled: Boolean = false
48
+ ) {
49
+ /** Has content beyond a label, which needs the rich dropdown rows. */
50
+ val isRich: Boolean get() = subtitle.isNotEmpty() || icon.isPresent
51
+ }
25
52
 
26
53
  companion object {
27
54
  private const val TAG = "PCSelectionMenu"
55
+ private const val HEADLESS_GROUP_ID = 0
28
56
  }
29
57
 
30
58
  // --- State Wrapper for Fabric state updates ---
@@ -46,6 +74,12 @@ class PCSelectionMenuView(context: Context) : FrameLayout(context), ReactScrollV
46
74
  // Only used to choose inline rendering style.
47
75
  var androidMaterial: String? = "system" // "system" | "m3"
48
76
 
77
+ // Embedded M3 only: the field accepts typing and filters the options.
78
+ var androidSearchable: Boolean = false
79
+
80
+ /** The `haptics` prop; the manager plays it with the user's action (see PCHaptics). */
81
+ var haptics: String = ""
82
+
49
83
  // --- Events ---
50
84
  var onSelect: ((index: Int, label: String, data: String) -> Unit)? = null
51
85
  var onRequestClose: (() -> Unit)? = null
@@ -56,6 +90,8 @@ class PCSelectionMenuView(context: Context) : FrameLayout(context), ReactScrollV
56
90
  private var inlineSpinner: Spinner? = null
57
91
  private var inlineDropdownOverlay: View? = null
58
92
  private var inlineSpinnerSuppressCount = 0
93
+ private var inlineSpinnerPendingSelection: String? = null
94
+ private var inlineSpinnerHasPlaceholder = false
59
95
 
60
96
  // --- Headless UI (true picker) ---
61
97
  private var headlessMenu: PopupMenu? = null
@@ -232,7 +268,7 @@ class PCSelectionMenuView(context: Context) : FrameLayout(context), ReactScrollV
232
268
  val next = data ?: ""
233
269
  if (selectedData == next) return
234
270
  selectedData = next
235
- Log.d(TAG, "applySelectedData selectedData=$selectedData")
271
+ Log.d(TAG, "applySelectedData")
236
272
  refreshSelections()
237
273
  }
238
274
 
@@ -257,7 +293,10 @@ class PCSelectionMenuView(context: Context) : FrameLayout(context), ReactScrollV
257
293
  if (placeholder == value) return
258
294
  placeholder = value
259
295
  inlineLayout?.hint = placeholder
260
- // Spinner doesn't support placeholder
296
+ if (inlineSpinner != null) {
297
+ refreshAdapters()
298
+ refreshSelections()
299
+ }
261
300
 
262
301
  // Re-measure after placeholder change
263
302
  if (anchorMode == "inline") {
@@ -312,6 +351,16 @@ class PCSelectionMenuView(context: Context) : FrameLayout(context), ReactScrollV
312
351
  if (anchorMode == "inline") rebuildUI()
313
352
  }
314
353
 
354
+ fun applyAndroidSearchable(value: Boolean) {
355
+ if (androidSearchable == value) return
356
+ androidSearchable = value
357
+ if (anchorMode == "inline" && parseMaterial(androidMaterial) == MaterialMode.M3) rebuildUI()
358
+ }
359
+
360
+ /** The embedded M3 field takes typing to filter the options. */
361
+ private val isSearchable: Boolean
362
+ get() = androidSearchable && anchorMode == "inline" && parseMaterial(androidMaterial) == MaterialMode.M3
363
+
315
364
  // ---- UI building ----
316
365
 
317
366
  private fun rebuildUI() {
@@ -328,6 +377,8 @@ class PCSelectionMenuView(context: Context) : FrameLayout(context), ReactScrollV
328
377
  inlineText = null
329
378
  inlineSpinner = null
330
379
  inlineSpinnerSuppressCount = 0
380
+ inlineSpinnerPendingSelection = null
381
+ inlineSpinnerHasPlaceholder = false
331
382
  headlessMenu = null
332
383
  headlessMenuShowing = false
333
384
  headlessDismissProgrammatic = false
@@ -387,24 +438,58 @@ class PCSelectionMenuView(context: Context) : FrameLayout(context), ReactScrollV
387
438
  ViewGroup.LayoutParams.WRAP_CONTENT
388
439
  )
389
440
 
390
- // Keep it a real text editor so the popup behaves modally
391
- inputType = InputType.TYPE_CLASS_TEXT
441
+ if (isSearchable) {
442
+ // Typing filters the options (see OptionAdapter). The text is only a
443
+ // query: selection still comes from picking an option.
444
+ inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS
445
+ imeOptions = EditorInfo.IME_ACTION_DONE
446
+ // The first tap selects the label, so typing replaces it
447
+ setSelectAllOnFocus(true)
448
+ setOnEditorActionListener { _, actionId, _ ->
449
+ if (actionId == EditorInfo.IME_ACTION_DONE) {
450
+ clearFocus()
451
+ true
452
+ } else {
453
+ false
454
+ }
455
+ }
456
+ } else {
457
+ // Keep it a real text editor so the popup behaves modally
458
+ inputType = InputType.TYPE_CLASS_TEXT
459
+
460
+ // Prevent keyboard
461
+ showSoftInputOnFocus = false
392
462
 
393
- // Prevent keyboard
394
- showSoftInputOnFocus = false
463
+ // Optional: keep it from being typed into
464
+ keyListener = null
465
+ isCursorVisible = false
466
+ }
395
467
 
396
- // Optional: keep it from being typed into
397
- keyListener = null
398
- isCursorVisible = false
468
+ // Highlight the selected option in the dropdown, like the M3 exposed dropdown menu.
469
+ // The adapter from setSimpleItems() marks the item whose text matches the field.
470
+ simpleItemSelectedColor = MaterialColors.getColor(
471
+ til.context,
472
+ com.google.android.material.R.attr.colorSecondaryContainer,
473
+ 0
474
+ )
399
475
 
400
476
  // Nice UX: click anywhere opens dropdown
401
477
  setOnClickListener { showDropDown() }
402
478
 
403
479
  setOnItemClickListener { _, _, position, _ ->
404
- val opt = options.getOrNull(position) ?: return@setOnItemClickListener
405
- selectedData = opt.data
406
- onSelect?.invoke(position, opt.label, opt.data)
480
+ // A filtered list's positions differ from the options'
481
+ val opt = (adapter as? OptionAdapter)?.getItem(position)
482
+ ?: options.getOrNull(position)
483
+ ?: return@setOnItemClickListener
484
+ val index = options.indexOf(opt)
485
+ if (interactivity != "enabled" || opt.disabled) {
486
+ post { refreshSelections() }
487
+ return@setOnItemClickListener
488
+ }
489
+ onSelect?.invoke(index, opt.label, opt.data)
490
+ post { refreshSelections() }
407
491
  detachInlineDropdownOverlay()
492
+ if (isSearchable) clearFocus()
408
493
  }
409
494
 
410
495
  setOnTouchListener { _, e ->
@@ -416,6 +501,21 @@ class PCSelectionMenuView(context: Context) : FrameLayout(context), ReactScrollV
416
501
  }
417
502
 
418
503
  til.addView(actv)
504
+ if (isSearchable) {
505
+ // Set after the field joins the layout, whose dropdown icon installs its
506
+ // own focus listener; that one still runs first.
507
+ val materialFocusListener = actv.onFocusChangeListener
508
+ actv.setOnFocusChangeListener { view, hasFocus ->
509
+ materialFocusListener?.onFocusChange(view, hasFocus)
510
+ if (hasFocus) return@setOnFocusChangeListener
511
+ // Leaving the field: the query goes, and the field shows the
512
+ // selected option again (or the placeholder)
513
+ actv.dismissDropDown()
514
+ showSelectedText()
515
+ val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
516
+ imm?.hideSoftInputFromWindow(view.windowToken, 0)
517
+ }
518
+ }
419
519
  addView(til)
420
520
  inlineLayout = til
421
521
  } else {
@@ -423,6 +523,7 @@ class PCSelectionMenuView(context: Context) : FrameLayout(context), ReactScrollV
423
523
  val sp = object : Spinner(context, null, android.R.attr.spinnerStyle, Spinner.MODE_DROPDOWN) {
424
524
  override fun setSelection(position: Int, animate: Boolean) {
425
525
  val oldPos = selectedItemPosition
526
+ val selectionAdapter = adapter
426
527
  super.setSelection(position, animate)
427
528
 
428
529
  // Manually trigger onItemSelectedListener if selection changed
@@ -430,6 +531,7 @@ class PCSelectionMenuView(context: Context) : FrameLayout(context), ReactScrollV
430
531
  // the selection changes via user interaction with the dropdown
431
532
  if (position != oldPos && onItemSelectedListener != null) {
432
533
  post {
534
+ if (adapter !== selectionAdapter || selectedItemPosition != position) return@post
433
535
  onItemSelectedListener?.onItemSelected(
434
536
  this,
435
537
  selectedView,
@@ -442,11 +544,13 @@ class PCSelectionMenuView(context: Context) : FrameLayout(context), ReactScrollV
442
544
 
443
545
  override fun setSelection(position: Int) {
444
546
  val oldPos = selectedItemPosition
547
+ val selectionAdapter = adapter
445
548
  super.setSelection(position)
446
549
 
447
550
  // Manually trigger onItemSelectedListener if selection changed
448
551
  if (position != oldPos && onItemSelectedListener != null) {
449
552
  post {
553
+ if (adapter !== selectionAdapter || selectedItemPosition != position) return@post
450
554
  onItemSelectedListener?.onItemSelected(
451
555
  this,
452
556
  selectedView,
@@ -470,15 +574,31 @@ class PCSelectionMenuView(context: Context) : FrameLayout(context), ReactScrollV
470
574
  if (inlineSpinnerSuppressCount > 0) return
471
575
 
472
576
  if (interactivity != "enabled") return
473
-
474
- val opt = options.getOrNull(position) ?: return
577
+ // Spinner can notify both synchronously and on its next layout; the
578
+ // fallback in setSelection must not duplicate a single user selection.
579
+ if (position != sp.selectedItemPosition) return
580
+
581
+ val index = position - if (inlineSpinnerHasPlaceholder) 1 else 0
582
+ val opt = options.getOrNull(index) ?: return
583
+ if (opt.disabled) {
584
+ post { refreshSelections() }
585
+ return
586
+ }
475
587
 
476
588
  // Only fire callback if selection actually changed
477
589
  if (opt.data == selectedData) return
590
+ if (inlineSpinnerPendingSelection == opt.data) return
591
+ inlineSpinnerPendingSelection = opt.data
478
592
 
479
593
  // Don't update selectedData here - let applySelectedData handle it
480
594
  // This ensures refreshSelections() is called to update the Spinner's display
481
- onSelect?.invoke(position, opt.label, opt.data)
595
+ onSelect?.invoke(index, opt.label, opt.data)
596
+ post {
597
+ if (inlineSpinner === sp) {
598
+ refreshSelections()
599
+ inlineSpinnerPendingSelection = null
600
+ }
601
+ }
482
602
  }
483
603
 
484
604
  override fun onNothingSelected(parent: AdapterView<*>) {
@@ -503,11 +623,10 @@ class PCSelectionMenuView(context: Context) : FrameLayout(context), ReactScrollV
503
623
  val popup = PopupMenu(context, this@PCSelectionMenuView).apply {
504
624
  setOnMenuItemClickListener { item ->
505
625
  val index = item.itemId
506
- val opt = options.getOrNull(index)
507
- Log.d(
508
- TAG,
509
- "headless onMenuItemClick index=$index optData=${opt?.data} selectedData=$selectedData"
510
- )
626
+ if (interactivity != "enabled" || options.getOrNull(index)?.disabled != false) {
627
+ return@setOnMenuItemClickListener false
628
+ }
629
+ Log.d(TAG, "headless onMenuItemClick index=$index")
511
630
  headlessDismissAfterSelect = true
512
631
  handleHeadlessSelection(index)
513
632
  true
@@ -540,15 +659,53 @@ class PCSelectionMenuView(context: Context) : FrameLayout(context), ReactScrollV
540
659
 
541
660
  private fun refreshAdapters() {
542
661
  val labels = options.map { it.label }
662
+ val rich = options.any { it.isRich }
543
663
 
544
664
  inlineText?.let { actv ->
545
- val adapter = ArrayAdapter(actv.context, android.R.layout.simple_list_item_1, labels)
546
- actv.setAdapter(adapter)
665
+ if (rich || isSearchable || options.any { it.disabled }) {
666
+ // Icon + label + subtitle rows, filtered by the typed query
667
+ actv.setAdapter(OptionAdapter(actv.context, options))
668
+ } else {
669
+ // Material's simple-item adapter highlights the selected option (simpleItemSelectedColor).
670
+ actv.setSimpleItems(labels.toTypedArray())
671
+ }
547
672
  }
548
673
 
549
674
  inlineSpinner?.let { sp ->
550
675
  suppressInlineSpinnerCallbacks(sp)
551
- val adapter = ArrayAdapter(sp.context, android.R.layout.simple_spinner_item, labels)
676
+ // The platform Spinner keeps its own rows (labels only): its dropdown is
677
+ // sized to its widest row and anchored at the field's start, so rich
678
+ // rows would run off the screen's edge.
679
+ // Spinner needs a selected row even for null. Use a normal disabled
680
+ // placeholder until a value is selected, then show only real options.
681
+ // ListView measures zero-height rows with UNSPECIFIED height, so a GONE
682
+ // placeholder can leave a full-height row with unreliable touch bounds.
683
+ val hasPlaceholder = options.none { it.data == selectedData }
684
+ inlineSpinnerHasPlaceholder = hasPlaceholder
685
+ val adapter = object : ArrayAdapter<String>(
686
+ sp.context, android.R.layout.simple_spinner_item,
687
+ if (hasPlaceholder) listOf(placeholder.orEmpty()) + labels else labels
688
+ ) {
689
+ override fun areAllItemsEnabled() = !hasPlaceholder && options.none { it.disabled }
690
+
691
+ // https://developer.android.com/reference/android/widget/BaseAdapter#isEnabled(int)
692
+ override fun isEnabled(position: Int) =
693
+ options.getOrNull(position - if (hasPlaceholder) 1 else 0)?.disabled == false
694
+
695
+ override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
696
+ val enabled = isEnabled(position)
697
+ return super.getDropDownView(position, convertView, parent).apply {
698
+ isEnabled = enabled
699
+ alpha = if (enabled) 1f else 0.38f
700
+ }
701
+ }
702
+
703
+ override fun getView(position: Int, convertView: View?, parent: ViewGroup): View =
704
+ (super.getView(position, convertView, parent) as TextView).apply {
705
+ if (hasPlaceholder && position == 0) text = ""
706
+ hint = if (hasPlaceholder && position == 0) placeholder else null
707
+ }
708
+ }
552
709
  adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
553
710
  sp.adapter = adapter
554
711
  }
@@ -564,19 +721,12 @@ class PCSelectionMenuView(context: Context) : FrameLayout(context), ReactScrollV
564
721
  private fun refreshSelections() {
565
722
  val idx = options.indexOfFirst { it.data == selectedData }
566
723
 
567
- inlineText?.let { actv ->
568
- if (idx >= 0) {
569
- // Show selected value
570
- actv.setText(options[idx].label, false)
571
- } else {
572
- // Clear text to show placeholder
573
- actv.setText("", false)
574
- }
575
- }
724
+ // A searchable field keeps the user's query while it has focus
725
+ if (!(isSearchable && inlineText?.hasFocus() == true)) showSelectedText()
576
726
 
577
727
  inlineSpinner?.let { sp ->
578
- if (options.isEmpty()) return
579
- val target = if (idx >= 0) idx else 0
728
+ if (inlineSpinnerHasPlaceholder != (idx < 0)) refreshAdapters()
729
+ val target = if (inlineSpinnerHasPlaceholder) 0 else idx
580
730
  // Always call setSelection to ensure the view is refreshed
581
731
  // Even if the position hasn't changed, we need to update the displayed text
582
732
  suppressInlineSpinnerCallbacks(sp)
@@ -592,6 +742,176 @@ class PCSelectionMenuView(context: Context) : FrameLayout(context), ReactScrollV
592
742
  }
593
743
  }
594
744
 
745
+ /** The embedded M3 field shows the selected option's label, or empty for the placeholder. */
746
+ private fun showSelectedText() {
747
+ val actv = inlineText ?: return
748
+ val label = options.firstOrNull { it.data == selectedData }?.label ?: ""
749
+ actv.setText(label, false)
750
+ // The next open lists every option until the user types again
751
+ (actv.adapter as? OptionAdapter)?.resetFilter()
752
+ }
753
+
754
+ // ---- Rich dropdown rows ----
755
+
756
+ /**
757
+ * Rows for the M3 exposed dropdown when options have icons or subtitles, or
758
+ * the field is searchable: a leading icon, the label and a second line,
759
+ * laid out like a Material list item. The selected row is highlighted like
760
+ * Material's simple items, and the list filters by the typed query (a
761
+ * case-insensitive prefix of the label or of any word in it, as
762
+ * ArrayAdapter does).
763
+ */
764
+ private inner class OptionAdapter(
765
+ private val themed: Context,
766
+ private val all: List<Option>
767
+ ) : BaseAdapter(), Filterable {
768
+ private var shown: List<Option> = all
769
+ private val showsIcons = all.any { it.icon.isPresent }
770
+ private val icons = HashMap<Int, Drawable?>()
771
+ private val density = themed.resources.displayMetrics.density
772
+
773
+ init {
774
+ // Resolve icons up front; ones that load in the background redraw the list
775
+ all.forEachIndexed { index, option ->
776
+ if (!option.icon.isPresent) return@forEachIndexed
777
+ var sync = true
778
+ PCMenuSupport.loadIcon(themed, option.icon) { drawable ->
779
+ icons[index] = drawable
780
+ if (!sync) notifyDataSetChanged()
781
+ }
782
+ sync = false
783
+ }
784
+ }
785
+
786
+ fun resetFilter() {
787
+ if (shown === all) return
788
+ shown = all
789
+ notifyDataSetChanged()
790
+ }
791
+
792
+ override fun getCount(): Int = shown.size
793
+ override fun getItem(position: Int): Option? = shown.getOrNull(position)
794
+ override fun getItemId(position: Int): Long = position.toLong()
795
+ override fun areAllItemsEnabled(): Boolean = shown.none { it.disabled }
796
+ override fun isEnabled(position: Int): Boolean = shown.getOrNull(position)?.disabled == false
797
+
798
+ override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
799
+ val option = shown[position]
800
+ val holder = (convertView?.tag as? RowHolder) ?: RowHolder()
801
+ val selected = option.data == selectedData && selectedData.isNotEmpty()
802
+
803
+ holder.icon.visibility = if (showsIcons) View.VISIBLE else View.GONE
804
+ holder.icon.setImageDrawable(icons[all.indexOf(option)])
805
+ holder.label.text = option.label
806
+ holder.subtitle.text = option.subtitle
807
+ holder.subtitle.visibility = if (option.subtitle.isEmpty()) View.GONE else View.VISIBLE
808
+ holder.root.minimumHeight = dp(if (option.subtitle.isEmpty()) 48 else 64)
809
+ holder.root.background = if (selected) selectedBackground() else itemBackground()
810
+ holder.root.isSelected = selected
811
+ holder.root.isEnabled = !option.disabled
812
+ holder.label.isEnabled = !option.disabled
813
+ holder.subtitle.isEnabled = !option.disabled
814
+ holder.root.alpha = if (option.disabled) 0.38f else 1f
815
+ return holder.root
816
+ }
817
+
818
+ private fun dp(value: Int): Int = (value * density).toInt()
819
+
820
+ private fun selectedBackground(): Drawable {
821
+ val color = MaterialColors.getColor(themed, MaterialR.attr.colorSecondaryContainer, 0)
822
+ val ripple = MaterialColors.getColor(themed, MaterialR.attr.colorOnSecondaryContainer, 0)
823
+ return RippleDrawable(
824
+ ColorStateList.valueOf(ripple and 0x1FFFFFFF),
825
+ ColorDrawable(color),
826
+ null
827
+ )
828
+ }
829
+
830
+ private fun itemBackground(): Drawable? {
831
+ val value = TypedValue()
832
+ if (!themed.theme.resolveAttribute(android.R.attr.selectableItemBackground, value, true)) return null
833
+ return themed.getDrawable(value.resourceId)
834
+ }
835
+
836
+ private fun textAppearance(attr: Int, fallback: Int): Int {
837
+ val value = TypedValue()
838
+ return if (themed.theme.resolveAttribute(attr, value, true) && value.resourceId != 0) {
839
+ value.resourceId
840
+ } else {
841
+ fallback
842
+ }
843
+ }
844
+
845
+ private inner class RowHolder {
846
+ val icon = ImageView(themed).apply {
847
+ layoutParams = LinearLayout.LayoutParams(dp(24), dp(24)).apply { marginEnd = dp(16) }
848
+ scaleType = ImageView.ScaleType.FIT_CENTER
849
+ importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO
850
+ }
851
+ val label = TextView(themed).apply {
852
+ TextViewCompat.setTextAppearance(
853
+ this,
854
+ textAppearance(MaterialR.attr.textAppearanceBodyLarge, android.R.style.TextAppearance_Material_Subhead)
855
+ )
856
+ maxLines = 1
857
+ ellipsize = TextUtils.TruncateAt.END
858
+ }
859
+ val subtitle = TextView(themed).apply {
860
+ TextViewCompat.setTextAppearance(
861
+ this,
862
+ textAppearance(MaterialR.attr.textAppearanceBodyMedium, android.R.style.TextAppearance_Material_Body1)
863
+ )
864
+ MaterialColors.getColor(themed, MaterialR.attr.colorOnSurfaceVariant, 0)
865
+ .takeIf { it != 0 }
866
+ ?.let { setTextColor(it) }
867
+ maxLines = 1
868
+ ellipsize = TextUtils.TruncateAt.END
869
+ }
870
+ val root = LinearLayout(themed).apply {
871
+ orientation = LinearLayout.HORIZONTAL
872
+ gravity = Gravity.CENTER_VERTICAL
873
+ setPaddingRelative(dp(16), dp(8), dp(16), dp(8))
874
+ layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
875
+ addView(icon)
876
+ addView(
877
+ LinearLayout(themed).apply {
878
+ orientation = LinearLayout.VERTICAL
879
+ layoutParams = LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f)
880
+ addView(label)
881
+ addView(subtitle)
882
+ }
883
+ )
884
+ tag = this@RowHolder
885
+ }
886
+ }
887
+
888
+ override fun getFilter(): Filter = object : Filter() {
889
+ override fun performFiltering(constraint: CharSequence?): FilterResults {
890
+ val query = constraint?.toString()?.trim()?.lowercase(Locale.getDefault()).orEmpty()
891
+ val matches = if (!isSearchable || query.isEmpty()) all else all.filter { matches(it.label, query) }
892
+ return FilterResults().apply {
893
+ values = matches
894
+ count = matches.size
895
+ }
896
+ }
897
+
898
+ @Suppress("UNCHECKED_CAST")
899
+ override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
900
+ shown = (results?.values as? List<Option>) ?: all
901
+ if (shown.isNotEmpty()) notifyDataSetChanged() else notifyDataSetInvalidated()
902
+ }
903
+
904
+ override fun convertResultToString(resultValue: Any?): CharSequence =
905
+ (resultValue as? Option)?.label ?: ""
906
+ }
907
+
908
+ /** ArrayAdapter's rule: the label, or one of its words, starts with the query. */
909
+ private fun matches(label: String, query: String): Boolean {
910
+ val lower = label.lowercase(Locale.getDefault())
911
+ return lower.startsWith(query) || lower.split(' ').any { it.startsWith(query) }
912
+ }
913
+ }
914
+
595
915
  // ---- Inline dropdown overlay ----
596
916
 
597
917
  private inner class InlineAutoCompleteTextView(context: Context) :
@@ -629,6 +949,8 @@ class PCSelectionMenuView(context: Context) : FrameLayout(context), ReactScrollV
629
949
  if (event.action == android.view.MotionEvent.ACTION_DOWN) {
630
950
  inlineText?.dismissDropDown()
631
951
  detachInlineDropdownOverlay()
952
+ // A tap outside also leaves a searchable field
953
+ if (isSearchable) inlineText?.clearFocus()
632
954
  }
633
955
  true
634
956
  }
@@ -695,8 +1017,8 @@ class PCSelectionMenuView(context: Context) : FrameLayout(context), ReactScrollV
695
1017
 
696
1018
  private fun handleHeadlessSelection(position: Int) {
697
1019
  val opt = options.getOrNull(position) ?: return
698
- Log.d(TAG, "handleHeadlessSelection pos=$position data=${opt.data}")
699
- selectedData = opt.data
1020
+ if (interactivity != "enabled" || opt.disabled) return
1021
+ Log.d(TAG, "handleHeadlessSelection pos=$position")
700
1022
  onSelect?.invoke(position, opt.label, opt.data)
701
1023
  }
702
1024
 
@@ -706,9 +1028,19 @@ class PCSelectionMenuView(context: Context) : FrameLayout(context), ReactScrollV
706
1028
  menu.clear()
707
1029
  val selectedIdx = options.indexOfFirst { it.data == selectedData }
708
1030
  options.forEachIndexed { index, opt ->
709
- val label = if (index == selectedIdx) "✓ ${opt.label}" else opt.label
710
- menu.add(0, index, index, label)
1031
+ val item = menu.add(HEADLESS_GROUP_ID, index, index, opt.label)
1032
+ item.isEnabled = !opt.disabled
1033
+ item.isChecked = index == selectedIdx
1034
+ // PopupMenu rows have one line, so only the icon is shown (no subtitle)
1035
+ if (opt.icon.isPresent) {
1036
+ PCMenuSupport.loadIcon(context, opt.icon) { drawable ->
1037
+ if (drawable != null && headlessMenu === popup) item.icon = drawable
1038
+ }
1039
+ }
711
1040
  }
1041
+ // Single-choice group: the menu draws a native radio indicator on each row.
1042
+ menu.setGroupCheckable(HEADLESS_GROUP_ID, true, true)
1043
+ popup.setForceShowIcon(options.any { it.icon.isPresent })
712
1044
  }
713
1045
 
714
1046
  private fun suppressInlineSpinnerCallbacks(sp: Spinner) {
@@ -13,6 +13,7 @@ import com.facebook.react.uimanager.events.Event
13
13
  import com.facebook.react.uimanager.events.RCTEventEmitter
14
14
  import com.facebook.react.viewmanagers.PCSelectionMenuManagerDelegate
15
15
  import com.facebook.react.viewmanagers.PCSelectionMenuManagerInterface
16
+ import com.platformcomponents.PCButtonSupport.stringOr
16
17
 
17
18
  class PCSelectionMenuViewManager :
18
19
  SimpleViewManager<PCSelectionMenuView>(),
@@ -49,6 +50,7 @@ class PCSelectionMenuViewManager :
49
50
  val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, view.id)
50
51
 
51
52
  view.onSelect = { index, label, data ->
53
+ PCHaptics.perform(view, view.haptics)
52
54
  dispatcher?.dispatchEvent(SelectEvent(view.id, index, label, data))
53
55
  }
54
56
 
@@ -57,15 +59,21 @@ class PCSelectionMenuViewManager :
57
59
  }
58
60
  }
59
61
 
60
- // options: array of {label,data}
62
+ // options: array of {label, data, subtitle, iconType, iconName, iconUri, iconScale, iconTinted}
61
63
  override fun setOptions(view: PCSelectionMenuView, value: ReadableArray?) {
62
64
  val out = ArrayList<PCSelectionMenuView.Option>()
63
65
  if (value != null) {
64
66
  for (i in 0 until value.size()) {
65
67
  val m = value.getMap(i) ?: continue
66
- val label = if (m.hasKey("label") && !m.isNull("label")) m.getString("label") ?: "" else ""
67
- val data = if (m.hasKey("data") && !m.isNull("data")) m.getString("data") ?: "" else ""
68
- out.add(PCSelectionMenuView.Option(label = label, data = data))
68
+ out.add(
69
+ PCSelectionMenuView.Option(
70
+ label = m.stringOr("label", ""),
71
+ data = m.stringOr("data", ""),
72
+ subtitle = m.stringOr("subtitle", ""),
73
+ disabled = m.stringOr("disabled", "false") == "true",
74
+ icon = PCButtonSupport.parseIcon(m)
75
+ )
76
+ )
69
77
  }
70
78
  }
71
79
  view.applyOptions(out)
@@ -92,10 +100,16 @@ class PCSelectionMenuViewManager :
92
100
  view.applyVisible(value)
93
101
  }
94
102
 
103
+ // "" (none added) | "none" | "selection" | "light" | "medium" | "heavy" | "success" | "warning" | "error"
104
+ override fun setHaptics(view: PCSelectionMenuView, value: String?) {
105
+ view.haptics = PCHaptics.configure(view, value)
106
+ }
107
+
95
108
  override fun setAndroid(view: PCSelectionMenuView, value: ReadableMap?) {
96
109
  val material =
97
110
  if (value != null && value.hasKey("material") && !value.isNull("material")) value.getString("material") else null
98
111
  view.applyAndroidMaterial(material)
112
+ view.applyAndroidSearchable(value?.stringOr("searchable", "false") == "true")
99
113
  }
100
114
 
101
115
  override fun setIos(view: PCSelectionMenuView, value: ReadableMap?) {