tempest-react-sdk 0.77.0 → 0.79.0

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 (1623) hide show
  1. package/README.md +6 -6
  2. package/bin/lib/alias/collect.mjs +20 -3
  3. package/bin/lib/alias/index.mjs +12 -1
  4. package/bin/lib/alias/index.test.mjs +24 -0
  5. package/bin/lib/css/analyze.test.mjs +21 -1
  6. package/bin/lib/css/collect.mjs +14 -0
  7. package/bin/lib/css/extract.mjs +63 -5
  8. package/bin/lib/css/extract.test.mjs +110 -1
  9. package/bin/lib/css/fix.e2e.test.mjs +50 -0
  10. package/bin/lib/css/index.mjs +6 -1
  11. package/bin/lib/fs/contain.mjs +50 -0
  12. package/bin/lib/icons/generate.mjs +28 -3
  13. package/bin/lib/icons/generate.test.mjs +57 -1
  14. package/bin/lib/openapi/escape.mjs +20 -6
  15. package/bin/lib/openapi/generate.encode.test.mjs +120 -0
  16. package/bin/lib/openapi/generate.hostile.test.mjs +38 -9
  17. package/bin/lib/openapi/generate.mjs +203 -64
  18. package/bin/lib/openapi/generate.pagination.test.mjs +3 -2
  19. package/bin/lib/openapi/generate.test.mjs +270 -3
  20. package/bin/lib/openapi/schema-to-zod.mjs +5 -3
  21. package/bin/tempest-gen.test.mjs +188 -0
  22. package/bin/tempest.mjs +120 -44
  23. package/dist/access/Can.cjs.map +1 -1
  24. package/dist/access/Can.js.map +1 -1
  25. package/dist/access/access-control-context.cjs.map +1 -1
  26. package/dist/access/access-control-context.js.map +1 -1
  27. package/dist/access/create-role-access-control.cjs.map +1 -1
  28. package/dist/access/create-role-access-control.js.map +1 -1
  29. package/dist/access/permissions-from-token.cjs.map +1 -1
  30. package/dist/access/permissions-from-token.js.map +1 -1
  31. package/dist/access/use-can.cjs.map +1 -1
  32. package/dist/access/use-can.js.map +1 -1
  33. package/dist/app/AppProviders.cjs.map +1 -1
  34. package/dist/app/AppProviders.js.map +1 -1
  35. package/dist/audio/audio-bus.cjs.map +1 -1
  36. package/dist/audio/audio-bus.js.map +1 -1
  37. package/dist/audio/audio-output.cjs.map +1 -1
  38. package/dist/audio/audio-output.js.map +1 -1
  39. package/dist/audio/audio-player.cjs.map +1 -1
  40. package/dist/audio/audio-player.js.map +1 -1
  41. package/dist/audio/audio-recorder.cjs.map +1 -1
  42. package/dist/audio/audio-recorder.js.map +1 -1
  43. package/dist/audio/duration.cjs.map +1 -1
  44. package/dist/audio/duration.js.map +1 -1
  45. package/dist/audio/level-meter.cjs.map +1 -1
  46. package/dist/audio/level-meter.js.map +1 -1
  47. package/dist/audio/media-access.cjs.map +1 -1
  48. package/dist/audio/media-access.js.map +1 -1
  49. package/dist/audio/noise-floor.cjs.map +1 -1
  50. package/dist/audio/noise-floor.js.map +1 -1
  51. package/dist/audio/sfx-pool.cjs.map +1 -1
  52. package/dist/audio/sfx-pool.js.map +1 -1
  53. package/dist/audio/use-audio-bus.cjs.map +1 -1
  54. package/dist/audio/use-audio-bus.js.map +1 -1
  55. package/dist/audio/use-audio-recorder.cjs.map +1 -1
  56. package/dist/audio/use-audio-recorder.js.map +1 -1
  57. package/dist/audio/use-audio.cjs.map +1 -1
  58. package/dist/audio/use-audio.js.map +1 -1
  59. package/dist/audio/use-microphone.cjs +1 -1
  60. package/dist/audio/use-microphone.cjs.map +1 -1
  61. package/dist/audio/use-microphone.js +1 -5
  62. package/dist/audio/use-microphone.js.map +1 -1
  63. package/dist/audio/use-sfx-pool.cjs.map +1 -1
  64. package/dist/audio/use-sfx-pool.js.map +1 -1
  65. package/dist/audio/voice-activity.cjs.map +1 -1
  66. package/dist/audio/voice-activity.js.map +1 -1
  67. package/dist/audio/voice-chain-stages.cjs.map +1 -1
  68. package/dist/audio/voice-chain-stages.js.map +1 -1
  69. package/dist/audio/voice-chain.cjs.map +1 -1
  70. package/dist/audio/voice-chain.js.map +1 -1
  71. package/dist/audio/wav.cjs.map +1 -1
  72. package/dist/audio/wav.js.map +1 -1
  73. package/dist/auth/AuthGuard.cjs.map +1 -1
  74. package/dist/auth/AuthGuard.js.map +1 -1
  75. package/dist/auth/create-auth-store.cjs.map +1 -1
  76. package/dist/auth/create-auth-store.js.map +1 -1
  77. package/dist/auth/create-tempest-auth.cjs +1 -1
  78. package/dist/auth/create-tempest-auth.cjs.map +1 -1
  79. package/dist/auth/create-tempest-auth.js +185 -114
  80. package/dist/auth/create-tempest-auth.js.map +1 -1
  81. package/dist/auth/jwt.cjs.map +1 -1
  82. package/dist/auth/jwt.js.map +1 -1
  83. package/dist/auth/lazy-with-retry.cjs.map +1 -1
  84. package/dist/auth/lazy-with-retry.js.map +1 -1
  85. package/dist/auth/passkey.cjs.map +1 -1
  86. package/dist/auth/passkey.js.map +1 -1
  87. package/dist/auth/refresh-queue.cjs.map +1 -1
  88. package/dist/auth/refresh-queue.js.map +1 -1
  89. package/dist/auth/use-passkey.cjs +1 -1
  90. package/dist/auth/use-passkey.cjs.map +1 -1
  91. package/dist/auth/use-passkey.js +1 -1
  92. package/dist/auth/use-passkey.js.map +1 -1
  93. package/dist/br/BrazilMap.cjs.map +1 -1
  94. package/dist/br/BrazilMap.js.map +1 -1
  95. package/dist/br/BrazilMap.module.cjs.map +1 -1
  96. package/dist/br/BrazilMap.module.js.map +1 -1
  97. package/dist/br/BrazilStateCitySelect.cjs.map +1 -1
  98. package/dist/br/BrazilStateCitySelect.js.map +1 -1
  99. package/dist/br/BrazilStateMap.cjs.map +1 -1
  100. package/dist/br/BrazilStateMap.js.map +1 -1
  101. package/dist/br/MapLegend.cjs.map +1 -1
  102. package/dist/br/MapLegend.js.map +1 -1
  103. package/dist/br/MapLegend.module.cjs.map +1 -1
  104. package/dist/br/MapLegend.module.js.map +1 -1
  105. package/dist/br/MapMarkers.cjs.map +1 -1
  106. package/dist/br/MapMarkers.js.map +1 -1
  107. package/dist/br/MapTooltip.cjs.map +1 -1
  108. package/dist/br/MapTooltip.js.map +1 -1
  109. package/dist/br/MunicipalitySearch.cjs +1 -1
  110. package/dist/br/MunicipalitySearch.cjs.map +1 -1
  111. package/dist/br/MunicipalitySearch.js +2 -5
  112. package/dist/br/MunicipalitySearch.js.map +1 -1
  113. package/dist/br/MunicipalitySearch.module.cjs.map +1 -1
  114. package/dist/br/MunicipalitySearch.module.js.map +1 -1
  115. package/dist/br/PixQRCode.cjs.map +1 -1
  116. package/dist/br/PixQRCode.js.map +1 -1
  117. package/dist/br/PixQRCode.module.cjs.map +1 -1
  118. package/dist/br/PixQRCode.module.js.map +1 -1
  119. package/dist/br/boleto.cjs.map +1 -1
  120. package/dist/br/boleto.js.map +1 -1
  121. package/dist/br/br-geo.cjs.map +1 -1
  122. package/dist/br/br-geo.js.map +1 -1
  123. package/dist/br/data/br-centroids.cjs.map +1 -1
  124. package/dist/br/data/br-centroids.js.map +1 -1
  125. package/dist/br/data/br-locations.cjs.map +1 -1
  126. package/dist/br/data/br-locations.js.map +1 -1
  127. package/dist/br/data/br-uf-geo.cjs.map +1 -1
  128. package/dist/br/data/br-uf-geo.js.map +1 -1
  129. package/dist/br/data/mun/AC.cjs.map +1 -1
  130. package/dist/br/data/mun/AC.js.map +1 -1
  131. package/dist/br/data/mun/AL.cjs.map +1 -1
  132. package/dist/br/data/mun/AL.js.map +1 -1
  133. package/dist/br/data/mun/AM.cjs.map +1 -1
  134. package/dist/br/data/mun/AM.js.map +1 -1
  135. package/dist/br/data/mun/AP.cjs.map +1 -1
  136. package/dist/br/data/mun/AP.js.map +1 -1
  137. package/dist/br/data/mun/BA.cjs.map +1 -1
  138. package/dist/br/data/mun/BA.js.map +1 -1
  139. package/dist/br/data/mun/CE.cjs.map +1 -1
  140. package/dist/br/data/mun/CE.js.map +1 -1
  141. package/dist/br/data/mun/DF.cjs.map +1 -1
  142. package/dist/br/data/mun/DF.js.map +1 -1
  143. package/dist/br/data/mun/ES.cjs.map +1 -1
  144. package/dist/br/data/mun/ES.js.map +1 -1
  145. package/dist/br/data/mun/GO.cjs.map +1 -1
  146. package/dist/br/data/mun/GO.js.map +1 -1
  147. package/dist/br/data/mun/MA.cjs.map +1 -1
  148. package/dist/br/data/mun/MA.js.map +1 -1
  149. package/dist/br/data/mun/MG.cjs.map +1 -1
  150. package/dist/br/data/mun/MG.js.map +1 -1
  151. package/dist/br/data/mun/MS.cjs.map +1 -1
  152. package/dist/br/data/mun/MS.js.map +1 -1
  153. package/dist/br/data/mun/MT.cjs.map +1 -1
  154. package/dist/br/data/mun/MT.js.map +1 -1
  155. package/dist/br/data/mun/PA.cjs.map +1 -1
  156. package/dist/br/data/mun/PA.js.map +1 -1
  157. package/dist/br/data/mun/PB.cjs.map +1 -1
  158. package/dist/br/data/mun/PB.js.map +1 -1
  159. package/dist/br/data/mun/PE.cjs.map +1 -1
  160. package/dist/br/data/mun/PE.js.map +1 -1
  161. package/dist/br/data/mun/PI.cjs.map +1 -1
  162. package/dist/br/data/mun/PI.js.map +1 -1
  163. package/dist/br/data/mun/PR.cjs.map +1 -1
  164. package/dist/br/data/mun/PR.js.map +1 -1
  165. package/dist/br/data/mun/RJ.cjs.map +1 -1
  166. package/dist/br/data/mun/RJ.js.map +1 -1
  167. package/dist/br/data/mun/RN.cjs.map +1 -1
  168. package/dist/br/data/mun/RN.js.map +1 -1
  169. package/dist/br/data/mun/RO.cjs.map +1 -1
  170. package/dist/br/data/mun/RO.js.map +1 -1
  171. package/dist/br/data/mun/RR.cjs.map +1 -1
  172. package/dist/br/data/mun/RR.js.map +1 -1
  173. package/dist/br/data/mun/RS.cjs.map +1 -1
  174. package/dist/br/data/mun/RS.js.map +1 -1
  175. package/dist/br/data/mun/SC.cjs.map +1 -1
  176. package/dist/br/data/mun/SC.js.map +1 -1
  177. package/dist/br/data/mun/SE.cjs.map +1 -1
  178. package/dist/br/data/mun/SE.js.map +1 -1
  179. package/dist/br/data/mun/SP.cjs.map +1 -1
  180. package/dist/br/data/mun/SP.js.map +1 -1
  181. package/dist/br/data/mun/TO.cjs.map +1 -1
  182. package/dist/br/data/mun/TO.js.map +1 -1
  183. package/dist/br/geocode.cjs.map +1 -1
  184. package/dist/br/geocode.js.map +1 -1
  185. package/dist/br/holidays.cjs.map +1 -1
  186. package/dist/br/holidays.js.map +1 -1
  187. package/dist/br/locations.cjs.map +1 -1
  188. package/dist/br/locations.js.map +1 -1
  189. package/dist/br/nfe.cjs.map +1 -1
  190. package/dist/br/nfe.js.map +1 -1
  191. package/dist/br/pix.cjs +1 -1
  192. package/dist/br/pix.cjs.map +1 -1
  193. package/dist/br/pix.js +108 -71
  194. package/dist/br/pix.js.map +1 -1
  195. package/dist/br/regions.cjs.map +1 -1
  196. package/dist/br/regions.js.map +1 -1
  197. package/dist/br/scales.cjs.map +1 -1
  198. package/dist/br/scales.js.map +1 -1
  199. package/dist/br/state-geo.cjs.map +1 -1
  200. package/dist/br/state-geo.js.map +1 -1
  201. package/dist/br/svg-utils.cjs.map +1 -1
  202. package/dist/br/svg-utils.js.map +1 -1
  203. package/dist/br/use-map-hover.cjs.map +1 -1
  204. package/dist/br/use-map-hover.js.map +1 -1
  205. package/dist/br/use-map-zoom.cjs.map +1 -1
  206. package/dist/br/use-map-zoom.js.map +1 -1
  207. package/dist/br/whatsapp.cjs.map +1 -1
  208. package/dist/br/whatsapp.js.map +1 -1
  209. package/dist/br.cjs.map +1 -1
  210. package/dist/br.d.ts +16 -5
  211. package/dist/br.js.map +1 -1
  212. package/dist/capture/barcode.cjs.map +1 -1
  213. package/dist/capture/barcode.js.map +1 -1
  214. package/dist/capture/media-recorder.cjs.map +1 -1
  215. package/dist/capture/media-recorder.js.map +1 -1
  216. package/dist/capture/use-barcode-scanner.cjs.map +1 -1
  217. package/dist/capture/use-barcode-scanner.js.map +1 -1
  218. package/dist/capture/use-screen-capture.cjs +1 -1
  219. package/dist/capture/use-screen-capture.cjs.map +1 -1
  220. package/dist/capture/use-screen-capture.js +1 -7
  221. package/dist/capture/use-screen-capture.js.map +1 -1
  222. package/dist/capture/use-speech-recognition.cjs +1 -1
  223. package/dist/capture/use-speech-recognition.cjs.map +1 -1
  224. package/dist/capture/use-speech-recognition.js +35 -36
  225. package/dist/capture/use-speech-recognition.js.map +1 -1
  226. package/dist/capture/use-torch.cjs.map +1 -1
  227. package/dist/capture/use-torch.js.map +1 -1
  228. package/dist/capture/use-video-recorder.cjs.map +1 -1
  229. package/dist/capture/use-video-recorder.js.map +1 -1
  230. package/dist/capture/video-recorder.cjs.map +1 -1
  231. package/dist/capture/video-recorder.js.map +1 -1
  232. package/dist/charts/AreaChart.cjs.map +1 -1
  233. package/dist/charts/AreaChart.js.map +1 -1
  234. package/dist/charts/BarChart.cjs.map +1 -1
  235. package/dist/charts/BarChart.js.map +1 -1
  236. package/dist/charts/LineChart.cjs.map +1 -1
  237. package/dist/charts/LineChart.js.map +1 -1
  238. package/dist/charts/PieChart.cjs.map +1 -1
  239. package/dist/charts/PieChart.js.map +1 -1
  240. package/dist/charts/RadarChart.cjs.map +1 -1
  241. package/dist/charts/RadarChart.js.map +1 -1
  242. package/dist/charts/palette.cjs.map +1 -1
  243. package/dist/charts/palette.js.map +1 -1
  244. package/dist/charts/scales.cjs.map +1 -1
  245. package/dist/charts/scales.js.map +1 -1
  246. package/dist/charts/types.cjs.map +1 -1
  247. package/dist/charts/types.js.map +1 -1
  248. package/dist/charts/use-chart-colors.cjs.map +1 -1
  249. package/dist/charts/use-chart-colors.js.map +1 -1
  250. package/dist/components/AIChat/AIChat.cjs +1 -1
  251. package/dist/components/AIChat/AIChat.cjs.map +1 -1
  252. package/dist/components/AIChat/AIChat.js +1 -5
  253. package/dist/components/AIChat/AIChat.js.map +1 -1
  254. package/dist/components/AIChat/AIChat.module.cjs.map +1 -1
  255. package/dist/components/AIChat/AIChat.module.js.map +1 -1
  256. package/dist/components/AIChat/AIChatComposer.cjs +1 -1
  257. package/dist/components/AIChat/AIChatComposer.cjs.map +1 -1
  258. package/dist/components/AIChat/AIChatComposer.js +1 -7
  259. package/dist/components/AIChat/AIChatComposer.js.map +1 -1
  260. package/dist/components/AIChat/AIChatTurn.cjs.map +1 -1
  261. package/dist/components/AIChat/AIChatTurn.js.map +1 -1
  262. package/dist/components/AIChat/ai-chat-turns.cjs.map +1 -1
  263. package/dist/components/AIChat/ai-chat-turns.js.map +1 -1
  264. package/dist/components/Accordion/Accordion.cjs.map +1 -1
  265. package/dist/components/Accordion/Accordion.js.map +1 -1
  266. package/dist/components/Accordion/Accordion.module.cjs.map +1 -1
  267. package/dist/components/Accordion/Accordion.module.js.map +1 -1
  268. package/dist/components/Alert/Alert.cjs.map +1 -1
  269. package/dist/components/Alert/Alert.js.map +1 -1
  270. package/dist/components/Alert/Alert.module.cjs.map +1 -1
  271. package/dist/components/Alert/Alert.module.js.map +1 -1
  272. package/dist/components/AppBar/AppBar.cjs.map +1 -1
  273. package/dist/components/AppBar/AppBar.js.map +1 -1
  274. package/dist/components/AppBar/AppBar.module.cjs.map +1 -1
  275. package/dist/components/AppBar/AppBar.module.js.map +1 -1
  276. package/dist/components/AppBar/use-sticky-body-warning.cjs +1 -1
  277. package/dist/components/AppBar/use-sticky-body-warning.cjs.map +1 -1
  278. package/dist/components/AppBar/use-sticky-body-warning.js +1 -1
  279. package/dist/components/AppBar/use-sticky-body-warning.js.map +1 -1
  280. package/dist/components/AppShell/AppShell.cjs.map +1 -1
  281. package/dist/components/AppShell/AppShell.js.map +1 -1
  282. package/dist/components/AppShell/AppShell.module.cjs.map +1 -1
  283. package/dist/components/AppShell/AppShell.module.js.map +1 -1
  284. package/dist/components/AspectRatio/AspectRatio.cjs.map +1 -1
  285. package/dist/components/AspectRatio/AspectRatio.js.map +1 -1
  286. package/dist/components/AspectRatio/AspectRatio.module.cjs.map +1 -1
  287. package/dist/components/AspectRatio/AspectRatio.module.js.map +1 -1
  288. package/dist/components/AudioPlayer/AudioPlayer.cjs +1 -1
  289. package/dist/components/AudioPlayer/AudioPlayer.cjs.map +1 -1
  290. package/dist/components/AudioPlayer/AudioPlayer.js +1 -7
  291. package/dist/components/AudioPlayer/AudioPlayer.js.map +1 -1
  292. package/dist/components/AudioPlayer/AudioPlayer.module.cjs.map +1 -1
  293. package/dist/components/AudioPlayer/AudioPlayer.module.js.map +1 -1
  294. package/dist/components/AudioRecorder/AudioRecorder.cjs +1 -1
  295. package/dist/components/AudioRecorder/AudioRecorder.cjs.map +1 -1
  296. package/dist/components/AudioRecorder/AudioRecorder.js +16 -21
  297. package/dist/components/AudioRecorder/AudioRecorder.js.map +1 -1
  298. package/dist/components/AudioRecorder/AudioRecorder.module.cjs.map +1 -1
  299. package/dist/components/AudioRecorder/AudioRecorder.module.js.map +1 -1
  300. package/dist/components/Avatar/Avatar.cjs.map +1 -1
  301. package/dist/components/Avatar/Avatar.js.map +1 -1
  302. package/dist/components/Avatar/Avatar.module.cjs.map +1 -1
  303. package/dist/components/Avatar/Avatar.module.js.map +1 -1
  304. package/dist/components/AvatarGroup/AvatarGroup.cjs.map +1 -1
  305. package/dist/components/AvatarGroup/AvatarGroup.js.map +1 -1
  306. package/dist/components/AvatarGroup/AvatarGroup.module.cjs.map +1 -1
  307. package/dist/components/AvatarGroup/AvatarGroup.module.js.map +1 -1
  308. package/dist/components/Badge/Badge.cjs.map +1 -1
  309. package/dist/components/Badge/Badge.js.map +1 -1
  310. package/dist/components/Badge/Badge.module.cjs.map +1 -1
  311. package/dist/components/Badge/Badge.module.js.map +1 -1
  312. package/dist/components/Banner/Banner.cjs.map +1 -1
  313. package/dist/components/Banner/Banner.js.map +1 -1
  314. package/dist/components/Banner/Banner.module.cjs.map +1 -1
  315. package/dist/components/Banner/Banner.module.js.map +1 -1
  316. package/dist/components/BarList/BarList.cjs.map +1 -1
  317. package/dist/components/BarList/BarList.js.map +1 -1
  318. package/dist/components/BarList/BarList.module.cjs.map +1 -1
  319. package/dist/components/BarList/BarList.module.js.map +1 -1
  320. package/dist/components/BarList/bar-list-model.cjs.map +1 -1
  321. package/dist/components/BarList/bar-list-model.js.map +1 -1
  322. package/dist/components/BarcodeScanner/BarcodeScanner.cjs.map +1 -1
  323. package/dist/components/BarcodeScanner/BarcodeScanner.js.map +1 -1
  324. package/dist/components/BarcodeScanner/BarcodeScanner.module.cjs.map +1 -1
  325. package/dist/components/BarcodeScanner/BarcodeScanner.module.js.map +1 -1
  326. package/dist/components/BottomNavigation/BottomNavigation.cjs.map +1 -1
  327. package/dist/components/BottomNavigation/BottomNavigation.js.map +1 -1
  328. package/dist/components/BottomNavigation/BottomNavigation.module.cjs.map +1 -1
  329. package/dist/components/BottomNavigation/BottomNavigation.module.js.map +1 -1
  330. package/dist/components/BottomSheet/BottomSheet.cjs.map +1 -1
  331. package/dist/components/BottomSheet/BottomSheet.js.map +1 -1
  332. package/dist/components/BottomSheet/BottomSheet.module.cjs.map +1 -1
  333. package/dist/components/BottomSheet/BottomSheet.module.js.map +1 -1
  334. package/dist/components/Breadcrumbs/Breadcrumbs.cjs.map +1 -1
  335. package/dist/components/Breadcrumbs/Breadcrumbs.js.map +1 -1
  336. package/dist/components/Breadcrumbs/Breadcrumbs.module.cjs.map +1 -1
  337. package/dist/components/Breadcrumbs/Breadcrumbs.module.js.map +1 -1
  338. package/dist/components/Button/Button.cjs.map +1 -1
  339. package/dist/components/Button/Button.js.map +1 -1
  340. package/dist/components/Button/Button.module.cjs.map +1 -1
  341. package/dist/components/Button/Button.module.js.map +1 -1
  342. package/dist/components/Button/ButtonContent.cjs.map +1 -1
  343. package/dist/components/Button/ButtonContent.js.map +1 -1
  344. package/dist/components/Button/ButtonSlot.cjs.map +1 -1
  345. package/dist/components/Button/ButtonSlot.js.map +1 -1
  346. package/dist/components/Button/button-class.cjs.map +1 -1
  347. package/dist/components/Button/button-class.js.map +1 -1
  348. package/dist/components/Button/link-rel.cjs.map +1 -1
  349. package/dist/components/Button/link-rel.js.map +1 -1
  350. package/dist/components/Button/slot.cjs.map +1 -1
  351. package/dist/components/Button/slot.js.map +1 -1
  352. package/dist/components/Calendar/Calendar.cjs.map +1 -1
  353. package/dist/components/Calendar/Calendar.js.map +1 -1
  354. package/dist/components/Calendar/Calendar.module.cjs.map +1 -1
  355. package/dist/components/Calendar/Calendar.module.js.map +1 -1
  356. package/dist/components/Card/Card.cjs.map +1 -1
  357. package/dist/components/Card/Card.js.map +1 -1
  358. package/dist/components/Card/Card.module.cjs.map +1 -1
  359. package/dist/components/Card/Card.module.js.map +1 -1
  360. package/dist/components/Carousel/Carousel.cjs.map +1 -1
  361. package/dist/components/Carousel/Carousel.js.map +1 -1
  362. package/dist/components/Carousel/Carousel.module.cjs.map +1 -1
  363. package/dist/components/Carousel/Carousel.module.js.map +1 -1
  364. package/dist/components/Center/Center.cjs.map +1 -1
  365. package/dist/components/Center/Center.js.map +1 -1
  366. package/dist/components/Center/Center.module.cjs.map +1 -1
  367. package/dist/components/Center/Center.module.js.map +1 -1
  368. package/dist/components/Chat/Chat.cjs.map +1 -1
  369. package/dist/components/Chat/Chat.js.map +1 -1
  370. package/dist/components/Chat/Chat.module.cjs.map +1 -1
  371. package/dist/components/Chat/Chat.module.js.map +1 -1
  372. package/dist/components/Chat/ChatActionsMenu.cjs.map +1 -1
  373. package/dist/components/Chat/ChatActionsMenu.js.map +1 -1
  374. package/dist/components/Chat/ChatAttachments.cjs.map +1 -1
  375. package/dist/components/Chat/ChatAttachments.js.map +1 -1
  376. package/dist/components/Chat/ChatBubble.cjs.map +1 -1
  377. package/dist/components/Chat/ChatBubble.js.map +1 -1
  378. package/dist/components/Chat/ChatComposer.cjs.map +1 -1
  379. package/dist/components/Chat/ChatComposer.js.map +1 -1
  380. package/dist/components/Chat/chat-groups.cjs +1 -1
  381. package/dist/components/Chat/chat-groups.cjs.map +1 -1
  382. package/dist/components/Chat/chat-groups.js +2 -6
  383. package/dist/components/Chat/chat-groups.js.map +1 -1
  384. package/dist/components/Chat/chat-receipt.cjs.map +1 -1
  385. package/dist/components/Chat/chat-receipt.js.map +1 -1
  386. package/dist/components/Checkbox/Checkbox.cjs.map +1 -1
  387. package/dist/components/Checkbox/Checkbox.js.map +1 -1
  388. package/dist/components/Checkbox/Checkbox.module.cjs.map +1 -1
  389. package/dist/components/Checkbox/Checkbox.module.js.map +1 -1
  390. package/dist/components/ChipInput/ChipInput.cjs +1 -1
  391. package/dist/components/ChipInput/ChipInput.cjs.map +1 -1
  392. package/dist/components/ChipInput/ChipInput.js +2 -12
  393. package/dist/components/ChipInput/ChipInput.js.map +1 -1
  394. package/dist/components/ChipInput/ChipInput.module.cjs.map +1 -1
  395. package/dist/components/ChipInput/ChipInput.module.js.map +1 -1
  396. package/dist/components/ClickOutside/ClickOutside.cjs.map +1 -1
  397. package/dist/components/ClickOutside/ClickOutside.js.map +1 -1
  398. package/dist/components/CodeBlock/CodeBlock.cjs +1 -1
  399. package/dist/components/CodeBlock/CodeBlock.cjs.map +1 -1
  400. package/dist/components/CodeBlock/CodeBlock.js +1 -1
  401. package/dist/components/CodeBlock/CodeBlock.js.map +1 -1
  402. package/dist/components/CodeBlock/CodeBlock.module.cjs.map +1 -1
  403. package/dist/components/CodeBlock/CodeBlock.module.js.map +1 -1
  404. package/dist/components/CodeBlock/tokenize.cjs +1 -1
  405. package/dist/components/CodeBlock/tokenize.cjs.map +1 -1
  406. package/dist/components/CodeBlock/tokenize.js +54 -25
  407. package/dist/components/CodeBlock/tokenize.js.map +1 -1
  408. package/dist/components/Collapsible/Collapsible.cjs.map +1 -1
  409. package/dist/components/Collapsible/Collapsible.js.map +1 -1
  410. package/dist/components/Collapsible/Collapsible.module.cjs.map +1 -1
  411. package/dist/components/Collapsible/Collapsible.module.js.map +1 -1
  412. package/dist/components/Combobox/Combobox.cjs.map +1 -1
  413. package/dist/components/Combobox/Combobox.js.map +1 -1
  414. package/dist/components/Combobox/Combobox.module.cjs.map +1 -1
  415. package/dist/components/Combobox/Combobox.module.js.map +1 -1
  416. package/dist/components/Combobox/use-listbox-dismiss.cjs.map +1 -1
  417. package/dist/components/Combobox/use-listbox-dismiss.js.map +1 -1
  418. package/dist/components/Command/Command.cjs +1 -1
  419. package/dist/components/Command/Command.cjs.map +1 -1
  420. package/dist/components/Command/Command.js +4 -11
  421. package/dist/components/Command/Command.js.map +1 -1
  422. package/dist/components/Command/Command.module.cjs.map +1 -1
  423. package/dist/components/Command/Command.module.js.map +1 -1
  424. package/dist/components/ConditionalWrapper/ConditionalWrapper.cjs.map +1 -1
  425. package/dist/components/ConditionalWrapper/ConditionalWrapper.js.map +1 -1
  426. package/dist/components/ConfirmDialog/ConfirmDialog.cjs.map +1 -1
  427. package/dist/components/ConfirmDialog/ConfirmDialog.js.map +1 -1
  428. package/dist/components/ContextMenu/ContextMenu.cjs +1 -1
  429. package/dist/components/ContextMenu/ContextMenu.cjs.map +1 -1
  430. package/dist/components/ContextMenu/ContextMenu.js +1 -1
  431. package/dist/components/ContextMenu/ContextMenu.js.map +1 -1
  432. package/dist/components/ContextMenu/ContextMenu.module.cjs.map +1 -1
  433. package/dist/components/ContextMenu/ContextMenu.module.js.map +1 -1
  434. package/dist/components/CopyButton/CopyButton.cjs.map +1 -1
  435. package/dist/components/CopyButton/CopyButton.js.map +1 -1
  436. package/dist/components/CopyButton/CopyButton.module.cjs.map +1 -1
  437. package/dist/components/CopyButton/CopyButton.module.js.map +1 -1
  438. package/dist/components/DataList/DataList.cjs.map +1 -1
  439. package/dist/components/DataList/DataList.js.map +1 -1
  440. package/dist/components/DataList/DataList.module.cjs.map +1 -1
  441. package/dist/components/DataList/DataList.module.js.map +1 -1
  442. package/dist/components/DataTable/DataTable.cjs +1 -1
  443. package/dist/components/DataTable/DataTable.cjs.map +1 -1
  444. package/dist/components/DataTable/DataTable.js +6 -14
  445. package/dist/components/DataTable/DataTable.js.map +1 -1
  446. package/dist/components/DataTable/DataTable.module.cjs.map +1 -1
  447. package/dist/components/DataTable/DataTable.module.js.map +1 -1
  448. package/dist/components/DataTable/EditableCell.cjs +1 -1
  449. package/dist/components/DataTable/EditableCell.cjs.map +1 -1
  450. package/dist/components/DataTable/EditableCell.js +1 -9
  451. package/dist/components/DataTable/EditableCell.js.map +1 -1
  452. package/dist/components/DataTable/LoadingRows.cjs.map +1 -1
  453. package/dist/components/DataTable/LoadingRows.js.map +1 -1
  454. package/dist/components/DataTable/edit-labels.cjs.map +1 -1
  455. package/dist/components/DataTable/edit-labels.js.map +1 -1
  456. package/dist/components/DataTable/use-dev-warnings.cjs.map +1 -1
  457. package/dist/components/DataTable/use-dev-warnings.js.map +1 -1
  458. package/dist/components/DatePicker/DatePicker.cjs.map +1 -1
  459. package/dist/components/DatePicker/DatePicker.js.map +1 -1
  460. package/dist/components/DateRangePicker/DateRangePicker.cjs.map +1 -1
  461. package/dist/components/DateRangePicker/DateRangePicker.js.map +1 -1
  462. package/dist/components/DateRangePicker/DateRangePicker.module.cjs.map +1 -1
  463. package/dist/components/DateRangePicker/DateRangePicker.module.js.map +1 -1
  464. package/dist/components/DescriptionList/DescriptionList.cjs.map +1 -1
  465. package/dist/components/DescriptionList/DescriptionList.js.map +1 -1
  466. package/dist/components/DescriptionList/DescriptionList.module.cjs.map +1 -1
  467. package/dist/components/DescriptionList/DescriptionList.module.js.map +1 -1
  468. package/dist/components/Divider/Divider.cjs.map +1 -1
  469. package/dist/components/Divider/Divider.js.map +1 -1
  470. package/dist/components/Divider/Divider.module.cjs.map +1 -1
  471. package/dist/components/Divider/Divider.module.js.map +1 -1
  472. package/dist/components/Drawer/Drawer.cjs.map +1 -1
  473. package/dist/components/Drawer/Drawer.js.map +1 -1
  474. package/dist/components/Drawer/Drawer.module.cjs.map +1 -1
  475. package/dist/components/Drawer/Drawer.module.js.map +1 -1
  476. package/dist/components/DropdownMenu/DropdownMenu.cjs +1 -1
  477. package/dist/components/DropdownMenu/DropdownMenu.cjs.map +1 -1
  478. package/dist/components/DropdownMenu/DropdownMenu.js +2 -14
  479. package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -1
  480. package/dist/components/DropdownMenu/DropdownMenu.module.cjs.map +1 -1
  481. package/dist/components/DropdownMenu/DropdownMenu.module.js.map +1 -1
  482. package/dist/components/Dropzone/Dropzone.cjs.map +1 -1
  483. package/dist/components/Dropzone/Dropzone.js.map +1 -1
  484. package/dist/components/Dropzone/Dropzone.module.cjs.map +1 -1
  485. package/dist/components/Dropzone/Dropzone.module.js.map +1 -1
  486. package/dist/components/EmptyState/EmptyState.cjs.map +1 -1
  487. package/dist/components/EmptyState/EmptyState.js.map +1 -1
  488. package/dist/components/EmptyState/EmptyState.module.cjs.map +1 -1
  489. package/dist/components/EmptyState/EmptyState.module.js.map +1 -1
  490. package/dist/components/ErrorState/ErrorState.cjs.map +1 -1
  491. package/dist/components/ErrorState/ErrorState.js.map +1 -1
  492. package/dist/components/ErrorState/ErrorState.module.cjs.map +1 -1
  493. package/dist/components/ErrorState/ErrorState.module.js.map +1 -1
  494. package/dist/components/ErrorText/ErrorText.cjs.map +1 -1
  495. package/dist/components/ErrorText/ErrorText.js.map +1 -1
  496. package/dist/components/ErrorText/ErrorText.module.cjs.map +1 -1
  497. package/dist/components/ErrorText/ErrorText.module.js.map +1 -1
  498. package/dist/components/FileUpload/FileUpload.cjs +1 -1
  499. package/dist/components/FileUpload/FileUpload.cjs.map +1 -1
  500. package/dist/components/FileUpload/FileUpload.js +7 -17
  501. package/dist/components/FileUpload/FileUpload.js.map +1 -1
  502. package/dist/components/FileUpload/FileUpload.module.cjs.map +1 -1
  503. package/dist/components/FileUpload/FileUpload.module.js.map +1 -1
  504. package/dist/components/FilterBar/FilterBar.cjs.map +1 -1
  505. package/dist/components/FilterBar/FilterBar.js.map +1 -1
  506. package/dist/components/FilterBar/FilterBar.module.cjs.map +1 -1
  507. package/dist/components/FilterBar/FilterBar.module.js.map +1 -1
  508. package/dist/components/FilterBar/filter-apply.cjs.map +1 -1
  509. package/dist/components/FilterBar/filter-apply.js.map +1 -1
  510. package/dist/components/FilterBar/filter-model.cjs.map +1 -1
  511. package/dist/components/FilterBar/filter-model.js.map +1 -1
  512. package/dist/components/FilterBar/filter-query.cjs +1 -1
  513. package/dist/components/FilterBar/filter-query.cjs.map +1 -1
  514. package/dist/components/FilterBar/filter-query.js +2 -5
  515. package/dist/components/FilterBar/filter-query.js.map +1 -1
  516. package/dist/components/FilterPanel/FilterPanel.cjs.map +1 -1
  517. package/dist/components/FilterPanel/FilterPanel.js.map +1 -1
  518. package/dist/components/FilterPanel/FilterPanel.module.cjs.map +1 -1
  519. package/dist/components/FilterPanel/FilterPanel.module.js.map +1 -1
  520. package/dist/components/FloatingActionButton/FloatingActionButton.cjs.map +1 -1
  521. package/dist/components/FloatingActionButton/FloatingActionButton.js.map +1 -1
  522. package/dist/components/FloatingActionButton/FloatingActionButton.module.cjs.map +1 -1
  523. package/dist/components/FloatingActionButton/FloatingActionButton.module.js.map +1 -1
  524. package/dist/components/For/For.cjs.map +1 -1
  525. package/dist/components/For/For.js.map +1 -1
  526. package/dist/components/Form/Form.cjs.map +1 -1
  527. package/dist/components/Form/Form.js.map +1 -1
  528. package/dist/components/Form/Form.module.cjs.map +1 -1
  529. package/dist/components/Form/Form.module.js.map +1 -1
  530. package/dist/components/HoverCard/HoverCard.cjs.map +1 -1
  531. package/dist/components/HoverCard/HoverCard.js.map +1 -1
  532. package/dist/components/HoverCard/HoverCard.module.cjs.map +1 -1
  533. package/dist/components/HoverCard/HoverCard.module.js.map +1 -1
  534. package/dist/components/Image/Image.cjs.map +1 -1
  535. package/dist/components/Image/Image.js.map +1 -1
  536. package/dist/components/Image/Image.module.cjs.map +1 -1
  537. package/dist/components/Image/Image.module.js.map +1 -1
  538. package/dist/components/ImageCropper/ImageCropper.cjs +1 -1
  539. package/dist/components/ImageCropper/ImageCropper.cjs.map +1 -1
  540. package/dist/components/ImageCropper/ImageCropper.js +4 -8
  541. package/dist/components/ImageCropper/ImageCropper.js.map +1 -1
  542. package/dist/components/ImageCropper/ImageCropper.module.cjs.map +1 -1
  543. package/dist/components/ImageCropper/ImageCropper.module.js.map +1 -1
  544. package/dist/components/ImageCropper/crop-geometry.cjs.map +1 -1
  545. package/dist/components/ImageCropper/crop-geometry.js.map +1 -1
  546. package/dist/components/Input/Input.cjs.map +1 -1
  547. package/dist/components/Input/Input.js.map +1 -1
  548. package/dist/components/Input/Input.module.cjs.map +1 -1
  549. package/dist/components/Input/Input.module.js.map +1 -1
  550. package/dist/components/InstallBanner/InstallBanner.cjs.map +1 -1
  551. package/dist/components/InstallBanner/InstallBanner.js.map +1 -1
  552. package/dist/components/InstallBanner/InstallBanner.module.cjs.map +1 -1
  553. package/dist/components/InstallBanner/InstallBanner.module.js.map +1 -1
  554. package/dist/components/InstallButton/InstallButton.cjs.map +1 -1
  555. package/dist/components/InstallButton/InstallButton.js.map +1 -1
  556. package/dist/components/InstallButton/InstallButton.module.cjs.map +1 -1
  557. package/dist/components/InstallButton/InstallButton.module.js.map +1 -1
  558. package/dist/components/InstallButton/install-hints.cjs.map +1 -1
  559. package/dist/components/InstallButton/install-hints.js.map +1 -1
  560. package/dist/components/Kanban/Kanban.cjs.map +1 -1
  561. package/dist/components/Kanban/Kanban.js.map +1 -1
  562. package/dist/components/Kanban/Kanban.module.cjs.map +1 -1
  563. package/dist/components/Kanban/Kanban.module.js.map +1 -1
  564. package/dist/components/Kbd/Kbd.cjs.map +1 -1
  565. package/dist/components/Kbd/Kbd.js.map +1 -1
  566. package/dist/components/Kbd/Kbd.module.cjs.map +1 -1
  567. package/dist/components/Kbd/Kbd.module.js.map +1 -1
  568. package/dist/components/Label/Label.cjs.map +1 -1
  569. package/dist/components/Label/Label.js.map +1 -1
  570. package/dist/components/Label/Label.module.cjs.map +1 -1
  571. package/dist/components/Label/Label.module.js.map +1 -1
  572. package/dist/components/Layout/Layout.cjs.map +1 -1
  573. package/dist/components/Layout/Layout.js.map +1 -1
  574. package/dist/components/Layout/Layout.module.cjs.map +1 -1
  575. package/dist/components/Layout/Layout.module.js.map +1 -1
  576. package/dist/components/Lightbox/Lightbox.cjs +1 -1
  577. package/dist/components/Lightbox/Lightbox.cjs.map +1 -1
  578. package/dist/components/Lightbox/Lightbox.js +1 -1
  579. package/dist/components/Lightbox/Lightbox.js.map +1 -1
  580. package/dist/components/Lightbox/Lightbox.module.cjs.map +1 -1
  581. package/dist/components/Lightbox/Lightbox.module.js.map +1 -1
  582. package/dist/components/ListTile/ListTile.cjs.map +1 -1
  583. package/dist/components/ListTile/ListTile.js.map +1 -1
  584. package/dist/components/ListTile/ListTile.module.cjs.map +1 -1
  585. package/dist/components/ListTile/ListTile.module.js.map +1 -1
  586. package/dist/components/Markdown/Markdown.cjs.map +1 -1
  587. package/dist/components/Markdown/Markdown.js.map +1 -1
  588. package/dist/components/Markdown/Markdown.module.cjs.map +1 -1
  589. package/dist/components/Markdown/Markdown.module.js.map +1 -1
  590. package/dist/components/Markdown/markdown-parse.cjs +6 -6
  591. package/dist/components/Markdown/markdown-parse.cjs.map +1 -1
  592. package/dist/components/Markdown/markdown-parse.js +94 -96
  593. package/dist/components/Markdown/markdown-parse.js.map +1 -1
  594. package/dist/components/Masonry/Masonry.cjs.map +1 -1
  595. package/dist/components/Masonry/Masonry.js.map +1 -1
  596. package/dist/components/Masonry/Masonry.module.cjs.map +1 -1
  597. package/dist/components/Masonry/Masonry.module.js.map +1 -1
  598. package/dist/components/Masonry/masonry-layout.cjs.map +1 -1
  599. package/dist/components/Masonry/masonry-layout.js.map +1 -1
  600. package/dist/components/Menubar/Menubar.cjs.map +1 -1
  601. package/dist/components/Menubar/Menubar.js.map +1 -1
  602. package/dist/components/Menubar/Menubar.module.cjs.map +1 -1
  603. package/dist/components/Menubar/Menubar.module.js.map +1 -1
  604. package/dist/components/Modal/Modal.cjs.map +1 -1
  605. package/dist/components/Modal/Modal.js.map +1 -1
  606. package/dist/components/Modal/Modal.module.cjs.map +1 -1
  607. package/dist/components/Modal/Modal.module.js.map +1 -1
  608. package/dist/components/ModalsManager/ModalsManager.cjs.map +1 -1
  609. package/dist/components/ModalsManager/ModalsManager.js.map +1 -1
  610. package/dist/components/ModalsManager/ModalsManager.module.cjs.map +1 -1
  611. package/dist/components/ModalsManager/ModalsManager.module.js.map +1 -1
  612. package/dist/components/Money/Money.cjs.map +1 -1
  613. package/dist/components/Money/Money.js.map +1 -1
  614. package/dist/components/MultiSelect/MultiSelect.cjs.map +1 -1
  615. package/dist/components/MultiSelect/MultiSelect.js.map +1 -1
  616. package/dist/components/MultiSelect/MultiSelect.module.cjs.map +1 -1
  617. package/dist/components/MultiSelect/MultiSelect.module.js.map +1 -1
  618. package/dist/components/NProgress/NProgress.cjs.map +1 -1
  619. package/dist/components/NProgress/NProgress.js.map +1 -1
  620. package/dist/components/NProgress/NProgress.module.cjs.map +1 -1
  621. package/dist/components/NProgress/NProgress.module.js.map +1 -1
  622. package/dist/components/Navbar/Navbar.cjs.map +1 -1
  623. package/dist/components/Navbar/Navbar.js.map +1 -1
  624. package/dist/components/Navbar/Navbar.module.cjs.map +1 -1
  625. package/dist/components/Navbar/Navbar.module.js.map +1 -1
  626. package/dist/components/NavigationMenu/NavigationMenu.cjs.map +1 -1
  627. package/dist/components/NavigationMenu/NavigationMenu.js.map +1 -1
  628. package/dist/components/NavigationMenu/NavigationMenu.module.cjs.map +1 -1
  629. package/dist/components/NavigationMenu/NavigationMenu.module.js.map +1 -1
  630. package/dist/components/NavigationRail/NavigationRail.cjs.map +1 -1
  631. package/dist/components/NavigationRail/NavigationRail.js.map +1 -1
  632. package/dist/components/NavigationRail/NavigationRail.module.cjs.map +1 -1
  633. package/dist/components/NavigationRail/NavigationRail.module.js.map +1 -1
  634. package/dist/components/NotificationCenter/NotificationCenter.cjs.map +1 -1
  635. package/dist/components/NotificationCenter/NotificationCenter.js.map +1 -1
  636. package/dist/components/NotificationCenter/NotificationCenter.module.cjs.map +1 -1
  637. package/dist/components/NotificationCenter/NotificationCenter.module.js.map +1 -1
  638. package/dist/components/NotificationCenter/use-notification-inbox.cjs.map +1 -1
  639. package/dist/components/NotificationCenter/use-notification-inbox.js.map +1 -1
  640. package/dist/components/OfflineIndicator/OfflineIndicator.cjs.map +1 -1
  641. package/dist/components/OfflineIndicator/OfflineIndicator.js.map +1 -1
  642. package/dist/components/OfflineIndicator/OfflineIndicator.module.cjs.map +1 -1
  643. package/dist/components/OfflineIndicator/OfflineIndicator.module.js.map +1 -1
  644. package/dist/components/Page/Page.cjs.map +1 -1
  645. package/dist/components/Page/Page.js.map +1 -1
  646. package/dist/components/Page/Page.module.cjs.map +1 -1
  647. package/dist/components/Page/Page.module.js.map +1 -1
  648. package/dist/components/Pagination/Pagination.cjs.map +1 -1
  649. package/dist/components/Pagination/Pagination.js.map +1 -1
  650. package/dist/components/Pagination/Pagination.module.cjs.map +1 -1
  651. package/dist/components/Pagination/Pagination.module.js.map +1 -1
  652. package/dist/components/PasswordInput/PasswordInput.cjs.map +1 -1
  653. package/dist/components/PasswordInput/PasswordInput.js.map +1 -1
  654. package/dist/components/PasswordInput/PasswordInput.module.cjs.map +1 -1
  655. package/dist/components/PasswordInput/PasswordInput.module.js.map +1 -1
  656. package/dist/components/PinInput/PinInput.cjs.map +1 -1
  657. package/dist/components/PinInput/PinInput.js.map +1 -1
  658. package/dist/components/PinInput/PinInput.module.cjs.map +1 -1
  659. package/dist/components/PinInput/PinInput.module.js.map +1 -1
  660. package/dist/components/Popover/Popover.cjs.map +1 -1
  661. package/dist/components/Popover/Popover.js.map +1 -1
  662. package/dist/components/Popover/Popover.module.cjs.map +1 -1
  663. package/dist/components/Popover/Popover.module.js.map +1 -1
  664. package/dist/components/Portal/Portal.cjs.map +1 -1
  665. package/dist/components/Portal/Portal.js.map +1 -1
  666. package/dist/components/Portal/anchor-position.cjs.map +1 -1
  667. package/dist/components/Portal/anchor-position.js.map +1 -1
  668. package/dist/components/Portal/escape-layer.cjs.map +1 -1
  669. package/dist/components/Portal/escape-layer.js.map +1 -1
  670. package/dist/components/Portal/portal-host.cjs.map +1 -1
  671. package/dist/components/Portal/portal-host.js.map +1 -1
  672. package/dist/components/Portal/tab-bridge.cjs +1 -1
  673. package/dist/components/Portal/tab-bridge.cjs.map +1 -1
  674. package/dist/components/Portal/tab-bridge.js +1 -5
  675. package/dist/components/Portal/tab-bridge.js.map +1 -1
  676. package/dist/components/Progress/Progress.cjs.map +1 -1
  677. package/dist/components/Progress/Progress.js.map +1 -1
  678. package/dist/components/Progress/Progress.module.cjs.map +1 -1
  679. package/dist/components/Progress/Progress.module.js.map +1 -1
  680. package/dist/components/QRCode/QRCode.cjs.map +1 -1
  681. package/dist/components/QRCode/QRCode.js.map +1 -1
  682. package/dist/components/QRCode/QRCode.module.cjs.map +1 -1
  683. package/dist/components/QRCode/QRCode.module.js.map +1 -1
  684. package/dist/components/QRCode/qr-encode.cjs +1 -1
  685. package/dist/components/QRCode/qr-encode.cjs.map +1 -1
  686. package/dist/components/QRCode/qr-encode.js +7 -13
  687. package/dist/components/QRCode/qr-encode.js.map +1 -1
  688. package/dist/components/QRCode/qr-tables.cjs.map +1 -1
  689. package/dist/components/QRCode/qr-tables.js.map +1 -1
  690. package/dist/components/Radio/Radio.cjs.map +1 -1
  691. package/dist/components/Radio/Radio.js.map +1 -1
  692. package/dist/components/Radio/Radio.module.cjs.map +1 -1
  693. package/dist/components/Radio/Radio.module.js.map +1 -1
  694. package/dist/components/RangeSlider/RangeSlider.cjs.map +1 -1
  695. package/dist/components/RangeSlider/RangeSlider.js.map +1 -1
  696. package/dist/components/RangeSlider/RangeSlider.module.cjs.map +1 -1
  697. package/dist/components/RangeSlider/RangeSlider.module.js.map +1 -1
  698. package/dist/components/RatingStars/RatingStars.cjs.map +1 -1
  699. package/dist/components/RatingStars/RatingStars.js.map +1 -1
  700. package/dist/components/RatingStars/RatingStars.module.cjs.map +1 -1
  701. package/dist/components/RatingStars/RatingStars.module.js.map +1 -1
  702. package/dist/components/RefreshIndicator/RefreshIndicator.cjs +1 -1
  703. package/dist/components/RefreshIndicator/RefreshIndicator.cjs.map +1 -1
  704. package/dist/components/RefreshIndicator/RefreshIndicator.js +10 -18
  705. package/dist/components/RefreshIndicator/RefreshIndicator.js.map +1 -1
  706. package/dist/components/RefreshIndicator/RefreshIndicator.module.cjs.map +1 -1
  707. package/dist/components/RefreshIndicator/RefreshIndicator.module.js.map +1 -1
  708. package/dist/components/RelativeTime/RelativeTime.cjs.map +1 -1
  709. package/dist/components/RelativeTime/RelativeTime.js.map +1 -1
  710. package/dist/components/Resizable/Resizable.cjs +1 -1
  711. package/dist/components/Resizable/Resizable.cjs.map +1 -1
  712. package/dist/components/Resizable/Resizable.js +1 -9
  713. package/dist/components/Resizable/Resizable.js.map +1 -1
  714. package/dist/components/Resizable/Resizable.module.cjs.map +1 -1
  715. package/dist/components/Resizable/Resizable.module.js.map +1 -1
  716. package/dist/components/Responsive/Responsive.cjs.map +1 -1
  717. package/dist/components/Responsive/Responsive.js.map +1 -1
  718. package/dist/components/Reveal/Reveal.cjs.map +1 -1
  719. package/dist/components/Reveal/Reveal.js.map +1 -1
  720. package/dist/components/Reveal/Reveal.module.cjs.map +1 -1
  721. package/dist/components/Reveal/Reveal.module.js.map +1 -1
  722. package/dist/components/Reveal/reveal-threshold.cjs.map +1 -1
  723. package/dist/components/Reveal/reveal-threshold.js.map +1 -1
  724. package/dist/components/SafeArea/SafeArea.cjs.map +1 -1
  725. package/dist/components/SafeArea/SafeArea.js.map +1 -1
  726. package/dist/components/SafeArea/SafeArea.module.cjs.map +1 -1
  727. package/dist/components/SafeArea/SafeArea.module.js.map +1 -1
  728. package/dist/components/Scheduler/Scheduler.cjs.map +1 -1
  729. package/dist/components/Scheduler/Scheduler.js.map +1 -1
  730. package/dist/components/Scheduler/Scheduler.module.cjs.map +1 -1
  731. package/dist/components/Scheduler/Scheduler.module.js.map +1 -1
  732. package/dist/components/Scheduler/scheduler-layout.cjs.map +1 -1
  733. package/dist/components/Scheduler/scheduler-layout.js.map +1 -1
  734. package/dist/components/ScrollArea/ScrollArea.cjs.map +1 -1
  735. package/dist/components/ScrollArea/ScrollArea.js.map +1 -1
  736. package/dist/components/ScrollArea/ScrollArea.module.cjs.map +1 -1
  737. package/dist/components/ScrollArea/ScrollArea.module.js.map +1 -1
  738. package/dist/components/SearchBar/SearchBar.cjs.map +1 -1
  739. package/dist/components/SearchBar/SearchBar.js.map +1 -1
  740. package/dist/components/SearchBar/SearchBar.module.cjs.map +1 -1
  741. package/dist/components/SearchBar/SearchBar.module.js.map +1 -1
  742. package/dist/components/SectionHeader/SectionHeader.cjs.map +1 -1
  743. package/dist/components/SectionHeader/SectionHeader.js.map +1 -1
  744. package/dist/components/SectionHeader/SectionHeader.module.cjs.map +1 -1
  745. package/dist/components/SectionHeader/SectionHeader.module.js.map +1 -1
  746. package/dist/components/SegmentedControl/SegmentedControl.cjs.map +1 -1
  747. package/dist/components/SegmentedControl/SegmentedControl.js.map +1 -1
  748. package/dist/components/SegmentedControl/SegmentedControl.module.cjs.map +1 -1
  749. package/dist/components/SegmentedControl/SegmentedControl.module.js.map +1 -1
  750. package/dist/components/Select/CaretIcon.cjs.map +1 -1
  751. package/dist/components/Select/CaretIcon.js.map +1 -1
  752. package/dist/components/Select/Select.cjs.map +1 -1
  753. package/dist/components/Select/Select.js.map +1 -1
  754. package/dist/components/Select/Select.module.cjs.map +1 -1
  755. package/dist/components/Select/Select.module.js.map +1 -1
  756. package/dist/components/Select/options.cjs.map +1 -1
  757. package/dist/components/Select/options.js.map +1 -1
  758. package/dist/components/Sidebar/Sidebar.cjs +1 -1
  759. package/dist/components/Sidebar/Sidebar.cjs.map +1 -1
  760. package/dist/components/Sidebar/Sidebar.js +13 -23
  761. package/dist/components/Sidebar/Sidebar.js.map +1 -1
  762. package/dist/components/Sidebar/Sidebar.module.cjs.map +1 -1
  763. package/dist/components/Sidebar/Sidebar.module.js.map +1 -1
  764. package/dist/components/Sidebar/SidebarEntry.cjs.map +1 -1
  765. package/dist/components/Sidebar/SidebarEntry.js.map +1 -1
  766. package/dist/components/Sidebar/active-nav-key.cjs.map +1 -1
  767. package/dist/components/Sidebar/active-nav-key.js.map +1 -1
  768. package/dist/components/SignaturePad/SignaturePad.cjs +1 -1
  769. package/dist/components/SignaturePad/SignaturePad.cjs.map +1 -1
  770. package/dist/components/SignaturePad/SignaturePad.js +1 -5
  771. package/dist/components/SignaturePad/SignaturePad.js.map +1 -1
  772. package/dist/components/SignaturePad/SignaturePad.module.cjs.map +1 -1
  773. package/dist/components/SignaturePad/SignaturePad.module.js.map +1 -1
  774. package/dist/components/Skeleton/Skeleton.cjs.map +1 -1
  775. package/dist/components/Skeleton/Skeleton.js.map +1 -1
  776. package/dist/components/Skeleton/Skeleton.module.cjs.map +1 -1
  777. package/dist/components/Skeleton/Skeleton.module.js.map +1 -1
  778. package/dist/components/Slider/Slider.cjs.map +1 -1
  779. package/dist/components/Slider/Slider.js.map +1 -1
  780. package/dist/components/Slider/Slider.module.cjs.map +1 -1
  781. package/dist/components/Slider/Slider.module.js.map +1 -1
  782. package/dist/components/Spacer/Spacer.cjs.map +1 -1
  783. package/dist/components/Spacer/Spacer.js.map +1 -1
  784. package/dist/components/Spacer/Spacer.module.cjs.map +1 -1
  785. package/dist/components/Spacer/Spacer.module.js.map +1 -1
  786. package/dist/components/Sparkline/Sparkline.cjs.map +1 -1
  787. package/dist/components/Sparkline/Sparkline.js.map +1 -1
  788. package/dist/components/Sparkline/Sparkline.module.cjs.map +1 -1
  789. package/dist/components/Sparkline/Sparkline.module.js.map +1 -1
  790. package/dist/components/Sparkline/sparkline-geometry.cjs.map +1 -1
  791. package/dist/components/Sparkline/sparkline-geometry.js.map +1 -1
  792. package/dist/components/Spinner/Spinner.cjs.map +1 -1
  793. package/dist/components/Spinner/Spinner.js.map +1 -1
  794. package/dist/components/Spinner/Spinner.module.cjs.map +1 -1
  795. package/dist/components/Spinner/Spinner.module.js.map +1 -1
  796. package/dist/components/Stat/Stat.cjs.map +1 -1
  797. package/dist/components/Stat/Stat.js.map +1 -1
  798. package/dist/components/Stat/Stat.module.cjs.map +1 -1
  799. package/dist/components/Stat/Stat.module.js.map +1 -1
  800. package/dist/components/Stepper/Stepper.cjs.map +1 -1
  801. package/dist/components/Stepper/Stepper.js.map +1 -1
  802. package/dist/components/Stepper/Stepper.module.cjs.map +1 -1
  803. package/dist/components/Stepper/Stepper.module.js.map +1 -1
  804. package/dist/components/StepperInput/StepperInput.cjs.map +1 -1
  805. package/dist/components/StepperInput/StepperInput.js.map +1 -1
  806. package/dist/components/StepperInput/StepperInput.module.cjs.map +1 -1
  807. package/dist/components/StepperInput/StepperInput.module.js.map +1 -1
  808. package/dist/components/Switch/Switch.cjs.map +1 -1
  809. package/dist/components/Switch/Switch.js.map +1 -1
  810. package/dist/components/Switch/Switch.module.cjs.map +1 -1
  811. package/dist/components/Switch/Switch.module.js.map +1 -1
  812. package/dist/components/SyncStatusBadge/SyncStatusBadge.cjs.map +1 -1
  813. package/dist/components/SyncStatusBadge/SyncStatusBadge.js.map +1 -1
  814. package/dist/components/SyncStatusBadge/SyncStatusBadge.module.cjs.map +1 -1
  815. package/dist/components/SyncStatusBadge/SyncStatusBadge.module.js.map +1 -1
  816. package/dist/components/Table/Table.cjs.map +1 -1
  817. package/dist/components/Table/Table.js.map +1 -1
  818. package/dist/components/Table/Table.module.cjs.map +1 -1
  819. package/dist/components/Table/Table.module.js.map +1 -1
  820. package/dist/components/Tabs/Tabs.cjs.map +1 -1
  821. package/dist/components/Tabs/Tabs.js.map +1 -1
  822. package/dist/components/Tabs/Tabs.module.cjs.map +1 -1
  823. package/dist/components/Tabs/Tabs.module.js.map +1 -1
  824. package/dist/components/Tag/Tag.cjs.map +1 -1
  825. package/dist/components/Tag/Tag.js.map +1 -1
  826. package/dist/components/Tag/Tag.module.cjs.map +1 -1
  827. package/dist/components/Tag/Tag.module.js.map +1 -1
  828. package/dist/components/Textarea/Textarea.cjs.map +1 -1
  829. package/dist/components/Textarea/Textarea.js.map +1 -1
  830. package/dist/components/Textarea/Textarea.module.cjs.map +1 -1
  831. package/dist/components/Textarea/Textarea.module.js.map +1 -1
  832. package/dist/components/TimePicker/TimePicker.cjs.map +1 -1
  833. package/dist/components/TimePicker/TimePicker.js.map +1 -1
  834. package/dist/components/TimePicker/TimePicker.module.cjs.map +1 -1
  835. package/dist/components/TimePicker/TimePicker.module.js.map +1 -1
  836. package/dist/components/Timeline/Timeline.cjs.map +1 -1
  837. package/dist/components/Timeline/Timeline.js.map +1 -1
  838. package/dist/components/Timeline/Timeline.module.cjs.map +1 -1
  839. package/dist/components/Timeline/Timeline.module.js.map +1 -1
  840. package/dist/components/Toast/Toast.module.cjs.map +1 -1
  841. package/dist/components/Toast/Toast.module.js.map +1 -1
  842. package/dist/components/Toast/ToastProvider.cjs.map +1 -1
  843. package/dist/components/Toast/ToastProvider.js.map +1 -1
  844. package/dist/components/Toggle/Toggle.cjs.map +1 -1
  845. package/dist/components/Toggle/Toggle.js.map +1 -1
  846. package/dist/components/Toggle/Toggle.module.cjs.map +1 -1
  847. package/dist/components/Toggle/Toggle.module.js.map +1 -1
  848. package/dist/components/ToggleGroup/ToggleGroup.cjs.map +1 -1
  849. package/dist/components/ToggleGroup/ToggleGroup.js.map +1 -1
  850. package/dist/components/ToggleGroup/ToggleGroup.module.cjs.map +1 -1
  851. package/dist/components/ToggleGroup/ToggleGroup.module.js.map +1 -1
  852. package/dist/components/Tooltip/Tooltip.cjs.map +1 -1
  853. package/dist/components/Tooltip/Tooltip.js.map +1 -1
  854. package/dist/components/Tooltip/Tooltip.module.cjs.map +1 -1
  855. package/dist/components/Tooltip/Tooltip.module.js.map +1 -1
  856. package/dist/components/Tour/Tour.cjs +1 -1
  857. package/dist/components/Tour/Tour.cjs.map +1 -1
  858. package/dist/components/Tour/Tour.js +1 -5
  859. package/dist/components/Tour/Tour.js.map +1 -1
  860. package/dist/components/Tour/Tour.module.cjs.map +1 -1
  861. package/dist/components/Tour/Tour.module.js.map +1 -1
  862. package/dist/components/Tour/tour-position.cjs.map +1 -1
  863. package/dist/components/Tour/tour-position.js.map +1 -1
  864. package/dist/components/Transfer/Transfer.cjs.map +1 -1
  865. package/dist/components/Transfer/Transfer.js.map +1 -1
  866. package/dist/components/Transfer/Transfer.module.cjs.map +1 -1
  867. package/dist/components/Transfer/Transfer.module.js.map +1 -1
  868. package/dist/components/Transfer/transfer-state.cjs.map +1 -1
  869. package/dist/components/Transfer/transfer-state.js.map +1 -1
  870. package/dist/components/TreeView/TreeView.cjs.map +1 -1
  871. package/dist/components/TreeView/TreeView.js.map +1 -1
  872. package/dist/components/TreeView/TreeView.module.cjs.map +1 -1
  873. package/dist/components/TreeView/TreeView.module.js.map +1 -1
  874. package/dist/components/TruncateText/TruncateText.cjs.map +1 -1
  875. package/dist/components/TruncateText/TruncateText.js.map +1 -1
  876. package/dist/components/TruncateText/TruncateText.module.cjs.map +1 -1
  877. package/dist/components/TruncateText/TruncateText.module.js.map +1 -1
  878. package/dist/components/UpdatePrompt/UpdatePrompt.cjs.map +1 -1
  879. package/dist/components/UpdatePrompt/UpdatePrompt.js.map +1 -1
  880. package/dist/components/UpdatePrompt/UpdatePrompt.module.cjs.map +1 -1
  881. package/dist/components/UpdatePrompt/UpdatePrompt.module.js.map +1 -1
  882. package/dist/components/VideoPlayer/VideoPlayer.cjs +1 -1
  883. package/dist/components/VideoPlayer/VideoPlayer.cjs.map +1 -1
  884. package/dist/components/VideoPlayer/VideoPlayer.js +1 -7
  885. package/dist/components/VideoPlayer/VideoPlayer.js.map +1 -1
  886. package/dist/components/VideoPlayer/VideoPlayer.module.cjs.map +1 -1
  887. package/dist/components/VideoPlayer/VideoPlayer.module.js.map +1 -1
  888. package/dist/components/VideoPlayer/playback-rates.cjs.map +1 -1
  889. package/dist/components/VideoPlayer/playback-rates.js.map +1 -1
  890. package/dist/components/VirtualList/VirtualList.cjs.map +1 -1
  891. package/dist/components/VirtualList/VirtualList.js.map +1 -1
  892. package/dist/components/VirtualList/VirtualList.module.cjs.map +1 -1
  893. package/dist/components/VirtualList/VirtualList.module.js.map +1 -1
  894. package/dist/components/VirtualTable/VirtualTable.cjs.map +1 -1
  895. package/dist/components/VirtualTable/VirtualTable.js.map +1 -1
  896. package/dist/components/VirtualTable/VirtualTable.module.cjs.map +1 -1
  897. package/dist/components/VirtualTable/VirtualTable.module.js.map +1 -1
  898. package/dist/components/VisuallyHidden/VisuallyHidden.cjs.map +1 -1
  899. package/dist/components/VisuallyHidden/VisuallyHidden.js.map +1 -1
  900. package/dist/components/VisuallyHidden/VisuallyHidden.module.cjs.map +1 -1
  901. package/dist/components/VisuallyHidden/VisuallyHidden.module.js.map +1 -1
  902. package/dist/components/Wizard/Wizard.cjs +1 -1
  903. package/dist/components/Wizard/Wizard.cjs.map +1 -1
  904. package/dist/components/Wizard/Wizard.js +4 -11
  905. package/dist/components/Wizard/Wizard.js.map +1 -1
  906. package/dist/components/Wizard/Wizard.module.cjs.map +1 -1
  907. package/dist/components/Wizard/Wizard.module.js.map +1 -1
  908. package/dist/data/create-data-provider.cjs.map +1 -1
  909. package/dist/data/create-data-provider.js.map +1 -1
  910. package/dist/data/data-provider-context.cjs.map +1 -1
  911. package/dist/data/data-provider-context.js.map +1 -1
  912. package/dist/data/use-resource.cjs.map +1 -1
  913. package/dist/data/use-resource.js.map +1 -1
  914. package/dist/editor/RichTextEditor.cjs.map +1 -1
  915. package/dist/editor/RichTextEditor.js.map +1 -1
  916. package/dist/editor/RichTextEditor.module.cjs.map +1 -1
  917. package/dist/editor/RichTextEditor.module.js.map +1 -1
  918. package/dist/editor.js +1 -2
  919. package/dist/error-boundary/ErrorBoundary.cjs.map +1 -1
  920. package/dist/error-boundary/ErrorBoundary.js.map +1 -1
  921. package/dist/error-boundary/use-error-handler.cjs.map +1 -1
  922. package/dist/error-boundary/use-error-handler.js.map +1 -1
  923. package/dist/feature-flags/FeatureFlagsProvider.cjs.map +1 -1
  924. package/dist/feature-flags/FeatureFlagsProvider.js.map +1 -1
  925. package/dist/feature-flags/growthbook-adapter.cjs.map +1 -1
  926. package/dist/feature-flags/growthbook-adapter.js.map +1 -1
  927. package/dist/feature-flags/in-memory-adapter.cjs.map +1 -1
  928. package/dist/feature-flags/in-memory-adapter.js.map +1 -1
  929. package/dist/feature-flags/launchdarkly-adapter.cjs.map +1 -1
  930. package/dist/feature-flags/launchdarkly-adapter.js.map +1 -1
  931. package/dist/forms/FormField.cjs.map +1 -1
  932. package/dist/forms/FormField.js.map +1 -1
  933. package/dist/forms/br-validators.cjs.map +1 -1
  934. package/dist/forms/br-validators.js.map +1 -1
  935. package/dist/forms/masked-inputs.cjs.map +1 -1
  936. package/dist/forms/masked-inputs.js.map +1 -1
  937. package/dist/forms/use-viacep.cjs.map +1 -1
  938. package/dist/forms/use-viacep.js.map +1 -1
  939. package/dist/forms/use-zod-form.cjs.map +1 -1
  940. package/dist/forms/use-zod-form.js.map +1 -1
  941. package/dist/forms/validate-form.cjs.map +1 -1
  942. package/dist/forms/validate-form.js.map +1 -1
  943. package/dist/forms/zod-resolver.cjs.map +1 -1
  944. package/dist/forms/zod-resolver.js.map +1 -1
  945. package/dist/geo/TrajectoryMap.cjs.map +1 -1
  946. package/dist/geo/TrajectoryMap.js.map +1 -1
  947. package/dist/geo/TrajectoryMap.module.cjs.map +1 -1
  948. package/dist/geo/TrajectoryMap.module.js.map +1 -1
  949. package/dist/geo/bounds.cjs.map +1 -1
  950. package/dist/geo/bounds.js.map +1 -1
  951. package/dist/geo/create-position-tracker.cjs +1 -1
  952. package/dist/geo/create-position-tracker.cjs.map +1 -1
  953. package/dist/geo/create-position-tracker.js +1 -7
  954. package/dist/geo/create-position-tracker.js.map +1 -1
  955. package/dist/geo/distance.cjs.map +1 -1
  956. package/dist/geo/distance.js.map +1 -1
  957. package/dist/geo/estimate.cjs.map +1 -1
  958. package/dist/geo/estimate.js.map +1 -1
  959. package/dist/geo/leaflet-map.cjs.map +1 -1
  960. package/dist/geo/leaflet-map.js.map +1 -1
  961. package/dist/geo/projection.cjs.map +1 -1
  962. package/dist/geo/projection.js.map +1 -1
  963. package/dist/geo/routing.cjs.map +1 -1
  964. package/dist/geo/routing.js.map +1 -1
  965. package/dist/geo/types.cjs.map +1 -1
  966. package/dist/geo/types.js.map +1 -1
  967. package/dist/geo/use-position-tracker.cjs.map +1 -1
  968. package/dist/geo/use-position-tracker.js.map +1 -1
  969. package/dist/hooks/pwa-env.cjs.map +1 -1
  970. package/dist/hooks/pwa-env.js.map +1 -1
  971. package/dist/hooks/tab-sequence.cjs.map +1 -1
  972. package/dist/hooks/tab-sequence.js.map +1 -1
  973. package/dist/hooks/use-announce.cjs +1 -1
  974. package/dist/hooks/use-announce.cjs.map +1 -1
  975. package/dist/hooks/use-announce.js +2 -2
  976. package/dist/hooks/use-announce.js.map +1 -1
  977. package/dist/hooks/use-async.cjs.map +1 -1
  978. package/dist/hooks/use-async.js.map +1 -1
  979. package/dist/hooks/use-before-install-prompt.cjs.map +1 -1
  980. package/dist/hooks/use-before-install-prompt.js.map +1 -1
  981. package/dist/hooks/use-breakpoint.cjs.map +1 -1
  982. package/dist/hooks/use-breakpoint.js.map +1 -1
  983. package/dist/hooks/use-click-outside.cjs.map +1 -1
  984. package/dist/hooks/use-click-outside.js.map +1 -1
  985. package/dist/hooks/use-client-filter.cjs.map +1 -1
  986. package/dist/hooks/use-client-filter.js.map +1 -1
  987. package/dist/hooks/use-clipboard.cjs.map +1 -1
  988. package/dist/hooks/use-clipboard.js.map +1 -1
  989. package/dist/hooks/use-countdown.cjs.map +1 -1
  990. package/dist/hooks/use-countdown.js.map +1 -1
  991. package/dist/hooks/use-counter.cjs.map +1 -1
  992. package/dist/hooks/use-counter.js.map +1 -1
  993. package/dist/hooks/use-debounce.cjs.map +1 -1
  994. package/dist/hooks/use-debounce.js.map +1 -1
  995. package/dist/hooks/use-deep-memo.cjs.map +1 -1
  996. package/dist/hooks/use-deep-memo.js.map +1 -1
  997. package/dist/hooks/use-disclosure.cjs.map +1 -1
  998. package/dist/hooks/use-disclosure.js.map +1 -1
  999. package/dist/hooks/use-document-title.cjs.map +1 -1
  1000. package/dist/hooks/use-document-title.js.map +1 -1
  1001. package/dist/hooks/use-document-visibility.cjs.map +1 -1
  1002. package/dist/hooks/use-document-visibility.js.map +1 -1
  1003. package/dist/hooks/use-draft-filters.cjs.map +1 -1
  1004. package/dist/hooks/use-draft-filters.js.map +1 -1
  1005. package/dist/hooks/use-event-listener.cjs.map +1 -1
  1006. package/dist/hooks/use-event-listener.js.map +1 -1
  1007. package/dist/hooks/use-favicon.cjs.map +1 -1
  1008. package/dist/hooks/use-favicon.js.map +1 -1
  1009. package/dist/hooks/use-focus-trap.cjs.map +1 -1
  1010. package/dist/hooks/use-focus-trap.js.map +1 -1
  1011. package/dist/hooks/use-fullscreen-element.cjs.map +1 -1
  1012. package/dist/hooks/use-fullscreen-element.js.map +1 -1
  1013. package/dist/hooks/use-fullscreen.cjs +1 -1
  1014. package/dist/hooks/use-fullscreen.cjs.map +1 -1
  1015. package/dist/hooks/use-fullscreen.js +7 -23
  1016. package/dist/hooks/use-fullscreen.js.map +1 -1
  1017. package/dist/hooks/use-geolocation.cjs.map +1 -1
  1018. package/dist/hooks/use-geolocation.js.map +1 -1
  1019. package/dist/hooks/use-hover.cjs.map +1 -1
  1020. package/dist/hooks/use-hover.js.map +1 -1
  1021. package/dist/hooks/use-idle.cjs.map +1 -1
  1022. package/dist/hooks/use-idle.js.map +1 -1
  1023. package/dist/hooks/use-install-prompt.cjs +1 -1
  1024. package/dist/hooks/use-install-prompt.cjs.map +1 -1
  1025. package/dist/hooks/use-install-prompt.js +1 -1
  1026. package/dist/hooks/use-install-prompt.js.map +1 -1
  1027. package/dist/hooks/use-intersection-observer.cjs.map +1 -1
  1028. package/dist/hooks/use-intersection-observer.js.map +1 -1
  1029. package/dist/hooks/use-interval.cjs.map +1 -1
  1030. package/dist/hooks/use-interval.js.map +1 -1
  1031. package/dist/hooks/use-is-first-render.cjs.map +1 -1
  1032. package/dist/hooks/use-is-first-render.js.map +1 -1
  1033. package/dist/hooks/use-keyboard-shortcut.cjs.map +1 -1
  1034. package/dist/hooks/use-keyboard-shortcut.js.map +1 -1
  1035. package/dist/hooks/use-latest-ref.cjs.map +1 -1
  1036. package/dist/hooks/use-latest-ref.js.map +1 -1
  1037. package/dist/hooks/use-list-state.cjs.map +1 -1
  1038. package/dist/hooks/use-list-state.js.map +1 -1
  1039. package/dist/hooks/use-local-storage.cjs +1 -1
  1040. package/dist/hooks/use-local-storage.cjs.map +1 -1
  1041. package/dist/hooks/use-local-storage.js +2 -5
  1042. package/dist/hooks/use-local-storage.js.map +1 -1
  1043. package/dist/hooks/use-long-press-handlers.cjs.map +1 -1
  1044. package/dist/hooks/use-long-press-handlers.js.map +1 -1
  1045. package/dist/hooks/use-long-press.cjs.map +1 -1
  1046. package/dist/hooks/use-long-press.js.map +1 -1
  1047. package/dist/hooks/use-map.cjs.map +1 -1
  1048. package/dist/hooks/use-map.js.map +1 -1
  1049. package/dist/hooks/use-media-devices.cjs.map +1 -1
  1050. package/dist/hooks/use-media-devices.js.map +1 -1
  1051. package/dist/hooks/use-media-permission.cjs +1 -1
  1052. package/dist/hooks/use-media-permission.cjs.map +1 -1
  1053. package/dist/hooks/use-media-permission.js +2 -5
  1054. package/dist/hooks/use-media-permission.js.map +1 -1
  1055. package/dist/hooks/use-media-query.cjs.map +1 -1
  1056. package/dist/hooks/use-media-query.js.map +1 -1
  1057. package/dist/hooks/use-object-url.cjs.map +1 -1
  1058. package/dist/hooks/use-object-url.js.map +1 -1
  1059. package/dist/hooks/use-online.cjs.map +1 -1
  1060. package/dist/hooks/use-online.js.map +1 -1
  1061. package/dist/hooks/use-pagination.cjs.map +1 -1
  1062. package/dist/hooks/use-pagination.js.map +1 -1
  1063. package/dist/hooks/use-previous.cjs.map +1 -1
  1064. package/dist/hooks/use-previous.js.map +1 -1
  1065. package/dist/hooks/use-push-to-talk.cjs.map +1 -1
  1066. package/dist/hooks/use-push-to-talk.js.map +1 -1
  1067. package/dist/hooks/use-queue.cjs.map +1 -1
  1068. package/dist/hooks/use-queue.js.map +1 -1
  1069. package/dist/hooks/use-resize-observer.cjs.map +1 -1
  1070. package/dist/hooks/use-resize-observer.js.map +1 -1
  1071. package/dist/hooks/use-scroll-lock.cjs.map +1 -1
  1072. package/dist/hooks/use-scroll-lock.js.map +1 -1
  1073. package/dist/hooks/use-scroll-overflow.cjs.map +1 -1
  1074. package/dist/hooks/use-scroll-overflow.js.map +1 -1
  1075. package/dist/hooks/use-service-worker-update.cjs.map +1 -1
  1076. package/dist/hooks/use-service-worker-update.js.map +1 -1
  1077. package/dist/hooks/use-set.cjs.map +1 -1
  1078. package/dist/hooks/use-set.js.map +1 -1
  1079. package/dist/hooks/use-sortable.cjs.map +1 -1
  1080. package/dist/hooks/use-sortable.js.map +1 -1
  1081. package/dist/hooks/use-stable-callback.cjs.map +1 -1
  1082. package/dist/hooks/use-stable-callback.js.map +1 -1
  1083. package/dist/hooks/use-storage-estimate.cjs.map +1 -1
  1084. package/dist/hooks/use-storage-estimate.js.map +1 -1
  1085. package/dist/hooks/use-throttle.cjs.map +1 -1
  1086. package/dist/hooks/use-throttle.js.map +1 -1
  1087. package/dist/hooks/use-timeout.cjs.map +1 -1
  1088. package/dist/hooks/use-timeout.js.map +1 -1
  1089. package/dist/hooks/use-toggle.cjs.map +1 -1
  1090. package/dist/hooks/use-toggle.js.map +1 -1
  1091. package/dist/hooks/use-typewriter.cjs.map +1 -1
  1092. package/dist/hooks/use-typewriter.js.map +1 -1
  1093. package/dist/hooks/use-window-size.cjs.map +1 -1
  1094. package/dist/hooks/use-window-size.js.map +1 -1
  1095. package/dist/http/api-client.cjs.map +1 -1
  1096. package/dist/http/api-client.js.map +1 -1
  1097. package/dist/http/build-url.cjs.map +1 -1
  1098. package/dist/http/build-url.js.map +1 -1
  1099. package/dist/http/credential-scope.cjs.map +1 -1
  1100. package/dist/http/credential-scope.js.map +1 -1
  1101. package/dist/http/csrf.cjs.map +1 -1
  1102. package/dist/http/csrf.js.map +1 -1
  1103. package/dist/http/decode-response.cjs.map +1 -1
  1104. package/dist/http/decode-response.js.map +1 -1
  1105. package/dist/http/describe-api-error.cjs.map +1 -1
  1106. package/dist/http/describe-api-error.js.map +1 -1
  1107. package/dist/http/errors.cjs.map +1 -1
  1108. package/dist/http/errors.js.map +1 -1
  1109. package/dist/http/idempotency.cjs.map +1 -1
  1110. package/dist/http/idempotency.js.map +1 -1
  1111. package/dist/http/parse-response.cjs.map +1 -1
  1112. package/dist/http/parse-response.js.map +1 -1
  1113. package/dist/http/resumable-upload.cjs +1 -1
  1114. package/dist/http/resumable-upload.cjs.map +1 -1
  1115. package/dist/http/resumable-upload.js +141 -105
  1116. package/dist/http/resumable-upload.js.map +1 -1
  1117. package/dist/http/retry.cjs +1 -1
  1118. package/dist/http/retry.cjs.map +1 -1
  1119. package/dist/http/retry.js +5 -6
  1120. package/dist/http/retry.js.map +1 -1
  1121. package/dist/http/timeout.cjs.map +1 -1
  1122. package/dist/http/timeout.js.map +1 -1
  1123. package/dist/http/upload-with-progress.cjs +1 -1
  1124. package/dist/http/upload-with-progress.cjs.map +1 -1
  1125. package/dist/http/upload-with-progress.js +2 -7
  1126. package/dist/http/upload-with-progress.js.map +1 -1
  1127. package/dist/http/use-describe-api-error.cjs.map +1 -1
  1128. package/dist/http/use-describe-api-error.js.map +1 -1
  1129. package/dist/http/use-poll.cjs +1 -1
  1130. package/dist/http/use-poll.cjs.map +1 -1
  1131. package/dist/http/use-poll.js +2 -5
  1132. package/dist/http/use-poll.js.map +1 -1
  1133. package/dist/i18n/I18nProvider.cjs.map +1 -1
  1134. package/dist/i18n/I18nProvider.js.map +1 -1
  1135. package/dist/i18n/create-i18n.cjs.map +1 -1
  1136. package/dist/i18n/create-i18n.js.map +1 -1
  1137. package/dist/icons/Icon.cjs.map +1 -1
  1138. package/dist/icons/Icon.js.map +1 -1
  1139. package/dist/icons/IconPicker.cjs.map +1 -1
  1140. package/dist/icons/IconPicker.js.map +1 -1
  1141. package/dist/icons/IconPicker.module.cjs.map +1 -1
  1142. package/dist/icons/IconPicker.module.js.map +1 -1
  1143. package/dist/icons/IconProvider.cjs.map +1 -1
  1144. package/dist/icons/IconProvider.js.map +1 -1
  1145. package/dist/icons/alias.cjs.map +1 -1
  1146. package/dist/icons/alias.js.map +1 -1
  1147. package/dist/icons/generated/aliases.cjs.map +1 -1
  1148. package/dist/icons/generated/aliases.js.map +1 -1
  1149. package/dist/icons/generated/icon-names.cjs.map +1 -1
  1150. package/dist/icons/generated/icon-names.js.map +1 -1
  1151. package/dist/icons/generated/loaders.cjs.map +1 -1
  1152. package/dist/icons/generated/loaders.js.map +1 -1
  1153. package/dist/icons/generated/shard-00.cjs.map +1 -1
  1154. package/dist/icons/generated/shard-00.js.map +1 -1
  1155. package/dist/icons/generated/shard-01.cjs.map +1 -1
  1156. package/dist/icons/generated/shard-01.js.map +1 -1
  1157. package/dist/icons/generated/shard-02.cjs.map +1 -1
  1158. package/dist/icons/generated/shard-02.js.map +1 -1
  1159. package/dist/icons/generated/shard-03.cjs.map +1 -1
  1160. package/dist/icons/generated/shard-03.js.map +1 -1
  1161. package/dist/icons/generated/shard-04.cjs.map +1 -1
  1162. package/dist/icons/generated/shard-04.js.map +1 -1
  1163. package/dist/icons/generated/shard-05.cjs.map +1 -1
  1164. package/dist/icons/generated/shard-05.js.map +1 -1
  1165. package/dist/icons/generated/shard-06.cjs.map +1 -1
  1166. package/dist/icons/generated/shard-06.js.map +1 -1
  1167. package/dist/icons/generated/shard-07.cjs.map +1 -1
  1168. package/dist/icons/generated/shard-07.js.map +1 -1
  1169. package/dist/icons/generated/shard-08.cjs.map +1 -1
  1170. package/dist/icons/generated/shard-08.js.map +1 -1
  1171. package/dist/icons/generated/shard-09.cjs.map +1 -1
  1172. package/dist/icons/generated/shard-09.js.map +1 -1
  1173. package/dist/icons/generated/shard-10.cjs.map +1 -1
  1174. package/dist/icons/generated/shard-10.js.map +1 -1
  1175. package/dist/icons/generated/shard-11.cjs.map +1 -1
  1176. package/dist/icons/generated/shard-11.js.map +1 -1
  1177. package/dist/icons/generated/shard-12.cjs.map +1 -1
  1178. package/dist/icons/generated/shard-12.js.map +1 -1
  1179. package/dist/icons/generated/shard-13.cjs.map +1 -1
  1180. package/dist/icons/generated/shard-13.js.map +1 -1
  1181. package/dist/icons/generated/shard-14.cjs.map +1 -1
  1182. package/dist/icons/generated/shard-14.js.map +1 -1
  1183. package/dist/icons/generated/shard-15.cjs.map +1 -1
  1184. package/dist/icons/generated/shard-15.js.map +1 -1
  1185. package/dist/icons/generated/shard-16.cjs.map +1 -1
  1186. package/dist/icons/generated/shard-16.js.map +1 -1
  1187. package/dist/icons/generated/shard-17.cjs.map +1 -1
  1188. package/dist/icons/generated/shard-17.js.map +1 -1
  1189. package/dist/icons/generated/shard-18.cjs.map +1 -1
  1190. package/dist/icons/generated/shard-18.js.map +1 -1
  1191. package/dist/icons/generated/shard-19.cjs.map +1 -1
  1192. package/dist/icons/generated/shard-19.js.map +1 -1
  1193. package/dist/icons/generated/shard-20.cjs.map +1 -1
  1194. package/dist/icons/generated/shard-20.js.map +1 -1
  1195. package/dist/icons/generated/shard-21.cjs.map +1 -1
  1196. package/dist/icons/generated/shard-21.js.map +1 -1
  1197. package/dist/icons/generated/shard-22.cjs.map +1 -1
  1198. package/dist/icons/generated/shard-22.js.map +1 -1
  1199. package/dist/icons/generated/shard-23.cjs.map +1 -1
  1200. package/dist/icons/generated/shard-23.js.map +1 -1
  1201. package/dist/icons/generated/shard-24.cjs.map +1 -1
  1202. package/dist/icons/generated/shard-24.js.map +1 -1
  1203. package/dist/icons/generated/shard-25.cjs.map +1 -1
  1204. package/dist/icons/generated/shard-25.js.map +1 -1
  1205. package/dist/icons/generated/shard-26.cjs.map +1 -1
  1206. package/dist/icons/generated/shard-26.js.map +1 -1
  1207. package/dist/icons/generated/shard-27.cjs.map +1 -1
  1208. package/dist/icons/generated/shard-27.js.map +1 -1
  1209. package/dist/icons/generated/shard-28.cjs.map +1 -1
  1210. package/dist/icons/generated/shard-28.js.map +1 -1
  1211. package/dist/icons/generated/shard-29.cjs.map +1 -1
  1212. package/dist/icons/generated/shard-29.js.map +1 -1
  1213. package/dist/icons/generated/shard-30.cjs.map +1 -1
  1214. package/dist/icons/generated/shard-30.js.map +1 -1
  1215. package/dist/icons/generated/shard-31.cjs.map +1 -1
  1216. package/dist/icons/generated/shard-31.js.map +1 -1
  1217. package/dist/icons/generated/shard-32.cjs.map +1 -1
  1218. package/dist/icons/generated/shard-32.js.map +1 -1
  1219. package/dist/icons/generated/shard-33.cjs.map +1 -1
  1220. package/dist/icons/generated/shard-33.js.map +1 -1
  1221. package/dist/icons/generated/shard-34.cjs.map +1 -1
  1222. package/dist/icons/generated/shard-34.js.map +1 -1
  1223. package/dist/icons/generated/shard-35.cjs.map +1 -1
  1224. package/dist/icons/generated/shard-35.js.map +1 -1
  1225. package/dist/icons/generated/shard-36.cjs.map +1 -1
  1226. package/dist/icons/generated/shard-36.js.map +1 -1
  1227. package/dist/icons/generated/shard-37.cjs.map +1 -1
  1228. package/dist/icons/generated/shard-37.js.map +1 -1
  1229. package/dist/icons/generated/shard-38.cjs.map +1 -1
  1230. package/dist/icons/generated/shard-38.js.map +1 -1
  1231. package/dist/icons/generated/shard-39.cjs.map +1 -1
  1232. package/dist/icons/generated/shard-39.js.map +1 -1
  1233. package/dist/icons/generated/shard-40.cjs.map +1 -1
  1234. package/dist/icons/generated/shard-40.js.map +1 -1
  1235. package/dist/icons/generated/shard-41.cjs.map +1 -1
  1236. package/dist/icons/generated/shard-41.js.map +1 -1
  1237. package/dist/icons/generated/shard-42.cjs.map +1 -1
  1238. package/dist/icons/generated/shard-42.js.map +1 -1
  1239. package/dist/icons/generated/shard-43.cjs.map +1 -1
  1240. package/dist/icons/generated/shard-43.js.map +1 -1
  1241. package/dist/icons/generated/shard-44.cjs.map +1 -1
  1242. package/dist/icons/generated/shard-44.js.map +1 -1
  1243. package/dist/icons/generated/shard-45.cjs.map +1 -1
  1244. package/dist/icons/generated/shard-45.js.map +1 -1
  1245. package/dist/icons/icon-context.cjs.map +1 -1
  1246. package/dist/icons/icon-context.js.map +1 -1
  1247. package/dist/icons/is-icon-name.cjs.map +1 -1
  1248. package/dist/icons/is-icon-name.js.map +1 -1
  1249. package/dist/icons/material-symbols.cjs.map +1 -1
  1250. package/dist/icons/material-symbols.js.map +1 -1
  1251. package/dist/icons/normalize-icon-name.cjs.map +1 -1
  1252. package/dist/icons/normalize-icon-name.js.map +1 -1
  1253. package/dist/icons/shard-cache.cjs +1 -1
  1254. package/dist/icons/shard-cache.cjs.map +1 -1
  1255. package/dist/icons/shard-cache.js +2 -5
  1256. package/dist/icons/shard-cache.js.map +1 -1
  1257. package/dist/icons/use-icon.cjs.map +1 -1
  1258. package/dist/icons/use-icon.js.map +1 -1
  1259. package/dist/icons/validate-icon-name.cjs.map +1 -1
  1260. package/dist/icons/validate-icon-name.js.map +1 -1
  1261. package/dist/icons-virtual.cjs.map +1 -1
  1262. package/dist/icons-virtual.js.map +1 -1
  1263. package/dist/imaging/canvas.cjs.map +1 -1
  1264. package/dist/imaging/canvas.js.map +1 -1
  1265. package/dist/imaging/compress.cjs.map +1 -1
  1266. package/dist/imaging/compress.js.map +1 -1
  1267. package/dist/imaging/decode.cjs.map +1 -1
  1268. package/dist/imaging/decode.js.map +1 -1
  1269. package/dist/imaging/encode.cjs.map +1 -1
  1270. package/dist/imaging/encode.js.map +1 -1
  1271. package/dist/imaging/exceptions.cjs.map +1 -1
  1272. package/dist/imaging/exceptions.js.map +1 -1
  1273. package/dist/imaging/frame.cjs.map +1 -1
  1274. package/dist/imaging/frame.js.map +1 -1
  1275. package/dist/imaging/thumbnails.cjs.map +1 -1
  1276. package/dist/imaging/thumbnails.js.map +1 -1
  1277. package/dist/imaging/transform.cjs.map +1 -1
  1278. package/dist/imaging/transform.js.map +1 -1
  1279. package/dist/imaging/use-image-processing.cjs.map +1 -1
  1280. package/dist/imaging/use-image-processing.js.map +1 -1
  1281. package/dist/logger/logger.cjs.map +1 -1
  1282. package/dist/logger/logger.js.map +1 -1
  1283. package/dist/neural.cjs.map +1 -1
  1284. package/dist/neural.js.map +1 -1
  1285. package/dist/oauth/GoogleSignIn.cjs +1 -1
  1286. package/dist/oauth/GoogleSignIn.cjs.map +1 -1
  1287. package/dist/oauth/GoogleSignIn.js +6 -9
  1288. package/dist/oauth/GoogleSignIn.js.map +1 -1
  1289. package/dist/oauth/callback.cjs.map +1 -1
  1290. package/dist/oauth/callback.js.map +1 -1
  1291. package/dist/oauth/use-oauth-callback.cjs.map +1 -1
  1292. package/dist/oauth/use-oauth-callback.js.map +1 -1
  1293. package/dist/offline/conflict.cjs.map +1 -1
  1294. package/dist/offline/conflict.js.map +1 -1
  1295. package/dist/offline/create-offline-database.cjs.map +1 -1
  1296. package/dist/offline/create-offline-database.js.map +1 -1
  1297. package/dist/offline/create-offline-store.cjs +1 -1
  1298. package/dist/offline/create-offline-store.cjs.map +1 -1
  1299. package/dist/offline/create-offline-store.js +1 -5
  1300. package/dist/offline/create-offline-store.js.map +1 -1
  1301. package/dist/offline/create-offline-sync.cjs +1 -1
  1302. package/dist/offline/create-offline-sync.cjs.map +1 -1
  1303. package/dist/offline/create-offline-sync.js +9 -14
  1304. package/dist/offline/create-offline-sync.js.map +1 -1
  1305. package/dist/offline/use-offline-sync.cjs.map +1 -1
  1306. package/dist/offline/use-offline-sync.js.map +1 -1
  1307. package/dist/perf/cache-size.cjs.map +1 -1
  1308. package/dist/perf/cache-size.js.map +1 -1
  1309. package/dist/perf/device.cjs.map +1 -1
  1310. package/dist/perf/device.js.map +1 -1
  1311. package/dist/perf/format.cjs.map +1 -1
  1312. package/dist/perf/format.js.map +1 -1
  1313. package/dist/perf/profiler.cjs.map +1 -1
  1314. package/dist/perf/profiler.js.map +1 -1
  1315. package/dist/push/use-push-subscription.cjs.map +1 -1
  1316. package/dist/push/use-push-subscription.js.map +1 -1
  1317. package/dist/push/utils.cjs.map +1 -1
  1318. package/dist/push/utils.js.map +1 -1
  1319. package/dist/push/web-push-client.cjs.map +1 -1
  1320. package/dist/push/web-push-client.js.map +1 -1
  1321. package/dist/query/QueryProvider.cjs.map +1 -1
  1322. package/dist/query/QueryProvider.js.map +1 -1
  1323. package/dist/query/constants.cjs.map +1 -1
  1324. package/dist/query/constants.js.map +1 -1
  1325. package/dist/query/create-query-keys.cjs.map +1 -1
  1326. package/dist/query/create-query-keys.js.map +1 -1
  1327. package/dist/query/foreign-client-warning.cjs.map +1 -1
  1328. package/dist/query/foreign-client-warning.js.map +1 -1
  1329. package/dist/query/offline-persistence.cjs +1 -1
  1330. package/dist/query/offline-persistence.cjs.map +1 -1
  1331. package/dist/query/offline-persistence.js +2 -10
  1332. package/dist/query/offline-persistence.js.map +1 -1
  1333. package/dist/query/optimistic.cjs.map +1 -1
  1334. package/dist/query/optimistic.js.map +1 -1
  1335. package/dist/query/pagination.cjs.map +1 -1
  1336. package/dist/query/pagination.js.map +1 -1
  1337. package/dist/query/retry-policy.cjs.map +1 -1
  1338. package/dist/query/retry-policy.js.map +1 -1
  1339. package/dist/query/use-cursor-query.cjs.map +1 -1
  1340. package/dist/query/use-cursor-query.js.map +1 -1
  1341. package/dist/query/use-offline-mutation.cjs.map +1 -1
  1342. package/dist/query/use-offline-mutation.js.map +1 -1
  1343. package/dist/query/use-paginated-query.cjs.map +1 -1
  1344. package/dist/query/use-paginated-query.js.map +1 -1
  1345. package/dist/router/AppRouter.cjs.map +1 -1
  1346. package/dist/router/AppRouter.js.map +1 -1
  1347. package/dist/router/RouteGuard.cjs.map +1 -1
  1348. package/dist/router/RouteGuard.js.map +1 -1
  1349. package/dist/router/index.js +2 -2
  1350. package/dist/share/share-or-download.cjs.map +1 -1
  1351. package/dist/share/share-or-download.js.map +1 -1
  1352. package/dist/share/share.cjs.map +1 -1
  1353. package/dist/share/share.js.map +1 -1
  1354. package/dist/sse/create-event-stream.cjs.map +1 -1
  1355. package/dist/sse/create-event-stream.js.map +1 -1
  1356. package/dist/sse/use-event-stream.cjs.map +1 -1
  1357. package/dist/sse/use-event-stream.js.map +1 -1
  1358. package/dist/store/create-selectors.cjs.map +1 -1
  1359. package/dist/store/create-selectors.js.map +1 -1
  1360. package/dist/store/create-store.cjs.map +1 -1
  1361. package/dist/store/create-store.js.map +1 -1
  1362. package/dist/sw/background-sync.cjs +1 -1
  1363. package/dist/sw/background-sync.cjs.map +1 -1
  1364. package/dist/sw/background-sync.js +32 -31
  1365. package/dist/sw/background-sync.js.map +1 -1
  1366. package/dist/sw/cache-inspect.cjs.map +1 -1
  1367. package/dist/sw/cache-inspect.js.map +1 -1
  1368. package/dist/sw/cache.cjs +1 -1
  1369. package/dist/sw/cache.cjs.map +1 -1
  1370. package/dist/sw/cache.js +2 -6
  1371. package/dist/sw/cache.js.map +1 -1
  1372. package/dist/sw/create-push-handler.cjs.map +1 -1
  1373. package/dist/sw/create-push-handler.js.map +1 -1
  1374. package/dist/sw/credential-headers.cjs.map +1 -1
  1375. package/dist/sw/credential-headers.js.map +1 -1
  1376. package/dist/sw/periodic-sync.cjs.map +1 -1
  1377. package/dist/sw/periodic-sync.js.map +1 -1
  1378. package/dist/sw/register-service-worker.cjs.map +1 -1
  1379. package/dist/sw/register-service-worker.js.map +1 -1
  1380. package/dist/sw/session-data.cjs.map +1 -1
  1381. package/dist/sw/session-data.js.map +1 -1
  1382. package/dist/sw.d.ts +46 -8
  1383. package/dist/tabular/assets.cjs.map +1 -1
  1384. package/dist/tabular/assets.js.map +1 -1
  1385. package/dist/tabular/cache.cjs.map +1 -1
  1386. package/dist/tabular/cache.js.map +1 -1
  1387. package/dist/tabular/compact.cjs.map +1 -1
  1388. package/dist/tabular/compact.js.map +1 -1
  1389. package/dist/tabular/exceptions.cjs.map +1 -1
  1390. package/dist/tabular/exceptions.js.map +1 -1
  1391. package/dist/tabular/manifest.cjs.map +1 -1
  1392. package/dist/tabular/manifest.js.map +1 -1
  1393. package/dist/tabular/predictor.cjs.map +1 -1
  1394. package/dist/tabular/predictor.js.map +1 -1
  1395. package/dist/tabular/use-tabular-predictor.cjs.map +1 -1
  1396. package/dist/tabular/use-tabular-predictor.js.map +1 -1
  1397. package/dist/telemetry/TelemetryProvider.cjs.map +1 -1
  1398. package/dist/telemetry/TelemetryProvider.js.map +1 -1
  1399. package/dist/telemetry/app-error-adapter.cjs.map +1 -1
  1400. package/dist/telemetry/app-error-adapter.js.map +1 -1
  1401. package/dist/telemetry/app-error-queue.cjs.map +1 -1
  1402. package/dist/telemetry/app-error-queue.js.map +1 -1
  1403. package/dist/telemetry/app-error-reporter.cjs +1 -1
  1404. package/dist/telemetry/app-error-reporter.cjs.map +1 -1
  1405. package/dist/telemetry/app-error-reporter.js +1 -1
  1406. package/dist/telemetry/app-error-reporter.js.map +1 -1
  1407. package/dist/telemetry/app-error-schema.cjs.map +1 -1
  1408. package/dist/telemetry/app-error-schema.js.map +1 -1
  1409. package/dist/telemetry/app-error-transport.cjs.map +1 -1
  1410. package/dist/telemetry/app-error-transport.js.map +1 -1
  1411. package/dist/telemetry/console-adapter.cjs.map +1 -1
  1412. package/dist/telemetry/console-adapter.js.map +1 -1
  1413. package/dist/telemetry/describe-app-error.cjs.map +1 -1
  1414. package/dist/telemetry/describe-app-error.js.map +1 -1
  1415. package/dist/telemetry/posthog-adapter.cjs +1 -1
  1416. package/dist/telemetry/posthog-adapter.cjs.map +1 -1
  1417. package/dist/telemetry/posthog-adapter.js +1 -5
  1418. package/dist/telemetry/posthog-adapter.js.map +1 -1
  1419. package/dist/telemetry/sentry-adapter.cjs.map +1 -1
  1420. package/dist/telemetry/sentry-adapter.js.map +1 -1
  1421. package/dist/tempest-react-sdk.cjs +1 -1
  1422. package/dist/tempest-react-sdk.d.ts +448 -15
  1423. package/dist/tempest-react-sdk.js +119 -119
  1424. package/dist/testing/create-mock-handlers.cjs.map +1 -1
  1425. package/dist/testing/create-mock-handlers.js.map +1 -1
  1426. package/dist/testing.js +1 -2
  1427. package/dist/theme/ThemeProvider.cjs.map +1 -1
  1428. package/dist/theme/ThemeProvider.js.map +1 -1
  1429. package/dist/theme/apply-theme.cjs.map +1 -1
  1430. package/dist/theme/apply-theme.js.map +1 -1
  1431. package/dist/theme/color.cjs.map +1 -1
  1432. package/dist/theme/color.js.map +1 -1
  1433. package/dist/theme/create-theme.cjs.map +1 -1
  1434. package/dist/theme/create-theme.js.map +1 -1
  1435. package/dist/theme/data-viz-ramps.cjs.map +1 -1
  1436. package/dist/theme/data-viz-ramps.js.map +1 -1
  1437. package/dist/theme/initial-theme.cjs.map +1 -1
  1438. package/dist/theme/initial-theme.js.map +1 -1
  1439. package/dist/theme/inverse-render.cjs.map +1 -1
  1440. package/dist/theme/inverse-render.js.map +1 -1
  1441. package/dist/theme/inverse-restore.cjs.map +1 -1
  1442. package/dist/theme/inverse-restore.js.map +1 -1
  1443. package/dist/theme/inverse-surface.cjs.map +1 -1
  1444. package/dist/theme/inverse-surface.js.map +1 -1
  1445. package/dist/theme/status-tokens.cjs.map +1 -1
  1446. package/dist/theme/status-tokens.js.map +1 -1
  1447. package/dist/theme/theme-presets.cjs.map +1 -1
  1448. package/dist/theme/theme-presets.js.map +1 -1
  1449. package/dist/utils/absent.cjs.map +1 -1
  1450. package/dist/utils/absent.js.map +1 -1
  1451. package/dist/utils/arrays.cjs.map +1 -1
  1452. package/dist/utils/arrays.js.map +1 -1
  1453. package/dist/utils/base64.cjs.map +1 -1
  1454. package/dist/utils/base64.js.map +1 -1
  1455. package/dist/utils/cn.cjs.map +1 -1
  1456. package/dist/utils/cn.js.map +1 -1
  1457. package/dist/utils/compare-values.cjs.map +1 -1
  1458. package/dist/utils/compare-values.js.map +1 -1
  1459. package/dist/utils/compressed-storage.cjs.map +1 -1
  1460. package/dist/utils/compressed-storage.js.map +1 -1
  1461. package/dist/utils/csv.cjs +3 -3
  1462. package/dist/utils/csv.cjs.map +1 -1
  1463. package/dist/utils/csv.js +11 -10
  1464. package/dist/utils/csv.js.map +1 -1
  1465. package/dist/utils/dev-mode.cjs.map +1 -1
  1466. package/dist/utils/dev-mode.js.map +1 -1
  1467. package/dist/utils/duplicate-instance.cjs.map +1 -1
  1468. package/dist/utils/duplicate-instance.js.map +1 -1
  1469. package/dist/utils/format.cjs.map +1 -1
  1470. package/dist/utils/format.js.map +1 -1
  1471. package/dist/utils/functions.cjs +1 -1
  1472. package/dist/utils/functions.cjs.map +1 -1
  1473. package/dist/utils/functions.js +1 -1
  1474. package/dist/utils/functions.js.map +1 -1
  1475. package/dist/utils/guards.cjs.map +1 -1
  1476. package/dist/utils/guards.js.map +1 -1
  1477. package/dist/utils/ids.cjs.map +1 -1
  1478. package/dist/utils/ids.js.map +1 -1
  1479. package/dist/utils/intl-cache.cjs.map +1 -1
  1480. package/dist/utils/intl-cache.js.map +1 -1
  1481. package/dist/utils/json-frame.cjs.map +1 -1
  1482. package/dist/utils/json-frame.js.map +1 -1
  1483. package/dist/utils/numbers.cjs.map +1 -1
  1484. package/dist/utils/numbers.js.map +1 -1
  1485. package/dist/utils/objects.cjs.map +1 -1
  1486. package/dist/utils/objects.js.map +1 -1
  1487. package/dist/{telemetry/app-error-owner.cjs → utils/owner-fingerprint.cjs} +2 -2
  1488. package/dist/utils/owner-fingerprint.cjs.map +1 -0
  1489. package/dist/{telemetry/app-error-owner.js → utils/owner-fingerprint.js} +3 -3
  1490. package/dist/utils/owner-fingerprint.js.map +1 -0
  1491. package/dist/utils/promises.cjs.map +1 -1
  1492. package/dist/utils/promises.js.map +1 -1
  1493. package/dist/utils/relative-time.cjs.map +1 -1
  1494. package/dist/utils/relative-time.js.map +1 -1
  1495. package/dist/utils/safe-url.cjs.map +1 -1
  1496. package/dist/utils/safe-url.js.map +1 -1
  1497. package/dist/utils/schema-like.cjs.map +1 -1
  1498. package/dist/utils/schema-like.js.map +1 -1
  1499. package/dist/utils/storage.cjs +1 -1
  1500. package/dist/utils/storage.cjs.map +1 -1
  1501. package/dist/utils/storage.js +2 -2
  1502. package/dist/utils/storage.js.map +1 -1
  1503. package/dist/utils/strings.cjs.map +1 -1
  1504. package/dist/utils/strings.js.map +1 -1
  1505. package/dist/utils/xlsx.cjs.map +1 -1
  1506. package/dist/utils/xlsx.js.map +1 -1
  1507. package/dist/vision/core/canvas.cjs.map +1 -1
  1508. package/dist/vision/core/canvas.js.map +1 -1
  1509. package/dist/vision/core/dtypes.cjs.map +1 -1
  1510. package/dist/vision/core/dtypes.js.map +1 -1
  1511. package/dist/vision/core/exceptions.cjs.map +1 -1
  1512. package/dist/vision/core/exceptions.js.map +1 -1
  1513. package/dist/vision/core/graph.cjs.map +1 -1
  1514. package/dist/vision/core/graph.js.map +1 -1
  1515. package/dist/vision/core/metadata.cjs +1 -1
  1516. package/dist/vision/core/metadata.cjs.map +1 -1
  1517. package/dist/vision/core/metadata.js +9 -26
  1518. package/dist/vision/core/metadata.js.map +1 -1
  1519. package/dist/vision/core/providers.cjs.map +1 -1
  1520. package/dist/vision/core/providers.js.map +1 -1
  1521. package/dist/vision/core/session.cjs.map +1 -1
  1522. package/dist/vision/core/session.js.map +1 -1
  1523. package/dist/vision/core/timing.cjs.map +1 -1
  1524. package/dist/vision/core/timing.js.map +1 -1
  1525. package/dist/vision/fusion.cjs.map +1 -1
  1526. package/dist/vision/fusion.js.map +1 -1
  1527. package/dist/vision/index.cjs.map +1 -1
  1528. package/dist/vision/index.js.map +1 -1
  1529. package/dist/vision/io/image.cjs.map +1 -1
  1530. package/dist/vision/io/image.js.map +1 -1
  1531. package/dist/vision/labels.cjs.map +1 -1
  1532. package/dist/vision/labels.js.map +1 -1
  1533. package/dist/vision/luminance.cjs.map +1 -1
  1534. package/dist/vision/luminance.js.map +1 -1
  1535. package/dist/vision/normalization.cjs.map +1 -1
  1536. package/dist/vision/normalization.js.map +1 -1
  1537. package/dist/vision/postprocess/classification.cjs.map +1 -1
  1538. package/dist/vision/postprocess/classification.js.map +1 -1
  1539. package/dist/vision/postprocess/detection.cjs.map +1 -1
  1540. package/dist/vision/postprocess/detection.js.map +1 -1
  1541. package/dist/vision/postprocess/segmentation.cjs.map +1 -1
  1542. package/dist/vision/postprocess/segmentation.js.map +1 -1
  1543. package/dist/vision/preprocess/image.cjs.map +1 -1
  1544. package/dist/vision/preprocess/image.js.map +1 -1
  1545. package/dist/vision/preprocess/pipeline.cjs.map +1 -1
  1546. package/dist/vision/preprocess/pipeline.js.map +1 -1
  1547. package/dist/vision/results.cjs.map +1 -1
  1548. package/dist/vision/results.js.map +1 -1
  1549. package/dist/vision/tasks/base.cjs.map +1 -1
  1550. package/dist/vision/tasks/base.js.map +1 -1
  1551. package/dist/vision/tasks/classifier.cjs.map +1 -1
  1552. package/dist/vision/tasks/classifier.js.map +1 -1
  1553. package/dist/vision/tasks/detectClassify.cjs.map +1 -1
  1554. package/dist/vision/tasks/detectClassify.js.map +1 -1
  1555. package/dist/vision/tasks/detector.cjs.map +1 -1
  1556. package/dist/vision/tasks/detector.js.map +1 -1
  1557. package/dist/vision/tasks/segmenter.cjs.map +1 -1
  1558. package/dist/vision/tasks/segmenter.js.map +1 -1
  1559. package/dist/vision/types.cjs.map +1 -1
  1560. package/dist/vision/types.js.map +1 -1
  1561. package/dist/vision/use-camera-stream.cjs +1 -1
  1562. package/dist/vision/use-camera-stream.cjs.map +1 -1
  1563. package/dist/vision/use-camera-stream.js +3 -9
  1564. package/dist/vision/use-camera-stream.js.map +1 -1
  1565. package/dist/vision/use-live-luminance.cjs +1 -1
  1566. package/dist/vision/use-live-luminance.cjs.map +1 -1
  1567. package/dist/vision/use-live-luminance.js +1 -5
  1568. package/dist/vision/use-live-luminance.js.map +1 -1
  1569. package/dist/vite/base-url.cjs.map +1 -1
  1570. package/dist/vite/base-url.js.map +1 -1
  1571. package/dist/vite/create-vite-config.cjs.map +1 -1
  1572. package/dist/vite/create-vite-config.js.map +1 -1
  1573. package/dist/vite/narrow-tokens.cjs.map +1 -1
  1574. package/dist/vite/narrow-tokens.js.map +1 -1
  1575. package/dist/vite/tempest-csp.cjs +2 -2
  1576. package/dist/vite/tempest-csp.cjs.map +1 -1
  1577. package/dist/vite/tempest-csp.js +69 -66
  1578. package/dist/vite/tempest-csp.js.map +1 -1
  1579. package/dist/vite/tempest-icons.cjs.map +1 -1
  1580. package/dist/vite/tempest-icons.js.map +1 -1
  1581. package/dist/vite/tempest-pwa-dev-sw.cjs +1 -1
  1582. package/dist/vite/tempest-pwa-dev-sw.cjs.map +1 -1
  1583. package/dist/vite/tempest-pwa-dev-sw.js +9 -16
  1584. package/dist/vite/tempest-pwa-dev-sw.js.map +1 -1
  1585. package/dist/vite/tempest-pwa-icons.cjs.map +1 -1
  1586. package/dist/vite/tempest-pwa-icons.js.map +1 -1
  1587. package/dist/vite/tempest-pwa-manifest.cjs.map +1 -1
  1588. package/dist/vite/tempest-pwa-manifest.js.map +1 -1
  1589. package/dist/vite/tempest-styles.cjs.map +1 -1
  1590. package/dist/vite/tempest-styles.js.map +1 -1
  1591. package/dist/vite/tempest-vitest.cjs.map +1 -1
  1592. package/dist/vite/tempest-vitest.js.map +1 -1
  1593. package/dist/vite.d.ts +5 -3
  1594. package/dist/webrtc/link-stats.cjs.map +1 -1
  1595. package/dist/webrtc/link-stats.js.map +1 -1
  1596. package/dist/webrtc/mesh-quality.cjs.map +1 -1
  1597. package/dist/webrtc/mesh-quality.js.map +1 -1
  1598. package/dist/webrtc/opus-sdp.cjs.map +1 -1
  1599. package/dist/webrtc/opus-sdp.js.map +1 -1
  1600. package/dist/webrtc/peer-link.cjs +1 -1
  1601. package/dist/webrtc/peer-link.cjs.map +1 -1
  1602. package/dist/webrtc/peer-link.js +2 -5
  1603. package/dist/webrtc/peer-link.js.map +1 -1
  1604. package/dist/webrtc/peer-mesh.cjs +1 -1
  1605. package/dist/webrtc/peer-mesh.cjs.map +1 -1
  1606. package/dist/webrtc/peer-mesh.js +8 -24
  1607. package/dist/webrtc/peer-mesh.js.map +1 -1
  1608. package/dist/webrtc/sender-bitrate.cjs.map +1 -1
  1609. package/dist/webrtc/sender-bitrate.js.map +1 -1
  1610. package/dist/webrtc/use-link-stats.cjs.map +1 -1
  1611. package/dist/webrtc/use-link-stats.js.map +1 -1
  1612. package/dist/ws/create-web-socket.cjs +1 -1
  1613. package/dist/ws/create-web-socket.cjs.map +1 -1
  1614. package/dist/ws/create-web-socket.js +4 -22
  1615. package/dist/ws/create-web-socket.js.map +1 -1
  1616. package/dist/ws/resilience.cjs.map +1 -1
  1617. package/dist/ws/resilience.js.map +1 -1
  1618. package/dist/ws/use-web-socket.cjs.map +1 -1
  1619. package/dist/ws/use-web-socket.js.map +1 -1
  1620. package/package.json +9 -6
  1621. package/template/package.json +1 -1
  1622. package/dist/telemetry/app-error-owner.cjs.map +0 -1
  1623. package/dist/telemetry/app-error-owner.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"ChatAttachments.js","names":[],"sources":["../../../src/components/Chat/ChatAttachments.tsx"],"sourcesContent":["import { useState } from \"react\";\n\nimport { formatBytes } from \"@/utils/numbers\";\nimport { safeAttachmentUrl } from \"@/utils/safe-url\";\n\nimport { AudioPlayer } from \"../AudioPlayer\";\nimport { Lightbox } from \"../Lightbox\";\nimport { VideoPlayer } from \"../VideoPlayer\";\nimport type { ChatAttachment } from \"./chat-groups\";\nimport styles from \"./Chat.module.css\";\n\n/** Strings this view needs, passed in so the locale table stays in one file. */\nexport interface ChatAttachmentStrings {\n voiceNote: string;\n download: string;\n}\n\nexport interface ChatAttachmentsProps {\n /** What this message carries. */\n attachments: readonly ChatAttachment[];\n /** Labels, from `chatStrings(locale)`. */\n strings: ChatAttachmentStrings;\n}\n\n/** Bars a voice note draws when the app gave no peaks. */\nconst FLAT_WAVEFORM = Array.from({ length: 28 }, () => 0.25);\n\n/** `1:04` from milliseconds — a duration, never a clock time. */\nfunction durationLabel(durationMs: number): string {\n const total = Math.round(durationMs / 1000);\n const minutes = Math.floor(total / 60);\n const seconds = total % 60;\n return `${minutes}:${String(seconds).padStart(2, \"0\")}`;\n}\n\n/**\n * The media half of a bubble.\n *\n * Kept in its own module, and reached through `lazy()` from the thread, because\n * it pulls three of the heaviest components in the SDK — `Lightbox`,\n * `VideoPlayer`, `AudioPlayer` — and a support thread of plain text should not\n * pay for a photo viewer it never opens. The thread renders it only for messages\n * that actually carry an attachment, so that chunk is requested the first time\n * one appears.\n *\n * Nothing here is new UI: an image opens the SDK's lightbox, a video and an audio\n * clip use the SDK's players, and a file is a download row. That composition is\n * the whole point — every app was writing it again, the same way.\n *\n * The file row is the one place a sender's URL becomes an `href`, so it goes\n * through {@link safeAttachmentUrl}: `http:`, `https:`, `blob:` and relative URLs\n * are linked, anything else renders the same row without a link (#447). Media\n * `src` is left as given — an `<img>`, `<video>` or `<audio>` does not run a\n * `javascript:` URL.\n *\n * @param props - The attachments and the locale strings.\n * @returns The rendered attachment list.\n */\nexport function ChatAttachments({ attachments, strings }: ChatAttachmentsProps) {\n const images = attachments.filter((attachment) => attachment.kind === \"image\");\n const [lightboxIndex, setLightboxIndex] = useState<number | null>(null);\n\n return (\n <div className={styles.attachments}>\n {attachments.map((attachment, index) => {\n const key = `${attachment.kind}-${attachment.url}-${index}`;\n if (attachment.kind === \"image\") {\n const position = images.indexOf(attachment);\n return (\n <button\n key={key}\n type=\"button\"\n className={styles.imageAttachment}\n onClick={() => setLightboxIndex(position)}\n >\n <img\n src={attachment.thumbnailUrl ?? attachment.url}\n alt={attachment.alt ?? attachment.name ?? \"\"}\n loading=\"lazy\"\n />\n </button>\n );\n }\n if (attachment.kind === \"video\") {\n return (\n <VideoPlayer\n key={key}\n src={attachment.url}\n durationMs={attachment.durationMs}\n poster={attachment.thumbnailUrl}\n className={styles.videoAttachment}\n />\n );\n }\n if (attachment.kind === \"voice\") {\n return (\n <div key={key} className={styles.voiceAttachment}>\n <div className={styles.waveform} aria-hidden=\"true\">\n {(attachment.waveform ?? FLAT_WAVEFORM).map((peak, bar) => (\n <span\n key={bar}\n style={{\n height: `${Math.max(8, Math.min(100, peak * 100))}%`,\n }}\n />\n ))}\n </div>\n <AudioPlayer\n src={attachment.url}\n durationMs={attachment.durationMs}\n aria-label={strings.voiceNote}\n />\n </div>\n );\n }\n if (attachment.kind === \"audio\") {\n return (\n <AudioPlayer\n key={key}\n src={attachment.url}\n durationMs={attachment.durationMs}\n />\n );\n }\n const href = safeAttachmentUrl(attachment.url);\n const row = (\n <>\n <span className={styles.fileName}>\n {attachment.name ?? strings.download}\n </span>\n <span className={styles.fileMeta}>\n {[\n attachment.sizeBytes !== undefined\n ? formatBytes(attachment.sizeBytes)\n : null,\n attachment.durationMs !== undefined\n ? durationLabel(attachment.durationMs)\n : null,\n ]\n .filter(Boolean)\n .join(\" · \")}\n </span>\n </>\n );\n return href ? (\n <a\n key={key}\n className={styles.fileAttachment}\n href={href}\n download={attachment.name ?? true}\n >\n {row}\n </a>\n ) : (\n <div key={key} className={styles.fileAttachment}>\n {row}\n </div>\n );\n })}\n\n {images.length > 0 && (\n <Lightbox\n items={images.map((image) => ({\n src: image.url,\n alt: image.alt ?? image.name ?? \"\",\n thumbnail: image.thumbnailUrl,\n }))}\n open={lightboxIndex !== null}\n index={lightboxIndex ?? 0}\n onIndexChange={setLightboxIndex}\n onClose={() => setLightboxIndex(null)}\n />\n )}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ChatAttachments.js","names":["styles","_Fragment","Chat_module_default","Fragment$1","FLAT_WAVEFORM","durationLabel","total","durationMs","minutes","seconds","ChatAttachments","images","attachments","attachment","lightboxIndex","setLightboxIndex","useState","key","index","position","VideoPlayer","peak","bar","AudioPlayer","strings","href","safeAttachmentUrl","row","formatBytes","Lightbox","image"],"sources":["../../../src/components/Chat/ChatAttachments.tsx"],"sourcesContent":["import { useState } from \"react\";\n\nimport { formatBytes } from \"@/utils/numbers\";\nimport { safeAttachmentUrl } from \"@/utils/safe-url\";\n\nimport { AudioPlayer } from \"../AudioPlayer\";\nimport { Lightbox } from \"../Lightbox\";\nimport { VideoPlayer } from \"../VideoPlayer\";\nimport type { ChatAttachment } from \"./chat-groups\";\nimport styles from \"./Chat.module.css\";\n\n/** Strings this view needs, passed in so the locale table stays in one file. */\nexport interface ChatAttachmentStrings {\n voiceNote: string;\n download: string;\n}\n\nexport interface ChatAttachmentsProps {\n /** What this message carries. */\n attachments: readonly ChatAttachment[];\n /** Labels, from `chatStrings(locale)`. */\n strings: ChatAttachmentStrings;\n}\n\n/** Bars a voice note draws when the app gave no peaks. */\nconst FLAT_WAVEFORM = Array.from({ length: 28 }, () => 0.25);\n\n/** `1:04` from milliseconds — a duration, never a clock time. */\nfunction durationLabel(durationMs: number): string {\n const total = Math.round(durationMs / 1000);\n const minutes = Math.floor(total / 60);\n const seconds = total % 60;\n return `${minutes}:${String(seconds).padStart(2, \"0\")}`;\n}\n\n/**\n * The media half of a bubble.\n *\n * Kept in its own module, and reached through `lazy()` from the thread, because\n * it pulls three of the heaviest components in the SDK — `Lightbox`,\n * `VideoPlayer`, `AudioPlayer` — and a support thread of plain text should not\n * pay for a photo viewer it never opens. The thread renders it only for messages\n * that actually carry an attachment, so that chunk is requested the first time\n * one appears.\n *\n * Nothing here is new UI: an image opens the SDK's lightbox, a video and an audio\n * clip use the SDK's players, and a file is a download row. That composition is\n * the whole point — every app was writing it again, the same way.\n *\n * The file row is the one place a sender's URL becomes an `href`, so it goes\n * through {@link safeAttachmentUrl}: `http:`, `https:`, `blob:` and relative URLs\n * are linked, anything else renders the same row without a link (#447). Media\n * `src` is left as given — an `<img>`, `<video>` or `<audio>` does not run a\n * `javascript:` URL.\n *\n * @param props - The attachments and the locale strings.\n * @returns The rendered attachment list.\n */\nexport function ChatAttachments({ attachments, strings }: ChatAttachmentsProps) {\n const images = attachments.filter((attachment) => attachment.kind === \"image\");\n const [lightboxIndex, setLightboxIndex] = useState<number | null>(null);\n\n return (\n <div className={styles.attachments}>\n {attachments.map((attachment, index) => {\n const key = `${attachment.kind}-${attachment.url}-${index}`;\n if (attachment.kind === \"image\") {\n const position = images.indexOf(attachment);\n return (\n <button\n key={key}\n type=\"button\"\n className={styles.imageAttachment}\n onClick={() => setLightboxIndex(position)}\n >\n <img\n src={attachment.thumbnailUrl ?? attachment.url}\n alt={attachment.alt ?? attachment.name ?? \"\"}\n loading=\"lazy\"\n />\n </button>\n );\n }\n if (attachment.kind === \"video\") {\n return (\n <VideoPlayer\n key={key}\n src={attachment.url}\n durationMs={attachment.durationMs}\n poster={attachment.thumbnailUrl}\n className={styles.videoAttachment}\n />\n );\n }\n if (attachment.kind === \"voice\") {\n return (\n <div key={key} className={styles.voiceAttachment}>\n <div className={styles.waveform} aria-hidden=\"true\">\n {(attachment.waveform ?? FLAT_WAVEFORM).map((peak, bar) => (\n <span\n key={bar}\n style={{\n height: `${Math.max(8, Math.min(100, peak * 100))}%`,\n }}\n />\n ))}\n </div>\n <AudioPlayer\n src={attachment.url}\n durationMs={attachment.durationMs}\n aria-label={strings.voiceNote}\n />\n </div>\n );\n }\n if (attachment.kind === \"audio\") {\n return (\n <AudioPlayer\n key={key}\n src={attachment.url}\n durationMs={attachment.durationMs}\n />\n );\n }\n const href = safeAttachmentUrl(attachment.url);\n const row = (\n <>\n <span className={styles.fileName}>\n {attachment.name ?? strings.download}\n </span>\n <span className={styles.fileMeta}>\n {[\n attachment.sizeBytes !== undefined\n ? formatBytes(attachment.sizeBytes)\n : null,\n attachment.durationMs !== undefined\n ? durationLabel(attachment.durationMs)\n : null,\n ]\n .filter(Boolean)\n .join(\" · \")}\n </span>\n </>\n );\n return href ? (\n <a\n key={key}\n className={styles.fileAttachment}\n href={href}\n download={attachment.name ?? true}\n >\n {row}\n </a>\n ) : (\n <div key={key} className={styles.fileAttachment}>\n {row}\n </div>\n );\n })}\n\n {images.length > 0 && (\n <Lightbox\n items={images.map((image) => ({\n src: image.url,\n alt: image.alt ?? image.name ?? \"\",\n thumbnail: image.thumbnailUrl,\n }))}\n open={lightboxIndex !== null}\n index={lightboxIndex ?? 0}\n onIndexChange={setLightboxIndex}\n onClose={() => setLightboxIndex(null)}\n />\n )}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ChatBubble.cjs","names":[],"sources":["../../../src/components/Chat/ChatBubble.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines props-count function-lines — one bubble is one unit of\n * layout, and every part of it reads from the same message: the quote above the\n * body, the body or its tombstone, the attachments, the reactions under it, and the\n * timestamp with its ticks. Splitting them would pass the same message to six\n * components and put the bubble's geometry in none of them.\n */\nimport { Suspense, lazy, type ReactNode } from \"react\";\n\nimport { cn } from \"@/utils/cn\";\n\nimport type { ContextMenuItem } from \"../ContextMenu\";\nimport { VisuallyHidden } from \"../VisuallyHidden\";\nimport { chatStrings, timeLabel, type ChatMessage } from \"./chat-groups\";\nimport { receiptLabel, resolveReceiptState } from \"./chat-receipt\";\nimport styles from \"./Chat.module.css\";\n\nconst ChatAttachments = lazy(() =>\n import(\"./ChatAttachments\").then((module) => ({ default: module.ChatAttachments })),\n);\n\nconst ChatActionsMenu = lazy(() =>\n import(\"./ChatActionsMenu\").then((module) => ({ default: module.ChatActionsMenu })),\n);\n\n/** Glyph per tick state. `delivered` is the one a boolean `status` cannot say. */\nconst RECEIPT_GLYPH = {\n sending: \"◌\",\n sent: \"✓\",\n delivered: \"✓✓\",\n read: \"✓✓\",\n failed: \"!\",\n} as const;\n\nexport interface ChatBubbleProps {\n /** The message this bubble renders. */\n message: ChatMessage;\n /** Whether it belongs to the current user — side, colour and ticks. */\n own: boolean;\n /** Locale for labels. */\n locale: \"pt-BR\" | \"en\";\n /** Retry handler for a `\"failed\"` message. */\n onRetry?: (message: ChatMessage) => void;\n /** Toggles a reaction. Receives the emoji that was pressed. */\n onReact?: (message: ChatMessage, emoji: string) => void;\n /** Per-message actions, opened by right click, long press or the ⋮ button. */\n messageActions?: (message: ChatMessage) => ContextMenuItem[];\n /** Called when the quote stub is activated — scroll to the quoted message. */\n onQuoteClick?: (message: ChatMessage) => void;\n}\n\n/**\n * One message bubble.\n *\n * Everything a messenger needs on a single message lives here, because every one\n * of these was a thing each app rebuilt on top of a text-only bubble: the reply\n * stub, attachments, reactions, per-recipient ticks, the actions menu, and the\n * tombstone of a deleted message.\n *\n * @param props - The message and its handlers.\n * @returns The bubble, wrapped in a context menu when actions are given.\n */\nexport function ChatBubble({\n message,\n own,\n locale,\n onRetry,\n onReact,\n messageActions,\n onQuoteClick,\n}: ChatBubbleProps) {\n const strings = chatStrings(locale);\n const receiptState = own ? resolveReceiptState(message) : null;\n const actions = message.deleted ? [] : (messageActions?.(message) ?? []);\n\n const bubble = (\n <div\n className={cn(\n styles.bubble,\n own && styles.ownBubble,\n message.deleted && styles.deletedBubble,\n message.status === \"failed\" && styles.failedBubble,\n )}\n >\n {message.quote && !message.deleted && (\n <QuoteStub message={message} locale={locale} onQuoteClick={onQuoteClick} />\n )}\n\n {message.deleted ? (\n <div className={styles.tombstone}>\n <span aria-hidden=\"true\">🚫</span> {strings.deleted}\n </div>\n ) : (\n <>\n {message.attachments && message.attachments.length > 0 && (\n <Suspense fallback={<div className={styles.attachmentsFallback} />}>\n <ChatAttachments attachments={message.attachments} strings={strings} />\n </Suspense>\n )}\n {message.body !== undefined && message.body !== null && message.body !== \"\" && (\n <div className={styles.body}>{message.body}</div>\n )}\n </>\n )}\n\n <div className={styles.meta}>\n {message.edited && !message.deleted && (\n <span className={styles.edited}>{strings.edited}</span>\n )}\n <time dateTime={new Date(message.sentAt).toISOString()}>\n {timeLabel(message.sentAt, locale)}\n </time>\n {receiptState && <Receipt message={message} state={receiptState} locale={locale} />}\n </div>\n </div>\n );\n\n return (\n <li className={styles.bubbleRow}>\n {actions.length > 0 ? (\n <Suspense fallback={bubble}>\n <ChatActionsMenu items={actions} trigger=\"contextmenu\">\n {bubble}\n </ChatActionsMenu>\n </Suspense>\n ) : (\n bubble\n )}\n\n {actions.length > 0 && (\n <Suspense fallback={null}>\n <ChatActionsMenu items={actions} trigger=\"click\">\n <button\n type=\"button\"\n className={styles.actionsButton}\n aria-label={strings.messageActions}\n >\n <span aria-hidden=\"true\">⋮</span>\n </button>\n </ChatActionsMenu>\n </Suspense>\n )}\n\n {message.reactions && message.reactions.length > 0 && (\n <ul className={styles.reactions} aria-label={strings.reactions}>\n {message.reactions.map((reaction) => (\n <li key={reaction.emoji}>\n <button\n type=\"button\"\n className={cn(\n styles.reaction,\n reaction.reacted && styles.reactionMine,\n )}\n aria-pressed={reaction.reacted ?? false}\n title={reaction.names?.join(\", \")}\n disabled={!onReact}\n onClick={() => onReact?.(message, reaction.emoji)}\n >\n <span aria-hidden=\"true\">\n {reaction.emoji} {reaction.count}\n </span>\n <VisuallyHidden>\n {strings.react(reaction.emoji, reaction.count)}\n </VisuallyHidden>\n </button>\n </li>\n ))}\n </ul>\n )}\n\n {message.status === \"failed\" && onRetry && (\n <button type=\"button\" className={styles.retry} onClick={() => onRetry(message)}>\n {strings.retry}\n </button>\n )}\n </li>\n );\n}\n\n/** The reply stub above a body, or its blanked form once the target is gone. */\nfunction QuoteStub({\n message,\n locale,\n onQuoteClick,\n}: {\n message: ChatMessage;\n locale: \"pt-BR\" | \"en\";\n onQuoteClick?: (message: ChatMessage) => void;\n}): ReactNode {\n const strings = chatStrings(locale);\n const quote = message.quote;\n if (!quote) return null;\n const label = quote.revoked\n ? strings.quoteRevoked\n : (quote.excerpt ??\n (quote.kind && quote.kind !== \"text\" ? strings.quoteKind[quote.kind] : \"\"));\n\n const content = (\n <>\n <span className={styles.quoteAuthor}>\n {quote.senderName ?? strings.replyingTo(quote.messageId)}\n </span>\n <span className={cn(styles.quoteText, quote.revoked && styles.quoteRevoked)}>\n {label}\n </span>\n </>\n );\n\n return onQuoteClick ? (\n <button\n type=\"button\"\n className={cn(styles.quote, styles.quoteButton)}\n onClick={() => onQuoteClick(message)}\n >\n {content}\n </button>\n ) : (\n <div className={styles.quote}>{content}</div>\n );\n}\n\n/** The ticks, and the sentence behind them. */\nfunction Receipt({\n message,\n state,\n locale,\n}: {\n message: ChatMessage;\n state: keyof typeof RECEIPT_GLYPH;\n locale: \"pt-BR\" | \"en\";\n}): ReactNode {\n const strings = chatStrings(locale);\n const label =\n message.receipt && message.receipt.totalRecipients > 0 && state !== \"failed\"\n ? receiptLabel(message.receipt, strings)\n : strings[state === \"delivered\" ? \"sent\" : state];\n\n return (\n <span\n className={cn(\n styles.status,\n state === \"read\" && styles.statusRead,\n state === \"failed\" && styles.statusFailed,\n )}\n title={label}\n >\n <span aria-hidden=\"true\">{RECEIPT_GLYPH[state]}</span>\n <VisuallyHidden>{label}</VisuallyHidden>\n </span>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ChatBubble.cjs","names":["lazy","chatStrings","resolveReceiptState","cn","styles","_Fragment","Suspense","timeLabel","VisuallyHidden","receiptLabel","require_cn","require_VisuallyHidden","require_chat_groups","require_chat_receipt","require_Chat_module","react","react_jsx_runtime","ChatAttachments","module","ChatActionsMenu","RECEIPT_GLYPH","ChatBubble","strings","locale","receiptState","own","message","actions","messageActions","bubble","QuoteStub","Receipt","reaction","onReact","onRetry","quote","label","content","onQuoteClick","state"],"sources":["../../../src/components/Chat/ChatBubble.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines props-count function-lines — one bubble is one unit of\n * layout, and every part of it reads from the same message: the quote above the\n * body, the body or its tombstone, the attachments, the reactions under it, and the\n * timestamp with its ticks. Splitting them would pass the same message to six\n * components and put the bubble's geometry in none of them.\n */\nimport { Suspense, lazy, type ReactNode } from \"react\";\n\nimport { cn } from \"@/utils/cn\";\n\nimport type { ContextMenuItem } from \"../ContextMenu\";\nimport { VisuallyHidden } from \"../VisuallyHidden\";\nimport { chatStrings, timeLabel, type ChatMessage } from \"./chat-groups\";\nimport { receiptLabel, resolveReceiptState } from \"./chat-receipt\";\nimport styles from \"./Chat.module.css\";\n\nconst ChatAttachments = lazy(() =>\n import(\"./ChatAttachments\").then((module) => ({ default: module.ChatAttachments })),\n);\n\nconst ChatActionsMenu = lazy(() =>\n import(\"./ChatActionsMenu\").then((module) => ({ default: module.ChatActionsMenu })),\n);\n\n/** Glyph per tick state. `delivered` is the one a boolean `status` cannot say. */\nconst RECEIPT_GLYPH = {\n sending: \"◌\",\n sent: \"✓\",\n delivered: \"✓✓\",\n read: \"✓✓\",\n failed: \"!\",\n} as const;\n\nexport interface ChatBubbleProps {\n /** The message this bubble renders. */\n message: ChatMessage;\n /** Whether it belongs to the current user — side, colour and ticks. */\n own: boolean;\n /** Locale for labels. */\n locale: \"pt-BR\" | \"en\";\n /** Retry handler for a `\"failed\"` message. */\n onRetry?: (message: ChatMessage) => void;\n /** Toggles a reaction. Receives the emoji that was pressed. */\n onReact?: (message: ChatMessage, emoji: string) => void;\n /** Per-message actions, opened by right click, long press or the ⋮ button. */\n messageActions?: (message: ChatMessage) => ContextMenuItem[];\n /** Called when the quote stub is activated — scroll to the quoted message. */\n onQuoteClick?: (message: ChatMessage) => void;\n}\n\n/**\n * One message bubble.\n *\n * Everything a messenger needs on a single message lives here, because every one\n * of these was a thing each app rebuilt on top of a text-only bubble: the reply\n * stub, attachments, reactions, per-recipient ticks, the actions menu, and the\n * tombstone of a deleted message.\n *\n * @param props - The message and its handlers.\n * @returns The bubble, wrapped in a context menu when actions are given.\n */\nexport function ChatBubble({\n message,\n own,\n locale,\n onRetry,\n onReact,\n messageActions,\n onQuoteClick,\n}: ChatBubbleProps) {\n const strings = chatStrings(locale);\n const receiptState = own ? resolveReceiptState(message) : null;\n const actions = message.deleted ? [] : (messageActions?.(message) ?? []);\n\n const bubble = (\n <div\n className={cn(\n styles.bubble,\n own && styles.ownBubble,\n message.deleted && styles.deletedBubble,\n message.status === \"failed\" && styles.failedBubble,\n )}\n >\n {message.quote && !message.deleted && (\n <QuoteStub message={message} locale={locale} onQuoteClick={onQuoteClick} />\n )}\n\n {message.deleted ? (\n <div className={styles.tombstone}>\n <span aria-hidden=\"true\">🚫</span> {strings.deleted}\n </div>\n ) : (\n <>\n {message.attachments && message.attachments.length > 0 && (\n <Suspense fallback={<div className={styles.attachmentsFallback} />}>\n <ChatAttachments attachments={message.attachments} strings={strings} />\n </Suspense>\n )}\n {message.body !== undefined && message.body !== null && message.body !== \"\" && (\n <div className={styles.body}>{message.body}</div>\n )}\n </>\n )}\n\n <div className={styles.meta}>\n {message.edited && !message.deleted && (\n <span className={styles.edited}>{strings.edited}</span>\n )}\n <time dateTime={new Date(message.sentAt).toISOString()}>\n {timeLabel(message.sentAt, locale)}\n </time>\n {receiptState && <Receipt message={message} state={receiptState} locale={locale} />}\n </div>\n </div>\n );\n\n return (\n <li className={styles.bubbleRow}>\n {actions.length > 0 ? (\n <Suspense fallback={bubble}>\n <ChatActionsMenu items={actions} trigger=\"contextmenu\">\n {bubble}\n </ChatActionsMenu>\n </Suspense>\n ) : (\n bubble\n )}\n\n {actions.length > 0 && (\n <Suspense fallback={null}>\n <ChatActionsMenu items={actions} trigger=\"click\">\n <button\n type=\"button\"\n className={styles.actionsButton}\n aria-label={strings.messageActions}\n >\n <span aria-hidden=\"true\">⋮</span>\n </button>\n </ChatActionsMenu>\n </Suspense>\n )}\n\n {message.reactions && message.reactions.length > 0 && (\n <ul className={styles.reactions} aria-label={strings.reactions}>\n {message.reactions.map((reaction) => (\n <li key={reaction.emoji}>\n <button\n type=\"button\"\n className={cn(\n styles.reaction,\n reaction.reacted && styles.reactionMine,\n )}\n aria-pressed={reaction.reacted ?? false}\n title={reaction.names?.join(\", \")}\n disabled={!onReact}\n onClick={() => onReact?.(message, reaction.emoji)}\n >\n <span aria-hidden=\"true\">\n {reaction.emoji} {reaction.count}\n </span>\n <VisuallyHidden>\n {strings.react(reaction.emoji, reaction.count)}\n </VisuallyHidden>\n </button>\n </li>\n ))}\n </ul>\n )}\n\n {message.status === \"failed\" && onRetry && (\n <button type=\"button\" className={styles.retry} onClick={() => onRetry(message)}>\n {strings.retry}\n </button>\n )}\n </li>\n );\n}\n\n/** The reply stub above a body, or its blanked form once the target is gone. */\nfunction QuoteStub({\n message,\n locale,\n onQuoteClick,\n}: {\n message: ChatMessage;\n locale: \"pt-BR\" | \"en\";\n onQuoteClick?: (message: ChatMessage) => void;\n}): ReactNode {\n const strings = chatStrings(locale);\n const quote = message.quote;\n if (!quote) return null;\n const label = quote.revoked\n ? strings.quoteRevoked\n : (quote.excerpt ??\n (quote.kind && quote.kind !== \"text\" ? strings.quoteKind[quote.kind] : \"\"));\n\n const content = (\n <>\n <span className={styles.quoteAuthor}>\n {quote.senderName ?? strings.replyingTo(quote.messageId)}\n </span>\n <span className={cn(styles.quoteText, quote.revoked && styles.quoteRevoked)}>\n {label}\n </span>\n </>\n );\n\n return onQuoteClick ? (\n <button\n type=\"button\"\n className={cn(styles.quote, styles.quoteButton)}\n onClick={() => onQuoteClick(message)}\n >\n {content}\n </button>\n ) : (\n <div className={styles.quote}>{content}</div>\n );\n}\n\n/** The ticks, and the sentence behind them. */\nfunction Receipt({\n message,\n state,\n locale,\n}: {\n message: ChatMessage;\n state: keyof typeof RECEIPT_GLYPH;\n locale: \"pt-BR\" | \"en\";\n}): ReactNode {\n const strings = chatStrings(locale);\n const label =\n message.receipt && message.receipt.totalRecipients > 0 && state !== \"failed\"\n ? receiptLabel(message.receipt, strings)\n : strings[state === \"delivered\" ? \"sent\" : state];\n\n return (\n <span\n className={cn(\n styles.status,\n state === \"read\" && styles.statusRead,\n state === \"failed\" && styles.statusFailed,\n )}\n title={label}\n >\n <span aria-hidden=\"true\">{RECEIPT_GLYPH[state]}</span>\n <VisuallyHidden>{label}</VisuallyHidden>\n </span>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ChatBubble.js","names":[],"sources":["../../../src/components/Chat/ChatBubble.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines props-count function-lines — one bubble is one unit of\n * layout, and every part of it reads from the same message: the quote above the\n * body, the body or its tombstone, the attachments, the reactions under it, and the\n * timestamp with its ticks. Splitting them would pass the same message to six\n * components and put the bubble's geometry in none of them.\n */\nimport { Suspense, lazy, type ReactNode } from \"react\";\n\nimport { cn } from \"@/utils/cn\";\n\nimport type { ContextMenuItem } from \"../ContextMenu\";\nimport { VisuallyHidden } from \"../VisuallyHidden\";\nimport { chatStrings, timeLabel, type ChatMessage } from \"./chat-groups\";\nimport { receiptLabel, resolveReceiptState } from \"./chat-receipt\";\nimport styles from \"./Chat.module.css\";\n\nconst ChatAttachments = lazy(() =>\n import(\"./ChatAttachments\").then((module) => ({ default: module.ChatAttachments })),\n);\n\nconst ChatActionsMenu = lazy(() =>\n import(\"./ChatActionsMenu\").then((module) => ({ default: module.ChatActionsMenu })),\n);\n\n/** Glyph per tick state. `delivered` is the one a boolean `status` cannot say. */\nconst RECEIPT_GLYPH = {\n sending: \"◌\",\n sent: \"✓\",\n delivered: \"✓✓\",\n read: \"✓✓\",\n failed: \"!\",\n} as const;\n\nexport interface ChatBubbleProps {\n /** The message this bubble renders. */\n message: ChatMessage;\n /** Whether it belongs to the current user — side, colour and ticks. */\n own: boolean;\n /** Locale for labels. */\n locale: \"pt-BR\" | \"en\";\n /** Retry handler for a `\"failed\"` message. */\n onRetry?: (message: ChatMessage) => void;\n /** Toggles a reaction. Receives the emoji that was pressed. */\n onReact?: (message: ChatMessage, emoji: string) => void;\n /** Per-message actions, opened by right click, long press or the ⋮ button. */\n messageActions?: (message: ChatMessage) => ContextMenuItem[];\n /** Called when the quote stub is activated — scroll to the quoted message. */\n onQuoteClick?: (message: ChatMessage) => void;\n}\n\n/**\n * One message bubble.\n *\n * Everything a messenger needs on a single message lives here, because every one\n * of these was a thing each app rebuilt on top of a text-only bubble: the reply\n * stub, attachments, reactions, per-recipient ticks, the actions menu, and the\n * tombstone of a deleted message.\n *\n * @param props - The message and its handlers.\n * @returns The bubble, wrapped in a context menu when actions are given.\n */\nexport function ChatBubble({\n message,\n own,\n locale,\n onRetry,\n onReact,\n messageActions,\n onQuoteClick,\n}: ChatBubbleProps) {\n const strings = chatStrings(locale);\n const receiptState = own ? resolveReceiptState(message) : null;\n const actions = message.deleted ? [] : (messageActions?.(message) ?? []);\n\n const bubble = (\n <div\n className={cn(\n styles.bubble,\n own && styles.ownBubble,\n message.deleted && styles.deletedBubble,\n message.status === \"failed\" && styles.failedBubble,\n )}\n >\n {message.quote && !message.deleted && (\n <QuoteStub message={message} locale={locale} onQuoteClick={onQuoteClick} />\n )}\n\n {message.deleted ? (\n <div className={styles.tombstone}>\n <span aria-hidden=\"true\">🚫</span> {strings.deleted}\n </div>\n ) : (\n <>\n {message.attachments && message.attachments.length > 0 && (\n <Suspense fallback={<div className={styles.attachmentsFallback} />}>\n <ChatAttachments attachments={message.attachments} strings={strings} />\n </Suspense>\n )}\n {message.body !== undefined && message.body !== null && message.body !== \"\" && (\n <div className={styles.body}>{message.body}</div>\n )}\n </>\n )}\n\n <div className={styles.meta}>\n {message.edited && !message.deleted && (\n <span className={styles.edited}>{strings.edited}</span>\n )}\n <time dateTime={new Date(message.sentAt).toISOString()}>\n {timeLabel(message.sentAt, locale)}\n </time>\n {receiptState && <Receipt message={message} state={receiptState} locale={locale} />}\n </div>\n </div>\n );\n\n return (\n <li className={styles.bubbleRow}>\n {actions.length > 0 ? (\n <Suspense fallback={bubble}>\n <ChatActionsMenu items={actions} trigger=\"contextmenu\">\n {bubble}\n </ChatActionsMenu>\n </Suspense>\n ) : (\n bubble\n )}\n\n {actions.length > 0 && (\n <Suspense fallback={null}>\n <ChatActionsMenu items={actions} trigger=\"click\">\n <button\n type=\"button\"\n className={styles.actionsButton}\n aria-label={strings.messageActions}\n >\n <span aria-hidden=\"true\">⋮</span>\n </button>\n </ChatActionsMenu>\n </Suspense>\n )}\n\n {message.reactions && message.reactions.length > 0 && (\n <ul className={styles.reactions} aria-label={strings.reactions}>\n {message.reactions.map((reaction) => (\n <li key={reaction.emoji}>\n <button\n type=\"button\"\n className={cn(\n styles.reaction,\n reaction.reacted && styles.reactionMine,\n )}\n aria-pressed={reaction.reacted ?? false}\n title={reaction.names?.join(\", \")}\n disabled={!onReact}\n onClick={() => onReact?.(message, reaction.emoji)}\n >\n <span aria-hidden=\"true\">\n {reaction.emoji} {reaction.count}\n </span>\n <VisuallyHidden>\n {strings.react(reaction.emoji, reaction.count)}\n </VisuallyHidden>\n </button>\n </li>\n ))}\n </ul>\n )}\n\n {message.status === \"failed\" && onRetry && (\n <button type=\"button\" className={styles.retry} onClick={() => onRetry(message)}>\n {strings.retry}\n </button>\n )}\n </li>\n );\n}\n\n/** The reply stub above a body, or its blanked form once the target is gone. */\nfunction QuoteStub({\n message,\n locale,\n onQuoteClick,\n}: {\n message: ChatMessage;\n locale: \"pt-BR\" | \"en\";\n onQuoteClick?: (message: ChatMessage) => void;\n}): ReactNode {\n const strings = chatStrings(locale);\n const quote = message.quote;\n if (!quote) return null;\n const label = quote.revoked\n ? strings.quoteRevoked\n : (quote.excerpt ??\n (quote.kind && quote.kind !== \"text\" ? strings.quoteKind[quote.kind] : \"\"));\n\n const content = (\n <>\n <span className={styles.quoteAuthor}>\n {quote.senderName ?? strings.replyingTo(quote.messageId)}\n </span>\n <span className={cn(styles.quoteText, quote.revoked && styles.quoteRevoked)}>\n {label}\n </span>\n </>\n );\n\n return onQuoteClick ? (\n <button\n type=\"button\"\n className={cn(styles.quote, styles.quoteButton)}\n onClick={() => onQuoteClick(message)}\n >\n {content}\n </button>\n ) : (\n <div className={styles.quote}>{content}</div>\n );\n}\n\n/** The ticks, and the sentence behind them. */\nfunction Receipt({\n message,\n state,\n locale,\n}: {\n message: ChatMessage;\n state: keyof typeof RECEIPT_GLYPH;\n locale: \"pt-BR\" | \"en\";\n}): ReactNode {\n const strings = chatStrings(locale);\n const label =\n message.receipt && message.receipt.totalRecipients > 0 && state !== \"failed\"\n ? receiptLabel(message.receipt, strings)\n : strings[state === \"delivered\" ? \"sent\" : state];\n\n return (\n <span\n className={cn(\n styles.status,\n state === \"read\" && styles.statusRead,\n state === \"failed\" && styles.statusFailed,\n )}\n title={label}\n >\n <span aria-hidden=\"true\">{RECEIPT_GLYPH[state]}</span>\n <VisuallyHidden>{label}</VisuallyHidden>\n </span>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ChatBubble.js","names":["styles","_Fragment","Chat_module_default","Fragment$1","ChatAttachments","lazy","module","ChatActionsMenu","RECEIPT_GLYPH","ChatBubble","strings","chatStrings","locale","receiptState","own","resolveReceiptState","message","actions","messageActions","bubble","cn","QuoteStub","Suspense","timeLabel","Receipt","reaction","onReact","VisuallyHidden","onRetry","quote","label","content","onQuoteClick","state","receiptLabel"],"sources":["../../../src/components/Chat/ChatBubble.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines props-count function-lines — one bubble is one unit of\n * layout, and every part of it reads from the same message: the quote above the\n * body, the body or its tombstone, the attachments, the reactions under it, and the\n * timestamp with its ticks. Splitting them would pass the same message to six\n * components and put the bubble's geometry in none of them.\n */\nimport { Suspense, lazy, type ReactNode } from \"react\";\n\nimport { cn } from \"@/utils/cn\";\n\nimport type { ContextMenuItem } from \"../ContextMenu\";\nimport { VisuallyHidden } from \"../VisuallyHidden\";\nimport { chatStrings, timeLabel, type ChatMessage } from \"./chat-groups\";\nimport { receiptLabel, resolveReceiptState } from \"./chat-receipt\";\nimport styles from \"./Chat.module.css\";\n\nconst ChatAttachments = lazy(() =>\n import(\"./ChatAttachments\").then((module) => ({ default: module.ChatAttachments })),\n);\n\nconst ChatActionsMenu = lazy(() =>\n import(\"./ChatActionsMenu\").then((module) => ({ default: module.ChatActionsMenu })),\n);\n\n/** Glyph per tick state. `delivered` is the one a boolean `status` cannot say. */\nconst RECEIPT_GLYPH = {\n sending: \"◌\",\n sent: \"✓\",\n delivered: \"✓✓\",\n read: \"✓✓\",\n failed: \"!\",\n} as const;\n\nexport interface ChatBubbleProps {\n /** The message this bubble renders. */\n message: ChatMessage;\n /** Whether it belongs to the current user — side, colour and ticks. */\n own: boolean;\n /** Locale for labels. */\n locale: \"pt-BR\" | \"en\";\n /** Retry handler for a `\"failed\"` message. */\n onRetry?: (message: ChatMessage) => void;\n /** Toggles a reaction. Receives the emoji that was pressed. */\n onReact?: (message: ChatMessage, emoji: string) => void;\n /** Per-message actions, opened by right click, long press or the ⋮ button. */\n messageActions?: (message: ChatMessage) => ContextMenuItem[];\n /** Called when the quote stub is activated — scroll to the quoted message. */\n onQuoteClick?: (message: ChatMessage) => void;\n}\n\n/**\n * One message bubble.\n *\n * Everything a messenger needs on a single message lives here, because every one\n * of these was a thing each app rebuilt on top of a text-only bubble: the reply\n * stub, attachments, reactions, per-recipient ticks, the actions menu, and the\n * tombstone of a deleted message.\n *\n * @param props - The message and its handlers.\n * @returns The bubble, wrapped in a context menu when actions are given.\n */\nexport function ChatBubble({\n message,\n own,\n locale,\n onRetry,\n onReact,\n messageActions,\n onQuoteClick,\n}: ChatBubbleProps) {\n const strings = chatStrings(locale);\n const receiptState = own ? resolveReceiptState(message) : null;\n const actions = message.deleted ? [] : (messageActions?.(message) ?? []);\n\n const bubble = (\n <div\n className={cn(\n styles.bubble,\n own && styles.ownBubble,\n message.deleted && styles.deletedBubble,\n message.status === \"failed\" && styles.failedBubble,\n )}\n >\n {message.quote && !message.deleted && (\n <QuoteStub message={message} locale={locale} onQuoteClick={onQuoteClick} />\n )}\n\n {message.deleted ? (\n <div className={styles.tombstone}>\n <span aria-hidden=\"true\">🚫</span> {strings.deleted}\n </div>\n ) : (\n <>\n {message.attachments && message.attachments.length > 0 && (\n <Suspense fallback={<div className={styles.attachmentsFallback} />}>\n <ChatAttachments attachments={message.attachments} strings={strings} />\n </Suspense>\n )}\n {message.body !== undefined && message.body !== null && message.body !== \"\" && (\n <div className={styles.body}>{message.body}</div>\n )}\n </>\n )}\n\n <div className={styles.meta}>\n {message.edited && !message.deleted && (\n <span className={styles.edited}>{strings.edited}</span>\n )}\n <time dateTime={new Date(message.sentAt).toISOString()}>\n {timeLabel(message.sentAt, locale)}\n </time>\n {receiptState && <Receipt message={message} state={receiptState} locale={locale} />}\n </div>\n </div>\n );\n\n return (\n <li className={styles.bubbleRow}>\n {actions.length > 0 ? (\n <Suspense fallback={bubble}>\n <ChatActionsMenu items={actions} trigger=\"contextmenu\">\n {bubble}\n </ChatActionsMenu>\n </Suspense>\n ) : (\n bubble\n )}\n\n {actions.length > 0 && (\n <Suspense fallback={null}>\n <ChatActionsMenu items={actions} trigger=\"click\">\n <button\n type=\"button\"\n className={styles.actionsButton}\n aria-label={strings.messageActions}\n >\n <span aria-hidden=\"true\">⋮</span>\n </button>\n </ChatActionsMenu>\n </Suspense>\n )}\n\n {message.reactions && message.reactions.length > 0 && (\n <ul className={styles.reactions} aria-label={strings.reactions}>\n {message.reactions.map((reaction) => (\n <li key={reaction.emoji}>\n <button\n type=\"button\"\n className={cn(\n styles.reaction,\n reaction.reacted && styles.reactionMine,\n )}\n aria-pressed={reaction.reacted ?? false}\n title={reaction.names?.join(\", \")}\n disabled={!onReact}\n onClick={() => onReact?.(message, reaction.emoji)}\n >\n <span aria-hidden=\"true\">\n {reaction.emoji} {reaction.count}\n </span>\n <VisuallyHidden>\n {strings.react(reaction.emoji, reaction.count)}\n </VisuallyHidden>\n </button>\n </li>\n ))}\n </ul>\n )}\n\n {message.status === \"failed\" && onRetry && (\n <button type=\"button\" className={styles.retry} onClick={() => onRetry(message)}>\n {strings.retry}\n </button>\n )}\n </li>\n );\n}\n\n/** The reply stub above a body, or its blanked form once the target is gone. */\nfunction QuoteStub({\n message,\n locale,\n onQuoteClick,\n}: {\n message: ChatMessage;\n locale: \"pt-BR\" | \"en\";\n onQuoteClick?: (message: ChatMessage) => void;\n}): ReactNode {\n const strings = chatStrings(locale);\n const quote = message.quote;\n if (!quote) return null;\n const label = quote.revoked\n ? strings.quoteRevoked\n : (quote.excerpt ??\n (quote.kind && quote.kind !== \"text\" ? strings.quoteKind[quote.kind] : \"\"));\n\n const content = (\n <>\n <span className={styles.quoteAuthor}>\n {quote.senderName ?? strings.replyingTo(quote.messageId)}\n </span>\n <span className={cn(styles.quoteText, quote.revoked && styles.quoteRevoked)}>\n {label}\n </span>\n </>\n );\n\n return onQuoteClick ? (\n <button\n type=\"button\"\n className={cn(styles.quote, styles.quoteButton)}\n onClick={() => onQuoteClick(message)}\n >\n {content}\n </button>\n ) : (\n <div className={styles.quote}>{content}</div>\n );\n}\n\n/** The ticks, and the sentence behind them. */\nfunction Receipt({\n message,\n state,\n locale,\n}: {\n message: ChatMessage;\n state: keyof typeof RECEIPT_GLYPH;\n locale: \"pt-BR\" | \"en\";\n}): ReactNode {\n const strings = chatStrings(locale);\n const label =\n message.receipt && message.receipt.totalRecipients > 0 && state !== \"failed\"\n ? receiptLabel(message.receipt, strings)\n : strings[state === \"delivered\" ? \"sent\" : state];\n\n return (\n <span\n className={cn(\n styles.status,\n state === \"read\" && styles.statusRead,\n state === \"failed\" && styles.statusFailed,\n )}\n title={label}\n >\n <span aria-hidden=\"true\">{RECEIPT_GLYPH[state]}</span>\n <VisuallyHidden>{label}</VisuallyHidden>\n </span>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ChatComposer.cjs","names":[],"sources":["../../../src/components/Chat/ChatComposer.tsx"],"sourcesContent":["import {\n forwardRef,\n useImperativeHandle,\n useLayoutEffect,\n useRef,\n useState,\n type FormEvent,\n type KeyboardEvent,\n type ReactNode,\n type TextareaHTMLAttributes,\n} from \"react\";\n\nimport { cn } from \"@/utils/cn\";\n\nimport { chatStrings } from \"./chat-groups\";\nimport styles from \"./Chat.module.css\";\n\n/** DOM attributes the composer redefines. */\ntype OverriddenDomProps = \"onSubmit\" | \"value\" | \"defaultValue\" | \"rows\";\n\nexport interface ChatComposerProps extends Omit<\n TextareaHTMLAttributes<HTMLTextAreaElement>,\n OverriddenDomProps\n> {\n /** Called with the trimmed text. The field clears only when this does not throw. */\n onSend: (text: string) => void | Promise<void>;\n /** Locale for the placeholder and the send label. Default `\"pt-BR\"`. */\n locale?: \"pt-BR\" | \"en\";\n /** Rendered to the left of the send button — an attach button, an emoji picker. */\n actions?: ReactNode;\n /** Largest height the field grows to, in lines. Default 6. */\n maxRows?: number;\n /** Send label. Defaults to the locale string. */\n sendLabel?: string;\n /**\n * Called when `onSend` rejects. The draft is kept either way.\n *\n * Without it the rejection is swallowed after the draft is preserved, because\n * the alternative is worse: re-throwing out of a DOM event handler surfaces as\n * an unhandled promise rejection — console noise for the developer, a hit in\n * whatever crash reporter the app runs, and nothing the user can act on. The\n * visible signal is the text still sitting in the field; wire this to a toast\n * to say why.\n */\n onError?: (error: unknown) => void;\n}\n\n/** Imperative handle, so a thread can focus the field after retrying a message. */\nexport interface ChatComposerHandle {\n focus: () => void;\n /** Replace the draft — used to put a failed message back in the field. */\n setValue: (text: string) => void;\n}\n\n/**\n * The message field of a thread: a textarea that grows with its content, sends on\n * `Enter` and keeps `Shift+Enter` for a newline.\n *\n * Uncontrolled on purpose. A chat draft changes on every keystroke, and lifting\n * that into app state re-renders the whole thread per character — the one place\n * where \"controlled by default\" costs something visible. Apps that need the draft\n * (a persisted composer, a slash-command menu) read it from `onChange` or drive it\n * through the ref.\n *\n * @example\n * <ChatComposer onSend={(text) => api.post(\"/messages\", { body: { text } })} />\n */\nexport const ChatComposer = forwardRef<ChatComposerHandle, ChatComposerProps>(function ChatComposer(\n {\n onSend,\n locale = \"pt-BR\",\n actions,\n maxRows = 6,\n sendLabel,\n onError,\n className,\n disabled,\n placeholder,\n onKeyDown,\n onChange,\n ...rest\n },\n ref,\n) {\n const strings = chatStrings(locale);\n const textarea = useRef<HTMLTextAreaElement | null>(null);\n const [value, setValue] = useState(\"\");\n const [busy, setBusy] = useState(false);\n\n useImperativeHandle(ref, () => ({\n focus: () => textarea.current?.focus(),\n setValue: (text: string) => {\n setValue(text);\n textarea.current?.focus();\n },\n }));\n\n /**\n * Grow the field to fit its content, up to `maxRows`.\n *\n * Measured from `scrollHeight` after resetting the height, because\n * `scrollHeight` on an element that is already tall enough reports the\n * current height and the field would never shrink back.\n */\n useLayoutEffect(() => {\n const node = textarea.current;\n if (!node) return;\n node.style.height = \"auto\";\n const lineHeight = Number.parseFloat(getComputedStyle(node).lineHeight) || 20;\n const max = lineHeight * maxRows;\n node.style.height = `${Math.min(node.scrollHeight, max)}px`;\n node.style.overflowY = node.scrollHeight > max ? \"auto\" : \"hidden\";\n }, [value, maxRows]);\n\n const submit = async (): Promise<void> => {\n const text = value.trim();\n if (!text || busy || disabled) return;\n setBusy(true);\n try {\n await onSend(text);\n setValue(\"\");\n } catch (error) {\n onError?.(error);\n } finally {\n setBusy(false);\n }\n };\n\n const handleSubmit = (event: FormEvent): void => {\n event.preventDefault();\n void submit();\n };\n\n /**\n * `Enter` sends, `Shift+Enter` breaks the line.\n *\n * The IME check is not optional: while composing Japanese or Korean, `Enter`\n * confirms the candidate word and `keyCode === 229` marks that keystroke.\n * Sending there would post half a word and eat the confirmation.\n */\n const handleKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>): void => {\n onKeyDown?.(event);\n if (event.defaultPrevented) return;\n if (event.key !== \"Enter\" || event.shiftKey) return;\n if (event.nativeEvent.isComposing || event.keyCode === 229) return;\n event.preventDefault();\n void submit();\n };\n\n return (\n <form className={cn(styles.composer, className)} onSubmit={handleSubmit}>\n <textarea\n {...rest}\n ref={textarea}\n className={styles.field}\n rows={1}\n value={value}\n disabled={disabled}\n placeholder={placeholder ?? strings.placeholder}\n onChange={(event) => {\n setValue(event.target.value);\n onChange?.(event);\n }}\n onKeyDown={handleKeyDown}\n />\n <div className={styles.composerActions}>\n {actions}\n <button\n type=\"submit\"\n className={styles.send}\n disabled={disabled || busy || value.trim() === \"\"}\n >\n {sendLabel ?? strings.send}\n </button>\n </div>\n </form>\n );\n});\n"],"mappings":"0JAmEA,IAAa,GAAA,EAAe,EAAA,WAAA,CAAkD,SAC1E,CACI,SACA,SAAS,QACT,UACA,UAAU,EACV,YACA,UACA,YACA,WACA,cACA,YACA,WACA,GAAG,GAEP,EACF,CACE,IAAM,EAAU,EAAA,YAAY,CAAM,EAC5B,GAAA,EAAW,EAAA,OAAA,CAAmC,IAAI,EAClD,CAAC,EAAO,IAAA,EAAY,EAAA,SAAA,CAAS,EAAE,EAC/B,CAAC,EAAM,IAAA,EAAW,EAAA,SAAA,CAAS,EAAK,GAEtC,EAAA,EAAA,oBAAA,CAAoB,OAAY,CAC5B,UAAa,EAAS,SAAS,MAAM,EACrC,SAAW,GAAiB,CACxB,EAAS,CAAI,EACb,EAAS,SAAS,MAAM,CAC5B,CACJ,EAAE,GASF,EAAA,EAAA,gBAAA,KAAsB,CAClB,IAAM,EAAO,EAAS,QACtB,GAAI,CAAC,EAAM,OACX,EAAK,MAAM,OAAS,OAEpB,IAAM,GADa,OAAO,WAAW,iBAAiB,CAAI,CAAC,CAAC,UAAU,GAAK,IAClD,EACzB,EAAK,MAAM,OAAS,GAAG,KAAK,IAAI,EAAK,aAAc,CAAG,EAAE,IACxD,EAAK,MAAM,UAAY,EAAK,aAAe,EAAM,OAAS,QAC9D,EAAG,CAAC,EAAO,CAAO,CAAC,EAEnB,IAAM,EAAS,SAA2B,CACtC,IAAM,EAAO,EAAM,KAAK,EACpB,MAAC,GAAQ,GAAQ,GACrB,GAAQ,EAAI,EACZ,GAAI,CACA,MAAM,EAAO,CAAI,EACjB,EAAS,EAAE,CACf,OAAS,EAAO,CACZ,IAAU,CAAK,CACnB,QAAU,CACN,EAAQ,EAAK,CACjB,CARY,CAShB,EAEM,EAAgB,GAA2B,CAC7C,EAAM,eAAe,EACrB,EAAY,CAChB,EASM,EAAiB,GAAoD,CACvE,IAAY,CAAK,EACb,GAAM,mBACN,EAAM,MAAQ,SAAW,EAAM,UAC/B,EAAM,YAAY,aAAe,EAAM,UAAY,MACvD,EAAM,eAAe,EACrB,EAAY,GAChB,EAEA,OACI,EAAA,EAAA,KAAA,CAAC,OAAD,CAAM,UAAW,EAAA,GAAG,EAAA,QAAO,SAAU,CAAS,EAAG,SAAU,EAA3D,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,WAAD,CACI,GAAI,EACJ,IAAK,EACL,UAAW,EAAA,QAAO,MAClB,KAAM,EACC,QACG,WACV,YAAa,GAAe,EAAQ,YACpC,SAAW,GAAU,CACjB,EAAS,EAAM,OAAO,KAAK,EAC3B,IAAW,CAAK,CACpB,EACA,UAAW,CACd,CAAA,GACD,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,gBAAvB,SAAA,CACK,GACD,EAAA,EAAA,IAAA,CAAC,SAAD,CACI,KAAK,SACL,UAAW,EAAA,QAAO,KAClB,SAAU,GAAY,GAAQ,EAAM,KAAK,IAAM,GAE9C,SAAA,GAAa,EAAQ,IAClB,CAAA,CACP,CACH,CAAA,CAAA,GAEd,CAAC"}
1
+ {"version":3,"file":"ChatComposer.cjs","names":["forwardRef","chatStrings","useRef","useState","cn","styles","require_cn","require_chat_groups","require_Chat_module","react","react_jsx_runtime","ChatComposer","rest","strings","locale","textarea","value","setValue","busy","setBusy","ref","text","node","max","maxRows","submit","disabled","onSend","error","onError","handleSubmit","event","handleKeyDown","onKeyDown","className","placeholder","onChange","actions","sendLabel"],"sources":["../../../src/components/Chat/ChatComposer.tsx"],"sourcesContent":["import {\n forwardRef,\n useImperativeHandle,\n useLayoutEffect,\n useRef,\n useState,\n type FormEvent,\n type KeyboardEvent,\n type ReactNode,\n type TextareaHTMLAttributes,\n} from \"react\";\n\nimport { cn } from \"@/utils/cn\";\n\nimport { chatStrings } from \"./chat-groups\";\nimport styles from \"./Chat.module.css\";\n\n/** DOM attributes the composer redefines. */\ntype OverriddenDomProps = \"onSubmit\" | \"value\" | \"defaultValue\" | \"rows\";\n\nexport interface ChatComposerProps extends Omit<\n TextareaHTMLAttributes<HTMLTextAreaElement>,\n OverriddenDomProps\n> {\n /** Called with the trimmed text. The field clears only when this does not throw. */\n onSend: (text: string) => void | Promise<void>;\n /** Locale for the placeholder and the send label. Default `\"pt-BR\"`. */\n locale?: \"pt-BR\" | \"en\";\n /** Rendered to the left of the send button — an attach button, an emoji picker. */\n actions?: ReactNode;\n /** Largest height the field grows to, in lines. Default 6. */\n maxRows?: number;\n /** Send label. Defaults to the locale string. */\n sendLabel?: string;\n /**\n * Called when `onSend` rejects. The draft is kept either way.\n *\n * Without it the rejection is swallowed after the draft is preserved, because\n * the alternative is worse: re-throwing out of a DOM event handler surfaces as\n * an unhandled promise rejection — console noise for the developer, a hit in\n * whatever crash reporter the app runs, and nothing the user can act on. The\n * visible signal is the text still sitting in the field; wire this to a toast\n * to say why.\n */\n onError?: (error: unknown) => void;\n}\n\n/** Imperative handle, so a thread can focus the field after retrying a message. */\nexport interface ChatComposerHandle {\n focus: () => void;\n /** Replace the draft — used to put a failed message back in the field. */\n setValue: (text: string) => void;\n}\n\n/**\n * The message field of a thread: a textarea that grows with its content, sends on\n * `Enter` and keeps `Shift+Enter` for a newline.\n *\n * Uncontrolled on purpose. A chat draft changes on every keystroke, and lifting\n * that into app state re-renders the whole thread per character — the one place\n * where \"controlled by default\" costs something visible. Apps that need the draft\n * (a persisted composer, a slash-command menu) read it from `onChange` or drive it\n * through the ref.\n *\n * @example\n * <ChatComposer onSend={(text) => api.post(\"/messages\", { body: { text } })} />\n */\nexport const ChatComposer = forwardRef<ChatComposerHandle, ChatComposerProps>(function ChatComposer(\n {\n onSend,\n locale = \"pt-BR\",\n actions,\n maxRows = 6,\n sendLabel,\n onError,\n className,\n disabled,\n placeholder,\n onKeyDown,\n onChange,\n ...rest\n },\n ref,\n) {\n const strings = chatStrings(locale);\n const textarea = useRef<HTMLTextAreaElement | null>(null);\n const [value, setValue] = useState(\"\");\n const [busy, setBusy] = useState(false);\n\n useImperativeHandle(ref, () => ({\n focus: () => textarea.current?.focus(),\n setValue: (text: string) => {\n setValue(text);\n textarea.current?.focus();\n },\n }));\n\n /**\n * Grow the field to fit its content, up to `maxRows`.\n *\n * Measured from `scrollHeight` after resetting the height, because\n * `scrollHeight` on an element that is already tall enough reports the\n * current height and the field would never shrink back.\n */\n useLayoutEffect(() => {\n const node = textarea.current;\n if (!node) return;\n node.style.height = \"auto\";\n const lineHeight = Number.parseFloat(getComputedStyle(node).lineHeight) || 20;\n const max = lineHeight * maxRows;\n node.style.height = `${Math.min(node.scrollHeight, max)}px`;\n node.style.overflowY = node.scrollHeight > max ? \"auto\" : \"hidden\";\n }, [value, maxRows]);\n\n const submit = async (): Promise<void> => {\n const text = value.trim();\n if (!text || busy || disabled) return;\n setBusy(true);\n try {\n await onSend(text);\n setValue(\"\");\n } catch (error) {\n onError?.(error);\n } finally {\n setBusy(false);\n }\n };\n\n const handleSubmit = (event: FormEvent): void => {\n event.preventDefault();\n void submit();\n };\n\n /**\n * `Enter` sends, `Shift+Enter` breaks the line.\n *\n * The IME check is not optional: while composing Japanese or Korean, `Enter`\n * confirms the candidate word and `keyCode === 229` marks that keystroke.\n * Sending there would post half a word and eat the confirmation.\n */\n const handleKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>): void => {\n onKeyDown?.(event);\n if (event.defaultPrevented) return;\n if (event.key !== \"Enter\" || event.shiftKey) return;\n if (event.nativeEvent.isComposing || event.keyCode === 229) return;\n event.preventDefault();\n void submit();\n };\n\n return (\n <form className={cn(styles.composer, className)} onSubmit={handleSubmit}>\n <textarea\n {...rest}\n ref={textarea}\n className={styles.field}\n rows={1}\n value={value}\n disabled={disabled}\n placeholder={placeholder ?? strings.placeholder}\n onChange={(event) => {\n setValue(event.target.value);\n onChange?.(event);\n }}\n onKeyDown={handleKeyDown}\n />\n <div className={styles.composerActions}>\n {actions}\n <button\n type=\"submit\"\n className={styles.send}\n disabled={disabled || busy || value.trim() === \"\"}\n >\n {sendLabel ?? strings.send}\n </button>\n </div>\n </form>\n );\n});\n"],"mappings":"A,0JAmEA,IAAaW,GAAA,EAAeX,EAAAA,WAAAA,CAAkD,SAC1E,CACI,SACA,SAAS,QACT,UACA,UAAU,EACV,YACA,UACA,YACA,WACA,cACA,YACA,WACA,GAAGY,GAEP,EACF,CACE,IAAMC,EAAUZ,EAAAA,YAAYa,CAAM,EAC5BC,GAAA,EAAWb,EAAAA,OAAAA,CAAmC,IAAI,EAClD,CAACc,EAAOC,IAAA,EAAYd,EAAAA,SAAAA,CAAS,EAAE,EAC/B,CAACe,EAAMC,IAAA,EAAWhB,EAAAA,SAAAA,CAAS,EAAK,GAEtC,EAAAM,EAAA,oBAAA,CAAoBW,OAAY,CAC5B,UAAaL,EAAS,SAAS,MAAM,EACrC,SAAW,GAAiB,CACxBE,EAASI,CAAI,EACbN,EAAS,SAAS,MAAM,CAC5B,CACJ,EAAE,GASF,EAAAN,EAAA,gBAAA,KAAsB,CAClB,IAAMa,EAAOP,EAAS,QACtB,GAAI,CAACO,EAAM,OACX,EAAK,MAAM,OAAS,OAEpB,IAAMC,GADa,OAAO,WAAW,iBAAiBD,CAAI,CAAC,CAAC,UAAU,GAAK,IAClDE,EACzB,EAAK,MAAM,OAAS,GAAG,KAAK,IAAIF,EAAK,aAAcC,CAAG,EAAE,IACxD,EAAK,MAAM,UAAYD,EAAK,aAAeC,EAAM,OAAS,QAC9D,EAAG,CAACP,EAAOQ,CAAO,CAAC,EAEnB,IAAMC,EAAS,SAA2B,CACtC,IAAMJ,EAAOL,EAAM,KAAK,EACxB,GAAI,GAACK,GAAQH,GAAQQ,GACrB,GAAQ,EAAI,EACZ,GAAI,CACA,MAAMC,EAAON,CAAI,EACjBJ,EAAS,EAAE,CACf,OAASW,EAAO,CACZC,IAAUD,CAAK,CACnB,QAAU,CACNT,EAAQ,EAAK,CACjB,CARY,CAShB,EAEMW,EAAgB,GAA2B,CAC7CC,EAAM,eAAe,EACrBN,EAAY,CAChB,EASMO,EAAiB,GAAoD,CACvEC,IAAYF,CAAK,EACb,GAAM,mBACNA,EAAM,MAAQ,SAAWA,EAAM,UAC/BA,EAAM,YAAY,aAAeA,EAAM,UAAY,MACvDA,EAAM,eAAe,EACrBN,EAAY,GAChB,EAEA,OACI,EAAAf,EAAA,KAAA,CAAC,OAAD,CAAM,UAAWN,EAAAA,GAAGC,EAAAA,QAAO,SAAU6B,CAAS,EAAG,SAAUJ,EAA3D,SAAA,EACI,EAAApB,EAAA,IAAA,CAAC,WAAD,CACI,GAAIE,EACJ,IAAKG,EACL,UAAWV,EAAAA,QAAO,MAClB,KAAM,EACC,QACG,WACV,YAAa8B,GAAetB,EAAQ,YACpC,SAAW,GAAU,CACjBI,EAASc,EAAM,OAAO,KAAK,EAC3BK,IAAWL,CAAK,CACpB,EACA,UAAWC,CACd,CAAA,GACD,EAAAtB,EAAA,KAAA,CAAC,MAAD,CAAK,UAAWL,EAAAA,QAAO,gBAAvB,SAAA,CACKgC,GACD,EAAA3B,EAAA,IAAA,CAAC,SAAD,CACI,KAAK,SACL,UAAWL,EAAAA,QAAO,KAClB,SAAUqB,GAAYR,GAAQF,EAAM,KAAK,IAAM,GAE9C,SAAAsB,GAAazB,EAAQ,IAClB,CAAA,CACP,CACH,CAAA,CAAA,C,EAEd,CAAC,E"}
@@ -1 +1 @@
1
- {"version":3,"file":"ChatComposer.js","names":[],"sources":["../../../src/components/Chat/ChatComposer.tsx"],"sourcesContent":["import {\n forwardRef,\n useImperativeHandle,\n useLayoutEffect,\n useRef,\n useState,\n type FormEvent,\n type KeyboardEvent,\n type ReactNode,\n type TextareaHTMLAttributes,\n} from \"react\";\n\nimport { cn } from \"@/utils/cn\";\n\nimport { chatStrings } from \"./chat-groups\";\nimport styles from \"./Chat.module.css\";\n\n/** DOM attributes the composer redefines. */\ntype OverriddenDomProps = \"onSubmit\" | \"value\" | \"defaultValue\" | \"rows\";\n\nexport interface ChatComposerProps extends Omit<\n TextareaHTMLAttributes<HTMLTextAreaElement>,\n OverriddenDomProps\n> {\n /** Called with the trimmed text. The field clears only when this does not throw. */\n onSend: (text: string) => void | Promise<void>;\n /** Locale for the placeholder and the send label. Default `\"pt-BR\"`. */\n locale?: \"pt-BR\" | \"en\";\n /** Rendered to the left of the send button — an attach button, an emoji picker. */\n actions?: ReactNode;\n /** Largest height the field grows to, in lines. Default 6. */\n maxRows?: number;\n /** Send label. Defaults to the locale string. */\n sendLabel?: string;\n /**\n * Called when `onSend` rejects. The draft is kept either way.\n *\n * Without it the rejection is swallowed after the draft is preserved, because\n * the alternative is worse: re-throwing out of a DOM event handler surfaces as\n * an unhandled promise rejection — console noise for the developer, a hit in\n * whatever crash reporter the app runs, and nothing the user can act on. The\n * visible signal is the text still sitting in the field; wire this to a toast\n * to say why.\n */\n onError?: (error: unknown) => void;\n}\n\n/** Imperative handle, so a thread can focus the field after retrying a message. */\nexport interface ChatComposerHandle {\n focus: () => void;\n /** Replace the draft — used to put a failed message back in the field. */\n setValue: (text: string) => void;\n}\n\n/**\n * The message field of a thread: a textarea that grows with its content, sends on\n * `Enter` and keeps `Shift+Enter` for a newline.\n *\n * Uncontrolled on purpose. A chat draft changes on every keystroke, and lifting\n * that into app state re-renders the whole thread per character — the one place\n * where \"controlled by default\" costs something visible. Apps that need the draft\n * (a persisted composer, a slash-command menu) read it from `onChange` or drive it\n * through the ref.\n *\n * @example\n * <ChatComposer onSend={(text) => api.post(\"/messages\", { body: { text } })} />\n */\nexport const ChatComposer = forwardRef<ChatComposerHandle, ChatComposerProps>(function ChatComposer(\n {\n onSend,\n locale = \"pt-BR\",\n actions,\n maxRows = 6,\n sendLabel,\n onError,\n className,\n disabled,\n placeholder,\n onKeyDown,\n onChange,\n ...rest\n },\n ref,\n) {\n const strings = chatStrings(locale);\n const textarea = useRef<HTMLTextAreaElement | null>(null);\n const [value, setValue] = useState(\"\");\n const [busy, setBusy] = useState(false);\n\n useImperativeHandle(ref, () => ({\n focus: () => textarea.current?.focus(),\n setValue: (text: string) => {\n setValue(text);\n textarea.current?.focus();\n },\n }));\n\n /**\n * Grow the field to fit its content, up to `maxRows`.\n *\n * Measured from `scrollHeight` after resetting the height, because\n * `scrollHeight` on an element that is already tall enough reports the\n * current height and the field would never shrink back.\n */\n useLayoutEffect(() => {\n const node = textarea.current;\n if (!node) return;\n node.style.height = \"auto\";\n const lineHeight = Number.parseFloat(getComputedStyle(node).lineHeight) || 20;\n const max = lineHeight * maxRows;\n node.style.height = `${Math.min(node.scrollHeight, max)}px`;\n node.style.overflowY = node.scrollHeight > max ? \"auto\" : \"hidden\";\n }, [value, maxRows]);\n\n const submit = async (): Promise<void> => {\n const text = value.trim();\n if (!text || busy || disabled) return;\n setBusy(true);\n try {\n await onSend(text);\n setValue(\"\");\n } catch (error) {\n onError?.(error);\n } finally {\n setBusy(false);\n }\n };\n\n const handleSubmit = (event: FormEvent): void => {\n event.preventDefault();\n void submit();\n };\n\n /**\n * `Enter` sends, `Shift+Enter` breaks the line.\n *\n * The IME check is not optional: while composing Japanese or Korean, `Enter`\n * confirms the candidate word and `keyCode === 229` marks that keystroke.\n * Sending there would post half a word and eat the confirmation.\n */\n const handleKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>): void => {\n onKeyDown?.(event);\n if (event.defaultPrevented) return;\n if (event.key !== \"Enter\" || event.shiftKey) return;\n if (event.nativeEvent.isComposing || event.keyCode === 229) return;\n event.preventDefault();\n void submit();\n };\n\n return (\n <form className={cn(styles.composer, className)} onSubmit={handleSubmit}>\n <textarea\n {...rest}\n ref={textarea}\n className={styles.field}\n rows={1}\n value={value}\n disabled={disabled}\n placeholder={placeholder ?? strings.placeholder}\n onChange={(event) => {\n setValue(event.target.value);\n onChange?.(event);\n }}\n onKeyDown={handleKeyDown}\n />\n <div className={styles.composerActions}>\n {actions}\n <button\n type=\"submit\"\n className={styles.send}\n disabled={disabled || busy || value.trim() === \"\"}\n >\n {sendLabel ?? strings.send}\n </button>\n </div>\n </form>\n );\n});\n"],"mappings":";;;;;;AAmEA,IAAa,IAAe,EAAkD,SAC1E,EACI,WACA,YAAS,SACT,YACA,aAAU,GACV,cACA,YACA,cACA,aACA,gBACA,cACA,aACA,GAAG,KAEP,GACF;CACE,IAAM,IAAU,EAAY,CAAM,GAC5B,IAAW,EAAmC,IAAI,GAClD,CAAC,GAAO,KAAY,EAAS,EAAE,GAC/B,CAAC,GAAM,KAAW,EAAS,EAAK;CAiBtC,AAfA,EAAoB,UAAY;EAC5B,aAAa,EAAS,SAAS,MAAM;EACrC,WAAW,MAAiB;GAExB,AADA,EAAS,CAAI,GACb,EAAS,SAAS,MAAM;EAC5B;CACJ,EAAE,GASF,QAAsB;EAClB,IAAM,IAAO,EAAS;EACtB,IAAI,CAAC,GAAM;EACX,EAAK,MAAM,SAAS;EAEpB,IAAM,KADa,OAAO,WAAW,iBAAiB,CAAI,CAAC,CAAC,UAAU,KAAK,MAClD;EAEzB,AADA,EAAK,MAAM,SAAS,GAAG,KAAK,IAAI,EAAK,cAAc,CAAG,EAAE,KACxD,EAAK,MAAM,YAAY,EAAK,eAAe,IAAM,SAAS;CAC9D,GAAG,CAAC,GAAO,CAAO,CAAC;CAEnB,IAAM,IAAS,YAA2B;EACtC,IAAM,IAAO,EAAM,KAAK;EACpB,OAAC,KAAQ,KAAQ,IACrB;KAAQ,EAAI;GACZ,IAAI;IAEA,AADA,MAAM,EAAO,CAAI,GACjB,EAAS,EAAE;GACf,SAAS,GAAO;IACZ,IAAU,CAAK;GACnB,UAAU;IACN,EAAQ,EAAK;GACjB;EARY;CAShB,GAEM,KAAgB,MAA2B;EAE7C,AADA,EAAM,eAAe,GACrB,EAAY;CAChB,GASM,KAAiB,MAAoD;EACvE,IAAY,CAAK,GACb,GAAM,qBACN,EAAM,QAAQ,WAAW,EAAM,YAC/B,EAAM,YAAY,eAAe,EAAM,YAAY,QACvD,EAAM,eAAe,GACrB,EAAY;CAChB;CAEA,OACI,kBAAC,QAAD;EAAM,WAAW,EAAG,EAAO,UAAU,CAAS;EAAG,UAAU;EAA3D,UAAA,CACI,kBAAC,YAAD;GACI,GAAI;GACJ,KAAK;GACL,WAAW,EAAO;GAClB,MAAM;GACC;GACG;GACV,aAAa,KAAe,EAAQ;GACpC,WAAW,MAAU;IAEjB,AADA,EAAS,EAAM,OAAO,KAAK,GAC3B,IAAW,CAAK;GACpB;GACA,WAAW;EACd,CAAA,GACD,kBAAC,OAAD;GAAK,WAAW,EAAO;GAAvB,UAAA,CACK,GACD,kBAAC,UAAD;IACI,MAAK;IACL,WAAW,EAAO;IAClB,UAAU,KAAY,KAAQ,EAAM,KAAK,MAAM;IAE9C,UAAA,KAAa,EAAQ;GAClB,CAAA,CACP;EACH,CAAA,CAAA;;AAEd,CAAC"}
1
+ {"version":3,"file":"ChatComposer.js","names":["styles","Chat_module_default","ChatComposer","forwardRef","rest","strings","chatStrings","locale","textarea","useRef","value","setValue","useState","busy","setBusy","useImperativeHandle","ref","text","useLayoutEffect","node","max","maxRows","submit","disabled","onSend","error","handleSubmit","event","handleKeyDown","onKeyDown","cn","className","placeholder","onChange","actions","sendLabel"],"sources":["../../../src/components/Chat/ChatComposer.tsx"],"sourcesContent":["import {\n forwardRef,\n useImperativeHandle,\n useLayoutEffect,\n useRef,\n useState,\n type FormEvent,\n type KeyboardEvent,\n type ReactNode,\n type TextareaHTMLAttributes,\n} from \"react\";\n\nimport { cn } from \"@/utils/cn\";\n\nimport { chatStrings } from \"./chat-groups\";\nimport styles from \"./Chat.module.css\";\n\n/** DOM attributes the composer redefines. */\ntype OverriddenDomProps = \"onSubmit\" | \"value\" | \"defaultValue\" | \"rows\";\n\nexport interface ChatComposerProps extends Omit<\n TextareaHTMLAttributes<HTMLTextAreaElement>,\n OverriddenDomProps\n> {\n /** Called with the trimmed text. The field clears only when this does not throw. */\n onSend: (text: string) => void | Promise<void>;\n /** Locale for the placeholder and the send label. Default `\"pt-BR\"`. */\n locale?: \"pt-BR\" | \"en\";\n /** Rendered to the left of the send button — an attach button, an emoji picker. */\n actions?: ReactNode;\n /** Largest height the field grows to, in lines. Default 6. */\n maxRows?: number;\n /** Send label. Defaults to the locale string. */\n sendLabel?: string;\n /**\n * Called when `onSend` rejects. The draft is kept either way.\n *\n * Without it the rejection is swallowed after the draft is preserved, because\n * the alternative is worse: re-throwing out of a DOM event handler surfaces as\n * an unhandled promise rejection — console noise for the developer, a hit in\n * whatever crash reporter the app runs, and nothing the user can act on. The\n * visible signal is the text still sitting in the field; wire this to a toast\n * to say why.\n */\n onError?: (error: unknown) => void;\n}\n\n/** Imperative handle, so a thread can focus the field after retrying a message. */\nexport interface ChatComposerHandle {\n focus: () => void;\n /** Replace the draft — used to put a failed message back in the field. */\n setValue: (text: string) => void;\n}\n\n/**\n * The message field of a thread: a textarea that grows with its content, sends on\n * `Enter` and keeps `Shift+Enter` for a newline.\n *\n * Uncontrolled on purpose. A chat draft changes on every keystroke, and lifting\n * that into app state re-renders the whole thread per character — the one place\n * where \"controlled by default\" costs something visible. Apps that need the draft\n * (a persisted composer, a slash-command menu) read it from `onChange` or drive it\n * through the ref.\n *\n * @example\n * <ChatComposer onSend={(text) => api.post(\"/messages\", { body: { text } })} />\n */\nexport const ChatComposer = forwardRef<ChatComposerHandle, ChatComposerProps>(function ChatComposer(\n {\n onSend,\n locale = \"pt-BR\",\n actions,\n maxRows = 6,\n sendLabel,\n onError,\n className,\n disabled,\n placeholder,\n onKeyDown,\n onChange,\n ...rest\n },\n ref,\n) {\n const strings = chatStrings(locale);\n const textarea = useRef<HTMLTextAreaElement | null>(null);\n const [value, setValue] = useState(\"\");\n const [busy, setBusy] = useState(false);\n\n useImperativeHandle(ref, () => ({\n focus: () => textarea.current?.focus(),\n setValue: (text: string) => {\n setValue(text);\n textarea.current?.focus();\n },\n }));\n\n /**\n * Grow the field to fit its content, up to `maxRows`.\n *\n * Measured from `scrollHeight` after resetting the height, because\n * `scrollHeight` on an element that is already tall enough reports the\n * current height and the field would never shrink back.\n */\n useLayoutEffect(() => {\n const node = textarea.current;\n if (!node) return;\n node.style.height = \"auto\";\n const lineHeight = Number.parseFloat(getComputedStyle(node).lineHeight) || 20;\n const max = lineHeight * maxRows;\n node.style.height = `${Math.min(node.scrollHeight, max)}px`;\n node.style.overflowY = node.scrollHeight > max ? \"auto\" : \"hidden\";\n }, [value, maxRows]);\n\n const submit = async (): Promise<void> => {\n const text = value.trim();\n if (!text || busy || disabled) return;\n setBusy(true);\n try {\n await onSend(text);\n setValue(\"\");\n } catch (error) {\n onError?.(error);\n } finally {\n setBusy(false);\n }\n };\n\n const handleSubmit = (event: FormEvent): void => {\n event.preventDefault();\n void submit();\n };\n\n /**\n * `Enter` sends, `Shift+Enter` breaks the line.\n *\n * The IME check is not optional: while composing Japanese or Korean, `Enter`\n * confirms the candidate word and `keyCode === 229` marks that keystroke.\n * Sending there would post half a word and eat the confirmation.\n */\n const handleKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>): void => {\n onKeyDown?.(event);\n if (event.defaultPrevented) return;\n if (event.key !== \"Enter\" || event.shiftKey) return;\n if (event.nativeEvent.isComposing || event.keyCode === 229) return;\n event.preventDefault();\n void submit();\n };\n\n return (\n <form className={cn(styles.composer, className)} onSubmit={handleSubmit}>\n <textarea\n {...rest}\n ref={textarea}\n className={styles.field}\n rows={1}\n value={value}\n disabled={disabled}\n placeholder={placeholder ?? strings.placeholder}\n onChange={(event) => {\n setValue(event.target.value);\n onChange?.(event);\n }}\n onKeyDown={handleKeyDown}\n />\n <div className={styles.composerActions}>\n {actions}\n <button\n type=\"submit\"\n className={styles.send}\n disabled={disabled || busy || value.trim() === \"\"}\n >\n {sendLabel ?? strings.send}\n </button>\n </div>\n </form>\n );\n});\n"],"mappings":";;;;;;AAmEA,IAAaE,IAAeC,EAAkD,SAC1E,EACI,WACA,YAAS,SACT,YACA,aAAU,GACV,cACA,YACA,cACA,aACA,gBACA,cACA,aACA,GAAGC,KAEP,GACF;CACE,IAAMC,IAAUC,EAAYC,CAAM,GAC5BC,IAAWC,EAAmC,IAAI,GAClD,CAACC,GAAOC,KAAYC,EAAS,EAAE,GAC/B,CAACC,GAAMC,KAAWF,EAAS,EAAK;CAiBtC,AAfAG,EAAoBC,UAAY;EAC5B,aAAaR,EAAS,SAAS,MAAM;EACrC,WAAW,MAAiB;GAExB,AADAG,EAASM,CAAI,GACbT,EAAS,SAAS,MAAM;EAC5B;CACJ,EAAE,GASFU,QAAsB;EAClB,IAAMC,IAAOX,EAAS;EACtB,IAAI,CAACW,GAAM;EACX,EAAK,MAAM,SAAS;EAEpB,IAAMC,KADa,OAAO,WAAW,iBAAiBD,CAAI,CAAC,CAAC,UAAU,KAAK,MAClDE;EAEzB,AADA,EAAK,MAAM,SAAS,GAAG,KAAK,IAAIF,EAAK,cAAcC,CAAG,EAAE,KACxD,EAAK,MAAM,YAAYD,EAAK,eAAeC,IAAM,SAAS;CAC9D,GAAG,CAACV,GAAOW,CAAO,CAAC;CAEnB,IAAMC,IAAS,YAA2B;EACtC,IAAML,IAAOP,EAAM,KAAK;EACxB,IAAI,GAACO,KAAQJ,KAAQU,IACrB;KAAQ,EAAI;GACZ,IAAI;IAEA,AADA,MAAMC,EAAOP,CAAI,GACjBN,EAAS,EAAE;GACf,SAASc,GAAO;IACZ,IAAUA,CAAK;GACnB,UAAU;IACN,EAAQ,EAAK;GACjB;EARY;CAShB,GAEMC,KAAgB,MAA2B;EAE7C,AADAC,EAAM,eAAe,GACrBL,EAAY;CAChB,GASMM,KAAiB,MAAoD;EAEvE,AADAC,IAAYF,CAAK,GACb,GAAM,qBACNA,EAAM,QAAQ,WAAWA,EAAM,YAC/BA,EAAM,YAAY,eAAeA,EAAM,YAAY,QACvDA,EAAM,eAAe,GACrBL,EAAY;CAChB;CAEA,OACI,kBAAC,QAAD;EAAM,WAAWQ,EAAG9B,EAAO,UAAU+B,CAAS;EAAG,UAAUL;EAA3D,UAAA,CACI,kBAAC,YAAD;GACI,GAAItB;GACJ,KAAKI;GACL,WAAWR,EAAO;GAClB,MAAM;GACC;GACG;GACV,aAAagC,KAAe3B,EAAQ;GACpC,WAAW,MAAU;IAEjB,AADAM,EAASgB,EAAM,OAAO,KAAK,GAC3BM,IAAWN,CAAK;GACpB;GACA,WAAWC;EACd,CAAA,GACD,kBAAC,OAAD;GAAK,WAAW5B,EAAO;GAAvB,UAAA,CACKkC,GACD,kBAAC,UAAD;IACI,MAAK;IACL,WAAWlC,EAAO;IAClB,UAAUuB,KAAYV,KAAQH,EAAM,KAAK,MAAM;IAE9C,UAAAyB,KAAa9B,EAAQ;GAClB,CAAA,CACP;EACH,CAAA,CAAA;;AAEd,CAAC"}
@@ -1,2 +1,2 @@
1
- var e=3e5;function t(e){let t=new Date(e);return t.setHours(0,0,0,0),t.getTime()}function n({messages:n,currentUserId:r,windowMs:i=e}){let a=[],o=null,s=null;for(let e of n){let n=t(e.sentAt);n!==o&&(o=n,s=null,a.push({kind:`day`,key:`day-${n}`,date:n}));let c=s?.messages[s.messages.length-1];if(s!==null&&c!==void 0&&s.authorId===e.authorId&&e.sentAt-c.sentAt<=i&&s){s.messages.push(e);continue}s={kind:`run`,key:`${e.authorId}-${e.id}`,authorId:e.authorId,authorName:e.authorName,own:r!==void 0&&e.authorId===r,messages:[e]},a.push(s)}return a}var r={thread:`Conversa`,today:`Hoje`,yesterday:`Ontem`,you:`Você`,typingOne:e=>`${e} está digitando…`,typingTwo:(e,t)=>`${e} e ${t} estão digitando…`,typingMany:e=>`${e} pessoas estão digitando…`,sending:`Enviando`,sent:`Enviada`,read:`Lida`,failed:`Falhou ao enviar`,retry:`Tentar de novo`,empty:`Nenhuma mensagem ainda`,placeholder:`Escreva uma mensagem`,send:`Enviar`,deleted:`Esta mensagem foi apagada`,edited:`editada`,replyingTo:e=>`Em resposta a ${e}`,quoteRevoked:`Mensagem apagada`,quoteKind:{image:`Foto`,video:`Vídeo`,audio:`Áudio`,voice:`Mensagem de voz`,file:`Documento`},reactions:`Reações`,react:(e,t)=>`${e}, ${t} ${t===1?`pessoa`:`pessoas`}`,deliveredAll:`Entregue a todos`,deliveredSome:(e,t)=>`Entregue a ${e} de ${t}`,readAll:`Lida por todos`,readSome:(e,t)=>`Lida por ${e} de ${t}`,messageActions:`Ações da mensagem`,voiceNote:`Mensagem de voz`,download:`Baixar`},i={thread:`Conversation`,today:`Today`,yesterday:`Yesterday`,you:`You`,typingOne:e=>`${e} is typing…`,typingTwo:(e,t)=>`${e} and ${t} are typing…`,typingMany:e=>`${e} people are typing…`,sending:`Sending`,sent:`Sent`,read:`Read`,failed:`Failed to send`,retry:`Try again`,empty:`No messages yet`,placeholder:`Write a message`,send:`Send`,deleted:`This message was deleted`,edited:`edited`,replyingTo:e=>`Replying to ${e}`,quoteRevoked:`Message deleted`,quoteKind:{image:`Photo`,video:`Video`,audio:`Audio`,voice:`Voice message`,file:`Document`},reactions:`Reactions`,react:(e,t)=>`${e}, ${t} ${t===1?`person`:`people`}`,deliveredAll:`Delivered to everyone`,deliveredSome:(e,t)=>`Delivered to ${e} of ${t}`,readAll:`Read by everyone`,readSome:(e,t)=>`Read by ${e} of ${t}`,messageActions:`Message actions`,voiceNote:`Voice message`,download:`Download`};function a(e){return e===`en`?i:r}function o(e,{locale:n=`pt-BR`,now:r}={}){let i=a(n),o=t(r??Date.now()),s=864e5;return e===o?i.today:e===o-s?i.yesterday:new Date(e).toLocaleDateString(n===`en`?`en-US`:`pt-BR`,{day:`2-digit`,month:`short`,year:e<o-300*s?`numeric`:void 0})}function s(e,t=`pt-BR`){return new Date(e).toLocaleTimeString(t===`en`?`en-US`:`pt-BR`,{hour:`2-digit`,minute:`2-digit`})}function c(e,t=`pt-BR`){let n=a(t);return e.length===0?null:e.length===1?n.typingOne(e[0]):e.length===2?n.typingTwo(e[0],e[1]):n.typingMany(e.length)}exports.DEFAULT_GROUP_WINDOW_MS=e,exports.chatStrings=a,exports.dayLabel=o,exports.groupMessages=n,exports.timeLabel=s,exports.typingLabel=c;
1
+ var e=3e5;function t(e){let t=new Date(e);return t.setHours(0,0,0,0),t.getTime()}function n({messages:n,currentUserId:r,windowMs:i=e}){let a=[],o=null,s=null;for(let e of n){let n=t(e.sentAt);n!==o&&(o=n,s=null,a.push({kind:`day`,key:`day-${n}`,date:n}));let c=s?.messages[s.messages.length-1];s!==null&&c!==void 0&&s.authorId===e.authorId&&e.sentAt-c.sentAt<=i&&s?s.messages.push(e):(s={kind:`run`,key:`${e.authorId}-${e.id}`,authorId:e.authorId,authorName:e.authorName,own:r!==void 0&&e.authorId===r,messages:[e]},a.push(s))}return a}var r={thread:`Conversa`,today:`Hoje`,yesterday:`Ontem`,you:`Você`,typingOne:e=>`${e} está digitando…`,typingTwo:(e,t)=>`${e} e ${t} estão digitando…`,typingMany:e=>`${e} pessoas estão digitando…`,sending:`Enviando`,sent:`Enviada`,read:`Lida`,failed:`Falhou ao enviar`,retry:`Tentar de novo`,empty:`Nenhuma mensagem ainda`,placeholder:`Escreva uma mensagem`,send:`Enviar`,deleted:`Esta mensagem foi apagada`,edited:`editada`,replyingTo:e=>`Em resposta a ${e}`,quoteRevoked:`Mensagem apagada`,quoteKind:{image:`Foto`,video:`Vídeo`,audio:`Áudio`,voice:`Mensagem de voz`,file:`Documento`},reactions:`Reações`,react:(e,t)=>`${e}, ${t} ${t===1?`pessoa`:`pessoas`}`,deliveredAll:`Entregue a todos`,deliveredSome:(e,t)=>`Entregue a ${e} de ${t}`,readAll:`Lida por todos`,readSome:(e,t)=>`Lida por ${e} de ${t}`,messageActions:`Ações da mensagem`,voiceNote:`Mensagem de voz`,download:`Baixar`},i={thread:`Conversation`,today:`Today`,yesterday:`Yesterday`,you:`You`,typingOne:e=>`${e} is typing…`,typingTwo:(e,t)=>`${e} and ${t} are typing…`,typingMany:e=>`${e} people are typing…`,sending:`Sending`,sent:`Sent`,read:`Read`,failed:`Failed to send`,retry:`Try again`,empty:`No messages yet`,placeholder:`Write a message`,send:`Send`,deleted:`This message was deleted`,edited:`edited`,replyingTo:e=>`Replying to ${e}`,quoteRevoked:`Message deleted`,quoteKind:{image:`Photo`,video:`Video`,audio:`Audio`,voice:`Voice message`,file:`Document`},reactions:`Reactions`,react:(e,t)=>`${e}, ${t} ${t===1?`person`:`people`}`,deliveredAll:`Delivered to everyone`,deliveredSome:(e,t)=>`Delivered to ${e} of ${t}`,readAll:`Read by everyone`,readSome:(e,t)=>`Read by ${e} of ${t}`,messageActions:`Message actions`,voiceNote:`Voice message`,download:`Download`};function a(e){return e===`en`?i:r}function o(e,{locale:n=`pt-BR`,now:r}={}){let i=a(n),o=t(r??Date.now()),s=864e5;return e===o?i.today:e===o-s?i.yesterday:new Date(e).toLocaleDateString(n===`en`?`en-US`:`pt-BR`,{day:`2-digit`,month:`short`,year:e<o-300*s?`numeric`:void 0})}function s(e,t=`pt-BR`){return new Date(e).toLocaleTimeString(t===`en`?`en-US`:`pt-BR`,{hour:`2-digit`,minute:`2-digit`})}function c(e,t=`pt-BR`){let n=a(t);return e.length===0?null:e.length===1?n.typingOne(e[0]):e.length===2?n.typingTwo(e[0],e[1]):n.typingMany(e.length)}exports.DEFAULT_GROUP_WINDOW_MS=e,exports.chatStrings=a,exports.dayLabel=o,exports.groupMessages=n,exports.timeLabel=s,exports.typingLabel=c;
2
2
  //# sourceMappingURL=chat-groups.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"chat-groups.cjs","names":[],"sources":["../../../src/components/Chat/chat-groups.ts"],"sourcesContent":["import type { ReactNode } from \"react\";\n\n/** What a bubble can carry besides text. */\nexport type ChatAttachmentKind = \"image\" | \"video\" | \"audio\" | \"voice\" | \"file\";\n\n/** One attachment on a message. */\nexport interface ChatAttachment {\n /** Decides how it renders: a picture, a player, a voice note, a download row. */\n kind: ChatAttachmentKind;\n /** Where the bytes are. A blob URL works for a message still uploading. */\n url: string;\n /** File name, shown for `\"file\"` and used as the download name. */\n name?: string;\n /** MIME type, when the app knows it. */\n mimeType?: string;\n /** Size in bytes, shown next to a file. */\n sizeBytes?: number;\n /** Duration in ms, for audio, voice and video. */\n durationMs?: number;\n /** Poster for a video, or a smaller copy of an image. */\n thumbnailUrl?: string;\n /**\n * Normalised peaks, `0`–`1`, for a voice note.\n *\n * A voice note without one is a grey rectangle: the waveform is what tells\n * somebody whether this is a word or a two-minute monologue.\n */\n waveform?: readonly number[];\n /** Alternative text for an image. */\n alt?: string;\n}\n\n/**\n * The stub of the message being replied to, shown above the body.\n *\n * `revoked` is not decoration: deleting the quoted message has to blank the\n * quoted text, or it leaks through everyone who replied to it.\n */\nexport interface ChatQuote {\n /** Id of the quoted message, so the app can scroll to it. */\n messageId: string;\n /** Who wrote it. */\n senderName?: string;\n /** A short piece of what it said. The component never truncates for you. */\n excerpt?: string;\n /** What the quoted message was, when it was not text. */\n kind?: \"text\" | ChatAttachmentKind;\n /** The quoted message was deleted — the excerpt is not shown. */\n revoked?: boolean;\n}\n\n/** One emoji on a message, with its tally. */\nexport interface ChatReaction {\n /** The emoji itself. */\n emoji: string;\n /** How many people reacted with it. */\n count: number;\n /** Whether the current user is one of them — the chip reads as pressed. */\n reacted?: boolean;\n /** Who reacted, for the chip's tooltip. */\n names?: readonly string[];\n}\n\n/**\n * Per-recipient delivery, which is what a group needs.\n *\n * `status` is a boolean for the sender: it cannot say \"delivered to everyone\"\n * versus \"read by everyone\", and only the second one turns the ticks blue.\n */\nexport interface ChatReceipt {\n /** How many recipients have received it. */\n deliveredTo: number;\n /** How many have read it. */\n readBy: number;\n /** How many recipients there are. */\n totalRecipients: number;\n}\n\n/** One entry in a thread. */\nexport interface ChatMessage {\n /** Stable identity. Used as the React key and by `onRetry`. */\n id: string;\n /**\n * What was said. A node, so an app can render a link, an image or a quote.\n *\n * Optional, because a message can be all attachment, or be a tombstone: a\n * deleted message has no body to show, and requiring one made every app\n * invent a placeholder string for the state the component now owns.\n */\n body?: ReactNode;\n /** Who said it. Compared against `currentUserId` to decide sides. */\n authorId: string;\n /** Display name. Falls back to `authorId` in the header of a run. */\n authorName?: string;\n /** Epoch milliseconds. */\n sentAt: number;\n /**\n * Delivery state of an outgoing message.\n *\n * `\"failed\"` is the one that matters: without it an app has to invent its own\n * way to say \"this never left\", and the user re-types a message that is\n * sitting right there.\n */\n status?: \"sending\" | \"sent\" | \"read\" | \"failed\";\n /**\n * Per-recipient delivery. Takes precedence over `status` for the ticks.\n *\n * Use it in a group, where \"delivered to all\" and \"read by all\" are different\n * states and `status` can only say one thing.\n */\n receipt?: ChatReceipt;\n /** Media, voice notes and documents carried by this message. */\n attachments?: readonly ChatAttachment[];\n /** The message this one replies to. */\n quote?: ChatQuote;\n /** Emoji reactions, already tallied by the app. */\n reactions?: readonly ChatReaction[];\n /**\n * The message was deleted — it renders as a tombstone.\n *\n * A state, not a `body` the app swaps for a string: as a state the quote of\n * it can be blanked too, and every app stops writing its own wording.\n */\n deleted?: boolean;\n /** The message was edited after it was sent. */\n edited?: boolean;\n /** Anything the app wants to carry through to its own renderers. */\n data?: Record<string, unknown>;\n}\n\n/** A run of consecutive messages from one author, under one day. */\nexport interface ChatRun {\n kind: \"run\";\n /** `${authorId}-${first message id}` — stable across re-renders. */\n key: string;\n authorId: string;\n authorName?: string;\n /** Whether this run belongs to the current user. */\n own: boolean;\n messages: ChatMessage[];\n}\n\n/** A date heading between runs. */\nexport interface ChatDay {\n kind: \"day\";\n key: string;\n /** Midnight of that local day, epoch ms — the label is formatted by the view. */\n date: number;\n}\n\nexport type ChatSection = ChatDay | ChatRun;\n\n/** Default window in which consecutive messages from one author stay in a run. */\nexport const DEFAULT_GROUP_WINDOW_MS = 5 * 60 * 1000;\n\n/** Local midnight of an instant, epoch ms. */\nfunction startOfDay(timestamp: number): number {\n const date = new Date(timestamp);\n date.setHours(0, 0, 0, 0);\n return date.getTime();\n}\n\n/**\n * Turn a flat message list into the sections a thread renders: a date heading\n * whenever the local day changes, and runs of consecutive messages from the same\n * author.\n *\n * Grouping is what makes a thread readable — repeating the avatar and the name on\n * every line of a five-line burst turns a conversation into a list of receipts.\n * The run breaks on a different author, a different day, or a gap longer than\n * `windowMs`: a reply an hour later is a new beat in the conversation even when\n * nobody else spoke, and joining it to the earlier burst would put one timestamp\n * on messages an hour apart.\n *\n * Order is taken as given, oldest first, and never sorted here: a thread that\n * reorders what the server sent would fight optimistic inserts, where the\n * pending message is deliberately last.\n *\n * @param params.messages - Oldest first.\n * @param params.currentUserId - Author id treated as \"own\".\n * @param params.windowMs - Gap that still keeps a run together. Default 5 min.\n * @returns Sections in render order.\n */\nexport function groupMessages({\n messages,\n currentUserId,\n windowMs = DEFAULT_GROUP_WINDOW_MS,\n}: {\n messages: readonly ChatMessage[];\n currentUserId?: string;\n windowMs?: number;\n}): ChatSection[] {\n const sections: ChatSection[] = [];\n let day: number | null = null;\n let run: ChatRun | null = null;\n\n for (const message of messages) {\n const messageDay = startOfDay(message.sentAt);\n if (messageDay !== day) {\n day = messageDay;\n run = null;\n sections.push({ kind: \"day\", key: `day-${messageDay}`, date: messageDay });\n }\n\n const previous = run?.messages[run.messages.length - 1];\n const continues =\n run !== null &&\n previous !== undefined &&\n run.authorId === message.authorId &&\n message.sentAt - previous.sentAt <= windowMs;\n\n if (continues && run) {\n run.messages.push(message);\n continue;\n }\n\n run = {\n kind: \"run\",\n key: `${message.authorId}-${message.id}`,\n authorId: message.authorId,\n authorName: message.authorName,\n own: currentUserId !== undefined && message.authorId === currentUserId,\n messages: [message],\n };\n sections.push(run);\n }\n\n return sections;\n}\n\n/** Labels the thread needs, per locale. */\ninterface ChatStrings {\n thread: string;\n today: string;\n yesterday: string;\n you: string;\n typingOne: (name: string) => string;\n typingTwo: (a: string, b: string) => string;\n typingMany: (n: number) => string;\n sending: string;\n sent: string;\n read: string;\n failed: string;\n retry: string;\n empty: string;\n placeholder: string;\n send: string;\n deleted: string;\n edited: string;\n replyingTo: (name: string) => string;\n quoteRevoked: string;\n quoteKind: Record<ChatAttachmentKind, string>;\n reactions: string;\n react: (emoji: string, count: number) => string;\n deliveredAll: string;\n deliveredSome: (delivered: number, total: number) => string;\n readAll: string;\n readSome: (read: number, total: number) => string;\n messageActions: string;\n voiceNote: string;\n download: string;\n}\n\nconst PT_BR: ChatStrings = {\n thread: \"Conversa\",\n today: \"Hoje\",\n yesterday: \"Ontem\",\n you: \"Você\",\n typingOne: (name) => `${name} está digitando…`,\n typingTwo: (a, b) => `${a} e ${b} estão digitando…`,\n typingMany: (n) => `${n} pessoas estão digitando…`,\n sending: \"Enviando\",\n sent: \"Enviada\",\n read: \"Lida\",\n failed: \"Falhou ao enviar\",\n retry: \"Tentar de novo\",\n empty: \"Nenhuma mensagem ainda\",\n placeholder: \"Escreva uma mensagem\",\n send: \"Enviar\",\n deleted: \"Esta mensagem foi apagada\",\n edited: \"editada\",\n replyingTo: (name) => `Em resposta a ${name}`,\n quoteRevoked: \"Mensagem apagada\",\n quoteKind: {\n image: \"Foto\",\n video: \"Vídeo\",\n audio: \"Áudio\",\n voice: \"Mensagem de voz\",\n file: \"Documento\",\n },\n reactions: \"Reações\",\n react: (emoji, count) => `${emoji}, ${count} ${count === 1 ? \"pessoa\" : \"pessoas\"}`,\n deliveredAll: \"Entregue a todos\",\n deliveredSome: (delivered, total) => `Entregue a ${delivered} de ${total}`,\n readAll: \"Lida por todos\",\n readSome: (read, total) => `Lida por ${read} de ${total}`,\n messageActions: \"Ações da mensagem\",\n voiceNote: \"Mensagem de voz\",\n download: \"Baixar\",\n};\n\nconst EN: ChatStrings = {\n thread: \"Conversation\",\n today: \"Today\",\n yesterday: \"Yesterday\",\n you: \"You\",\n typingOne: (name) => `${name} is typing…`,\n typingTwo: (a, b) => `${a} and ${b} are typing…`,\n typingMany: (n) => `${n} people are typing…`,\n sending: \"Sending\",\n sent: \"Sent\",\n read: \"Read\",\n failed: \"Failed to send\",\n retry: \"Try again\",\n empty: \"No messages yet\",\n placeholder: \"Write a message\",\n send: \"Send\",\n deleted: \"This message was deleted\",\n edited: \"edited\",\n replyingTo: (name) => `Replying to ${name}`,\n quoteRevoked: \"Message deleted\",\n quoteKind: {\n image: \"Photo\",\n video: \"Video\",\n audio: \"Audio\",\n voice: \"Voice message\",\n file: \"Document\",\n },\n reactions: \"Reactions\",\n react: (emoji, count) => `${emoji}, ${count} ${count === 1 ? \"person\" : \"people\"}`,\n deliveredAll: \"Delivered to everyone\",\n deliveredSome: (delivered, total) => `Delivered to ${delivered} of ${total}`,\n readAll: \"Read by everyone\",\n readSome: (read, total) => `Read by ${read} of ${total}`,\n messageActions: \"Message actions\",\n voiceNote: \"Voice message\",\n download: \"Download\",\n};\n\n/** Locale strings for the thread. */\nexport function chatStrings(locale: \"pt-BR\" | \"en\"): ChatStrings {\n return locale === \"en\" ? EN : PT_BR;\n}\n\n/**\n * Label for a date heading: `\"Hoje\"`, `\"Ontem\"`, or the formatted date.\n *\n * @param date - Local midnight of the day being labelled.\n * @param params.now - Reference instant, so tests and SSR-free renders are stable.\n */\nexport function dayLabel(\n date: number,\n { locale = \"pt-BR\", now }: { locale?: \"pt-BR\" | \"en\"; now?: number } = {},\n): string {\n const strings = chatStrings(locale);\n const today = startOfDay(now ?? Date.now());\n const dayMs = 24 * 60 * 60 * 1000;\n if (date === today) return strings.today;\n if (date === today - dayMs) return strings.yesterday;\n return new Date(date).toLocaleDateString(locale === \"en\" ? \"en-US\" : \"pt-BR\", {\n day: \"2-digit\",\n month: \"short\",\n year: date < today - 300 * dayMs ? \"numeric\" : undefined,\n });\n}\n\n/** Clock label for a single message — the time, not a relative phrase. */\nexport function timeLabel(timestamp: number, locale: \"pt-BR\" | \"en\" = \"pt-BR\"): string {\n return new Date(timestamp).toLocaleTimeString(locale === \"en\" ? \"en-US\" : \"pt-BR\", {\n hour: \"2-digit\",\n minute: \"2-digit\",\n });\n}\n\n/** Sentence for the typing indicator, or `null` when nobody is typing. */\nexport function typingLabel(\n names: readonly string[],\n locale: \"pt-BR\" | \"en\" = \"pt-BR\",\n): string | null {\n const strings = chatStrings(locale);\n if (names.length === 0) return null;\n if (names.length === 1) return strings.typingOne(names[0]);\n if (names.length === 2) return strings.typingTwo(names[0], names[1]);\n return strings.typingMany(names.length);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"chat-groups.cjs","names":["DEFAULT_GROUP_WINDOW_MS","startOfDay","date","timestamp","groupMessages","sections","day","run","message","messages","messageDay","previous","windowMs","currentUserId","PT_BR","name","a","b","n","emoji","count","delivered","total","read","EN","chatStrings","locale","dayLabel","strings","today","now","dayMs","timeLabel","typingLabel","names"],"sources":["../../../src/components/Chat/chat-groups.ts"],"sourcesContent":["import type { ReactNode } from \"react\";\n\n/** What a bubble can carry besides text. */\nexport type ChatAttachmentKind = \"image\" | \"video\" | \"audio\" | \"voice\" | \"file\";\n\n/** One attachment on a message. */\nexport interface ChatAttachment {\n /** Decides how it renders: a picture, a player, a voice note, a download row. */\n kind: ChatAttachmentKind;\n /** Where the bytes are. A blob URL works for a message still uploading. */\n url: string;\n /** File name, shown for `\"file\"` and used as the download name. */\n name?: string;\n /** MIME type, when the app knows it. */\n mimeType?: string;\n /** Size in bytes, shown next to a file. */\n sizeBytes?: number;\n /** Duration in ms, for audio, voice and video. */\n durationMs?: number;\n /** Poster for a video, or a smaller copy of an image. */\n thumbnailUrl?: string;\n /**\n * Normalised peaks, `0`–`1`, for a voice note.\n *\n * A voice note without one is a grey rectangle: the waveform is what tells\n * somebody whether this is a word or a two-minute monologue.\n */\n waveform?: readonly number[];\n /** Alternative text for an image. */\n alt?: string;\n}\n\n/**\n * The stub of the message being replied to, shown above the body.\n *\n * `revoked` is not decoration: deleting the quoted message has to blank the\n * quoted text, or it leaks through everyone who replied to it.\n */\nexport interface ChatQuote {\n /** Id of the quoted message, so the app can scroll to it. */\n messageId: string;\n /** Who wrote it. */\n senderName?: string;\n /** A short piece of what it said. The component never truncates for you. */\n excerpt?: string;\n /** What the quoted message was, when it was not text. */\n kind?: \"text\" | ChatAttachmentKind;\n /** The quoted message was deleted — the excerpt is not shown. */\n revoked?: boolean;\n}\n\n/** One emoji on a message, with its tally. */\nexport interface ChatReaction {\n /** The emoji itself. */\n emoji: string;\n /** How many people reacted with it. */\n count: number;\n /** Whether the current user is one of them — the chip reads as pressed. */\n reacted?: boolean;\n /** Who reacted, for the chip's tooltip. */\n names?: readonly string[];\n}\n\n/**\n * Per-recipient delivery, which is what a group needs.\n *\n * `status` is a boolean for the sender: it cannot say \"delivered to everyone\"\n * versus \"read by everyone\", and only the second one turns the ticks blue.\n */\nexport interface ChatReceipt {\n /** How many recipients have received it. */\n deliveredTo: number;\n /** How many have read it. */\n readBy: number;\n /** How many recipients there are. */\n totalRecipients: number;\n}\n\n/** One entry in a thread. */\nexport interface ChatMessage {\n /** Stable identity. Used as the React key and by `onRetry`. */\n id: string;\n /**\n * What was said. A node, so an app can render a link, an image or a quote.\n *\n * Optional, because a message can be all attachment, or be a tombstone: a\n * deleted message has no body to show, and requiring one made every app\n * invent a placeholder string for the state the component now owns.\n */\n body?: ReactNode;\n /** Who said it. Compared against `currentUserId` to decide sides. */\n authorId: string;\n /** Display name. Falls back to `authorId` in the header of a run. */\n authorName?: string;\n /** Epoch milliseconds. */\n sentAt: number;\n /**\n * Delivery state of an outgoing message.\n *\n * `\"failed\"` is the one that matters: without it an app has to invent its own\n * way to say \"this never left\", and the user re-types a message that is\n * sitting right there.\n */\n status?: \"sending\" | \"sent\" | \"read\" | \"failed\";\n /**\n * Per-recipient delivery. Takes precedence over `status` for the ticks.\n *\n * Use it in a group, where \"delivered to all\" and \"read by all\" are different\n * states and `status` can only say one thing.\n */\n receipt?: ChatReceipt;\n /** Media, voice notes and documents carried by this message. */\n attachments?: readonly ChatAttachment[];\n /** The message this one replies to. */\n quote?: ChatQuote;\n /** Emoji reactions, already tallied by the app. */\n reactions?: readonly ChatReaction[];\n /**\n * The message was deleted — it renders as a tombstone.\n *\n * A state, not a `body` the app swaps for a string: as a state the quote of\n * it can be blanked too, and every app stops writing its own wording.\n */\n deleted?: boolean;\n /** The message was edited after it was sent. */\n edited?: boolean;\n /** Anything the app wants to carry through to its own renderers. */\n data?: Record<string, unknown>;\n}\n\n/** A run of consecutive messages from one author, under one day. */\nexport interface ChatRun {\n kind: \"run\";\n /** `${authorId}-${first message id}` — stable across re-renders. */\n key: string;\n authorId: string;\n authorName?: string;\n /** Whether this run belongs to the current user. */\n own: boolean;\n messages: ChatMessage[];\n}\n\n/** A date heading between runs. */\nexport interface ChatDay {\n kind: \"day\";\n key: string;\n /** Midnight of that local day, epoch ms — the label is formatted by the view. */\n date: number;\n}\n\nexport type ChatSection = ChatDay | ChatRun;\n\n/** Default window in which consecutive messages from one author stay in a run. */\nexport const DEFAULT_GROUP_WINDOW_MS = 5 * 60 * 1000;\n\n/** Local midnight of an instant, epoch ms. */\nfunction startOfDay(timestamp: number): number {\n const date = new Date(timestamp);\n date.setHours(0, 0, 0, 0);\n return date.getTime();\n}\n\n/**\n * Turn a flat message list into the sections a thread renders: a date heading\n * whenever the local day changes, and runs of consecutive messages from the same\n * author.\n *\n * Grouping is what makes a thread readable — repeating the avatar and the name on\n * every line of a five-line burst turns a conversation into a list of receipts.\n * The run breaks on a different author, a different day, or a gap longer than\n * `windowMs`: a reply an hour later is a new beat in the conversation even when\n * nobody else spoke, and joining it to the earlier burst would put one timestamp\n * on messages an hour apart.\n *\n * Order is taken as given, oldest first, and never sorted here: a thread that\n * reorders what the server sent would fight optimistic inserts, where the\n * pending message is deliberately last.\n *\n * @param params.messages - Oldest first.\n * @param params.currentUserId - Author id treated as \"own\".\n * @param params.windowMs - Gap that still keeps a run together. Default 5 min.\n * @returns Sections in render order.\n */\nexport function groupMessages({\n messages,\n currentUserId,\n windowMs = DEFAULT_GROUP_WINDOW_MS,\n}: {\n messages: readonly ChatMessage[];\n currentUserId?: string;\n windowMs?: number;\n}): ChatSection[] {\n const sections: ChatSection[] = [];\n let day: number | null = null;\n let run: ChatRun | null = null;\n\n for (const message of messages) {\n const messageDay = startOfDay(message.sentAt);\n if (messageDay !== day) {\n day = messageDay;\n run = null;\n sections.push({ kind: \"day\", key: `day-${messageDay}`, date: messageDay });\n }\n\n const previous = run?.messages[run.messages.length - 1];\n const continues =\n run !== null &&\n previous !== undefined &&\n run.authorId === message.authorId &&\n message.sentAt - previous.sentAt <= windowMs;\n\n if (continues && run) {\n run.messages.push(message);\n continue;\n }\n\n run = {\n kind: \"run\",\n key: `${message.authorId}-${message.id}`,\n authorId: message.authorId,\n authorName: message.authorName,\n own: currentUserId !== undefined && message.authorId === currentUserId,\n messages: [message],\n };\n sections.push(run);\n }\n\n return sections;\n}\n\n/** Labels the thread needs, per locale. */\ninterface ChatStrings {\n thread: string;\n today: string;\n yesterday: string;\n you: string;\n typingOne: (name: string) => string;\n typingTwo: (a: string, b: string) => string;\n typingMany: (n: number) => string;\n sending: string;\n sent: string;\n read: string;\n failed: string;\n retry: string;\n empty: string;\n placeholder: string;\n send: string;\n deleted: string;\n edited: string;\n replyingTo: (name: string) => string;\n quoteRevoked: string;\n quoteKind: Record<ChatAttachmentKind, string>;\n reactions: string;\n react: (emoji: string, count: number) => string;\n deliveredAll: string;\n deliveredSome: (delivered: number, total: number) => string;\n readAll: string;\n readSome: (read: number, total: number) => string;\n messageActions: string;\n voiceNote: string;\n download: string;\n}\n\nconst PT_BR: ChatStrings = {\n thread: \"Conversa\",\n today: \"Hoje\",\n yesterday: \"Ontem\",\n you: \"Você\",\n typingOne: (name) => `${name} está digitando…`,\n typingTwo: (a, b) => `${a} e ${b} estão digitando…`,\n typingMany: (n) => `${n} pessoas estão digitando…`,\n sending: \"Enviando\",\n sent: \"Enviada\",\n read: \"Lida\",\n failed: \"Falhou ao enviar\",\n retry: \"Tentar de novo\",\n empty: \"Nenhuma mensagem ainda\",\n placeholder: \"Escreva uma mensagem\",\n send: \"Enviar\",\n deleted: \"Esta mensagem foi apagada\",\n edited: \"editada\",\n replyingTo: (name) => `Em resposta a ${name}`,\n quoteRevoked: \"Mensagem apagada\",\n quoteKind: {\n image: \"Foto\",\n video: \"Vídeo\",\n audio: \"Áudio\",\n voice: \"Mensagem de voz\",\n file: \"Documento\",\n },\n reactions: \"Reações\",\n react: (emoji, count) => `${emoji}, ${count} ${count === 1 ? \"pessoa\" : \"pessoas\"}`,\n deliveredAll: \"Entregue a todos\",\n deliveredSome: (delivered, total) => `Entregue a ${delivered} de ${total}`,\n readAll: \"Lida por todos\",\n readSome: (read, total) => `Lida por ${read} de ${total}`,\n messageActions: \"Ações da mensagem\",\n voiceNote: \"Mensagem de voz\",\n download: \"Baixar\",\n};\n\nconst EN: ChatStrings = {\n thread: \"Conversation\",\n today: \"Today\",\n yesterday: \"Yesterday\",\n you: \"You\",\n typingOne: (name) => `${name} is typing…`,\n typingTwo: (a, b) => `${a} and ${b} are typing…`,\n typingMany: (n) => `${n} people are typing…`,\n sending: \"Sending\",\n sent: \"Sent\",\n read: \"Read\",\n failed: \"Failed to send\",\n retry: \"Try again\",\n empty: \"No messages yet\",\n placeholder: \"Write a message\",\n send: \"Send\",\n deleted: \"This message was deleted\",\n edited: \"edited\",\n replyingTo: (name) => `Replying to ${name}`,\n quoteRevoked: \"Message deleted\",\n quoteKind: {\n image: \"Photo\",\n video: \"Video\",\n audio: \"Audio\",\n voice: \"Voice message\",\n file: \"Document\",\n },\n reactions: \"Reactions\",\n react: (emoji, count) => `${emoji}, ${count} ${count === 1 ? \"person\" : \"people\"}`,\n deliveredAll: \"Delivered to everyone\",\n deliveredSome: (delivered, total) => `Delivered to ${delivered} of ${total}`,\n readAll: \"Read by everyone\",\n readSome: (read, total) => `Read by ${read} of ${total}`,\n messageActions: \"Message actions\",\n voiceNote: \"Voice message\",\n download: \"Download\",\n};\n\n/** Locale strings for the thread. */\nexport function chatStrings(locale: \"pt-BR\" | \"en\"): ChatStrings {\n return locale === \"en\" ? EN : PT_BR;\n}\n\n/**\n * Label for a date heading: `\"Hoje\"`, `\"Ontem\"`, or the formatted date.\n *\n * @param date - Local midnight of the day being labelled.\n * @param params.now - Reference instant, so tests and SSR-free renders are stable.\n */\nexport function dayLabel(\n date: number,\n { locale = \"pt-BR\", now }: { locale?: \"pt-BR\" | \"en\"; now?: number } = {},\n): string {\n const strings = chatStrings(locale);\n const today = startOfDay(now ?? Date.now());\n const dayMs = 24 * 60 * 60 * 1000;\n if (date === today) return strings.today;\n if (date === today - dayMs) return strings.yesterday;\n return new Date(date).toLocaleDateString(locale === \"en\" ? \"en-US\" : \"pt-BR\", {\n day: \"2-digit\",\n month: \"short\",\n year: date < today - 300 * dayMs ? \"numeric\" : undefined,\n });\n}\n\n/** Clock label for a single message — the time, not a relative phrase. */\nexport function timeLabel(timestamp: number, locale: \"pt-BR\" | \"en\" = \"pt-BR\"): string {\n return new Date(timestamp).toLocaleTimeString(locale === \"en\" ? \"en-US\" : \"pt-BR\", {\n hour: \"2-digit\",\n minute: \"2-digit\",\n });\n}\n\n/** Sentence for the typing indicator, or `null` when nobody is typing. */\nexport function typingLabel(\n names: readonly string[],\n locale: \"pt-BR\" | \"en\" = \"pt-BR\",\n): string | null {\n const strings = chatStrings(locale);\n if (names.length === 0) return null;\n if (names.length === 1) return strings.typingOne(names[0]);\n if (names.length === 2) return strings.typingTwo(names[0], names[1]);\n return strings.typingMany(names.length);\n}\n"],"mappings":"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"}
@@ -14,18 +14,14 @@ function n({ messages: n, currentUserId: r, windowMs: i = e }) {
14
14
  date: n
15
15
  }));
16
16
  let c = s?.messages[s.messages.length - 1];
17
- if (s !== null && c !== void 0 && s.authorId === e.authorId && e.sentAt - c.sentAt <= i && s) {
18
- s.messages.push(e);
19
- continue;
20
- }
21
- s = {
17
+ s !== null && c !== void 0 && s.authorId === e.authorId && e.sentAt - c.sentAt <= i && s ? s.messages.push(e) : (s = {
22
18
  kind: "run",
23
19
  key: `${e.authorId}-${e.id}`,
24
20
  authorId: e.authorId,
25
21
  authorName: e.authorName,
26
22
  own: r !== void 0 && e.authorId === r,
27
23
  messages: [e]
28
- }, a.push(s);
24
+ }, a.push(s));
29
25
  }
30
26
  return a;
31
27
  }
@@ -1 +1 @@
1
- {"version":3,"file":"chat-groups.js","names":[],"sources":["../../../src/components/Chat/chat-groups.ts"],"sourcesContent":["import type { ReactNode } from \"react\";\n\n/** What a bubble can carry besides text. */\nexport type ChatAttachmentKind = \"image\" | \"video\" | \"audio\" | \"voice\" | \"file\";\n\n/** One attachment on a message. */\nexport interface ChatAttachment {\n /** Decides how it renders: a picture, a player, a voice note, a download row. */\n kind: ChatAttachmentKind;\n /** Where the bytes are. A blob URL works for a message still uploading. */\n url: string;\n /** File name, shown for `\"file\"` and used as the download name. */\n name?: string;\n /** MIME type, when the app knows it. */\n mimeType?: string;\n /** Size in bytes, shown next to a file. */\n sizeBytes?: number;\n /** Duration in ms, for audio, voice and video. */\n durationMs?: number;\n /** Poster for a video, or a smaller copy of an image. */\n thumbnailUrl?: string;\n /**\n * Normalised peaks, `0`–`1`, for a voice note.\n *\n * A voice note without one is a grey rectangle: the waveform is what tells\n * somebody whether this is a word or a two-minute monologue.\n */\n waveform?: readonly number[];\n /** Alternative text for an image. */\n alt?: string;\n}\n\n/**\n * The stub of the message being replied to, shown above the body.\n *\n * `revoked` is not decoration: deleting the quoted message has to blank the\n * quoted text, or it leaks through everyone who replied to it.\n */\nexport interface ChatQuote {\n /** Id of the quoted message, so the app can scroll to it. */\n messageId: string;\n /** Who wrote it. */\n senderName?: string;\n /** A short piece of what it said. The component never truncates for you. */\n excerpt?: string;\n /** What the quoted message was, when it was not text. */\n kind?: \"text\" | ChatAttachmentKind;\n /** The quoted message was deleted — the excerpt is not shown. */\n revoked?: boolean;\n}\n\n/** One emoji on a message, with its tally. */\nexport interface ChatReaction {\n /** The emoji itself. */\n emoji: string;\n /** How many people reacted with it. */\n count: number;\n /** Whether the current user is one of them — the chip reads as pressed. */\n reacted?: boolean;\n /** Who reacted, for the chip's tooltip. */\n names?: readonly string[];\n}\n\n/**\n * Per-recipient delivery, which is what a group needs.\n *\n * `status` is a boolean for the sender: it cannot say \"delivered to everyone\"\n * versus \"read by everyone\", and only the second one turns the ticks blue.\n */\nexport interface ChatReceipt {\n /** How many recipients have received it. */\n deliveredTo: number;\n /** How many have read it. */\n readBy: number;\n /** How many recipients there are. */\n totalRecipients: number;\n}\n\n/** One entry in a thread. */\nexport interface ChatMessage {\n /** Stable identity. Used as the React key and by `onRetry`. */\n id: string;\n /**\n * What was said. A node, so an app can render a link, an image or a quote.\n *\n * Optional, because a message can be all attachment, or be a tombstone: a\n * deleted message has no body to show, and requiring one made every app\n * invent a placeholder string for the state the component now owns.\n */\n body?: ReactNode;\n /** Who said it. Compared against `currentUserId` to decide sides. */\n authorId: string;\n /** Display name. Falls back to `authorId` in the header of a run. */\n authorName?: string;\n /** Epoch milliseconds. */\n sentAt: number;\n /**\n * Delivery state of an outgoing message.\n *\n * `\"failed\"` is the one that matters: without it an app has to invent its own\n * way to say \"this never left\", and the user re-types a message that is\n * sitting right there.\n */\n status?: \"sending\" | \"sent\" | \"read\" | \"failed\";\n /**\n * Per-recipient delivery. Takes precedence over `status` for the ticks.\n *\n * Use it in a group, where \"delivered to all\" and \"read by all\" are different\n * states and `status` can only say one thing.\n */\n receipt?: ChatReceipt;\n /** Media, voice notes and documents carried by this message. */\n attachments?: readonly ChatAttachment[];\n /** The message this one replies to. */\n quote?: ChatQuote;\n /** Emoji reactions, already tallied by the app. */\n reactions?: readonly ChatReaction[];\n /**\n * The message was deleted — it renders as a tombstone.\n *\n * A state, not a `body` the app swaps for a string: as a state the quote of\n * it can be blanked too, and every app stops writing its own wording.\n */\n deleted?: boolean;\n /** The message was edited after it was sent. */\n edited?: boolean;\n /** Anything the app wants to carry through to its own renderers. */\n data?: Record<string, unknown>;\n}\n\n/** A run of consecutive messages from one author, under one day. */\nexport interface ChatRun {\n kind: \"run\";\n /** `${authorId}-${first message id}` — stable across re-renders. */\n key: string;\n authorId: string;\n authorName?: string;\n /** Whether this run belongs to the current user. */\n own: boolean;\n messages: ChatMessage[];\n}\n\n/** A date heading between runs. */\nexport interface ChatDay {\n kind: \"day\";\n key: string;\n /** Midnight of that local day, epoch ms — the label is formatted by the view. */\n date: number;\n}\n\nexport type ChatSection = ChatDay | ChatRun;\n\n/** Default window in which consecutive messages from one author stay in a run. */\nexport const DEFAULT_GROUP_WINDOW_MS = 5 * 60 * 1000;\n\n/** Local midnight of an instant, epoch ms. */\nfunction startOfDay(timestamp: number): number {\n const date = new Date(timestamp);\n date.setHours(0, 0, 0, 0);\n return date.getTime();\n}\n\n/**\n * Turn a flat message list into the sections a thread renders: a date heading\n * whenever the local day changes, and runs of consecutive messages from the same\n * author.\n *\n * Grouping is what makes a thread readable — repeating the avatar and the name on\n * every line of a five-line burst turns a conversation into a list of receipts.\n * The run breaks on a different author, a different day, or a gap longer than\n * `windowMs`: a reply an hour later is a new beat in the conversation even when\n * nobody else spoke, and joining it to the earlier burst would put one timestamp\n * on messages an hour apart.\n *\n * Order is taken as given, oldest first, and never sorted here: a thread that\n * reorders what the server sent would fight optimistic inserts, where the\n * pending message is deliberately last.\n *\n * @param params.messages - Oldest first.\n * @param params.currentUserId - Author id treated as \"own\".\n * @param params.windowMs - Gap that still keeps a run together. Default 5 min.\n * @returns Sections in render order.\n */\nexport function groupMessages({\n messages,\n currentUserId,\n windowMs = DEFAULT_GROUP_WINDOW_MS,\n}: {\n messages: readonly ChatMessage[];\n currentUserId?: string;\n windowMs?: number;\n}): ChatSection[] {\n const sections: ChatSection[] = [];\n let day: number | null = null;\n let run: ChatRun | null = null;\n\n for (const message of messages) {\n const messageDay = startOfDay(message.sentAt);\n if (messageDay !== day) {\n day = messageDay;\n run = null;\n sections.push({ kind: \"day\", key: `day-${messageDay}`, date: messageDay });\n }\n\n const previous = run?.messages[run.messages.length - 1];\n const continues =\n run !== null &&\n previous !== undefined &&\n run.authorId === message.authorId &&\n message.sentAt - previous.sentAt <= windowMs;\n\n if (continues && run) {\n run.messages.push(message);\n continue;\n }\n\n run = {\n kind: \"run\",\n key: `${message.authorId}-${message.id}`,\n authorId: message.authorId,\n authorName: message.authorName,\n own: currentUserId !== undefined && message.authorId === currentUserId,\n messages: [message],\n };\n sections.push(run);\n }\n\n return sections;\n}\n\n/** Labels the thread needs, per locale. */\ninterface ChatStrings {\n thread: string;\n today: string;\n yesterday: string;\n you: string;\n typingOne: (name: string) => string;\n typingTwo: (a: string, b: string) => string;\n typingMany: (n: number) => string;\n sending: string;\n sent: string;\n read: string;\n failed: string;\n retry: string;\n empty: string;\n placeholder: string;\n send: string;\n deleted: string;\n edited: string;\n replyingTo: (name: string) => string;\n quoteRevoked: string;\n quoteKind: Record<ChatAttachmentKind, string>;\n reactions: string;\n react: (emoji: string, count: number) => string;\n deliveredAll: string;\n deliveredSome: (delivered: number, total: number) => string;\n readAll: string;\n readSome: (read: number, total: number) => string;\n messageActions: string;\n voiceNote: string;\n download: string;\n}\n\nconst PT_BR: ChatStrings = {\n thread: \"Conversa\",\n today: \"Hoje\",\n yesterday: \"Ontem\",\n you: \"Você\",\n typingOne: (name) => `${name} está digitando…`,\n typingTwo: (a, b) => `${a} e ${b} estão digitando…`,\n typingMany: (n) => `${n} pessoas estão digitando…`,\n sending: \"Enviando\",\n sent: \"Enviada\",\n read: \"Lida\",\n failed: \"Falhou ao enviar\",\n retry: \"Tentar de novo\",\n empty: \"Nenhuma mensagem ainda\",\n placeholder: \"Escreva uma mensagem\",\n send: \"Enviar\",\n deleted: \"Esta mensagem foi apagada\",\n edited: \"editada\",\n replyingTo: (name) => `Em resposta a ${name}`,\n quoteRevoked: \"Mensagem apagada\",\n quoteKind: {\n image: \"Foto\",\n video: \"Vídeo\",\n audio: \"Áudio\",\n voice: \"Mensagem de voz\",\n file: \"Documento\",\n },\n reactions: \"Reações\",\n react: (emoji, count) => `${emoji}, ${count} ${count === 1 ? \"pessoa\" : \"pessoas\"}`,\n deliveredAll: \"Entregue a todos\",\n deliveredSome: (delivered, total) => `Entregue a ${delivered} de ${total}`,\n readAll: \"Lida por todos\",\n readSome: (read, total) => `Lida por ${read} de ${total}`,\n messageActions: \"Ações da mensagem\",\n voiceNote: \"Mensagem de voz\",\n download: \"Baixar\",\n};\n\nconst EN: ChatStrings = {\n thread: \"Conversation\",\n today: \"Today\",\n yesterday: \"Yesterday\",\n you: \"You\",\n typingOne: (name) => `${name} is typing…`,\n typingTwo: (a, b) => `${a} and ${b} are typing…`,\n typingMany: (n) => `${n} people are typing…`,\n sending: \"Sending\",\n sent: \"Sent\",\n read: \"Read\",\n failed: \"Failed to send\",\n retry: \"Try again\",\n empty: \"No messages yet\",\n placeholder: \"Write a message\",\n send: \"Send\",\n deleted: \"This message was deleted\",\n edited: \"edited\",\n replyingTo: (name) => `Replying to ${name}`,\n quoteRevoked: \"Message deleted\",\n quoteKind: {\n image: \"Photo\",\n video: \"Video\",\n audio: \"Audio\",\n voice: \"Voice message\",\n file: \"Document\",\n },\n reactions: \"Reactions\",\n react: (emoji, count) => `${emoji}, ${count} ${count === 1 ? \"person\" : \"people\"}`,\n deliveredAll: \"Delivered to everyone\",\n deliveredSome: (delivered, total) => `Delivered to ${delivered} of ${total}`,\n readAll: \"Read by everyone\",\n readSome: (read, total) => `Read by ${read} of ${total}`,\n messageActions: \"Message actions\",\n voiceNote: \"Voice message\",\n download: \"Download\",\n};\n\n/** Locale strings for the thread. */\nexport function chatStrings(locale: \"pt-BR\" | \"en\"): ChatStrings {\n return locale === \"en\" ? EN : PT_BR;\n}\n\n/**\n * Label for a date heading: `\"Hoje\"`, `\"Ontem\"`, or the formatted date.\n *\n * @param date - Local midnight of the day being labelled.\n * @param params.now - Reference instant, so tests and SSR-free renders are stable.\n */\nexport function dayLabel(\n date: number,\n { locale = \"pt-BR\", now }: { locale?: \"pt-BR\" | \"en\"; now?: number } = {},\n): string {\n const strings = chatStrings(locale);\n const today = startOfDay(now ?? Date.now());\n const dayMs = 24 * 60 * 60 * 1000;\n if (date === today) return strings.today;\n if (date === today - dayMs) return strings.yesterday;\n return new Date(date).toLocaleDateString(locale === \"en\" ? \"en-US\" : \"pt-BR\", {\n day: \"2-digit\",\n month: \"short\",\n year: date < today - 300 * dayMs ? \"numeric\" : undefined,\n });\n}\n\n/** Clock label for a single message — the time, not a relative phrase. */\nexport function timeLabel(timestamp: number, locale: \"pt-BR\" | \"en\" = \"pt-BR\"): string {\n return new Date(timestamp).toLocaleTimeString(locale === \"en\" ? \"en-US\" : \"pt-BR\", {\n hour: \"2-digit\",\n minute: \"2-digit\",\n });\n}\n\n/** Sentence for the typing indicator, or `null` when nobody is typing. */\nexport function typingLabel(\n names: readonly string[],\n locale: \"pt-BR\" | \"en\" = \"pt-BR\",\n): string | null {\n const strings = chatStrings(locale);\n if (names.length === 0) return null;\n if (names.length === 1) return strings.typingOne(names[0]);\n if (names.length === 2) return strings.typingTwo(names[0], names[1]);\n return strings.typingMany(names.length);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"chat-groups.js","names":["DEFAULT_GROUP_WINDOW_MS","startOfDay","date","timestamp","groupMessages","sections","day","run","message","messages","messageDay","previous","windowMs","currentUserId","PT_BR","name","a","b","n","emoji","count","delivered","total","read","EN","chatStrings","locale","dayLabel","strings","today","now","dayMs","timeLabel","typingLabel","names"],"sources":["../../../src/components/Chat/chat-groups.ts"],"sourcesContent":["import type { ReactNode } from \"react\";\n\n/** What a bubble can carry besides text. */\nexport type ChatAttachmentKind = \"image\" | \"video\" | \"audio\" | \"voice\" | \"file\";\n\n/** One attachment on a message. */\nexport interface ChatAttachment {\n /** Decides how it renders: a picture, a player, a voice note, a download row. */\n kind: ChatAttachmentKind;\n /** Where the bytes are. A blob URL works for a message still uploading. */\n url: string;\n /** File name, shown for `\"file\"` and used as the download name. */\n name?: string;\n /** MIME type, when the app knows it. */\n mimeType?: string;\n /** Size in bytes, shown next to a file. */\n sizeBytes?: number;\n /** Duration in ms, for audio, voice and video. */\n durationMs?: number;\n /** Poster for a video, or a smaller copy of an image. */\n thumbnailUrl?: string;\n /**\n * Normalised peaks, `0`–`1`, for a voice note.\n *\n * A voice note without one is a grey rectangle: the waveform is what tells\n * somebody whether this is a word or a two-minute monologue.\n */\n waveform?: readonly number[];\n /** Alternative text for an image. */\n alt?: string;\n}\n\n/**\n * The stub of the message being replied to, shown above the body.\n *\n * `revoked` is not decoration: deleting the quoted message has to blank the\n * quoted text, or it leaks through everyone who replied to it.\n */\nexport interface ChatQuote {\n /** Id of the quoted message, so the app can scroll to it. */\n messageId: string;\n /** Who wrote it. */\n senderName?: string;\n /** A short piece of what it said. The component never truncates for you. */\n excerpt?: string;\n /** What the quoted message was, when it was not text. */\n kind?: \"text\" | ChatAttachmentKind;\n /** The quoted message was deleted — the excerpt is not shown. */\n revoked?: boolean;\n}\n\n/** One emoji on a message, with its tally. */\nexport interface ChatReaction {\n /** The emoji itself. */\n emoji: string;\n /** How many people reacted with it. */\n count: number;\n /** Whether the current user is one of them — the chip reads as pressed. */\n reacted?: boolean;\n /** Who reacted, for the chip's tooltip. */\n names?: readonly string[];\n}\n\n/**\n * Per-recipient delivery, which is what a group needs.\n *\n * `status` is a boolean for the sender: it cannot say \"delivered to everyone\"\n * versus \"read by everyone\", and only the second one turns the ticks blue.\n */\nexport interface ChatReceipt {\n /** How many recipients have received it. */\n deliveredTo: number;\n /** How many have read it. */\n readBy: number;\n /** How many recipients there are. */\n totalRecipients: number;\n}\n\n/** One entry in a thread. */\nexport interface ChatMessage {\n /** Stable identity. Used as the React key and by `onRetry`. */\n id: string;\n /**\n * What was said. A node, so an app can render a link, an image or a quote.\n *\n * Optional, because a message can be all attachment, or be a tombstone: a\n * deleted message has no body to show, and requiring one made every app\n * invent a placeholder string for the state the component now owns.\n */\n body?: ReactNode;\n /** Who said it. Compared against `currentUserId` to decide sides. */\n authorId: string;\n /** Display name. Falls back to `authorId` in the header of a run. */\n authorName?: string;\n /** Epoch milliseconds. */\n sentAt: number;\n /**\n * Delivery state of an outgoing message.\n *\n * `\"failed\"` is the one that matters: without it an app has to invent its own\n * way to say \"this never left\", and the user re-types a message that is\n * sitting right there.\n */\n status?: \"sending\" | \"sent\" | \"read\" | \"failed\";\n /**\n * Per-recipient delivery. Takes precedence over `status` for the ticks.\n *\n * Use it in a group, where \"delivered to all\" and \"read by all\" are different\n * states and `status` can only say one thing.\n */\n receipt?: ChatReceipt;\n /** Media, voice notes and documents carried by this message. */\n attachments?: readonly ChatAttachment[];\n /** The message this one replies to. */\n quote?: ChatQuote;\n /** Emoji reactions, already tallied by the app. */\n reactions?: readonly ChatReaction[];\n /**\n * The message was deleted — it renders as a tombstone.\n *\n * A state, not a `body` the app swaps for a string: as a state the quote of\n * it can be blanked too, and every app stops writing its own wording.\n */\n deleted?: boolean;\n /** The message was edited after it was sent. */\n edited?: boolean;\n /** Anything the app wants to carry through to its own renderers. */\n data?: Record<string, unknown>;\n}\n\n/** A run of consecutive messages from one author, under one day. */\nexport interface ChatRun {\n kind: \"run\";\n /** `${authorId}-${first message id}` — stable across re-renders. */\n key: string;\n authorId: string;\n authorName?: string;\n /** Whether this run belongs to the current user. */\n own: boolean;\n messages: ChatMessage[];\n}\n\n/** A date heading between runs. */\nexport interface ChatDay {\n kind: \"day\";\n key: string;\n /** Midnight of that local day, epoch ms — the label is formatted by the view. */\n date: number;\n}\n\nexport type ChatSection = ChatDay | ChatRun;\n\n/** Default window in which consecutive messages from one author stay in a run. */\nexport const DEFAULT_GROUP_WINDOW_MS = 5 * 60 * 1000;\n\n/** Local midnight of an instant, epoch ms. */\nfunction startOfDay(timestamp: number): number {\n const date = new Date(timestamp);\n date.setHours(0, 0, 0, 0);\n return date.getTime();\n}\n\n/**\n * Turn a flat message list into the sections a thread renders: a date heading\n * whenever the local day changes, and runs of consecutive messages from the same\n * author.\n *\n * Grouping is what makes a thread readable — repeating the avatar and the name on\n * every line of a five-line burst turns a conversation into a list of receipts.\n * The run breaks on a different author, a different day, or a gap longer than\n * `windowMs`: a reply an hour later is a new beat in the conversation even when\n * nobody else spoke, and joining it to the earlier burst would put one timestamp\n * on messages an hour apart.\n *\n * Order is taken as given, oldest first, and never sorted here: a thread that\n * reorders what the server sent would fight optimistic inserts, where the\n * pending message is deliberately last.\n *\n * @param params.messages - Oldest first.\n * @param params.currentUserId - Author id treated as \"own\".\n * @param params.windowMs - Gap that still keeps a run together. Default 5 min.\n * @returns Sections in render order.\n */\nexport function groupMessages({\n messages,\n currentUserId,\n windowMs = DEFAULT_GROUP_WINDOW_MS,\n}: {\n messages: readonly ChatMessage[];\n currentUserId?: string;\n windowMs?: number;\n}): ChatSection[] {\n const sections: ChatSection[] = [];\n let day: number | null = null;\n let run: ChatRun | null = null;\n\n for (const message of messages) {\n const messageDay = startOfDay(message.sentAt);\n if (messageDay !== day) {\n day = messageDay;\n run = null;\n sections.push({ kind: \"day\", key: `day-${messageDay}`, date: messageDay });\n }\n\n const previous = run?.messages[run.messages.length - 1];\n const continues =\n run !== null &&\n previous !== undefined &&\n run.authorId === message.authorId &&\n message.sentAt - previous.sentAt <= windowMs;\n\n if (continues && run) {\n run.messages.push(message);\n continue;\n }\n\n run = {\n kind: \"run\",\n key: `${message.authorId}-${message.id}`,\n authorId: message.authorId,\n authorName: message.authorName,\n own: currentUserId !== undefined && message.authorId === currentUserId,\n messages: [message],\n };\n sections.push(run);\n }\n\n return sections;\n}\n\n/** Labels the thread needs, per locale. */\ninterface ChatStrings {\n thread: string;\n today: string;\n yesterday: string;\n you: string;\n typingOne: (name: string) => string;\n typingTwo: (a: string, b: string) => string;\n typingMany: (n: number) => string;\n sending: string;\n sent: string;\n read: string;\n failed: string;\n retry: string;\n empty: string;\n placeholder: string;\n send: string;\n deleted: string;\n edited: string;\n replyingTo: (name: string) => string;\n quoteRevoked: string;\n quoteKind: Record<ChatAttachmentKind, string>;\n reactions: string;\n react: (emoji: string, count: number) => string;\n deliveredAll: string;\n deliveredSome: (delivered: number, total: number) => string;\n readAll: string;\n readSome: (read: number, total: number) => string;\n messageActions: string;\n voiceNote: string;\n download: string;\n}\n\nconst PT_BR: ChatStrings = {\n thread: \"Conversa\",\n today: \"Hoje\",\n yesterday: \"Ontem\",\n you: \"Você\",\n typingOne: (name) => `${name} está digitando…`,\n typingTwo: (a, b) => `${a} e ${b} estão digitando…`,\n typingMany: (n) => `${n} pessoas estão digitando…`,\n sending: \"Enviando\",\n sent: \"Enviada\",\n read: \"Lida\",\n failed: \"Falhou ao enviar\",\n retry: \"Tentar de novo\",\n empty: \"Nenhuma mensagem ainda\",\n placeholder: \"Escreva uma mensagem\",\n send: \"Enviar\",\n deleted: \"Esta mensagem foi apagada\",\n edited: \"editada\",\n replyingTo: (name) => `Em resposta a ${name}`,\n quoteRevoked: \"Mensagem apagada\",\n quoteKind: {\n image: \"Foto\",\n video: \"Vídeo\",\n audio: \"Áudio\",\n voice: \"Mensagem de voz\",\n file: \"Documento\",\n },\n reactions: \"Reações\",\n react: (emoji, count) => `${emoji}, ${count} ${count === 1 ? \"pessoa\" : \"pessoas\"}`,\n deliveredAll: \"Entregue a todos\",\n deliveredSome: (delivered, total) => `Entregue a ${delivered} de ${total}`,\n readAll: \"Lida por todos\",\n readSome: (read, total) => `Lida por ${read} de ${total}`,\n messageActions: \"Ações da mensagem\",\n voiceNote: \"Mensagem de voz\",\n download: \"Baixar\",\n};\n\nconst EN: ChatStrings = {\n thread: \"Conversation\",\n today: \"Today\",\n yesterday: \"Yesterday\",\n you: \"You\",\n typingOne: (name) => `${name} is typing…`,\n typingTwo: (a, b) => `${a} and ${b} are typing…`,\n typingMany: (n) => `${n} people are typing…`,\n sending: \"Sending\",\n sent: \"Sent\",\n read: \"Read\",\n failed: \"Failed to send\",\n retry: \"Try again\",\n empty: \"No messages yet\",\n placeholder: \"Write a message\",\n send: \"Send\",\n deleted: \"This message was deleted\",\n edited: \"edited\",\n replyingTo: (name) => `Replying to ${name}`,\n quoteRevoked: \"Message deleted\",\n quoteKind: {\n image: \"Photo\",\n video: \"Video\",\n audio: \"Audio\",\n voice: \"Voice message\",\n file: \"Document\",\n },\n reactions: \"Reactions\",\n react: (emoji, count) => `${emoji}, ${count} ${count === 1 ? \"person\" : \"people\"}`,\n deliveredAll: \"Delivered to everyone\",\n deliveredSome: (delivered, total) => `Delivered to ${delivered} of ${total}`,\n readAll: \"Read by everyone\",\n readSome: (read, total) => `Read by ${read} of ${total}`,\n messageActions: \"Message actions\",\n voiceNote: \"Voice message\",\n download: \"Download\",\n};\n\n/** Locale strings for the thread. */\nexport function chatStrings(locale: \"pt-BR\" | \"en\"): ChatStrings {\n return locale === \"en\" ? EN : PT_BR;\n}\n\n/**\n * Label for a date heading: `\"Hoje\"`, `\"Ontem\"`, or the formatted date.\n *\n * @param date - Local midnight of the day being labelled.\n * @param params.now - Reference instant, so tests and SSR-free renders are stable.\n */\nexport function dayLabel(\n date: number,\n { locale = \"pt-BR\", now }: { locale?: \"pt-BR\" | \"en\"; now?: number } = {},\n): string {\n const strings = chatStrings(locale);\n const today = startOfDay(now ?? Date.now());\n const dayMs = 24 * 60 * 60 * 1000;\n if (date === today) return strings.today;\n if (date === today - dayMs) return strings.yesterday;\n return new Date(date).toLocaleDateString(locale === \"en\" ? \"en-US\" : \"pt-BR\", {\n day: \"2-digit\",\n month: \"short\",\n year: date < today - 300 * dayMs ? \"numeric\" : undefined,\n });\n}\n\n/** Clock label for a single message — the time, not a relative phrase. */\nexport function timeLabel(timestamp: number, locale: \"pt-BR\" | \"en\" = \"pt-BR\"): string {\n return new Date(timestamp).toLocaleTimeString(locale === \"en\" ? \"en-US\" : \"pt-BR\", {\n hour: \"2-digit\",\n minute: \"2-digit\",\n });\n}\n\n/** Sentence for the typing indicator, or `null` when nobody is typing. */\nexport function typingLabel(\n names: readonly string[],\n locale: \"pt-BR\" | \"en\" = \"pt-BR\",\n): string | null {\n const strings = chatStrings(locale);\n if (names.length === 0) return null;\n if (names.length === 1) return strings.typingOne(names[0]);\n if (names.length === 2) return strings.typingTwo(names[0], names[1]);\n return strings.typingMany(names.length);\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"chat-receipt.cjs","names":[],"sources":["../../../src/components/Chat/chat-receipt.ts"],"sourcesContent":["import type { ChatMessage, ChatReceipt } from \"./chat-groups\";\n\n/**\n * What the ticks on an outgoing message say.\n *\n * `\"read\"` is the only one that turns them blue, and in a group that means\n * **everyone** has read it — the distinction `status: \"read\"` cannot make.\n */\nexport type ChatReceiptState = \"sending\" | \"sent\" | \"delivered\" | \"read\" | \"failed\";\n\n/**\n * Resolve the tick state of an outgoing message.\n *\n * A group needs three states where a single message has two: sent to the server,\n * delivered to the recipients, read by the recipients. A boolean `status` collapses\n * the middle one, so an app that has per-recipient counts either invents its own\n * glyph or shows a message as read when one person out of nine opened it.\n *\n * The counts win when they are there, and the thresholds are deliberately \"all\":\n * blue ticks in every messenger mean the whole room, and reporting \"read\" for a\n * partial count is the failure that makes people distrust the indicator entirely.\n * A `totalRecipients` of zero — a note to self, a thread whose membership the app\n * does not track — falls back to `status`, because \"read by all of nobody\" is not\n * a claim worth making.\n *\n * `\"failed\"` and `\"sending\"` come from `status` regardless: they are about this\n * side of the wire, and no recipient count exists yet.\n *\n * @param message - The message being rendered.\n * @returns The tick state, or `null` when there is nothing to show.\n */\nexport function resolveReceiptState(message: ChatMessage): ChatReceiptState | null {\n if (message.status === \"failed\" || message.status === \"sending\") return message.status;\n const receipt = message.receipt;\n if (!receipt || receipt.totalRecipients <= 0) return message.status ?? null;\n if (receipt.readBy >= receipt.totalRecipients) return \"read\";\n if (receipt.deliveredTo >= receipt.totalRecipients) return \"delivered\";\n return message.status ?? \"sent\";\n}\n\n/**\n * The sentence a reader gets for a receipt, for the tooltip and the screen reader.\n *\n * Partial counts are spelled out rather than rounded to a state: \"delivered to 3\n * of 9\" is the information the sender actually wants when the ticks are not blue\n * yet, and it is the part a glyph cannot carry.\n *\n * @param receipt - Per-recipient counts.\n * @param strings - Locale strings for the thread.\n * @returns One sentence describing delivery and reading.\n */\nexport function receiptLabel(\n receipt: ChatReceipt,\n strings: {\n deliveredAll: string;\n deliveredSome: (delivered: number, total: number) => string;\n readAll: string;\n readSome: (read: number, total: number) => string;\n },\n): string {\n const { deliveredTo, readBy, totalRecipients } = receipt;\n if (readBy >= totalRecipients) return strings.readAll;\n if (readBy > 0) return strings.readSome(readBy, totalRecipients);\n if (deliveredTo >= totalRecipients) return strings.deliveredAll;\n return strings.deliveredSome(deliveredTo, totalRecipients);\n}\n"],"mappings":"AA+BA,SAAgB,EAAoB,EAA+C,CAC/E,GAAI,EAAQ,SAAW,UAAY,EAAQ,SAAW,UAAW,OAAO,EAAQ,OAChF,IAAM,EAAU,EAAQ,QAIxB,MAHI,CAAC,GAAW,EAAQ,iBAAmB,EAAU,EAAQ,QAAU,KACnE,EAAQ,QAAU,EAAQ,gBAAwB,OAClD,EAAQ,aAAe,EAAQ,gBAAwB,YACpD,EAAQ,QAAU,MAC7B,CAaA,SAAgB,EACZ,EACA,EAMM,CACN,GAAM,CAAE,cAAa,SAAQ,mBAAoB,EAIjD,OAHI,GAAU,EAAwB,EAAQ,QAC1C,EAAS,EAAU,EAAQ,SAAS,EAAQ,CAAe,EAC3D,GAAe,EAAwB,EAAQ,aAC5C,EAAQ,cAAc,EAAa,CAAe,CAC7D"}
1
+ {"version":3,"file":"chat-receipt.cjs","names":["resolveReceiptState","message","receipt","receiptLabel","readBy","totalRecipients","strings","deliveredTo"],"sources":["../../../src/components/Chat/chat-receipt.ts"],"sourcesContent":["import type { ChatMessage, ChatReceipt } from \"./chat-groups\";\n\n/**\n * What the ticks on an outgoing message say.\n *\n * `\"read\"` is the only one that turns them blue, and in a group that means\n * **everyone** has read it — the distinction `status: \"read\"` cannot make.\n */\nexport type ChatReceiptState = \"sending\" | \"sent\" | \"delivered\" | \"read\" | \"failed\";\n\n/**\n * Resolve the tick state of an outgoing message.\n *\n * A group needs three states where a single message has two: sent to the server,\n * delivered to the recipients, read by the recipients. A boolean `status` collapses\n * the middle one, so an app that has per-recipient counts either invents its own\n * glyph or shows a message as read when one person out of nine opened it.\n *\n * The counts win when they are there, and the thresholds are deliberately \"all\":\n * blue ticks in every messenger mean the whole room, and reporting \"read\" for a\n * partial count is the failure that makes people distrust the indicator entirely.\n * A `totalRecipients` of zero — a note to self, a thread whose membership the app\n * does not track — falls back to `status`, because \"read by all of nobody\" is not\n * a claim worth making.\n *\n * `\"failed\"` and `\"sending\"` come from `status` regardless: they are about this\n * side of the wire, and no recipient count exists yet.\n *\n * @param message - The message being rendered.\n * @returns The tick state, or `null` when there is nothing to show.\n */\nexport function resolveReceiptState(message: ChatMessage): ChatReceiptState | null {\n if (message.status === \"failed\" || message.status === \"sending\") return message.status;\n const receipt = message.receipt;\n if (!receipt || receipt.totalRecipients <= 0) return message.status ?? null;\n if (receipt.readBy >= receipt.totalRecipients) return \"read\";\n if (receipt.deliveredTo >= receipt.totalRecipients) return \"delivered\";\n return message.status ?? \"sent\";\n}\n\n/**\n * The sentence a reader gets for a receipt, for the tooltip and the screen reader.\n *\n * Partial counts are spelled out rather than rounded to a state: \"delivered to 3\n * of 9\" is the information the sender actually wants when the ticks are not blue\n * yet, and it is the part a glyph cannot carry.\n *\n * @param receipt - Per-recipient counts.\n * @param strings - Locale strings for the thread.\n * @returns One sentence describing delivery and reading.\n */\nexport function receiptLabel(\n receipt: ChatReceipt,\n strings: {\n deliveredAll: string;\n deliveredSome: (delivered: number, total: number) => string;\n readAll: string;\n readSome: (read: number, total: number) => string;\n },\n): string {\n const { deliveredTo, readBy, totalRecipients } = receipt;\n if (readBy >= totalRecipients) return strings.readAll;\n if (readBy > 0) return strings.readSome(readBy, totalRecipients);\n if (deliveredTo >= totalRecipients) return strings.deliveredAll;\n return strings.deliveredSome(deliveredTo, totalRecipients);\n}\n"],"mappings":"AA+BA,SAAgBA,EAAoB,EAA+C,CAC/E,GAAIC,EAAQ,SAAW,UAAYA,EAAQ,SAAW,UAAW,OAAOA,EAAQ,OAChF,IAAMC,EAAUD,EAAQ,QAIxB,MAHI,CAACC,GAAWA,EAAQ,iBAAmB,EAAUD,EAAQ,QAAU,KACnEC,EAAQ,QAAUA,EAAQ,gBAAwB,OAClDA,EAAQ,aAAeA,EAAQ,gBAAwB,YACpDD,EAAQ,QAAU,MAC7B,CAaA,SAAgBE,EACZ,EACA,EAMM,CACN,GAAM,CAAE,cAAa,SAAQ,mBAAoBD,EAIjD,OAHIE,GAAUC,EAAwBC,EAAQ,QAC1CF,EAAS,EAAUE,EAAQ,SAASF,EAAQC,CAAe,EAC3DE,GAAeF,EAAwBC,EAAQ,aAC5CA,EAAQ,cAAcC,EAAaF,CAAe,CAC7D,C"}
@@ -1 +1 @@
1
- {"version":3,"file":"chat-receipt.js","names":[],"sources":["../../../src/components/Chat/chat-receipt.ts"],"sourcesContent":["import type { ChatMessage, ChatReceipt } from \"./chat-groups\";\n\n/**\n * What the ticks on an outgoing message say.\n *\n * `\"read\"` is the only one that turns them blue, and in a group that means\n * **everyone** has read it — the distinction `status: \"read\"` cannot make.\n */\nexport type ChatReceiptState = \"sending\" | \"sent\" | \"delivered\" | \"read\" | \"failed\";\n\n/**\n * Resolve the tick state of an outgoing message.\n *\n * A group needs three states where a single message has two: sent to the server,\n * delivered to the recipients, read by the recipients. A boolean `status` collapses\n * the middle one, so an app that has per-recipient counts either invents its own\n * glyph or shows a message as read when one person out of nine opened it.\n *\n * The counts win when they are there, and the thresholds are deliberately \"all\":\n * blue ticks in every messenger mean the whole room, and reporting \"read\" for a\n * partial count is the failure that makes people distrust the indicator entirely.\n * A `totalRecipients` of zero — a note to self, a thread whose membership the app\n * does not track — falls back to `status`, because \"read by all of nobody\" is not\n * a claim worth making.\n *\n * `\"failed\"` and `\"sending\"` come from `status` regardless: they are about this\n * side of the wire, and no recipient count exists yet.\n *\n * @param message - The message being rendered.\n * @returns The tick state, or `null` when there is nothing to show.\n */\nexport function resolveReceiptState(message: ChatMessage): ChatReceiptState | null {\n if (message.status === \"failed\" || message.status === \"sending\") return message.status;\n const receipt = message.receipt;\n if (!receipt || receipt.totalRecipients <= 0) return message.status ?? null;\n if (receipt.readBy >= receipt.totalRecipients) return \"read\";\n if (receipt.deliveredTo >= receipt.totalRecipients) return \"delivered\";\n return message.status ?? \"sent\";\n}\n\n/**\n * The sentence a reader gets for a receipt, for the tooltip and the screen reader.\n *\n * Partial counts are spelled out rather than rounded to a state: \"delivered to 3\n * of 9\" is the information the sender actually wants when the ticks are not blue\n * yet, and it is the part a glyph cannot carry.\n *\n * @param receipt - Per-recipient counts.\n * @param strings - Locale strings for the thread.\n * @returns One sentence describing delivery and reading.\n */\nexport function receiptLabel(\n receipt: ChatReceipt,\n strings: {\n deliveredAll: string;\n deliveredSome: (delivered: number, total: number) => string;\n readAll: string;\n readSome: (read: number, total: number) => string;\n },\n): string {\n const { deliveredTo, readBy, totalRecipients } = receipt;\n if (readBy >= totalRecipients) return strings.readAll;\n if (readBy > 0) return strings.readSome(readBy, totalRecipients);\n if (deliveredTo >= totalRecipients) return strings.deliveredAll;\n return strings.deliveredSome(deliveredTo, totalRecipients);\n}\n"],"mappings":";AA+BA,SAAgB,EAAoB,GAA+C;CAC/E,IAAI,EAAQ,WAAW,YAAY,EAAQ,WAAW,WAAW,OAAO,EAAQ;CAChF,IAAM,IAAU,EAAQ;CAIxB,OAHI,CAAC,KAAW,EAAQ,mBAAmB,IAAU,EAAQ,UAAU,OACnE,EAAQ,UAAU,EAAQ,kBAAwB,SAClD,EAAQ,eAAe,EAAQ,kBAAwB,cACpD,EAAQ,UAAU;AAC7B;AAaA,SAAgB,EACZ,GACA,GAMM;CACN,IAAM,EAAE,gBAAa,WAAQ,uBAAoB;CAIjD,OAHI,KAAU,IAAwB,EAAQ,UAC1C,IAAS,IAAU,EAAQ,SAAS,GAAQ,CAAe,IAC3D,KAAe,IAAwB,EAAQ,eAC5C,EAAQ,cAAc,GAAa,CAAe;AAC7D"}
1
+ {"version":3,"file":"chat-receipt.js","names":["resolveReceiptState","message","receipt","receiptLabel","readBy","totalRecipients","strings","deliveredTo"],"sources":["../../../src/components/Chat/chat-receipt.ts"],"sourcesContent":["import type { ChatMessage, ChatReceipt } from \"./chat-groups\";\n\n/**\n * What the ticks on an outgoing message say.\n *\n * `\"read\"` is the only one that turns them blue, and in a group that means\n * **everyone** has read it — the distinction `status: \"read\"` cannot make.\n */\nexport type ChatReceiptState = \"sending\" | \"sent\" | \"delivered\" | \"read\" | \"failed\";\n\n/**\n * Resolve the tick state of an outgoing message.\n *\n * A group needs three states where a single message has two: sent to the server,\n * delivered to the recipients, read by the recipients. A boolean `status` collapses\n * the middle one, so an app that has per-recipient counts either invents its own\n * glyph or shows a message as read when one person out of nine opened it.\n *\n * The counts win when they are there, and the thresholds are deliberately \"all\":\n * blue ticks in every messenger mean the whole room, and reporting \"read\" for a\n * partial count is the failure that makes people distrust the indicator entirely.\n * A `totalRecipients` of zero — a note to self, a thread whose membership the app\n * does not track — falls back to `status`, because \"read by all of nobody\" is not\n * a claim worth making.\n *\n * `\"failed\"` and `\"sending\"` come from `status` regardless: they are about this\n * side of the wire, and no recipient count exists yet.\n *\n * @param message - The message being rendered.\n * @returns The tick state, or `null` when there is nothing to show.\n */\nexport function resolveReceiptState(message: ChatMessage): ChatReceiptState | null {\n if (message.status === \"failed\" || message.status === \"sending\") return message.status;\n const receipt = message.receipt;\n if (!receipt || receipt.totalRecipients <= 0) return message.status ?? null;\n if (receipt.readBy >= receipt.totalRecipients) return \"read\";\n if (receipt.deliveredTo >= receipt.totalRecipients) return \"delivered\";\n return message.status ?? \"sent\";\n}\n\n/**\n * The sentence a reader gets for a receipt, for the tooltip and the screen reader.\n *\n * Partial counts are spelled out rather than rounded to a state: \"delivered to 3\n * of 9\" is the information the sender actually wants when the ticks are not blue\n * yet, and it is the part a glyph cannot carry.\n *\n * @param receipt - Per-recipient counts.\n * @param strings - Locale strings for the thread.\n * @returns One sentence describing delivery and reading.\n */\nexport function receiptLabel(\n receipt: ChatReceipt,\n strings: {\n deliveredAll: string;\n deliveredSome: (delivered: number, total: number) => string;\n readAll: string;\n readSome: (read: number, total: number) => string;\n },\n): string {\n const { deliveredTo, readBy, totalRecipients } = receipt;\n if (readBy >= totalRecipients) return strings.readAll;\n if (readBy > 0) return strings.readSome(readBy, totalRecipients);\n if (deliveredTo >= totalRecipients) return strings.deliveredAll;\n return strings.deliveredSome(deliveredTo, totalRecipients);\n}\n"],"mappings":";AA+BA,SAAgBA,EAAoB,GAA+C;CAC/E,IAAIC,EAAQ,WAAW,YAAYA,EAAQ,WAAW,WAAW,OAAOA,EAAQ;CAChF,IAAMC,IAAUD,EAAQ;CAIxB,OAHI,CAACC,KAAWA,EAAQ,mBAAmB,IAAUD,EAAQ,UAAU,OACnEC,EAAQ,UAAUA,EAAQ,kBAAwB,SAClDA,EAAQ,eAAeA,EAAQ,kBAAwB,cACpDD,EAAQ,UAAU;AAC7B;AAaA,SAAgBE,EACZ,GACA,GAMM;CACN,IAAM,EAAE,gBAAa,WAAQ,uBAAoBD;CAIjD,OAHIE,KAAUC,IAAwBC,EAAQ,UAC1CF,IAAS,IAAUE,EAAQ,SAASF,GAAQC,CAAe,IAC3DE,KAAeF,IAAwBC,EAAQ,eAC5CA,EAAQ,cAAcC,GAAaF,CAAe;AAC7D"}