@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
@@ -1,15 +1,29 @@
1
- import { Icon } from './chunk-TKVFVF5D.js';
2
- import * as React2 from 'react';
1
+ import { useLabels } from './chunk-APCWFOZW.js';
2
+ import { Icon } from './chunk-UXGIW7OK.js';
3
+ import { springConfig } from './chunk-J64KGCGX.js';
4
+ import * as React from 'react';
3
5
  import { StyleSheet, Pressable, Text, useWindowDimensions, Animated, Easing, AccessibilityInfo, Platform, findNodeHandle, BackHandler, PanResponder, View } from 'react-native';
4
6
  import { createStyleSheet, useLoamTheme, useStyles } from '@btndprojects/loam-theme-native';
5
7
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
6
8
 
9
+ // src/navigation/labels.ts
10
+ var DEFAULT_NAVIGATION_LABELS = {
11
+ back: "Back",
12
+ backTo: (title) => `Back to ${title}`,
13
+ cancel: "Cancel",
14
+ dismiss: "Dismiss"
15
+ };
16
+
7
17
  // src/navigation/geometry.ts
8
18
  var NAV_PARALLAX_RATIO = 0.3;
9
19
  var NAV_EDGE_HIT_WIDTH = 20;
10
20
  var NAV_AXIS_LOCK_SLOP = 8;
11
21
  var NAV_SWIPE_COMPLETE_FRACTION = 0.5;
12
22
  var NAV_SWIPE_COMPLETE_VELOCITY = 0.5;
23
+ var NAV_PREDICTIVE_SCALE = 0.9;
24
+ var NAV_PREDICTIVE_SHIFT = 0.05;
25
+ var NAV_PREDICTIVE_SPAN = 0.4;
26
+ var NAV_PREDICTIVE_FADE = 0.7;
13
27
  var NAV_TAB_FADE_SCALE = 0.97;
14
28
  var NAV_HERO_CONTENT_FADE_START = 0.5;
15
29
  var NAV_MODAL_TOP_INSET = 34;
@@ -48,6 +62,22 @@ function claimsHorizontalAxis(dx, dy, slop = NAV_AXIS_LOCK_SLOP) {
48
62
  function isFromLeadingEdge(x, width, rtl, edgeWidth = NAV_EDGE_HIT_WIDTH) {
49
63
  return rtl ? x >= width - edgeWidth : x <= edgeWidth;
50
64
  }
65
+ function isFromTrailingEdge(x, width, rtl, edgeWidth = NAV_EDGE_HIT_WIDTH) {
66
+ return isFromLeadingEdge(x, width, !rtl, edgeWidth);
67
+ }
68
+ function predictiveTravel(dx, fromLeading, rtl) {
69
+ return dx * directionSign(rtl) * (fromLeading ? 1 : -1);
70
+ }
71
+ function predictivePeek(travel, width) {
72
+ if (width <= 0) return 0;
73
+ return clampProgress(travel / (width * NAV_PREDICTIVE_SPAN));
74
+ }
75
+ function predictiveScale(peek) {
76
+ return 1 - (1 - NAV_PREDICTIVE_SCALE) * clampProgress(peek);
77
+ }
78
+ function predictiveShift(peek, width, fromLeading, rtl) {
79
+ return clampProgress(peek) * width * NAV_PREDICTIVE_SHIFT * directionSign(rtl) * (fromLeading ? 1 : -1);
80
+ }
51
81
  function modalTranslateY(progress, height) {
52
82
  return (1 - clampProgress(progress)) * height;
53
83
  }
@@ -78,15 +108,17 @@ function NavBackButton({
78
108
  previousTitle,
79
109
  platform: platformProp,
80
110
  accessibilityLabel,
81
- disabled = false
111
+ disabled = false,
112
+ labels: labelsProp
82
113
  }) {
83
- const theme = useLoamTheme();
114
+ const labels = useLabels("navigation", DEFAULT_NAVIGATION_LABELS, labelsProp);
115
+ const theme = useLoamTheme("navigation");
84
116
  const platform = platformProp ?? navPlatform(theme.platform);
85
117
  const { styles } = useStyles(sheet, { platform });
86
118
  const back = theme.rtl ? "chevron-right" : "chevron-left";
87
119
  const arrow = theme.rtl ? "arrow-right" : "arrow-left";
88
120
  const showTitle = platform === "iOS" && previousTitle !== void 0;
89
- const label = accessibilityLabel ?? (previousTitle ? `Back to ${previousTitle}` : "Back");
121
+ const label = accessibilityLabel ?? (previousTitle ? labels.backTo(previousTitle) : labels.back);
90
122
  return /* @__PURE__ */ jsxs(
91
123
  Pressable,
92
124
  {
@@ -121,38 +153,47 @@ function NavBar({
121
153
  previousTitle,
122
154
  onBack,
123
155
  backLabel,
156
+ labels,
124
157
  leading,
125
158
  trailing
126
159
  }) {
127
160
  const { styles } = useStyles(sheet, { platform });
128
- return /* @__PURE__ */ jsxs(View, { accessibilityRole: "header", style: styles.bar, children: [
161
+ return /* @__PURE__ */ jsxs(View, { style: styles.bar, children: [
129
162
  onBack ? /* @__PURE__ */ jsx(
130
163
  NavBackButton,
131
164
  {
132
165
  platform,
133
166
  previousTitle,
134
167
  accessibilityLabel: previousTitle ? void 0 : backLabel,
168
+ labels,
135
169
  onPress: onBack
136
170
  }
137
171
  ) : leading,
138
- /* @__PURE__ */ jsx(Text, { numberOfLines: 1, style: styles.barTitle, children: title }),
172
+ /* @__PURE__ */ jsx(Text, { accessibilityRole: "header", numberOfLines: 1, style: styles.barTitle, children: title }),
139
173
  trailing ? /* @__PURE__ */ jsx(View, { style: styles.barTrailing, children: trailing }) : null
140
174
  ] });
141
175
  }
176
+ function setInert(node, hidden) {
177
+ if (Platform.OS !== "web" || node == null) return;
178
+ node.inert = hidden;
179
+ }
142
180
  function navPlatform(platform) {
143
181
  return platform === "Android" ? "Android" : "iOS";
144
182
  }
145
- function NavigationStack({
183
+ function NavStack({
146
184
  screens,
147
185
  onPop,
148
186
  onExit,
149
187
  platform: platformProp,
150
188
  swipeEnabled,
151
- backLabel = "Back",
189
+ backLabel: backLabelProp,
190
+ labels: labelsProp,
152
191
  announce = true,
153
192
  style
154
193
  }) {
155
- const theme = useLoamTheme();
194
+ const labels = useLabels("navigation", DEFAULT_NAVIGATION_LABELS, labelsProp);
195
+ const backLabel = backLabelProp ?? labels.back;
196
+ const theme = useLoamTheme("navigation");
156
197
  const platform = platformProp ?? navPlatform(theme.platform);
157
198
  const { styles } = useStyles(sheet, { platform });
158
199
  const rtl = theme.rtl;
@@ -161,25 +202,27 @@ function NavigationStack({
161
202
  const depth = screens.length;
162
203
  const top = depth > 0 ? screens[depth - 1] : void 0;
163
204
  const below = depth > 1 ? screens[depth - 2] : void 0;
164
- const [width, setWidth] = React2.useState(window.width);
205
+ const [width, setWidth] = React.useState(window.width);
165
206
  const onRootLayout = (e) => {
166
207
  const next = e.nativeEvent.layout.width;
167
208
  if (next > 0) setWidth(next);
168
209
  };
169
- const progress = React2.useRef(new Animated.Value(1)).current;
170
- const [exiting, setExiting] = React2.useState(null);
210
+ const progress = React.useRef(new Animated.Value(1)).current;
211
+ const peek = React.useRef(new Animated.Value(0)).current;
212
+ const [peekFrom, setPeekFrom] = React.useState(null);
213
+ const [exiting, setExiting] = React.useState(null);
171
214
  const over = exiting ?? top;
172
215
  const under = exiting ? top : below;
173
216
  const page = theme.motion.page;
174
- const pageEasing = React2.useMemo(() => Easing.bezier(...page.easing), [page.easing]);
175
- const live = React2.useRef({ top, below, onPop, onExit, width, rtl });
217
+ const pageEasing = React.useMemo(() => Easing.bezier(...page.easing), [page.easing]);
218
+ const live = React.useRef({ top, below, onPop, onExit, width, rtl });
176
219
  live.current = { top, below, onPop, onExit, width, rtl };
177
- const screenRef = React2.useRef(null);
178
- const announceRef = React2.useRef(null);
179
- const pendingFocusRef = React2.useRef(null);
180
- const skipExitRef = React2.useRef(false);
181
- const historyRef = React2.useRef(null);
182
- const revealTop = React2.useCallback(
220
+ const screenRef = React.useRef(null);
221
+ const announceRef = React.useRef(null);
222
+ const pendingFocusRef = React.useRef(null);
223
+ const skipExitRef = React.useRef(false);
224
+ const historyRef = React.useRef(null);
225
+ const revealTop = React.useCallback(
183
226
  (screen) => {
184
227
  if (announce) {
185
228
  const text = screen.announcement ?? screen.title;
@@ -190,7 +233,7 @@ function NavigationStack({
190
233
  },
191
234
  [announce]
192
235
  );
193
- React2.useEffect(() => {
236
+ React.useEffect(() => {
194
237
  const wanted = pendingFocusRef.current;
195
238
  if (wanted === null || wanted !== top?.key) return;
196
239
  pendingFocusRef.current = null;
@@ -199,7 +242,7 @@ function NavigationStack({
199
242
  const tag = findNodeHandle(node);
200
243
  if (tag !== null) AccessibilityInfo.setAccessibilityFocus(tag);
201
244
  });
202
- React2.useEffect(() => {
245
+ React.useEffect(() => {
203
246
  const previous = historyRef.current;
204
247
  if (top) historyRef.current = { depth, key: top.key, screen: top };
205
248
  if (!top) return;
@@ -208,6 +251,8 @@ function NavigationStack({
208
251
  if (skipExitRef.current) {
209
252
  skipExitRef.current = false;
210
253
  progress.setValue(1);
254
+ peek.setValue(0);
255
+ setPeekFrom(null);
211
256
  revealTop(top);
212
257
  return;
213
258
  }
@@ -236,7 +281,7 @@ function NavigationStack({
236
281
  }
237
282
  revealTop(top);
238
283
  }, [depth, top?.key]);
239
- React2.useEffect(() => {
284
+ React.useEffect(() => {
240
285
  if (platform !== "Android") return;
241
286
  const subscription = BackHandler.addEventListener("hardwareBackPress", () => {
242
287
  const { top: current, below: parent, onPop: pop, onExit: exit } = live.current;
@@ -250,11 +295,33 @@ function NavigationStack({
250
295
  return () => subscription?.remove();
251
296
  }, [platform]);
252
297
  const canPop = under !== void 0 && over !== void 0;
253
- const swipeActive = (swipeEnabled ?? platform === "iOS") && canPop && exiting === null;
254
- const startXRef = React2.useRef(0);
255
- const swipeRef = React2.useRef({ active: swipeActive, page, pageEasing });
256
- swipeRef.current = { active: swipeActive, page, pageEasing };
257
- const pan = React2.useMemo(
298
+ const swipeActive = (swipeEnabled ?? true) && canPop && exiting === null;
299
+ const startXRef = React.useRef(0);
300
+ const fromLeadingRef = React.useRef(true);
301
+ const swipeRef = React.useRef({ active: swipeActive, page, pageEasing, platform, theme });
302
+ swipeRef.current = { active: swipeActive, page, pageEasing, platform, theme };
303
+ const settle = (t, android, speed, w) => {
304
+ if (android) {
305
+ const velocity2 = w > 0 ? speed / (w * NAV_PREDICTIVE_SPAN) * 1e3 : 0;
306
+ Animated.spring(peek, {
307
+ toValue: 0,
308
+ ...springConfig(t, "ss", { velocity: velocity2 }),
309
+ useNativeDriver: true
310
+ }).start(({ finished }) => {
311
+ if (finished) setPeekFrom(null);
312
+ });
313
+ return;
314
+ }
315
+ const velocity = w > 0 ? -speed / w * 1e3 : 0;
316
+ Animated.spring(progress, {
317
+ toValue: 1,
318
+ ...springConfig(t, "ss", { velocity }),
319
+ useNativeDriver: true
320
+ }).start();
321
+ };
322
+ const settleRef = React.useRef(settle);
323
+ settleRef.current = settle;
324
+ const pan = React.useMemo(
258
325
  () => PanResponder.create({
259
326
  onStartShouldSetPanResponderCapture: (e) => {
260
327
  startXRef.current = e.nativeEvent.locationX;
@@ -264,16 +331,39 @@ function NavigationStack({
264
331
  if (!swipeRef.current.active) return false;
265
332
  if (!claimsHorizontalAxis(g.dx, g.dy)) return false;
266
333
  const { width: w, rtl: isRtl } = live.current;
267
- return isFromLeadingEdge(startXRef.current, w, isRtl);
334
+ const x = startXRef.current;
335
+ if (isFromLeadingEdge(x, w, isRtl)) {
336
+ fromLeadingRef.current = true;
337
+ return true;
338
+ }
339
+ if (swipeRef.current.platform === "Android" && isFromTrailingEdge(x, w, isRtl)) {
340
+ fromLeadingRef.current = false;
341
+ return true;
342
+ }
343
+ return false;
344
+ },
345
+ onPanResponderGrant: () => {
346
+ if (swipeRef.current.platform !== "Android") return;
347
+ peek.stopAnimation();
348
+ setPeekFrom(fromLeadingRef.current ? "leading" : "trailing");
268
349
  },
269
350
  onPanResponderMove: (_e, g) => {
270
351
  const { width: w, rtl: isRtl } = live.current;
352
+ if (swipeRef.current.platform === "Android") {
353
+ const travel = predictiveTravel(g.dx, fromLeadingRef.current, isRtl);
354
+ peek.setValue(predictivePeek(travel, w));
355
+ return;
356
+ }
271
357
  progress.setValue(progressFromEdgeSwipe(g.dx, w, isRtl));
272
358
  },
273
359
  onPanResponderRelease: (_e, g) => {
274
360
  const { top: current, width: w, rtl: isRtl, onPop: pop } = live.current;
275
- const { page: spec, pageEasing: easing } = swipeRef.current;
276
- if (current && shouldCompletePop(g.dx, g.vx, w, isRtl)) {
361
+ const { page: spec, pageEasing: easing, platform: os } = swipeRef.current;
362
+ const android = os === "Android";
363
+ const fromLeading2 = android ? fromLeadingRef.current : true;
364
+ const travel = predictiveTravel(g.dx, fromLeading2, isRtl);
365
+ const speed = predictiveTravel(g.vx, fromLeading2, isRtl);
366
+ if (current && shouldCompletePop(travel, speed, w, false)) {
277
367
  Animated.timing(progress, {
278
368
  toValue: 0,
279
369
  duration: spec.duration,
@@ -282,41 +372,68 @@ function NavigationStack({
282
372
  }).start(({ finished }) => {
283
373
  if (!finished) return;
284
374
  skipExitRef.current = true;
285
- pop?.(current, "edge-swipe");
375
+ pop?.(current, android ? "system-back" : "edge-swipe");
286
376
  });
287
377
  return;
288
378
  }
289
- Animated.spring(progress, { toValue: 1, useNativeDriver: true }).start();
379
+ settleRef.current(swipeRef.current.theme, android, speed, w);
290
380
  },
291
381
  onPanResponderTerminate: () => {
292
- Animated.spring(progress, { toValue: 1, useNativeDriver: true }).start();
382
+ const { platform: os, theme: t } = swipeRef.current;
383
+ settleRef.current(t, os === "Android", 0, live.current.width);
293
384
  }
294
385
  }),
295
- [progress]
386
+ [progress, peek]
296
387
  );
297
- const overTranslateX = React2.useMemo(
388
+ const overTranslateX = React.useMemo(
298
389
  () => progress.interpolate({
299
390
  inputRange: [0, 1],
300
391
  outputRange: [incomingTranslateX(0, width, rtl), incomingTranslateX(1, width, rtl)]
301
392
  }),
302
393
  [progress, width, rtl]
303
394
  );
304
- const underTranslateX = React2.useMemo(
395
+ const underTranslateX = React.useMemo(
305
396
  () => progress.interpolate({
306
397
  inputRange: [0, 1],
307
398
  outputRange: [parallaxTranslateX(0, width, rtl), parallaxTranslateX(1, width, rtl)]
308
399
  }),
309
400
  [progress, width, rtl]
310
401
  );
311
- const dimOpacity = React2.useMemo(
402
+ const dimOpacity = React.useMemo(
312
403
  () => progress.interpolate({
313
404
  inputRange: [0, 1],
314
405
  outputRange: [parallaxDimOpacity(0), parallaxDimOpacity(1)]
315
406
  }),
316
407
  [progress]
317
408
  );
318
- const overStyle = reduce ? { opacity: progress } : { transform: [{ translateX: overTranslateX }] };
319
- const underStyle = reduce ? {} : { transform: [{ translateX: underTranslateX }] };
409
+ const fromLeading = peekFrom !== "trailing";
410
+ const peekScale = React.useMemo(
411
+ () => peek.interpolate({
412
+ inputRange: [0, 1],
413
+ outputRange: [predictiveScale(0), predictiveScale(1)]
414
+ }),
415
+ [peek]
416
+ );
417
+ const peekShift = React.useMemo(
418
+ () => peek.interpolate({
419
+ inputRange: [0, 1],
420
+ outputRange: [0, predictiveShift(1, width, fromLeading, rtl)]
421
+ }),
422
+ [peek, width, fromLeading, rtl]
423
+ );
424
+ const peekUnwind = React.useMemo(
425
+ () => peek.interpolate({ inputRange: [0, 1], outputRange: [1, 0], extrapolate: "clamp" }),
426
+ [peek]
427
+ );
428
+ const peekFade = React.useMemo(
429
+ () => peek.interpolate({ inputRange: [0, 1], outputRange: [1, NAV_PREDICTIVE_FADE] }),
430
+ [peek]
431
+ );
432
+ const overStyle = reduce ? { opacity: Animated.multiply(progress, peekFade) } : {
433
+ transform: [{ translateX: Animated.add(overTranslateX, peekShift) }, { scale: peekScale }]
434
+ };
435
+ const underStyle = reduce ? {} : { transform: [{ translateX: Animated.multiply(underTranslateX, peekUnwind) }] };
436
+ const underDim = Animated.multiply(dimOpacity, peekUnwind);
320
437
  if (!over) return /* @__PURE__ */ jsx(View, { style: [styles.root, style] });
321
438
  const rootScreen = screens[0];
322
439
  const overIsRoot = over === rootScreen;
@@ -325,9 +442,18 @@ function NavigationStack({
325
442
  under ? /* @__PURE__ */ jsxs(
326
443
  Animated.View,
327
444
  {
328
- ref: exiting ? screenRef : void 0,
445
+ ref: (node) => {
446
+ if (exiting) screenRef.current = node;
447
+ setInert(node, !exiting);
448
+ },
329
449
  role: "group",
330
450
  accessibilityLabel: under.title,
451
+ ...exiting ? null : {
452
+ accessibilityElementsHidden: true,
453
+ importantForAccessibility: "no-hide-descendants",
454
+ pointerEvents: "none",
455
+ "aria-hidden": true
456
+ },
331
457
  style: [styles.screen, underIsRoot ? styles.screenRoot : styles.screenPushed, underStyle],
332
458
  children: [
333
459
  under.hideBar ? null : /* @__PURE__ */ jsx(
@@ -337,7 +463,8 @@ function NavigationStack({
337
463
  title: under.title,
338
464
  leading: under.leading,
339
465
  trailing: under.trailing,
340
- backLabel
466
+ backLabel,
467
+ labels: labelsProp
341
468
  }
342
469
  ),
343
470
  /* @__PURE__ */ jsx(View, { style: styles.body, children: under.content }),
@@ -345,7 +472,7 @@ function NavigationStack({
345
472
  Animated.View,
346
473
  {
347
474
  pointerEvents: "none",
348
- style: [StyleSheet.absoluteFill, styles.dim, { opacity: dimOpacity }]
475
+ style: [StyleSheet.absoluteFill, styles.dim, { opacity: underDim }]
349
476
  }
350
477
  )
351
478
  ]
@@ -355,11 +482,22 @@ function NavigationStack({
355
482
  /* @__PURE__ */ jsxs(
356
483
  Animated.View,
357
484
  {
358
- ref: exiting ? void 0 : screenRef,
485
+ ref: (node) => {
486
+ if (!exiting) screenRef.current = node;
487
+ setInert(node, exiting !== null);
488
+ },
359
489
  role: "group",
360
490
  accessibilityLabel: over.title,
361
491
  pointerEvents: exiting ? "none" : "auto",
362
- style: [styles.screen, overIsRoot ? styles.screenRoot : styles.screenPushed, overStyle],
492
+ accessibilityElementsHidden: exiting !== null,
493
+ importantForAccessibility: exiting ? "no-hide-descendants" : "auto",
494
+ ...exiting ? { "aria-hidden": true } : null,
495
+ style: [
496
+ styles.screen,
497
+ overIsRoot ? styles.screenRoot : styles.screenPushed,
498
+ peekFrom !== null && !reduce ? styles.screenPeeking : null,
499
+ overStyle
500
+ ],
363
501
  ...swipeActive ? pan.panHandlers : {},
364
502
  children: [
365
503
  over.hideBar ? null : /* @__PURE__ */ jsx(
@@ -374,7 +512,8 @@ function NavigationStack({
374
512
  } : void 0,
375
513
  leading: over.leading,
376
514
  trailing: over.trailing,
377
- backLabel
515
+ backLabel,
516
+ labels: labelsProp
378
517
  }
379
518
  ),
380
519
  /* @__PURE__ */ jsx(View, { style: styles.body, children: over.content })
@@ -407,6 +546,12 @@ var sheet = createStyleSheet((theme) => ({
407
546
  backgroundColor: theme.color.surface,
408
547
  ...theme.shadow.lg
409
548
  },
549
+ // A screen held in a predictive-back preview reads as a card lifted off the
550
+ // stack: rounded and clipped to the radius while it is shrunk.
551
+ screenPeeking: {
552
+ borderRadius: theme.radius.lg,
553
+ overflow: "hidden"
554
+ },
410
555
  // The wash over the parallaxing parent. `scrimLight` already carries the
411
556
  // alpha, so the animation only scales it from 0 to 1.
412
557
  dim: {
@@ -415,7 +560,7 @@ var sheet = createStyleSheet((theme) => ({
415
560
  body: {
416
561
  flex: 1
417
562
  },
418
- // Matches `Header`'s metrics: `layout.appbarH` is the only height in the
563
+ // Matches `NavHeader`'s metrics: `layout.appbarH` is the only height in the
419
564
  // system that branches on platform (44 on iOS, 64 on Android).
420
565
  bar: {
421
566
  flexDirection: "row",
@@ -488,27 +633,35 @@ var sheet = createStyleSheet((theme) => ({
488
633
  }
489
634
  }));
490
635
  var FALLBACK_PANEL_HEIGHT = 640;
636
+ function setInert2(node, hidden) {
637
+ if (Platform.OS !== "web" || node == null) return;
638
+ node.inert = hidden;
639
+ }
491
640
  function NavModal({
492
641
  open,
493
642
  title,
494
643
  onDismiss,
495
- dismissLabel = "Cancel",
644
+ dismissLabel: dismissLabelProp,
496
645
  confirmLabel,
497
646
  onConfirm,
498
647
  children,
499
648
  announcement,
500
- scrimLabel = "Dismiss"
649
+ scrimLabel: scrimLabelProp,
650
+ labels: labelsProp
501
651
  }) {
502
- const theme = useLoamTheme();
652
+ const labels = useLabels("navigation", DEFAULT_NAVIGATION_LABELS, labelsProp);
653
+ const dismissLabel = dismissLabelProp ?? labels.cancel;
654
+ const scrimLabel = scrimLabelProp ?? labels.dismiss;
655
+ const theme = useLoamTheme("navigation");
503
656
  const { styles } = useStyles(sheet2);
504
- const [mounted, setMounted] = React2.useState(open);
505
- const progress = React2.useRef(new Animated.Value(0)).current;
506
- const heightRef = React2.useRef(FALLBACK_PANEL_HEIGHT);
657
+ const [mounted, setMounted] = React.useState(open);
658
+ const progress = React.useRef(new Animated.Value(0)).current;
659
+ const heightRef = React.useRef(FALLBACK_PANEL_HEIGHT);
507
660
  const enter = theme.motion.enter;
508
661
  const exit = theme.motion.exit;
509
- const enterEasing = React2.useMemo(() => Easing.bezier(...enter.easing), [enter.easing]);
510
- const exitEasing = React2.useMemo(() => Easing.bezier(...exit.easing), [exit.easing]);
511
- React2.useEffect(() => {
662
+ const enterEasing = React.useMemo(() => Easing.bezier(...enter.easing), [enter.easing]);
663
+ const exitEasing = React.useMemo(() => Easing.bezier(...exit.easing), [exit.easing]);
664
+ React.useEffect(() => {
512
665
  if (open) {
513
666
  setMounted(true);
514
667
  AccessibilityInfo.announceForAccessibility(announcement ?? title);
@@ -524,7 +677,7 @@ function NavModal({
524
677
  if (finished) setMounted(false);
525
678
  });
526
679
  }, [open]);
527
- React2.useEffect(() => {
680
+ React.useEffect(() => {
528
681
  if (!mounted || !open) return;
529
682
  progress.setValue(0);
530
683
  Animated.timing(progress, {
@@ -534,7 +687,7 @@ function NavModal({
534
687
  useNativeDriver: true
535
688
  }).start();
536
689
  }, [mounted]);
537
- const [panelHeight, setPanelHeight] = React2.useState(FALLBACK_PANEL_HEIGHT);
690
+ const [panelHeight, setPanelHeight] = React.useState(FALLBACK_PANEL_HEIGHT);
538
691
  const onPanelLayout = (e) => {
539
692
  const next = e.nativeEvent.layout.height;
540
693
  if (next > 0 && next !== heightRef.current) {
@@ -542,7 +695,7 @@ function NavModal({
542
695
  setPanelHeight(next);
543
696
  }
544
697
  };
545
- const translateY = React2.useMemo(
698
+ const translateY = React.useMemo(
546
699
  () => progress.interpolate({
547
700
  inputRange: [0, 1],
548
701
  outputRange: [modalTranslateY(0, panelHeight), modalTranslateY(1, panelHeight)]
@@ -610,18 +763,18 @@ function NavTabView({
610
763
  announce = true,
611
764
  style
612
765
  }) {
613
- const theme = useLoamTheme();
766
+ const theme = useLoamTheme("navigation");
614
767
  const { styles } = useStyles(sheet2);
615
768
  const page = theme.motion.page;
616
- const pageEasing = React2.useMemo(() => Easing.bezier(...page.easing), [page.easing]);
769
+ const pageEasing = React.useMemo(() => Easing.bezier(...page.easing), [page.easing]);
617
770
  const active = tabs.find((tab) => tab.value === value);
618
- const [outgoing, setOutgoing] = React2.useState(null);
619
- const previousRef = React2.useRef(active);
620
- const visited = React2.useRef(new Set(active ? [active.value] : []));
771
+ const [outgoing, setOutgoing] = React.useState(null);
772
+ const previousRef = React.useRef(active);
773
+ const visited = React.useRef(new Set(active ? [active.value] : []));
621
774
  if (active) visited.current.add(active.value);
622
775
  const panes = tabs.filter((tab) => visited.current.has(tab.value));
623
- const fade = React2.useRef(new Animated.Value(1)).current;
624
- React2.useEffect(() => {
776
+ const fade = React.useRef(new Animated.Value(1)).current;
777
+ React.useEffect(() => {
625
778
  const previous = previousRef.current;
626
779
  previousRef.current = active;
627
780
  if (!active || !previous || previous.value === active.value) return;
@@ -652,6 +805,7 @@ function NavTabView({
652
805
  return /* @__PURE__ */ jsx(
653
806
  Animated.View,
654
807
  {
808
+ ref: (node) => setInert2(node, !isActive),
655
809
  role: "group",
656
810
  accessibilityLabel: pane.title,
657
811
  importantForAccessibility: isActive ? "auto" : "no-hide-descendants",
@@ -675,21 +829,21 @@ function NavHero({
675
829
  accessibilityLabel,
676
830
  announcement
677
831
  }) {
678
- const theme = useLoamTheme();
832
+ const theme = useLoamTheme("navigation");
679
833
  const { styles } = useStyles(sheet2);
680
834
  const reduce = theme.reduceMotion;
681
835
  const hero = theme.motion.hero;
682
- const heroEasing = React2.useMemo(() => Easing.bezier(...hero.easing), [hero.easing]);
683
- const [mounted, setMounted] = React2.useState(active);
684
- const progress = React2.useRef(new Animated.Value(0)).current;
685
- const [bounds, setBounds] = React2.useState(null);
836
+ const heroEasing = React.useMemo(() => Easing.bezier(...hero.easing), [hero.easing]);
837
+ const [mounted, setMounted] = React.useState(active);
838
+ const progress = React.useRef(new Animated.Value(0)).current;
839
+ const [bounds, setBounds] = React.useState(null);
686
840
  const onRootLayout = (e) => {
687
841
  const { width, height } = e.nativeEvent.layout;
688
842
  if (width > 0 && height > 0) setBounds({ x: 0, y: 0, width, height });
689
843
  };
690
- const endRef = React2.useRef(onMorphEnd);
844
+ const endRef = React.useRef(onMorphEnd);
691
845
  endRef.current = onMorphEnd;
692
- React2.useEffect(() => {
846
+ React.useEffect(() => {
693
847
  if (active) {
694
848
  setMounted(true);
695
849
  if (announcement ?? accessibilityLabel) {
@@ -709,7 +863,7 @@ function NavHero({
709
863
  endRef.current?.(false);
710
864
  });
711
865
  }, [active]);
712
- React2.useEffect(() => {
866
+ React.useEffect(() => {
713
867
  if (!mounted || !active) return;
714
868
  progress.setValue(0);
715
869
  Animated.timing(progress, {
@@ -871,4 +1025,4 @@ var sheet2 = createStyleSheet((theme) => ({
871
1025
  }
872
1026
  }));
873
1027
 
874
- export { NAV_AXIS_LOCK_SLOP, NAV_EDGE_HIT_WIDTH, NAV_HERO_CONTENT_FADE_START, NAV_MODAL_HEADER_HEIGHT, NAV_MODAL_TOP_INSET, NAV_PARALLAX_RATIO, NAV_SWIPE_COMPLETE_FRACTION, NAV_SWIPE_COMPLETE_VELOCITY, NAV_TAB_FADE_SCALE, NavBackButton, NavHero, NavModal, NavTabView, NavigationStack, claimsHorizontalAxis, clampProgress, directionSign, heroContentOpacity, heroTransform, incomingTranslateX, isFromLeadingEdge, modalTranslateY, parallaxDimOpacity, parallaxTranslateX, progressFromEdgeSwipe, shouldCompletePop, tabFadeScale };
1028
+ export { NAV_AXIS_LOCK_SLOP, NAV_EDGE_HIT_WIDTH, NAV_HERO_CONTENT_FADE_START, NAV_MODAL_HEADER_HEIGHT, NAV_MODAL_TOP_INSET, NAV_PARALLAX_RATIO, NAV_PREDICTIVE_FADE, NAV_PREDICTIVE_SCALE, NAV_PREDICTIVE_SHIFT, NAV_PREDICTIVE_SPAN, NAV_SWIPE_COMPLETE_FRACTION, NAV_SWIPE_COMPLETE_VELOCITY, NAV_TAB_FADE_SCALE, NavBackButton, NavHero, NavModal, NavStack, NavTabView, claimsHorizontalAxis, clampProgress, directionSign, heroContentOpacity, heroTransform, incomingTranslateX, isFromLeadingEdge, isFromTrailingEdge, modalTranslateY, parallaxDimOpacity, parallaxTranslateX, predictivePeek, predictiveScale, predictiveShift, predictiveTravel, progressFromEdgeSwipe, shouldCompletePop, tabFadeScale };
@@ -1,9 +1,12 @@
1
+ import { useLabels } from './chunk-APCWFOZW.js';
1
2
  import * as React from 'react';
2
3
  import { View, Text } from 'react-native';
3
4
  import { createStyleSheet, useStyles, useLoamTheme } from '@btndprojects/loam-theme-native';
4
5
  import { jsx, jsxs } from 'react/jsx-runtime';
5
6
 
6
- // src/description-list/description-list.tsx
7
+ var DEFAULT_LABELS = {
8
+ pair: (term, description) => `${term}, ${description}`
9
+ };
7
10
  var DescriptionListContext = React.createContext({
8
11
  layout: "stacked",
9
12
  density: "comfortable"
@@ -15,12 +18,13 @@ function DescriptionList({
15
18
  items,
16
19
  // Accepted for API consistency; static data drives no motion.
17
20
  motion: _motion,
18
- children
21
+ children,
22
+ labels
19
23
  }) {
20
24
  const { styles } = useStyles(sheet);
21
25
  const ctx = React.useMemo(
22
- () => ({ layout, density }),
23
- [layout, density]
26
+ () => ({ layout, density, labels }),
27
+ [layout, density, labels]
24
28
  );
25
29
  const rows = [
26
30
  ...items?.map((entry, i) => /* @__PURE__ */ jsx(DescriptionItem, { term: entry.term, description: entry.description }, `item-${i}`)) ?? [],
@@ -33,13 +37,15 @@ function DescriptionList({
33
37
  }
34
38
  function DescriptionItem({
35
39
  term,
36
- description
40
+ description,
41
+ labels: labelsProp
37
42
  }) {
38
- const { layout, density } = React.useContext(DescriptionListContext);
43
+ const { layout, density, labels: ctxLabels } = React.useContext(DescriptionListContext);
44
+ const labels = useLabels("descriptionList", DEFAULT_LABELS, labelsProp ?? ctxLabels);
39
45
  const { styles } = useStyles(sheet, { layout, density });
40
- const theme = useLoamTheme();
46
+ const theme = useLoamTheme("description-list");
41
47
  const isInline = layout === "inline";
42
- const pairLabel = typeof term === "string" && typeof description === "string" ? `${term}, ${description}` : void 0;
48
+ const pairLabel = typeof term === "string" && typeof description === "string" ? labels.pair(term, description) : void 0;
43
49
  return /* @__PURE__ */ jsxs(
44
50
  View,
45
51
  {