@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,116 @@
1
+ import 'react';
2
+ import { Svg, Circle, Line, Rect, Polyline, Polygon, Ellipse, Path } from 'react-native-svg';
3
+ import { icons } from '@btndprojects/loam-icons';
4
+ import { useLoamTheme } from '@btndprojects/loam-theme-native';
5
+ import { jsx } from 'react/jsx-runtime';
6
+
7
+ // src/lib/icon.tsx
8
+ function Icon({
9
+ name,
10
+ size = 20,
11
+ color,
12
+ strokeWidth = 1.5,
13
+ accessibilityLabel
14
+ }) {
15
+ const theme = useLoamTheme();
16
+ const stroke = color ?? theme.color.text;
17
+ return /* @__PURE__ */ jsx(
18
+ Svg,
19
+ {
20
+ width: size,
21
+ height: size,
22
+ viewBox: "0 0 24 24",
23
+ fill: "none",
24
+ ...accessibilityLabel ? { accessible: true, accessibilityRole: "image", accessibilityLabel } : {
25
+ accessible: false,
26
+ accessibilityElementsHidden: true,
27
+ importantForAccessibility: "no-hide-descendants",
28
+ "aria-hidden": true
29
+ },
30
+ children: icons[name].map((p, i) => {
31
+ if (p.t === "circle")
32
+ return p.fill ? /* @__PURE__ */ jsx(Circle, { cx: p.cx, cy: p.cy, r: p.r, fill: stroke }, i) : /* @__PURE__ */ jsx(Circle, { cx: p.cx, cy: p.cy, r: p.r, stroke, strokeWidth }, i);
33
+ if (p.t === "line")
34
+ return /* @__PURE__ */ jsx(
35
+ Line,
36
+ {
37
+ x1: p.x1,
38
+ y1: p.y1,
39
+ x2: p.x2,
40
+ y2: p.y2,
41
+ stroke,
42
+ strokeWidth,
43
+ strokeLinecap: "round"
44
+ },
45
+ i
46
+ );
47
+ if (p.t === "rect")
48
+ return /* @__PURE__ */ jsx(
49
+ Rect,
50
+ {
51
+ x: p.x,
52
+ y: p.y,
53
+ width: p.width,
54
+ height: p.height,
55
+ rx: p.rx,
56
+ ry: p.ry,
57
+ stroke,
58
+ strokeWidth,
59
+ strokeLinejoin: "round"
60
+ },
61
+ i
62
+ );
63
+ if (p.t === "polyline")
64
+ return /* @__PURE__ */ jsx(
65
+ Polyline,
66
+ {
67
+ points: p.points,
68
+ stroke,
69
+ strokeWidth,
70
+ strokeLinecap: "round",
71
+ strokeLinejoin: "round"
72
+ },
73
+ i
74
+ );
75
+ if (p.t === "polygon")
76
+ return /* @__PURE__ */ jsx(
77
+ Polygon,
78
+ {
79
+ points: p.points,
80
+ stroke,
81
+ strokeWidth,
82
+ strokeLinecap: "round",
83
+ strokeLinejoin: "round"
84
+ },
85
+ i
86
+ );
87
+ if (p.t === "ellipse")
88
+ return /* @__PURE__ */ jsx(
89
+ Ellipse,
90
+ {
91
+ cx: p.cx,
92
+ cy: p.cy,
93
+ rx: p.rx,
94
+ ry: p.ry,
95
+ stroke,
96
+ strokeWidth
97
+ },
98
+ i
99
+ );
100
+ return /* @__PURE__ */ jsx(
101
+ Path,
102
+ {
103
+ d: p.d,
104
+ stroke,
105
+ strokeWidth,
106
+ strokeLinecap: "round",
107
+ strokeLinejoin: "round"
108
+ },
109
+ i
110
+ );
111
+ })
112
+ }
113
+ );
114
+ }
115
+
116
+ export { Icon };
@@ -1,43 +1,63 @@
1
- import { Progress } from './chunk-2ZZ7TDJ4.js';
2
- import { Button } from './chunk-3ARE4TES.js';
3
- import { Icon } from './chunk-TKVFVF5D.js';
1
+ import { Progress } from './chunk-5UTRIXQ6.js';
2
+ import { Button } from './chunk-E2E3I5W2.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 { View, Text, Animated, Easing } from 'react-native';
6
7
  import { createStyleSheet, useLoamTheme, useStyles } from '@btndprojects/loam-theme-native';
7
8
  import { jsxs, jsx } from 'react/jsx-runtime';
8
9
 
10
+ var DEFAULT_LABELS = {
11
+ hint: "PNG, JPG or PDF \xB7 up to 25 MB each",
12
+ camera: "Camera",
13
+ library: "Library",
14
+ permissionTitle: "Permission needed",
15
+ permissionBody: "Allow camera and photo access in Settings to upload.",
16
+ openSettings: "Open settings",
17
+ done: "Done",
18
+ failed: "Failed",
19
+ queued: "Queued",
20
+ progressRemaining: (percent2, remaining) => `${percent2}% \xB7 ${remaining}`,
21
+ phraseDone: (size) => size ? `uploaded, ${size}` : "uploaded",
22
+ phraseFailed: (error) => error ? `upload failed, ${error}` : "upload failed",
23
+ phraseQueued: "queued",
24
+ phraseUploading: (percent2) => `uploading, ${percent2} percent`,
25
+ uploading: (name) => `Uploading ${name}`,
26
+ retry: (name) => `Retry ${name}`,
27
+ remove: (name) => `Remove ${name}`
28
+ };
9
29
  function clamp(n, lo, hi) {
10
30
  return Math.max(lo, Math.min(hi, n));
11
31
  }
12
32
  function percent(progress) {
13
33
  return Math.round(clamp(progress ?? 0, 0, 1) * 100);
14
34
  }
15
- function statusLabel(file) {
35
+ function statusLabel(file, labels) {
16
36
  switch (file.status) {
17
37
  case "done":
18
- return file.size ?? "Done";
38
+ return [file.fileType, file.size].filter(Boolean).join(" \xB7 ") || labels.done;
19
39
  case "error":
20
- return "Failed";
40
+ return labels.failed;
21
41
  case "queued":
22
- return "Queued";
42
+ return labels.queued;
23
43
  default:
24
- return `${percent(file.progress)}%`;
44
+ return file.remaining ? labels.progressRemaining(percent(file.progress), file.remaining) : `${percent(file.progress)}%`;
25
45
  }
26
46
  }
27
- function statusPhrase(file) {
47
+ function statusPhrase(file, labels) {
28
48
  switch (file.status) {
29
49
  case "done":
30
- return file.size ? `uploaded, ${file.size}` : "uploaded";
50
+ return labels.phraseDone(file.size);
31
51
  case "error":
32
- return file.error ? `upload failed, ${file.error}` : "upload failed";
52
+ return labels.phraseFailed(file.error);
33
53
  case "queued":
34
- return "queued";
54
+ return labels.phraseQueued;
35
55
  default:
36
- return `uploading, ${percent(file.progress)} percent`;
56
+ return labels.phraseUploading(percent(file.progress));
37
57
  }
38
58
  }
39
- function FileUploadRow({ file, onRetry, onRemove, motion }) {
40
- const theme = useLoamTheme();
59
+ function FileUploadRow({ file, onRetry, onRemove, motion, labels }) {
60
+ const theme = useLoamTheme("file-upload");
41
61
  const { styles } = useStyles(sheet);
42
62
  const isError = file.status === "error";
43
63
  const isDone = file.status === "done";
@@ -82,19 +102,20 @@ function FileUploadRow({ file, onRetry, onRemove, motion }) {
82
102
  Text,
83
103
  {
84
104
  numberOfLines: 1,
85
- accessibilityLabel: `${file.name}, ${statusPhrase(file)}`,
105
+ accessibilityLabel: `${file.name}, ${statusPhrase(file, labels)}`,
86
106
  style: styles.name,
87
107
  children: file.name
88
108
  }
89
109
  ),
90
- /* @__PURE__ */ jsx(Text, { style: [styles.status, { color: isError ? theme.color.danger : theme.color.text2 }], children: statusLabel(file) })
110
+ /* @__PURE__ */ jsx(Text, { style: [styles.status, { color: isError ? theme.color.danger : theme.color.text2 }], children: statusLabel(file, labels) })
91
111
  ] }),
112
+ isError && file.error ? /* @__PURE__ */ jsx(Text, { style: [styles.status, { color: theme.color.danger }], children: file.error }) : null,
92
113
  isUploading ? /* @__PURE__ */ jsx(
93
114
  Progress,
94
115
  {
95
116
  size: "sm",
96
117
  value: percent(file.progress),
97
- accessibilityLabel: `Uploading ${file.name}`
118
+ accessibilityLabel: labels.uploading(file.name)
98
119
  }
99
120
  ) : null
100
121
  ] }),
@@ -104,7 +125,7 @@ function FileUploadRow({ file, onRetry, onRemove, motion }) {
104
125
  variant: "ghost",
105
126
  size: "sm",
106
127
  leadingIcon: "refresh",
107
- accessibilityLabel: `Retry ${file.name}`,
128
+ accessibilityLabel: labels.retry(file.name),
108
129
  onPress: onRetry ? () => onRetry(file.id) : void 0
109
130
  }
110
131
  ) : /* @__PURE__ */ jsx(
@@ -113,7 +134,7 @@ function FileUploadRow({ file, onRetry, onRemove, motion }) {
113
134
  variant: "ghost",
114
135
  size: "sm",
115
136
  leadingIcon: "x",
116
- accessibilityLabel: `Remove ${file.name}`,
137
+ accessibilityLabel: labels.remove(file.name),
117
138
  onPress: onRemove ? () => onRemove(file.id) : void 0
118
139
  }
119
140
  )
@@ -128,19 +149,22 @@ function FileUpload({
128
149
  permissionState = "granted",
129
150
  onOpenSettings,
130
151
  accept: _accept,
131
- hint = "PNG, JPG or PDF \xB7 up to 25 MB each",
132
- motion = "reduced"
152
+ hint: hintProp,
153
+ motion = "reduced",
154
+ labels: labelsProp
133
155
  }) {
134
- const theme = useLoamTheme();
156
+ const theme = useLoamTheme("file-upload");
135
157
  const { styles } = useStyles(sheet);
158
+ const labels = useLabels("fileUpload", DEFAULT_LABELS, labelsProp);
159
+ const hint = hintProp ?? labels.hint;
136
160
  const denied = permissionState === "denied";
137
161
  return /* @__PURE__ */ jsxs(View, { style: styles.rootWrap, children: [
138
162
  denied ? /* @__PURE__ */ jsxs(View, { style: styles.denied, children: [
139
163
  /* @__PURE__ */ jsxs(View, { style: styles.deniedHead, children: [
140
164
  /* @__PURE__ */ jsx(Icon, { name: "lock", size: theme.icon.md, color: theme.color.warnOnSoft }),
141
165
  /* @__PURE__ */ jsxs(View, { style: styles.main, children: [
142
- /* @__PURE__ */ jsx(Text, { style: [styles.deniedTitle, { color: theme.color.warnOnSoft }], children: "Permission needed" }),
143
- /* @__PURE__ */ jsx(Text, { style: [styles.deniedBody, { color: theme.color.warnOnSoft }], children: "Allow camera and photo access in Settings to upload." })
166
+ /* @__PURE__ */ jsx(Text, { style: [styles.deniedTitle, { color: theme.color.warnOnSoft }], children: labels.permissionTitle }),
167
+ /* @__PURE__ */ jsx(Text, { style: [styles.deniedBody, { color: theme.color.warnOnSoft }], children: labels.permissionBody })
144
168
  ] })
145
169
  ] }),
146
170
  /* @__PURE__ */ jsx(
@@ -149,15 +173,15 @@ function FileUpload({
149
173
  variant: "outline",
150
174
  size: "sm",
151
175
  leadingIcon: "settings",
152
- accessibilityLabel: "Open settings",
176
+ accessibilityLabel: labels.openSettings,
153
177
  onPress: onOpenSettings,
154
- children: "Open settings"
178
+ children: labels.openSettings
155
179
  }
156
180
  )
157
181
  ] }) : /* @__PURE__ */ jsxs(View, { style: styles.entry, children: [
158
182
  /* @__PURE__ */ jsxs(View, { style: styles.actions, children: [
159
- /* @__PURE__ */ jsx(View, { style: styles.actionItem, children: /* @__PURE__ */ jsx(Button, { variant: "outline", leadingIcon: "maximize", fullWidth: true, onPress: onPickCamera, children: "Camera" }) }),
160
- /* @__PURE__ */ jsx(View, { style: styles.actionItem, children: /* @__PURE__ */ jsx(Button, { variant: "outline", leadingIcon: "image", fullWidth: true, onPress: onPickLibrary, children: "Library" }) })
183
+ /* @__PURE__ */ jsx(View, { style: styles.actionItem, children: /* @__PURE__ */ jsx(Button, { variant: "outline", leadingIcon: "maximize", fullWidth: true, onPress: onPickCamera, children: labels.camera }) }),
184
+ /* @__PURE__ */ jsx(View, { style: styles.actionItem, children: /* @__PURE__ */ jsx(Button, { variant: "outline", leadingIcon: "image", fullWidth: true, onPress: onPickLibrary, children: labels.library }) })
161
185
  ] }),
162
186
  hint ? /* @__PURE__ */ jsx(Text, { style: styles.hint, children: hint }) : null
163
187
  ] }),
@@ -167,7 +191,8 @@ function FileUpload({
167
191
  file,
168
192
  onRetry,
169
193
  onRemove,
170
- motion
194
+ motion,
195
+ labels
171
196
  },
172
197
  file.id
173
198
  )) }) : null
@@ -1,12 +1,21 @@
1
- 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';
2
4
  import * as React from 'react';
3
- import { View, Image, Text } from 'react-native';
5
+ import { Animated, View, Text, StyleSheet, Image } from 'react-native';
4
6
  import { createStyleSheet, useStyles, useLoamTheme } from '@btndprojects/loam-theme-native';
5
7
  import { jsxs, jsx } from 'react/jsx-runtime';
6
8
 
7
9
  var SIZE_PX = { xs: 28, sm: 36, md: 48, lg: 60, xl: 76 };
10
+ var DEFAULT_LABELS = {
11
+ avatar: "Avatar",
12
+ online: "online",
13
+ offline: "offline",
14
+ busy: "busy",
15
+ away: "away"
16
+ };
8
17
  function useStatusColor(status) {
9
- const theme = useLoamTheme();
18
+ const theme = useLoamTheme("avatar");
10
19
  if (!status) return void 0;
11
20
  switch (status) {
12
21
  case "online":
@@ -54,19 +63,32 @@ function Avatar({
54
63
  shape = "circle",
55
64
  accent = false,
56
65
  hashed = false,
57
- // Inert (see prop docs); destructured so it never reaches a native element.
58
- motion: _motion = "full"
66
+ motion = "full",
67
+ labels: labelsProp
59
68
  }) {
69
+ const labels = useLabels("avatar", DEFAULT_LABELS, labelsProp);
60
70
  const { styles } = useStyles(sheet, { size, accent });
61
- const theme = useLoamTheme();
71
+ const theme = useLoamTheme("avatar");
62
72
  const [errored, setErrored] = React.useState(false);
63
73
  const statusColor = useStatusColor(status);
74
+ const level = useResolvedMotion(motion, "avatar");
75
+ const photo = React.useRef(new Animated.Value(0)).current;
76
+ const pop = React.useRef(new Animated.Value(level === "full" ? 0 : 1)).current;
77
+ React.useEffect(() => {
78
+ if (level !== "full") return;
79
+ Animated.spring(pop, { ...springConfig(theme, "fs"), toValue: 1, useNativeDriver: true }).start();
80
+ }, []);
81
+ const onLoad = () => {
82
+ if (level === "none") photo.setValue(1);
83
+ else Animated.timing(photo, { ...motionTiming(level), toValue: 1, useNativeDriver: true }).start();
84
+ };
64
85
  const dim = SIZE_PX[size];
65
86
  const showImage = Boolean(src) && !errored;
66
87
  const initials = initialsFromName(name);
67
88
  const hashPair = hashed && initials ? hashedColors(theme, id ?? name) : void 0;
68
89
  const fg = hashPair ? hashPair.ink : accent ? theme.color.accentOnSoft : theme.color.text2;
69
- const label = name ?? "Avatar";
90
+ const label = name ?? labels.avatar;
91
+ const statusLabel = status ? labels[status] : void 0;
70
92
  const shapeRadius = shape === "circle" ? theme.radius.full : shape === "rounded" ? theme.radius.lg : Math.round(dim * 0.32);
71
93
  const shapeStyle = {
72
94
  borderRadius: shapeRadius,
@@ -83,7 +105,11 @@ function Avatar({
83
105
  borderRadius: theme.radius.full,
84
106
  borderWidth: ring,
85
107
  borderColor: theme.color.surface,
86
- backgroundColor: statusColor
108
+ backgroundColor: statusColor,
109
+ // Each state has its own silhouette as well as its own hue, so online/busy
110
+ // never rest on red-versus-green alone: online a solid disc, offline a
111
+ // hollow one, busy a diamond, away a square.
112
+ ...status === "offline" ? { backgroundColor: theme.color.surface, borderColor: statusColor } : status === "busy" ? { borderRadius: theme.radius.sm, transform: [{ rotate: "45deg" }] } : status === "away" ? { borderRadius: 0 } : null
87
113
  };
88
114
  const ringStyle = {
89
115
  position: "absolute",
@@ -94,40 +120,28 @@ function Avatar({
94
120
  borderRadius: shape === "circle" ? theme.radius.full : shapeRadius + ring + 1,
95
121
  borderWidth: ring,
96
122
  borderColor: statusColor,
123
+ // Line style carries the state alongside the hue.
124
+ borderStyle: status === "offline" ? "dashed" : status === "away" ? "dotted" : "solid",
97
125
  ...shape === "squircle" ? { borderCurve: "continuous" } : null
98
126
  };
99
127
  return /* @__PURE__ */ jsxs(View, { style: styles.root, accessibilityRole: "image", accessibilityLabel: label, children: [
100
- /* @__PURE__ */ jsx(View, { style: [styles.circle, shapeStyle, hashPair ? { backgroundColor: hashPair.bg } : null], children: showImage ? /* @__PURE__ */ jsx(Image, { source: { uri: src }, style: styles.image, onError: () => setErrored(true) }) : initials ? /* @__PURE__ */ jsx(Text, { style: [styles.initials, { color: fg }], children: initials }) : /* @__PURE__ */ jsx(Icon, { name: "user", size: Math.round(dim * 0.5), color: fg }) }),
101
- statusColor && presence === "ring" ? /* @__PURE__ */ jsx(View, { style: ringStyle, accessibilityRole: "image", accessibilityLabel: status }) : null,
102
- statusColor && presence === "dot" ? /* @__PURE__ */ jsx(View, { style: dotStyle, accessibilityRole: "image", accessibilityLabel: status }) : null
103
- ] });
104
- }
105
- function AvatarGroup({ children, size = "md", max }) {
106
- const { styles } = useStyles(sheet, { size, accent: false });
107
- const theme = useLoamTheme();
108
- const dim = SIZE_PX[size];
109
- const ring = 2.5;
110
- const overlap = Math.round(dim * 0.3);
111
- const all = React.Children.toArray(children);
112
- const visible = typeof max === "number" ? all.slice(0, max) : all;
113
- const extra = all.length - visible.length;
114
- const wrapper = (index) => ({
115
- backgroundColor: theme.color.surface,
116
- borderRadius: theme.radius.full,
117
- padding: ring,
118
- marginStart: index === 0 ? 0 : -overlap
119
- });
120
- return /* @__PURE__ */ jsxs(View, { style: styles.group, children: [
121
- visible.map((child, i) => /* @__PURE__ */ jsx(View, { style: wrapper(i), children: React.isValidElement(child) ? React.cloneElement(child, { size }) : child }, i)),
122
- extra > 0 ? /* @__PURE__ */ jsx(View, { style: wrapper(visible.length), children: /* @__PURE__ */ jsx(View, { style: styles.circle, children: /* @__PURE__ */ jsxs(Text, { style: styles.overflow, children: [
123
- "+",
124
- extra
125
- ] }) }) }) : null
128
+ /* @__PURE__ */ jsxs(View, { style: [styles.circle, shapeStyle, hashPair ? { backgroundColor: hashPair.bg } : null], children: [
129
+ initials ? /* @__PURE__ */ jsx(Text, { style: [styles.initials, { color: fg }], children: initials }) : /* @__PURE__ */ jsx(Icon, { name: "user", size: Math.round(dim * 0.5), color: fg }),
130
+ showImage ? /* @__PURE__ */ jsx(Animated.View, { style: [StyleSheet.absoluteFill, { opacity: photo }], children: /* @__PURE__ */ jsx(Image, { source: { uri: src }, style: styles.image, onLoad, onError: () => setErrored(true) }) }) : null
131
+ ] }),
132
+ statusColor && presence === "ring" ? /* @__PURE__ */ jsx(View, { style: ringStyle, accessibilityRole: "image", accessibilityLabel: statusLabel }) : null,
133
+ statusColor && presence === "dot" ? /* @__PURE__ */ jsx(
134
+ Animated.View,
135
+ {
136
+ style: [dotStyle, { transform: [...dotStyle.transform ?? [], { scale: pop }] }],
137
+ accessibilityRole: "image",
138
+ accessibilityLabel: statusLabel
139
+ }
140
+ ) : null
126
141
  ] });
127
142
  }
128
143
  var sheet = createStyleSheet((theme) => ({
129
144
  root: { position: "relative" },
130
- group: { flexDirection: "row", alignItems: "center" },
131
145
  circle: {
132
146
  alignItems: "center",
133
147
  justifyContent: "center",
@@ -176,22 +190,7 @@ var sheet = createStyleSheet((theme) => ({
176
190
  false: { color: theme.color.text2 }
177
191
  }
178
192
  }
179
- },
180
- overflow: {
181
- fontFamily: theme.font.sans,
182
- fontWeight: theme.fontWeight.bold,
183
- color: theme.color.text2,
184
- variants: {
185
- size: {
186
- xs: { fontSize: theme.fontSize[9] },
187
- sm: { fontSize: theme.fontSize[12] },
188
- md: { fontSize: theme.fontSize[16] },
189
- lg: { fontSize: theme.fontSize[20] },
190
- xl: { fontSize: theme.fontSize[25] }
191
- },
192
- accent: {}
193
- }
194
193
  }
195
194
  }));
196
195
 
197
- export { Avatar, AvatarGroup, hashToChartIndex, initialsFromName };
196
+ export { Avatar, hashToChartIndex, initialsFromName };
@@ -1,24 +1,37 @@
1
- import { Icon } from './chunk-TKVFVF5D.js';
1
+ import { useLabels, useLoamLocale } from './chunk-APCWFOZW.js';
2
+ import { Icon } from './chunk-UXGIW7OK.js';
3
+ import { useResolvedMotion } from './chunk-J64KGCGX.js';
2
4
  import 'react';
3
- import { View, Text, Pressable } from 'react-native';
5
+ import { View, Text, Pressable, LayoutAnimation } from 'react-native';
4
6
  import { createStyleSheet, useStyles, useLoamTheme } from '@btndprojects/loam-theme-native';
5
7
  import { jsxs, jsx } from 'react/jsx-runtime';
6
8
 
9
+ var DEFAULT_LABELS = {
10
+ items: "items",
11
+ showing: (shown, total, noun) => `Showing ${shown} of ${total} ${noun}`,
12
+ showAllName: (total, noun) => `Show all ${total} ${noun}`,
13
+ showAll: (total) => `Show all ${total}`
14
+ };
7
15
  function TruncationNotice({
8
16
  shown,
9
17
  total,
10
- noun = "items",
18
+ noun: nounProp,
11
19
  onShowAll,
12
20
  actionIcon = "arrow-down",
13
21
  variant = "inline",
14
22
  size = "md",
15
- // Accepted for API consistency; intentionally unused (static feedback).
16
- motion: _motion = "full"
23
+ motion = "full",
24
+ labels: labelsProp
17
25
  }) {
26
+ const labels = useLabels("truncationNotice", DEFAULT_LABELS, labelsProp);
27
+ const locale = useLoamLocale();
28
+ const noun = nounProp ?? labels.items;
18
29
  const { styles } = useStyles(sheet, { variant, size });
19
- const theme = useLoamTheme();
30
+ const theme = useLoamTheme("truncation-notice");
31
+ const level = useResolvedMotion(motion, "truncation-notice");
20
32
  if (shown >= total) return null;
21
- const message = `Showing ${shown.toLocaleString()} of ${total.toLocaleString()} ${noun}`;
33
+ const totalText = total.toLocaleString(locale);
34
+ const message = labels.showing(shown.toLocaleString(locale), totalText, noun);
22
35
  const iconSize = size === "sm" ? theme.icon.xs : theme.icon.sm;
23
36
  const pad = variant === "bar" ? size === "sm" ? { paddingHorizontal: theme.space.s3, paddingVertical: theme.space.s2 } : { paddingHorizontal: theme.space.s4, paddingVertical: theme.space.s3 } : null;
24
37
  return /* @__PURE__ */ jsxs(View, { style: [styles.base, pad], children: [
@@ -27,15 +40,23 @@ function TruncationNotice({
27
40
  Pressable,
28
41
  {
29
42
  accessibilityRole: "button",
30
- accessibilityLabel: `Show all ${total.toLocaleString()} ${noun}`,
31
- onPress: onShowAll,
43
+ accessibilityLabel: labels.showAllName(totalText, noun),
44
+ onPress: () => {
45
+ if (level === "full") {
46
+ const ds = theme.spring.ds;
47
+ LayoutAnimation.configureNext({
48
+ duration: ds.duration,
49
+ create: { type: "easeInEaseOut", property: "opacity" },
50
+ update: { type: "spring", springDamping: ds.dampingRatio },
51
+ delete: { type: "easeInEaseOut", property: "opacity" }
52
+ });
53
+ }
54
+ onShowAll();
55
+ },
32
56
  hitSlop: { top: theme.space.s2, bottom: theme.space.s2 },
33
57
  style: ({ pressed }) => [styles.action, pressed ? styles.pressed : null],
34
58
  children: [
35
- /* @__PURE__ */ jsxs(Text, { style: styles.actionLabel, children: [
36
- "Show all ",
37
- total.toLocaleString()
38
- ] }),
59
+ /* @__PURE__ */ jsx(Text, { style: styles.actionLabel, children: labels.showAll(totalText) }),
39
60
  actionIcon ? /* @__PURE__ */ jsx(Icon, { name: actionIcon, size: iconSize, color: theme.color.accentStrong }) : null
40
61
  ]
41
62
  }
@@ -1,6 +1,7 @@
1
1
  import { MAX_OVERSCROLL_PX, REFRESH_ARM_PX, SCROLL_TOP_SLOP_PX, overscrollOffset, overscrollIntent } from './chunk-HU2EQNRZ.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 { Animated, Easing, View, Text, Pressable, ScrollView } from 'react-native';
6
7
  import { createStyleSheet, useStyles, useLoamTheme } from '@btndprojects/loam-theme-native';
@@ -15,20 +16,31 @@ function touchPageY(e) {
15
16
  function isThenable(v) {
16
17
  return typeof v?.then === "function";
17
18
  }
19
+ var DEFAULT_LABELS = {
20
+ arm: "Release to refresh",
21
+ refreshing: "Refreshing",
22
+ refresh: "Refresh",
23
+ refreshBusy: (refresh, refreshing) => `${refresh}, ${refreshing}`
24
+ };
18
25
  function PullToRefresh({
19
26
  onRefresh,
20
27
  onArm,
21
28
  refreshing,
22
29
  phase,
23
30
  indicator,
24
- armLabel = "Release to refresh",
25
- refreshingLabel = "Refreshing",
26
- refreshAccessibilityLabel = "Refresh",
31
+ armLabel: armLabelProp,
32
+ refreshingLabel: refreshingLabelProp,
33
+ refreshAccessibilityLabel: refreshAccessibilityLabelProp,
34
+ labels: labelsProp,
27
35
  children,
28
36
  ...rest
29
37
  }) {
30
38
  const { styles } = useStyles(sheet);
31
- const theme = useLoamTheme();
39
+ const theme = useLoamTheme("pull-to-refresh");
40
+ const labels = useLabels("pullToRefresh", DEFAULT_LABELS, labelsProp);
41
+ const armLabel = armLabelProp ?? labels.arm;
42
+ const refreshingLabel = refreshingLabelProp ?? labels.refreshing;
43
+ const refreshAccessibilityLabel = refreshAccessibilityLabelProp ?? labels.refresh;
32
44
  const isAndroid = (indicator ?? (theme.platform === "Android" ? "android" : "ios")) === "android";
33
45
  const reduce = theme.reduceMotion;
34
46
  const controlled = phase != null;
@@ -210,7 +222,7 @@ function PullToRefresh({
210
222
  {
211
223
  onPress: isRefreshing ? void 0 : beginRefresh,
212
224
  accessibilityRole: "button",
213
- accessibilityLabel: refreshAccessibilityLabel,
225
+ accessibilityLabel: displayRefreshing ? labels.refreshBusy(refreshAccessibilityLabel, refreshingLabel) : refreshAccessibilityLabel,
214
226
  accessibilityState: { busy: isRefreshing, disabled: isRefreshing },
215
227
  "aria-busy": isRefreshing || void 0,
216
228
  hitSlop: theme.space.s2,
@@ -0,0 +1,37 @@
1
+ import { Platform, AccessibilityInfo } from 'react-native';
2
+
3
+ // src/lib/a11y.ts
4
+ function expandedProps(expanded) {
5
+ return { "aria-expanded": expanded };
6
+ }
7
+ var NAMED_ROLE = Platform.OS === "web" ? "image" : "text";
8
+ var webRegions = {};
9
+ function webRegion(politeness) {
10
+ if (typeof document === "undefined") return null;
11
+ const existing = webRegions[politeness];
12
+ if (existing?.isConnected) return existing;
13
+ const el = document.createElement("div");
14
+ el.setAttribute("aria-live", politeness);
15
+ el.setAttribute("aria-atomic", "true");
16
+ el.setAttribute("data-loam-announcer", politeness);
17
+ el.style.cssText = // loam-audit-ignore raw-length-in-string — the sr-only clip is a DOM idiom, not a design length.
18
+ "position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0";
19
+ document.body.appendChild(el);
20
+ webRegions[politeness] = el;
21
+ return el;
22
+ }
23
+ function announce(message, politeness = "polite") {
24
+ if (!message) return;
25
+ if (Platform.OS !== "web") {
26
+ AccessibilityInfo.announceForAccessibility?.(message);
27
+ return;
28
+ }
29
+ const region = webRegion(politeness);
30
+ if (!region) return;
31
+ region.textContent = "";
32
+ setTimeout(() => {
33
+ region.textContent = message;
34
+ }, 50);
35
+ }
36
+
37
+ export { NAMED_ROLE, announce, expandedProps };