@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,339 @@
1
+ import { useLabels } from './chunk-APCWFOZW.js';
2
+ import { Icon } from './chunk-UXGIW7OK.js';
3
+ import * as React from 'react';
4
+ import { Animated, Pressable, Text, Easing, Platform, findNodeHandle, AccessibilityInfo, Modal, View } from 'react-native';
5
+ import { useStyles, createStyleSheet, useLoamTheme } from '@btndprojects/loam-theme-native';
6
+ import { jsx, jsxs } from 'react/jsx-runtime';
7
+
8
+ var AnimatedPressable = Animated.createAnimatedComponent(Pressable);
9
+ var memoryStore = /* @__PURE__ */ new Map();
10
+ var defaultRememberStorage = {
11
+ getItem: (key) => memoryStore.get(key) ?? null,
12
+ setItem: (key, value) => {
13
+ memoryStore.set(key, value);
14
+ }
15
+ };
16
+ function measureBox(node) {
17
+ return new Promise((resolve) => {
18
+ if (!node?.measureInWindow) return resolve(null);
19
+ node.measureInWindow((x, y, w, h) => resolve(Number.isFinite(x) && w > 0 && h > 0 ? { x, y, w, h } : null));
20
+ });
21
+ }
22
+ var DEFAULT_LABELS = {
23
+ closeDialog: "Close dialog",
24
+ close: "Close"
25
+ };
26
+ function Dialog({
27
+ open,
28
+ defaultOpen = false,
29
+ onClose,
30
+ onOpenChange,
31
+ dismissible = true,
32
+ remember = false,
33
+ rememberKey,
34
+ storage = defaultRememberStorage,
35
+ title,
36
+ description,
37
+ showClose = dismissible,
38
+ accessibilityLabel,
39
+ motion = "full",
40
+ morphFrom,
41
+ children,
42
+ labels: labelsProp
43
+ }) {
44
+ const labels = useLabels("dialog", DEFAULT_LABELS, labelsProp);
45
+ const theme = useLoamTheme("dialog");
46
+ const { styles } = useStyles(sheet);
47
+ const controlled = open !== void 0;
48
+ const persist = remember && rememberKey != null;
49
+ const reducedMotion = theme.reduceMotion || motion === "reduced";
50
+ const instantMotion = motion === "none";
51
+ const [internalOpen, setInternalOpen] = React.useState(() => {
52
+ if (!controlled && persist) {
53
+ const v = storage.getItem(rememberKey);
54
+ if (v === "open") return true;
55
+ if (v === "closed") return false;
56
+ }
57
+ return defaultOpen;
58
+ });
59
+ const actualOpen = controlled ? open : internalOpen;
60
+ const setOpen = React.useCallback(
61
+ (next) => {
62
+ if (persist) storage.setItem(rememberKey, next ? "open" : "closed");
63
+ if (!controlled) setInternalOpen(next);
64
+ onOpenChange?.(next);
65
+ },
66
+ [persist, rememberKey, storage, controlled, onOpenChange]
67
+ );
68
+ const requestDismiss = React.useCallback(() => {
69
+ if (!dismissible) return;
70
+ setOpen(false);
71
+ onClose?.();
72
+ }, [dismissible, setOpen, onClose]);
73
+ const [mounted, setMounted] = React.useState(actualOpen);
74
+ const progress = React.useRef(new Animated.Value(actualOpen ? 1 : 0)).current;
75
+ const canMorph = !!morphFrom && !reducedMotion && !instantMotion;
76
+ const rootRef = React.useRef(null);
77
+ const cardRef = React.useRef(null);
78
+ const fly = React.useRef(new Animated.Value(1)).current;
79
+ const [pending, setPending] = React.useState(false);
80
+ const [flight, setFlight] = React.useState(null);
81
+ const closingMorph = React.useRef(false);
82
+ const flightFor = React.useCallback(async () => {
83
+ const [src, dst, root] = await Promise.all([
84
+ measureBox(morphFrom?.current),
85
+ measureBox(cardRef.current),
86
+ measureBox(rootRef.current)
87
+ ]);
88
+ if (!src || !dst) return null;
89
+ const ox = root?.x ?? 0;
90
+ const oy = root?.y ?? 0;
91
+ const radius = Math.abs(src.w - src.h) < 2 ? src.h / 2 : Math.min(src.h / 2, theme.radius.md);
92
+ return { src: { ...src, x: src.x - ox, y: src.y - oy }, dst: { ...dst, x: dst.x - ox, y: dst.y - oy }, radius };
93
+ }, [morphFrom, theme.radius.md]);
94
+ const onCardLayout = React.useCallback(() => {
95
+ if (!pending) return;
96
+ void flightFor().then((f) => {
97
+ setPending(false);
98
+ if (!f) return;
99
+ setFlight(f);
100
+ fly.setValue(0);
101
+ Animated.timing(fly, {
102
+ toValue: 1,
103
+ duration: theme.motion.expand.duration,
104
+ easing: Easing.bezier(...theme.motion.expand.easing),
105
+ useNativeDriver: false
106
+ }).start(() => setFlight(null));
107
+ });
108
+ }, [pending, flightFor, fly, theme.motion.expand]);
109
+ React.useEffect(() => {
110
+ const easing = Easing.bezier(...theme.easing.base);
111
+ if (actualOpen) {
112
+ setMounted(true);
113
+ closingMorph.current = false;
114
+ if (canMorph) setPending(true);
115
+ if (instantMotion) {
116
+ progress.setValue(1);
117
+ return;
118
+ }
119
+ Animated.timing(progress, {
120
+ toValue: 1,
121
+ duration: theme.duration.base,
122
+ easing,
123
+ useNativeDriver: true
124
+ }).start();
125
+ } else {
126
+ if (instantMotion) {
127
+ progress.setValue(0);
128
+ setMounted(false);
129
+ return;
130
+ }
131
+ if (canMorph) {
132
+ closingMorph.current = true;
133
+ setPending(false);
134
+ void flightFor().then((f) => {
135
+ if (!closingMorph.current) return;
136
+ if (!f) {
137
+ closingMorph.current = false;
138
+ setMounted(false);
139
+ return;
140
+ }
141
+ setFlight(f);
142
+ fly.setValue(1);
143
+ Animated.timing(fly, {
144
+ toValue: 0,
145
+ duration: theme.motion.collapse.duration,
146
+ easing: Easing.bezier(...theme.motion.collapse.easing),
147
+ useNativeDriver: false
148
+ }).start(() => {
149
+ if (!closingMorph.current) return;
150
+ closingMorph.current = false;
151
+ setFlight(null);
152
+ setMounted(false);
153
+ });
154
+ });
155
+ }
156
+ Animated.timing(progress, {
157
+ toValue: 0,
158
+ duration: theme.motion.exit.duration,
159
+ easing: Easing.bezier(...theme.motion.exit.easing),
160
+ useNativeDriver: true
161
+ }).start(({ finished }) => {
162
+ if (finished && !closingMorph.current) setMounted(false);
163
+ });
164
+ }
165
+ }, [
166
+ actualOpen,
167
+ progress,
168
+ theme.duration.base,
169
+ theme.easing.base,
170
+ theme.motion.exit.duration,
171
+ theme.motion.exit.easing,
172
+ instantMotion,
173
+ canMorph,
174
+ flightFor,
175
+ fly,
176
+ theme.motion.collapse
177
+ ]);
178
+ const titleRef = React.useRef(null);
179
+ const cardMounted = mounted;
180
+ React.useEffect(() => {
181
+ if (!actualOpen || !cardMounted || Platform.OS === "web") return;
182
+ const node = titleRef.current;
183
+ const tag = node ? findNodeHandle(node) : null;
184
+ if (tag !== null) AccessibilityInfo.setAccessibilityFocus(tag);
185
+ }, [actualOpen, cardMounted]);
186
+ if (!mounted) return null;
187
+ const cardScale = reducedMotion || canMorph ? 1 : progress.interpolate({ inputRange: [0, 1], outputRange: [0.96, 1] });
188
+ const lerp = (a, b) => fly.interpolate({ inputRange: [0, 1], outputRange: [a, b] });
189
+ const clipStyle = flight ? [
190
+ styles.clip,
191
+ {
192
+ left: lerp(flight.src.x, flight.dst.x),
193
+ top: lerp(flight.src.y, flight.dst.y),
194
+ width: lerp(flight.src.w, flight.dst.w),
195
+ height: lerp(flight.src.h, flight.dst.h),
196
+ borderRadius: lerp(flight.radius, theme.radius.xl)
197
+ }
198
+ ] : styles.rest;
199
+ const innerStyle = flight ? {
200
+ position: "absolute",
201
+ left: lerp(flight.dst.x - flight.src.x, 0),
202
+ top: lerp(flight.dst.y - flight.src.y, 0),
203
+ width: flight.dst.w,
204
+ // The content arrives once the clip is big enough to hold it.
205
+ opacity: fly.interpolate({ inputRange: [0, 0.4, 1], outputRange: [0, 0, 1] })
206
+ } : styles.rest;
207
+ const cardStyle = flight ? [styles.card, styles.flat, { width: flight.dst.w, maxWidth: flight.dst.w }] : [styles.card, { opacity: pending ? 0 : progress, transform: [{ scale: cardScale }] }];
208
+ return /* @__PURE__ */ jsx(Modal, { transparent: true, visible: mounted, animationType: "none", onRequestClose: requestDismiss, children: /* @__PURE__ */ jsxs(View, { ref: rootRef, collapsable: false, style: styles.root, children: [
209
+ /* @__PURE__ */ jsx(
210
+ AnimatedPressable,
211
+ {
212
+ accessibilityRole: "button",
213
+ accessibilityLabel: labels.closeDialog,
214
+ accessibilityElementsHidden: !dismissible,
215
+ importantForAccessibility: dismissible ? "auto" : "no-hide-descendants",
216
+ onPress: dismissible ? requestDismiss : void 0,
217
+ style: [styles.scrim, { opacity: progress }]
218
+ }
219
+ ),
220
+ /* @__PURE__ */ jsx(Animated.View, { style: clipStyle, children: /* @__PURE__ */ jsx(Animated.View, { style: innerStyle, children: /* @__PURE__ */ jsxs(
221
+ Animated.View,
222
+ {
223
+ ref: cardRef,
224
+ role: "dialog",
225
+ accessibilityViewIsModal: true,
226
+ accessibilityLabel: accessibilityLabel ?? title,
227
+ onLayout: onCardLayout,
228
+ style: cardStyle,
229
+ children: [
230
+ showClose ? /* @__PURE__ */ jsx(
231
+ Pressable,
232
+ {
233
+ accessibilityRole: "button",
234
+ accessibilityLabel: labels.close,
235
+ onPress: requestDismiss,
236
+ style: styles.close,
237
+ hitSlop: 8,
238
+ children: /* @__PURE__ */ jsx(Icon, { name: "x", size: 20, color: theme.color.text3 })
239
+ }
240
+ ) : null,
241
+ title ? /* @__PURE__ */ jsx(DialogTitle, { ref: titleRef, children: title }) : null,
242
+ description ? /* @__PURE__ */ jsx(DialogDescription, { children: description }) : null,
243
+ children
244
+ ]
245
+ }
246
+ ) }) })
247
+ ] }) });
248
+ }
249
+ var DialogTitle = React.forwardRef(
250
+ function DialogTitle2({ children }, ref) {
251
+ const { styles } = useStyles(sheet);
252
+ return /* @__PURE__ */ jsx(Text, { ref, accessibilityRole: "header", style: styles.title, children });
253
+ }
254
+ );
255
+ function DialogDescription({ children }) {
256
+ const { styles } = useStyles(sheet);
257
+ return /* @__PURE__ */ jsx(Text, { style: styles.description, children });
258
+ }
259
+ function DialogFooter({ children }) {
260
+ const { styles } = useStyles(sheet);
261
+ return /* @__PURE__ */ jsx(View, { style: styles.footer, children });
262
+ }
263
+ var sheet = createStyleSheet((theme) => ({
264
+ root: {
265
+ flex: 1,
266
+ alignItems: "center",
267
+ justifyContent: "center",
268
+ padding: theme.space.s5
269
+ },
270
+ scrim: {
271
+ position: "absolute",
272
+ top: 0,
273
+ left: 0,
274
+ right: 0,
275
+ bottom: 0,
276
+ backgroundColor: theme.color.scrim
277
+ },
278
+ // loam-contrast-ignore — the boundary here is the scrim, not the shadow.
279
+ // `color.scrim` is a 44% wash and is *not* re-resolved by high contrast, so
280
+ // this surface is still separated from the page when the elevation zeroes
281
+ // out. A border would put a hairline around every modal for no gain.
282
+ card: {
283
+ width: "100%",
284
+ // The reference width, which is now a named tier rather than a literal.
285
+ maxWidth: theme.panel.xl,
286
+ alignSelf: "center",
287
+ backgroundColor: theme.color.surface,
288
+ borderRadius: theme.radius.xl,
289
+ padding: theme.space.s5,
290
+ gap: theme.space.s3,
291
+ ...theme.shadow.lg
292
+ },
293
+ // The pass-through wrappers around the card at rest: full width, centring it.
294
+ rest: {
295
+ width: "100%",
296
+ alignItems: "center"
297
+ },
298
+ // The travelling clip while the card morphs to or from its source.
299
+ clip: {
300
+ position: "absolute",
301
+ overflow: "hidden",
302
+ backgroundColor: theme.color.surface
303
+ },
304
+ // No shadow in flight: overflow clipping would cut it anyway.
305
+ flat: {
306
+ shadowOpacity: 0,
307
+ elevation: 0
308
+ },
309
+ close: {
310
+ position: "absolute",
311
+ top: theme.space.s3,
312
+ right: theme.space.s3,
313
+ zIndex: 1,
314
+ padding: theme.space.s1,
315
+ borderRadius: theme.radius.full
316
+ },
317
+ title: {
318
+ fontFamily: theme.font.display,
319
+ fontWeight: `${theme.font.displayWeight}`,
320
+ fontSize: theme.fontSize[26],
321
+ color: theme.color.text
322
+ },
323
+ description: {
324
+ fontFamily: theme.font.sans,
325
+ // Reference (buildOverlays, Android): font-size:14px — sm token matches exactly.
326
+ fontSize: theme.fontSize[14],
327
+ lineHeight: theme.fontSize[14] * 1.5,
328
+ color: theme.color.text2
329
+ },
330
+ footer: {
331
+ flexDirection: "row",
332
+ justifyContent: "flex-end",
333
+ alignItems: "center",
334
+ gap: theme.space.s2,
335
+ marginTop: theme.space.s2
336
+ }
337
+ }));
338
+
339
+ export { Dialog, DialogDescription, DialogFooter, DialogTitle, defaultRememberStorage };
@@ -0,0 +1,10 @@
1
+ import { useLabels } from './chunk-APCWFOZW.js';
2
+ import * as React from 'react';
3
+ import { DEFAULT_PAY_LABELS, resolvePayLabels } from '@btndprojects/loam-pay';
4
+
5
+ function usePayLabels(own) {
6
+ const merged = useLabels("pay", DEFAULT_PAY_LABELS, own);
7
+ return React.useMemo(() => resolvePayLabels(merged), [merged]);
8
+ }
9
+
10
+ export { usePayLabels };
@@ -1,9 +1,9 @@
1
+ import { useLabels } from './chunk-APCWFOZW.js';
1
2
  import * as React from 'react';
2
3
  import { View, Animated, Easing, Pressable, I18nManager } from 'react-native';
3
4
  import { createStyleSheet, useLoamTheme, useStyles } from '@btndprojects/loam-theme-native';
4
5
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
5
6
 
6
- // src/spotlight/spotlight.tsx
7
7
  var NO_INSETS = { top: 0, bottom: 0, left: 0, right: 0 };
8
8
  var HostContext = React.createContext(null);
9
9
  function TourOverlay({ children }) {
@@ -179,7 +179,7 @@ function Spotlight({
179
179
  radius,
180
180
  motion = "full"
181
181
  }) {
182
- const theme = useLoamTheme();
182
+ const theme = useLoamTheme("spotlight");
183
183
  const { styles } = useStyles(sheet);
184
184
  const rect = useAnchorRect(target);
185
185
  const fade = React.useRef(new Animated.Value(0)).current;
@@ -221,12 +221,12 @@ function HighlightRing({
221
221
  pulse = false,
222
222
  motion = "full"
223
223
  }) {
224
- const theme = useLoamTheme();
224
+ const theme = useLoamTheme("spotlight");
225
225
  const { styles } = useStyles(sheet);
226
226
  const rect = useAnchorRect(target);
227
227
  const breathe = React.useRef(new Animated.Value(1)).current;
228
228
  React.useEffect(() => {
229
- if (!pulse || motion === "none") return;
229
+ if (!pulse || motion === "none" || theme.reduceMotion) return;
230
230
  const loop = Animated.loop(
231
231
  Animated.sequence([
232
232
  Animated.timing(breathe, {
@@ -245,7 +245,7 @@ function HighlightRing({
245
245
  );
246
246
  loop.start();
247
247
  return () => loop.stop();
248
- }, [pulse, motion, breathe, theme.loop.pulse]);
248
+ }, [pulse, motion, breathe, theme.loop.pulse, theme.reduceMotion]);
249
249
  if (!rect) return null;
250
250
  return /* @__PURE__ */ jsx(
251
251
  Animated.View,
@@ -265,28 +265,38 @@ function HighlightRing({
265
265
  }
266
266
  );
267
267
  }
268
- function Highlight({ kind = "spotlight", pulse, ...rest }) {
268
+ function Highlight({
269
+ kind = "spotlight",
270
+ pulse,
271
+ ...rest
272
+ }) {
269
273
  if (kind === "none") return null;
270
274
  if (kind === "spotlight") return /* @__PURE__ */ jsx(Spotlight, { ...rest });
271
275
  return /* @__PURE__ */ jsx(HighlightRing, { ...rest, pulse: kind === "pulse" || pulse });
272
276
  }
277
+ var DEFAULT_LABELS = {
278
+ whatsNew: "What\u2019s new here"
279
+ };
273
280
  var DOT = 12;
274
281
  var OVERHANG = 5;
275
282
  function Beacon({
276
283
  target,
277
284
  corner = "trailing-top",
278
- accessibilityLabel = "What\u2019s new here",
285
+ accessibilityLabel: accessibilityLabelProp,
279
286
  pulsing = true,
280
287
  onPress,
281
- motion = "full"
288
+ motion = "full",
289
+ labels: labelsProp
282
290
  }) {
283
- const theme = useLoamTheme();
291
+ const theme = useLoamTheme("spotlight");
292
+ const labels = useLabels("beacon", DEFAULT_LABELS, labelsProp);
293
+ const accessibilityLabel = accessibilityLabelProp ?? labels.whatsNew;
284
294
  const { styles } = useStyles(sheet);
285
295
  const rect = useAnchorRect(target ?? null);
286
296
  const ring = React.useRef(new Animated.Value(0)).current;
287
297
  const anchored = target != null;
288
298
  React.useEffect(() => {
289
- if (!pulsing || motion === "none") return;
299
+ if (!pulsing || motion === "none" || theme.reduceMotion) return;
290
300
  const loop = Animated.loop(
291
301
  Animated.timing(ring, {
292
302
  toValue: 1,
@@ -298,7 +308,7 @@ function Beacon({
298
308
  ring.setValue(0);
299
309
  loop.start();
300
310
  return () => loop.stop();
301
- }, [pulsing, motion, ring, theme.loop.beacon]);
311
+ }, [pulsing, motion, ring, theme.loop.beacon, theme.reduceMotion]);
302
312
  if (anchored && !rect) return null;
303
313
  let placement;
304
314
  if (rect) {
@@ -328,7 +338,9 @@ function Beacon({
328
338
  styles.beaconRing,
329
339
  {
330
340
  opacity: ring.interpolate({ inputRange: [0, 0.7, 1], outputRange: [0.55, 0, 0] }),
331
- transform: [{ scale: ring.interpolate({ inputRange: [0, 1], outputRange: [1, 2.8] }) }]
341
+ transform: [
342
+ { scale: ring.interpolate({ inputRange: [0, 1], outputRange: [1, 2.8] }) }
343
+ ]
332
344
  }
333
345
  ]
334
346
  }
@@ -0,0 +1 @@
1
+
@@ -1,10 +1,86 @@
1
- import { Icon } from './chunk-TKVFVF5D.js';
2
- import * as React from 'react';
1
+ import { useLabels } from './chunk-APCWFOZW.js';
2
+ import { Icon } from './chunk-UXGIW7OK.js';
3
+ import * as React3 from 'react';
4
+ import { resolveAnalyzerLabels, localizeProfile, profile, gateHintDisplay } from '@btndprojects/loam-analyzer';
3
5
  import { View, Text, Pressable } from 'react-native';
4
6
  import { createStyleSheet, useStyles, useLoamTheme } from '@btndprojects/loam-theme-native';
5
- import { profile, gateHintDisplay } from '@btndprojects/loam-analyzer';
6
7
  import { jsxs, jsx } from 'react/jsx-runtime';
7
8
 
9
+ var DEFAULT_ANALYZER_UI_LABELS = {
10
+ uploadPhoto: "Upload a photo",
11
+ expertControls: "Expert controls",
12
+ placeholderFeed: "live feed \xB7 placeholder",
13
+ webcamFront: "webcam \xB7 front",
14
+ rearCamera: "rear camera",
15
+ feedLive: (facing, ratio, zoom) => `${facing} \xB7 ${ratio} \xB7 ${zoom}x \xB7 placeholder feed`,
16
+ feedCaptured: (ratio) => `frozen frame \xB7 ${ratio} \xB7 placeholder`,
17
+ feedAnalysing: "frozen frame \xB7 analysing",
18
+ feedFrozen: "frozen frame",
19
+ feedDone: "captured frame",
20
+ analysing: "Analysing",
21
+ resultReady: "Result ready",
22
+ analysisFailed: "Analysis failed",
23
+ plate: {
24
+ plant: "plant subject",
25
+ document: "document page",
26
+ barcode: "barcode",
27
+ car: "vehicle",
28
+ id: "identity document",
29
+ generic: "scene"
30
+ }
31
+ };
32
+ function useAnalyzerLabels(own) {
33
+ const base = useLabels("analyzer", DEFAULT_ANALYZER_UI_LABELS, own);
34
+ return React3.useMemo(
35
+ () => ({ ...base, plate: { ...DEFAULT_ANALYZER_UI_LABELS.plate, ...base.plate } }),
36
+ [base]
37
+ );
38
+ }
39
+ var NO_COPY = {};
40
+ function useAnalyzerCopy(own) {
41
+ const provided = useLabels("analyzerCopy", NO_COPY);
42
+ const scoped = React3.useContext(AnalyzerCopyScope);
43
+ return React3.useMemo(() => resolveAnalyzerLabels(provided, scoped, own), [provided, scoped, own]);
44
+ }
45
+ var AnalyzerCopyScope = React3.createContext(void 0);
46
+ var DEFAULT_VIEWFINDER_LABELS = {
47
+ closeCamera: "Close camera",
48
+ autoCapturing: "Auto-capturing",
49
+ capture: "Capture",
50
+ torch: "Torch",
51
+ grid: "Grid",
52
+ flipCamera: "Flip camera",
53
+ zoom: "Zoom",
54
+ zoomStop: (stop) => `${stop}x`,
55
+ capturedPages: "Captured pages",
56
+ captureSequence: "Capture sequence",
57
+ stepCaptured: (name) => `${name} \u2014 captured, tap to redo`,
58
+ expertControls: "Expert controls",
59
+ expert: "Expert",
60
+ closeExpert: "Close expert controls",
61
+ level: "Level",
62
+ torchLevels: { off: "off", low: "low", high: "high" },
63
+ formats: { pipeline: "Pipeline-native", full: "Full sensor" },
64
+ uploadPhoto: "Upload a photo",
65
+ cameraDevice: "Camera device"
66
+ };
67
+ function useViewfinderLabels(own) {
68
+ const merged = useLabels("viewfinder", DEFAULT_VIEWFINDER_LABELS, own);
69
+ const provided = useLabels("viewfinder", NONE);
70
+ return React3.useMemo(
71
+ () => ({
72
+ ...merged,
73
+ torchLevels: {
74
+ ...DEFAULT_VIEWFINDER_LABELS.torchLevels,
75
+ ...provided.torchLevels,
76
+ ...own?.torchLevels
77
+ },
78
+ formats: { ...DEFAULT_VIEWFINDER_LABELS.formats, ...provided.formats, ...own?.formats }
79
+ }),
80
+ [merged, provided, own]
81
+ );
82
+ }
83
+ var NONE = {};
8
84
  function camGlass(theme) {
9
85
  return {
10
86
  backgroundColor: theme.black.a12,
@@ -18,7 +94,9 @@ function camInk(theme) {
18
94
  function camMeta(theme) {
19
95
  return {
20
96
  fontFamily: theme.font.mono,
21
- color: theme.white.a10,
97
+ // `a13`, not `a10`: at 38% the metadata measured 2:1 on the scrim over a
98
+ // bright feed. 70% still reads as secondary beside the full-white ink.
99
+ color: theme.white.a13,
22
100
  letterSpacing: theme.tracking.wider
23
101
  };
24
102
  }
@@ -32,10 +110,10 @@ function decorativeProps() {
32
110
  function untabbableProps() {
33
111
  return { tabIndex: -1 };
34
112
  }
35
- var AnnounceContext = React.createContext(null);
113
+ var AnnounceContext = React3.createContext(null);
36
114
  function SurfaceLiveRegion({ children }) {
37
- const [message, setMessage] = React.useState("");
38
- const announce = React.useCallback((m) => setMessage(m), []);
115
+ const [message, setMessage] = React3.useState("");
116
+ const announce = React3.useCallback((m) => setMessage(m), []);
39
117
  const { styles } = useStyles(chromeSheet);
40
118
  return /* @__PURE__ */ jsxs(AnnounceContext.Provider, { value: announce, children: [
41
119
  children,
@@ -52,7 +130,7 @@ function SurfaceLiveRegion({ children }) {
52
130
  ] });
53
131
  }
54
132
  function useSurfaceAnnounce() {
55
- return React.useContext(AnnounceContext);
133
+ return React3.useContext(AnnounceContext);
56
134
  }
57
135
  function GlassIconButton({
58
136
  icon,
@@ -62,7 +140,7 @@ function GlassIconButton({
62
140
  radius = "full",
63
141
  onPress
64
142
  }) {
65
- const theme = useLoamTheme();
143
+ const theme = useLoamTheme("viewfinder");
66
144
  const { styles } = useStyles(chromeSheet, { size, radius, on: on === true });
67
145
  const glyph = on ? theme.media.onInk : camInk(theme);
68
146
  return /* @__PURE__ */ jsx(
@@ -98,7 +176,7 @@ function GuidanceChip({
98
176
  tone = "neutral",
99
177
  icon
100
178
  }) {
101
- const theme = useLoamTheme();
179
+ const theme = useLoamTheme("viewfinder");
102
180
  const { styles } = useStyles(chromeSheet, { tone });
103
181
  const { ink } = chipColours(theme, tone);
104
182
  return (
@@ -115,17 +193,22 @@ function GateHint({
115
193
  gate = { pass: true, failing: [] },
116
194
  countdown = null,
117
195
  live = true,
118
- throttleMs = GATE_ANNOUNCE_MS
196
+ throttleMs = GATE_ANNOUNCE_MS,
197
+ copy
119
198
  }) {
120
- const resolved = profile(profileProp);
121
- const display = gateHintDisplay(resolved, gate, countdown);
199
+ const words = useAnalyzerCopy(copy);
200
+ const resolved = React3.useMemo(
201
+ () => localizeProfile(profile(profileProp), words),
202
+ [profileProp, words]
203
+ );
204
+ const display = gateHintDisplay(resolved, gate, countdown, words);
122
205
  const surface = useSurfaceAnnounce();
123
- const [own, setOwn] = React.useState("");
206
+ const [own, setOwn] = React3.useState("");
124
207
  const { styles } = useStyles(chromeSheet);
125
- const sink = React.useRef(setOwn);
208
+ const sink = React3.useRef(setOwn);
126
209
  sink.current = surface ?? setOwn;
127
- const last = React.useRef({ text: "", at: 0 });
128
- React.useEffect(() => {
210
+ const last = React3.useRef({ text: "", at: 0 });
211
+ React3.useEffect(() => {
129
212
  if (!live) return;
130
213
  const text = display.text;
131
214
  if (text === last.current.text) return;
@@ -159,15 +242,17 @@ function ViewfinderTopBar({
159
242
  title,
160
243
  subtitle,
161
244
  align = "start",
162
- closeLabel = "Close camera",
245
+ closeLabel,
246
+ labels,
163
247
  onClose,
164
248
  children
165
249
  }) {
166
- const theme = useLoamTheme();
250
+ const t = useViewfinderLabels(labels);
251
+ const theme = useLoamTheme("viewfinder");
167
252
  const { styles } = useStyles(chromeSheet, { align });
168
253
  const ink = camInk(theme);
169
254
  return /* @__PURE__ */ jsxs(View, { style: styles.topBar, children: [
170
- onClose ? /* @__PURE__ */ jsx(GlassIconButton, { icon: "x", label: closeLabel, onPress: onClose }) : null,
255
+ onClose ? /* @__PURE__ */ jsx(GlassIconButton, { icon: "x", label: closeLabel ?? t.closeCamera, onPress: onClose }) : null,
171
256
  /* @__PURE__ */ jsxs(View, { style: styles.titlePlate, children: [
172
257
  /* @__PURE__ */ jsx(Text, { numberOfLines: 1, style: [styles.title, { color: ink }], children: title }),
173
258
  subtitle ? /* @__PURE__ */ jsx(Text, { numberOfLines: 1, style: [styles.subtitle, { color: ink }], children: subtitle }) : null
@@ -281,4 +366,4 @@ var chromeSheet = createStyleSheet((theme) => ({
281
366
  }
282
367
  }));
283
368
 
284
- export { GATE_ANNOUNCE_MS, GateHint, GlassIconButton, GuidanceChip, SurfaceLiveRegion, ViewfinderTopBar, camGlass, camInk, camMeta, decorativeProps, pressedProps, untabbableProps, useSurfaceAnnounce };
369
+ export { AnalyzerCopyScope, GATE_ANNOUNCE_MS, GateHint, GlassIconButton, GuidanceChip, SurfaceLiveRegion, ViewfinderTopBar, camGlass, camInk, camMeta, decorativeProps, pressedProps, untabbableProps, useAnalyzerCopy, useAnalyzerLabels, useSurfaceAnnounce, useViewfinderLabels };