@btndprojects/loam-ui-native 0.1.1 → 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 (262) hide show
  1. package/dist/accordion/index.js +5 -3
  2. package/dist/adaptive/index.js +6 -2
  3. package/dist/alert/index.js +5 -2
  4. package/dist/analyzer/index.js +9 -6
  5. package/dist/announcement/index.js +8 -5
  6. package/dist/audio-player/index.js +5 -3
  7. package/dist/avatar/index.js +5 -2
  8. package/dist/avatar-group/index.js +7 -3
  9. package/dist/badge/index.js +7 -4
  10. package/dist/banner/index.js +5 -2
  11. package/dist/board/index.js +11 -6
  12. package/dist/button/index.js +6 -3
  13. package/dist/camera-permission/index.js +15 -12
  14. package/dist/capture-result/index.js +19 -16
  15. package/dist/card/index.js +6 -3
  16. package/dist/card-form/index.js +12 -8
  17. package/dist/carousel/index.js +4 -2
  18. package/dist/chart/index.js +8 -5
  19. package/dist/charts/index.js +8 -6
  20. package/dist/chat/index.js +16 -0
  21. package/dist/checkbox/index.js +6 -4
  22. package/dist/checklist/index.js +11 -8
  23. package/dist/checkout/index.js +16 -11
  24. package/dist/chip/index.js +7 -4
  25. package/dist/{chunk-XNUVB5OL.js → chunk-2OLKPG4E.js} +92 -28
  26. package/dist/{chunk-RUZHTGKB.js → chunk-2PKYGLQ6.js} +71 -40
  27. package/dist/{chunk-UC2WGUP3.js → chunk-2SWKL3AJ.js} +91 -252
  28. package/dist/{chunk-AI4DWZCD.js → chunk-2SY63FCH.js} +63 -16
  29. package/dist/{chunk-F5XNPWS7.js → chunk-2TXERVVA.js} +92 -35
  30. package/dist/chunk-36EC2T6P.js +581 -0
  31. package/dist/chunk-3DUWIYV5.js +437 -0
  32. package/dist/{chunk-JNY4ZHAR.js → chunk-3QMEOFW5.js} +275 -71
  33. package/dist/chunk-3WEZCGHX.js +265 -0
  34. package/dist/chunk-46MMSDGL.js +194 -0
  35. package/dist/{chunk-7O2FMUPT.js → chunk-4IZXHVFJ.js} +297 -92
  36. package/dist/{chunk-LAECSR4H.js → chunk-5LAAAXFP.js} +14 -8
  37. package/dist/{chunk-2A5NIQAK.js → chunk-5RENVKBQ.js} +134 -46
  38. package/dist/{chunk-2ZZ7TDJ4.js → chunk-5UTRIXQ6.js} +37 -31
  39. package/dist/{chunk-LOE5YNN3.js → chunk-5VFZRGVD.js} +37 -10
  40. package/dist/{chunk-52X2VYTD.js → chunk-67IZZ2MJ.js} +115 -60
  41. package/dist/{chunk-UYG5L34B.js → chunk-6YAQBXB3.js} +10 -4
  42. package/dist/{chunk-BTTFCMKG.js → chunk-74FLKD24.js} +94 -23
  43. package/dist/{chunk-ITTYJZWX.js → chunk-7BUIKDD6.js} +73 -18
  44. package/dist/{chunk-423B7SPN.js → chunk-7OVVSVEZ.js} +273 -109
  45. package/dist/chunk-AEB7KCHQ.js +287 -0
  46. package/dist/chunk-APCWFOZW.js +28 -0
  47. package/dist/chunk-AWKQIE5I.js +139 -0
  48. package/dist/{chunk-VCDBXW5H.js → chunk-B7N4ASYE.js} +86 -42
  49. package/dist/{chunk-IVNRBPGC.js → chunk-C4GTDLRC.js} +104 -20
  50. package/dist/{chunk-4ZAHCY44.js → chunk-C6APNDVA.js} +12 -5
  51. package/dist/{chunk-4SZYY6AN.js → chunk-CMTVNF3D.js} +18 -13
  52. package/dist/{chunk-HZ6CNMAF.js → chunk-CPTOADB2.js} +151 -96
  53. package/dist/chunk-D5N5QWI7.js +1325 -0
  54. package/dist/{chunk-IIQTAY3J.js → chunk-DN7MNQIP.js} +113 -29
  55. package/dist/{chunk-47FWHGUN.js → chunk-DVGBZ3TX.js} +84 -23
  56. package/dist/chunk-DW3L54DQ.js +305 -0
  57. package/dist/{chunk-3ARE4TES.js → chunk-E2E3I5W2.js} +69 -18
  58. package/dist/{chunk-DHWADYZX.js → chunk-EDCBJV7J.js} +41 -28
  59. package/dist/{chunk-WSW6ZFAQ.js → chunk-ENP3BMZU.js} +4 -4
  60. package/dist/{chunk-OOPPQH27.js → chunk-EVOIGUBI.js} +43 -19
  61. package/dist/{chunk-VEAYTRPX.js → chunk-EY4DD67D.js} +165 -97
  62. package/dist/{chunk-223Q2T2Q.js → chunk-F3H33DQX.js} +132 -61
  63. package/dist/{chunk-CYRBHQQZ.js → chunk-F5B3UINI.js} +68 -35
  64. package/dist/{chunk-6X6PQ443.js → chunk-FAJI7BSC.js} +20 -9
  65. package/dist/{chunk-MOUJOP55.js → chunk-FUMHAAF3.js} +96 -29
  66. package/dist/{chunk-6HT2LP62.js → chunk-FV6HMP7W.js} +192 -73
  67. package/dist/{chunk-S7F6XLTK.js → chunk-FYWNRX4F.js} +76 -47
  68. package/dist/{chunk-YG3ZJHGU.js → chunk-FZGAAOKS.js} +30 -8
  69. package/dist/{chunk-YDGVJETP.js → chunk-G3AFC24V.js} +1 -1
  70. package/dist/{chunk-EJBDRVIH.js → chunk-G6UESEVN.js} +15 -8
  71. package/dist/chunk-GDKVKNR2.js +339 -0
  72. package/dist/chunk-GEIGMWNF.js +10 -0
  73. package/dist/{chunk-JUAMLEHX.js → chunk-H7DWSL4O.js} +24 -12
  74. package/dist/chunk-HJFFOOJ4.js +1 -0
  75. package/dist/{chunk-RW6ZL2FQ.js → chunk-HJLPZA4X.js} +106 -21
  76. package/dist/chunk-HYEOQWT7.js +647 -0
  77. package/dist/chunk-I2KLQ2HA.js +19 -0
  78. package/dist/{chunk-CJ5EOYZE.js → chunk-I4FHVKEC.js} +11 -5
  79. package/dist/{chunk-JNH2TYIN.js → chunk-IDM7JJMO.js} +19 -5
  80. package/dist/{chunk-O4AEHWII.js → chunk-IPUNJMAQ.js} +141 -49
  81. package/dist/{chunk-J7Q7VCVC.js → chunk-IT6FUXXG.js} +13 -6
  82. package/dist/{chunk-QJJ6MADV.js → chunk-IVKMZ7BB.js} +80 -28
  83. package/dist/{chunk-Z7H7VSFZ.js → chunk-IXKWIFWZ.js} +17 -6
  84. package/dist/chunk-J64KGCGX.js +55 -0
  85. package/dist/chunk-JBMLWFSJ.js +270 -0
  86. package/dist/{chunk-4BXMXBJO.js → chunk-JJLPBRVZ.js} +22 -11
  87. package/dist/chunk-JLC6PM5S.js +406 -0
  88. package/dist/chunk-JUYWSSKW.js +335 -0
  89. package/dist/{chunk-7CFF4HXS.js → chunk-JV5YOTOB.js} +49 -11
  90. package/dist/{chunk-LZLHELAG.js → chunk-KFJGFLMW.js} +29 -8
  91. package/dist/{chunk-O7AE6DAF.js → chunk-KQZ3GLHR.js} +18 -8
  92. package/dist/{chunk-N32RGOA5.js → chunk-LKFC4CS7.js} +80 -24
  93. package/dist/{chunk-YC6WORFL.js → chunk-LMPHCVJJ.js} +82 -50
  94. package/dist/{chunk-3WPW4KUN.js → chunk-LQP4KEXZ.js} +45 -13
  95. package/dist/{chunk-TKQYWZ5V.js → chunk-LUMVGO2K.js} +47 -31
  96. package/dist/{chunk-AWJOCGFZ.js → chunk-M656FYNH.js} +25 -13
  97. package/dist/{chunk-35OFI3JG.js → chunk-MKSNFG7H.js} +73 -20
  98. package/dist/{chunk-4GBOGOTV.js → chunk-NBEF4EPJ.js} +16 -6
  99. package/dist/chunk-NNCOFLNE.js +24 -0
  100. package/dist/{chunk-4YQOR7JM.js → chunk-NTQ2F3AU.js} +73 -20
  101. package/dist/{chunk-QCDXZBC5.js → chunk-O5V4TG3V.js} +126 -44
  102. package/dist/{chunk-U7TFM2JA.js → chunk-OJQUBQWA.js} +3 -3
  103. package/dist/{chunk-VQHPQEUH.js → chunk-OWAMM2DK.js} +13 -6
  104. package/dist/chunk-PID3NJB7.js +405 -0
  105. package/dist/{chunk-HET4LLMX.js → chunk-PMMTGBBS.js} +27 -17
  106. package/dist/{chunk-RIBDXGUG.js → chunk-PNF3NKB5.js} +49 -16
  107. package/dist/{chunk-JXJB2X6M.js → chunk-Q6NKEPRE.js} +81 -32
  108. package/dist/chunk-QDZGFXQD.js +176 -0
  109. package/dist/{chunk-SYNOJOQO.js → chunk-QEYFDRHR.js} +60 -26
  110. package/dist/{chunk-VBOXAEPI.js → chunk-QHAITQIF.js} +97 -22
  111. package/dist/{chunk-VXDZFJGP.js → chunk-QHTVYA65.js} +230 -76
  112. package/dist/{chunk-TUTI5HOZ.js → chunk-QIKT7LIB.js} +14 -8
  113. package/dist/{chunk-3ENTMPQY.js → chunk-QP3KMOVF.js} +82 -42
  114. package/dist/{chunk-GNNJ4GCC.js → chunk-QPWDDJJ4.js} +62 -148
  115. package/dist/{chunk-QWCMU5B2.js → chunk-QRUMA22E.js} +205 -80
  116. package/dist/{chunk-ZVFE5QGU.js → chunk-QYPE5JX3.js} +50 -10
  117. package/dist/{chunk-PUPM2YGF.js → chunk-ROCUG24E.js} +76 -36
  118. package/dist/{chunk-NQYBUO3K.js → chunk-RU3ZPNL6.js} +333 -142
  119. package/dist/{chunk-TOXAGRDQ.js → chunk-RXSCIO6W.js} +14 -5
  120. package/dist/{chunk-FMYDDECK.js → chunk-SATMR6SG.js} +631 -203
  121. package/dist/{chunk-4YIP3CWS.js → chunk-SHHY5OMK.js} +7 -5
  122. package/dist/chunk-SKWO3SZF.js +2284 -0
  123. package/dist/{chunk-YF4NSSMT.js → chunk-SWS5JQIF.js} +41 -13
  124. package/dist/{chunk-CUMUNPXY.js → chunk-T5LTPKX6.js} +15 -7
  125. package/dist/{chunk-H6NIOQHK.js → chunk-TDMG26JI.js} +26 -6
  126. package/dist/{chunk-UWFLYMAR.js → chunk-TLCIR6RG.js} +267 -126
  127. package/dist/{chunk-SBMNWWBV.js → chunk-TN2ZNJUI.js} +47 -9
  128. package/dist/{chunk-5YNTNN5A.js → chunk-TQVAIKFD.js} +106 -41
  129. package/dist/chunk-TRGFFU6A.js +1456 -0
  130. package/dist/{chunk-2GK6PHGE.js → chunk-TY4MTKQJ.js} +100 -22
  131. package/dist/{chunk-AZRX6SAC.js → chunk-U23FYWME.js} +15 -7
  132. package/dist/{chunk-PZXZJBMP.js → chunk-U5NLHYV6.js} +26 -12
  133. package/dist/chunk-UQEN55EY.js +1 -0
  134. package/dist/chunk-UQGBTPXH.js +218 -0
  135. package/dist/chunk-UXGIW7OK.js +116 -0
  136. package/dist/{chunk-PJXUJYS6.js → chunk-UYGDJWMN.js} +55 -30
  137. package/dist/{chunk-QDYDBCFP.js → chunk-V2OEB75Z.js} +50 -51
  138. package/dist/{chunk-LSS54GLJ.js → chunk-VAOAKWUK.js} +34 -13
  139. package/dist/{chunk-DM5QUKKO.js → chunk-VDPK5CY4.js} +18 -6
  140. package/dist/chunk-W23G6JLF.js +37 -0
  141. package/dist/{chunk-CDRZHT42.js → chunk-W63AJTM7.js} +276 -12
  142. package/dist/{chunk-XXXEFXY5.js → chunk-W74TXYFB.js} +13 -5
  143. package/dist/{chunk-LRJNDEIA.js → chunk-WRDSPUE7.js} +144 -29
  144. package/dist/{chunk-C2NTXVWM.js → chunk-XBZGDDMR.js} +11 -4
  145. package/dist/{chunk-BV3B2HYZ.js → chunk-XIDTBCBA.js} +189 -131
  146. package/dist/{chunk-YTFKPRUK.js → chunk-XN4KG3P4.js} +348 -153
  147. package/dist/chunk-XQXMLMH3.js +211 -0
  148. package/dist/{chunk-HPPW424V.js → chunk-XTORZWRF.js} +19 -8
  149. package/dist/{chunk-P23EQNRQ.js → chunk-YAAHPATV.js} +181 -30
  150. package/dist/{chunk-KMI5ML5I.js → chunk-YXOAPXMU.js} +57 -18
  151. package/dist/{chunk-RJQOOHT2.js → chunk-ZECZOOSB.js} +59 -28
  152. package/dist/{chunk-QKXCPTFS.js → chunk-ZLTO5VQI.js} +121 -31
  153. package/dist/{chunk-BEDBFJND.js → chunk-ZVATDZOM.js} +16 -18
  154. package/dist/coachmark/index.js +6 -3
  155. package/dist/code-block/index.js +5 -3
  156. package/dist/color-field/index.js +6 -4
  157. package/dist/commerce/index.js +19 -16
  158. package/dist/connectivity/index.js +5 -2
  159. package/dist/context-menu/index.js +5 -3
  160. package/dist/copy-button/index.js +4 -2
  161. package/dist/data-grid/index.js +21 -16
  162. package/dist/date-range-picker/index.js +11 -8
  163. package/dist/description-list/index.js +3 -1
  164. package/dist/dialog/index.js +4 -2
  165. package/dist/empty-state/index.js +4 -2
  166. package/dist/error-summary/index.js +4 -2
  167. package/dist/fab/index.js +5 -2
  168. package/dist/file-manager/index.js +28 -0
  169. package/dist/file-upload/index.js +10 -7
  170. package/dist/filter-bar/index.js +9 -6
  171. package/dist/flow-run/index.js +15 -12
  172. package/dist/form/index.js +5 -3
  173. package/dist/gallery/index.js +5 -2
  174. package/dist/hold-to-confirm/index.js +4 -2
  175. package/dist/index.d.ts +9557 -2985
  176. package/dist/index.js +355 -122
  177. package/dist/infinite-list/index.js +4 -2
  178. package/dist/inline-edit/index.js +6 -4
  179. package/dist/input/index.js +5 -3
  180. package/dist/interactions/index.js +2 -1
  181. package/dist/invoice/index.js +13 -9
  182. package/dist/kbd/index.js +5 -1
  183. package/dist/keyboard/index.js +4 -2
  184. package/dist/list-row/index.js +6 -4
  185. package/dist/log-viewer/index.js +4 -2
  186. package/dist/map-view/index.js +5 -3
  187. package/dist/markdown/index.js +9 -6
  188. package/dist/metric/index.js +7 -4
  189. package/dist/money/index.js +9 -3
  190. package/dist/nav-drawer/index.js +4 -2
  191. package/dist/nav-header/index.js +9 -0
  192. package/dist/navigation/index.js +5 -2
  193. package/dist/notification-center/index.js +12 -10
  194. package/dist/number-roll/index.js +5 -2
  195. package/dist/one-handed/index.js +5 -3
  196. package/dist/os-surfaces/index.js +6 -3
  197. package/dist/otp/index.js +7 -4
  198. package/dist/page-header/index.js +1 -0
  199. package/dist/pagination/index.js +6 -0
  200. package/dist/payment-method/index.js +14 -10
  201. package/dist/payment-status/index.js +17 -14
  202. package/dist/permission/index.js +5 -2
  203. package/dist/picker/index.js +11 -6
  204. package/dist/progress/index.js +6 -3
  205. package/dist/pull-to-refresh/index.js +4 -2
  206. package/dist/radio-group/index.js +6 -4
  207. package/dist/rating/index.js +5 -2
  208. package/dist/receivables/index.js +21 -16
  209. package/dist/refund/index.js +18 -14
  210. package/dist/save-status/index.js +5 -3
  211. package/dist/scroll-area/index.js +3 -1
  212. package/dist/search-field/index.js +8 -0
  213. package/dist/segmented-control/index.js +4 -3
  214. package/dist/sheet/index.js +5 -3
  215. package/dist/skeleton/index.js +3 -1
  216. package/dist/slider/index.js +4 -2
  217. package/dist/sortable/index.js +7 -0
  218. package/dist/spinner/index.js +3 -1
  219. package/dist/split-button/index.js +9 -6
  220. package/dist/spotlight/index.js +3 -1
  221. package/dist/stage-timeline/index.js +5 -3
  222. package/dist/status-dot/index.js +4 -2
  223. package/dist/stepper/index.js +7 -4
  224. package/dist/streaming-text/index.js +3 -2
  225. package/dist/survey/index.js +18 -15
  226. package/dist/switch/index.js +5 -3
  227. package/dist/system-state/index.js +7 -4
  228. package/dist/tab-bar/index.js +5 -2
  229. package/dist/tabs/index.js +4 -2
  230. package/dist/tags-input/index.js +10 -0
  231. package/dist/textarea/index.js +6 -4
  232. package/dist/thinking/index.js +3 -1
  233. package/dist/time-field/index.js +12 -0
  234. package/dist/time-range-control/index.js +22 -0
  235. package/dist/timeline/index.js +4 -2
  236. package/dist/toast/index.js +4 -2
  237. package/dist/toolbar/index.js +4 -2
  238. package/dist/tour/index.js +12 -9
  239. package/dist/truncation-notice/index.js +5 -2
  240. package/dist/update-notice/index.js +12 -9
  241. package/dist/video-player/index.js +5 -2
  242. package/dist/viewfinder/index.js +6 -4
  243. package/dist/widget/index.js +7 -4
  244. package/dist/wizard/index.js +7 -4
  245. package/package.json +13 -12
  246. package/dist/chunk-6N33LFQA.js +0 -35
  247. package/dist/chunk-GDKZTW34.js +0 -395
  248. package/dist/chunk-GL7B2DOW.js +0 -134
  249. package/dist/chunk-NKB7BZYK.js +0 -167
  250. package/dist/chunk-OETCUXQP.js +0 -134
  251. package/dist/chunk-OPXFZ4Y5.js +0 -204
  252. package/dist/chunk-Q72LJOVE.js +0 -169
  253. package/dist/chunk-RNGLIHFA.js +0 -191
  254. package/dist/chunk-RQ3HASCC.js +0 -6
  255. package/dist/chunk-RSOJT5YW.js +0 -124
  256. package/dist/chunk-TKVFVF5D.js +0 -95
  257. package/dist/chunk-XOSCY2CW.js +0 -242
  258. package/dist/header/index.js +0 -5
  259. package/dist/search-bar/index.js +0 -5
  260. /package/dist/{chunk-3ECPOSKO.js → chunk-3UG6JUCV.js} +0 -0
  261. /package/dist/{chunk-JRLTGLN4.js → chunk-5WWRTEPS.js} +0 -0
  262. /package/dist/{chunk-RTIKSY6A.js → chunk-5Z5ZYMOJ.js} +0 -0
@@ -1,10 +1,50 @@
1
- import { useResolvedMotion } from './chunk-6N33LFQA.js';
2
- import { Icon } from './chunk-TKVFVF5D.js';
1
+ import { useLabels } from './chunk-APCWFOZW.js';
2
+ import { Icon } from './chunk-UXGIW7OK.js';
3
+ import { useResolvedMotion, springConfig, motionTiming } from './chunk-J64KGCGX.js';
3
4
  import * as React from 'react';
4
5
  import { View, Pressable, Text, Animated, Easing } from 'react-native';
5
6
  import { createStyleSheet, useStyles, useLoamTheme } from '@btndprojects/loam-theme-native';
6
7
  import { jsxs, jsx } from 'react/jsx-runtime';
7
8
 
9
+ var DEFAULT_LABELS = {
10
+ seek: "Seek",
11
+ seekValue: (current, total) => `${current} of ${total}`,
12
+ previous: "Previous track",
13
+ next: "Next track",
14
+ play: "Play",
15
+ pause: "Pause",
16
+ close: "Close player",
17
+ artworkPlaceholder: "1:1",
18
+ expand: (title, meta) => `${title}${meta ? `, ${meta}` : ""}. Expand player`,
19
+ collapse: "Collapse player",
20
+ artwork: "Artwork 1:1",
21
+ position: "Playback position",
22
+ skipBack: "Skip back",
23
+ skipForward: "Skip forward"
24
+ };
25
+ function PlayPauseGlyph({ playing, size, color }) {
26
+ const theme = useLoamTheme("audio-player");
27
+ const level = useResolvedMotion(void 0, "audio-player");
28
+ const v = React.useRef(new Animated.Value(playing ? 1 : 0)).current;
29
+ React.useEffect(() => {
30
+ const toValue = playing ? 1 : 0;
31
+ if (level === "none") v.setValue(toValue);
32
+ else if (level === "reduced") Animated.timing(v, { ...motionTiming(level), toValue, useNativeDriver: true }).start();
33
+ else Animated.spring(v, { ...springConfig(theme, "fs"), toValue, useNativeDriver: true }).start();
34
+ }, [playing, level, v, theme]);
35
+ const layer = (shown) => ({
36
+ position: "absolute",
37
+ opacity: shown,
38
+ transform: level === "full" ? [{ scale: shown.interpolate({ inputRange: [0, 1], outputRange: [0.5, 1] }) }] : []
39
+ });
40
+ const pauseShown = v.interpolate({ inputRange: [0, 1], outputRange: [0, 1], extrapolate: "clamp" });
41
+ const playShown = v.interpolate({ inputRange: [0, 1], outputRange: [1, 0], extrapolate: "clamp" });
42
+ return /* @__PURE__ */ jsxs(View, { style: { width: size, height: size, alignItems: "center", justifyContent: "center" }, children: [
43
+ /* @__PURE__ */ jsx(Animated.View, { style: layer(playShown), children: /* @__PURE__ */ jsx(Icon, { name: "play", size, color }) }),
44
+ /* @__PURE__ */ jsx(Animated.View, { style: layer(pauseShown), children: /* @__PURE__ */ jsx(Icon, { name: "pause", size, color }) })
45
+ ] });
46
+ }
47
+ var SEEK_STEP = 5;
8
48
  function formatTime(seconds) {
9
49
  const s = Number.isFinite(seconds) && seconds > 0 ? Math.floor(seconds) : 0;
10
50
  return `${Math.floor(s / 60)}:${String(s % 60).padStart(2, "0")}`;
@@ -15,16 +55,18 @@ function AudioMiniBar({
15
55
  playing = false,
16
56
  progress,
17
57
  onPress,
18
- onTogglePlay
58
+ onTogglePlay,
59
+ labels: labelsProp
19
60
  }) {
61
+ const labels = useLabels("audioPlayer", DEFAULT_LABELS, labelsProp);
20
62
  const { styles } = useStyles(sheet);
21
- const theme = useLoamTheme();
63
+ const theme = useLoamTheme("audio-player");
22
64
  return /* @__PURE__ */ jsxs(View, { style: styles.mini, children: [
23
65
  /* @__PURE__ */ jsxs(
24
66
  Pressable,
25
67
  {
26
68
  accessibilityRole: "button",
27
- accessibilityLabel: `${title}${meta ? `, ${meta}` : ""}. Expand player`,
69
+ accessibilityLabel: labels.expand(title, meta),
28
70
  onPress,
29
71
  style: styles.miniBody,
30
72
  children: [
@@ -40,11 +82,11 @@ function AudioMiniBar({
40
82
  Pressable,
41
83
  {
42
84
  accessibilityRole: "button",
43
- accessibilityLabel: playing ? "Pause" : "Play",
85
+ accessibilityLabel: playing ? labels.pause : labels.play,
44
86
  onPress: onTogglePlay,
45
87
  hitSlop: Math.max(0, (theme.tapMin - theme.ctl.iconBtn) / 2),
46
88
  style: styles.miniTransport,
47
- children: /* @__PURE__ */ jsx(Icon, { name: playing ? "pause" : "play", size: 16, color: theme.color.accentInk })
89
+ children: /* @__PURE__ */ jsx(PlayPauseGlyph, { playing, size: 16, color: theme.color.accentInk })
48
90
  }
49
91
  ),
50
92
  progress != null ? /* @__PURE__ */ jsx(
@@ -62,40 +104,75 @@ function AudioSheet({
62
104
  position = 0,
63
105
  duration = 0,
64
106
  onTogglePlay,
107
+ onSeek,
65
108
  onSkipBack,
66
109
  onSkipForward,
67
- onCollapse
110
+ onCollapse,
111
+ labels: labelsProp
68
112
  }) {
113
+ const labels = useLabels("audioPlayer", DEFAULT_LABELS, labelsProp);
69
114
  const { styles } = useStyles(sheet);
70
- const theme = useLoamTheme();
115
+ const theme = useLoamTheme("audio-player");
71
116
  const pct = duration > 0 ? Math.min(1, Math.max(0, position / duration)) : 0;
117
+ const [trackWidth, setTrackWidth] = React.useState(0);
118
+ const held = React.useRef(new Animated.Value(0)).current;
119
+ const hold = (to) => {
120
+ if (theme.reduceMotion) return held.setValue(0);
121
+ Animated.spring(held, { ...springConfig(theme, "fs"), toValue: to, useNativeDriver: true }).start();
122
+ };
123
+ const seekFromX = (x) => {
124
+ if (!onSeek || trackWidth <= 0 || duration <= 0) return;
125
+ onSeek(Math.min(duration, Math.max(0, x / trackWidth * duration)));
126
+ };
72
127
  return /* @__PURE__ */ jsxs(View, { style: styles.sheetBody, children: [
73
128
  /* @__PURE__ */ jsx(
74
129
  Pressable,
75
130
  {
76
131
  accessibilityRole: "button",
77
- accessibilityLabel: "Collapse player",
132
+ accessibilityLabel: labels.collapse,
78
133
  onPress: onCollapse,
79
134
  style: styles.grabberHit,
80
135
  children: /* @__PURE__ */ jsx(View, { style: styles.grabber })
81
136
  }
82
137
  ),
83
- /* @__PURE__ */ jsx(View, { style: styles.artwork, children: /* @__PURE__ */ jsx(Text, { style: styles.artworkLabel, children: "Artwork 1:1" }) }),
138
+ /* @__PURE__ */ jsx(View, { style: styles.artwork, children: /* @__PURE__ */ jsx(Text, { style: styles.artworkLabel, children: labels.artwork }) }),
84
139
  /* @__PURE__ */ jsxs(View, { style: styles.sheetText, children: [
85
140
  /* @__PURE__ */ jsx(Text, { style: styles.sheetTitle, children: title }),
86
141
  meta ? /* @__PURE__ */ jsx(Text, { style: styles.sheetMeta, children: meta }) : null
87
142
  ] }),
88
143
  /* @__PURE__ */ jsxs(View, { style: styles.progressWrap, children: [
89
144
  /* @__PURE__ */ jsx(
90
- View,
145
+ Pressable,
91
146
  {
92
- accessibilityRole: "progressbar",
93
- accessibilityLabel: "Playback position",
147
+ accessibilityRole: onSeek ? "adjustable" : "progressbar",
148
+ accessibilityLabel: labels.position,
94
149
  "aria-valuemin": 0,
95
150
  "aria-valuemax": Math.round(duration),
96
151
  "aria-valuenow": Math.round(position),
97
- style: styles.progressTrack,
98
- children: /* @__PURE__ */ jsx(View, { style: [styles.progressFill, { width: `${pct * 100}%` }] })
152
+ "aria-valuetext": labels.seekValue(formatTime(position), formatTime(duration)),
153
+ accessibilityActions: onSeek ? [{ name: "increment" }, { name: "decrement" }] : void 0,
154
+ onAccessibilityAction: (e) => {
155
+ const delta = e.nativeEvent.actionName === "increment" ? SEEK_STEP : -SEEK_STEP;
156
+ onSeek?.(Math.min(duration, Math.max(0, position + delta)));
157
+ },
158
+ onLayout: (e) => setTrackWidth(e.nativeEvent.layout.width),
159
+ onPress: onSeek ? (e) => seekFromX(e.nativeEvent.locationX) : void 0,
160
+ onTouchMove: onSeek ? (e) => seekFromX(e.nativeEvent.locationX) : void 0,
161
+ onPressIn: onSeek ? () => hold(1) : void 0,
162
+ onPressOut: onSeek ? () => hold(0) : void 0,
163
+ hitSlop: onSeek ? theme.space.s4 : void 0,
164
+ disabled: !onSeek,
165
+ style: styles.progressHit,
166
+ children: /* @__PURE__ */ jsx(
167
+ Animated.View,
168
+ {
169
+ style: [
170
+ styles.progressTrack,
171
+ { pointerEvents: "none", transform: [{ scaleY: held.interpolate({ inputRange: [0, 1], outputRange: [1, 2] }) }] }
172
+ ],
173
+ children: /* @__PURE__ */ jsx(View, { style: [styles.progressFill, { width: `${pct * 100}%` }] })
174
+ }
175
+ )
99
176
  }
100
177
  ),
101
178
  /* @__PURE__ */ jsxs(View, { style: styles.timeRow, children: [
@@ -111,7 +188,7 @@ function AudioSheet({
111
188
  Pressable,
112
189
  {
113
190
  accessibilityRole: "button",
114
- accessibilityLabel: "Skip back",
191
+ accessibilityLabel: labels.skipBack,
115
192
  onPress: onSkipBack,
116
193
  style: styles.transportSecondary,
117
194
  children: /* @__PURE__ */ jsx(Icon, { name: "skip-back", size: 22, color: theme.color.text2 })
@@ -121,17 +198,17 @@ function AudioSheet({
121
198
  Pressable,
122
199
  {
123
200
  accessibilityRole: "button",
124
- accessibilityLabel: playing ? "Pause" : "Play",
201
+ accessibilityLabel: playing ? labels.pause : labels.play,
125
202
  onPress: onTogglePlay,
126
203
  style: styles.transportPrimary,
127
- children: /* @__PURE__ */ jsx(Icon, { name: playing ? "pause" : "play", size: 26, color: theme.color.accentInk })
204
+ children: /* @__PURE__ */ jsx(PlayPauseGlyph, { playing, size: 26, color: theme.color.accentInk })
128
205
  }
129
206
  ),
130
207
  /* @__PURE__ */ jsx(
131
208
  Pressable,
132
209
  {
133
210
  accessibilityRole: "button",
134
- accessibilityLabel: "Skip forward",
211
+ accessibilityLabel: labels.skipForward,
135
212
  onPress: onSkipForward,
136
213
  style: styles.transportSecondary,
137
214
  children: /* @__PURE__ */ jsx(Icon, { name: "skip-forward", size: 22, color: theme.color.text2 })
@@ -148,8 +225,8 @@ function AudioPlayerCollapsible({
148
225
  ...rest
149
226
  }) {
150
227
  const { styles } = useStyles(sheet);
151
- const theme = useLoamTheme();
152
- const resolvedMotion = useResolvedMotion(motion);
228
+ const theme = useLoamTheme("audio-player");
229
+ const resolvedMotion = useResolvedMotion(motion, "audio-player");
153
230
  const [ownExpanded, setOwnExpanded] = React.useState(false);
154
231
  const isExpanded = expanded ?? ownExpanded;
155
232
  const fade = React.useRef(new Animated.Value(isExpanded ? 1 : 0)).current;
@@ -322,6 +399,7 @@ var sheet = createStyleSheet((theme) => ({
322
399
  color: theme.color.text3
323
400
  },
324
401
  progressWrap: { gap: theme.space[6] },
402
+ progressHit: { justifyContent: "center" },
325
403
  progressTrack: {
326
404
  height: theme.space[4],
327
405
  borderRadius: theme.radius.full,
@@ -1,9 +1,14 @@
1
- import { Icon } from './chunk-TKVFVF5D.js';
1
+ import { useLabels } from './chunk-APCWFOZW.js';
2
+ import { Icon } from './chunk-UXGIW7OK.js';
3
+ import { springConfig } from './chunk-J64KGCGX.js';
2
4
  import * as React from 'react';
3
5
  import { StyleSheet, Animated, Easing, View, Pressable, Text } from 'react-native';
4
6
  import { createStyleSheet, useLoamTheme, useStyles } from '@btndprojects/loam-theme-native';
5
7
  import { jsxs, jsx } from 'react/jsx-runtime';
6
8
 
9
+ var DEFAULT_LABELS = {
10
+ closeMenu: "Close menu"
11
+ };
7
12
  function foreground(theme, variant) {
8
13
  switch (variant) {
9
14
  case "primary":
@@ -36,9 +41,12 @@ function Fab({
36
41
  position = "bottom-end",
37
42
  motion = "full",
38
43
  safeAreaBottom = 0,
39
- accessibilityLabel
44
+ bottomOffset = 0,
45
+ accessibilityLabel,
46
+ labels: labelsProp
40
47
  }) {
41
- const theme = useLoamTheme();
48
+ const labels = useLabels("fab", DEFAULT_LABELS, labelsProp);
49
+ const theme = useLoamTheme("fab");
42
50
  const isExtended = typeof label === "string" && label.length > 0;
43
51
  const { styles } = useStyles(sheet, {
44
52
  variant,
@@ -57,7 +65,7 @@ function Fab({
57
65
  const animateOpen = motion === "full" && !reduced;
58
66
  const fg = foreground(theme, variant);
59
67
  const iconSize = size === "regular" ? theme.icon.lg : theme.icon.md;
60
- const bottom = theme.layout.screenPad + safeAreaBottom;
68
+ const bottom = theme.layout.screenPad + safeAreaBottom + bottomOffset;
61
69
  const highContrast = theme.contrast === "more";
62
70
  const elevation = size === "regular" ? theme.shadow.lg : theme.shadow.md;
63
71
  const edgeStyle = highContrast ? { borderWidth: theme.borderWidth.base, borderColor: highContrastEdge(theme, variant) } : null;
@@ -98,7 +106,7 @@ function Fab({
98
106
  const scale = React.useRef(new Animated.Value(1)).current;
99
107
  const spring = (to) => {
100
108
  if (!animatePress) return;
101
- Animated.spring(scale, { toValue: to, useNativeDriver: true, speed: 40, bounciness: 6 }).start();
109
+ Animated.spring(scale, { ...springConfig(theme, "fs"), toValue: to, useNativeDriver: true }).start();
102
110
  };
103
111
  const handleMainPress = () => {
104
112
  if (hasActions) setOpen((o) => !o);
@@ -125,7 +133,7 @@ function Fab({
125
133
  Pressable,
126
134
  {
127
135
  accessibilityRole: "button",
128
- accessibilityLabel: "Close menu",
136
+ accessibilityLabel: labels.closeMenu,
129
137
  onPress: () => setOpen(false),
130
138
  style: styles.scrim
131
139
  }
@@ -176,7 +184,7 @@ function Fab({
176
184
  accessibilityLabel: name,
177
185
  accessibilityState: hasActions ? { expanded: open } : void 0,
178
186
  onPress: handleMainPress,
179
- onPressIn: () => spring(0.97),
187
+ onPressIn: () => spring(0.96),
180
188
  onPressOut: () => spring(1),
181
189
  children: /* @__PURE__ */ jsxs(Animated.View, { style: [styles.fab, edgeStyle, elevation, { transform: [{ scale }] }], children: [
182
190
  /* @__PURE__ */ jsx(Animated.View, { style: { transform: [{ rotate }] }, children: /* @__PURE__ */ jsx(Icon, { name: icon, size: iconSize, color: fg }) }),
@@ -1,6 +1,7 @@
1
- import { expandedProps } from './chunk-RQ3HASCC.js';
1
+ import { expandedProps } from './chunk-W23G6JLF.js';
2
2
  import { haptics } from './chunk-NY2U3PBI.js';
3
- import { Icon } from './chunk-TKVFVF5D.js';
3
+ import { useLabels } from './chunk-APCWFOZW.js';
4
+ import { Icon } from './chunk-UXGIW7OK.js';
4
5
  import * as React from 'react';
5
6
  import { useWindowDimensions, Animated, Easing, Modal, View, StyleSheet, Pressable, Text, Platform } from 'react-native';
6
7
  import { createStyleSheet, useLoamTheme, useStyles } from '@btndprojects/loam-theme-native';
@@ -54,7 +55,7 @@ function placeContextMenu(anchor, screen, platform) {
54
55
  return { left, top, width };
55
56
  }
56
57
  function useResolvedPlatform(explicit) {
57
- const theme = useLoamTheme();
58
+ const theme = useLoamTheme("context-menu");
58
59
  if (explicit) return explicit;
59
60
  if (Platform.OS === "ios") return "ios";
60
61
  if (Platform.OS === "android") return "android";
@@ -68,11 +69,13 @@ function ContextMenuOverlay({
68
69
  platform,
69
70
  lift,
70
71
  radius,
71
- accessibilityLabel = "Actions",
72
- closeLabel = "Close menu",
72
+ accessibilityLabel,
73
+ closeLabel,
74
+ labels: labelsProp,
73
75
  motion = "full"
74
76
  }) {
75
- const theme = useLoamTheme();
77
+ const labels = useLabels("contextMenu", DEFAULT_LABELS, labelsProp);
78
+ const theme = useLoamTheme("context-menu");
76
79
  const os = useResolvedPlatform(platform);
77
80
  const ios = os === "ios";
78
81
  const { styles } = useStyles(sheet, { platform: os });
@@ -229,7 +232,7 @@ function ContextMenuOverlay({
229
232
  {
230
233
  style: StyleSheet.absoluteFill,
231
234
  accessibilityRole: "button",
232
- accessibilityLabel: closeLabel,
235
+ accessibilityLabel: closeLabel ?? labels.closeMenu,
233
236
  onPress: onClose
234
237
  }
235
238
  )
@@ -238,6 +241,8 @@ function ContextMenuOverlay({
238
241
  Animated.View,
239
242
  {
240
243
  pointerEvents: "none",
244
+ accessibilityElementsHidden: true,
245
+ importantForAccessibility: "no-hide-descendants",
241
246
  style: [
242
247
  styles.lift,
243
248
  {
@@ -258,8 +263,9 @@ function ContextMenuOverlay({
258
263
  /* @__PURE__ */ jsxs(
259
264
  Animated.View,
260
265
  {
266
+ accessibilityViewIsModal: true,
261
267
  accessibilityRole: "menu",
262
- accessibilityLabel,
268
+ accessibilityLabel: accessibilityLabel ?? labels.actions,
263
269
  style: [
264
270
  styles.menu,
265
271
  {
@@ -295,7 +301,7 @@ function MenuItem({
295
301
  last,
296
302
  onClose
297
303
  }) {
298
- const theme = useLoamTheme();
304
+ const theme = useLoamTheme("context-menu");
299
305
  const ios = platform === "ios";
300
306
  const { styles } = useStyles(sheet, { platform, separated: ios && !last });
301
307
  const size = React.useRef({ width: 0, height: 0 });
@@ -395,6 +401,11 @@ function MenuItem({
395
401
  }
396
402
  );
397
403
  }
404
+ var DEFAULT_LABELS = {
405
+ actions: "Actions",
406
+ closeMenu: "Close menu",
407
+ showActions: "Show actions"
408
+ };
398
409
  function ContextMenu({
399
410
  items,
400
411
  children,
@@ -406,9 +417,11 @@ function ContextMenu({
406
417
  style,
407
418
  onOpen,
408
419
  onClose,
409
- motion = "full"
420
+ motion = "full",
421
+ labels: labelsProp
410
422
  }) {
411
- const theme = useLoamTheme();
423
+ const labels = useLabels("contextMenu", DEFAULT_LABELS, labelsProp);
424
+ const theme = useLoamTheme("context-menu");
412
425
  const os = useResolvedPlatform(platform);
413
426
  const ios = os === "ios";
414
427
  const { styles } = useStyles(sheet, { platform: os });
@@ -464,7 +477,7 @@ function ContextMenu({
464
477
  accessibilityLabel,
465
478
  accessibilityState: { disabled, expanded: open },
466
479
  ...expandedProps(open),
467
- accessibilityActions: [{ name: "longpress", label: "Show actions" }],
480
+ accessibilityActions: [{ name: "longpress", label: labels.showActions }],
468
481
  onAccessibilityAction: (e) => {
469
482
  if (e.nativeEvent.actionName === "longpress") openMenu();
470
483
  },
@@ -509,6 +522,7 @@ function ContextMenu({
509
522
  lift: children,
510
523
  radius: triggerRadius,
511
524
  accessibilityLabel,
525
+ labels: labelsProp,
512
526
  motion
513
527
  }
514
528
  )
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,218 @@
1
+ import { useLabels } from './chunk-APCWFOZW.js';
2
+ import { Icon } from './chunk-UXGIW7OK.js';
3
+ import { useResolvedMotion, springConfig } from './chunk-J64KGCGX.js';
4
+ import * as React from 'react';
5
+ import { Animated, Easing, Pressable, Text, View } from 'react-native';
6
+ import { createStyleSheet, useStyles, useLoamTheme } from '@btndprojects/loam-theme-native';
7
+ import { jsx, jsxs } from 'react/jsx-runtime';
8
+
9
+ var DEFAULT_LABELS = {
10
+ offline: (queued) => `Offline \xB7 ${queued} change${queued === 1 ? "" : "s"} queued`,
11
+ syncing: "Back online \xB7 syncing",
12
+ synced: "All changes synced",
13
+ retry: "RETRY",
14
+ badgeQueued: "Queued \u2014 waiting for a connection",
15
+ badgeSyncing: "Syncing",
16
+ badgeSynced: "Synced",
17
+ badgeFailed: "Failed to sync"
18
+ };
19
+ function statusMeta(status, queued, labels) {
20
+ switch (status) {
21
+ case "offline":
22
+ return { icon: "wifi-off", label: labels.offline(queued) };
23
+ case "syncing":
24
+ return { icon: "refresh", label: labels.syncing };
25
+ default:
26
+ return { icon: "check-circle", label: labels.synced };
27
+ }
28
+ }
29
+ function ConnectivityBanner({
30
+ status,
31
+ queuedCount = 0,
32
+ onRetry,
33
+ message,
34
+ motion = "full",
35
+ labels: labelsProp
36
+ }) {
37
+ const labels = useLabels("connectivity", DEFAULT_LABELS, labelsProp);
38
+ const { styles } = useStyles(sheet, { status });
39
+ const theme = useLoamTheme("connectivity");
40
+ const level = useResolvedMotion(motion, "connectivity");
41
+ const enter = React.useRef(new Animated.Value(level === "full" ? 0 : 1)).current;
42
+ const first = React.useRef(true);
43
+ React.useEffect(() => {
44
+ if (level !== "full") {
45
+ enter.setValue(1);
46
+ return;
47
+ }
48
+ enter.setValue(first.current ? 0 : 0.6);
49
+ first.current = false;
50
+ const run = Animated.spring(enter, {
51
+ ...springConfig(theme, "ds"),
52
+ toValue: 1,
53
+ useNativeDriver: true
54
+ });
55
+ run.start();
56
+ return () => run.stop();
57
+ }, [status, level, enter, theme]);
58
+ const dim = React.useRef(new Animated.Value(1)).current;
59
+ React.useEffect(() => {
60
+ if (status !== "syncing" || level !== "full" || theme.reduceMotion) {
61
+ dim.setValue(1);
62
+ return;
63
+ }
64
+ const half = theme.loop.pulse / 2;
65
+ const easing = Easing.bezier(...theme.easing.inOut);
66
+ const loop = Animated.loop(
67
+ Animated.sequence([
68
+ Animated.timing(dim, { toValue: 0.4, duration: half, easing, useNativeDriver: true }),
69
+ Animated.timing(dim, { toValue: 1, duration: half, easing, useNativeDriver: true })
70
+ ])
71
+ );
72
+ loop.start();
73
+ return () => loop.stop();
74
+ }, [status, level, theme.reduceMotion, theme.loop.pulse, theme.easing.inOut, dim]);
75
+ const meta = statusMeta(status, queuedCount, labels);
76
+ const fg = status === "offline" ? (
77
+ // The offline banner rests on `surface3`, where neutral `text2` measures
78
+ // only 4.4:1 (WCAG fail); primary `text` clears 4.5:1.
79
+ theme.color.text
80
+ ) : status === "syncing" ? theme.color.warnOnSoft : theme.color.goodOnSoft;
81
+ return /* @__PURE__ */ jsx(
82
+ Pressable,
83
+ {
84
+ accessibilityRole: onRetry ? "button" : "text",
85
+ accessibilityLabel: message ?? meta.label,
86
+ accessibilityState: onRetry ? {} : { disabled: true },
87
+ onPress: onRetry,
88
+ style: ({ pressed }) => [styles.banner, pressed && onRetry ? styles.pressed : null],
89
+ children: /* @__PURE__ */ jsxs(
90
+ Animated.View,
91
+ {
92
+ style: [
93
+ styles.slide,
94
+ {
95
+ opacity: enter,
96
+ transform: [
97
+ {
98
+ translateY: enter.interpolate({
99
+ inputRange: [0, 1],
100
+ outputRange: [-theme.space[10], 0]
101
+ })
102
+ }
103
+ ]
104
+ }
105
+ ],
106
+ children: [
107
+ /* @__PURE__ */ jsx(Animated.View, { style: { opacity: dim }, children: /* @__PURE__ */ jsx(Icon, { name: meta.icon, size: 15, color: fg }) }),
108
+ /* @__PURE__ */ jsx(Text, { style: [styles.label, { color: fg }], numberOfLines: 1, ellipsizeMode: "tail", children: message ?? meta.label }),
109
+ status === "offline" && onRetry ? /* @__PURE__ */ jsx(Text, { style: styles.retry, children: labels.retry }) : null
110
+ ]
111
+ }
112
+ )
113
+ }
114
+ );
115
+ }
116
+ var SYNC_ICON = {
117
+ queued: "refresh",
118
+ syncing: "refresh",
119
+ synced: "check",
120
+ failed: "alert-circle"
121
+ };
122
+ function SyncBadge({
123
+ state,
124
+ accessibilityLabel,
125
+ size = 26,
126
+ labels: labelsProp
127
+ }) {
128
+ const labels = useLabels("connectivity", DEFAULT_LABELS, labelsProp);
129
+ const { styles } = useStyles(sheet, { state });
130
+ const theme = useLoamTheme("connectivity");
131
+ const meta = {
132
+ icon: SYNC_ICON[state],
133
+ label: {
134
+ queued: labels.badgeQueued,
135
+ syncing: labels.badgeSyncing,
136
+ synced: labels.badgeSynced,
137
+ failed: labels.badgeFailed
138
+ }[state]
139
+ };
140
+ const fg = state === "synced" ? theme.color.goodOnSoft : state === "failed" ? theme.color.dangerOnSoft : theme.color.warnOnSoft;
141
+ return /* @__PURE__ */ jsx(
142
+ View,
143
+ {
144
+ accessibilityRole: "image",
145
+ accessibilityLabel: accessibilityLabel ?? meta.label,
146
+ style: [styles.badge, { width: size, height: size }],
147
+ children: /* @__PURE__ */ jsx(Icon, { name: meta.icon, size: Math.round(size * 0.54), color: fg })
148
+ }
149
+ );
150
+ }
151
+ var sheet = createStyleSheet((theme) => ({
152
+ banner: {
153
+ flexDirection: "row",
154
+ alignItems: "center",
155
+ paddingVertical: theme.space[10],
156
+ paddingHorizontal: theme.space.s4,
157
+ borderBottomWidth: theme.borderWidth.base,
158
+ variants: {
159
+ status: {
160
+ offline: {
161
+ backgroundColor: theme.color.surface3,
162
+ borderBottomColor: theme.color.border
163
+ },
164
+ syncing: {
165
+ backgroundColor: theme.color.warnSoft,
166
+ borderBottomColor: theme.edge.warn
167
+ },
168
+ online: {
169
+ backgroundColor: theme.color.goodSoft,
170
+ borderBottomColor: theme.edge.good
171
+ }
172
+ },
173
+ state: {}
174
+ }
175
+ },
176
+ slide: {
177
+ flex: 1,
178
+ flexDirection: "row",
179
+ alignItems: "center",
180
+ gap: theme.space[9],
181
+ variants: { status: {}, state: {} }
182
+ },
183
+ // `minWidth: 0` lets the copy truncate rather than push `RETRY` off the edge.
184
+ label: {
185
+ flex: 1,
186
+ minWidth: 0,
187
+ fontFamily: theme.font.sans,
188
+ fontWeight: theme.fontWeight.semibold,
189
+ fontSize: theme.type.caption1.fontSize,
190
+ variants: { status: {}, state: {} }
191
+ },
192
+ retry: {
193
+ fontFamily: theme.font.mono,
194
+ fontSize: theme.fontSize[10],
195
+ // Shown only on the offline banner's `surface3` fill, where `text3` is
196
+ // 4.16:1 (WCAG fail); primary `text` clears 4.5:1.
197
+ color: theme.color.text,
198
+ variants: { status: {}, state: {} }
199
+ },
200
+ badge: {
201
+ alignItems: "center",
202
+ justifyContent: "center",
203
+ borderRadius: theme.radius.full,
204
+ borderWidth: theme.borderWidth.base,
205
+ variants: {
206
+ state: {
207
+ queued: { backgroundColor: theme.color.warnSoft, borderColor: theme.edge.warn },
208
+ syncing: { backgroundColor: theme.color.warnSoft, borderColor: theme.edge.warn },
209
+ synced: { backgroundColor: theme.color.goodSoft, borderColor: theme.edge.good },
210
+ failed: { backgroundColor: theme.color.dangerSoft, borderColor: theme.edge.danger }
211
+ },
212
+ status: {}
213
+ }
214
+ },
215
+ pressed: { opacity: theme.state.pressedOpacity }
216
+ }));
217
+
218
+ export { ConnectivityBanner, SyncBadge };