rn-grid-date-time-picker 1.0.0 → 1.2.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 (384) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/README.md +100 -638
  3. package/lib/commonjs/adapters/utcMidnight.js +15 -6
  4. package/lib/commonjs/adapters/utcMidnight.js.map +1 -1
  5. package/lib/commonjs/components/DateTimePicker.js +484 -85
  6. package/lib/commonjs/components/DateTimePicker.js.map +1 -1
  7. package/lib/commonjs/components/calendar/Calendar.js +21 -7
  8. package/lib/commonjs/components/calendar/Calendar.js.map +1 -1
  9. package/lib/commonjs/components/calendar/CalendarHeader.js +46 -6
  10. package/lib/commonjs/components/calendar/CalendarHeader.js.map +1 -1
  11. package/lib/commonjs/components/calendar/CalendarSwitch.js +150 -0
  12. package/lib/commonjs/components/calendar/CalendarSwitch.js.map +1 -0
  13. package/lib/commonjs/components/calendar/DayCell.js +8 -3
  14. package/lib/commonjs/components/calendar/DayCell.js.map +1 -1
  15. package/lib/commonjs/components/calendar/DayGrid.js +13 -2
  16. package/lib/commonjs/components/calendar/DayGrid.js.map +1 -1
  17. package/lib/commonjs/components/calendar/PeriodGrid.js +3 -1
  18. package/lib/commonjs/components/calendar/PeriodGrid.js.map +1 -1
  19. package/lib/commonjs/components/calendar/calendarStyles.js +3 -2
  20. package/lib/commonjs/components/calendar/calendarStyles.js.map +1 -1
  21. package/lib/commonjs/components/calendar/localeNames.js +46 -24
  22. package/lib/commonjs/components/calendar/localeNames.js.map +1 -1
  23. package/lib/commonjs/components/calendar/selection.js +9 -1
  24. package/lib/commonjs/components/calendar/selection.js.map +1 -1
  25. package/lib/commonjs/components/container/DefaultSheet.js +42 -11
  26. package/lib/commonjs/components/container/DefaultSheet.js.map +1 -1
  27. package/lib/commonjs/components/container/PickerContainer.js +4 -0
  28. package/lib/commonjs/components/container/PickerContainer.js.map +1 -1
  29. package/lib/commonjs/components/container/PickerLayout.js +1 -1
  30. package/lib/commonjs/components/container/PickerLayout.js.map +1 -1
  31. package/lib/commonjs/components/container/containerStyles.js +12 -4
  32. package/lib/commonjs/components/container/containerStyles.js.map +1 -1
  33. package/lib/commonjs/components/field/RangeFields.js +5 -1
  34. package/lib/commonjs/components/field/RangeFields.js.map +1 -1
  35. package/lib/commonjs/components/field/SegmentedInput.js +8 -3
  36. package/lib/commonjs/components/field/SegmentedInput.js.map +1 -1
  37. package/lib/commonjs/components/field/ValueField.js +64 -8
  38. package/lib/commonjs/components/field/ValueField.js.map +1 -1
  39. package/lib/commonjs/components/field/fieldStyles.js +17 -0
  40. package/lib/commonjs/components/field/fieldStyles.js.map +1 -1
  41. package/lib/commonjs/components/field/fieldText.js +29 -13
  42. package/lib/commonjs/components/field/fieldText.js.map +1 -1
  43. package/lib/commonjs/components/hooks/useBottomInset.js +32 -0
  44. package/lib/commonjs/components/hooks/useBottomInset.js.map +1 -0
  45. package/lib/commonjs/components/hooks/useKeyboardFold.js +36 -13
  46. package/lib/commonjs/components/hooks/useKeyboardFold.js.map +1 -1
  47. package/lib/commonjs/components/hooks/useOpenPicker.js +39 -17
  48. package/lib/commonjs/components/hooks/useOpenPicker.js.map +1 -1
  49. package/lib/commonjs/components/hooks/useTypedSegments.js +6 -2
  50. package/lib/commonjs/components/hooks/useTypedSegments.js.map +1 -1
  51. package/lib/commonjs/components/theme/defaultStrings.js +13 -3
  52. package/lib/commonjs/components/theme/defaultStrings.js.map +1 -1
  53. package/lib/commonjs/components/theme/direction.js +17 -0
  54. package/lib/commonjs/components/theme/direction.js.map +1 -0
  55. package/lib/commonjs/components/theme/numerals.js +16 -0
  56. package/lib/commonjs/components/theme/numerals.js.map +1 -0
  57. package/lib/commonjs/components/theme/styleKeys.js +10 -2
  58. package/lib/commonjs/components/theme/styleKeys.js.map +1 -1
  59. package/lib/commonjs/components/theme/tokens.js +4 -0
  60. package/lib/commonjs/components/theme/tokens.js.map +1 -1
  61. package/lib/commonjs/components/time/TimeRow.js +10 -2
  62. package/lib/commonjs/components/time/TimeRow.js.map +1 -1
  63. package/lib/commonjs/components/time/TypedTime.js +3 -1
  64. package/lib/commonjs/components/time/TypedTime.js.map +1 -1
  65. package/lib/commonjs/components/time/Wheel.js +20 -3
  66. package/lib/commonjs/components/time/Wheel.js.map +1 -1
  67. package/lib/commonjs/components/time/timeStyles.js +4 -5
  68. package/lib/commonjs/components/time/timeStyles.js.map +1 -1
  69. package/lib/commonjs/components/types.js +10 -0
  70. package/lib/commonjs/components/types.js.map +1 -1
  71. package/lib/commonjs/core/calendarSystem.js +123 -22
  72. package/lib/commonjs/core/calendarSystem.js.map +1 -1
  73. package/lib/commonjs/core/digits.js +25 -0
  74. package/lib/commonjs/core/digits.js.map +1 -0
  75. package/lib/commonjs/core/draft.js +31 -10
  76. package/lib/commonjs/core/draft.js.map +1 -1
  77. package/lib/commonjs/core/locale.js +20 -4
  78. package/lib/commonjs/core/locale.js.map +1 -1
  79. package/lib/commonjs/core/numerals.js +46 -0
  80. package/lib/commonjs/core/numerals.js.map +1 -0
  81. package/lib/commonjs/core/segmentEditor.js +9 -0
  82. package/lib/commonjs/core/segmentEditor.js.map +1 -1
  83. package/lib/commonjs/core/segments.js +2 -11
  84. package/lib/commonjs/core/segments.js.map +1 -1
  85. package/lib/commonjs/core/selectionRules.js +2 -1
  86. package/lib/commonjs/core/selectionRules.js.map +1 -1
  87. package/lib/commonjs/core/timeEntry.js +7 -91
  88. package/lib/commonjs/core/timeEntry.js.map +1 -1
  89. package/lib/commonjs/icons/index.js +5 -1
  90. package/lib/commonjs/icons/index.js.map +1 -1
  91. package/lib/commonjs/index.js +20 -0
  92. package/lib/commonjs/index.js.map +1 -1
  93. package/lib/module/adapters/utcMidnight.js +14 -5
  94. package/lib/module/adapters/utcMidnight.js.map +1 -1
  95. package/lib/module/components/DateTimePicker.js +490 -91
  96. package/lib/module/components/DateTimePicker.js.map +1 -1
  97. package/lib/module/components/calendar/Calendar.js +25 -11
  98. package/lib/module/components/calendar/Calendar.js.map +1 -1
  99. package/lib/module/components/calendar/CalendarHeader.js +47 -7
  100. package/lib/module/components/calendar/CalendarHeader.js.map +1 -1
  101. package/lib/module/components/calendar/CalendarSwitch.js +145 -0
  102. package/lib/module/components/calendar/CalendarSwitch.js.map +1 -0
  103. package/lib/module/components/calendar/DayCell.js +8 -3
  104. package/lib/module/components/calendar/DayCell.js.map +1 -1
  105. package/lib/module/components/calendar/DayGrid.js +14 -3
  106. package/lib/module/components/calendar/DayGrid.js.map +1 -1
  107. package/lib/module/components/calendar/PeriodGrid.js +3 -1
  108. package/lib/module/components/calendar/PeriodGrid.js.map +1 -1
  109. package/lib/module/components/calendar/calendarStyles.js +3 -2
  110. package/lib/module/components/calendar/calendarStyles.js.map +1 -1
  111. package/lib/module/components/calendar/localeNames.js +46 -24
  112. package/lib/module/components/calendar/localeNames.js.map +1 -1
  113. package/lib/module/components/calendar/selection.js +7 -0
  114. package/lib/module/components/calendar/selection.js.map +1 -1
  115. package/lib/module/components/container/DefaultSheet.js +42 -12
  116. package/lib/module/components/container/DefaultSheet.js.map +1 -1
  117. package/lib/module/components/container/PickerContainer.js +4 -0
  118. package/lib/module/components/container/PickerContainer.js.map +1 -1
  119. package/lib/module/components/container/PickerLayout.js +1 -1
  120. package/lib/module/components/container/PickerLayout.js.map +1 -1
  121. package/lib/module/components/container/containerStyles.js +11 -3
  122. package/lib/module/components/container/containerStyles.js.map +1 -1
  123. package/lib/module/components/field/RangeFields.js +5 -1
  124. package/lib/module/components/field/RangeFields.js.map +1 -1
  125. package/lib/module/components/field/SegmentedInput.js +8 -3
  126. package/lib/module/components/field/SegmentedInput.js.map +1 -1
  127. package/lib/module/components/field/ValueField.js +66 -10
  128. package/lib/module/components/field/ValueField.js.map +1 -1
  129. package/lib/module/components/field/fieldStyles.js +17 -0
  130. package/lib/module/components/field/fieldStyles.js.map +1 -1
  131. package/lib/module/components/field/fieldText.js +28 -11
  132. package/lib/module/components/field/fieldText.js.map +1 -1
  133. package/lib/module/components/hooks/useBottomInset.js +27 -0
  134. package/lib/module/components/hooks/useBottomInset.js.map +1 -0
  135. package/lib/module/components/hooks/useKeyboardFold.js +33 -12
  136. package/lib/module/components/hooks/useKeyboardFold.js.map +1 -1
  137. package/lib/module/components/hooks/useOpenPicker.js +39 -17
  138. package/lib/module/components/hooks/useOpenPicker.js.map +1 -1
  139. package/lib/module/components/hooks/useTypedSegments.js +6 -2
  140. package/lib/module/components/hooks/useTypedSegments.js.map +1 -1
  141. package/lib/module/components/theme/defaultStrings.js +11 -2
  142. package/lib/module/components/theme/defaultStrings.js.map +1 -1
  143. package/lib/module/components/theme/direction.js +13 -0
  144. package/lib/module/components/theme/direction.js.map +1 -0
  145. package/lib/module/components/theme/numerals.js +12 -0
  146. package/lib/module/components/theme/numerals.js.map +1 -0
  147. package/lib/module/components/theme/styleKeys.js +10 -2
  148. package/lib/module/components/theme/styleKeys.js.map +1 -1
  149. package/lib/module/components/theme/tokens.js +4 -0
  150. package/lib/module/components/theme/tokens.js.map +1 -1
  151. package/lib/module/components/time/TimeRow.js +11 -3
  152. package/lib/module/components/time/TimeRow.js.map +1 -1
  153. package/lib/module/components/time/TypedTime.js +3 -1
  154. package/lib/module/components/time/TypedTime.js.map +1 -1
  155. package/lib/module/components/time/Wheel.js +18 -2
  156. package/lib/module/components/time/Wheel.js.map +1 -1
  157. package/lib/module/components/time/timeStyles.js +4 -5
  158. package/lib/module/components/time/timeStyles.js.map +1 -1
  159. package/lib/module/components/types.js +10 -0
  160. package/lib/module/components/types.js.map +1 -1
  161. package/lib/module/core/calendarSystem.js +118 -19
  162. package/lib/module/core/calendarSystem.js.map +1 -1
  163. package/lib/module/core/digits.js +20 -0
  164. package/lib/module/core/digits.js.map +1 -0
  165. package/lib/module/core/draft.js +29 -9
  166. package/lib/module/core/draft.js.map +1 -1
  167. package/lib/module/core/locale.js +18 -3
  168. package/lib/module/core/locale.js.map +1 -1
  169. package/lib/module/core/numerals.js +39 -0
  170. package/lib/module/core/numerals.js.map +1 -0
  171. package/lib/module/core/segmentEditor.js +9 -0
  172. package/lib/module/core/segmentEditor.js.map +1 -1
  173. package/lib/module/core/segments.js +0 -8
  174. package/lib/module/core/segments.js.map +1 -1
  175. package/lib/module/core/selectionRules.js +2 -1
  176. package/lib/module/core/selectionRules.js.map +1 -1
  177. package/lib/module/core/timeEntry.js +7 -89
  178. package/lib/module/core/timeEntry.js.map +1 -1
  179. package/lib/module/icons/index.js +5 -1
  180. package/lib/module/icons/index.js.map +1 -1
  181. package/lib/module/index.js +2 -0
  182. package/lib/module/index.js.map +1 -1
  183. package/lib/typescript/commonjs/src/adapters/utcMidnight.d.ts.map +1 -1
  184. package/lib/typescript/commonjs/src/components/DateTimePicker.d.ts.map +1 -1
  185. package/lib/typescript/commonjs/src/components/calendar/Calendar.d.ts +8 -4
  186. package/lib/typescript/commonjs/src/components/calendar/Calendar.d.ts.map +1 -1
  187. package/lib/typescript/commonjs/src/components/calendar/CalendarHeader.d.ts.map +1 -1
  188. package/lib/typescript/commonjs/src/components/calendar/CalendarSwitch.d.ts +26 -0
  189. package/lib/typescript/commonjs/src/components/calendar/CalendarSwitch.d.ts.map +1 -0
  190. package/lib/typescript/commonjs/src/components/calendar/DayCell.d.ts +1 -1
  191. package/lib/typescript/commonjs/src/components/calendar/DayCell.d.ts.map +1 -1
  192. package/lib/typescript/commonjs/src/components/calendar/DayGrid.d.ts +2 -0
  193. package/lib/typescript/commonjs/src/components/calendar/DayGrid.d.ts.map +1 -1
  194. package/lib/typescript/commonjs/src/components/calendar/PeriodGrid.d.ts.map +1 -1
  195. package/lib/typescript/commonjs/src/components/calendar/calendarStyles.d.ts +1 -1
  196. package/lib/typescript/commonjs/src/components/calendar/calendarStyles.d.ts.map +1 -1
  197. package/lib/typescript/commonjs/src/components/calendar/localeNames.d.ts +8 -3
  198. package/lib/typescript/commonjs/src/components/calendar/localeNames.d.ts.map +1 -1
  199. package/lib/typescript/commonjs/src/components/calendar/selection.d.ts +2 -0
  200. package/lib/typescript/commonjs/src/components/calendar/selection.d.ts.map +1 -1
  201. package/lib/typescript/commonjs/src/components/container/DefaultSheet.d.ts +10 -2
  202. package/lib/typescript/commonjs/src/components/container/DefaultSheet.d.ts.map +1 -1
  203. package/lib/typescript/commonjs/src/components/container/PickerContainer.d.ts.map +1 -1
  204. package/lib/typescript/commonjs/src/components/container/containerStyles.d.ts +6 -0
  205. package/lib/typescript/commonjs/src/components/container/containerStyles.d.ts.map +1 -1
  206. package/lib/typescript/commonjs/src/components/field/RangeFields.d.ts +5 -0
  207. package/lib/typescript/commonjs/src/components/field/RangeFields.d.ts.map +1 -1
  208. package/lib/typescript/commonjs/src/components/field/SegmentedInput.d.ts.map +1 -1
  209. package/lib/typescript/commonjs/src/components/field/ValueField.d.ts +7 -0
  210. package/lib/typescript/commonjs/src/components/field/ValueField.d.ts.map +1 -1
  211. package/lib/typescript/commonjs/src/components/field/fieldStyles.d.ts +15 -0
  212. package/lib/typescript/commonjs/src/components/field/fieldStyles.d.ts.map +1 -1
  213. package/lib/typescript/commonjs/src/components/field/fieldText.d.ts +14 -5
  214. package/lib/typescript/commonjs/src/components/field/fieldText.d.ts.map +1 -1
  215. package/lib/typescript/commonjs/src/components/hooks/useBottomInset.d.ts +8 -0
  216. package/lib/typescript/commonjs/src/components/hooks/useBottomInset.d.ts.map +1 -0
  217. package/lib/typescript/commonjs/src/components/hooks/useKeyboardFold.d.ts +10 -2
  218. package/lib/typescript/commonjs/src/components/hooks/useKeyboardFold.d.ts.map +1 -1
  219. package/lib/typescript/commonjs/src/components/hooks/useOpenPicker.d.ts +2 -1
  220. package/lib/typescript/commonjs/src/components/hooks/useOpenPicker.d.ts.map +1 -1
  221. package/lib/typescript/commonjs/src/components/hooks/useTypedSegments.d.ts +3 -2
  222. package/lib/typescript/commonjs/src/components/hooks/useTypedSegments.d.ts.map +1 -1
  223. package/lib/typescript/commonjs/src/components/theme/defaultStrings.d.ts +13 -2
  224. package/lib/typescript/commonjs/src/components/theme/defaultStrings.d.ts.map +1 -1
  225. package/lib/typescript/commonjs/src/components/theme/direction.d.ts +8 -0
  226. package/lib/typescript/commonjs/src/components/theme/direction.d.ts.map +1 -0
  227. package/lib/typescript/commonjs/src/components/theme/numerals.d.ts +7 -0
  228. package/lib/typescript/commonjs/src/components/theme/numerals.d.ts.map +1 -0
  229. package/lib/typescript/commonjs/src/components/theme/styleKeys.d.ts +1 -1
  230. package/lib/typescript/commonjs/src/components/theme/styleKeys.d.ts.map +1 -1
  231. package/lib/typescript/commonjs/src/components/theme/tokens.d.ts +3 -1
  232. package/lib/typescript/commonjs/src/components/theme/tokens.d.ts.map +1 -1
  233. package/lib/typescript/commonjs/src/components/time/TimeRow.d.ts.map +1 -1
  234. package/lib/typescript/commonjs/src/components/time/TypedTime.d.ts.map +1 -1
  235. package/lib/typescript/commonjs/src/components/time/Wheel.d.ts +5 -0
  236. package/lib/typescript/commonjs/src/components/time/Wheel.d.ts.map +1 -1
  237. package/lib/typescript/commonjs/src/components/time/timeStyles.d.ts +0 -2
  238. package/lib/typescript/commonjs/src/components/time/timeStyles.d.ts.map +1 -1
  239. package/lib/typescript/commonjs/src/components/types.d.ts +84 -4
  240. package/lib/typescript/commonjs/src/components/types.d.ts.map +1 -1
  241. package/lib/typescript/commonjs/src/core/calendarSystem.d.ts +20 -5
  242. package/lib/typescript/commonjs/src/core/calendarSystem.d.ts.map +1 -1
  243. package/lib/typescript/commonjs/src/core/digits.d.ts +3 -0
  244. package/lib/typescript/commonjs/src/core/digits.d.ts.map +1 -0
  245. package/lib/typescript/commonjs/src/core/draft.d.ts +12 -1
  246. package/lib/typescript/commonjs/src/core/draft.d.ts.map +1 -1
  247. package/lib/typescript/commonjs/src/core/locale.d.ts +6 -0
  248. package/lib/typescript/commonjs/src/core/locale.d.ts.map +1 -1
  249. package/lib/typescript/commonjs/src/core/numerals.d.ts +15 -0
  250. package/lib/typescript/commonjs/src/core/numerals.d.ts.map +1 -0
  251. package/lib/typescript/commonjs/src/core/segmentEditor.d.ts.map +1 -1
  252. package/lib/typescript/commonjs/src/core/segments.d.ts +0 -2
  253. package/lib/typescript/commonjs/src/core/segments.d.ts.map +1 -1
  254. package/lib/typescript/commonjs/src/core/selectionRules.d.ts +3 -2
  255. package/lib/typescript/commonjs/src/core/selectionRules.d.ts.map +1 -1
  256. package/lib/typescript/commonjs/src/core/timeEntry.d.ts +4 -24
  257. package/lib/typescript/commonjs/src/core/timeEntry.d.ts.map +1 -1
  258. package/lib/typescript/commonjs/src/icons/index.d.ts.map +1 -1
  259. package/lib/typescript/commonjs/src/index.d.ts +7 -3
  260. package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
  261. package/lib/typescript/module/src/adapters/utcMidnight.d.ts.map +1 -1
  262. package/lib/typescript/module/src/components/DateTimePicker.d.ts.map +1 -1
  263. package/lib/typescript/module/src/components/calendar/Calendar.d.ts +8 -4
  264. package/lib/typescript/module/src/components/calendar/Calendar.d.ts.map +1 -1
  265. package/lib/typescript/module/src/components/calendar/CalendarHeader.d.ts.map +1 -1
  266. package/lib/typescript/module/src/components/calendar/CalendarSwitch.d.ts +26 -0
  267. package/lib/typescript/module/src/components/calendar/CalendarSwitch.d.ts.map +1 -0
  268. package/lib/typescript/module/src/components/calendar/DayCell.d.ts +1 -1
  269. package/lib/typescript/module/src/components/calendar/DayCell.d.ts.map +1 -1
  270. package/lib/typescript/module/src/components/calendar/DayGrid.d.ts +2 -0
  271. package/lib/typescript/module/src/components/calendar/DayGrid.d.ts.map +1 -1
  272. package/lib/typescript/module/src/components/calendar/PeriodGrid.d.ts.map +1 -1
  273. package/lib/typescript/module/src/components/calendar/calendarStyles.d.ts +1 -1
  274. package/lib/typescript/module/src/components/calendar/calendarStyles.d.ts.map +1 -1
  275. package/lib/typescript/module/src/components/calendar/localeNames.d.ts +8 -3
  276. package/lib/typescript/module/src/components/calendar/localeNames.d.ts.map +1 -1
  277. package/lib/typescript/module/src/components/calendar/selection.d.ts +2 -0
  278. package/lib/typescript/module/src/components/calendar/selection.d.ts.map +1 -1
  279. package/lib/typescript/module/src/components/container/DefaultSheet.d.ts +10 -2
  280. package/lib/typescript/module/src/components/container/DefaultSheet.d.ts.map +1 -1
  281. package/lib/typescript/module/src/components/container/PickerContainer.d.ts.map +1 -1
  282. package/lib/typescript/module/src/components/container/containerStyles.d.ts +6 -0
  283. package/lib/typescript/module/src/components/container/containerStyles.d.ts.map +1 -1
  284. package/lib/typescript/module/src/components/field/RangeFields.d.ts +5 -0
  285. package/lib/typescript/module/src/components/field/RangeFields.d.ts.map +1 -1
  286. package/lib/typescript/module/src/components/field/SegmentedInput.d.ts.map +1 -1
  287. package/lib/typescript/module/src/components/field/ValueField.d.ts +7 -0
  288. package/lib/typescript/module/src/components/field/ValueField.d.ts.map +1 -1
  289. package/lib/typescript/module/src/components/field/fieldStyles.d.ts +15 -0
  290. package/lib/typescript/module/src/components/field/fieldStyles.d.ts.map +1 -1
  291. package/lib/typescript/module/src/components/field/fieldText.d.ts +14 -5
  292. package/lib/typescript/module/src/components/field/fieldText.d.ts.map +1 -1
  293. package/lib/typescript/module/src/components/hooks/useBottomInset.d.ts +8 -0
  294. package/lib/typescript/module/src/components/hooks/useBottomInset.d.ts.map +1 -0
  295. package/lib/typescript/module/src/components/hooks/useKeyboardFold.d.ts +10 -2
  296. package/lib/typescript/module/src/components/hooks/useKeyboardFold.d.ts.map +1 -1
  297. package/lib/typescript/module/src/components/hooks/useOpenPicker.d.ts +2 -1
  298. package/lib/typescript/module/src/components/hooks/useOpenPicker.d.ts.map +1 -1
  299. package/lib/typescript/module/src/components/hooks/useTypedSegments.d.ts +3 -2
  300. package/lib/typescript/module/src/components/hooks/useTypedSegments.d.ts.map +1 -1
  301. package/lib/typescript/module/src/components/theme/defaultStrings.d.ts +13 -2
  302. package/lib/typescript/module/src/components/theme/defaultStrings.d.ts.map +1 -1
  303. package/lib/typescript/module/src/components/theme/direction.d.ts +8 -0
  304. package/lib/typescript/module/src/components/theme/direction.d.ts.map +1 -0
  305. package/lib/typescript/module/src/components/theme/numerals.d.ts +7 -0
  306. package/lib/typescript/module/src/components/theme/numerals.d.ts.map +1 -0
  307. package/lib/typescript/module/src/components/theme/styleKeys.d.ts +1 -1
  308. package/lib/typescript/module/src/components/theme/styleKeys.d.ts.map +1 -1
  309. package/lib/typescript/module/src/components/theme/tokens.d.ts +3 -1
  310. package/lib/typescript/module/src/components/theme/tokens.d.ts.map +1 -1
  311. package/lib/typescript/module/src/components/time/TimeRow.d.ts.map +1 -1
  312. package/lib/typescript/module/src/components/time/TypedTime.d.ts.map +1 -1
  313. package/lib/typescript/module/src/components/time/Wheel.d.ts +5 -0
  314. package/lib/typescript/module/src/components/time/Wheel.d.ts.map +1 -1
  315. package/lib/typescript/module/src/components/time/timeStyles.d.ts +0 -2
  316. package/lib/typescript/module/src/components/time/timeStyles.d.ts.map +1 -1
  317. package/lib/typescript/module/src/components/types.d.ts +84 -4
  318. package/lib/typescript/module/src/components/types.d.ts.map +1 -1
  319. package/lib/typescript/module/src/core/calendarSystem.d.ts +20 -5
  320. package/lib/typescript/module/src/core/calendarSystem.d.ts.map +1 -1
  321. package/lib/typescript/module/src/core/digits.d.ts +3 -0
  322. package/lib/typescript/module/src/core/digits.d.ts.map +1 -0
  323. package/lib/typescript/module/src/core/draft.d.ts +12 -1
  324. package/lib/typescript/module/src/core/draft.d.ts.map +1 -1
  325. package/lib/typescript/module/src/core/locale.d.ts +6 -0
  326. package/lib/typescript/module/src/core/locale.d.ts.map +1 -1
  327. package/lib/typescript/module/src/core/numerals.d.ts +15 -0
  328. package/lib/typescript/module/src/core/numerals.d.ts.map +1 -0
  329. package/lib/typescript/module/src/core/segmentEditor.d.ts.map +1 -1
  330. package/lib/typescript/module/src/core/segments.d.ts +0 -2
  331. package/lib/typescript/module/src/core/segments.d.ts.map +1 -1
  332. package/lib/typescript/module/src/core/selectionRules.d.ts +3 -2
  333. package/lib/typescript/module/src/core/selectionRules.d.ts.map +1 -1
  334. package/lib/typescript/module/src/core/timeEntry.d.ts +4 -24
  335. package/lib/typescript/module/src/core/timeEntry.d.ts.map +1 -1
  336. package/lib/typescript/module/src/icons/index.d.ts.map +1 -1
  337. package/lib/typescript/module/src/index.d.ts +7 -3
  338. package/lib/typescript/module/src/index.d.ts.map +1 -1
  339. package/package.json +22 -7
  340. package/src/adapters/utcMidnight.ts +14 -5
  341. package/src/components/DateTimePicker.tsx +607 -108
  342. package/src/components/calendar/Calendar.tsx +54 -16
  343. package/src/components/calendar/CalendarHeader.tsx +41 -9
  344. package/src/components/calendar/CalendarSwitch.tsx +170 -0
  345. package/src/components/calendar/DayCell.tsx +16 -4
  346. package/src/components/calendar/DayGrid.tsx +18 -3
  347. package/src/components/calendar/PeriodGrid.tsx +3 -1
  348. package/src/components/calendar/calendarStyles.ts +3 -2
  349. package/src/components/calendar/localeNames.ts +52 -22
  350. package/src/components/calendar/selection.ts +8 -0
  351. package/src/components/container/DefaultSheet.tsx +60 -14
  352. package/src/components/container/PickerContainer.tsx +4 -0
  353. package/src/components/container/PickerLayout.tsx +1 -1
  354. package/src/components/container/containerStyles.ts +12 -3
  355. package/src/components/field/RangeFields.tsx +12 -2
  356. package/src/components/field/SegmentedInput.tsx +8 -3
  357. package/src/components/field/ValueField.tsx +94 -18
  358. package/src/components/field/fieldStyles.ts +6 -0
  359. package/src/components/field/fieldText.ts +68 -15
  360. package/src/components/hooks/useBottomInset.ts +33 -0
  361. package/src/components/hooks/useKeyboardFold.ts +41 -13
  362. package/src/components/hooks/useOpenPicker.ts +41 -18
  363. package/src/components/hooks/useTypedSegments.ts +7 -3
  364. package/src/components/theme/defaultStrings.ts +29 -4
  365. package/src/components/theme/direction.ts +12 -0
  366. package/src/components/theme/numerals.ts +11 -0
  367. package/src/components/theme/styleKeys.ts +18 -1
  368. package/src/components/theme/tokens.ts +5 -1
  369. package/src/components/time/TimeRow.tsx +23 -3
  370. package/src/components/time/TypedTime.tsx +3 -1
  371. package/src/components/time/Wheel.tsx +19 -5
  372. package/src/components/time/timeStyles.ts +2 -3
  373. package/src/components/types.ts +86 -4
  374. package/src/core/calendarSystem.ts +145 -21
  375. package/src/core/digits.ts +21 -0
  376. package/src/core/draft.ts +41 -13
  377. package/src/core/locale.ts +20 -3
  378. package/src/core/numerals.ts +35 -0
  379. package/src/core/segmentEditor.ts +13 -0
  380. package/src/core/segments.ts +0 -8
  381. package/src/core/selectionRules.ts +3 -2
  382. package/src/core/timeEntry.ts +6 -96
  383. package/src/icons/index.tsx +3 -1
  384. package/src/index.tsx +12 -2
@@ -1,20 +1,26 @@
1
- import { DateTime, Info } from 'luxon';
1
+ import { weekdayOf } from '../../core/calendarDate';
2
+ import { withCalendar } from '../../core/locale';
2
3
  import type { CalendarDate, Weekday } from '../../core/types';
3
4
 
4
5
  /**
5
- * Month and weekday names from Luxon (Intl), cached per locale. Falls back to
6
- * 'en-US' when the device's Intl can't format the locale (some engines return
7
- * empty names instead of failing), and to built-in English names after that.
6
+ * Month and weekday names from the platform's Intl, cached per locale. Each
7
+ * name is formatted on its own (not read from formatToParts: iOS labels every
8
+ * part of some locales, such as 'de-DE' and 'ar-SA', as plain text), in the
9
+ * Gregorian calendar. Falls back to 'en-US' when the device's Intl can't name
10
+ * the locale, and to built-in English names after that.
8
11
  */
9
12
  interface Names {
10
13
  monthsShort: string[];
11
14
  monthsLong: string[];
15
+ /** Monday … Sunday, as the weekday row shows them. */
12
16
  weekdays: string[];
17
+ /** Monday … Sunday, for screen readers. */
18
+ weekdaysLong: string[];
13
19
  }
14
20
 
15
21
  const cache = new Map<string, Names>();
16
22
 
17
- const FALLBACK = {
23
+ const FALLBACK: Names = {
18
24
  monthsShort: [
19
25
  'Jan',
20
26
  'Feb',
@@ -43,26 +49,53 @@ const FALLBACK = {
43
49
  'November',
44
50
  'December',
45
51
  ],
46
- // Luxon order: Monday … Sunday.
47
52
  weekdays: ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'],
53
+ weekdaysLong: [
54
+ 'Monday',
55
+ 'Tuesday',
56
+ 'Wednesday',
57
+ 'Thursday',
58
+ 'Friday',
59
+ 'Saturday',
60
+ 'Sunday',
61
+ ],
48
62
  };
49
63
 
64
+ const range = (n: number) => Array.from({ length: n }, (_, i) => i);
65
+
50
66
  const readNames = (locale: string): Names | null => {
51
67
  try {
52
- const short = Info.weekdays('short', { locale });
53
- const names = {
54
- monthsShort: Info.months('short', { locale }),
55
- monthsLong: Info.months('long', { locale }),
68
+ const tag = withCalendar(locale, 'gregory');
69
+ const namer = (options: Intl.DateTimeFormatOptions) => {
70
+ const f = new Intl.DateTimeFormat(tag, { timeZone: 'UTC', ...options });
71
+ return (d: Date) => f.format(d);
72
+ };
73
+ // Mid-month, at noon UTC, so no zone moves the day.
74
+ const months = range(12).map((i) => new Date(Date.UTC(2021, i, 15, 12)));
75
+ // 1 February 2021 was a Monday.
76
+ const days = range(7).map((i) => new Date(Date.UTC(2021, 1, 1 + i, 12)));
77
+ const short = days.map(namer({ weekday: 'short' }));
78
+ // The language Intl actually uses: an unknown tag falls back to the device's.
79
+ const english = new Intl.DateTimeFormat(tag)
80
+ .resolvedOptions()
81
+ .locale.startsWith('en');
82
+ const names: Names = {
83
+ monthsShort: months.map(namer({ month: 'short' })),
84
+ monthsLong: months.map(namer({ month: 'long' })),
56
85
  // Two letters for English ("Su", "Mo"); other locales keep their short form.
57
- weekdays: locale.startsWith('en')
58
- ? short.map((w) => w?.slice(0, 2))
59
- : short,
86
+ weekdays: english ? short.map((w) => w.slice(0, 2)) : short,
87
+ weekdaysLong: days.map(namer({ weekday: 'long' })),
60
88
  };
61
- const complete = (list: string[] | undefined, length: number) =>
62
- list?.length === length && list.every(Boolean);
89
+ // Every name present and different (an engine that ignores the options
90
+ // writes whole dates, or the same text, instead).
91
+ const complete = (list: string[], length: number) =>
92
+ list.length === length &&
93
+ list.every(Boolean) &&
94
+ new Set(list).size === length;
63
95
  return complete(names.monthsShort, 12) &&
64
96
  complete(names.monthsLong, 12) &&
65
- complete(names.weekdays, 7)
97
+ complete(names.weekdays, 7) &&
98
+ complete(names.weekdaysLong, 7)
66
99
  ? names
67
100
  : null;
68
101
  } catch {
@@ -84,10 +117,7 @@ export const weekdayName = (locale: string, weekday: Weekday): string =>
84
117
 
85
118
  /** Full date for screen readers, e.g. "Wednesday, 21 October 2026". */
86
119
  export const fullDateLabel = (locale: string, day: CalendarDate): string => {
87
- const dt = DateTime.utc(day.year, day.month, day.day);
88
- try {
89
- return dt.setLocale(locale).toFormat('cccc, d LLLL yyyy');
90
- } catch {
91
- return dt.toFormat('cccc, d LLLL yyyy');
92
- }
120
+ const names = localeNames(locale);
121
+ const weekday = names.weekdaysLong[weekdayOf(day) - 1];
122
+ return `${weekday}, ${day.day} ${names.monthsLong[day.month - 1]} ${day.year}`;
93
123
  };
@@ -17,6 +17,14 @@ export const firstSelectedDay = (
17
17
  return sel.days[0] ?? null;
18
18
  };
19
19
 
20
+ /** Every selected day. */
21
+ export const selectedDays = (sel: CalendarSelection): CalendarDate[] => {
22
+ if (sel.kind === 'single') return sel.day ? [sel.day] : [];
23
+ if (sel.kind === 'range')
24
+ return [sel.from, sel.to].filter((d): d is CalendarDate => !!d);
25
+ return sel.days;
26
+ };
27
+
20
28
  const isNextDay = (a: CalendarDate, b: CalendarDate): boolean => {
21
29
  const next = new Date(Date.UTC(a.year, a.month - 1, a.day + 1));
22
30
  return (
@@ -1,8 +1,7 @@
1
- import React from 'react';
1
+ import React, { useState } from 'react';
2
2
  import {
3
3
  KeyboardAvoidingView,
4
4
  Modal,
5
- Platform,
6
5
  Pressable,
7
6
  useWindowDimensions,
8
7
  View,
@@ -10,23 +9,36 @@ import {
10
9
  import type { PickerStyles } from '../theme/styleKeys';
11
10
  import type { ThemeTokens } from '../theme/tokens';
12
11
  import type { SheetRenderProps, SheetSize } from '../types';
13
- import { buildContainerStyles } from './containerStyles';
12
+ import { useBottomInset } from '../hooks/useBottomInset';
13
+ import { useKeyboard } from '../hooks/useKeyboardFold';
14
+ import { buildContainerStyles, SHEET_PADDING_BOTTOM } from './containerStyles';
14
15
 
15
16
  interface Props extends SheetRenderProps {
16
17
  height?: SheetSize;
17
18
  maxHeight?: SheetSize;
19
+ keyboardMaxHeight?: SheetSize;
20
+ /** Space kept free below the footer; default: the app's safe-area inset. */
21
+ bottomInset?: number;
22
+ /** The backdrop's screen-reader label. */
23
+ closeLabel: string;
18
24
  tokens: ThemeTokens;
19
25
  styles?: PickerStyles;
20
26
  }
21
27
 
28
+ /** The least room the sheet gets while the keyboard is up, in points. */
29
+ const MIN_ROOM = 160;
30
+
22
31
  /** Points for a size given in points or as a percentage of the screen. */
23
32
  const toPoints = (size: SheetSize, screen: number): number =>
24
33
  typeof size === 'number' ? size : (screen * parseFloat(size)) / 100;
25
34
 
26
35
  /**
27
36
  * The built-in bottom sheet: an RN Modal with a backdrop and a panel pinned to
28
- * the bottom, up to 90% of the screen (`sheet.height` / `sheet.maxHeight`). Backdrop taps and Android back call
29
- * onRequestClose. `styles.sheet` styles the panel (e.g. a bottom safe-area inset);
37
+ * the bottom, up to 90% of the screen (`sheet.height` / `sheet.maxHeight`).
38
+ * While the keyboard is up it sits on the keyboard, within `sheet.keyboardMaxHeight`
39
+ * (default `maxHeight`) of the room above it; otherwise it keeps the bottom
40
+ * safe-area inset (`sheet.bottomInset`) free below the footer. Backdrop taps
41
+ * and Android back call onRequestClose. `styles.sheet` styles the panel;
30
42
  * `renderSheet` replaces the whole sheet.
31
43
  */
32
44
  const DefaultSheet: React.FC<Props> = ({
@@ -36,15 +48,36 @@ const DefaultSheet: React.FC<Props> = ({
36
48
  testID,
37
49
  height,
38
50
  maxHeight = '90%',
51
+ keyboardMaxHeight = maxHeight,
52
+ bottomInset,
53
+ closeLabel,
39
54
  tokens,
40
55
  styles,
41
56
  }) => {
42
57
  const { height: screen } = useWindowDimensions();
43
- const max = toPoints(maxHeight, screen);
58
+ const keyboard = useKeyboard(true);
59
+ // The room above the keyboard: measured (padding on iOS, the window on
60
+ // Android), and the screen less the keyboard for an Android window that
61
+ // isn't resized.
62
+ const [measured, setMeasured] = useState(screen);
63
+ // Never less than a strip to show the sheet in, even when the keyboard
64
+ // reports itself as tall as the window (split screen, Slide Over).
65
+ const room = Math.max(
66
+ Math.min(measured, screen - keyboard.height),
67
+ Math.min(screen, MIN_ROOM)
68
+ );
69
+ const max = keyboard.up
70
+ ? Math.min(toPoints(keyboardMaxHeight, room), room)
71
+ : toPoints(maxHeight, screen);
44
72
  const size =
45
73
  height === undefined
46
74
  ? { maxHeight: max }
47
75
  : { height: Math.min(toPoints(height, screen), max) };
76
+ // Below the footer: the home indicator or Android's navigation bar, which
77
+ // an edge-to-edge app draws under. While the keyboard is up the sheet sits
78
+ // on the keyboard instead, with nothing under it.
79
+ const safeInset = useBottomInset();
80
+ const inset = keyboard.up ? 0 : Math.max(0, bottomInset ?? safeInset);
48
81
  const s = buildContainerStyles(tokens);
49
82
  return (
50
83
  <Modal
@@ -54,20 +87,33 @@ const DefaultSheet: React.FC<Props> = ({
54
87
  statusBarTranslucent
55
88
  onRequestClose={onRequestClose}
56
89
  >
57
- <KeyboardAvoidingView
58
- behavior={Platform.OS === 'ios' ? 'padding' : undefined}
59
- style={s.sheetRoot}
60
- >
90
+ {/* Pads by the part of the screen the keyboard covers: all of it in an
91
+ edge-to-edge Android app, whose window the keyboard doesn't resize;
92
+ none where the window does shrink. */}
93
+ <KeyboardAvoidingView behavior="padding" style={s.sheetRoot}>
61
94
  <Pressable
62
95
  testID={testID ? `${testID}-backdrop` : undefined}
63
96
  accessibilityRole="button"
64
- accessibilityLabel="Close"
97
+ accessibilityLabel={closeLabel}
65
98
  onPress={onRequestClose}
66
99
  style={[s.sheetBackdrop, styles?.sheetBackdrop]}
67
100
  />
68
- <View testID={testID} style={[s.sheet, size, styles?.sheet]}>
69
- {body}
70
- {footer}
101
+ <View
102
+ style={s.sheetRoom}
103
+ onLayout={(e) => setMeasured(e.nativeEvent.layout.height)}
104
+ >
105
+ <View
106
+ testID={testID}
107
+ style={[
108
+ s.sheet,
109
+ size,
110
+ inset > 0 && { paddingBottom: SHEET_PADDING_BOTTOM + inset },
111
+ styles?.sheet,
112
+ ]}
113
+ >
114
+ {body}
115
+ {footer}
116
+ </View>
71
117
  </View>
72
118
  </KeyboardAvoidingView>
73
119
  </Modal>
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  import { View } from 'react-native';
3
+ import { DEFAULT_STRINGS } from '../theme/defaultStrings';
3
4
  import type { SheetOptions, SheetRenderProps } from '../types';
4
5
  import DefaultSheet from './DefaultSheet';
5
6
  import { buildPickerLayout, type PickerLayoutProps } from './PickerLayout';
@@ -52,6 +53,9 @@ const PickerContainer: React.FC<PickerContainerProps> = ({
52
53
  {...p}
53
54
  height={sheet?.height}
54
55
  maxHeight={sheet?.maxHeight}
56
+ keyboardMaxHeight={sheet?.keyboardMaxHeight}
57
+ bottomInset={sheet?.bottomInset}
58
+ closeLabel={layout.state.strings.a11yClose ?? DEFAULT_STRINGS.a11yClose}
55
59
  tokens={layout.state.tokens}
56
60
  styles={layout.styles}
57
61
  />
@@ -134,7 +134,7 @@ export const buildPickerLayout = ({
134
134
  keyboardShouldPersistTaps="handled"
135
135
  nestedScrollEnabled
136
136
  bounces={false}
137
- showsVerticalScrollIndicator
137
+ showsVerticalScrollIndicator={false}
138
138
  >
139
139
  {headerScrolls ? headerNode : null}
140
140
  {content}
@@ -2,12 +2,20 @@ import { StyleSheet } from 'react-native';
2
2
  import { fontStyle, type ThemeTokens } from '../theme/tokens';
3
3
 
4
4
  const GUTTER = 16;
5
+ /** Space under the sheet's footer, before any bottom inset. */
6
+ export const SHEET_PADDING_BOTTOM = 8;
5
7
 
6
8
  const cache = new WeakMap<ThemeTokens, ReturnType<typeof create>>();
7
9
 
8
10
  const create = (t: ThemeTokens) =>
9
11
  StyleSheet.create({
10
- sheetRoot: { flex: 1, justifyContent: 'flex-end' },
12
+ sheetRoot: { flex: 1 },
13
+ // The room above the keyboard (all of the screen while it's down); the panel sits at its bottom.
14
+ sheetRoom: {
15
+ flex: 1,
16
+ justifyContent: 'flex-end',
17
+ pointerEvents: 'box-none',
18
+ },
11
19
  sheetBackdrop: {
12
20
  ...StyleSheet.absoluteFill,
13
21
  backgroundColor: 'rgba(0, 0, 0, 0.4)',
@@ -16,7 +24,7 @@ const create = (t: ThemeTokens) =>
16
24
  borderTopLeftRadius: t.radius * 2,
17
25
  borderTopRightRadius: t.radius * 2,
18
26
  backgroundColor: t.background,
19
- paddingBottom: 24,
27
+ paddingBottom: SHEET_PADDING_BOTTOM,
20
28
  },
21
29
  container: { width: '100%', paddingHorizontal: GUTTER },
22
30
  // In a sheet the body shrinks to the sheet's max height and scrolls.
@@ -30,7 +38,8 @@ const create = (t: ThemeTokens) =>
30
38
  flexDirection: 'row',
31
39
  alignItems: 'center',
32
40
  justifyContent: 'space-between',
33
- paddingTop: 8,
41
+ // Room between the sheet's top edge and the title.
42
+ paddingTop: 24,
34
43
  paddingBottom: 12,
35
44
  },
36
45
  title: {
@@ -8,7 +8,7 @@ import type { PickerStyles } from '../theme/styleKeys';
8
8
  import type { ThemeTokens } from '../theme/tokens';
9
9
  import type { LabelRenderProps } from '../types';
10
10
  import FieldMessages from './FieldMessages';
11
- import { formatRangeText } from './fieldText';
11
+ import { formatRangeText, type DateTextFormatter } from './fieldText';
12
12
  import ValueField from './ValueField';
13
13
 
14
14
  export type RangeEnd = 'from' | 'to';
@@ -30,6 +30,8 @@ interface Props {
30
30
  errorMessage?: string;
31
31
  type: PickerType;
32
32
  dateFormat: string;
33
+ /** Writes the shown dates another way (as Hijri dates). Not used while typing. */
34
+ dateText?: DateTextFormatter;
33
35
  timeFormat: TimeFormat;
34
36
  yearRange?: { first: number; last: number };
35
37
  disabled?: boolean;
@@ -45,6 +47,8 @@ interface Props {
45
47
  tokens: ThemeTokens;
46
48
  styles?: PickerStyles;
47
49
  strings: PickerStrings;
50
+ /** The texts of the typed-input errors. Default `strings`. */
51
+ errorStrings?: PickerStrings;
48
52
  testID?: string;
49
53
  }
50
54
 
@@ -70,6 +74,7 @@ const RangeFields: React.FC<Props> = (props) => {
70
74
  errorMessage,
71
75
  type,
72
76
  dateFormat,
77
+ dateText,
73
78
  timeFormat,
74
79
  yearRange,
75
80
  disabled,
@@ -81,11 +86,13 @@ const RangeFields: React.FC<Props> = (props) => {
81
86
  tokens,
82
87
  styles,
83
88
  strings,
89
+ errorStrings,
84
90
  testID,
85
91
  } = props;
86
92
  const common = {
87
93
  type,
88
94
  dateFormat,
95
+ dateText,
89
96
  timeFormat,
90
97
  yearRange,
91
98
  renderLabel,
@@ -94,6 +101,7 @@ const RangeFields: React.FC<Props> = (props) => {
94
101
  tokens,
95
102
  styles,
96
103
  strings,
104
+ errorStrings,
97
105
  disabled,
98
106
  };
99
107
 
@@ -108,7 +116,9 @@ const RangeFields: React.FC<Props> = (props) => {
108
116
  type,
109
117
  dateFormat,
110
118
  timeFormat,
111
- strings.rangeSeparator
119
+ strings.rangeSeparator,
120
+ dateText,
121
+ strings
112
122
  )}
113
123
  placeholder={placeholder}
114
124
  allowClear={allowClear}
@@ -12,10 +12,12 @@ import type {
12
12
  SegmentEditorAction,
13
13
  SegmentEditorState,
14
14
  } from '../../core/segmentEditor';
15
+ import { toLatinDigits } from '../../core/digits';
15
16
  import type { Period, SegmentKey, SegmentSpec } from '../../core/segments';
16
17
  import type { PickerStrings } from '../theme/defaultStrings';
17
18
  import type { PickerStyles } from '../theme/styleKeys';
18
19
  import { MAX_FONT_SCALE } from '../theme/a11y';
20
+ import { useNumerals } from '../theme/numerals';
19
21
  import type { ThemeTokens } from '../theme/tokens';
20
22
  import { buildFieldStyles } from './fieldStyles';
21
23
 
@@ -105,6 +107,7 @@ const SegmentedInput: React.FC<Props> = ({
105
107
  fieldLabel,
106
108
  testID,
107
109
  }) => {
110
+ const digits = useNumerals();
108
111
  // Each box's text as last rendered, and as it last reported. Fast input (a
109
112
  // hardware keyboard, autofill) sends the next character before React has
110
113
  // re-rendered, and the native box may ignore React's reset while it's
@@ -188,7 +191,7 @@ const SegmentedInput: React.FC<Props> = ({
188
191
  }}
189
192
  testID={testID ? `${testID}-segment-${spec.key}` : undefined}
190
193
  accessibilityLabel={labels[spec.key]}
191
- value={text}
194
+ value={digits(text)}
192
195
  placeholder={placeholders[spec.key]}
193
196
  placeholderTextColor={tokens.placeholder}
194
197
  keyboardType="number-pad"
@@ -204,8 +207,10 @@ const SegmentedInput: React.FC<Props> = ({
204
207
  dispatch({ type: 'blur' });
205
208
  }}
206
209
  onKeyPress={onKeyPress}
207
- onChangeText={(next) => {
210
+ onChangeText={(raw) => {
208
211
  claimFocus();
212
+ // An Arabic or Persian number pad types ٠–٩ / ۰–۹.
213
+ const next = toLatinDigits(raw);
209
214
  const { rendered, reported } = track;
210
215
  const before =
211
216
  reported !== undefined &&
@@ -287,7 +292,7 @@ const SegmentedInput: React.FC<Props> = ({
287
292
  {dateSpecs.map((spec, i) => renderNumeric(spec, i))}
288
293
  </View>
289
294
  {timeSpecs.length ? (
290
- <View style={s.segmentGroup}>
295
+ <View style={[s.segmentGroup, dateSpecs.length > 0 && s.segmentTime]}>
291
296
  {timeSpecs.map((spec, i) =>
292
297
  spec.key === 'period' ? renderPeriod() : renderNumeric(spec, i)
293
298
  )}
@@ -1,5 +1,5 @@
1
1
  import React, { useEffect, useRef, useState } from 'react';
2
- import { Pressable, Text, View } from 'react-native';
2
+ import { Pressable, ScrollView, Text, View } from 'react-native';
3
3
  import type { SegmentEditorAction } from '../../core/segmentEditor';
4
4
  import type { ParsedSegments } from '../../core/segments';
5
5
  import type { DateTimeValue, PickerType, TimeFormat } from '../../core/types';
@@ -11,19 +11,33 @@ import {
11
11
  type IconSet,
12
12
  } from '../../icons';
13
13
  import { useTypedSegments } from '../hooks/useTypedSegments';
14
+ import type { ScrollViewRef } from '../nativeTypes';
14
15
  import type { PickerStrings } from '../theme/defaultStrings';
15
16
  import type { PickerStyles } from '../theme/styleKeys';
17
+ import { useNumerals } from '../theme/numerals';
16
18
  import type { ThemeTokens } from '../theme/tokens';
17
19
  import type { InstructionRenderProps, LabelRenderProps } from '../types';
18
20
  import FieldMessages from './FieldMessages';
19
21
  import {
22
+ formatValueParts,
20
23
  formatValueText,
21
24
  placeholderText,
22
25
  segmentErrorText,
26
+ type DateTextFormatter,
23
27
  } from './fieldText';
24
28
  import { buildFieldStyles } from './fieldStyles';
25
29
  import SegmentedInput from './SegmentedInput';
26
30
 
31
+ // Hebrew and Arabic letters; Arabic-Indic digits (٠–٩, ۰–۹) are left out, since
32
+ // digits don't set the reading direction.
33
+ const RTL_LETTER = '֐-׿؀-ٟ٪-ۯۺ-ࣿ';
34
+ const FIRST_LETTER_RTL = new RegExp(
35
+ `^[^A-Za-zÀ-ɏ${RTL_LETTER}]*[${RTL_LETTER}]`
36
+ );
37
+ /** Whether a text reads right to left: its first letter is Hebrew or Arabic. */
38
+ export const startsRightToLeft = (text: string): boolean =>
39
+ FIRST_LETTER_RTL.test(text);
40
+
27
41
  export interface ValueFieldProps {
28
42
  type: PickerType;
29
43
  /** The value to show (or to start typing from). */
@@ -32,6 +46,8 @@ export interface ValueFieldProps {
32
46
  displayText?: string;
33
47
  /** Date format, e.g. 'dd/MM/yyyy'. */
34
48
  dateFormat: string;
49
+ /** Writes the shown date another way (as a Hijri date). Not used while typing. */
50
+ dateText?: DateTextFormatter;
35
51
  timeFormat: TimeFormat;
36
52
  yearRange?: { first: number; last: number };
37
53
  /** Typed date + time segments. Otherwise the field shows text and opens the picker on tap. */
@@ -75,6 +91,8 @@ export interface ValueFieldProps {
75
91
  tokens: ThemeTokens;
76
92
  styles?: PickerStyles;
77
93
  strings: PickerStrings;
94
+ /** The texts of its typed-input errors. Default `strings`. */
95
+ errorStrings?: PickerStrings;
78
96
  testID?: string;
79
97
  }
80
98
 
@@ -123,11 +141,13 @@ const DefaultInstruction: React.FC<
123
141
  * results go to `onTyped`, and the sheet decides what to do with them.
124
142
  */
125
143
  const ValueField: React.FC<ValueFieldProps> = (props) => {
144
+ const digits = useNumerals();
126
145
  const {
127
146
  type,
128
147
  value,
129
148
  displayText,
130
149
  dateFormat,
150
+ dateText,
131
151
  timeFormat,
132
152
  yearRange,
133
153
  allowTyping,
@@ -154,17 +174,20 @@ const ValueField: React.FC<ValueFieldProps> = (props) => {
154
174
  tokens,
155
175
  styles,
156
176
  strings,
177
+ errorStrings = strings,
157
178
  testID,
158
179
  } = props;
159
180
  const s = buildFieldStyles(tokens);
160
181
  const ico = resolveIcons(iconOverrides);
182
+ const scrollRef = useRef<ScrollViewRef>(null);
161
183
  const [lastParsed, setLastParsed] = useState<ParsedSegments | null>(null);
162
184
  const { state, dispatch, getState } = useTypedSegments(
163
185
  value,
164
186
  { dateFormat, type, timeFormat, yearRange },
165
- (parsed) => {
187
+ (parsed, fromOutside) => {
166
188
  setLastParsed(parsed);
167
- onTyped?.(parsed);
189
+ // A value shown from outside (a calendar tap) isn't an edit.
190
+ if (!fromOutside) onTyped?.(parsed);
168
191
  }
169
192
  );
170
193
 
@@ -198,12 +221,25 @@ const ValueField: React.FC<ValueFieldProps> = (props) => {
198
221
  const typing = !!allowTyping && editable;
199
222
  const typedError =
200
223
  typing && !state.focused && lastParsed && !lastParsed.isEmpty
201
- ? segmentErrorText(lastParsed.errors, strings, yearRange)
224
+ ? segmentErrorText(lastParsed.errors, errorStrings, yearRange)
202
225
  : '';
203
226
  const error = typedError || errorMessage || '';
204
227
  const hasValue = typing ? !state.parsed.isEmpty : !!value || !!displayText;
205
228
  const text =
206
- displayText ?? formatValueText(value, type, dateFormat, timeFormat);
229
+ displayText ??
230
+ formatValueText(value, type, dateFormat, timeFormat, dateText, strings);
231
+ // With a fieldDateText style, a single date-time shows its date and time
232
+ // apart (no sideways scroll).
233
+ const valueParts =
234
+ styles?.fieldDateText && displayText === undefined && value
235
+ ? formatValueParts(value, type, dateFormat, timeFormat, dateText, strings)
236
+ : null;
237
+ const parts = valueParts?.time ? valueParts : null;
238
+ const valueStyle = [
239
+ s.text,
240
+ styles?.fieldText,
241
+ disabled && [s.disabledText, styles?.fieldTextDisabled],
242
+ ];
207
243
 
208
244
  const clear = () => {
209
245
  dispatch({ type: 'reset', value: null });
@@ -292,19 +328,59 @@ const ValueField: React.FC<ValueFieldProps> = (props) => {
292
328
  onPress={onPress}
293
329
  style={fieldStyle}
294
330
  >
295
- <Text
296
- numberOfLines={1}
297
- style={[
298
- s.text,
299
- styles?.fieldText,
300
- !text && [s.placeholder, styles?.fieldPlaceholder],
301
- disabled && [s.disabledText, text ? styles?.fieldTextDisabled : null],
302
- ]}
303
- >
304
- {text ||
305
- placeholder ||
306
- placeholderText(type, dateFormat, timeFormat, strings)}
307
- </Text>
331
+ {parts ? (
332
+ <>
333
+ <Text
334
+ numberOfLines={1}
335
+ ellipsizeMode="clip"
336
+ style={[valueStyle, s.textScrolled, styles?.fieldDateText]}
337
+ >
338
+ {digits(`${parts.date}${strings.dateTimeSeparator ?? ' '}`)}
339
+ </Text>
340
+ <Text numberOfLines={1} ellipsizeMode="clip" style={valueStyle}>
341
+ {digits(parts.time)}
342
+ </Text>
343
+ </>
344
+ ) : text ? (
345
+ // A value too long for the box scrolls sideways; a tap still opens.
346
+ <ScrollView
347
+ ref={scrollRef}
348
+ horizontal
349
+ showsHorizontalScrollIndicator={false}
350
+ keyboardShouldPersistTaps="always"
351
+ style={s.textScroll}
352
+ contentContainerStyle={s.textScrollContent}
353
+ // Right-to-left text (a Hijri date) starts at its right end.
354
+ onContentSizeChange={() => {
355
+ if (startsRightToLeft(text))
356
+ scrollRef.current?.scrollToEnd({ animated: false });
357
+ }}
358
+ >
359
+ <Text
360
+ numberOfLines={1}
361
+ // Android can measure a line a pixel short (right-to-left text
362
+ // most often) and would then swap its last word for "…".
363
+ ellipsizeMode="clip"
364
+ style={[valueStyle, s.textScrolled]}
365
+ >
366
+ {digits(text)}
367
+ </Text>
368
+ </ScrollView>
369
+ ) : (
370
+ <Text
371
+ numberOfLines={1}
372
+ style={[
373
+ s.text,
374
+ styles?.fieldText,
375
+ s.placeholder,
376
+ styles?.fieldPlaceholder,
377
+ disabled && s.disabledText,
378
+ ]}
379
+ >
380
+ {placeholder ||
381
+ placeholderText(type, dateFormat, timeFormat, strings)}
382
+ </Text>
383
+ )}
308
384
  {icons}
309
385
  </Pressable>
310
386
  );
@@ -32,6 +32,10 @@ const create = (t: ThemeTokens) =>
32
32
  fontSize: t.fontSizeMedium,
33
33
  color: t.text,
34
34
  },
35
+ textScroll: { flex: 1 },
36
+ textScrollContent: { flexGrow: 1, alignItems: 'center' },
37
+ // In the scroll, or as a date set apart from its time, the text keeps its full width.
38
+ textScrolled: { flex: 0, flexShrink: 0 },
35
39
  placeholder: { color: t.placeholder },
36
40
  disabledText: { color: t.disabledText },
37
41
  icons: { flexDirection: 'row', alignItems: 'center', marginStart: 8 },
@@ -55,6 +59,8 @@ const create = (t: ThemeTokens) =>
55
59
  alignItems: 'center',
56
60
  flexWrap: 'nowrap',
57
61
  },
62
+ // After a date, the time sits in the middle of the space left before the icons.
63
+ segmentTime: { flexGrow: 1, justifyContent: 'center' },
58
64
  segment: {
59
65
  paddingVertical: 8,
60
66
  paddingHorizontal: 0,