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
@@ -0,0 +1,415 @@
1
+ import UIKit
2
+
3
+ /// A rail destination, bridged from ObjC++ as a dictionary.
4
+ struct PCNavigationRailItem {
5
+ let label: String
6
+ let value: String
7
+ let disabled: Bool
8
+ let icon: PCButtonSupport.Icon
9
+ let selectedIcon: PCButtonSupport.Icon
10
+ /// "" = no badge, " " = a dot, anything else is the badge text
11
+ let badge: String
12
+ let accessibilityLabel: String
13
+ let testID: String
14
+ /// "" | "search": a search destination without an icon gets the magnifying glass
15
+ let role: String
16
+ }
17
+
18
+ /// iOS has no navigation rail (the iPad sidebar belongs to the navigation
19
+ /// controller), so this is a column of tab-style `UIButton`s: the plain
20
+ /// configuration with the image above the title, the selected one in the
21
+ /// accent color as `UITabBar` shows it, badges, and the React header above
22
+ /// them. Expanded, the image sits before the title. Selection is controlled
23
+ /// from JS; a press reports the destination and whether it was selected.
24
+ @objcMembers
25
+ public final class PCNavigationRailView: UIView {
26
+ // MARK: - Props (set from ObjC++)
27
+
28
+ /// ObjC++ sets this as an array of dictionaries; see `rebuildItems` for keys.
29
+ public var items: [Any] = [] { didSet { rebuildItems() } }
30
+
31
+ /// Controlled selection by value; "" = none.
32
+ public var selectedValue: String = "" {
33
+ didSet { if oldValue != selectedValue { applyConfigurations() } }
34
+ }
35
+
36
+ /// "auto" | "labeled" | "selected" | "unlabeled"
37
+ public var labelVisibility: String = "auto" {
38
+ didSet { if oldValue != labelVisibility { applyConfigurations(); onNeedsRemeasure?() } }
39
+ }
40
+
41
+ /// "top" | "center" | "bottom"
42
+ public var menuGravity: String = "top" {
43
+ didSet { if oldValue != menuGravity { setNeedsLayout() } }
44
+ }
45
+
46
+ /// The expanded rail: the image before the title
47
+ public var expanded: Bool = false {
48
+ didSet { if oldValue != expanded { updateExpanded() } }
49
+ }
50
+
51
+ public var activeTintColor: UIColor? { didSet { applyConfigurations() } }
52
+ public var inactiveTintColor: UIColor? { didSet { applyConfigurations() } }
53
+ public var railColor: UIColor? { didSet { backgroundColor = railColor } }
54
+ public var badgeBackgroundColor: UIColor? { didSet { updateBadges() } }
55
+ public var badgeTextColor: UIColor? { didSet { updateBadges() } }
56
+
57
+ /// Label font; nil keeps the default (caption, medium)
58
+ public var labelFont: UIFont? {
59
+ didSet { applyConfigurations(); onNeedsRemeasure?() }
60
+ }
61
+
62
+ /// The `haptics` prop; PCNavigationRail.mm plays it on a destination press
63
+ public let haptics = PCHaptics()
64
+
65
+ // MARK: - Events back to ObjC++
66
+
67
+ /// (index, value, reselected)
68
+ public var onItemPress: ((Int, String, Bool) -> Void)?
69
+
70
+ /// Called when the rail's natural width may have changed.
71
+ public var onNeedsRemeasure: (() -> Void)?
72
+
73
+ /// Where ObjC++ mounts the React header.
74
+ public let headerContainer = PCRailHeaderContainer()
75
+
76
+ // MARK: - Internal
77
+
78
+ private var railItems: [PCNavigationRailItem] = []
79
+ private var buttons: [UIButton] = []
80
+ private var badges: [UILabel] = []
81
+ private var images: [(normal: UIImage?, selected: UIImage?)] = []
82
+
83
+ /// Bumped on every rebuild so late image loads can't touch stale buttons.
84
+ private var generation = 0
85
+
86
+ private let inset: CGFloat = 8
87
+ private let topInset: CGFloat = 12
88
+ private let headerSpacing: CGFloat = 20
89
+ private let itemSpacing: CGFloat = 4
90
+
91
+ public override init(frame: CGRect) {
92
+ super.init(frame: frame)
93
+ setup()
94
+ }
95
+
96
+ public required init?(coder: NSCoder) {
97
+ super.init(coder: coder)
98
+ setup()
99
+ }
100
+
101
+ private func setup() {
102
+ addSubview(headerContainer)
103
+ headerContainer.onSizeChange = { [weak self] in
104
+ self?.setNeedsLayout()
105
+ self?.onNeedsRemeasure?()
106
+ }
107
+ }
108
+
109
+ // MARK: - Items
110
+
111
+ private func rebuildItems() {
112
+ railItems = items.compactMap { any in
113
+ guard let dict = any as? [String: Any] else { return nil }
114
+ func icon(_ prefix: String) -> PCButtonSupport.Icon {
115
+ let key = { (name: String) in prefix.isEmpty ? name : prefix + name.prefix(1).uppercased() + name.dropFirst() }
116
+ let scale = (dict[key("iconScale")] as? NSNumber).map { CGFloat(truncating: $0) } ?? 1
117
+ return PCButtonSupport.Icon(
118
+ type: (dict[key("iconType")] as? String) ?? "",
119
+ name: (dict[key("iconName")] as? String) ?? "",
120
+ uri: (dict[key("iconUri")] as? String) ?? "",
121
+ scale: scale > 0 ? scale : 1,
122
+ tinted: (dict[key("iconTinted")] as? String) != "false",
123
+ request: (dict[key("iconRequest")] as? String) ?? ""
124
+ )
125
+ }
126
+ return PCNavigationRailItem(
127
+ label: (dict["label"] as? String) ?? "",
128
+ value: (dict["value"] as? String) ?? "",
129
+ disabled: (dict["disabled"] as? String) == "disabled",
130
+ icon: icon(""),
131
+ selectedIcon: icon("selected"),
132
+ badge: (dict["badge"] as? String) ?? "",
133
+ accessibilityLabel: (dict["accessibilityLabel"] as? String) ?? "",
134
+ testID: (dict["testID"] as? String) ?? "",
135
+ role: (dict["role"] as? String) ?? ""
136
+ )
137
+ }
138
+
139
+ generation += 1
140
+ let current = generation
141
+ buttons.forEach { $0.removeFromSuperview() }
142
+ buttons = []
143
+ badges = []
144
+ images = []
145
+
146
+ for (index, item) in railItems.enumerated() {
147
+ let button = UIButton(type: .system)
148
+ button.tag = index
149
+ button.addTarget(self, action: #selector(pressed(_:)), for: .touchUpInside)
150
+ button.addTarget(self, action: #selector(touchedDown), for: .touchDown)
151
+ button.accessibilityIdentifier = item.testID.isEmpty ? nil : item.testID
152
+ let badge = UILabel()
153
+ badge.textAlignment = .center
154
+ badge.clipsToBounds = true
155
+ badge.isAccessibilityElement = false
156
+ button.addSubview(badge)
157
+ addSubview(button)
158
+ buttons.append(button)
159
+ badges.append(badge)
160
+
161
+ let icon = item.role == "search" && !item.icon.isPresent
162
+ ? PCButtonSupport.Icon(type: "sfSymbol", name: "magnifyingglass", uri: "", scale: 1, tinted: true)
163
+ : item.icon
164
+ let normal = PCButtonSupport.image(for: icon) { [weak self] image in
165
+ guard let self, self.generation == current, index < self.images.count else { return }
166
+ self.images[index].normal = image
167
+ self.applyConfigurations()
168
+ }
169
+ let selected = item.selectedIcon.isPresent
170
+ ? PCButtonSupport.image(for: item.selectedIcon) { [weak self] image in
171
+ guard let self, self.generation == current, index < self.images.count else { return }
172
+ self.images[index].selected = image
173
+ self.applyConfigurations()
174
+ }
175
+ : nil
176
+ images.append((normal, selected))
177
+ }
178
+ applyConfigurations()
179
+ updateBadges()
180
+ onNeedsRemeasure?()
181
+ }
182
+
183
+ /// Readies the haptic for the press that is likely to follow.
184
+ @objc private func touchedDown() {
185
+ haptics.prepare(in: self)
186
+ }
187
+
188
+ @objc private func pressed(_ sender: UIButton) {
189
+ let index = sender.tag
190
+ guard index >= 0, index < railItems.count else { return }
191
+ let value = railItems[index].value
192
+ onItemPress?(index, value, value == selectedValue)
193
+ }
194
+
195
+ // MARK: - Appearance
196
+
197
+ private var defaultLabelFont: UIFont {
198
+ let style: UIFont.TextStyle = expanded ? .subheadline : .caption1
199
+ let base = UIFont.systemFont(ofSize: UIFont.preferredFont(forTextStyle: style).pointSize, weight: .medium)
200
+ return base
201
+ }
202
+
203
+ /// The symbol configuration of a destination's image.
204
+ private func symbolConfiguration(selected: Bool) -> UIImage.SymbolConfiguration {
205
+ UIImage.SymbolConfiguration(pointSize: expanded ? 18 : 20, weight: selected ? .semibold : .regular)
206
+ }
207
+
208
+ /// The image a destination shows in its current state.
209
+ private func image(for index: Int) -> UIImage? {
210
+ let isSelected = railItems[index].value == selectedValue
211
+ return isSelected ? (images[index].selected ?? images[index].normal) : images[index].normal
212
+ }
213
+
214
+ /// Expanded, the titles line up: each image gets the padding that makes
215
+ /// up the difference to the widest one.
216
+ private var widestImage: CGFloat {
217
+ buttons.indices.compactMap { index -> CGFloat? in
218
+ guard index < railItems.count, let shown = image(for: index) else { return nil }
219
+ let selected = railItems[index].value == selectedValue
220
+ return (shown.applyingSymbolConfiguration(symbolConfiguration(selected: selected)) ?? shown).size.width
221
+ }.max() ?? 0
222
+ }
223
+
224
+ private func applyConfigurations() {
225
+ let widest = expanded ? widestImage : 0
226
+ for (index, button) in buttons.enumerated() where index < railItems.count {
227
+ button.configuration = configuration(for: index, widestImage: widest)
228
+ let item = railItems[index]
229
+ button.isEnabled = !item.disabled
230
+ let isSelected = item.value == selectedValue
231
+ button.accessibilityTraits = isSelected ? [.button, .selected] : .button
232
+ let spoken = item.accessibilityLabel.isEmpty ? item.label : item.accessibilityLabel
233
+ button.accessibilityLabel = item.badge.isEmpty || item.badge == " " ? spoken : "\(spoken), \(item.badge)"
234
+ }
235
+ setNeedsLayout()
236
+ }
237
+
238
+ private func configuration(for index: Int, widestImage: CGFloat) -> UIButton.Configuration {
239
+ let item = railItems[index]
240
+ let isSelected = item.value == selectedValue
241
+ var config = UIButton.Configuration.plain()
242
+ let shown = image(for: index)
243
+ let symbols = symbolConfiguration(selected: isSelected)
244
+ config.image = shown
245
+ config.preferredSymbolConfigurationForImage = symbols
246
+ let showsLabel = labelVisibility != "unlabeled" && (labelVisibility != "selected" || isSelected)
247
+ config.title = showsLabel ? item.label : nil
248
+ config.imagePlacement = expanded ? .leading : .top
249
+ if showsLabel, let shown {
250
+ let width = (shown.applyingSymbolConfiguration(symbols) ?? shown).size.width
251
+ config.imagePadding = expanded ? 12 + max(0, widestImage - width) : 4
252
+ } else {
253
+ config.imagePadding = 0
254
+ }
255
+ config.titleAlignment = expanded ? .leading : .center
256
+ config.titleLineBreakMode = .byTruncatingTail
257
+ config.contentInsets = expanded
258
+ ? NSDirectionalEdgeInsets(top: 12, leading: 12, bottom: 12, trailing: 12)
259
+ : NSDirectionalEdgeInsets(top: 8, leading: 4, bottom: 8, trailing: 4)
260
+ // The selected destination takes the accent color, as UITabBar shows it
261
+ config.baseForegroundColor = isSelected
262
+ ? (activeTintColor ?? tintColor)
263
+ : (inactiveTintColor ?? .secondaryLabel)
264
+ let font = labelFont ?? defaultLabelFont
265
+ config.titleTextAttributesTransformer = UIConfigurationTextAttributesTransformer { incoming in
266
+ var outgoing = incoming
267
+ outgoing.font = font
268
+ return outgoing
269
+ }
270
+ return config
271
+ }
272
+
273
+ public override func tintColorDidChange() {
274
+ super.tintColorDidChange()
275
+ applyConfigurations()
276
+ }
277
+
278
+ public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
279
+ super.traitCollectionDidChange(previousTraitCollection)
280
+ guard previousTraitCollection?.preferredContentSizeCategory != traitCollection.preferredContentSizeCategory
281
+ else { return }
282
+ applyConfigurations()
283
+ onNeedsRemeasure?()
284
+ }
285
+
286
+ /// Badges in the system's badge colors: a count or text in a red capsule, or a dot.
287
+ private func updateBadges() {
288
+ for (index, badge) in badges.enumerated() where index < railItems.count {
289
+ let text = railItems[index].badge
290
+ badge.isHidden = text.isEmpty
291
+ badge.text = text == " " ? nil : text
292
+ badge.font = UIFont.systemFont(ofSize: 12, weight: .semibold)
293
+ badge.textColor = badgeTextColor ?? .white
294
+ badge.backgroundColor = badgeBackgroundColor ?? .systemRed
295
+ }
296
+ setNeedsLayout()
297
+ }
298
+
299
+ private func updateExpanded() {
300
+ onNeedsRemeasure?()
301
+ guard window != nil else {
302
+ applyConfigurations()
303
+ return
304
+ }
305
+ UIView.animate(withDuration: 0.3, delay: 0, options: [.beginFromCurrentState, .curveEaseInOut]) {
306
+ self.applyConfigurations()
307
+ self.layoutIfNeeded()
308
+ }
309
+ }
310
+
311
+ // MARK: - Sizing
312
+
313
+ private func fittedSize(_ button: UIButton) -> CGSize {
314
+ let size = button.sizeThatFits(CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude))
315
+ return CGSize(width: ceil(size.width), height: ceil(size.height))
316
+ }
317
+
318
+ /// The width the rail wants: its widest destination or header, and at
319
+ /// least 80pt (200pt expanded).
320
+ @objc public func naturalWidth() -> CGFloat {
321
+ let buttonWidth = buttons.map { fittedSize($0).width }.max() ?? 0
322
+ let headerWidth = headerContainer.contentSize.width
323
+ let minimum: CGFloat = expanded ? 200 : 80
324
+ return ceil(max(minimum, buttonWidth + inset * 2, headerWidth + inset * 2))
325
+ }
326
+
327
+ public override func layoutSubviews() {
328
+ super.layoutSubviews()
329
+ let headerSize = headerContainer.contentSize
330
+ let hasHeader = headerSize.width > 0 && headerSize.height > 0
331
+ // Centered over the destinations, at their leading edge when expanded
332
+ let headerX = expanded
333
+ ? (effectiveUserInterfaceLayoutDirection == .rightToLeft
334
+ ? bounds.width - inset - 4 - headerSize.width
335
+ : inset + 4)
336
+ : (bounds.width - headerSize.width) / 2
337
+ headerContainer.frame = CGRect(
338
+ x: headerX,
339
+ y: topInset,
340
+ width: headerSize.width,
341
+ height: headerSize.height
342
+ )
343
+ let regionTop = hasHeader ? headerContainer.frame.maxY + headerSpacing : topInset
344
+ let regionBottom = bounds.height - topInset
345
+
346
+ let buttonWidth = bounds.width - inset * 2
347
+ let heights = buttons.map { max(expanded ? 44 : 56, fittedSize($0).height) }
348
+ let total = heights.reduce(0, +) + itemSpacing * CGFloat(max(0, buttons.count - 1))
349
+ // As the Material rail does it: placed in the rail's height, and
350
+ // never above the header
351
+ var y: CGFloat
352
+ switch menuGravity {
353
+ case "center": y = max(regionTop, (bounds.height - total) / 2)
354
+ case "bottom": y = max(regionTop, regionBottom - total)
355
+ default: y = regionTop
356
+ }
357
+ for (index, button) in buttons.enumerated() {
358
+ button.frame = CGRect(x: inset, y: y, width: buttonWidth, height: heights[index])
359
+ button.contentHorizontalAlignment = expanded ? .leading : .center
360
+ y += heights[index] + itemSpacing
361
+ layoutBadge(index)
362
+ }
363
+ }
364
+
365
+ /// The badge at the image's top trailing corner.
366
+ private func layoutBadge(_ index: Int) {
367
+ let badge = badges[index]
368
+ guard !badge.isHidden else { return }
369
+ let button = buttons[index]
370
+ button.layoutIfNeeded()
371
+ let dot = badge.text == nil
372
+ let height: CGFloat = dot ? 8 : 18
373
+ let width = dot ? 8 : max(18, ceil(badge.intrinsicContentSize.width) + 10)
374
+ badge.layer.cornerRadius = height / 2
375
+ let imageFrame = button.imageView.map { button.convert($0.bounds, from: $0) } ?? .zero
376
+ let anchorX = imageFrame.maxX
377
+ let anchorY = imageFrame.minY
378
+ badge.frame = CGRect(
379
+ x: anchorX - (dot ? 4 : 8),
380
+ y: anchorY - (dot ? 2 : 6),
381
+ width: width,
382
+ height: height
383
+ )
384
+ button.bringSubviewToFront(badge)
385
+ }
386
+ }
387
+
388
+ /// Holds the React header, reporting when React resizes it.
389
+ @objcMembers
390
+ public final class PCRailHeaderContainer: UIView {
391
+ var onSizeChange: (() -> Void)?
392
+ private var observations: [ObjectIdentifier: NSKeyValueObservation] = [:]
393
+
394
+ /// The header's size, as React laid it out.
395
+ var contentSize: CGSize {
396
+ subviews.reduce(CGSize.zero) { size, view in
397
+ CGSize(width: max(size.width, view.frame.maxX), height: max(size.height, view.frame.maxY))
398
+ }
399
+ }
400
+
401
+ public override func didAddSubview(_ subview: UIView) {
402
+ super.didAddSubview(subview)
403
+ observations[ObjectIdentifier(subview)] = subview.layer.observe(\.bounds, options: [.old, .new]) { [weak self] _, change in
404
+ guard change.oldValue?.size != change.newValue?.size else { return }
405
+ DispatchQueue.main.async { self?.onSizeChange?() }
406
+ }
407
+ onSizeChange?()
408
+ }
409
+
410
+ public override func willRemoveSubview(_ subview: UIView) {
411
+ super.willRemoveSubview(subview)
412
+ observations.removeValue(forKey: ObjectIdentifier(subview))?.invalidate()
413
+ DispatchQueue.main.async { [weak self] in self?.onSizeChange?() }
414
+ }
415
+ }
@@ -35,11 +35,12 @@ static inline bool SegmentsEqual(
35
35
  if (a[i].disabled != b[i].disabled) return false;
36
36
  if (a[i].iconType != b[i].iconType) return false;
37
37
  if (a[i].iconName != b[i].iconName) return false;
38
- if (a[i].iconUri != b[i].iconUri) return false;
38
+ if (a[i].iconRequest != b[i].iconRequest || a[i].iconUri != b[i].iconUri) return false;
39
39
  if (a[i].iconScale != b[i].iconScale) return false;
40
40
  if (a[i].iconTinted != b[i].iconTinted) return false;
41
41
  if (a[i].badge != b[i].badge) return false;
42
42
  if (a[i].accessibilityLabel != b[i].accessibilityLabel) return false;
43
+ if (a[i].testID != b[i].testID) return false;
43
44
  }
44
45
  return true;
45
46
  }
@@ -93,6 +94,12 @@ static UIFont *FontFromLabelStyle(
93
94
 
94
95
  - (instancetype)initWithFrame:(CGRect)frame {
95
96
  if (self = [super initWithFrame:frame]) {
97
+ // Fabric views seed _props with their own defaults: RCTViewComponentView
98
+ // asserts on it in debug builds of React Native core, and the first
99
+ // updateProps would otherwise read the base ViewProps as PCSegmentedControlProps.
100
+ static const auto defaultProps = std::make_shared<const PCSegmentedControlProps>();
101
+ _props = defaultProps;
102
+
96
103
  _view = [PCSegmentedControlView new];
97
104
  self.contentView = _view;
98
105
 
@@ -102,6 +109,8 @@ static UIFont *FontFromLabelStyle(
102
109
  __typeof(self) strongSelf = weakSelf;
103
110
  if (!strongSelf) return;
104
111
 
112
+ [strongSelf->_view.haptics performIn:strongSelf->_view];
113
+
105
114
  auto eventEmitter =
106
115
  std::static_pointer_cast<const PCSegmentedControlEventEmitter>(
107
116
  strongSelf->_eventEmitter);
@@ -132,7 +141,7 @@ static UIFont *FontFromLabelStyle(
132
141
  std::static_pointer_cast<const PCSegmentedControlProps>(oldProps);
133
142
 
134
143
  // segments: [{label, value, disabled, iconType, iconName, iconUri, iconScale,
135
- // iconTinted, accessibilityLabel}]
144
+ // iconTinted, accessibilityLabel, testID}]
136
145
  if (!prevProps || !SegmentsEqual(newProps.segments, prevProps->segments)) {
137
146
  NSMutableArray *arr = [NSMutableArray new];
138
147
  for (const auto &seg : newProps.segments) {
@@ -142,11 +151,13 @@ static UIFont *FontFromLabelStyle(
142
151
  @"disabled": NSStringFromStd(seg.disabled, @"enabled"),
143
152
  @"iconType": NSStringFromStd(seg.iconType, @""),
144
153
  @"iconName": NSStringFromStd(seg.iconName, @""),
154
+ @"iconRequest": NSStringFromStd(seg.iconRequest, @""),
145
155
  @"iconUri": NSStringFromStd(seg.iconUri, @""),
146
156
  @"iconScale": @(seg.iconScale),
147
157
  @"iconTinted": NSStringFromStd(seg.iconTinted, @"true"),
148
158
  @"badge": NSStringFromStd(seg.badge, @""),
149
159
  @"accessibilityLabel": NSStringFromStd(seg.accessibilityLabel, @""),
160
+ @"testID": NSStringFromStd(seg.testID, @""),
150
161
  }];
151
162
  }
152
163
  _view.segments = arr;
@@ -208,6 +219,10 @@ static UIFont *FontFromLabelStyle(
208
219
  _view.labelFont = FontFromLabelStyle(newProps.labelStyle);
209
220
  }
210
221
 
222
+ if (!prevProps || newProps.haptics != prevProps->haptics) {
223
+ _view.haptics.kind = NSStringFromStd(newProps.haptics, @"");
224
+ }
225
+
211
226
  if (!prevProps || newProps.badgeBackgroundColor != prevProps->badgeBackgroundColor) {
212
227
  _view.badgeBackgroundColor = RCTUIColorFromSharedColor(newProps.badgeBackgroundColor);
213
228
  }
@@ -9,11 +9,13 @@ struct PCSegmentedControlSegment {
9
9
  /// "", "sfSymbol", "drawable" (ignored on iOS) or "image"
10
10
  let iconType: String
11
11
  let iconName: String
12
+ let iconRequest: String
12
13
  let iconUri: String
13
14
  let iconScale: CGFloat
14
15
  let iconTinted: Bool
15
16
  let badge: String
16
17
  let accessibilityLabel: String
18
+ let testID: String
17
19
 
18
20
  var hasIcon: Bool { iconType == "sfSymbol" || iconType == "image" }
19
21
 
@@ -102,6 +104,9 @@ public final class PCSegmentedControlView: UIControl {
102
104
  /// Badge text color; nil = white
103
105
  public var badgeTextColor: UIColor? { didSet { updateBadgeColors() } }
104
106
 
107
+ /// The `haptics` prop; PCSegmentedControl.mm plays it on a user selection
108
+ public let haptics = PCHaptics()
109
+
105
110
  // MARK: - Events back to ObjC++
106
111
 
107
112
  public var onSelect: ((Int, String) -> Void)? // (index, value)
@@ -157,6 +162,11 @@ public final class PCSegmentedControlView: UIControl {
157
162
 
158
163
  let segment = parsedSegments[index]
159
164
  onSelect?(index, segment.value)
165
+ if !momentary {
166
+ // UIKit selects immediately; restore the controlled value if
167
+ // the parent keeps its previous selection.
168
+ DispatchQueue.main.async { [weak self] in self?.updateSelection() }
169
+ }
160
170
  }
161
171
 
162
172
  // MARK: - Props handling
@@ -171,11 +181,13 @@ public final class PCSegmentedControlView: UIControl {
171
181
  disabled: (dict["disabled"] as? String) == "disabled",
172
182
  iconType: (dict["iconType"] as? String) ?? "",
173
183
  iconName: (dict["iconName"] as? String) ?? "",
184
+ iconRequest: (dict["iconRequest"] as? String) ?? "",
174
185
  iconUri: (dict["iconUri"] as? String) ?? "",
175
186
  iconScale: scale > 0 ? scale : 1,
176
187
  iconTinted: (dict["iconTinted"] as? String) != "false",
177
188
  badge: (dict["badge"] as? String) ?? "",
178
- accessibilityLabel: (dict["accessibilityLabel"] as? String) ?? ""
189
+ accessibilityLabel: (dict["accessibilityLabel"] as? String) ?? "",
190
+ testID: (dict["testID"] as? String) ?? ""
179
191
  )
180
192
  }
181
193
 
@@ -197,6 +209,7 @@ public final class PCSegmentedControlView: UIControl {
197
209
  rebuildBadges()
198
210
  updateSelection()
199
211
  invalidateIntrinsicContentSize()
212
+ setNeedsLayout()
200
213
  }
201
214
 
202
215
  // MARK: - Badges
@@ -231,11 +244,9 @@ public final class PCSegmentedControlView: UIControl {
231
244
  let count = control.numberOfSegments
232
245
  guard count > 0 else { return [] }
233
246
 
234
- let segmentViews = control.subviews
235
- .filter { NSStringFromClass(type(of: $0)) == "UISegment" }
236
- .sorted { $0.frame.minX < $1.frame.minX }
247
+ let segmentViews = self.segmentViews()
237
248
  if segmentViews.count == count {
238
- return segmentViews.map { $0.frame }
249
+ return segmentViews.map { control.convert($0.bounds, from: $0) }
239
250
  }
240
251
 
241
252
  let width = control.bounds.width / CGFloat(count)
@@ -244,6 +255,44 @@ public final class PCSegmentedControlView: UIControl {
244
255
  }
245
256
  }
246
257
 
258
+ /// The control's segment views in index order (right to left in RTL).
259
+ private func segmentViews() -> [UIView] {
260
+ // Direct subviews before iOS 26; inside a container view on iOS 26
261
+ var found: [UIView] = []
262
+ func collect(_ view: UIView) {
263
+ for sub in view.subviews {
264
+ if NSStringFromClass(type(of: sub)) == "UISegment" {
265
+ found.append(sub)
266
+ } else {
267
+ collect(sub)
268
+ }
269
+ }
270
+ }
271
+ collect(control)
272
+ let views = found.sorted {
273
+ control.convert($0.bounds, from: $0).minX < control.convert($1.bounds, from: $1).minX
274
+ }
275
+ return control.effectiveUserInterfaceLayoutDirection == .rightToLeft ? views.reversed() : views
276
+ }
277
+
278
+ /// Puts each segment's testID on the segment's title label or image view.
279
+ /// A UISegment hands its hit-tests to the control, so E2E drivers (Detox)
280
+ /// reject a tap on the segment itself as not hittable; its content view
281
+ /// passes. The views exist once laid out, and are replaced when a
282
+ /// segment's title or image changes.
283
+ private func applySegmentTestIDs() {
284
+ guard parsedSegments.contains(where: { !$0.testID.isEmpty }) else { return }
285
+ control.layoutIfNeeded()
286
+ let views = segmentViews()
287
+ guard views.count == parsedSegments.count else { return }
288
+ for (view, segment) in zip(views, parsedSegments) {
289
+ let content = view.subviews.first {
290
+ ($0 is UILabel || $0 is UIImageView) && !$0.isHidden
291
+ } ?? view
292
+ content.accessibilityIdentifier = segment.testID.isEmpty ? nil : segment.testID
293
+ }
294
+ }
295
+
247
296
  private func layoutBadges() {
248
297
  guard !badgeLabels.isEmpty else { return }
249
298
  control.layoutIfNeeded()
@@ -269,6 +318,7 @@ public final class PCSegmentedControlView: UIControl {
269
318
  public override func layoutSubviews() {
270
319
  super.layoutSubviews()
271
320
  layoutBadges()
321
+ applySegmentTestIDs()
272
322
  }
273
323
 
274
324
  /// Resolves the image shown for a segment, or nil when the segment shows
@@ -282,10 +332,10 @@ public final class PCSegmentedControlView: UIControl {
282
332
 
283
333
  switch segment.iconType {
284
334
  case "sfSymbol":
285
- return UIImage(systemName: segment.iconName).map { decorate($0, for: segment) }
335
+ return PCImageLoader.symbol(named: segment.iconName).map { decorate($0, for: segment) }
286
336
 
287
337
  case "image":
288
- let cached = PCImageLoader.shared.image(uri: segment.iconUri, scale: segment.iconScale) { [weak self] image in
338
+ let cached = PCImageLoader.shared.image(uri: segment.iconUri, scale: segment.iconScale, request: segment.iconRequest) { [weak self] image in
289
339
  guard let self, let image,
290
340
  self.rebuildGeneration == generation,
291
341
  let index = self.parsedSegments.firstIndex(where: { $0.value == segment.value }),