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
@@ -3,9 +3,9 @@ package com.platformcomponents
3
3
  import android.app.Activity
4
4
  import android.content.Context
5
5
  import android.content.ContextWrapper
6
- import android.content.DialogInterface
7
- import android.os.Build
6
+ import android.content.res.Configuration
8
7
  import android.util.Log
8
+ import android.view.ContextThemeWrapper
9
9
  import android.view.Gravity
10
10
  import android.view.View
11
11
  import android.view.ViewGroup
@@ -15,6 +15,7 @@ import android.widget.FrameLayout
15
15
  import android.widget.LinearLayout
16
16
  import android.widget.TimePicker
17
17
  import androidx.appcompat.app.AlertDialog
18
+ import androidx.fragment.app.DialogFragment
18
19
  import androidx.fragment.app.FragmentActivity
19
20
  import com.facebook.react.bridge.WritableNativeMap
20
21
  import com.facebook.react.uimanager.PixelUtil
@@ -22,9 +23,14 @@ import com.facebook.react.uimanager.StateWrapper
22
23
  import com.facebook.react.uimanager.ThemedReactContext
23
24
  import com.facebook.react.views.scroll.ReactScrollViewHelper
24
25
  import com.google.android.material.datepicker.CalendarConstraints
26
+ import com.google.android.material.datepicker.CompositeDateValidator
27
+ import com.google.android.material.datepicker.DateValidatorPointBackward
28
+ import com.google.android.material.datepicker.DateValidatorPointForward
25
29
  import com.google.android.material.datepicker.MaterialDatePicker
26
30
  import com.google.android.material.timepicker.MaterialTimePicker
27
31
  import com.google.android.material.timepicker.TimeFormat
32
+ import java.text.DateFormat
33
+ import java.text.SimpleDateFormat
28
34
  import java.util.Calendar
29
35
  import java.util.Locale
30
36
  import java.util.TimeZone
@@ -35,6 +41,7 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
35
41
 
36
42
  companion object {
37
43
  private const val TAG = "PCDatePicker"
44
+ private val UTC: TimeZone = TimeZone.getTimeZone("UTC")
38
45
  }
39
46
 
40
47
  // --- State Wrapper for Fabric state updates ---
@@ -42,17 +49,20 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
42
49
 
43
50
  private var lastReportedWidth: Float = 0f
44
51
  private var lastReportedHeight: Float = 0f
52
+ private var inlineContentHeight = 0
45
53
 
46
54
  // --- Public props (set by manager) ---
47
- private var mode: String = "date" // "date" | "time" | "dateAndTime"
55
+ private var mode: String = "date" // "date" | "time" | "dateAndTime" | "dateRange"
48
56
  private var presentation: String = "modal" // "inline" | "modal" | "popover" | "sheet" | "auto" (we treat non-inline as modal-ish)
49
57
  private var visible: String = "closed" // "open" | "closed" (only for non-inline)
50
58
  private var locale: Locale? = null
51
59
  private var timeZone: TimeZone = TimeZone.getDefault()
52
60
 
53
61
  private var dateMs: Long? = null
62
+ private var endDateMs: Long? = null // dateRange: the last day
54
63
  private var minDateMs: Long? = null
55
64
  private var maxDateMs: Long? = null
65
+ private var hourFormat: String = "" // "" (device setting) | "12" | "24"
56
66
 
57
67
  // --- Android config from nested `android` prop ---
58
68
  private var androidFirstDayOfWeek: Int? = null
@@ -60,9 +70,12 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
60
70
  private var androidDialogTitle: String? = null
61
71
  private var androidPositiveTitle: String? = null
62
72
  private var androidNegativeTitle: String? = null
73
+ private var androidInputMode: String = "" // "" | "calendar" | "text"
63
74
 
64
75
  // --- Events (wired by manager) ---
65
76
  var onConfirm: ((Long) -> Unit)? = null
77
+ /** dateRange: the first and last day. */
78
+ var onConfirmRange: ((Long, Long) -> Unit)? = null
66
79
  var onCancel: (() -> Unit)? = null
67
80
 
68
81
  // --- Inline UI ---
@@ -73,6 +86,9 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
73
86
 
74
87
  // --- Modal state ---
75
88
  private var showingModal = false
89
+ private var modalGeneration = 0
90
+ private var systemDialog: AlertDialog? = null
91
+ private var materialDialog: DialogFragment? = null
76
92
 
77
93
  // --- Native theme ---
78
94
  // Widgets read theme colors when they are created, so they are rebuilt when the
@@ -90,7 +106,12 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
90
106
  setMeasuredDimension(0, 0)
91
107
  return
92
108
  }
93
- super.onMeasure(widthMeasureSpec, heightMeasureSpec)
109
+ // Measure the picker's intrinsic height before layout. Measuring again in
110
+ // onLayout leaves NumberPicker's centered text awaiting another layout,
111
+ // so its selected day/year can stay outside the visible text area.
112
+ super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED))
113
+ inlineContentHeight = inlineContainer?.measuredHeight ?: 0
114
+ setMeasuredDimension(measuredWidth, resolveSize(measuredHeight, heightMeasureSpec))
94
115
  }
95
116
 
96
117
  override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
@@ -107,15 +128,9 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
107
128
  private fun updateFrameSizeState() {
108
129
  val wrapper = stateWrapper ?: return
109
130
 
110
- // Measure the inline container's preferred height
111
- inlineContainer?.let { container ->
112
- container.measure(
113
- MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
114
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
115
- )
116
-
131
+ inlineContainer?.let {
117
132
  val widthDp = PixelUtil.toDIPFromPixel(width.toFloat())
118
- val heightDp = PixelUtil.toDIPFromPixel(container.measuredHeight.toFloat())
133
+ val heightDp = PixelUtil.toDIPFromPixel(inlineContentHeight.toFloat())
119
134
 
120
135
  // Only update state if the size actually changed (avoid infinite loops)
121
136
  if (widthDp != lastReportedWidth || heightDp != lastReportedHeight) {
@@ -139,7 +154,8 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
139
154
 
140
155
  fun applyMode(value: String?) {
141
156
  mode = when (value) {
142
- "date", "time", "dateAndTime" -> value
157
+ "date", "time", "dateAndTime", "dateRange" -> value
158
+ // UIDatePicker's month and year wheels have no Android counterpart
143
159
  else -> "date"
144
160
  }
145
161
  Log.d(TAG, "applyMode mode=$mode")
@@ -148,8 +164,8 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
148
164
 
149
165
  fun applyPresentation(value: String?) {
150
166
  presentation = value ?: "modal"
167
+ if (isInline()) dismissIfNeeded()
151
168
  rebuildUI()
152
- // If we were showing and presentation changed, we’ll let JS drive visible again.
153
169
  }
154
170
 
155
171
  fun applyVisible(value: String?) {
@@ -164,13 +180,15 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
164
180
  }
165
181
 
166
182
  fun applyLocale(value: String?) {
183
+ val previous = locale
167
184
  locale =
168
185
  try {
169
186
  if (value.isNullOrBlank()) null else Locale.forLanguageTag(value)
170
187
  } catch (_: Throwable) {
171
188
  null
172
189
  }
173
- // Inline pickers don’t render strings; no-op other than storing.
190
+ // The embedded pickers are built from a locale-wrapped context.
191
+ if (isInline() && locale != previous) rebuildUI()
174
192
  }
175
193
 
176
194
  fun applyTimeZoneName(value: String?) {
@@ -189,6 +207,17 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
189
207
  syncInlineFromState()
190
208
  }
191
209
 
210
+ fun applyEndDateMs(value: Long?) {
211
+ endDateMs = value
212
+ }
213
+
214
+ fun applyHourFormat(value: String?) {
215
+ val next = if (value == "12" || value == "24") value else ""
216
+ if (hourFormat == next) return
217
+ hourFormat = next
218
+ inlineTimePicker?.setIs24HourView(is24Hour(context))
219
+ }
220
+
192
221
  fun applyMinDateMs(value: Long?) {
193
222
  minDateMs = value
194
223
  // clamp if needed
@@ -214,9 +243,11 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
214
243
  material: String?,
215
244
  dialogTitle: String?,
216
245
  positiveButtonTitle: String?,
217
- negativeButtonTitle: String?
246
+ negativeButtonTitle: String?,
247
+ inputMode: String?
218
248
  ) {
219
249
  androidFirstDayOfWeek = firstDayOfWeek
250
+ androidInputMode = if (inputMode == "calendar" || inputMode == "text") inputMode else ""
220
251
 
221
252
  androidMaterialMode = when (material) {
222
253
  "m3" -> PCMaterialMode.M3
@@ -228,7 +259,7 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
228
259
  androidPositiveTitle = positiveButtonTitle
229
260
  androidNegativeTitle = negativeButtonTitle
230
261
 
231
- // Inline date picker can use firstDayOfWeek in its internal Calendar calculations
262
+ inlineDatePicker?.let { applyFirstDayOfWeek(it) }
232
263
  syncInlineFromState()
233
264
  }
234
265
 
@@ -241,6 +272,7 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
241
272
 
242
273
  override fun onDetachedFromWindow() {
243
274
  PCNativeTheme.removeListener(nativeThemeListener)
275
+ dismissIfNeeded(notifyClosed = false)
244
276
  super.onDetachedFromWindow()
245
277
  }
246
278
 
@@ -277,6 +309,7 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
277
309
  return
278
310
  }
279
311
 
312
+ val pickerContext = localizedContext(context)
280
313
  val container = LinearLayout(context).apply {
281
314
  layoutParams = FrameLayout.LayoutParams(
282
315
  ViewGroup.LayoutParams.MATCH_PARENT,
@@ -288,20 +321,17 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
288
321
 
289
322
  // date and/or time
290
323
  if (mode == "date" || mode == "dateAndTime") {
291
- val dp = DatePicker(context).apply {
324
+ // DatePicker chooses its delegate in the constructor; the visibility
325
+ // setters cannot change a calendar delegate into spinner mode.
326
+ // https://developer.android.com/reference/android/widget/DatePicker#attr_android:datePickerMode
327
+ val dp = DatePicker(ContextThemeWrapper(pickerContext, R.style.PCInlineDatePickerThemeOverlay)).apply {
328
+ applyFirstDayOfWeek(this)
292
329
  layoutParams = LinearLayout.LayoutParams(
293
330
  ViewGroup.LayoutParams.WRAP_CONTENT,
294
331
  ViewGroup.LayoutParams.WRAP_CONTENT
295
332
  )
296
- // Use spinner mode to avoid CalendarView rendering bugs when scrolling months
297
- calendarViewShown = false
298
- spinnersShown = true
299
- // Defer min/max date setting to avoid CalendarView initialization race condition
300
- // where SimpleMonthView may not be fully detached yet during layout
301
- post {
302
- minDateMs?.let { minDate = it }
303
- maxDateMs?.let { maxDate = it }
304
- }
333
+ minDateMs?.let { minDate = it }
334
+ maxDateMs?.let { maxDate = it }
305
335
  }
306
336
  container.addView(dp)
307
337
  inlineDatePicker = dp
@@ -313,13 +343,12 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
313
343
  }
314
344
 
315
345
  if (mode == "time" || mode == "dateAndTime") {
316
- val tp = TimePicker(context).apply {
346
+ val tp = TimePicker(pickerContext).apply {
317
347
  layoutParams = LinearLayout.LayoutParams(
318
348
  ViewGroup.LayoutParams.WRAP_CONTENT,
319
349
  ViewGroup.LayoutParams.WRAP_CONTENT
320
350
  )
321
- val is24 = android.text.format.DateFormat.is24HourFormat(context)
322
- setIs24HourView(is24)
351
+ setIs24HourView(is24Hour(context))
323
352
  }
324
353
  container.addView(tp)
325
354
  inlineTimePicker = tp
@@ -366,15 +395,8 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
366
395
  inlineTimePicker?.let { tp ->
367
396
  val hour = cal.get(Calendar.HOUR_OF_DAY)
368
397
  val minute = cal.get(Calendar.MINUTE)
369
- if (Build.VERSION.SDK_INT >= 23) {
370
- if (tp.hour != hour) tp.hour = hour
371
- if (tp.minute != minute) tp.minute = minute
372
- } else {
373
- @Suppress("DEPRECATION")
374
- if (tp.currentHour != hour) tp.currentHour = hour
375
- @Suppress("DEPRECATION")
376
- if (tp.currentMinute != minute) tp.currentMinute = minute
377
- }
398
+ if (tp.hour != hour) tp.hour = hour
399
+ if (tp.minute != minute) tp.minute = minute
378
400
  }
379
401
  } finally {
380
402
  suppressInlineCallbacks = false
@@ -420,17 +442,23 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
420
442
  private fun presentIfNeeded() {
421
443
  if (showingModal) return
422
444
  showingModal = true
445
+ val generation = ++modalGeneration
423
446
 
424
447
  // Defer presentation to the next frame to ensure all props from the current
425
448
  // React Native batch are applied first. This guarantees dateMs reflects the
426
449
  // latest value from React Native before we create the dialog.
427
450
  post {
428
- if (!showingModal) return@post
451
+ if (!showingModal || generation != modalGeneration) return@post
429
452
 
430
453
  val act = findFragmentActivity() ?: run {
431
454
  Log.w(TAG, "presentIfNeeded: no FragmentActivity found")
432
- onCancel?.invoke()
433
- showingModal = false
455
+ dismissIfNeeded()
456
+ return@post
457
+ }
458
+ if (!isAttachedToWindow || act.isFinishing || act.isDestroyed ||
459
+ act.supportFragmentManager.isStateSaved
460
+ ) {
461
+ dismissIfNeeded()
434
462
  return@post
435
463
  }
436
464
 
@@ -439,15 +467,36 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
439
467
  when (mode) {
440
468
  "time" -> presentTime(act)
441
469
  "dateAndTime" -> presentDateThenTime(act)
470
+ // Only Material has a range picker
471
+ "dateRange" -> presentM3DateRange(act)
442
472
  else -> presentDate(act)
443
473
  }
444
474
  }
445
475
  }
446
476
 
447
- private fun dismissIfNeeded() {
448
- // We don’t retain dialog instances here; JS will close by dismissing itself or user action.
449
- // This keeps parity with Fabric headless patterns.
450
- showingModal = false
477
+ private fun dismissIfNeeded(notifyClosed: Boolean = true) {
478
+ val wasShowing = showingModal
479
+ val system = systemDialog
480
+ val material = materialDialog
481
+ // Clear ownership before dismissal: its listeners may run synchronously.
482
+ modalGeneration += 1
483
+ onCancelOrClose()
484
+ system?.dismiss()
485
+ // A React view can detach after the activity saved its fragment state.
486
+ // https://developer.android.com/reference/androidx/fragment/app/DialogFragment#dismissAllowingStateLoss()
487
+ material?.dismissAllowingStateLoss()
488
+ if (wasShowing && notifyClosed) onCancel?.invoke()
489
+ }
490
+
491
+ private fun showSystemDialog(dialog: AlertDialog) {
492
+ systemDialog = dialog
493
+ dialog.setOnDismissListener {
494
+ if (systemDialog === dialog && showingModal) {
495
+ onCancelOrClose()
496
+ onCancel?.invoke()
497
+ }
498
+ }
499
+ dialog.show()
451
500
  }
452
501
 
453
502
  private fun presentDate(act: FragmentActivity) {
@@ -474,7 +523,9 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
474
523
  val ts = clamp(dateMs ?: System.currentTimeMillis())
475
524
  val cal = calendarFor(ts)
476
525
 
477
- val picker = DatePicker(act).apply {
526
+ val dialogContext = localizedContext(PCThemeSupport.appCompatDialogContext(act, "DatePicker"))
527
+ val picker = DatePicker(dialogContext).apply {
528
+ applyFirstDayOfWeek(this)
478
529
  calendarViewShown = true
479
530
  spinnersShown = false
480
531
  // Set the date first, before min/max constraints
@@ -493,13 +544,13 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
493
544
 
494
545
  // Wrap picker in a container with horizontal padding to prevent CalendarView
495
546
  // from clipping against the dialog edges
496
- val container = FrameLayout(act).apply {
547
+ val container = FrameLayout(dialogContext).apply {
497
548
  val horizontalPadding = (8 * resources.displayMetrics.density).toInt()
498
549
  setPadding(horizontalPadding, 0, horizontalPadding, 0)
499
550
  addView(picker)
500
551
  }
501
552
 
502
- val dlg = AlertDialog.Builder(PCThemeSupport.appCompatDialogContext(act, "DatePicker"))
553
+ val dlg = AlertDialog.Builder(dialogContext)
503
554
  .setTitle(androidDialogTitle ?: "")
504
555
  .setView(container)
505
556
  .setPositiveButton(androidPositiveTitle ?: "OK") { _, _ ->
@@ -524,46 +575,31 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
524
575
  }
525
576
  .create()
526
577
 
527
- dlg.show()
578
+ showSystemDialog(dlg)
528
579
  }
529
580
 
530
581
  private fun presentSystemTime(act: FragmentActivity) {
531
582
  val ts = clamp(dateMs ?: System.currentTimeMillis())
532
583
  val cal = calendarFor(ts)
533
584
 
534
- val picker = TimePicker(act).apply {
535
- val is24 = android.text.format.DateFormat.is24HourFormat(act)
536
- setIs24HourView(is24)
585
+ val dialogContext = localizedContext(PCThemeSupport.appCompatDialogContext(act, "DatePicker"))
586
+ val picker = TimePicker(dialogContext).apply {
587
+ setIs24HourView(is24Hour(act))
537
588
 
538
589
  val hour = cal.get(Calendar.HOUR_OF_DAY)
539
590
  val minute = cal.get(Calendar.MINUTE)
540
591
 
541
- if (Build.VERSION.SDK_INT >= 23) {
542
- this.hour = hour
543
- this.minute = minute
544
- } else {
545
- @Suppress("DEPRECATION") this.currentHour = hour
546
- @Suppress("DEPRECATION") this.currentMinute = minute
547
- }
592
+ this.hour = hour
593
+ this.minute = minute
548
594
  }
549
595
 
550
- val dlg = AlertDialog.Builder(PCThemeSupport.appCompatDialogContext(act, "DatePicker"))
596
+ val dlg = AlertDialog.Builder(dialogContext)
551
597
  .setTitle(androidDialogTitle ?: "")
552
598
  .setView(picker)
553
599
  .setPositiveButton(androidPositiveTitle ?: "OK") { _, _ ->
554
- val h: Int
555
- val m: Int
556
- if (Build.VERSION.SDK_INT >= 23) {
557
- h = picker.hour
558
- m = picker.minute
559
- } else {
560
- @Suppress("DEPRECATION") h = picker.currentHour
561
- @Suppress("DEPRECATION") m = picker.currentMinute
562
- }
563
-
564
600
  val c = calendarFor(ts)
565
- c.set(Calendar.HOUR_OF_DAY, h)
566
- c.set(Calendar.MINUTE, m)
601
+ c.set(Calendar.HOUR_OF_DAY, picker.hour)
602
+ c.set(Calendar.MINUTE, picker.minute)
567
603
  c.set(Calendar.SECOND, 0)
568
604
  c.set(Calendar.MILLISECOND, 0)
569
605
 
@@ -581,7 +617,7 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
581
617
  }
582
618
  .create()
583
619
 
584
- dlg.show()
620
+ showSystemDialog(dlg)
585
621
  }
586
622
 
587
623
  private fun presentSystemDateThenTime(act: FragmentActivity) {
@@ -589,7 +625,9 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
589
625
  val ts = clamp(dateMs ?: System.currentTimeMillis())
590
626
  val cal = calendarFor(ts)
591
627
 
592
- val picker = DatePicker(act).apply {
628
+ val dialogContext = localizedContext(PCThemeSupport.appCompatDialogContext(act, "DatePicker"))
629
+ val picker = DatePicker(dialogContext).apply {
630
+ applyFirstDayOfWeek(this)
593
631
  calendarViewShown = true
594
632
  spinnersShown = false
595
633
  // Set the date first, before min/max constraints
@@ -608,13 +646,13 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
608
646
 
609
647
  // Wrap picker in a container with horizontal padding to prevent CalendarView
610
648
  // from clipping against the dialog edges
611
- val container = FrameLayout(act).apply {
649
+ val container = FrameLayout(dialogContext).apply {
612
650
  val horizontalPadding = (8 * resources.displayMetrics.density).toInt()
613
651
  setPadding(horizontalPadding, 0, horizontalPadding, 0)
614
652
  addView(picker)
615
653
  }
616
654
 
617
- val dlg = AlertDialog.Builder(PCThemeSupport.appCompatDialogContext(act, "DatePicker"))
655
+ val dlg = AlertDialog.Builder(dialogContext)
618
656
  .setTitle(androidDialogTitle ?: "")
619
657
  .setView(container)
620
658
  .setPositiveButton(androidPositiveTitle ?: "Next") { _, _ ->
@@ -639,7 +677,7 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
639
677
  }
640
678
  .create()
641
679
 
642
- dlg.show()
680
+ showSystemDialog(dlg)
643
681
  }
644
682
 
645
683
  // -----------------------------
@@ -649,24 +687,13 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
649
687
  private fun presentM3Date(act: FragmentActivity) {
650
688
  val ts = clamp(dateMs ?: System.currentTimeMillis())
651
689
 
652
- val builder = MaterialDatePicker.Builder.datePicker()
653
- .setSelection(ts)
654
- .setTheme(m3CalendarTheme(act))
655
-
656
- androidDialogTitle?.let { builder.setTitleText(it) }
657
- androidPositiveTitle?.let { builder.setPositiveButtonText(it) }
658
- androidNegativeTitle?.let { builder.setNegativeButtonText(it) }
659
-
660
- val constraints = buildM3CalendarConstraints()
661
- if (constraints != null) builder.setCalendarConstraints(constraints)
662
-
663
- val picker = builder.build()
690
+ val picker = buildM3DatePicker(act, ts)
664
691
 
665
692
  picker.addOnPositiveButtonClickListener { selection ->
666
693
  val sel = (selection ?: ts)
667
694
  // Selection is date-based; merge with existing time-of-day
668
695
  val base = calendarFor(ts)
669
- val selUtc = Calendar.getInstance(TimeZone.getTimeZone("UTC")).apply { timeInMillis = sel }
696
+ val selUtc = Calendar.getInstance(UTC).apply { timeInMillis = sel }
670
697
  base.set(Calendar.YEAR, selUtc.get(Calendar.YEAR))
671
698
  base.set(Calendar.MONTH, selUtc.get(Calendar.MONTH))
672
699
  base.set(Calendar.DAY_OF_MONTH, selUtc.get(Calendar.DAY_OF_MONTH))
@@ -680,12 +707,13 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
680
707
 
681
708
  picker.addOnDismissListener {
682
709
  // If dismissed without confirm, treat as cancel
683
- if (showingModal) {
710
+ if (materialDialog === picker && showingModal) {
684
711
  onCancel?.invoke()
685
712
  onCancelOrClose()
686
713
  }
687
714
  }
688
715
 
716
+ materialDialog = picker
689
717
  picker.show(act.supportFragmentManager, "PCDatePicker_M3_DATE")
690
718
  }
691
719
 
@@ -693,12 +721,15 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
693
721
  val ts = clamp(dateMs ?: System.currentTimeMillis())
694
722
  val cal = calendarFor(ts)
695
723
 
696
- val is24 = android.text.format.DateFormat.is24HourFormat(act)
697
724
  val builder = MaterialTimePicker.Builder()
698
725
  .setTheme(m3TimePickerTheme(act))
699
- .setTimeFormat(if (is24) TimeFormat.CLOCK_24H else TimeFormat.CLOCK_12H)
726
+ .setTimeFormat(if (is24Hour(act)) TimeFormat.CLOCK_24H else TimeFormat.CLOCK_12H)
700
727
  .setHour(cal.get(Calendar.HOUR_OF_DAY))
701
728
  .setMinute(cal.get(Calendar.MINUTE))
729
+ when (androidInputMode) {
730
+ "text" -> builder.setInputMode(MaterialTimePicker.INPUT_MODE_KEYBOARD)
731
+ "calendar" -> builder.setInputMode(MaterialTimePicker.INPUT_MODE_CLOCK)
732
+ }
702
733
 
703
734
  androidDialogTitle?.let { builder.setTitleText(it) }
704
735
  // These exist in recent Material; if you’re on an older one, you’ll get compile errors.
@@ -720,35 +751,25 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
720
751
  }
721
752
 
722
753
  picker.addOnDismissListener {
723
- if (showingModal) {
754
+ if (materialDialog === picker && showingModal) {
724
755
  onCancel?.invoke()
725
756
  onCancelOrClose()
726
757
  }
727
758
  }
728
759
 
760
+ materialDialog = picker
729
761
  picker.show(act.supportFragmentManager, "PCDatePicker_M3_TIME")
730
762
  }
731
763
 
732
764
  private fun presentM3DateThenTime(act: FragmentActivity) {
733
765
  val ts = clamp(dateMs ?: System.currentTimeMillis())
734
766
 
735
- val builder = MaterialDatePicker.Builder.datePicker()
736
- .setSelection(ts)
737
- .setTheme(m3CalendarTheme(act))
738
-
739
- androidDialogTitle?.let { builder.setTitleText(it) }
740
- androidPositiveTitle?.let { builder.setPositiveButtonText(it) }
741
- androidNegativeTitle?.let { builder.setNegativeButtonText(it) }
742
-
743
- val constraints = buildM3CalendarConstraints()
744
- if (constraints != null) builder.setCalendarConstraints(constraints)
745
-
746
- val picker = builder.build()
767
+ val picker = buildM3DatePicker(act, ts)
747
768
 
748
769
  picker.addOnPositiveButtonClickListener { selection ->
749
770
  val sel = (selection ?: ts)
750
771
  val base = calendarFor(ts)
751
- val selUtc = Calendar.getInstance(TimeZone.getTimeZone("UTC")).apply { timeInMillis = sel }
772
+ val selUtc = Calendar.getInstance(UTC).apply { timeInMillis = sel }
752
773
  base.set(Calendar.YEAR, selUtc.get(Calendar.YEAR))
753
774
  base.set(Calendar.MONTH, selUtc.get(Calendar.MONTH))
754
775
  base.set(Calendar.DAY_OF_MONTH, selUtc.get(Calendar.DAY_OF_MONTH))
@@ -761,15 +782,66 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
761
782
  }
762
783
 
763
784
  picker.addOnDismissListener {
764
- if (showingModal) {
785
+ // Material also dismisses after Next. The time picker owns the session
786
+ // then, so finishing the date dialog must not close it.
787
+ // https://developer.android.com/reference/com/google/android/material/datepicker/MaterialDatePicker#addOnDismissListener(android.content.DialogInterface.OnDismissListener)
788
+ if (materialDialog === picker && showingModal) {
765
789
  onCancel?.invoke()
766
790
  onCancelOrClose()
767
791
  }
768
792
  }
769
793
 
794
+ materialDialog = picker
770
795
  picker.show(act.supportFragmentManager, "PCDatePicker_M3_DATE_THEN_TIME")
771
796
  }
772
797
 
798
+ /**
799
+ * The Material range picker (full screen). The selection is two UTC-midnight
800
+ * days, reported as the start of each day in this picker's time zone.
801
+ */
802
+ private fun presentM3DateRange(act: FragmentActivity) {
803
+ val builder = MaterialDatePicker.Builder.dateRangePicker()
804
+ .setTheme(m3CalendarTheme(act))
805
+ .setCalendarConstraints(buildM3CalendarConstraints())
806
+ val start = dateMs?.let { utcDayFor(clamp(it)) }
807
+ val end = endDateMs?.let { utcDayFor(clamp(it)) }
808
+ if (start != null && end != null && end >= start) {
809
+ builder.setSelection(androidx.core.util.Pair(start, end))
810
+ }
811
+ androidDialogTitle?.let { builder.setTitleText(it) }
812
+ androidPositiveTitle?.let { builder.setPositiveButtonText(it) }
813
+ androidNegativeTitle?.let { builder.setNegativeButtonText(it) }
814
+ m3InputMode()?.let { builder.setInputMode(it) }
815
+ locale?.let { l -> m3TextInputFormat(l)?.let { builder.setTextInputFormat(it) } }
816
+
817
+ val picker = builder.build()
818
+
819
+ picker.addOnPositiveButtonClickListener { selection ->
820
+ val first = selection?.first
821
+ val second = selection?.second
822
+ if (first != null && second != null) {
823
+ val startMs = clamp(localDayStartFor(first))
824
+ val endMs = clamp(localDayStartFor(second))
825
+ dateMs = startMs
826
+ endDateMs = endMs
827
+ onConfirmRange?.invoke(startMs, endMs)
828
+ } else {
829
+ onCancel?.invoke()
830
+ }
831
+ onCancelOrClose()
832
+ }
833
+
834
+ picker.addOnDismissListener {
835
+ if (materialDialog === picker && showingModal) {
836
+ onCancel?.invoke()
837
+ onCancelOrClose()
838
+ }
839
+ }
840
+
841
+ materialDialog = picker
842
+ picker.show(act.supportFragmentManager, "PCDatePicker_M3_RANGE")
843
+ }
844
+
773
845
  /**
774
846
  * Material pickers resolve their theme from the activity. When the app theme is
775
847
  * not a Material theme they would throw, so hand them a full Material 3 dialog
@@ -791,17 +863,138 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
791
863
  R.style.PCMaterial3TimePickerDialogTheme_NativeTheme
792
864
  )
793
865
 
794
- private fun buildM3CalendarConstraints(): CalendarConstraints? {
795
- val min = minDateMs
796
- val max = maxDateMs
797
- if (min == null && max == null) return null
866
+ private fun buildM3DatePicker(act: FragmentActivity, ts: Long): MaterialDatePicker<Long> {
867
+ val builder = MaterialDatePicker.Builder.datePicker()
868
+ // MaterialDatePicker works in UTC days: its selection is the UTC midnight
869
+ // of the chosen day, so hand it this picker's calendar day in those terms.
870
+ .setSelection(utcDayFor(ts))
871
+ .setTheme(m3CalendarTheme(act))
872
+ .setCalendarConstraints(buildM3CalendarConstraints())
798
873
 
874
+ androidDialogTitle?.let { builder.setTitleText(it) }
875
+ androidPositiveTitle?.let { builder.setPositiveButtonText(it) }
876
+ androidNegativeTitle?.let { builder.setNegativeButtonText(it) }
877
+ m3InputMode()?.let { builder.setInputMode(it) }
878
+ // MaterialDatePicker formats with the process default locale and cannot be
879
+ // given a context, so `locale` only reaches its text-input date format.
880
+ locale?.let { l -> m3TextInputFormat(l)?.let { builder.setTextInputFormat(it) } }
881
+
882
+ return builder.build()
883
+ }
884
+
885
+ private fun buildM3CalendarConstraints(): CalendarConstraints {
799
886
  val b = CalendarConstraints.Builder()
800
- min?.let { b.setStart(it) }
801
- max?.let { b.setEnd(it) }
887
+ androidFirstDayOfWeek?.takeIf { it in Calendar.SUNDAY..Calendar.SATURDAY }?.let {
888
+ b.setFirstDayOfWeek(it)
889
+ }
890
+
891
+ val minDay = minDateMs?.let { utcDayFor(it) }
892
+ val maxDay = maxDateMs?.let { utcDayFor(it) }
893
+ minDay?.let { b.setStart(it) }
894
+ maxDay?.let { b.setEnd(it) }
895
+
896
+ // setStart/setEnd only limit month paging; the validator greys out the days
897
+ // before min in the first month and after max in the last one. Both points
898
+ // are UTC midnights, like the days the picker validates, and both bounds are
899
+ // inclusive (forward: day >= min, backward: day <= max).
900
+ val validators = listOfNotNull<CalendarConstraints.DateValidator>(
901
+ minDay?.let { DateValidatorPointForward.from(it) },
902
+ maxDay?.let { DateValidatorPointBackward.before(it) }
903
+ )
904
+ if (validators.isNotEmpty()) b.setValidator(CompositeDateValidator.allOf(validators))
802
905
  return b.build()
803
906
  }
804
907
 
908
+ /** MaterialDatePicker's input mode for `android.inputMode`; null keeps its default. */
909
+ private fun m3InputMode(): Int? = when (androidInputMode) {
910
+ "text" -> MaterialDatePicker.INPUT_MODE_TEXT
911
+ "calendar" -> MaterialDatePicker.INPUT_MODE_CALENDAR
912
+ else -> null
913
+ }
914
+
915
+ /** `is24Hour`, else the device's 12/24-hour setting. */
916
+ private fun is24Hour(ctx: Context): Boolean = when (hourFormat) {
917
+ "24" -> true
918
+ "12" -> false
919
+ else -> android.text.format.DateFormat.is24HourFormat(ctx)
920
+ }
921
+
922
+ /** The start of the day [utcDay] (a UTC midnight) names, in this picker's time zone. */
923
+ private fun localDayStartFor(utcDay: Long): Long {
924
+ val day = Calendar.getInstance(UTC).apply { timeInMillis = utcDay }
925
+ return Calendar.getInstance(timeZone).apply {
926
+ clear()
927
+ set(day.get(Calendar.YEAR), day.get(Calendar.MONTH), day.get(Calendar.DAY_OF_MONTH))
928
+ }.timeInMillis
929
+ }
930
+
931
+ /** The UTC midnight of [ts]'s calendar day in this picker's time zone. */
932
+ private fun utcDayFor(ts: Long): Long {
933
+ val local = calendarFor(ts)
934
+ return Calendar.getInstance(UTC).apply {
935
+ clear()
936
+ set(
937
+ local.get(Calendar.YEAR),
938
+ local.get(Calendar.MONTH),
939
+ local.get(Calendar.DAY_OF_MONTH)
940
+ )
941
+ }.timeInMillis
942
+ }
943
+
944
+ /**
945
+ * The locale's short date pattern as a fixed-width input format (dd, MM,
946
+ * yyyy), the way MaterialDatePicker derives its default one.
947
+ */
948
+ private fun m3TextInputFormat(l: Locale): SimpleDateFormat? {
949
+ val pattern = (DateFormat.getDateInstance(DateFormat.SHORT, l) as? SimpleDateFormat)
950
+ ?.toPattern() ?: return null
951
+ val input = pattern
952
+ .replace(Regex("[^dMy/\\-.]"), "")
953
+ .replace(Regex("d{1,2}"), "dd")
954
+ .replace(Regex("M{1,2}"), "MM")
955
+ .replace(Regex("y{1,4}"), "yyyy")
956
+ .replace(Regex("\\.$"), "")
957
+ return try {
958
+ SimpleDateFormat(input, l).apply {
959
+ timeZone = UTC
960
+ isLenient = false
961
+ }
962
+ } catch (_: IllegalArgumentException) {
963
+ null
964
+ }
965
+ }
966
+
967
+ private fun applyFirstDayOfWeek(picker: DatePicker) {
968
+ androidFirstDayOfWeek?.takeIf { it in Calendar.SUNDAY..Calendar.SATURDAY }?.let {
969
+ picker.firstDayOfWeek = it
970
+ }
971
+ }
972
+
973
+ /**
974
+ * [base] with the `locale` prop as its configuration locale, so the system
975
+ * pickers built from it draw month and weekday names in that locale.
976
+ */
977
+ private fun localizedContext(base: Context): Context {
978
+ val l = locale ?: return base
979
+ val config = Configuration(base.resources.configuration).apply { setLocale(l) }
980
+ return LocaleContext(base, base.createConfigurationContext(config).resources)
981
+ }
982
+
983
+ /**
984
+ * Swaps only the Resources. `applyOverrideConfiguration` would copy the base
985
+ * theme into a theme of the new Resources (Theme.setTo), which drops
986
+ * attributes (runtime native-theme colors among them), so the base theme
987
+ * object is used as is. Being a ContextThemeWrapper, its LayoutInflater is
988
+ * bound to this context, so inflated views see the localized Resources.
989
+ */
990
+ private class LocaleContext(
991
+ base: Context,
992
+ private val localized: android.content.res.Resources
993
+ ) : ContextThemeWrapper(base, 0) {
994
+ override fun getResources(): android.content.res.Resources = localized
995
+ override fun getTheme(): android.content.res.Resources.Theme = baseContext.theme
996
+ }
997
+
805
998
  // -----------------------------
806
999
  // Utility
807
1000
  // -----------------------------
@@ -809,6 +1002,8 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
809
1002
  private fun onCancelOrClose() {
810
1003
  Log.d(TAG, "onCancelOrClose")
811
1004
  showingModal = false
1005
+ systemDialog = null
1006
+ materialDialog = null
812
1007
  }
813
1008
 
814
1009
  private fun clamp(valueMs: Long): Long {