@btndprojects/loam-ui-native 0.1.0 → 0.2.1

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 (263) hide show
  1. package/README.md +56 -0
  2. package/dist/accordion/index.js +5 -3
  3. package/dist/adaptive/index.js +6 -2
  4. package/dist/alert/index.js +5 -2
  5. package/dist/analyzer/index.js +9 -6
  6. package/dist/announcement/index.js +8 -5
  7. package/dist/audio-player/index.js +5 -3
  8. package/dist/avatar/index.js +5 -2
  9. package/dist/avatar-group/index.js +7 -3
  10. package/dist/badge/index.js +7 -4
  11. package/dist/banner/index.js +5 -2
  12. package/dist/board/index.js +11 -6
  13. package/dist/button/index.js +6 -3
  14. package/dist/camera-permission/index.js +15 -12
  15. package/dist/capture-result/index.js +19 -16
  16. package/dist/card/index.js +6 -3
  17. package/dist/card-form/index.js +12 -8
  18. package/dist/carousel/index.js +4 -2
  19. package/dist/chart/index.js +8 -5
  20. package/dist/charts/index.js +8 -6
  21. package/dist/chat/index.js +16 -0
  22. package/dist/checkbox/index.js +6 -4
  23. package/dist/checklist/index.js +11 -8
  24. package/dist/checkout/index.js +16 -11
  25. package/dist/chip/index.js +7 -4
  26. package/dist/{chunk-XNUVB5OL.js → chunk-2OLKPG4E.js} +92 -28
  27. package/dist/{chunk-RUZHTGKB.js → chunk-2PKYGLQ6.js} +71 -40
  28. package/dist/{chunk-UC2WGUP3.js → chunk-2SWKL3AJ.js} +91 -252
  29. package/dist/{chunk-AI4DWZCD.js → chunk-2SY63FCH.js} +63 -16
  30. package/dist/{chunk-F5XNPWS7.js → chunk-2TXERVVA.js} +92 -35
  31. package/dist/chunk-36EC2T6P.js +581 -0
  32. package/dist/chunk-3DUWIYV5.js +437 -0
  33. package/dist/{chunk-RGQWWKLA.js → chunk-3QMEOFW5.js} +275 -71
  34. package/dist/chunk-3WEZCGHX.js +265 -0
  35. package/dist/chunk-46MMSDGL.js +194 -0
  36. package/dist/{chunk-7O2FMUPT.js → chunk-4IZXHVFJ.js} +297 -92
  37. package/dist/{chunk-LAECSR4H.js → chunk-5LAAAXFP.js} +14 -8
  38. package/dist/{chunk-2A5NIQAK.js → chunk-5RENVKBQ.js} +134 -46
  39. package/dist/{chunk-2ZZ7TDJ4.js → chunk-5UTRIXQ6.js} +37 -31
  40. package/dist/{chunk-LOE5YNN3.js → chunk-5VFZRGVD.js} +37 -10
  41. package/dist/{chunk-52X2VYTD.js → chunk-67IZZ2MJ.js} +115 -60
  42. package/dist/{chunk-UYG5L34B.js → chunk-6YAQBXB3.js} +10 -4
  43. package/dist/{chunk-BTTFCMKG.js → chunk-74FLKD24.js} +94 -23
  44. package/dist/{chunk-ITTYJZWX.js → chunk-7BUIKDD6.js} +73 -18
  45. package/dist/{chunk-FOKG57CR.js → chunk-7OVVSVEZ.js} +273 -109
  46. package/dist/chunk-AEB7KCHQ.js +287 -0
  47. package/dist/chunk-APCWFOZW.js +28 -0
  48. package/dist/chunk-AWKQIE5I.js +139 -0
  49. package/dist/{chunk-VCDBXW5H.js → chunk-B7N4ASYE.js} +86 -42
  50. package/dist/{chunk-IVNRBPGC.js → chunk-C4GTDLRC.js} +104 -20
  51. package/dist/{chunk-4ZAHCY44.js → chunk-C6APNDVA.js} +12 -5
  52. package/dist/{chunk-4SZYY6AN.js → chunk-CMTVNF3D.js} +18 -13
  53. package/dist/{chunk-WVKKJA6U.js → chunk-CPTOADB2.js} +151 -96
  54. package/dist/chunk-D5N5QWI7.js +1325 -0
  55. package/dist/{chunk-IIQTAY3J.js → chunk-DN7MNQIP.js} +113 -29
  56. package/dist/{chunk-47FWHGUN.js → chunk-DVGBZ3TX.js} +84 -23
  57. package/dist/chunk-DW3L54DQ.js +305 -0
  58. package/dist/{chunk-3ARE4TES.js → chunk-E2E3I5W2.js} +69 -18
  59. package/dist/{chunk-DHWADYZX.js → chunk-EDCBJV7J.js} +41 -28
  60. package/dist/{chunk-WSW6ZFAQ.js → chunk-ENP3BMZU.js} +4 -4
  61. package/dist/{chunk-OOPPQH27.js → chunk-EVOIGUBI.js} +43 -19
  62. package/dist/{chunk-VEAYTRPX.js → chunk-EY4DD67D.js} +165 -97
  63. package/dist/{chunk-223Q2T2Q.js → chunk-F3H33DQX.js} +132 -61
  64. package/dist/{chunk-CYRBHQQZ.js → chunk-F5B3UINI.js} +68 -35
  65. package/dist/{chunk-6X6PQ443.js → chunk-FAJI7BSC.js} +20 -9
  66. package/dist/{chunk-MOUJOP55.js → chunk-FUMHAAF3.js} +96 -29
  67. package/dist/{chunk-6HT2LP62.js → chunk-FV6HMP7W.js} +192 -73
  68. package/dist/{chunk-S7F6XLTK.js → chunk-FYWNRX4F.js} +76 -47
  69. package/dist/{chunk-YG3ZJHGU.js → chunk-FZGAAOKS.js} +30 -8
  70. package/dist/{chunk-YDGVJETP.js → chunk-G3AFC24V.js} +1 -1
  71. package/dist/{chunk-EJBDRVIH.js → chunk-G6UESEVN.js} +15 -8
  72. package/dist/chunk-GDKVKNR2.js +339 -0
  73. package/dist/chunk-GEIGMWNF.js +10 -0
  74. package/dist/{chunk-JUAMLEHX.js → chunk-H7DWSL4O.js} +24 -12
  75. package/dist/chunk-HJFFOOJ4.js +1 -0
  76. package/dist/{chunk-RW6ZL2FQ.js → chunk-HJLPZA4X.js} +106 -21
  77. package/dist/chunk-HYEOQWT7.js +647 -0
  78. package/dist/chunk-I2KLQ2HA.js +19 -0
  79. package/dist/{chunk-CJ5EOYZE.js → chunk-I4FHVKEC.js} +11 -5
  80. package/dist/{chunk-JNH2TYIN.js → chunk-IDM7JJMO.js} +19 -5
  81. package/dist/{chunk-O4AEHWII.js → chunk-IPUNJMAQ.js} +141 -49
  82. package/dist/{chunk-J7Q7VCVC.js → chunk-IT6FUXXG.js} +13 -6
  83. package/dist/{chunk-QJJ6MADV.js → chunk-IVKMZ7BB.js} +80 -28
  84. package/dist/{chunk-Z7H7VSFZ.js → chunk-IXKWIFWZ.js} +17 -6
  85. package/dist/chunk-J64KGCGX.js +55 -0
  86. package/dist/chunk-JBMLWFSJ.js +270 -0
  87. package/dist/{chunk-4BXMXBJO.js → chunk-JJLPBRVZ.js} +22 -11
  88. package/dist/chunk-JLC6PM5S.js +406 -0
  89. package/dist/chunk-JUYWSSKW.js +335 -0
  90. package/dist/{chunk-7CFF4HXS.js → chunk-JV5YOTOB.js} +49 -11
  91. package/dist/{chunk-LZLHELAG.js → chunk-KFJGFLMW.js} +29 -8
  92. package/dist/{chunk-O7AE6DAF.js → chunk-KQZ3GLHR.js} +18 -8
  93. package/dist/{chunk-N32RGOA5.js → chunk-LKFC4CS7.js} +80 -24
  94. package/dist/{chunk-YC6WORFL.js → chunk-LMPHCVJJ.js} +82 -50
  95. package/dist/{chunk-3WPW4KUN.js → chunk-LQP4KEXZ.js} +45 -13
  96. package/dist/{chunk-TKQYWZ5V.js → chunk-LUMVGO2K.js} +47 -31
  97. package/dist/{chunk-AWJOCGFZ.js → chunk-M656FYNH.js} +25 -13
  98. package/dist/{chunk-35OFI3JG.js → chunk-MKSNFG7H.js} +73 -20
  99. package/dist/{chunk-4GBOGOTV.js → chunk-NBEF4EPJ.js} +16 -6
  100. package/dist/chunk-NNCOFLNE.js +24 -0
  101. package/dist/{chunk-4YQOR7JM.js → chunk-NTQ2F3AU.js} +73 -20
  102. package/dist/{chunk-QCDXZBC5.js → chunk-O5V4TG3V.js} +126 -44
  103. package/dist/{chunk-U7TFM2JA.js → chunk-OJQUBQWA.js} +3 -3
  104. package/dist/{chunk-VQHPQEUH.js → chunk-OWAMM2DK.js} +13 -6
  105. package/dist/chunk-PID3NJB7.js +405 -0
  106. package/dist/{chunk-66SG2H23.js → chunk-PMMTGBBS.js} +27 -17
  107. package/dist/{chunk-RIBDXGUG.js → chunk-PNF3NKB5.js} +49 -16
  108. package/dist/{chunk-JXJB2X6M.js → chunk-Q6NKEPRE.js} +81 -32
  109. package/dist/chunk-QDZGFXQD.js +176 -0
  110. package/dist/{chunk-SYNOJOQO.js → chunk-QEYFDRHR.js} +60 -26
  111. package/dist/{chunk-VBOXAEPI.js → chunk-QHAITQIF.js} +97 -22
  112. package/dist/{chunk-VXDZFJGP.js → chunk-QHTVYA65.js} +230 -76
  113. package/dist/{chunk-TUTI5HOZ.js → chunk-QIKT7LIB.js} +14 -8
  114. package/dist/{chunk-3ENTMPQY.js → chunk-QP3KMOVF.js} +82 -42
  115. package/dist/{chunk-GNNJ4GCC.js → chunk-QPWDDJJ4.js} +62 -148
  116. package/dist/{chunk-QWCMU5B2.js → chunk-QRUMA22E.js} +205 -80
  117. package/dist/{chunk-ZVFE5QGU.js → chunk-QYPE5JX3.js} +50 -10
  118. package/dist/{chunk-PUPM2YGF.js → chunk-ROCUG24E.js} +76 -36
  119. package/dist/{chunk-NQYBUO3K.js → chunk-RU3ZPNL6.js} +333 -142
  120. package/dist/{chunk-TOXAGRDQ.js → chunk-RXSCIO6W.js} +14 -5
  121. package/dist/{chunk-FIF2M24N.js → chunk-SATMR6SG.js} +631 -203
  122. package/dist/{chunk-4YIP3CWS.js → chunk-SHHY5OMK.js} +7 -5
  123. package/dist/chunk-SKWO3SZF.js +2284 -0
  124. package/dist/{chunk-YF4NSSMT.js → chunk-SWS5JQIF.js} +41 -13
  125. package/dist/{chunk-CUMUNPXY.js → chunk-T5LTPKX6.js} +15 -7
  126. package/dist/{chunk-H6NIOQHK.js → chunk-TDMG26JI.js} +26 -6
  127. package/dist/{chunk-UWFLYMAR.js → chunk-TLCIR6RG.js} +267 -126
  128. package/dist/{chunk-SBMNWWBV.js → chunk-TN2ZNJUI.js} +47 -9
  129. package/dist/{chunk-5YNTNN5A.js → chunk-TQVAIKFD.js} +106 -41
  130. package/dist/chunk-TRGFFU6A.js +1456 -0
  131. package/dist/{chunk-2GK6PHGE.js → chunk-TY4MTKQJ.js} +100 -22
  132. package/dist/{chunk-AZRX6SAC.js → chunk-U23FYWME.js} +15 -7
  133. package/dist/{chunk-PZXZJBMP.js → chunk-U5NLHYV6.js} +26 -12
  134. package/dist/chunk-UQEN55EY.js +1 -0
  135. package/dist/chunk-UQGBTPXH.js +218 -0
  136. package/dist/chunk-UXGIW7OK.js +116 -0
  137. package/dist/{chunk-PJXUJYS6.js → chunk-UYGDJWMN.js} +55 -30
  138. package/dist/{chunk-QDYDBCFP.js → chunk-V2OEB75Z.js} +50 -51
  139. package/dist/{chunk-LSS54GLJ.js → chunk-VAOAKWUK.js} +34 -13
  140. package/dist/{chunk-DM5QUKKO.js → chunk-VDPK5CY4.js} +18 -6
  141. package/dist/chunk-W23G6JLF.js +37 -0
  142. package/dist/{chunk-CDRZHT42.js → chunk-W63AJTM7.js} +276 -12
  143. package/dist/{chunk-XXXEFXY5.js → chunk-W74TXYFB.js} +13 -5
  144. package/dist/{chunk-LRJNDEIA.js → chunk-WRDSPUE7.js} +144 -29
  145. package/dist/{chunk-C2NTXVWM.js → chunk-XBZGDDMR.js} +11 -4
  146. package/dist/{chunk-BV3B2HYZ.js → chunk-XIDTBCBA.js} +189 -131
  147. package/dist/{chunk-DSJBXLUG.js → chunk-XN4KG3P4.js} +348 -153
  148. package/dist/chunk-XQXMLMH3.js +211 -0
  149. package/dist/{chunk-HPPW424V.js → chunk-XTORZWRF.js} +19 -8
  150. package/dist/{chunk-P23EQNRQ.js → chunk-YAAHPATV.js} +181 -30
  151. package/dist/{chunk-KMI5ML5I.js → chunk-YXOAPXMU.js} +57 -18
  152. package/dist/{chunk-RJQOOHT2.js → chunk-ZECZOOSB.js} +59 -28
  153. package/dist/{chunk-QKXCPTFS.js → chunk-ZLTO5VQI.js} +121 -31
  154. package/dist/{chunk-BEDBFJND.js → chunk-ZVATDZOM.js} +16 -18
  155. package/dist/coachmark/index.js +6 -3
  156. package/dist/code-block/index.js +5 -3
  157. package/dist/color-field/index.js +6 -4
  158. package/dist/commerce/index.js +19 -16
  159. package/dist/connectivity/index.js +5 -2
  160. package/dist/context-menu/index.js +5 -3
  161. package/dist/copy-button/index.js +4 -2
  162. package/dist/data-grid/index.js +21 -16
  163. package/dist/date-range-picker/index.js +11 -8
  164. package/dist/description-list/index.js +3 -1
  165. package/dist/dialog/index.js +4 -2
  166. package/dist/empty-state/index.js +4 -2
  167. package/dist/error-summary/index.js +4 -2
  168. package/dist/fab/index.js +5 -2
  169. package/dist/file-manager/index.js +28 -0
  170. package/dist/file-upload/index.js +10 -7
  171. package/dist/filter-bar/index.js +9 -6
  172. package/dist/flow-run/index.js +15 -12
  173. package/dist/form/index.js +5 -3
  174. package/dist/gallery/index.js +5 -2
  175. package/dist/hold-to-confirm/index.js +4 -2
  176. package/dist/index.d.ts +9557 -2985
  177. package/dist/index.js +355 -122
  178. package/dist/infinite-list/index.js +4 -2
  179. package/dist/inline-edit/index.js +6 -4
  180. package/dist/input/index.js +5 -3
  181. package/dist/interactions/index.js +2 -1
  182. package/dist/invoice/index.js +13 -9
  183. package/dist/kbd/index.js +5 -1
  184. package/dist/keyboard/index.js +4 -2
  185. package/dist/list-row/index.js +6 -4
  186. package/dist/log-viewer/index.js +4 -2
  187. package/dist/map-view/index.js +5 -3
  188. package/dist/markdown/index.js +9 -6
  189. package/dist/metric/index.js +7 -4
  190. package/dist/money/index.js +9 -3
  191. package/dist/nav-drawer/index.js +4 -2
  192. package/dist/nav-header/index.js +9 -0
  193. package/dist/navigation/index.js +5 -2
  194. package/dist/notification-center/index.js +12 -10
  195. package/dist/number-roll/index.js +5 -2
  196. package/dist/one-handed/index.js +5 -3
  197. package/dist/os-surfaces/index.js +6 -3
  198. package/dist/otp/index.js +7 -4
  199. package/dist/page-header/index.js +1 -0
  200. package/dist/pagination/index.js +6 -0
  201. package/dist/payment-method/index.js +14 -10
  202. package/dist/payment-status/index.js +17 -14
  203. package/dist/permission/index.js +5 -2
  204. package/dist/picker/index.js +11 -6
  205. package/dist/progress/index.js +6 -3
  206. package/dist/pull-to-refresh/index.js +4 -2
  207. package/dist/radio-group/index.js +6 -4
  208. package/dist/rating/index.js +5 -2
  209. package/dist/receivables/index.js +21 -16
  210. package/dist/refund/index.js +18 -14
  211. package/dist/save-status/index.js +5 -3
  212. package/dist/scroll-area/index.js +3 -1
  213. package/dist/search-field/index.js +8 -0
  214. package/dist/segmented-control/index.js +4 -3
  215. package/dist/sheet/index.js +5 -3
  216. package/dist/skeleton/index.js +3 -1
  217. package/dist/slider/index.js +4 -2
  218. package/dist/sortable/index.js +7 -0
  219. package/dist/spinner/index.js +3 -1
  220. package/dist/split-button/index.js +9 -6
  221. package/dist/spotlight/index.js +3 -1
  222. package/dist/stage-timeline/index.js +5 -3
  223. package/dist/status-dot/index.js +4 -2
  224. package/dist/stepper/index.js +7 -4
  225. package/dist/streaming-text/index.js +3 -2
  226. package/dist/survey/index.js +18 -15
  227. package/dist/switch/index.js +5 -3
  228. package/dist/system-state/index.js +7 -4
  229. package/dist/tab-bar/index.js +5 -2
  230. package/dist/tabs/index.js +4 -2
  231. package/dist/tags-input/index.js +10 -0
  232. package/dist/textarea/index.js +6 -4
  233. package/dist/thinking/index.js +3 -1
  234. package/dist/time-field/index.js +12 -0
  235. package/dist/time-range-control/index.js +22 -0
  236. package/dist/timeline/index.js +4 -2
  237. package/dist/toast/index.js +4 -2
  238. package/dist/toolbar/index.js +4 -2
  239. package/dist/tour/index.js +12 -9
  240. package/dist/truncation-notice/index.js +5 -2
  241. package/dist/update-notice/index.js +12 -9
  242. package/dist/video-player/index.js +5 -2
  243. package/dist/viewfinder/index.js +6 -4
  244. package/dist/widget/index.js +7 -4
  245. package/dist/wizard/index.js +7 -4
  246. package/package.json +13 -12
  247. package/dist/chunk-6N33LFQA.js +0 -35
  248. package/dist/chunk-GDKZTW34.js +0 -395
  249. package/dist/chunk-GL7B2DOW.js +0 -134
  250. package/dist/chunk-NKB7BZYK.js +0 -167
  251. package/dist/chunk-OETCUXQP.js +0 -134
  252. package/dist/chunk-OPXFZ4Y5.js +0 -204
  253. package/dist/chunk-Q72LJOVE.js +0 -169
  254. package/dist/chunk-RNGLIHFA.js +0 -191
  255. package/dist/chunk-RQ3HASCC.js +0 -6
  256. package/dist/chunk-RSOJT5YW.js +0 -124
  257. package/dist/chunk-TKVFVF5D.js +0 -95
  258. package/dist/chunk-XOSCY2CW.js +0 -242
  259. package/dist/header/index.js +0 -5
  260. package/dist/search-bar/index.js +0 -5
  261. /package/dist/{chunk-3ECPOSKO.js → chunk-3UG6JUCV.js} +0 -0
  262. /package/dist/{chunk-JRLTGLN4.js → chunk-5WWRTEPS.js} +0 -0
  263. /package/dist/{chunk-RTIKSY6A.js → chunk-5Z5ZYMOJ.js} +0 -0
@@ -0,0 +1,1325 @@
1
+ import { storageKey, readStored, writeStored } from './chunk-NNCOFLNE.js';
2
+ import { MonthList } from './chunk-DW3L54DQ.js';
3
+ import { Switch } from './chunk-FZGAAOKS.js';
4
+ import { SegmentedControl } from './chunk-TQVAIKFD.js';
5
+ import { Sheet } from './chunk-QYPE5JX3.js';
6
+ import { Input } from './chunk-7BUIKDD6.js';
7
+ import { Button } from './chunk-E2E3I5W2.js';
8
+ import { useLabels } from './chunk-APCWFOZW.js';
9
+ import { Icon } from './chunk-UXGIW7OK.js';
10
+ import * as React from 'react';
11
+ import { View, Pressable, Text, ScrollView, AppState, I18nManager } from 'react-native';
12
+ import { createStyleSheet, useLoamTheme, useStyles } from '@btndprojects/loam-theme-native';
13
+ import { DEFAULT_DATE_LABELS, timeRangeValue, dateZone, timeRangeReachesNow, timeRangeLabel, zoomTimeRange, timeRangeReceipt, TIME_RANGE_OPTIONS, sameDateValue, timeRangeText, parseTimeRange, resolveDateValue, valueLabel, findTimeRangeOption, durationLabel, zoneLabel, shiftTimeRange, isDateMath, parseDateRange, DAY_MS, HOUR_MS, pad2, localeNames, quickRangeLabel, timeLabel, dayLabel, formatDateMathInstant } from '@btndprojects/loam-date';
14
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
15
+
16
+ var UNIT_ROW = {
17
+ second: "Seconds",
18
+ minute: "Minutes",
19
+ hour: "Hours",
20
+ day: "Days",
21
+ week: "Weeks",
22
+ month: "Months",
23
+ quarter: "Quarters",
24
+ year: "Years"
25
+ };
26
+ var DEFAULT_LABELS = {
27
+ ...DEFAULT_DATE_LABELS,
28
+ timeRange: "Time range",
29
+ triggerLabel: (label, value) => `${label}, ${value}`,
30
+ moveBack: "Move back in time",
31
+ moveForward: "Move forward in time",
32
+ zoomOut: "Zoom out",
33
+ command: "Type a range",
34
+ commandPlaceholder: "45m, yesterday, now-2d to now-1d\u2026",
35
+ notARange: "Not a range yet",
36
+ lastHeading: "Last",
37
+ unitRow: (unit) => UNIT_ROW[unit],
38
+ periodsHeading: "Periods",
39
+ periodNames: {
40
+ today: "Today",
41
+ yesterday: "Yesterday",
42
+ week: "This week",
43
+ month: "This month",
44
+ year: "This year"
45
+ },
46
+ soFar: "So far",
47
+ preview: "Preview",
48
+ stepNames: {
49
+ relative: "Last\u2026",
50
+ periods: "Periods",
51
+ quickRanges: "All quick ranges",
52
+ custom: "Custom range"
53
+ },
54
+ stepHints: {
55
+ relative: "Minutes to months back",
56
+ periods: "Today, this week, this month\u2026",
57
+ quickRanges: "Search every preset",
58
+ custom: "Exact dates and times"
59
+ },
60
+ back: "Back",
61
+ viewSwitch: "Preview as",
62
+ viewNames: { clock: "Clock", calendar: "Calendar", year: "Year" },
63
+ clockHint: "Drag across the hours, or move an end.",
64
+ calendarHint: "Pick two days for a custom range.",
65
+ calendarHintEnd: "Now pick the last day.",
66
+ previousMonth: "Previous month",
67
+ nextMonth: "Next month",
68
+ now: "now",
69
+ from: "From",
70
+ to: "To",
71
+ applyRange: "Apply time range",
72
+ recentlyUsed: "Recently used",
73
+ quickRangeList: "Quick ranges",
74
+ searchRanges: (list) => `Search ${list.toLowerCase()}`,
75
+ noRangeMatches: (q) => `No range matches \u201C${q}\u201D.`,
76
+ refresh: "Refresh",
77
+ cancel: "Cancel",
78
+ cancelRefresh: "Cancel refresh",
79
+ autoRefresh: "Auto-refresh",
80
+ off: "Off"
81
+ };
82
+ function dateLabelsOf(labels) {
83
+ const out = {};
84
+ for (const k of Object.keys(DEFAULT_DATE_LABELS)) {
85
+ out[k] = labels[k];
86
+ }
87
+ return out;
88
+ }
89
+ var DEFAULT_PARTS = {
90
+ command: true,
91
+ relative: true,
92
+ periods: true,
93
+ recent: true,
94
+ quickRanges: false,
95
+ preview: true,
96
+ fields: true,
97
+ actions: true,
98
+ zone: true
99
+ };
100
+ var TIME_RANGE_UNITS = [
101
+ { unit: "minute", counts: [5, 15, 30] },
102
+ { unit: "hour", counts: [1, 3, 6, 12, 24] },
103
+ { unit: "day", counts: [2, 7, 14, 30, 90] },
104
+ { unit: "month", counts: [6, 12] }
105
+ ];
106
+ var TIME_RANGE_PERIODS = [
107
+ { id: "today", from: "now/d", to: "now/d", toSoFar: "now" },
108
+ { id: "yesterday", from: "now-1d/d", to: "now-1d/d" },
109
+ { id: "week", from: "now/w", to: "now/w", toSoFar: "now" },
110
+ { id: "month", from: "now/M", to: "now/M", toSoFar: "now" },
111
+ { id: "year", from: "now/y", to: "now/y", toSoFar: "now" }
112
+ ];
113
+ var TIME_RANGE_VIEWS = ["clock", "calendar", "year"];
114
+ var QUARTER_MS = HOUR_MS / 4;
115
+ var STEP_ICON = {
116
+ relative: "clock",
117
+ periods: "calendar",
118
+ quickRanges: "list-ul",
119
+ custom: "sliders"
120
+ };
121
+ var UNIT_CODE = {
122
+ second: "s",
123
+ minute: "m",
124
+ hour: "h",
125
+ day: "d",
126
+ week: "w",
127
+ month: "M",
128
+ quarter: "Q",
129
+ year: "y"
130
+ };
131
+ function readCommand(text, ctx) {
132
+ const q = text.trim();
133
+ if (!q) return null;
134
+ const split = /^(.+?)(?:\s*→\s*|\s+(?:to|–)\s+)(.+)$/i.exec(q);
135
+ if (split && parseTimeRange(split[1], split[2], ctx).ok) {
136
+ return { from: split[1].trim(), to: split[2].trim() };
137
+ }
138
+ const short = /^(\d+)\s*(mo|[smhdwMQy])$/.exec(q);
139
+ if (short && Number(short[1]) > 0) return { from: `now-${short[1]}${short[2]}`, to: "now" };
140
+ if (isDateMath(q) && parseTimeRange(q, "now", ctx).ok) return { from: q, to: "now" };
141
+ const r = parseDateRange(q, ctx);
142
+ if (!r.ok || !r.value) return null;
143
+ const v = r.value;
144
+ if (v.kind === "rolling") {
145
+ const c = UNIT_CODE[v.unit];
146
+ return v.includePartial === false ? { from: `now-${v.n}${c}/${c}`, to: `now-1${c}/${c}` } : { from: `now-${v.n}${c}`, to: "now" };
147
+ }
148
+ if (v.kind === "toDate") return { from: `now/${UNIT_CODE[v.unit]}`, to: "now" };
149
+ if (v.kind === "span") {
150
+ const c = UNIT_CODE[v.unit];
151
+ const at = v.off ? `now${v.off > 0 ? "+" : ""}${v.off}${c}/${c}` : `now/${c}`;
152
+ return { from: at, to: at };
153
+ }
154
+ return timeRangeText(v, ctx);
155
+ }
156
+ function dayText(Z, ms) {
157
+ return formatDateMathInstant(Z, ms).slice(0, 10);
158
+ }
159
+ function autoView(from, to, Z) {
160
+ const span = to - from;
161
+ const wholeDays = from === Z.startOfDay(from) && to === Z.startOfDay(to);
162
+ if (wholeDays && span <= 62 * DAY_MS) return "calendar";
163
+ if (span <= DAY_MS) return "clock";
164
+ return span <= 62 * DAY_MS ? "calendar" : "year";
165
+ }
166
+ function TimeRangeSheetBody({
167
+ ctx,
168
+ value,
169
+ onApply,
170
+ onCancel,
171
+ options,
172
+ recent,
173
+ labels,
174
+ dateLabels,
175
+ children,
176
+ parts: partsProp,
177
+ units = TIME_RANGE_UNITS,
178
+ periods = TIME_RANGE_PERIODS,
179
+ views = TIME_RANGE_VIEWS,
180
+ view: viewProp = "auto",
181
+ defaultSoFar = true,
182
+ applyMode = "instant",
183
+ allowFuture = false,
184
+ ampm = false
185
+ }) {
186
+ const theme = useLoamTheme();
187
+ const { styles } = useStyles(sheet);
188
+ const Z = ctx.Z;
189
+ const now = ctx.now ?? Date.now();
190
+ const part = { ...DEFAULT_PARTS, ...partsProp };
191
+ const initial = React.useMemo(() => timeRangeText(value, ctx), [value, ctx]);
192
+ const [from, setFrom] = React.useState(initial.from || "now-6h");
193
+ const [to, setTo] = React.useState(initial.to || "now");
194
+ const [command, setCommand] = React.useState("");
195
+ const steps = [
196
+ ["relative", part.relative && units.length > 0],
197
+ ["periods", part.periods && periods.length > 0],
198
+ ["quickRanges", part.quickRanges],
199
+ ["custom", part.preview || part.fields]
200
+ ].filter(([, on]) => on).map(([key]) => key);
201
+ const recentShown = part.recent ? recent.slice(0, 3) : [];
202
+ const single = steps.length === 1 && !part.command && recentShown.length === 0;
203
+ const [stepState, setStep] = React.useState("home");
204
+ const step = single ? steps[0] : stepState;
205
+ const [query, setQuery] = React.useState("");
206
+ const [soFar, setSoFar] = React.useState(() => {
207
+ const p = periods.find((x) => x.from === initial.from);
208
+ if (p && p.toSoFar != null && initial.to === p.toSoFar) return true;
209
+ if (p && initial.to === p.to) return false;
210
+ return defaultSoFar;
211
+ });
212
+ const [viewPick, setViewPick] = React.useState(
213
+ viewProp === "auto" ? null : viewProp
214
+ );
215
+ const [anchor, setAnchor] = React.useState(null);
216
+ const clockDrag = React.useRef(null);
217
+ const [rulerWidth, setRulerWidth] = React.useState(0);
218
+ const [calView, setCalView] = React.useState(null);
219
+ const [error, setError] = React.useState(null);
220
+ const parsed = React.useMemo(() => parseTimeRange(from, to, ctx), [from, to, ctx]);
221
+ const draft = parsed.ok ? parsed.value : null;
222
+ const lastGood = React.useRef(null);
223
+ if (draft) {
224
+ const r = resolveDateValue(draft, ctx);
225
+ if (r.from != null && r.to != null) lastGood.current = { from: r.from, to: r.to };
226
+ }
227
+ const shown = lastGood.current ?? { from: now - 6 * HOUR_MS, to: now };
228
+ const live = to.trim() === "now";
229
+ const dirty = from !== (initial.from || "now-6h") || to !== (initial.to || "now");
230
+ const apply = () => {
231
+ const r = parseTimeRange(from, to, ctx);
232
+ if (!r.ok) {
233
+ setError({ field: r.field, message: r.message });
234
+ setStep("custom");
235
+ return;
236
+ }
237
+ setError(null);
238
+ onApply(r.value);
239
+ };
240
+ const fill = (next, keep = {}) => {
241
+ setFrom(next.from);
242
+ setTo(next.to);
243
+ setError(null);
244
+ if (!keep.command) setCommand("");
245
+ if (!keep.view) {
246
+ setViewPick(viewProp === "auto" ? null : viewProp);
247
+ setCalView(null);
248
+ }
249
+ };
250
+ const pick = (next, keep) => {
251
+ if (applyMode === "instant") {
252
+ const r = parseTimeRange(next.from, next.to, ctx);
253
+ if (r.ok) {
254
+ onApply(r.value);
255
+ return;
256
+ }
257
+ }
258
+ setAnchor(null);
259
+ fill(next, keep);
260
+ };
261
+ const chip = (key, on, text, onPress, a11y, mono = false) => /* @__PURE__ */ jsx(
262
+ Pressable,
263
+ {
264
+ accessibilityRole: "button",
265
+ accessibilityLabel: a11y,
266
+ accessibilityState: { selected: on },
267
+ ...{ "aria-pressed": on },
268
+ onPress,
269
+ style: ({ pressed }) => [styles.chip, on && styles.chipOn, pressed && styles.pressed],
270
+ children: /* @__PURE__ */ jsx(Text, { style: [styles.chipText, mono && styles.mono, on && styles.chipTextOn], children: text })
271
+ },
272
+ key
273
+ );
274
+ const commandEnds = command.trim() ? readCommand(command, ctx) : null;
275
+ const commandBad = command.trim() !== "" && !commandEnds;
276
+ const commandBox = /* @__PURE__ */ jsxs(View, { style: styles.group, children: [
277
+ /* @__PURE__ */ jsx(
278
+ Input,
279
+ {
280
+ size: "sm",
281
+ leadingIcon: "search",
282
+ autoCapitalize: "none",
283
+ autoCorrect: false,
284
+ accessibilityLabel: labels.command,
285
+ placeholder: labels.commandPlaceholder,
286
+ value: command,
287
+ error: commandBad,
288
+ onChangeText: (text) => {
289
+ setCommand(text);
290
+ const ends = readCommand(text, ctx);
291
+ if (ends) {
292
+ setAnchor(null);
293
+ fill(ends, { command: true });
294
+ }
295
+ },
296
+ onSubmitEditing: () => {
297
+ if (commandEnds) apply();
298
+ }
299
+ }
300
+ ),
301
+ commandBad ? /* @__PURE__ */ jsx(Text, { style: styles.statusBad, children: labels.notARange }) : draft ? /* @__PURE__ */ jsxs(View, { style: styles.status, children: [
302
+ /* @__PURE__ */ jsx(Icon, { name: "check", size: theme.icon.xs, color: theme.color.accent }),
303
+ /* @__PURE__ */ jsx(Text, { numberOfLines: 1, style: styles.statusText, children: valueLabel(draft, ctx) })
304
+ ] }) : null
305
+ ] });
306
+ const ladderCols = Math.max(...units.map((r) => r.counts.length), 1);
307
+ const ladder = /* @__PURE__ */ jsx(View, { style: styles.group, children: units.map((row) => {
308
+ const code = UNIT_CODE[row.unit];
309
+ return /* @__PURE__ */ jsxs(View, { style: styles.unitRow, children: [
310
+ /* @__PURE__ */ jsx(Text, { style: styles.unitName, children: labels.unitRow(row.unit) }),
311
+ /* @__PURE__ */ jsx(View, { style: styles.chips, children: Array.from({ length: ladderCols }, (_, i) => {
312
+ const n = row.counts[i];
313
+ if (n == null) return /* @__PURE__ */ jsx(View, { style: styles.cell }, `gap-${i}`);
314
+ const ends = { from: `now-${n}${code}`, to: "now" };
315
+ return /* @__PURE__ */ jsx(View, { style: styles.cell, children: chip(
316
+ n,
317
+ from === ends.from && to === ends.to,
318
+ n.toLocaleString(ctx.locale),
319
+ () => pick(ends),
320
+ dateLabels.lastN(n, row.unit),
321
+ true
322
+ ) }, n);
323
+ }) })
324
+ ] }, row.unit);
325
+ }) });
326
+ const hasSoFar = periods.some((p) => p.toSoFar != null);
327
+ const periodEnds = (p, on) => ({
328
+ from: p.from,
329
+ to: on && p.toSoFar != null ? p.toSoFar : p.to
330
+ });
331
+ const activePeriod = periods.find((p) => from === p.from && (to === p.to || to === p.toSoFar));
332
+ const periodList = /* @__PURE__ */ jsxs(View, { children: [
333
+ periods.map((p) => {
334
+ const ends = periodEnds(p, soFar);
335
+ const on = from === ends.from && to === ends.to;
336
+ return /* @__PURE__ */ jsxs(
337
+ Pressable,
338
+ {
339
+ accessibilityRole: "button",
340
+ accessibilityState: { selected: on },
341
+ ...{ "aria-pressed": on },
342
+ onPress: () => pick(ends),
343
+ style: ({ pressed }) => [styles.row, pressed && styles.pressed],
344
+ children: [
345
+ /* @__PURE__ */ jsx(Text, { numberOfLines: 1, style: [styles.rowText, on && styles.rowTextOn], children: labels.periodNames[p.id] ?? p.label ?? p.id }),
346
+ on ? /* @__PURE__ */ jsx(Icon, { name: "check", size: theme.icon.xs, color: theme.color.accent }) : null
347
+ ]
348
+ },
349
+ p.id
350
+ );
351
+ }),
352
+ hasSoFar ? /* @__PURE__ */ jsxs(View, { style: styles.soFar, children: [
353
+ /* @__PURE__ */ jsx(Text, { style: styles.rowText, children: labels.soFar }),
354
+ /* @__PURE__ */ jsx(
355
+ Switch,
356
+ {
357
+ size: "sm",
358
+ accessibilityLabel: labels.soFar,
359
+ value: soFar,
360
+ onValueChange: (on) => {
361
+ setSoFar(on);
362
+ if (activePeriod) fill(periodEnds(activePeriod, on), { view: true });
363
+ }
364
+ }
365
+ )
366
+ ] }) : null
367
+ ] });
368
+ const recentList = /* @__PURE__ */ jsxs(View, { style: styles.group, children: [
369
+ /* @__PURE__ */ jsx(Text, { role: "heading", style: styles.partLabel, children: labels.recentlyUsed }),
370
+ /* @__PURE__ */ jsx(View, { accessibilityRole: "list", children: recentShown.map((r, i) => /* @__PURE__ */ jsxs(
371
+ Pressable,
372
+ {
373
+ accessibilityRole: "button",
374
+ onPress: () => pick(timeRangeText(r, ctx)),
375
+ style: ({ pressed }) => [styles.row, pressed && styles.pressed],
376
+ children: [
377
+ /* @__PURE__ */ jsx(Icon, { name: "clock", size: theme.icon.xs, color: theme.color.text3 }),
378
+ /* @__PURE__ */ jsx(Text, { numberOfLines: 1, style: styles.rowText, children: timeRangeLabel(r, ctx) })
379
+ ]
380
+ },
381
+ i
382
+ )) })
383
+ ] });
384
+ const selected = value?.kind === "expression" ? findTimeRangeOption(value, options) : null;
385
+ const quickList = () => {
386
+ const q = query.trim().toLowerCase();
387
+ const rows = options.filter(
388
+ (o) => !q || o.label.toLowerCase().includes(q) || quickRangeLabel(o, dateLabels).toLowerCase().includes(q) || o.from.toLowerCase().includes(q)
389
+ ).map((o) => ({
390
+ key: `${o.from}|${o.to}`,
391
+ name: o.label,
392
+ label: quickRangeLabel(o, dateLabels),
393
+ option: o
394
+ }));
395
+ return /* @__PURE__ */ jsxs(View, { style: styles.group, children: [
396
+ /* @__PURE__ */ jsx(
397
+ Input,
398
+ {
399
+ size: "sm",
400
+ leadingIcon: "search",
401
+ autoCapitalize: "none",
402
+ autoCorrect: false,
403
+ accessibilityLabel: labels.searchRanges(labels.quickRangeList),
404
+ placeholder: labels.searchRanges(labels.quickRangeList),
405
+ value: query,
406
+ onChangeText: setQuery
407
+ }
408
+ ),
409
+ /* @__PURE__ */ jsx(View, { accessibilityRole: "list", children: rows.length === 0 ? /* @__PURE__ */ jsx(Text, { style: styles.empty, children: labels.noRangeMatches(query.trim()) }) : rows.map((row) => {
410
+ const on = selected?.label === row.name;
411
+ return /* @__PURE__ */ jsxs(
412
+ Pressable,
413
+ {
414
+ accessibilityRole: "button",
415
+ accessibilityState: { selected: on },
416
+ onPress: () => {
417
+ const v = timeRangeValue(row.option);
418
+ if (applyMode === "instant") onApply(v);
419
+ else pick(timeRangeText(v, ctx));
420
+ },
421
+ style: ({ pressed }) => [styles.row, pressed && styles.pressed],
422
+ children: [
423
+ /* @__PURE__ */ jsx(Text, { numberOfLines: 1, style: [styles.rowText, on && styles.rowTextOn], children: row.label }),
424
+ on ? /* @__PURE__ */ jsx(Icon, { name: "check", size: theme.icon.xs, color: theme.color.accent }) : null
425
+ ]
426
+ },
427
+ row.key
428
+ );
429
+ }) })
430
+ ] });
431
+ };
432
+ const offered = views.length > 0 ? views : TIME_RANGE_VIEWS;
433
+ const auto = autoView(shown.from, shown.to, Z);
434
+ const mode = viewPick && offered.includes(viewPick) ? viewPick : offered.includes(auto) ? auto : offered[0];
435
+ const todayStart = Z.startOfDay(now);
436
+ const lastDay = Z.startOfDay(shown.to - 1);
437
+ const clockRange = (a, b) => {
438
+ let lo = Math.min(a, b);
439
+ let hi = Math.max(a, b);
440
+ if (!allowFuture) hi = Math.min(hi, now);
441
+ if (hi - lo < QUARTER_MS) lo = hi - QUARTER_MS;
442
+ fill(
443
+ {
444
+ from: formatDateMathInstant(Z, lo),
445
+ to: hi >= now ? "now" : formatDateMathInstant(Z, hi)
446
+ },
447
+ { view: true }
448
+ );
449
+ setViewPick("clock");
450
+ };
451
+ const clock = () => {
452
+ const anchorAt = shown.to > now - DAY_MS ? Math.max(now, shown.to) : shown.to;
453
+ const w = Z.wall(anchorAt);
454
+ const end = clockDrag.current?.end ?? Z.ms(w.y, w.mo, w.d, w.h) + (w.mi || w.s ? HOUR_MS : 0);
455
+ const start = end - DAY_MS;
456
+ const pct = (t) => Math.max(0, Math.min(100, (t - start) / DAY_MS * 100));
457
+ const snap = (t) => start + Math.round((t - start) / QUARTER_MS) * QUARTER_MS;
458
+ const ticks = [];
459
+ for (let i = 1; i < 24; i++) {
460
+ const t = start + i * HOUR_MS;
461
+ const tw = Z.wall(t);
462
+ if (tw.mi === 0 && tw.h % 6 === 0)
463
+ ticks.push({ at: pct(t), text: pad2(tw.h), midnight: tw.h === 0 });
464
+ }
465
+ const end2 = (ms) => `${dayLabel(Z, ms, { noYear: true, locale: ctx.locale })}, ${timeLabel(Z, ms, ampm, false, dateLabels)}`;
466
+ const oneDay = shown.to - shown.from <= DAY_MS && Z.dayKey(shown.from) === Z.dayKey(shown.to - 1);
467
+ const endText = (ms) => oneDay ? timeLabel(Z, ms, ampm, false, dateLabels) : end2(ms);
468
+ const at = (pageX, left) => {
469
+ let f = rulerWidth > 0 ? Math.max(0, Math.min(1, (pageX - left) / rulerWidth)) : 0;
470
+ if (I18nManager.isRTL) f = 1 - f;
471
+ return snap(start + f * DAY_MS);
472
+ };
473
+ const onGrant = (e) => {
474
+ const { pageX, locationX } = e.nativeEvent;
475
+ const left = pageX - locationX;
476
+ const t = at(pageX, left);
477
+ const near = HOUR_MS * 44 / Math.max(120, rulerWidth);
478
+ const fixed = Math.abs(t - shown.to) <= near ? shown.from : Math.abs(t - shown.from) <= near ? shown.to : t;
479
+ clockDrag.current = { fixed, end, left };
480
+ clockRange(fixed, fixed === t ? t + QUARTER_MS : t);
481
+ };
482
+ const onMove = (e) => {
483
+ const d = clockDrag.current;
484
+ if (d) clockRange(d.fixed, at(e.nativeEvent.pageX, d.left));
485
+ };
486
+ const onEnd = () => {
487
+ clockDrag.current = null;
488
+ };
489
+ const move = (which, by) => {
490
+ if (which === "from")
491
+ clockRange(Math.min(snap(shown.from + by), shown.to - QUARTER_MS), shown.to);
492
+ else clockRange(shown.from, Math.max(snap(shown.to + by), shown.from + QUARTER_MS));
493
+ };
494
+ const nudge = (which) => (e) => move(which, e.nativeEvent.actionName === "increment" ? QUARTER_MS : -QUARTER_MS);
495
+ const keys = (which) => ({
496
+ onKeyDown: (e) => {
497
+ const step2 = (e.shiftKey ? HOUR_MS : QUARTER_MS) * (I18nManager.isRTL ? -1 : 1);
498
+ const by = e.key === "ArrowRight" || e.key === "ArrowUp" ? step2 : e.key === "ArrowLeft" || e.key === "ArrowDown" ? -step2 : 0;
499
+ if (!by) return;
500
+ e.preventDefault();
501
+ move(which, by);
502
+ }
503
+ });
504
+ const handle = (which) => {
505
+ const t = which === "from" ? shown.from : shown.to;
506
+ if (t < start) return null;
507
+ return /* @__PURE__ */ jsx(
508
+ View,
509
+ {
510
+ accessible: true,
511
+ accessibilityRole: "adjustable",
512
+ accessibilityLabel: `${labels.preview}: ${which === "from" ? labels.from : labels.to}`,
513
+ accessibilityValue: { text: which === "to" && live ? labels.now : end2(t) },
514
+ accessibilityActions: [{ name: "increment" }, { name: "decrement" }],
515
+ onAccessibilityAction: nudge(which),
516
+ focusable: true,
517
+ ...keys(which),
518
+ pointerEvents: "none",
519
+ style: [styles.handle, { start: `${pct(t)}%` }],
520
+ children: /* @__PURE__ */ jsx(View, { style: styles.handleGrip })
521
+ },
522
+ which
523
+ );
524
+ };
525
+ return /* @__PURE__ */ jsxs(View, { style: styles.group, children: [
526
+ /* @__PURE__ */ jsxs(
527
+ Text,
528
+ {
529
+ accessibilityLabel: labels.timeRangeTo(
530
+ end2(shown.from),
531
+ live ? labels.now : end2(shown.to)
532
+ ),
533
+ style: [styles.bigTime, !oneDay && styles.bigTimeDays],
534
+ children: [
535
+ endText(shown.from),
536
+ /* @__PURE__ */ jsx(Text, { style: styles.arrow, children: " \u2192 " }),
537
+ live ? labels.now : endText(shown.to)
538
+ ]
539
+ }
540
+ ),
541
+ /* @__PURE__ */ jsxs(View, { children: [
542
+ /* @__PURE__ */ jsxs(
543
+ View,
544
+ {
545
+ onLayout: (e) => setRulerWidth(e.nativeEvent.layout.width),
546
+ onStartShouldSetResponder: () => true,
547
+ onMoveShouldSetResponder: () => true,
548
+ onResponderTerminationRequest: () => false,
549
+ onResponderGrant: onGrant,
550
+ onResponderMove: onMove,
551
+ onResponderRelease: onEnd,
552
+ onResponderTerminate: onEnd,
553
+ style: styles.rulerTouch,
554
+ children: [
555
+ /* @__PURE__ */ jsxs(View, { pointerEvents: "none", style: styles.ruler, children: [
556
+ ticks.map((t) => /* @__PURE__ */ jsx(
557
+ View,
558
+ {
559
+ style: [styles.tick, t.midnight && styles.tickMidnight, { start: `${t.at}%` }]
560
+ },
561
+ t.at
562
+ )),
563
+ /* @__PURE__ */ jsx(
564
+ View,
565
+ {
566
+ style: [
567
+ styles.band,
568
+ shown.from < start && styles.bandClipped,
569
+ { start: `${pct(shown.from)}%`, width: `${pct(shown.to) - pct(shown.from)}%` }
570
+ ]
571
+ }
572
+ ),
573
+ !live && now >= start && now <= end ? /* @__PURE__ */ jsx(View, { style: [styles.nowMark, { start: `${pct(now)}%` }] }) : null
574
+ ] }),
575
+ handle("from"),
576
+ handle("to")
577
+ ]
578
+ }
579
+ ),
580
+ /* @__PURE__ */ jsx(
581
+ View,
582
+ {
583
+ ...{ "aria-hidden": true },
584
+ importantForAccessibility: "no-hide-descendants",
585
+ style: styles.tickLabels,
586
+ children: ticks.map((t) => /* @__PURE__ */ jsx(Text, { style: [styles.tickText, { start: `${t.at}%` }], children: t.text }, t.at))
587
+ }
588
+ )
589
+ ] }),
590
+ /* @__PURE__ */ jsx(Text, { style: styles.empty, children: labels.clockHint })
591
+ ] });
592
+ };
593
+ const pickDay = (ms) => {
594
+ const d = Z.startOfDay(ms);
595
+ if (anchor == null) {
596
+ setAnchor(d);
597
+ fill({ from: dayText(Z, d), to: dayText(Z, d) }, { view: true });
598
+ setViewPick("calendar");
599
+ return;
600
+ }
601
+ const lo = Math.min(anchor, d);
602
+ const hi = Math.max(anchor, d);
603
+ setAnchor(null);
604
+ fill({ from: dayText(Z, lo), to: dayText(Z, hi) }, { view: true });
605
+ setViewPick("calendar");
606
+ };
607
+ const month = calView ?? Z.startOfMonth(lastDay);
608
+ const lastMonth = allowFuture ? null : Z.startOfMonth(now);
609
+ const navButton = (dir) => {
610
+ const off = dir > 0 && lastMonth != null && month >= lastMonth;
611
+ return /* @__PURE__ */ jsx(
612
+ Pressable,
613
+ {
614
+ accessibilityRole: "button",
615
+ accessibilityLabel: dir < 0 ? labels.previousMonth : labels.nextMonth,
616
+ accessibilityState: { disabled: off },
617
+ disabled: off,
618
+ onPress: () => setCalView(Z.addMonths(month, dir)),
619
+ style: ({ pressed }) => [styles.nav, off && styles.off, pressed && styles.pressed],
620
+ children: /* @__PURE__ */ jsx(
621
+ Icon,
622
+ {
623
+ name: dir < 0 ? "chevron-left" : "chevron-right",
624
+ size: theme.icon.sm,
625
+ color: theme.color.text2
626
+ }
627
+ )
628
+ }
629
+ );
630
+ };
631
+ const calendar = () => /* @__PURE__ */ jsxs(View, { style: styles.group, children: [
632
+ /* @__PURE__ */ jsxs(View, { style: styles.navRow, children: [
633
+ navButton(-1),
634
+ navButton(1)
635
+ ] }),
636
+ /* @__PURE__ */ jsx(
637
+ MonthList,
638
+ {
639
+ Z,
640
+ anchorMs: month,
641
+ radius: 0,
642
+ ctx,
643
+ from: anchor ?? Z.startOfDay(shown.from),
644
+ to: anchor != null ? null : Z.addDays(lastDay, 1),
645
+ constraints: allowFuture ? void 0 : { disableFuture: true },
646
+ onPick: pickDay
647
+ }
648
+ ),
649
+ /* @__PURE__ */ jsx(Text, { style: styles.empty, children: anchor != null ? labels.calendarHintEnd : labels.calendarHint })
650
+ ] });
651
+ const year = () => {
652
+ const names = localeNames(ctx.locale);
653
+ const endMonth = Z.startOfMonth(lastDay);
654
+ const cells = [];
655
+ for (let i = 11; i >= 0; i--) {
656
+ const s = Z.addMonths(endMonth, -i);
657
+ const e = Z.addMonths(s, 1);
658
+ const sw = Z.wall(s);
659
+ const overlap = Math.max(0, Math.min(e, shown.to) - Math.max(s, shown.from));
660
+ const fillPct = Math.round(overlap / (e - s) * 100);
661
+ const future = !allowFuture && s > now;
662
+ const lastPick = allowFuture ? Z.addDays(e, -1) : Math.min(Z.addDays(e, -1), todayStart);
663
+ const ends = { from: dayText(Z, s), to: dayText(Z, lastPick) };
664
+ const on = from === ends.from && to === ends.to;
665
+ cells.push(
666
+ /* @__PURE__ */ jsxs(
667
+ Pressable,
668
+ {
669
+ accessibilityRole: "button",
670
+ accessibilityLabel: `${names.months[sw.mo]} ${sw.y}`,
671
+ accessibilityState: { disabled: future, selected: on },
672
+ ...{ "aria-pressed": on },
673
+ disabled: future,
674
+ onPress: () => {
675
+ setAnchor(null);
676
+ fill(ends, { view: true });
677
+ },
678
+ style: ({ pressed }) => [
679
+ styles.monthCell,
680
+ future && styles.off,
681
+ pressed && styles.pressed
682
+ ],
683
+ children: [
684
+ /* @__PURE__ */ jsx(Text, { style: styles.monthName, children: names.abbr[sw.mo] }),
685
+ /* @__PURE__ */ jsx(View, { style: styles.monthBar, children: /* @__PURE__ */ jsx(View, { style: [styles.monthFill, { height: `${fillPct}%` }] }) }),
686
+ /* @__PURE__ */ jsx(Text, { style: styles.monthYear, children: sw.mo === 0 || i === 11 ? sw.y : "" })
687
+ ]
688
+ },
689
+ s
690
+ )
691
+ );
692
+ }
693
+ return /* @__PURE__ */ jsx(View, { style: styles.yearGrid, children: cells });
694
+ };
695
+ const preview = /* @__PURE__ */ jsxs(View, { accessibilityLabel: labels.preview, style: styles.group, children: [
696
+ /* @__PURE__ */ jsxs(View, { style: styles.headingRow, children: [
697
+ offered.length > 1 ? /* @__PURE__ */ jsx(
698
+ SegmentedControl,
699
+ {
700
+ size: "sm",
701
+ accessibilityLabel: labels.viewSwitch,
702
+ items: offered.map((v) => ({ value: v, label: labels.viewNames[v] })),
703
+ value: mode,
704
+ onValueChange: (v) => setViewPick(v)
705
+ }
706
+ ) : null,
707
+ /* @__PURE__ */ jsx(Text, { style: styles.duration, children: durationLabel(shown.from, shown.to, dateLabels) })
708
+ ] }),
709
+ mode === "clock" ? clock() : mode === "calendar" ? calendar() : year()
710
+ ] });
711
+ const field = (side) => /* @__PURE__ */ jsxs(View, { style: styles.field, children: [
712
+ /* @__PURE__ */ jsx(Text, { style: styles.partLabel, children: side === "from" ? labels.from : labels.to }),
713
+ /* @__PURE__ */ jsx(
714
+ Input,
715
+ {
716
+ size: "sm",
717
+ autoCapitalize: "none",
718
+ autoCorrect: false,
719
+ accessibilityLabel: side === "from" ? labels.from : labels.to,
720
+ value: side === "from" ? from : to,
721
+ error: error?.field === side,
722
+ onChangeText: (t) => {
723
+ (side === "from" ? setFrom : setTo)(t);
724
+ setCommand("");
725
+ setAnchor(null);
726
+ if (error?.field === side) setError(null);
727
+ },
728
+ onSubmitEditing: apply
729
+ }
730
+ )
731
+ ] }, side);
732
+ const inLadder = units.some(
733
+ (row) => row.counts.some((n) => from === `now-${n}${UNIT_CODE[row.unit]}` && to === "now")
734
+ );
735
+ const holder = !draft ? null : inLadder && steps.includes("relative") ? "relative" : activePeriod && steps.includes("periods") ? "periods" : steps.includes("custom") ? "custom" : null;
736
+ const home = /* @__PURE__ */ jsxs(Fragment, { children: [
737
+ part.command ? commandBox : null,
738
+ steps.length > 0 ? /* @__PURE__ */ jsx(View, { children: steps.map((s) => {
739
+ const on = holder === s;
740
+ return /* @__PURE__ */ jsxs(
741
+ Pressable,
742
+ {
743
+ accessibilityRole: "button",
744
+ onPress: () => setStep(s),
745
+ style: ({ pressed }) => [styles.stepRow, pressed && styles.pressed],
746
+ children: [
747
+ /* @__PURE__ */ jsx(View, { style: [styles.stepIcon, on && styles.stepIconOn], children: /* @__PURE__ */ jsx(
748
+ Icon,
749
+ {
750
+ name: STEP_ICON[s],
751
+ size: theme.icon.sm,
752
+ color: on ? theme.color.accent : theme.color.text2
753
+ }
754
+ ) }),
755
+ /* @__PURE__ */ jsxs(View, { style: styles.stepText, children: [
756
+ /* @__PURE__ */ jsx(Text, { style: styles.stepTitle, children: labels.stepNames[s] }),
757
+ /* @__PURE__ */ jsx(Text, { numberOfLines: 1, style: [styles.stepHint, on && styles.stepHintOn], children: on && draft ? timeRangeLabel(draft, ctx) : labels.stepHints[s] })
758
+ ] }),
759
+ /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: theme.icon.sm, color: theme.color.text3 })
760
+ ]
761
+ },
762
+ s
763
+ );
764
+ }) }) : null,
765
+ recentShown.length > 0 ? recentList : null,
766
+ children
767
+ ] });
768
+ const header = (title) => /* @__PURE__ */ jsxs(View, { style: styles.stepHeader, children: [
769
+ single ? null : /* @__PURE__ */ jsx(
770
+ Pressable,
771
+ {
772
+ accessibilityRole: "button",
773
+ accessibilityLabel: labels.back,
774
+ onPress: () => setStep("home"),
775
+ style: ({ pressed }) => [styles.nav, pressed && styles.pressed],
776
+ children: /* @__PURE__ */ jsx(Icon, { name: "chevron-left", size: theme.icon.sm, color: theme.color.text })
777
+ }
778
+ ),
779
+ /* @__PURE__ */ jsx(Text, { role: "heading", numberOfLines: 1, style: styles.stepTitle, children: title })
780
+ ] });
781
+ const custom = /* @__PURE__ */ jsxs(Fragment, { children: [
782
+ header(labels.stepNames.custom),
783
+ part.preview ? preview : null,
784
+ part.fields ? /* @__PURE__ */ jsxs(View, { style: styles.fields, children: [
785
+ field("from"),
786
+ field("to")
787
+ ] }) : null,
788
+ part.zone ? /* @__PURE__ */ jsxs(View, { style: styles.zone, children: [
789
+ /* @__PURE__ */ jsx(Icon, { name: "globe", size: theme.icon.xs, color: theme.color.text3 }),
790
+ /* @__PURE__ */ jsx(Text, { style: styles.zoneText, children: zoneLabel(Z, now) })
791
+ ] }) : null
792
+ ] });
793
+ const showActions = part.actions && (step === "custom" || dirty || error != null);
794
+ return /* @__PURE__ */ jsxs(View, { style: styles.panel, children: [
795
+ step === "home" ? home : null,
796
+ step === "relative" ? /* @__PURE__ */ jsxs(Fragment, { children: [
797
+ header(labels.lastHeading),
798
+ ladder
799
+ ] }) : null,
800
+ step === "periods" ? /* @__PURE__ */ jsxs(Fragment, { children: [
801
+ header(labels.periodsHeading),
802
+ periodList
803
+ ] }) : null,
804
+ step === "quickRanges" ? /* @__PURE__ */ jsxs(Fragment, { children: [
805
+ header(labels.quickRangeList),
806
+ quickList()
807
+ ] }) : null,
808
+ step === "custom" ? custom : null,
809
+ error ? /* @__PURE__ */ jsx(Text, { accessibilityRole: "alert", style: styles.error, children: error.message }) : null,
810
+ showActions ? /* @__PURE__ */ jsxs(View, { style: styles.actions, children: [
811
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onPress: onCancel, children: labels.cancel }),
812
+ /* @__PURE__ */ jsx(Button, { size: "sm", onPress: apply, children: labels.applyRange })
813
+ ] }) : null
814
+ ] });
815
+ }
816
+ var sheet = createStyleSheet((theme) => {
817
+ const small = {
818
+ fontFamily: theme.font.sans,
819
+ fontSize: theme.type.footnote.fontSize,
820
+ lineHeight: theme.type.footnote.lineHeight
821
+ };
822
+ const tiny = {
823
+ fontFamily: theme.font.mono,
824
+ fontSize: theme.type.caption2.fontSize,
825
+ lineHeight: theme.type.caption2.lineHeight,
826
+ color: theme.color.text3
827
+ };
828
+ return {
829
+ panel: { gap: theme.space.s5 },
830
+ stepRow: {
831
+ flexDirection: "row",
832
+ alignItems: "center",
833
+ gap: theme.space.s3,
834
+ minHeight: theme.tapMin + theme.space.s3
835
+ },
836
+ stepIcon: {
837
+ width: theme.tapMin - theme.space.s2,
838
+ height: theme.tapMin - theme.space.s2,
839
+ alignItems: "center",
840
+ justifyContent: "center",
841
+ borderRadius: theme.radius.md,
842
+ backgroundColor: theme.color.surface2
843
+ },
844
+ stepIconOn: { backgroundColor: theme.color.accentSoft },
845
+ stepText: { flex: 1, minWidth: 0 },
846
+ stepTitle: {
847
+ flexShrink: 1,
848
+ fontFamily: theme.font.sans,
849
+ fontSize: theme.type.body.fontSize,
850
+ lineHeight: theme.type.body.lineHeight,
851
+ fontWeight: theme.fontWeight.bold,
852
+ color: theme.color.text
853
+ },
854
+ stepHint: { ...small, color: theme.color.text3 },
855
+ stepHintOn: { color: theme.color.accent },
856
+ stepHeader: {
857
+ flexDirection: "row",
858
+ alignItems: "center",
859
+ gap: theme.space.s1,
860
+ marginStart: -theme.space.s3
861
+ },
862
+ group: { gap: theme.space.s2 },
863
+ headingRow: {
864
+ flexDirection: "row",
865
+ alignItems: "center",
866
+ justifyContent: "space-between",
867
+ gap: theme.space.s2
868
+ },
869
+ partLabel: {
870
+ fontFamily: theme.font.sans,
871
+ fontSize: theme.type.caption2.fontSize,
872
+ lineHeight: theme.type.caption2.lineHeight,
873
+ fontWeight: theme.fontWeight.bold,
874
+ color: theme.color.text2
875
+ },
876
+ status: { flexDirection: "row", alignItems: "center", gap: theme.space.s1 },
877
+ statusText: { ...small, flexShrink: 1, color: theme.color.text2 },
878
+ statusBad: { ...small, color: theme.color.dangerOnSoft },
879
+ unitRow: { flexDirection: "row", alignItems: "center", gap: theme.space.s2 },
880
+ unitName: { ...small, width: theme.space.s8 * 2, color: theme.color.text3 },
881
+ chips: { flex: 1, flexDirection: "row", gap: theme.space.s1 },
882
+ cell: { flex: 1, minWidth: 0 },
883
+ wrap: { flexDirection: "row", flexWrap: "wrap", gap: theme.space.s1 },
884
+ chip: {
885
+ minWidth: theme.tapMin,
886
+ minHeight: theme.tapMin,
887
+ alignItems: "center",
888
+ justifyContent: "center",
889
+ paddingHorizontal: theme.space.s3,
890
+ borderRadius: theme.radius.md,
891
+ borderWidth: theme.borderWidth.base,
892
+ borderColor: theme.color.border,
893
+ backgroundColor: theme.color.surface
894
+ },
895
+ chipOn: { borderColor: theme.edge.accent, backgroundColor: theme.color.accent },
896
+ chipText: { ...small, color: theme.color.text },
897
+ chipTextOn: { color: theme.color.accentInk, fontWeight: theme.fontWeight.bold },
898
+ mono: { fontFamily: theme.font.mono, fontVariant: ["tabular-nums"] },
899
+ soFar: {
900
+ flexDirection: "row",
901
+ alignItems: "center",
902
+ gap: theme.space.s2,
903
+ minHeight: theme.tapMin,
904
+ paddingHorizontal: theme.space.s1,
905
+ marginTop: theme.space.s2,
906
+ borderTopWidth: theme.borderWidth.base,
907
+ borderTopColor: theme.color.border
908
+ },
909
+ soFarText: { ...small, color: theme.color.text3 },
910
+ empty: { ...small, color: theme.color.text3 },
911
+ row: {
912
+ flexDirection: "row",
913
+ alignItems: "center",
914
+ gap: theme.space.s2,
915
+ minHeight: theme.tapMin,
916
+ paddingHorizontal: theme.space.s1
917
+ },
918
+ rowText: {
919
+ flex: 1,
920
+ fontFamily: theme.font.sans,
921
+ fontSize: theme.type.body.fontSize,
922
+ lineHeight: theme.type.body.lineHeight,
923
+ color: theme.color.text
924
+ },
925
+ rowTextOn: { fontWeight: theme.fontWeight.bold },
926
+ duration: { ...tiny, marginStart: "auto" },
927
+ bigTimeDays: { fontSize: theme.type.title3.fontSize, lineHeight: theme.type.title3.lineHeight },
928
+ bigTime: {
929
+ fontFamily: theme.font.mono,
930
+ fontSize: theme.type.title2.fontSize,
931
+ lineHeight: theme.type.title2.lineHeight,
932
+ fontWeight: theme.fontWeight.bold,
933
+ fontVariant: ["tabular-nums"],
934
+ color: theme.color.text
935
+ },
936
+ arrow: { color: theme.color.text3 },
937
+ rulerTouch: { justifyContent: "center", minHeight: theme.tapMin },
938
+ ruler: {
939
+ height: theme.space.s6,
940
+ borderRadius: theme.radius.xs,
941
+ backgroundColor: theme.color.surface2
942
+ },
943
+ tick: {
944
+ position: "absolute",
945
+ top: 0,
946
+ bottom: 0,
947
+ width: 1,
948
+ backgroundColor: theme.color.border
949
+ },
950
+ tickMidnight: { backgroundColor: theme.color.borderStrong },
951
+ band: {
952
+ position: "absolute",
953
+ top: 0,
954
+ bottom: 0,
955
+ borderRadius: theme.radius.xs,
956
+ borderWidth: theme.borderWidth.base,
957
+ borderColor: theme.edge.accent,
958
+ backgroundColor: theme.color.accentSoft
959
+ },
960
+ bandClipped: { borderStartWidth: 0, borderTopStartRadius: 0, borderBottomStartRadius: 0 },
961
+ nowMark: {
962
+ position: "absolute",
963
+ top: -theme.space.s1,
964
+ bottom: -theme.space.s1,
965
+ width: 1,
966
+ backgroundColor: theme.color.text3
967
+ },
968
+ handle: {
969
+ position: "absolute",
970
+ top: 0,
971
+ bottom: 0,
972
+ width: theme.space.s4,
973
+ marginStart: -theme.space.s2,
974
+ alignItems: "center",
975
+ justifyContent: "center"
976
+ },
977
+ handleGrip: {
978
+ width: theme.borderWidth.heavy * 2,
979
+ height: theme.space.s6 + theme.space.s2,
980
+ borderRadius: theme.radius.full,
981
+ backgroundColor: theme.color.accent
982
+ },
983
+ tickLabels: { height: theme.type.caption2.lineHeight, marginTop: theme.space.s1 },
984
+ tickText: { ...tiny, position: "absolute", transform: [{ translateX: -theme.space.s2 }] },
985
+ navRow: { flexDirection: "row", justifyContent: "space-between" },
986
+ nav: {
987
+ minWidth: theme.tapMin,
988
+ minHeight: theme.tapMin,
989
+ alignItems: "center",
990
+ justifyContent: "center"
991
+ },
992
+ yearGrid: { flexDirection: "row", flexWrap: "wrap", rowGap: theme.space.s2 },
993
+ monthCell: {
994
+ width: `${100 / 6}%`,
995
+ alignItems: "stretch",
996
+ gap: theme.space.s1,
997
+ paddingHorizontal: theme.space.s1
998
+ },
999
+ monthName: {
1000
+ ...small,
1001
+ textAlign: "center",
1002
+ fontWeight: theme.fontWeight.bold,
1003
+ color: theme.color.text2
1004
+ },
1005
+ monthBar: {
1006
+ height: theme.space.s8,
1007
+ overflow: "hidden",
1008
+ justifyContent: "flex-end",
1009
+ borderRadius: theme.radius.xs,
1010
+ backgroundColor: theme.color.surface2
1011
+ },
1012
+ monthFill: { backgroundColor: theme.color.accent },
1013
+ monthYear: { ...tiny, textAlign: "center" },
1014
+ fields: { flexDirection: "row", gap: theme.space.s2 },
1015
+ field: { flex: 1, gap: theme.space.s1 },
1016
+ error: { ...small, color: theme.color.dangerOnSoft },
1017
+ actions: { flexDirection: "row", justifyContent: "flex-end", gap: theme.space.s2 },
1018
+ off: { opacity: theme.state.disabledOpacity },
1019
+ pressed: { opacity: theme.state.pressedOpacity },
1020
+ zone: { flexDirection: "row", alignItems: "center", gap: theme.space.s1 },
1021
+ zoneText: {
1022
+ fontFamily: theme.font.sans,
1023
+ fontSize: theme.type.caption2.fontSize,
1024
+ lineHeight: theme.type.caption2.lineHeight,
1025
+ color: theme.color.text3
1026
+ }
1027
+ };
1028
+ });
1029
+ var REFRESH_INTERVALS = ["10s", "30s", "1m", "5m", "15m", "1h"];
1030
+ var INTERVAL_UNIT = { s: 1e3, m: 6e4, h: 36e5, d: 864e5 };
1031
+ function refreshIntervalMs(interval) {
1032
+ const m = /^(\d+)([smhd])$/.exec(interval ?? "");
1033
+ if (!m) return null;
1034
+ const ms = Number(m[1]) * INTERVAL_UNIT[m[2]];
1035
+ return ms > 0 ? ms : null;
1036
+ }
1037
+ function useRefreshTimer(ms, paused, onTick) {
1038
+ const [active, setActive] = React.useState(AppState.currentState !== "background");
1039
+ const tick = React.useRef(onTick);
1040
+ tick.current = onTick;
1041
+ React.useEffect(() => {
1042
+ const sub = AppState.addEventListener("change", (s) => setActive(s === "active"));
1043
+ return () => sub.remove();
1044
+ }, []);
1045
+ const [n, setN] = React.useState(0);
1046
+ React.useEffect(() => {
1047
+ if (ms == null || paused || !active) return;
1048
+ const id = setTimeout(() => {
1049
+ setN((x) => x + 1);
1050
+ tick.current();
1051
+ }, ms);
1052
+ return () => clearTimeout(id);
1053
+ }, [ms, paused, active, n]);
1054
+ }
1055
+ var DEFAULT_VALUE = timeRangeValue({ from: "now-6h", to: "now" });
1056
+ function TimeRangeControl({
1057
+ value: valueProp,
1058
+ defaultValue = DEFAULT_VALUE,
1059
+ onChange,
1060
+ open: openProp,
1061
+ defaultOpen = false,
1062
+ onOpenChange,
1063
+ timeZone = "default",
1064
+ options = TIME_RANGE_OPTIONS,
1065
+ weekStartsOn = 1,
1066
+ locale,
1067
+ now,
1068
+ recent: recentProp,
1069
+ onRecentChange,
1070
+ storage,
1071
+ storageId,
1072
+ recentLimit = 5,
1073
+ shift = true,
1074
+ zoom = true,
1075
+ onRefresh,
1076
+ loading = false,
1077
+ onCancelRefresh,
1078
+ refreshInterval,
1079
+ defaultRefreshInterval = "off",
1080
+ onRefreshIntervalChange,
1081
+ refreshIntervals = REFRESH_INTERVALS,
1082
+ minRefreshInterval,
1083
+ label: labelProp,
1084
+ disabled = false,
1085
+ style,
1086
+ labels: labelsProp,
1087
+ ...panelOptions
1088
+ }) {
1089
+ const labels = useLabels("timeRangeControl", DEFAULT_LABELS, labelsProp);
1090
+ const label = labelProp ?? labels.timeRange;
1091
+ const dateLabels = React.useMemo(() => dateLabelsOf(labels), [labels]);
1092
+ const theme = useLoamTheme();
1093
+ const { styles } = useStyles(sheet2);
1094
+ const [internalValue, setInternalValue] = React.useState(defaultValue);
1095
+ const value = valueProp !== void 0 ? valueProp : internalValue;
1096
+ const key = storage && storageId ? storageKey("time-range", storageId) : null;
1097
+ const [internalRecent, setInternalRecent] = React.useState(
1098
+ () => (key ? readStored(storage, key) : null) ?? []
1099
+ );
1100
+ const recent = recentProp ?? internalRecent;
1101
+ const floor = refreshIntervalMs(minRefreshInterval) ?? 0;
1102
+ const offered = refreshIntervals.filter((i) => (refreshIntervalMs(i) ?? 0) >= floor);
1103
+ const [internalInterval, setInternalInterval] = React.useState(defaultRefreshInterval);
1104
+ const chosen = refreshInterval ?? internalInterval;
1105
+ const interval = (refreshIntervalMs(chosen) ?? 0) >= floor ? chosen : "off";
1106
+ const pickInterval = (next) => {
1107
+ if (refreshInterval === void 0) setInternalInterval(next);
1108
+ onRefreshIntervalChange?.(next);
1109
+ };
1110
+ useRefreshTimer(
1111
+ onRefresh ? refreshIntervalMs(interval) : null,
1112
+ loading || disabled,
1113
+ () => onRefresh?.()
1114
+ );
1115
+ const Z = React.useMemo(() => dateZone(timeZone), [timeZone]);
1116
+ const readCtx = () => ({
1117
+ Z,
1118
+ now: now?.() ?? Date.now(),
1119
+ weekStartsOn,
1120
+ granularity: "second",
1121
+ locale,
1122
+ labels: dateLabels
1123
+ });
1124
+ const ctx = readCtx();
1125
+ const [internalOpen, setInternalOpen] = React.useState(defaultOpen);
1126
+ const open = openProp ?? internalOpen;
1127
+ const setOpen = (next) => {
1128
+ if (openProp === void 0) setInternalOpen(next);
1129
+ onOpenChange?.(next);
1130
+ };
1131
+ const [session, setSession] = React.useState(0);
1132
+ React.useEffect(() => {
1133
+ if (open) setSession((n) => n + 1);
1134
+ }, [open]);
1135
+ const commit = (next, source) => {
1136
+ const c = readCtx();
1137
+ const r = resolveDateValue(next, c);
1138
+ if (valueProp === void 0) setInternalValue(next);
1139
+ onChange?.({
1140
+ value: next,
1141
+ from: r.from,
1142
+ to: r.to,
1143
+ label: valueLabel(next, c),
1144
+ tz: Z.tz,
1145
+ exact: r.exact,
1146
+ source
1147
+ });
1148
+ };
1149
+ const commitFromSheet = (next) => {
1150
+ commit(next, "panel");
1151
+ const list = [next, ...recent.filter((r) => !sameDateValue(r, next))].slice(0, recentLimit);
1152
+ if (recentProp === void 0) setInternalRecent(list);
1153
+ if (key) writeStored(storage, key, list);
1154
+ onRecentChange?.(list);
1155
+ setOpen(false);
1156
+ };
1157
+ const step = (dir) => {
1158
+ if (!value) return;
1159
+ const next = shiftTimeRange(value, dir, readCtx());
1160
+ if (next) commit(next, "shift");
1161
+ };
1162
+ const zoomOut = () => {
1163
+ if (!value) return;
1164
+ const next = zoomTimeRange(value, 2, readCtx());
1165
+ if (next) commit(next, "zoom");
1166
+ };
1167
+ const atNow = value ? timeRangeReachesNow(value, ctx) : true;
1168
+ const text = value ? timeRangeLabel(value, ctx) : labels.anyTime;
1169
+ const canZoom = value != null && zoomTimeRange(value, 2, ctx) != null;
1170
+ const cancelling = loading && onCancelRefresh != null;
1171
+ const iconButton = (name, a11y, off, onPress) => /* @__PURE__ */ jsx(
1172
+ Pressable,
1173
+ {
1174
+ accessibilityRole: "button",
1175
+ accessibilityLabel: a11y,
1176
+ accessibilityState: { disabled: off },
1177
+ disabled: off,
1178
+ onPress,
1179
+ style: ({ pressed }) => [styles.square, off && styles.off, pressed && styles.pressed],
1180
+ children: /* @__PURE__ */ jsx(Icon, { name, size: theme.icon.sm, color: theme.color.text2 })
1181
+ }
1182
+ );
1183
+ return /* @__PURE__ */ jsxs(View, { style: [styles.root, style], children: [
1184
+ shift ? iconButton("chevrons-left", labels.moveBack, disabled || !value, () => step(-1)) : null,
1185
+ /* @__PURE__ */ jsxs(
1186
+ Pressable,
1187
+ {
1188
+ accessibilityRole: "button",
1189
+ accessibilityLabel: labels.triggerLabel(label, text),
1190
+ accessibilityHint: value ? timeRangeReceipt(value, ctx) : void 0,
1191
+ accessibilityState: { disabled, expanded: open },
1192
+ disabled,
1193
+ onPress: () => setOpen(true),
1194
+ style: ({ pressed }) => [styles.trigger, disabled && styles.off, pressed && styles.pressed],
1195
+ children: [
1196
+ /* @__PURE__ */ jsx(Icon, { name: "clock", size: theme.icon.sm, color: theme.color.text2 }),
1197
+ /* @__PURE__ */ jsx(Text, { numberOfLines: 1, style: styles.triggerText, children: text }),
1198
+ /* @__PURE__ */ jsx(Icon, { name: "chevron-down", size: theme.icon.sm, color: theme.color.text2 })
1199
+ ]
1200
+ }
1201
+ ),
1202
+ shift ? iconButton("chevrons-right", labels.moveForward, disabled || atNow, () => step(1)) : null,
1203
+ zoom ? iconButton("zoom-out", labels.zoomOut, disabled || !canZoom, zoomOut) : null,
1204
+ onRefresh ? /* @__PURE__ */ jsx(
1205
+ Button,
1206
+ {
1207
+ variant: "outline",
1208
+ size: "sm",
1209
+ disabled,
1210
+ loading: loading && !cancelling,
1211
+ leadingIcon: cancelling ? "x" : "refresh",
1212
+ accessibilityLabel: cancelling ? labels.cancelRefresh : labels.refresh,
1213
+ onPress: () => cancelling ? onCancelRefresh() : onRefresh(),
1214
+ children: cancelling ? labels.cancel : refreshIntervalMs(interval) ? interval : labels.refresh
1215
+ }
1216
+ ) : null,
1217
+ /* @__PURE__ */ jsx(Sheet, { open, onClose: () => setOpen(false), title: label, detents: ["half", "full"], children: /* @__PURE__ */ jsx(
1218
+ TimeRangeSheetBody,
1219
+ {
1220
+ ...panelOptions,
1221
+ ctx,
1222
+ value,
1223
+ options,
1224
+ recent,
1225
+ labels,
1226
+ dateLabels,
1227
+ onApply: commitFromSheet,
1228
+ onCancel: () => setOpen(false),
1229
+ children: onRefresh ? /* @__PURE__ */ jsxs(View, { style: styles.group, children: [
1230
+ /* @__PURE__ */ jsx(Text, { style: styles.partLabel, children: labels.autoRefresh }),
1231
+ /* @__PURE__ */ jsx(
1232
+ ScrollView,
1233
+ {
1234
+ horizontal: true,
1235
+ showsHorizontalScrollIndicator: false,
1236
+ contentContainerStyle: styles.chips,
1237
+ children: ["off", ...offered].map((i) => {
1238
+ const on = (refreshIntervalMs(interval) == null ? "off" : interval) === i;
1239
+ return /* @__PURE__ */ jsx(
1240
+ Pressable,
1241
+ {
1242
+ accessibilityRole: "radio",
1243
+ accessibilityState: { checked: on },
1244
+ accessibilityLabel: i === "off" ? labels.off : i,
1245
+ onPress: () => pickInterval(i),
1246
+ style: ({ pressed }) => [
1247
+ styles.chip,
1248
+ on && styles.chipOn,
1249
+ pressed && styles.pressed
1250
+ ],
1251
+ children: /* @__PURE__ */ jsx(Text, { style: [styles.chipText, on && styles.chipTextOn], children: i === "off" ? labels.off : i })
1252
+ },
1253
+ i
1254
+ );
1255
+ })
1256
+ }
1257
+ )
1258
+ ] }) : null
1259
+ },
1260
+ session
1261
+ ) })
1262
+ ] });
1263
+ }
1264
+ var sheet2 = createStyleSheet((theme) => ({
1265
+ root: { flexDirection: "row", alignItems: "center", gap: theme.space.s1 },
1266
+ square: {
1267
+ minWidth: theme.tapMin,
1268
+ minHeight: theme.tapMin,
1269
+ alignItems: "center",
1270
+ justifyContent: "center",
1271
+ borderRadius: theme.radius.md,
1272
+ borderWidth: theme.borderWidth.base,
1273
+ borderColor: theme.color.border,
1274
+ backgroundColor: theme.color.surface
1275
+ },
1276
+ trigger: {
1277
+ flexShrink: 1,
1278
+ flexDirection: "row",
1279
+ alignItems: "center",
1280
+ gap: theme.space.s2,
1281
+ minHeight: theme.tapMin,
1282
+ paddingHorizontal: theme.space.s3,
1283
+ borderRadius: theme.radius.md,
1284
+ borderWidth: theme.borderWidth.base,
1285
+ borderColor: theme.color.border,
1286
+ backgroundColor: theme.color.surface
1287
+ },
1288
+ triggerText: {
1289
+ flexShrink: 1,
1290
+ fontFamily: theme.font.sans,
1291
+ fontSize: theme.type.body.fontSize,
1292
+ lineHeight: theme.type.body.lineHeight,
1293
+ color: theme.color.text
1294
+ },
1295
+ off: { opacity: theme.state.disabledOpacity },
1296
+ pressed: { opacity: theme.state.pressedOpacity },
1297
+ group: { gap: theme.space.s1 },
1298
+ partLabel: {
1299
+ fontFamily: theme.font.sans,
1300
+ fontSize: theme.type.caption2.fontSize,
1301
+ lineHeight: theme.type.caption2.lineHeight,
1302
+ fontWeight: theme.fontWeight.bold,
1303
+ color: theme.color.text2
1304
+ },
1305
+ chips: { flexDirection: "row", gap: theme.space.s1 },
1306
+ chip: {
1307
+ minHeight: theme.tapMin,
1308
+ justifyContent: "center",
1309
+ paddingHorizontal: theme.space.s3,
1310
+ borderRadius: theme.radius.full,
1311
+ borderWidth: theme.borderWidth.base,
1312
+ borderColor: theme.color.border,
1313
+ backgroundColor: theme.color.surface
1314
+ },
1315
+ chipOn: { borderColor: theme.edge.accent, backgroundColor: theme.color.accentSoft },
1316
+ chipText: {
1317
+ fontFamily: theme.font.sans,
1318
+ fontSize: theme.type.footnote.fontSize,
1319
+ lineHeight: theme.type.footnote.lineHeight,
1320
+ color: theme.color.text
1321
+ },
1322
+ chipTextOn: { color: theme.color.accentOnSoft, fontWeight: theme.fontWeight.bold }
1323
+ }));
1324
+
1325
+ export { REFRESH_INTERVALS, TIME_RANGE_PERIODS, TIME_RANGE_UNITS, TIME_RANGE_VIEWS, TimeRangeControl, refreshIntervalMs };