@streamplace/components 0.8.9 → 0.8.11

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 (603) hide show
  1. package/dist/components/chat/chat-box.d.ts +8 -0
  2. package/dist/components/chat/chat-box.d.ts.map +1 -0
  3. package/dist/components/chat/chat-box.js +19 -2
  4. package/dist/components/chat/chat-box.js.map +1 -0
  5. package/dist/components/chat/chat-message.d.ts +8 -0
  6. package/dist/components/chat/chat-message.d.ts.map +1 -0
  7. package/dist/components/chat/chat-message.js +1 -0
  8. package/dist/components/chat/chat-message.js.map +1 -0
  9. package/dist/components/chat/chat.d.ts +7 -0
  10. package/dist/components/chat/chat.d.ts.map +1 -0
  11. package/dist/components/chat/chat.js +1 -0
  12. package/dist/components/chat/chat.js.map +1 -0
  13. package/dist/components/chat/emoji-suggestions.d.ts +38 -0
  14. package/dist/components/chat/emoji-suggestions.d.ts.map +1 -0
  15. package/dist/components/chat/emoji-suggestions.js +1 -0
  16. package/dist/components/chat/emoji-suggestions.js.map +1 -0
  17. package/dist/components/chat/mention-suggestions.d.ts +9 -0
  18. package/dist/components/chat/mention-suggestions.d.ts.map +1 -0
  19. package/dist/components/chat/mention-suggestions.js +1 -0
  20. package/dist/components/chat/mention-suggestions.js.map +1 -0
  21. package/dist/components/chat/mod-view.d.ts +20 -0
  22. package/dist/components/chat/mod-view.d.ts.map +1 -0
  23. package/dist/components/chat/mod-view.js +1 -0
  24. package/dist/components/chat/mod-view.js.map +1 -0
  25. package/dist/components/chat/system-message.d.ts +7 -0
  26. package/dist/components/chat/system-message.d.ts.map +1 -0
  27. package/dist/components/chat/system-message.js +1 -0
  28. package/dist/components/chat/system-message.js.map +1 -0
  29. package/dist/components/content-metadata/content-metadata-form.d.ts +9 -0
  30. package/dist/components/content-metadata/content-metadata-form.d.ts.map +1 -0
  31. package/dist/components/content-metadata/content-metadata-form.js +4 -2
  32. package/dist/components/content-metadata/content-metadata-form.js.map +1 -0
  33. package/dist/components/content-metadata/content-rights.d.ts +14 -0
  34. package/dist/components/content-metadata/content-rights.d.ts.map +1 -0
  35. package/dist/components/content-metadata/content-rights.js +1 -0
  36. package/dist/components/content-metadata/content-rights.js.map +1 -0
  37. package/dist/components/content-metadata/content-warning-badge.d.ts +5 -0
  38. package/dist/components/content-metadata/content-warning-badge.d.ts.map +1 -0
  39. package/dist/components/content-metadata/content-warning-badge.js +1 -0
  40. package/dist/components/content-metadata/content-warning-badge.js.map +1 -0
  41. package/dist/components/content-metadata/content-warnings.d.ts +7 -0
  42. package/dist/components/content-metadata/content-warnings.d.ts.map +1 -0
  43. package/dist/components/content-metadata/content-warnings.js +1 -0
  44. package/dist/components/content-metadata/content-warnings.js.map +1 -0
  45. package/dist/components/content-metadata/index.d.ts +8 -0
  46. package/dist/components/content-metadata/index.d.ts.map +1 -0
  47. package/dist/components/content-metadata/index.js +1 -0
  48. package/dist/components/content-metadata/index.js.map +1 -0
  49. package/dist/components/danmu/danmu-message.d.ts +17 -0
  50. package/dist/components/danmu/danmu-message.d.ts.map +1 -0
  51. package/dist/components/danmu/danmu-message.js +112 -0
  52. package/dist/components/danmu/danmu-message.js.map +1 -0
  53. package/dist/components/danmu/danmu-overlay-obs.d.ts +11 -0
  54. package/dist/components/danmu/danmu-overlay-obs.d.ts.map +1 -0
  55. package/dist/components/danmu/danmu-overlay-obs.js +21 -0
  56. package/dist/components/danmu/danmu-overlay-obs.js.map +1 -0
  57. package/dist/components/danmu/danmu-overlay.d.ts +10 -0
  58. package/dist/components/danmu/danmu-overlay.d.ts.map +1 -0
  59. package/dist/components/danmu/danmu-overlay.js +150 -0
  60. package/dist/components/danmu/danmu-overlay.js.map +1 -0
  61. package/dist/components/danmu/math.d.ts +10 -0
  62. package/dist/components/danmu/math.d.ts.map +1 -0
  63. package/dist/components/danmu/math.js +16 -0
  64. package/dist/components/danmu/math.js.map +1 -0
  65. package/dist/components/danmu/mu.d.ts +9 -0
  66. package/dist/components/danmu/mu.d.ts.map +1 -0
  67. package/dist/components/danmu/mu.js +9 -0
  68. package/dist/components/danmu/mu.js.map +1 -0
  69. package/dist/components/danmu/use-danmu-lanes.d.ts +19 -0
  70. package/dist/components/danmu/use-danmu-lanes.d.ts.map +1 -0
  71. package/dist/components/danmu/use-danmu-lanes.js +77 -0
  72. package/dist/components/danmu/use-danmu-lanes.js.map +1 -0
  73. package/dist/components/dashboard/chat-panel.d.ts +9 -0
  74. package/dist/components/dashboard/chat-panel.d.ts.map +1 -0
  75. package/dist/components/dashboard/chat-panel.js +1 -0
  76. package/dist/components/dashboard/chat-panel.js.map +1 -0
  77. package/dist/components/dashboard/header.d.ts +14 -0
  78. package/dist/components/dashboard/header.d.ts.map +1 -0
  79. package/dist/components/dashboard/header.js +1 -0
  80. package/dist/components/dashboard/header.js.map +1 -0
  81. package/dist/components/dashboard/index.d.ts +6 -0
  82. package/dist/components/dashboard/index.d.ts.map +1 -0
  83. package/dist/components/dashboard/index.js +1 -0
  84. package/dist/components/dashboard/index.js.map +1 -0
  85. package/dist/components/dashboard/information-widget.d.ts +9 -0
  86. package/dist/components/dashboard/information-widget.d.ts.map +1 -0
  87. package/dist/components/dashboard/information-widget.js +1 -0
  88. package/dist/components/dashboard/information-widget.js.map +1 -0
  89. package/dist/components/dashboard/mod-actions.d.ts +15 -0
  90. package/dist/components/dashboard/mod-actions.d.ts.map +1 -0
  91. package/dist/components/dashboard/mod-actions.js +1 -0
  92. package/dist/components/dashboard/mod-actions.js.map +1 -0
  93. package/dist/components/dashboard/problems.d.ts +13 -0
  94. package/dist/components/dashboard/problems.d.ts.map +1 -0
  95. package/dist/components/dashboard/problems.js +1 -0
  96. package/dist/components/dashboard/problems.js.map +1 -0
  97. package/dist/components/icons/bluesky-icon.d.ts +5 -0
  98. package/dist/components/icons/bluesky-icon.d.ts.map +1 -0
  99. package/dist/components/icons/bluesky-icon.js +1 -0
  100. package/dist/components/icons/bluesky-icon.js.map +1 -0
  101. package/dist/components/keep-awake.d.ts +2 -0
  102. package/dist/components/keep-awake.d.ts.map +1 -0
  103. package/dist/components/keep-awake.js +1 -0
  104. package/dist/components/keep-awake.js.map +1 -0
  105. package/dist/components/keep-awake.native.d.ts +2 -0
  106. package/dist/components/keep-awake.native.d.ts.map +1 -0
  107. package/dist/components/keep-awake.native.js +1 -0
  108. package/dist/components/keep-awake.native.js.map +1 -0
  109. package/dist/components/mobile-player/fullscreen.d.ts +7 -0
  110. package/dist/components/mobile-player/fullscreen.d.ts.map +1 -0
  111. package/dist/components/mobile-player/fullscreen.js +7 -1
  112. package/dist/components/mobile-player/fullscreen.js.map +1 -0
  113. package/dist/components/mobile-player/fullscreen.native.d.ts +7 -0
  114. package/dist/components/mobile-player/fullscreen.native.d.ts.map +1 -0
  115. package/dist/components/mobile-player/fullscreen.native.js +8 -2
  116. package/dist/components/mobile-player/fullscreen.native.js.map +1 -0
  117. package/dist/components/mobile-player/player.d.ts +8 -0
  118. package/dist/components/mobile-player/player.d.ts.map +1 -0
  119. package/dist/components/mobile-player/player.js +1 -0
  120. package/dist/components/mobile-player/player.js.map +1 -0
  121. package/dist/components/mobile-player/props.d.ts +19 -0
  122. package/dist/components/mobile-player/props.d.ts.map +1 -0
  123. package/dist/components/mobile-player/props.js +1 -0
  124. package/dist/components/mobile-player/props.js.map +1 -0
  125. package/dist/components/mobile-player/rotation-async.native.d.ts +4 -0
  126. package/dist/components/mobile-player/rotation-async.native.d.ts.map +1 -0
  127. package/dist/components/mobile-player/rotation-async.native.js +1 -0
  128. package/dist/components/mobile-player/rotation-async.native.js.map +1 -0
  129. package/dist/components/mobile-player/rotation-lock.d.ts +18 -0
  130. package/dist/components/mobile-player/rotation-lock.d.ts.map +1 -0
  131. package/dist/components/mobile-player/rotation-lock.js +1 -0
  132. package/dist/components/mobile-player/rotation-lock.js.map +1 -0
  133. package/dist/components/mobile-player/shared.d.ts +9 -0
  134. package/dist/components/mobile-player/shared.d.ts.map +1 -0
  135. package/dist/components/mobile-player/shared.js +1 -0
  136. package/dist/components/mobile-player/shared.js.map +1 -0
  137. package/dist/components/mobile-player/ui/autoplay-button.d.ts +2 -0
  138. package/dist/components/mobile-player/ui/autoplay-button.d.ts.map +1 -0
  139. package/dist/components/mobile-player/ui/autoplay-button.js +1 -0
  140. package/dist/components/mobile-player/ui/autoplay-button.js.map +1 -0
  141. package/dist/components/mobile-player/ui/countdown.d.ts +10 -0
  142. package/dist/components/mobile-player/ui/countdown.d.ts.map +1 -0
  143. package/dist/components/mobile-player/ui/countdown.js +1 -0
  144. package/dist/components/mobile-player/ui/countdown.js.map +1 -0
  145. package/dist/components/mobile-player/ui/index.d.ts +11 -0
  146. package/dist/components/mobile-player/ui/index.d.ts.map +1 -0
  147. package/dist/components/mobile-player/ui/index.js +2 -0
  148. package/dist/components/mobile-player/ui/index.js.map +1 -0
  149. package/dist/components/mobile-player/ui/input.d.ts +9 -0
  150. package/dist/components/mobile-player/ui/input.d.ts.map +1 -0
  151. package/dist/components/mobile-player/ui/input.js +1 -0
  152. package/dist/components/mobile-player/ui/input.js.map +1 -0
  153. package/dist/components/mobile-player/ui/metrics.d.ts +6 -0
  154. package/dist/components/mobile-player/ui/metrics.d.ts.map +1 -0
  155. package/dist/components/mobile-player/ui/metrics.js +1 -0
  156. package/dist/components/mobile-player/ui/metrics.js.map +1 -0
  157. package/dist/components/mobile-player/ui/report-modal.d.ts +13 -0
  158. package/dist/components/mobile-player/ui/report-modal.d.ts.map +1 -0
  159. package/dist/components/mobile-player/ui/report-modal.js +1 -0
  160. package/dist/components/mobile-player/ui/report-modal.js.map +1 -0
  161. package/dist/components/mobile-player/ui/streamer-context-menu.d.ts +2 -0
  162. package/dist/components/mobile-player/ui/streamer-context-menu.d.ts.map +1 -0
  163. package/dist/components/mobile-player/ui/streamer-context-menu.js +1 -0
  164. package/dist/components/mobile-player/ui/streamer-context-menu.js.map +1 -0
  165. package/dist/components/mobile-player/ui/streamer-loading-overlay.d.ts +11 -0
  166. package/dist/components/mobile-player/ui/streamer-loading-overlay.d.ts.map +1 -0
  167. package/dist/components/mobile-player/ui/streamer-loading-overlay.js +1 -0
  168. package/dist/components/mobile-player/ui/streamer-loading-overlay.js.map +1 -0
  169. package/dist/components/mobile-player/ui/viewer-context-menu.d.ts +9 -0
  170. package/dist/components/mobile-player/ui/viewer-context-menu.d.ts.map +1 -0
  171. package/dist/components/mobile-player/ui/viewer-context-menu.js +3 -2
  172. package/dist/components/mobile-player/ui/viewer-context-menu.js.map +1 -0
  173. package/dist/components/mobile-player/ui/viewer-count.d.ts +10 -0
  174. package/dist/components/mobile-player/ui/viewer-count.d.ts.map +1 -0
  175. package/dist/components/mobile-player/ui/viewer-count.js +24 -0
  176. package/dist/components/mobile-player/ui/viewer-count.js.map +1 -0
  177. package/dist/components/mobile-player/ui/viewer-loading-overlay.d.ts +2 -0
  178. package/dist/components/mobile-player/ui/viewer-loading-overlay.d.ts.map +1 -0
  179. package/dist/components/mobile-player/ui/viewer-loading-overlay.js +1 -0
  180. package/dist/components/mobile-player/ui/viewer-loading-overlay.js.map +1 -0
  181. package/dist/components/mobile-player/ui/viewers.d.ts +6 -0
  182. package/dist/components/mobile-player/ui/viewers.d.ts.map +1 -0
  183. package/dist/components/mobile-player/ui/viewers.js +9 -7
  184. package/dist/components/mobile-player/ui/viewers.js.map +1 -0
  185. package/dist/components/mobile-player/use-webrtc.d.ts +19 -0
  186. package/dist/components/mobile-player/use-webrtc.d.ts.map +1 -0
  187. package/dist/components/mobile-player/use-webrtc.js +1 -0
  188. package/dist/components/mobile-player/use-webrtc.js.map +1 -0
  189. package/dist/components/mobile-player/video-async.native.d.ts +16 -0
  190. package/dist/components/mobile-player/video-async.native.d.ts.map +1 -0
  191. package/dist/components/mobile-player/video-async.native.js +1 -0
  192. package/dist/components/mobile-player/video-async.native.js.map +1 -0
  193. package/dist/components/mobile-player/video-retry.d.ts +5 -0
  194. package/dist/components/mobile-player/video-retry.d.ts.map +1 -0
  195. package/dist/components/mobile-player/video-retry.js +1 -0
  196. package/dist/components/mobile-player/video-retry.js.map +1 -0
  197. package/dist/components/mobile-player/video.d.ts +25 -0
  198. package/dist/components/mobile-player/video.d.ts.map +1 -0
  199. package/dist/components/mobile-player/video.js +1 -0
  200. package/dist/components/mobile-player/video.js.map +1 -0
  201. package/dist/components/mobile-player/video.native.d.ts +3 -0
  202. package/dist/components/mobile-player/video.native.d.ts.map +1 -0
  203. package/dist/components/mobile-player/video.native.js +1 -0
  204. package/dist/components/mobile-player/video.native.js.map +1 -0
  205. package/dist/components/mobile-player/webrtc-diagnostics.d.ts +14 -0
  206. package/dist/components/mobile-player/webrtc-diagnostics.d.ts.map +1 -0
  207. package/dist/components/mobile-player/webrtc-diagnostics.js +1 -0
  208. package/dist/components/mobile-player/webrtc-diagnostics.js.map +1 -0
  209. package/dist/components/mobile-player/webrtc-primitives.d.ts +19 -0
  210. package/dist/components/mobile-player/webrtc-primitives.d.ts.map +1 -0
  211. package/dist/components/mobile-player/webrtc-primitives.js +1 -0
  212. package/dist/components/mobile-player/webrtc-primitives.js.map +1 -0
  213. package/dist/components/mobile-player/webrtc-primitives.native.d.ts +2 -0
  214. package/dist/components/mobile-player/webrtc-primitives.native.d.ts.map +1 -0
  215. package/dist/components/mobile-player/webrtc-primitives.native.js +1 -0
  216. package/dist/components/mobile-player/webrtc-primitives.native.js.map +1 -0
  217. package/dist/components/share/sharesheet.d.ts +5 -0
  218. package/dist/components/share/sharesheet.d.ts.map +1 -0
  219. package/dist/components/share/sharesheet.js +1 -0
  220. package/dist/components/share/sharesheet.js.map +1 -0
  221. package/dist/components/ui/button.d.ts +18 -0
  222. package/dist/components/ui/button.d.ts.map +1 -0
  223. package/dist/components/ui/button.js +14 -2
  224. package/dist/components/ui/button.js.map +1 -0
  225. package/dist/components/ui/checkbox.d.ts +11 -0
  226. package/dist/components/ui/checkbox.d.ts.map +1 -0
  227. package/dist/components/ui/checkbox.js +1 -0
  228. package/dist/components/ui/checkbox.js.map +1 -0
  229. package/dist/components/ui/dialog.d.ts +38 -0
  230. package/dist/components/ui/dialog.d.ts.map +1 -0
  231. package/dist/components/ui/dialog.js +1 -0
  232. package/dist/components/ui/dialog.js.map +1 -0
  233. package/dist/components/ui/dropdown.d.ts +132 -0
  234. package/dist/components/ui/dropdown.d.ts.map +1 -0
  235. package/dist/components/ui/dropdown.js +28 -238
  236. package/dist/components/ui/dropdown.js.map +1 -0
  237. package/dist/components/ui/dropdown.native.d.ts +132 -0
  238. package/dist/components/ui/dropdown.native.d.ts.map +1 -0
  239. package/dist/components/ui/dropdown.native.js +319 -0
  240. package/dist/components/ui/dropdown.native.js.map +1 -0
  241. package/dist/components/ui/icons.d.ts +12 -0
  242. package/dist/components/ui/icons.d.ts.map +1 -0
  243. package/dist/components/ui/icons.js +1 -0
  244. package/dist/components/ui/icons.js.map +1 -0
  245. package/dist/components/ui/index.d.ts +33 -0
  246. package/dist/components/ui/index.d.ts.map +1 -0
  247. package/dist/components/ui/index.js +2 -0
  248. package/dist/components/ui/index.js.map +1 -0
  249. package/dist/components/ui/info-box.d.ts +9 -0
  250. package/dist/components/ui/info-box.d.ts.map +1 -0
  251. package/dist/components/ui/info-box.js +1 -0
  252. package/dist/components/ui/info-box.js.map +1 -0
  253. package/dist/components/ui/info-row.d.ts +9 -0
  254. package/dist/components/ui/info-row.d.ts.map +1 -0
  255. package/dist/components/ui/info-row.js +1 -0
  256. package/dist/components/ui/info-row.js.map +1 -0
  257. package/dist/components/ui/input.d.ts +20 -0
  258. package/dist/components/ui/input.d.ts.map +1 -0
  259. package/dist/components/ui/input.js +1 -0
  260. package/dist/components/ui/input.js.map +1 -0
  261. package/dist/components/ui/loader.d.ts +3 -0
  262. package/dist/components/ui/loader.d.ts.map +1 -0
  263. package/dist/components/ui/loader.js +1 -0
  264. package/dist/components/ui/loader.js.map +1 -0
  265. package/dist/components/ui/menu.d.ts +34 -0
  266. package/dist/components/ui/menu.d.ts.map +1 -0
  267. package/dist/components/ui/menu.js +57 -0
  268. package/dist/components/ui/menu.js.map +1 -0
  269. package/dist/components/ui/primitives/button.d.ts +41 -0
  270. package/dist/components/ui/primitives/button.d.ts.map +1 -0
  271. package/dist/components/ui/primitives/button.js +1 -0
  272. package/dist/components/ui/primitives/button.js.map +1 -0
  273. package/dist/components/ui/primitives/input.d.ts +52 -0
  274. package/dist/components/ui/primitives/input.d.ts.map +1 -0
  275. package/dist/components/ui/primitives/input.js +1 -0
  276. package/dist/components/ui/primitives/input.js.map +1 -0
  277. package/dist/components/ui/primitives/modal.d.ts +46 -0
  278. package/dist/components/ui/primitives/modal.d.ts.map +1 -0
  279. package/dist/components/ui/primitives/modal.js +1 -0
  280. package/dist/components/ui/primitives/modal.js.map +1 -0
  281. package/dist/components/ui/primitives/text.d.ts +48 -0
  282. package/dist/components/ui/primitives/text.d.ts.map +1 -0
  283. package/dist/components/ui/primitives/text.js +1 -0
  284. package/dist/components/ui/primitives/text.js.map +1 -0
  285. package/dist/components/ui/resizeable.d.ts +14 -0
  286. package/dist/components/ui/resizeable.d.ts.map +1 -0
  287. package/dist/components/ui/resizeable.js +2 -1
  288. package/dist/components/ui/resizeable.js.map +1 -0
  289. package/dist/components/ui/select.d.ts +16 -0
  290. package/dist/components/ui/select.d.ts.map +1 -0
  291. package/dist/components/ui/select.js +1 -0
  292. package/dist/components/ui/select.js.map +1 -0
  293. package/dist/components/ui/slider.d.ts +2 -0
  294. package/dist/components/ui/slider.d.ts.map +1 -0
  295. package/dist/components/ui/slider.js +1 -0
  296. package/dist/components/ui/slider.js.map +1 -0
  297. package/dist/components/ui/text.d.ts +45 -0
  298. package/dist/components/ui/text.d.ts.map +1 -0
  299. package/dist/components/ui/text.js +1 -0
  300. package/dist/components/ui/text.js.map +1 -0
  301. package/dist/components/ui/textarea.d.ts +5 -0
  302. package/dist/components/ui/textarea.d.ts.map +1 -0
  303. package/dist/components/ui/textarea.js +1 -0
  304. package/dist/components/ui/textarea.js.map +1 -0
  305. package/dist/components/ui/toast.d.ts +92 -0
  306. package/dist/components/ui/toast.d.ts.map +1 -0
  307. package/dist/components/ui/toast.js +2 -1
  308. package/dist/components/ui/toast.js.map +1 -0
  309. package/dist/components/ui/tooltip.d.ts +8 -0
  310. package/dist/components/ui/tooltip.d.ts.map +1 -0
  311. package/dist/components/ui/tooltip.js +1 -0
  312. package/dist/components/ui/tooltip.js.map +1 -0
  313. package/dist/components/ui/view.d.ts +33 -0
  314. package/dist/components/ui/view.d.ts.map +1 -0
  315. package/dist/components/ui/view.js +1 -0
  316. package/dist/components/ui/view.js.map +1 -0
  317. package/dist/crypto-polyfill.d.ts +1 -0
  318. package/dist/crypto-polyfill.d.ts.map +1 -0
  319. package/dist/crypto-polyfill.js +1 -0
  320. package/dist/crypto-polyfill.js.map +1 -0
  321. package/dist/crypto-polyfill.native.d.ts +3 -0
  322. package/dist/crypto-polyfill.native.d.ts.map +1 -0
  323. package/dist/crypto-polyfill.native.js +1 -0
  324. package/dist/crypto-polyfill.native.js.map +1 -0
  325. package/dist/hooks/index.d.ts +11 -0
  326. package/dist/hooks/index.d.ts.map +1 -0
  327. package/dist/hooks/index.js +1 -0
  328. package/dist/hooks/index.js.map +1 -0
  329. package/dist/hooks/useAvatars.d.ts +3 -0
  330. package/dist/hooks/useAvatars.d.ts.map +1 -0
  331. package/dist/hooks/useAvatars.js +1 -0
  332. package/dist/hooks/useAvatars.js.map +1 -0
  333. package/dist/hooks/useCameraToggle.d.ts +5 -0
  334. package/dist/hooks/useCameraToggle.d.ts.map +1 -0
  335. package/dist/hooks/useCameraToggle.js +1 -0
  336. package/dist/hooks/useCameraToggle.js.map +1 -0
  337. package/dist/hooks/useKeyboard.d.ts +5 -0
  338. package/dist/hooks/useKeyboard.d.ts.map +1 -0
  339. package/dist/hooks/useKeyboard.js +1 -0
  340. package/dist/hooks/useKeyboard.js.map +1 -0
  341. package/dist/hooks/useKeyboardSlide.d.ts +5 -0
  342. package/dist/hooks/useKeyboardSlide.d.ts.map +1 -0
  343. package/dist/hooks/useKeyboardSlide.js +1 -0
  344. package/dist/hooks/useKeyboardSlide.js.map +1 -0
  345. package/dist/hooks/useLivestreamInfo.d.ts +15 -0
  346. package/dist/hooks/useLivestreamInfo.d.ts.map +1 -0
  347. package/dist/hooks/useLivestreamInfo.js +1 -0
  348. package/dist/hooks/useLivestreamInfo.js.map +1 -0
  349. package/dist/hooks/useOuterAndInnerDimensions.d.ts +10 -0
  350. package/dist/hooks/useOuterAndInnerDimensions.d.ts.map +1 -0
  351. package/dist/hooks/useOuterAndInnerDimensions.js +1 -0
  352. package/dist/hooks/useOuterAndInnerDimensions.js.map +1 -0
  353. package/dist/hooks/usePlayerDimensions.d.ts +12 -0
  354. package/dist/hooks/usePlayerDimensions.d.ts.map +1 -0
  355. package/dist/hooks/usePlayerDimensions.js +1 -0
  356. package/dist/hooks/usePlayerDimensions.js.map +1 -0
  357. package/dist/hooks/usePointerDevice.d.ts +12 -0
  358. package/dist/hooks/usePointerDevice.d.ts.map +1 -0
  359. package/dist/hooks/usePointerDevice.js +1 -0
  360. package/dist/hooks/usePointerDevice.js.map +1 -0
  361. package/dist/hooks/useSegmentDimensions.d.ts +6 -0
  362. package/dist/hooks/useSegmentDimensions.d.ts.map +1 -0
  363. package/dist/hooks/useSegmentDimensions.js +1 -0
  364. package/dist/hooks/useSegmentDimensions.js.map +1 -0
  365. package/dist/hooks/useSegmentTiming.d.ts +9 -0
  366. package/dist/hooks/useSegmentTiming.d.ts.map +1 -0
  367. package/dist/hooks/useSegmentTiming.js +1 -0
  368. package/dist/hooks/useSegmentTiming.js.map +1 -0
  369. package/dist/i18n/i18next-config.d.ts +41 -0
  370. package/dist/i18n/i18next-config.d.ts.map +1 -0
  371. package/dist/i18n/i18next-config.js +264 -0
  372. package/dist/i18n/i18next-config.js.map +1 -0
  373. package/dist/i18n/index.d.ts +11 -0
  374. package/dist/i18n/index.d.ts.map +1 -0
  375. package/dist/i18n/index.js +45 -0
  376. package/dist/i18n/index.js.map +1 -0
  377. package/dist/i18n/provider.d.ts +14 -0
  378. package/dist/i18n/provider.d.ts.map +1 -0
  379. package/dist/i18n/provider.js +58 -0
  380. package/dist/i18n/provider.js.map +1 -0
  381. package/dist/index.d.ts +33 -0
  382. package/dist/index.d.ts.map +1 -0
  383. package/dist/index.js +9 -1
  384. package/dist/index.js.map +1 -0
  385. package/dist/lib/browser.d.ts +2 -0
  386. package/dist/lib/browser.d.ts.map +1 -0
  387. package/dist/lib/browser.js +1 -0
  388. package/dist/lib/browser.js.map +1 -0
  389. package/dist/lib/facet.d.ts +11 -0
  390. package/dist/lib/facet.d.ts.map +1 -0
  391. package/dist/lib/facet.js +1 -0
  392. package/dist/lib/facet.js.map +1 -0
  393. package/dist/lib/metadata-constants.d.ts +13 -0
  394. package/dist/lib/metadata-constants.d.ts.map +1 -0
  395. package/dist/lib/metadata-constants.js +1 -0
  396. package/dist/lib/metadata-constants.js.map +1 -0
  397. package/dist/lib/system-messages.d.ts +49 -0
  398. package/dist/lib/system-messages.d.ts.map +1 -0
  399. package/dist/lib/system-messages.js +1 -0
  400. package/dist/lib/system-messages.js.map +1 -0
  401. package/dist/lib/theme/atoms.d.ts +4226 -0
  402. package/dist/lib/theme/atoms.d.ts.map +1 -0
  403. package/dist/lib/theme/atoms.js +1 -0
  404. package/dist/lib/theme/atoms.js.map +1 -0
  405. package/dist/lib/theme/atoms.types.d.ts +228 -0
  406. package/dist/lib/theme/atoms.types.d.ts.map +1 -0
  407. package/dist/lib/theme/atoms.types.js +1 -0
  408. package/dist/lib/theme/atoms.types.js.map +1 -0
  409. package/dist/lib/theme/index.d.ts +6 -0
  410. package/dist/lib/theme/index.d.ts.map +1 -0
  411. package/dist/lib/theme/index.js +1 -0
  412. package/dist/lib/theme/index.js.map +1 -0
  413. package/dist/lib/theme/theme.d.ts +327 -0
  414. package/dist/lib/theme/theme.d.ts.map +1 -0
  415. package/dist/lib/theme/theme.js +1 -0
  416. package/dist/lib/theme/theme.js.map +1 -0
  417. package/dist/lib/theme/tokens.d.ts +766 -0
  418. package/dist/lib/theme/tokens.d.ts.map +1 -0
  419. package/dist/lib/theme/tokens.js +1 -0
  420. package/dist/lib/theme/tokens.js.map +1 -0
  421. package/dist/lib/utils.d.ts +53 -0
  422. package/dist/lib/utils.d.ts.map +1 -0
  423. package/dist/lib/utils.js +1 -0
  424. package/dist/lib/utils.js.map +1 -0
  425. package/dist/livestream-provider/index.d.ts +13 -0
  426. package/dist/livestream-provider/index.d.ts.map +1 -0
  427. package/dist/livestream-provider/index.js +1 -0
  428. package/dist/livestream-provider/index.js.map +1 -0
  429. package/dist/livestream-provider/websocket.d.ts +2 -0
  430. package/dist/livestream-provider/websocket.d.ts.map +1 -0
  431. package/dist/livestream-provider/websocket.js +1 -0
  432. package/dist/livestream-provider/websocket.js.map +1 -0
  433. package/dist/livestream-store/chat.d.ts +21 -0
  434. package/dist/livestream-store/chat.d.ts.map +1 -0
  435. package/dist/livestream-store/chat.js +1 -0
  436. package/dist/livestream-store/chat.js.map +1 -0
  437. package/dist/livestream-store/context.d.ts +7 -0
  438. package/dist/livestream-store/context.d.ts.map +1 -0
  439. package/dist/livestream-store/context.js +1 -0
  440. package/dist/livestream-store/context.js.map +1 -0
  441. package/dist/livestream-store/index.d.ts +5 -0
  442. package/dist/livestream-store/index.d.ts.map +1 -0
  443. package/dist/livestream-store/index.js +1 -0
  444. package/dist/livestream-store/index.js.map +1 -0
  445. package/dist/livestream-store/livestream-state.d.ts +29 -0
  446. package/dist/livestream-store/livestream-state.d.ts.map +1 -0
  447. package/dist/livestream-store/livestream-state.js +1 -0
  448. package/dist/livestream-store/livestream-state.js.map +1 -0
  449. package/dist/livestream-store/livestream-store.d.ts +14 -0
  450. package/dist/livestream-store/livestream-store.d.ts.map +1 -0
  451. package/dist/livestream-store/livestream-store.js +1 -0
  452. package/dist/livestream-store/livestream-store.js.map +1 -0
  453. package/dist/livestream-store/problems.d.ts +4 -0
  454. package/dist/livestream-store/problems.d.ts.map +1 -0
  455. package/dist/livestream-store/problems.js +1 -0
  456. package/dist/livestream-store/problems.js.map +1 -0
  457. package/dist/livestream-store/stream-key.d.ts +9 -0
  458. package/dist/livestream-store/stream-key.d.ts.map +1 -0
  459. package/dist/livestream-store/stream-key.js +1 -0
  460. package/dist/livestream-store/stream-key.js.map +1 -0
  461. package/dist/livestream-store/websocket-consumer.d.ts +3 -0
  462. package/dist/livestream-store/websocket-consumer.d.ts.map +1 -0
  463. package/dist/livestream-store/websocket-consumer.js +1 -0
  464. package/dist/livestream-store/websocket-consumer.js.map +1 -0
  465. package/dist/player-store/context.d.ts +10 -0
  466. package/dist/player-store/context.d.ts.map +1 -0
  467. package/dist/player-store/context.js +1 -0
  468. package/dist/player-store/context.js.map +1 -0
  469. package/dist/player-store/index.d.ts +6 -0
  470. package/dist/player-store/index.d.ts.map +1 -0
  471. package/dist/player-store/index.js +1 -0
  472. package/dist/player-store/index.js.map +1 -0
  473. package/dist/player-store/player-provider.d.ts +12 -0
  474. package/dist/player-store/player-provider.d.ts.map +1 -0
  475. package/dist/player-store/player-provider.js +1 -0
  476. package/dist/player-store/player-provider.js.map +1 -0
  477. package/dist/player-store/player-state.d.ts +138 -0
  478. package/dist/player-store/player-state.d.ts.map +1 -0
  479. package/dist/player-store/player-state.js +1 -0
  480. package/dist/player-store/player-state.js.map +1 -0
  481. package/dist/player-store/player-store.d.ts +18 -0
  482. package/dist/player-store/player-store.d.ts.map +1 -0
  483. package/dist/player-store/player-store.js +1 -0
  484. package/dist/player-store/player-store.js.map +1 -0
  485. package/dist/player-store/single-player-provider.d.ts +61 -0
  486. package/dist/player-store/single-player-provider.d.ts.map +1 -0
  487. package/dist/player-store/single-player-provider.js +1 -0
  488. package/dist/player-store/single-player-provider.js.map +1 -0
  489. package/dist/storage/index.d.ts +4 -0
  490. package/dist/storage/index.d.ts.map +1 -0
  491. package/dist/storage/index.js +1 -0
  492. package/dist/storage/index.js.map +1 -0
  493. package/dist/storage/lock.d.ts +8 -0
  494. package/dist/storage/lock.d.ts.map +1 -0
  495. package/dist/storage/lock.js +1 -0
  496. package/dist/storage/lock.js.map +1 -0
  497. package/dist/storage/storage.d.ts +7 -0
  498. package/dist/storage/storage.d.ts.map +1 -0
  499. package/dist/storage/storage.js +1 -0
  500. package/dist/storage/storage.js.map +1 -0
  501. package/dist/storage/storage.native.d.ts +7 -0
  502. package/dist/storage/storage.native.d.ts.map +1 -0
  503. package/dist/storage/storage.native.js +1 -0
  504. package/dist/storage/storage.native.js.map +1 -0
  505. package/dist/storage/storage.shared.d.ts +6 -0
  506. package/dist/storage/storage.shared.d.ts.map +1 -0
  507. package/dist/storage/storage.shared.js +1 -0
  508. package/dist/storage/storage.shared.js.map +1 -0
  509. package/dist/streamplace-provider/context.d.ts +7 -0
  510. package/dist/streamplace-provider/context.d.ts.map +1 -0
  511. package/dist/streamplace-provider/context.js +1 -0
  512. package/dist/streamplace-provider/context.js.map +1 -0
  513. package/dist/streamplace-provider/index.d.ts +11 -0
  514. package/dist/streamplace-provider/index.d.ts.map +1 -0
  515. package/dist/streamplace-provider/index.js +1 -0
  516. package/dist/streamplace-provider/index.js.map +1 -0
  517. package/dist/streamplace-provider/poller.d.ts +5 -0
  518. package/dist/streamplace-provider/poller.d.ts.map +1 -0
  519. package/dist/streamplace-provider/poller.js +1 -0
  520. package/dist/streamplace-provider/poller.js.map +1 -0
  521. package/dist/streamplace-provider/xrpc.d.ts +1 -0
  522. package/dist/streamplace-provider/xrpc.d.ts.map +1 -0
  523. package/dist/streamplace-provider/xrpc.js +1 -0
  524. package/dist/streamplace-provider/xrpc.js.map +1 -0
  525. package/dist/streamplace-store/block.d.ts +9 -0
  526. package/dist/streamplace-store/block.d.ts.map +1 -0
  527. package/dist/streamplace-store/block.js +1 -0
  528. package/dist/streamplace-store/block.js.map +1 -0
  529. package/dist/streamplace-store/content-metadata-actions.d.ts +9 -0
  530. package/dist/streamplace-store/content-metadata-actions.d.ts.map +1 -0
  531. package/dist/streamplace-store/content-metadata-actions.js +1 -0
  532. package/dist/streamplace-store/content-metadata-actions.js.map +1 -0
  533. package/dist/streamplace-store/graph.d.ts +22 -0
  534. package/dist/streamplace-store/graph.d.ts.map +1 -0
  535. package/dist/streamplace-store/graph.js +1 -0
  536. package/dist/streamplace-store/graph.js.map +1 -0
  537. package/dist/streamplace-store/index.d.ts +4 -0
  538. package/dist/streamplace-store/index.d.ts.map +1 -0
  539. package/dist/streamplace-store/index.js +1 -0
  540. package/dist/streamplace-store/index.js.map +1 -0
  541. package/dist/streamplace-store/stream.d.ts +11 -0
  542. package/dist/streamplace-store/stream.d.ts.map +1 -0
  543. package/dist/streamplace-store/stream.js +1 -0
  544. package/dist/streamplace-store/stream.js.map +1 -0
  545. package/dist/streamplace-store/streamplace-store.d.ts +92 -0
  546. package/dist/streamplace-store/streamplace-store.d.ts.map +1 -0
  547. package/dist/streamplace-store/streamplace-store.js +158 -3
  548. package/dist/streamplace-store/streamplace-store.js.map +1 -0
  549. package/dist/streamplace-store/user.d.ts +6 -0
  550. package/dist/streamplace-store/user.d.ts.map +1 -0
  551. package/dist/streamplace-store/user.js +1 -0
  552. package/dist/streamplace-store/user.js.map +1 -0
  553. package/dist/streamplace-store/xrpc.d.ts +3 -0
  554. package/dist/streamplace-store/xrpc.d.ts.map +1 -0
  555. package/dist/streamplace-store/xrpc.js +1 -0
  556. package/dist/streamplace-store/xrpc.js.map +1 -0
  557. package/dist/ui/index.d.ts +15 -0
  558. package/dist/ui/index.d.ts.map +1 -0
  559. package/dist/ui/index.js +1 -0
  560. package/dist/ui/index.js.map +1 -0
  561. package/locales/en-US/common.ftl +41 -0
  562. package/locales/en-US/settings.ftl +122 -0
  563. package/locales/es-ES/common.ftl +41 -0
  564. package/locales/es-ES/settings.ftl +161 -0
  565. package/locales/fr-FR/common.ftl +41 -0
  566. package/locales/fr-FR/settings.ftl +158 -0
  567. package/locales/manifest.json +36 -0
  568. package/locales/pt-BR/common.ftl +41 -0
  569. package/locales/pt-BR/settings.ftl +159 -0
  570. package/locales/zh-Hant/common.ftl +41 -0
  571. package/locales/zh-Hant/settings.ftl +154 -0
  572. package/node-compile-cache/v22.15.0-x64-efe9a9df-0/37be0eec +0 -0
  573. package/package.json +24 -3
  574. package/scripts/compile-translations.js +254 -0
  575. package/scripts/extract-i18n.js +336 -0
  576. package/src/components/chat/chat-box.tsx +28 -9
  577. package/src/components/content-metadata/content-metadata-form.tsx +3 -1
  578. package/src/components/danmu/danmu-message.tsx +182 -0
  579. package/src/components/danmu/danmu-overlay-obs.tsx +44 -0
  580. package/src/components/danmu/danmu-overlay.tsx +225 -0
  581. package/src/components/danmu/math.ts +27 -0
  582. package/src/components/danmu/mu.tsx +28 -0
  583. package/src/components/danmu/use-danmu-lanes.ts +114 -0
  584. package/src/components/mobile-player/fullscreen.native.tsx +26 -0
  585. package/src/components/mobile-player/fullscreen.tsx +23 -1
  586. package/src/components/mobile-player/ui/index.ts +1 -0
  587. package/src/components/mobile-player/ui/viewer-context-menu.tsx +4 -4
  588. package/src/components/mobile-player/ui/viewer-count.tsx +39 -0
  589. package/src/components/mobile-player/ui/viewers.tsx +10 -14
  590. package/src/components/ui/button.tsx +22 -4
  591. package/src/components/ui/dropdown.native.tsx +696 -0
  592. package/src/components/ui/dropdown.tsx +57 -427
  593. package/src/components/ui/index.ts +1 -0
  594. package/src/components/ui/menu.tsx +171 -0
  595. package/src/components/ui/resizeable.tsx +1 -1
  596. package/src/components/ui/toast.tsx +6 -1
  597. package/src/i18n/i18next-config.ts +301 -0
  598. package/src/i18n/index.ts +50 -0
  599. package/src/i18n/provider.tsx +70 -0
  600. package/src/index.tsx +7 -0
  601. package/src/streamplace-store/streamplace-store.tsx +184 -2
  602. package/tsconfig.json +11 -2
  603. package/tsconfig.tsbuildinfo +0 -1
@@ -0,0 +1,225 @@
1
+ import { useCallback, useEffect, useRef, useState } from "react";
2
+ import { LayoutChangeEvent, StyleSheet } from "react-native";
3
+ import { ChatMessageViewHydrated } from "streamplace";
4
+ import { useChat, useLivestreamStore } from "../../livestream-store";
5
+ import { View } from "../ui";
6
+ import { DanmuMessage } from "./danmu-message";
7
+ import { baseDuration, MAX_DURATION, MIN_DURATION } from "./math";
8
+ import { useDanmuLanes } from "./use-danmu-lanes";
9
+
10
+ interface DanmuOverlayProps {
11
+ enabled?: boolean;
12
+ opacity?: number;
13
+ speed?: number;
14
+ laneCount?: number;
15
+ maxMessages?: number;
16
+ }
17
+
18
+ interface ActiveDanmuMessage {
19
+ message: ChatMessageViewHydrated;
20
+ lane: number;
21
+ }
22
+
23
+ const DEFAULT_LANE_COUNT = 12;
24
+ const DEFAULT_OPACITY = 80;
25
+ const DEFAULT_SPEED = 1;
26
+ const DEFAULT_MAX_MESSAGES = 50;
27
+ const FONT_SIZE_PERCENTAGE = 0.7;
28
+ const MAX_PROCESSED_MESSAGES = 10;
29
+
30
+ // px from top of video where danmu won't appear (avoid overlapping with title)
31
+ const TOP_GAP = 20;
32
+ // px from bottom of video (avoid overlapping with controls)
33
+ const BOTTOM_GAP = 20;
34
+
35
+ export function DanmuOverlay({
36
+ enabled = true,
37
+ opacity = DEFAULT_OPACITY,
38
+ speed = DEFAULT_SPEED,
39
+ laneCount = DEFAULT_LANE_COUNT,
40
+ maxMessages = DEFAULT_MAX_MESSAGES,
41
+ }: DanmuOverlayProps) {
42
+ const chat = useChat();
43
+ const segment = useLivestreamStore((x) => x.segment);
44
+
45
+ const [containerWidth, setContainerWidth] = useState(0);
46
+ const [containerHeight, setContainerHeight] = useState(0);
47
+ const [activeDanmu, setActiveDanmu] = useState<
48
+ Map<string, ActiveDanmuMessage>
49
+ >(new Map());
50
+ const processedMessages = useRef(new Set<string>());
51
+ const mountTime = useRef(Date.now());
52
+ const lastChatLength = useRef(0);
53
+ const { assignLane, updateDanmuWidth, releaseLane, cleanup } = useDanmuLanes(
54
+ laneCount,
55
+ containerWidth,
56
+ );
57
+
58
+ const handleLayout = useCallback((event: LayoutChangeEvent) => {
59
+ const { width, height } = event.nativeEvent.layout;
60
+ setContainerWidth(width);
61
+ setContainerHeight(height);
62
+ }, []);
63
+
64
+ const handleMessageComplete = useCallback(
65
+ (messageId: string) => {
66
+ releaseLane(messageId);
67
+ setActiveDanmu((prev) => {
68
+ const next = new Map(prev);
69
+ next.delete(messageId);
70
+ return next;
71
+ });
72
+ },
73
+ [releaseLane],
74
+ );
75
+
76
+ const handleWidthMeasured = useCallback(
77
+ (messageId: string, width: number) => {
78
+ updateDanmuWidth(messageId, width);
79
+ },
80
+ [updateDanmuWidth],
81
+ );
82
+
83
+ useEffect(() => {
84
+ if (!enabled || !chat || containerWidth === 0) return;
85
+
86
+ // only check new messages since last render (chat is sorted newest first)
87
+ const newMessageCount = chat.length - lastChatLength.current;
88
+ if (newMessageCount <= 0) return;
89
+
90
+ const messagesToCheck = chat.slice(0, newMessageCount);
91
+ lastChatLength.current = chat.length;
92
+
93
+ const newMessages = messagesToCheck.filter((msg) => {
94
+ const hasProcessed = processedMessages.current.has(msg.uri);
95
+ const isSystem = msg.author.did === "did:sys:system";
96
+ const msgTime = new Date(msg.record.createdAt).getTime();
97
+ const isAfterMount = msgTime >= mountTime.current;
98
+
99
+ return !hasProcessed && !isSystem && isAfterMount;
100
+ });
101
+
102
+ if (newMessages.length === 0) return;
103
+
104
+ const messagesToAdd: ActiveDanmuMessage[] = [];
105
+
106
+ for (const message of newMessages.slice(0, maxMessages)) {
107
+ // mark as processed FIRST to prevent duplicate processing if effect runs twice
108
+ if (processedMessages.current.has(message.uri)) {
109
+ continue;
110
+ }
111
+ processedMessages.current.add(message.uri);
112
+
113
+ if (processedMessages.current.size > MAX_PROCESSED_MESSAGES) {
114
+ const toRemove = Array.from(processedMessages.current).slice(
115
+ 0,
116
+ processedMessages.current.size - MAX_PROCESSED_MESSAGES,
117
+ );
118
+ toRemove.forEach((uri) => processedMessages.current.delete(uri));
119
+ }
120
+
121
+ const duration = baseDuration(message, MAX_DURATION, MIN_DURATION);
122
+ if (__DEV__)
123
+ console.log("[danmu] message", message.record.text, {
124
+ duration,
125
+ speed,
126
+ });
127
+ const lane = assignLane(message.uri, duration);
128
+
129
+ if (lane !== null) {
130
+ messagesToAdd.push({ message, lane });
131
+ }
132
+ }
133
+
134
+ if (messagesToAdd.length > 0) {
135
+ setActiveDanmu((prev) => {
136
+ const next = new Map(prev);
137
+ for (const danmu of messagesToAdd) {
138
+ next.set(danmu.message.uri, danmu);
139
+ }
140
+ return next;
141
+ });
142
+ }
143
+ }, [chat, enabled, speed, maxMessages]);
144
+
145
+ useEffect(() => {
146
+ const interval = setInterval(() => {
147
+ cleanup();
148
+ }, 1000);
149
+
150
+ return () => clearInterval(interval);
151
+ }, [cleanup]);
152
+
153
+ if (!enabled || containerWidth === 0 || containerHeight === 0) {
154
+ return <View style={styles.container} onLayout={handleLayout} />;
155
+ }
156
+
157
+ // Calculate video bounds based on actual video dimensions from segment
158
+ const segmentVideoWidth = segment?.video?.[0]?.width;
159
+ const segmentVideoHeight = segment?.video?.[0]?.height;
160
+
161
+ // Fall back to 16:9 if no segment dimensions available
162
+ const videoAspectRatio =
163
+ segmentVideoWidth && segmentVideoHeight
164
+ ? segmentVideoWidth / segmentVideoHeight
165
+ : 16 / 9;
166
+
167
+ const containerAspectRatio = containerWidth / containerHeight;
168
+
169
+ let videoWidth: number;
170
+ let videoHeight: number;
171
+ let videoTop: number;
172
+ let videoLeft: number;
173
+
174
+ if (containerAspectRatio > videoAspectRatio) {
175
+ // Container is wider than video - letterbox on sides
176
+ videoHeight = containerHeight;
177
+ videoWidth = videoHeight * videoAspectRatio;
178
+ videoTop = 0;
179
+ videoLeft = (containerWidth - videoWidth) / 2;
180
+ // Adjust for top/bottom gaps iff we don't have top letterboxing
181
+ videoTop += TOP_GAP;
182
+ videoHeight -= TOP_GAP + BOTTOM_GAP;
183
+ } else {
184
+ // Container is taller than video - letterbox on top/bottom
185
+ videoWidth = containerWidth;
186
+ videoHeight = videoWidth / videoAspectRatio;
187
+ videoTop = (containerHeight - videoHeight) / 2;
188
+ videoLeft = 0;
189
+ }
190
+
191
+ const laneHeight = videoHeight / laneCount;
192
+ const fontSize = laneHeight * FONT_SIZE_PERCENTAGE;
193
+
194
+ return (
195
+ <View style={styles.container} onLayout={handleLayout} pointerEvents="none">
196
+ {Array.from(activeDanmu.values()).map(({ message, lane }) => (
197
+ <DanmuMessage
198
+ key={message.uri}
199
+ message={message}
200
+ lane={lane}
201
+ laneHeight={laneHeight}
202
+ videoTop={videoTop}
203
+ opacity={opacity}
204
+ fontSize={fontSize}
205
+ speed={speed}
206
+ containerWidth={containerWidth}
207
+ containerHeight={containerHeight}
208
+ onComplete={handleMessageComplete}
209
+ onWidthMeasured={handleWidthMeasured}
210
+ />
211
+ ))}
212
+ </View>
213
+ );
214
+ }
215
+
216
+ const styles = StyleSheet.create({
217
+ container: {
218
+ position: "absolute",
219
+ top: 0,
220
+ left: 0,
221
+ right: 0,
222
+ bottom: 0,
223
+ overflow: "hidden",
224
+ },
225
+ });
@@ -0,0 +1,27 @@
1
+ export const mapRange = (
2
+ num: number,
3
+ inMin: number,
4
+ inMax: number,
5
+ outMin: number,
6
+ outMax: number,
7
+ ) => {
8
+ return ((num - inMin) * (outMax - outMin)) / (inMax - inMin) + outMin;
9
+ };
10
+
11
+ export const between = (num: number, min: number, max: number) => {
12
+ return Math.min(Math.max(num, min), max);
13
+ };
14
+
15
+ export const baseDuration = (
16
+ message: { record: { text: string | any[] } },
17
+ min: number,
18
+ max: number,
19
+ ) =>
20
+ between(
21
+ mapRange(Math.log(message.record.text.length) * 8, 1, 16, min, max),
22
+ min,
23
+ max,
24
+ );
25
+
26
+ export const MIN_DURATION = 6000;
27
+ export const MAX_DURATION = 12000;
@@ -0,0 +1,28 @@
1
+ import { G, Path, Svg, SvgProps } from "react-native-svg";
2
+
3
+ export interface MuProps extends SvgProps {
4
+ size?: number | string;
5
+ color?: string;
6
+ strokeWidth?: number | string;
7
+ }
8
+
9
+ export const Mu = ({
10
+ size = 24,
11
+ color = "#000000",
12
+ strokeWidth = 10.9,
13
+ ...props
14
+ }: MuProps) => (
15
+ <Svg width={size} height={size} viewBox="0 0 230 220" {...props}>
16
+ <G
17
+ strokeLinecap="round"
18
+ fillRule="evenodd"
19
+ stroke={color}
20
+ strokeWidth={strokeWidth}
21
+ fill={color}
22
+ >
23
+ <Path d="M 13.756 65.7 L 53.756 65.7 Q 55.756 65.7 57.256 64.2 Q 58.756 62.7 58.756 60.7 L 58.756 22.2 Q 58.756 20.2 57.256 18.7 Q 55.756 17.2 53.756 17.2 L 3.506 17.2 Q 2.006 17.2 1.006 16.2 Q 0.006 15.2 0.006 13.45 Q 0.006 11.95 1.006 10.95 Q 2.006 9.95 3.506 9.95 L 56.506 9.95 Q 60.756 9.95 63.506 12.7 Q 66.256 15.45 66.256 19.7 L 66.256 63.45 Q 66.256 67.45 63.506 70.325 Q 60.756 73.2 56.506 73.2 L 16.256 73.2 Q 14.006 73.2 12.506 74.7 Q 11.006 76.2 11.006 78.2 Q 10.756 89.7 10.506 98.575 Q 10.256 107.45 9.756 117.45 A 4.864 4.864 0 0 0 9.717 118.054 A 4.167 4.167 0 0 0 10.881 120.95 Q 12.256 122.45 14.506 122.45 L 60.256 122.45 Q 63.006 122.45 64.881 124.325 Q 66.756 126.2 66.756 129.7 A 1579.753 1579.753 0 0 1 65.295 155.188 Q 64.543 166.519 63.737 175.256 A 494.991 494.991 0 0 1 63.506 177.7 Q 61.756 195.7 59.506 204.7 A 39.785 39.785 0 0 1 55.486 215.384 A 14.939 14.939 0 0 1 54.006 217.45 Q 51.506 220.2 48.506 221.075 Q 45.506 221.95 40.506 222.2 Q 36.006 222.45 28.506 222.2 Q 21.006 221.95 11.756 221.45 A 5.389 5.389 0 0 1 10.79 221.197 A 5.13 5.13 0 0 1 9.131 220.2 Q 8.006 219.2 7.506 217.45 A 3.871 3.871 0 0 1 7.45 216.814 A 2.355 2.355 0 0 1 8.131 215.075 Q 9.006 214.2 10.506 214.2 Q 20.006 214.95 27.881 215.2 Q 35.756 215.45 39.006 215.45 Q 42.506 215.45 44.381 215.075 Q 46.256 214.7 47.756 212.95 A 17.691 17.691 0 0 0 51.389 205.661 A 55.6 55.6 0 0 0 52.381 201.825 A 144.371 144.371 0 0 0 54.411 189.832 A 374.249 374.249 0 0 0 55.881 176.95 A 735.769 735.769 0 0 0 57.475 157.825 A 1519.1 1519.1 0 0 0 59.006 133.45 A 5.968 5.968 0 0 0 59.061 132.663 A 2.91 2.91 0 0 0 55.506 129.7 L 11.506 129.7 Q 7.506 129.7 4.881 126.825 A 8.876 8.876 0 0 1 2.484 120.637 A 11.015 11.015 0 0 1 2.506 119.95 Q 2.756 113.95 3.006 108.7 Q 3.256 103.45 3.506 98.45 Q 3.756 93.45 3.881 87.95 Q 4.006 82.45 4.006 75.45 Q 4.006 71.2 6.881 68.45 Q 9.756 65.7 13.756 65.7 Z M 99.006 49.95 L 200.256 49.95 Q 204.506 49.95 207.256 52.7 Q 210.006 55.45 210.006 59.7 L 210.006 127.95 Q 210.006 131.95 207.256 134.825 Q 204.506 137.7 200.256 137.7 L 99.006 137.7 Q 95.006 137.7 92.131 134.825 Q 89.256 131.95 89.256 127.95 L 89.256 59.7 Q 89.256 55.45 92.131 52.7 Q 95.006 49.95 99.006 49.95 Z M 145.506 53.95 L 153.006 53.95 L 153.006 218.95 Q 153.006 220.7 152.006 221.7 Q 151.006 222.7 149.256 222.7 Q 147.506 222.7 146.506 221.7 Q 145.506 220.7 145.506 218.95 L 145.506 53.95 Z M 77.506 163.95 L 219.006 163.95 Q 220.756 163.95 221.756 164.95 Q 222.756 165.95 222.756 167.7 Q 222.756 169.45 221.756 170.45 Q 220.756 171.45 219.006 171.45 L 77.506 171.45 Q 75.756 171.45 74.756 170.45 Q 73.756 169.45 73.756 167.7 Q 73.756 165.95 74.756 164.95 Q 75.756 163.95 77.506 163.95 Z M 96.506 97.45 L 96.506 125.45 Q 96.506 127.45 98.006 128.95 Q 99.506 130.45 101.506 130.45 L 197.506 130.45 Q 199.506 130.45 201.006 128.95 Q 202.506 127.45 202.506 125.45 L 202.506 97.45 L 96.506 97.45 Z M 96.506 62.45 L 96.506 89.95 L 202.506 89.95 L 202.506 62.45 Q 202.506 60.45 201.006 58.95 Q 199.506 57.45 197.506 57.45 L 101.506 57.45 Q 99.506 57.45 98.006 58.95 Q 96.506 60.45 96.506 62.45 Z M 166.506 55.2 L 161.006 51.95 Q 168.756 41.7 176.881 27.7 A 383.321 383.321 0 0 0 189.09 5.114 A 264.812 264.812 0 0 0 190.506 2.2 Q 191.006 0.7 192.506 0.2 Q 194.006 -0.3 195.756 0.45 Q 197.256 0.95 197.756 2.45 Q 198.256 3.95 197.506 5.2 Q 190.506 17.95 182.506 31.45 Q 174.506 44.95 166.506 55.2 Z M 107.672 1.117 A 4.458 4.458 0 0 0 106.006 1.45 Q 104.756 1.95 104.381 2.95 Q 104.006 3.95 104.756 4.95 Q 111.756 13.95 117.006 22.825 Q 122.256 31.7 126.006 39.95 Q 126.506 41.2 127.756 41.7 Q 129.006 42.2 130.256 41.45 Q 132.006 40.7 132.506 39.2 Q 133.006 37.7 132.256 36.45 Q 128.506 28.45 123.256 19.95 Q 118.006 11.45 110.756 2.45 Q 109.756 1.45 108.506 1.2 A 4.24 4.24 0 0 0 107.672 1.117 Z" />
24
+ </G>
25
+ </Svg>
26
+ );
27
+
28
+ export default Mu;
@@ -0,0 +1,114 @@
1
+ import { useCallback, useRef } from "react";
2
+
3
+ export interface DanmuLane {
4
+ index: number;
5
+ occupiedUntil: number;
6
+ }
7
+
8
+ export interface ActiveDanmu {
9
+ id: string;
10
+ lane: number;
11
+ endTime: number;
12
+ startTime: number;
13
+ duration: number;
14
+ width?: number;
15
+ }
16
+
17
+ const LANE_GAP = 4;
18
+
19
+ export const useDanmuLanes = (laneCount: number, containerWidth: number) => {
20
+ const activeDanmu = useRef<Map<string, ActiveDanmu>>(new Map());
21
+ const lanes = useRef<DanmuLane[]>(
22
+ Array.from({ length: laneCount }, (_, i) => ({
23
+ index: i,
24
+ occupiedUntil: 0,
25
+ })),
26
+ );
27
+
28
+ const canFitInLane = useCallback(
29
+ (laneIndex: number): boolean => {
30
+ const now = Date.now();
31
+
32
+ // find all active danmu in this lane
33
+ const danmuInLane = Array.from(activeDanmu.current.values()).filter(
34
+ (d) => d.lane === laneIndex && d.endTime > now,
35
+ );
36
+
37
+ if (danmuInLane.length === 0) return true;
38
+
39
+ // check the most recent danmu in this lane
40
+ const mostRecent = danmuInLane.reduce((latest, current) =>
41
+ current.startTime > latest.startTime ? current : latest,
42
+ );
43
+
44
+ // calculate how far it has traveled
45
+ const elapsed = now - mostRecent.startTime;
46
+ const progress = elapsed / mostRecent.duration;
47
+ const traveled = containerWidth * progress;
48
+
49
+ // estimate width (assume ~8px per char, will be updated with actual width later)
50
+ const estimatedWidth = mostRecent.width || 200;
51
+
52
+ // check if there's enough space
53
+ const spaceNeeded = estimatedWidth + LANE_GAP;
54
+ const hasSpace = traveled >= spaceNeeded;
55
+
56
+ return hasSpace;
57
+ },
58
+ [containerWidth],
59
+ );
60
+
61
+ const assignLane = useCallback(
62
+ (messageId: string, duration: number, width?: number): number | null => {
63
+ const now = Date.now();
64
+
65
+ for (const lane of lanes.current) {
66
+ if (canFitInLane(lane.index)) {
67
+ const endTime = now + duration;
68
+ activeDanmu.current.set(messageId, {
69
+ id: messageId,
70
+ lane: lane.index,
71
+ endTime,
72
+ startTime: now,
73
+ duration,
74
+ width,
75
+ });
76
+ return lane.index;
77
+ }
78
+ }
79
+
80
+ return null;
81
+ },
82
+ [lanes, canFitInLane],
83
+ );
84
+
85
+ const updateDanmuWidth = useCallback((messageId: string, width: number) => {
86
+ const danmu = activeDanmu.current.get(messageId);
87
+ if (danmu) {
88
+ danmu.width = width;
89
+ }
90
+ }, []);
91
+
92
+ const releaseLane = useCallback((messageId: string) => {
93
+ const danmu = activeDanmu.current.get(messageId);
94
+ if (danmu) {
95
+ activeDanmu.current.delete(messageId);
96
+ }
97
+ }, []);
98
+
99
+ const cleanup = useCallback(() => {
100
+ const now = Date.now();
101
+ for (const [id, danmu] of activeDanmu.current.entries()) {
102
+ if (danmu.endTime <= now) {
103
+ activeDanmu.current.delete(id);
104
+ }
105
+ }
106
+ }, []);
107
+
108
+ return {
109
+ assignLane,
110
+ updateDanmuWidth,
111
+ releaseLane,
112
+ cleanup,
113
+ };
114
+ };
@@ -4,7 +4,13 @@ import { BackHandler, Dimensions, StyleSheet, View } from "react-native";
4
4
  import { SystemBars } from "react-native-edge-to-edge";
5
5
  import { useSafeAreaInsets } from "react-native-safe-area-context";
6
6
  import {
7
+ DanmuOverlay,
7
8
  PlayerProtocol,
9
+ useDanmuEnabled,
10
+ useDanmuLaneCount,
11
+ useDanmuMaxMessages,
12
+ useDanmuOpacity,
13
+ useDanmuSpeed,
8
14
  useLivestreamStore,
9
15
  usePlayerStore,
10
16
  VideoRetry,
@@ -30,6 +36,12 @@ export function Fullscreen(props: {
30
36
  const setFullscreen = usePlayerStore((x) => x.setFullscreen);
31
37
  const handle = useLivestreamStore((x) => x.profile?.handle);
32
38
 
39
+ const danmuEnabled = useDanmuEnabled();
40
+ const danmuOpacity = useDanmuOpacity();
41
+ const danmuSpeed = useDanmuSpeed();
42
+ const danmuLaneCount = useDanmuLaneCount();
43
+ const danmuMaxMessages = useDanmuMaxMessages();
44
+
33
45
  const setSrc = usePlayerStore((x) => x.setSrc);
34
46
 
35
47
  useEffect(() => {
@@ -154,6 +166,13 @@ export function Fullscreen(props: {
154
166
  objectFit={props.objectFit}
155
167
  pictureInPictureEnabled={props.pictureInPictureEnabled}
156
168
  />
169
+ <DanmuOverlay
170
+ enabled={danmuEnabled}
171
+ opacity={danmuOpacity}
172
+ speed={danmuSpeed}
173
+ laneCount={danmuLaneCount}
174
+ maxMessages={danmuMaxMessages}
175
+ />
157
176
  {props.children}
158
177
  </View>
159
178
  </View>
@@ -169,6 +188,13 @@ export function Fullscreen(props: {
169
188
  pictureInPictureEnabled={props.pictureInPictureEnabled}
170
189
  />
171
190
  </VideoRetry>
191
+ <DanmuOverlay
192
+ enabled={danmuEnabled}
193
+ opacity={danmuOpacity}
194
+ speed={danmuSpeed}
195
+ laneCount={danmuLaneCount}
196
+ maxMessages={danmuMaxMessages}
197
+ />
172
198
  {props.children}
173
199
  </>
174
200
  );
@@ -1,6 +1,15 @@
1
1
  import { useEffect, useRef } from "react";
2
2
  import { View as RNView } from "react-native";
3
- import { getFirstPlayerID, usePlayerStore } from "../..";
3
+ import {
4
+ DanmuOverlay,
5
+ getFirstPlayerID,
6
+ useDanmuEnabled,
7
+ useDanmuLaneCount,
8
+ useDanmuMaxMessages,
9
+ useDanmuOpacity,
10
+ useDanmuSpeed,
11
+ usePlayerStore,
12
+ } from "../..";
4
13
  import { View } from "../../components/ui";
5
14
  import Video from "./video";
6
15
  import VideoRetry from "./video-retry";
@@ -18,6 +27,12 @@ export function Fullscreen(props: {
18
27
  const setSrc = usePlayerStore((x) => x.setSrc);
19
28
  const setAutoplayFailed = usePlayerStore((x) => x.setAutoplayFailed);
20
29
 
30
+ const danmuEnabled = useDanmuEnabled();
31
+ const danmuOpacity = useDanmuOpacity();
32
+ const danmuSpeed = useDanmuSpeed();
33
+ const danmuLaneCount = useDanmuLaneCount();
34
+ const danmuMaxMessages = useDanmuMaxMessages();
35
+
21
36
  const divRef = useRef<RNView>(null);
22
37
  const videoRef = useRef<HTMLVideoElement | null>(null);
23
38
 
@@ -90,6 +105,13 @@ export function Fullscreen(props: {
90
105
  pictureInPictureEnabled={props.pictureInPictureEnabled}
91
106
  />
92
107
  </VideoRetry>
108
+ <DanmuOverlay
109
+ enabled={danmuEnabled}
110
+ opacity={danmuOpacity}
111
+ speed={danmuSpeed}
112
+ laneCount={danmuLaneCount}
113
+ maxMessages={danmuMaxMessages}
114
+ />
93
115
  {props.children}
94
116
  </View>
95
117
  );
@@ -5,5 +5,6 @@ export * from "./metrics";
5
5
  export * from "./streamer-context-menu";
6
6
  export * from "./streamer-loading-overlay";
7
7
  export * from "./viewer-context-menu";
8
+ export * from "./viewer-count";
8
9
  export * from "./viewer-loading-overlay";
9
10
  export * from "./viewers";
@@ -179,15 +179,15 @@ export function ContextMenu({
179
179
  <View
180
180
  style={[
181
181
  zero.flex.values[1],
182
- zero.layout.flex.row,
182
+ isMobile ? zero.layout.flex.row : zero.layout.flex.column,
183
183
  zero.layout.flex.spaceBetween,
184
184
  zero.pr[4],
185
185
  ]}
186
186
  >
187
187
  <Text>Quality</Text>
188
- <Text muted>
189
- ({quality}, {lowLatency ? "low latency" : "regular latency"}
190
- )
188
+ <Text muted size={isMobile ? "base" : "sm"}>
189
+ {quality === "source" ? "Source" : quality},{" "}
190
+ {lowLatency ? "Low Latency" : ""}
191
191
  </Text>
192
192
  </View>
193
193
  </DropdownMenuSubTrigger>
@@ -0,0 +1,39 @@
1
+ import { useMemo } from "react";
2
+ import { StyleSheet, TextStyle } from "react-native";
3
+ import { Text } from "../../ui/text";
4
+
5
+ export interface ViewerCountProps {
6
+ count?: number | null;
7
+ style?: TextStyle;
8
+ locales?: Intl.LocalesArgument;
9
+ numberFormat?: Intl.NumberFormatOptions;
10
+ }
11
+
12
+ export function ViewerCount({
13
+ count,
14
+ style = {},
15
+ locales,
16
+ numberFormat = { notation: "compact" },
17
+ }: ViewerCountProps) {
18
+ const formattedNumber = useMemo(() => {
19
+ return new Intl.NumberFormat(locales, numberFormat).format(count || 0);
20
+ }, [numberFormat, count]);
21
+
22
+ return (
23
+ <Text leading="snug" style={[styles.label, style]}>
24
+ {formattedNumber}
25
+ </Text>
26
+ );
27
+ }
28
+
29
+ const styles = StyleSheet.create({
30
+ label: {
31
+ color: "#fd5050",
32
+ textShadowColor: "black",
33
+ textShadowRadius: 3,
34
+ fontSize: 16,
35
+ lineHeight: 24,
36
+ },
37
+ });
38
+
39
+ export default ViewerCount;
@@ -1,32 +1,28 @@
1
1
  import { Eye } from "lucide-react-native";
2
2
  import * as atoms from "../../../lib/theme/atoms";
3
3
  import { useViewers } from "../../../livestream-store";
4
- import { Text, View } from "../../ui";
4
+ import { View } from "../../ui";
5
+ import ViewerCount from "./viewer-count";
5
6
 
6
7
  export function Viewers() {
7
8
  const viewers = useViewers();
9
+ return <DehydratedViewers viewers={viewers || 0} />;
10
+ }
11
+
12
+ export function DehydratedViewers({ viewers }: { viewers: number }) {
8
13
  return (
9
14
  <View
10
15
  style={[
11
16
  atoms.layout.flex.center,
12
17
  atoms.layout.flex.row,
13
18
  atoms.gap.all[2],
19
+ atoms.px[1],
14
20
  ]}
15
21
  >
16
22
  <Eye color="#fd5050" />
17
- <Text
18
- style={{
19
- color: "#fd5050",
20
- textShadowColor: "black",
21
- textShadowOffset: { width: -1, height: 1 },
22
- textShadowRadius: 3,
23
- fontSize: 16,
24
- }}
25
- >
26
- {new Intl.NumberFormat(undefined, { notation: "compact" }).format(
27
- viewers || 0,
28
- )}
29
- </Text>
23
+ <ViewerCount count={viewers} />
30
24
  </View>
31
25
  );
32
26
  }
27
+
28
+ export default Viewers;
@@ -39,6 +39,7 @@ export interface ButtonProps
39
39
  rightIcon?: React.ReactNode;
40
40
  loading?: boolean;
41
41
  loadingText?: string;
42
+ width?: "full" | "min" | number;
42
43
  }
43
44
 
44
45
  export const Button = forwardRef<any, ButtonProps>(
@@ -53,6 +54,7 @@ export const Button = forwardRef<any, ButtonProps>(
53
54
  loadingText,
54
55
  disabled,
55
56
  style,
57
+ width = "full",
56
58
  ...props
57
59
  },
58
60
  ref,
@@ -198,11 +200,21 @@ export const Button = forwardRef<any, ButtonProps>(
198
200
  }
199
201
  }, [variant, icons]);
200
202
 
203
+ const widthStyle = useMemo(() => {
204
+ if (width === "full") {
205
+ return { width: "100%" };
206
+ } else if (width === "min") {
207
+ return { alignSelf: "flex-start" as const };
208
+ } else {
209
+ return { width };
210
+ }
211
+ }, [width]);
212
+
201
213
  return (
202
214
  <ButtonPrimitive.Root
203
215
  ref={ref}
204
216
  disabled={disabled || loading}
205
- style={[buttonStyle, sizeStyles.button, style]}
217
+ style={[buttonStyle, sizeStyles.button, widthStyle, style]}
206
218
  {...props}
207
219
  >
208
220
  <ButtonPrimitive.Content style={sizeStyles.inner}>
@@ -216,9 +228,15 @@ export const Button = forwardRef<any, ButtonProps>(
216
228
  </ButtonPrimitive.Icon>
217
229
  ) : null}
218
230
 
219
- <TextPrimitive.Root style={[textStyle as any, sizeStyles.text]}>
220
- {loading && loadingText ? loadingText : children}
221
- </TextPrimitive.Root>
231
+ {typeof children === "string" ? (
232
+ <TextPrimitive.Root style={[textStyle as any, sizeStyles.text]}>
233
+ {loading && loadingText ? loadingText : children}
234
+ </TextPrimitive.Root>
235
+ ) : loading && loadingText ? (
236
+ loadingText
237
+ ) : (
238
+ children
239
+ )}
222
240
 
223
241
  {loading && rightIcon ? (
224
242
  <ButtonPrimitive.Icon position="right">