@liveblocks/react-ui 2.18.3 → 2.18.4-uns1

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 (675) hide show
  1. package/dist/_private/index.cjs +118 -0
  2. package/dist/_private/index.cjs.map +1 -0
  3. package/dist/_private/index.js +54 -117
  4. package/dist/_private/index.js.map +1 -1
  5. package/dist/components/{Comment.mjs → Comment.cjs} +196 -169
  6. package/dist/components/{Comment.mjs.map → Comment.cjs.map} +1 -1
  7. package/dist/components/Comment.js +168 -195
  8. package/dist/components/Comment.js.map +1 -1
  9. package/dist/components/{Composer.mjs → Composer.cjs} +151 -148
  10. package/dist/components/{Composer.mjs.map → Composer.cjs.map} +1 -1
  11. package/dist/components/Composer.js +147 -150
  12. package/dist/components/Composer.js.map +1 -1
  13. package/dist/components/HistoryVersionSummary.cjs +45 -0
  14. package/dist/components/{HistoryVersionSummary.mjs.map → HistoryVersionSummary.cjs.map} +1 -1
  15. package/dist/components/HistoryVersionSummary.js +17 -19
  16. package/dist/components/HistoryVersionSummary.js.map +1 -1
  17. package/dist/components/HistoryVersionSummaryList.cjs +25 -0
  18. package/dist/components/{HistoryVersionSummaryList.mjs.map → HistoryVersionSummaryList.cjs.map} +1 -1
  19. package/dist/components/HistoryVersionSummaryList.js +8 -10
  20. package/dist/components/HistoryVersionSummaryList.js.map +1 -1
  21. package/dist/components/{InboxNotification.mjs → InboxNotification.cjs} +124 -122
  22. package/dist/components/{InboxNotification.mjs.map → InboxNotification.cjs.map} +1 -1
  23. package/dist/components/InboxNotification.js +121 -123
  24. package/dist/components/InboxNotification.js.map +1 -1
  25. package/dist/components/InboxNotificationList.cjs +42 -0
  26. package/dist/components/{InboxNotificationList.mjs.map → InboxNotificationList.cjs.map} +1 -1
  27. package/dist/components/InboxNotificationList.js +14 -16
  28. package/dist/components/InboxNotificationList.js.map +1 -1
  29. package/dist/components/{Thread.mjs → Thread.cjs} +70 -49
  30. package/dist/components/{Thread.mjs.map → Thread.cjs.map} +1 -1
  31. package/dist/components/Thread.js +48 -69
  32. package/dist/components/Thread.js.map +1 -1
  33. package/dist/components/internal/{Attachment.mjs → Attachment.cjs} +82 -78
  34. package/dist/components/internal/{Attachment.mjs.map → Attachment.cjs.map} +1 -1
  35. package/dist/components/internal/Attachment.js +77 -81
  36. package/dist/components/internal/Attachment.js.map +1 -1
  37. package/dist/components/internal/{Attribution.mjs → Attribution.cjs} +10 -8
  38. package/dist/components/internal/{Attribution.mjs.map → Attribution.cjs.map} +1 -1
  39. package/dist/components/internal/Attribution.js +7 -9
  40. package/dist/components/internal/Attribution.js.map +1 -1
  41. package/dist/components/internal/Avatar.cjs +48 -0
  42. package/dist/components/internal/{Avatar.mjs.map → Avatar.cjs.map} +1 -1
  43. package/dist/components/internal/Avatar.js +18 -20
  44. package/dist/components/internal/Avatar.js.map +1 -1
  45. package/dist/components/internal/Button.cjs +80 -0
  46. package/dist/components/internal/{Button.mjs.map → Button.cjs.map} +1 -1
  47. package/dist/components/internal/Button.js +19 -23
  48. package/dist/components/internal/Button.js.map +1 -1
  49. package/dist/components/internal/Dropdown.cjs +92 -0
  50. package/dist/components/internal/{Dropdown.mjs.map → Dropdown.cjs.map} +1 -1
  51. package/dist/components/internal/Dropdown.js +22 -47
  52. package/dist/components/internal/Dropdown.js.map +1 -1
  53. package/dist/components/internal/Emoji.cjs +19 -0
  54. package/dist/components/internal/{Emoji.mjs.map → Emoji.cjs.map} +1 -1
  55. package/dist/components/internal/Emoji.js +8 -10
  56. package/dist/components/internal/Emoji.js.map +1 -1
  57. package/dist/components/internal/EmojiPicker.cjs +208 -0
  58. package/dist/components/internal/{EmojiPicker.mjs.map → EmojiPicker.cjs.map} +1 -1
  59. package/dist/components/internal/EmojiPicker.js +52 -76
  60. package/dist/components/internal/EmojiPicker.js.map +1 -1
  61. package/dist/components/internal/{Icon.mjs → Icon.cjs} +10 -6
  62. package/dist/components/internal/{Icon.mjs.map → Icon.cjs.map} +1 -1
  63. package/dist/components/internal/Icon.js +5 -9
  64. package/dist/components/internal/Icon.js.map +1 -1
  65. package/dist/components/internal/{InboxNotificationThread.mjs → InboxNotificationThread.cjs} +34 -30
  66. package/dist/components/internal/{InboxNotificationThread.mjs.map → InboxNotificationThread.cjs.map} +1 -1
  67. package/dist/components/internal/InboxNotificationThread.js +29 -33
  68. package/dist/components/internal/InboxNotificationThread.js.map +1 -1
  69. package/dist/components/internal/List.cjs +36 -0
  70. package/dist/components/internal/{List.mjs.map → List.cjs.map} +1 -1
  71. package/dist/components/internal/List.js +14 -16
  72. package/dist/components/internal/List.js.map +1 -1
  73. package/dist/components/internal/Room.cjs +24 -0
  74. package/dist/components/internal/{Room.mjs.map → Room.cjs.map} +1 -1
  75. package/dist/components/internal/Room.js +9 -11
  76. package/dist/components/internal/Room.js.map +1 -1
  77. package/dist/components/internal/Tooltip.cjs +134 -0
  78. package/dist/components/internal/{Tooltip.mjs.map → Tooltip.cjs.map} +1 -1
  79. package/dist/components/internal/Tooltip.js +29 -54
  80. package/dist/components/internal/Tooltip.js.map +1 -1
  81. package/dist/components/internal/User.cjs +28 -0
  82. package/dist/components/internal/{User.mjs.map → User.cjs.map} +1 -1
  83. package/dist/components/internal/User.js +13 -15
  84. package/dist/components/internal/User.js.map +1 -1
  85. package/dist/components.cjs +48 -0
  86. package/dist/{components.mjs.map → components.cjs.map} +1 -1
  87. package/dist/components.js +9 -14
  88. package/dist/components.js.map +1 -1
  89. package/dist/config.cjs +39 -0
  90. package/dist/{config.mjs.map → config.cjs.map} +1 -1
  91. package/dist/config.js +15 -18
  92. package/dist/config.js.map +1 -1
  93. package/dist/{constants.mjs → constants.cjs} +6 -2
  94. package/dist/{constants.mjs.map → constants.cjs.map} +1 -1
  95. package/dist/constants.js +1 -5
  96. package/dist/constants.js.map +1 -1
  97. package/dist/icon.cjs +69 -0
  98. package/dist/icon.cjs.map +1 -0
  99. package/dist/icon.js +32 -68
  100. package/dist/icon.js.map +1 -1
  101. package/dist/icons/ArrowCornerDownRight.cjs +16 -0
  102. package/dist/icons/{ArrowCornerDownRight.mjs.map → ArrowCornerDownRight.cjs.map} +1 -1
  103. package/dist/icons/ArrowCornerDownRight.js +5 -7
  104. package/dist/icons/ArrowCornerDownRight.js.map +1 -1
  105. package/dist/icons/ArrowCornerUpRight.cjs +16 -0
  106. package/dist/icons/ArrowCornerUpRight.cjs.map +1 -0
  107. package/dist/icons/ArrowCornerUpRight.js +5 -7
  108. package/dist/icons/ArrowCornerUpRight.js.map +1 -1
  109. package/dist/icons/ArrowDown.cjs +16 -0
  110. package/dist/icons/ArrowDown.cjs.map +1 -0
  111. package/dist/icons/ArrowDown.js +5 -7
  112. package/dist/icons/ArrowDown.js.map +1 -1
  113. package/dist/icons/ArrowUp.cjs +16 -0
  114. package/dist/icons/ArrowUp.cjs.map +1 -0
  115. package/dist/icons/ArrowUp.js +5 -7
  116. package/dist/icons/ArrowUp.js.map +1 -1
  117. package/dist/icons/{Attachment.mjs → Attachment.cjs} +8 -6
  118. package/dist/icons/{Attachment.mjs.map → Attachment.cjs.map} +1 -1
  119. package/dist/icons/Attachment.js +5 -7
  120. package/dist/icons/Attachment.js.map +1 -1
  121. package/dist/icons/Blockquote.cjs +16 -0
  122. package/dist/icons/Blockquote.cjs.map +1 -0
  123. package/dist/icons/Blockquote.js +5 -7
  124. package/dist/icons/Blockquote.js.map +1 -1
  125. package/dist/icons/Bold.cjs +16 -0
  126. package/dist/icons/{Bold.mjs.map → Bold.cjs.map} +1 -1
  127. package/dist/icons/Bold.js +5 -7
  128. package/dist/icons/Bold.js.map +1 -1
  129. package/dist/icons/Check.cjs +16 -0
  130. package/dist/icons/Check.cjs.map +1 -0
  131. package/dist/icons/Check.js +5 -7
  132. package/dist/icons/Check.js.map +1 -1
  133. package/dist/icons/ChevronDown.cjs +16 -0
  134. package/dist/icons/{ChevronDown.mjs.map → ChevronDown.cjs.map} +1 -1
  135. package/dist/icons/ChevronDown.js +5 -7
  136. package/dist/icons/ChevronDown.js.map +1 -1
  137. package/dist/icons/ChevronLeft.cjs +16 -0
  138. package/dist/icons/{ChevronLeft.mjs.map → ChevronLeft.cjs.map} +1 -1
  139. package/dist/icons/ChevronLeft.js +5 -7
  140. package/dist/icons/ChevronLeft.js.map +1 -1
  141. package/dist/icons/ChevronRight.cjs +16 -0
  142. package/dist/icons/{ChevronRight.mjs.map → ChevronRight.cjs.map} +1 -1
  143. package/dist/icons/ChevronRight.js +5 -7
  144. package/dist/icons/ChevronRight.js.map +1 -1
  145. package/dist/icons/ChevronUp.cjs +16 -0
  146. package/dist/icons/{ChevronUp.mjs.map → ChevronUp.cjs.map} +1 -1
  147. package/dist/icons/ChevronUp.js +5 -7
  148. package/dist/icons/ChevronUp.js.map +1 -1
  149. package/dist/icons/Code.cjs +16 -0
  150. package/dist/icons/Code.cjs.map +1 -0
  151. package/dist/icons/Code.js +5 -7
  152. package/dist/icons/Code.js.map +1 -1
  153. package/dist/icons/Comment.cjs +16 -0
  154. package/dist/icons/{Comment.mjs.map → Comment.cjs.map} +1 -1
  155. package/dist/icons/Comment.js +5 -7
  156. package/dist/icons/Comment.js.map +1 -1
  157. package/dist/icons/Cross.cjs +21 -0
  158. package/dist/icons/Cross.cjs.map +1 -0
  159. package/dist/icons/Cross.js +6 -8
  160. package/dist/icons/Cross.js.map +1 -1
  161. package/dist/icons/Delete.cjs +16 -0
  162. package/dist/icons/{Delete.mjs.map → Delete.cjs.map} +1 -1
  163. package/dist/icons/Delete.js +5 -7
  164. package/dist/icons/Delete.js.map +1 -1
  165. package/dist/icons/Edit.cjs +16 -0
  166. package/dist/icons/{Edit.mjs.map → Edit.cjs.map} +1 -1
  167. package/dist/icons/Edit.js +5 -7
  168. package/dist/icons/Edit.js.map +1 -1
  169. package/dist/icons/Ellipsis.cjs +31 -0
  170. package/dist/icons/Ellipsis.cjs.map +1 -0
  171. package/dist/icons/Ellipsis.js +7 -9
  172. package/dist/icons/Ellipsis.js.map +1 -1
  173. package/dist/icons/Emoji.cjs +34 -0
  174. package/dist/icons/Emoji.cjs.map +1 -0
  175. package/dist/icons/Emoji.js +9 -11
  176. package/dist/icons/Emoji.js.map +1 -1
  177. package/dist/icons/EmojiAdd.cjs +37 -0
  178. package/dist/icons/EmojiAdd.cjs.map +1 -0
  179. package/dist/icons/EmojiAdd.js +10 -12
  180. package/dist/icons/EmojiAdd.js.map +1 -1
  181. package/dist/icons/H1.cjs +16 -0
  182. package/dist/icons/{H1.mjs.map → H1.cjs.map} +1 -1
  183. package/dist/icons/H1.js +5 -7
  184. package/dist/icons/H1.js.map +1 -1
  185. package/dist/icons/H2.cjs +16 -0
  186. package/dist/icons/H2.cjs.map +1 -0
  187. package/dist/icons/H2.js +5 -7
  188. package/dist/icons/H2.js.map +1 -1
  189. package/dist/icons/H3.cjs +16 -0
  190. package/dist/icons/{H3.mjs.map → H3.cjs.map} +1 -1
  191. package/dist/icons/H3.js +5 -7
  192. package/dist/icons/H3.js.map +1 -1
  193. package/dist/icons/Italic.cjs +16 -0
  194. package/dist/icons/{Italic.mjs.map → Italic.cjs.map} +1 -1
  195. package/dist/icons/Italic.js +5 -7
  196. package/dist/icons/Italic.js.map +1 -1
  197. package/dist/icons/Lengthen.cjs +16 -0
  198. package/dist/icons/Lengthen.cjs.map +1 -0
  199. package/dist/icons/Lengthen.js +5 -7
  200. package/dist/icons/Lengthen.js.map +1 -1
  201. package/dist/icons/ListOrdered.cjs +16 -0
  202. package/dist/icons/{ListOrdered.mjs.map → ListOrdered.cjs.map} +1 -1
  203. package/dist/icons/ListOrdered.js +5 -7
  204. package/dist/icons/ListOrdered.js.map +1 -1
  205. package/dist/icons/ListUnordered.cjs +39 -0
  206. package/dist/icons/ListUnordered.cjs.map +1 -0
  207. package/dist/icons/ListUnordered.js +10 -12
  208. package/dist/icons/ListUnordered.js.map +1 -1
  209. package/dist/icons/Mention.cjs +21 -0
  210. package/dist/icons/Mention.cjs.map +1 -0
  211. package/dist/icons/Mention.js +6 -8
  212. package/dist/icons/Mention.js.map +1 -1
  213. package/dist/icons/QuestionMark.cjs +26 -0
  214. package/dist/icons/QuestionMark.cjs.map +1 -0
  215. package/dist/icons/QuestionMark.js +7 -9
  216. package/dist/icons/QuestionMark.js.map +1 -1
  217. package/dist/icons/Redo.cjs +21 -0
  218. package/dist/icons/Redo.cjs.map +1 -0
  219. package/dist/icons/Redo.js +6 -8
  220. package/dist/icons/Redo.js.map +1 -1
  221. package/dist/icons/Resolve.cjs +23 -0
  222. package/dist/icons/Resolve.cjs.map +1 -0
  223. package/dist/icons/Resolve.js +6 -8
  224. package/dist/icons/Resolve.js.map +1 -1
  225. package/dist/icons/Resolved.cjs +25 -0
  226. package/dist/icons/Resolved.cjs.map +1 -0
  227. package/dist/icons/Resolved.js +6 -8
  228. package/dist/icons/Resolved.js.map +1 -1
  229. package/dist/icons/Restore.cjs +21 -0
  230. package/dist/icons/Restore.cjs.map +1 -0
  231. package/dist/icons/Restore.js +6 -8
  232. package/dist/icons/Restore.js.map +1 -1
  233. package/dist/icons/Search.cjs +16 -0
  234. package/dist/icons/{Search.mjs.map → Search.cjs.map} +1 -1
  235. package/dist/icons/Search.js +5 -7
  236. package/dist/icons/Search.js.map +1 -1
  237. package/dist/icons/Send.cjs +16 -0
  238. package/dist/icons/Send.cjs.map +1 -0
  239. package/dist/icons/Send.js +5 -7
  240. package/dist/icons/Send.js.map +1 -1
  241. package/dist/icons/Shorten.cjs +16 -0
  242. package/dist/icons/{Shorten.mjs.map → Shorten.cjs.map} +1 -1
  243. package/dist/icons/Shorten.js +5 -7
  244. package/dist/icons/Shorten.js.map +1 -1
  245. package/dist/icons/{Sparkles.mjs → Sparkles.cjs} +8 -6
  246. package/dist/icons/{Sparkles.mjs.map → Sparkles.cjs.map} +1 -1
  247. package/dist/icons/Sparkles.js +5 -7
  248. package/dist/icons/Sparkles.js.map +1 -1
  249. package/dist/icons/SparklesText.cjs +21 -0
  250. package/dist/icons/{SparklesText.mjs.map → SparklesText.cjs.map} +1 -1
  251. package/dist/icons/SparklesText.js +6 -8
  252. package/dist/icons/SparklesText.js.map +1 -1
  253. package/dist/icons/Spinner.cjs +17 -0
  254. package/dist/icons/Spinner.cjs.map +1 -0
  255. package/dist/icons/Spinner.js +5 -7
  256. package/dist/icons/Spinner.js.map +1 -1
  257. package/dist/icons/Strikethrough.cjs +16 -0
  258. package/dist/icons/{Strikethrough.mjs.map → Strikethrough.cjs.map} +1 -1
  259. package/dist/icons/Strikethrough.js +5 -7
  260. package/dist/icons/Strikethrough.js.map +1 -1
  261. package/dist/icons/Text.cjs +16 -0
  262. package/dist/icons/{Text.mjs.map → Text.cjs.map} +1 -1
  263. package/dist/icons/Text.js +5 -7
  264. package/dist/icons/Text.js.map +1 -1
  265. package/dist/icons/Translate.cjs +21 -0
  266. package/dist/icons/{Translate.mjs.map → Translate.cjs.map} +1 -1
  267. package/dist/icons/Translate.js +6 -8
  268. package/dist/icons/Translate.js.map +1 -1
  269. package/dist/icons/Underline.cjs +16 -0
  270. package/dist/icons/Underline.cjs.map +1 -0
  271. package/dist/icons/Underline.js +5 -7
  272. package/dist/icons/Underline.js.map +1 -1
  273. package/dist/icons/Undo.cjs +21 -0
  274. package/dist/icons/Undo.cjs.map +1 -0
  275. package/dist/icons/Undo.js +6 -8
  276. package/dist/icons/Undo.js.map +1 -1
  277. package/dist/icons/Warning.cjs +23 -0
  278. package/dist/icons/Warning.cjs.map +1 -0
  279. package/dist/icons/Warning.js +6 -8
  280. package/dist/icons/Warning.js.map +1 -1
  281. package/dist/icons/index.cjs +96 -0
  282. package/dist/icons/index.cjs.map +1 -0
  283. package/dist/icons/index.js +45 -95
  284. package/dist/icons/index.js.map +1 -1
  285. package/dist/index.cjs +28 -0
  286. package/dist/{index.mjs.map → index.cjs.map} +1 -1
  287. package/dist/index.js +14 -26
  288. package/dist/index.js.map +1 -1
  289. package/dist/{overrides.mjs → overrides.cjs} +32 -27
  290. package/dist/{overrides.mjs.map → overrides.cjs.map} +1 -1
  291. package/dist/overrides.js +26 -31
  292. package/dist/overrides.js.map +1 -1
  293. package/dist/primitives/Comment/{index.mjs → index.cjs} +35 -31
  294. package/dist/primitives/Comment/{index.mjs.map → index.cjs.map} +1 -1
  295. package/dist/primitives/Comment/index.js +30 -34
  296. package/dist/primitives/Comment/index.js.map +1 -1
  297. package/dist/primitives/Comment/{utils.mjs → utils.cjs} +7 -2
  298. package/dist/primitives/Comment/{utils.mjs.map → utils.cjs.map} +1 -1
  299. package/dist/primitives/Comment/utils.js +1 -6
  300. package/dist/primitives/Comment/utils.js.map +1 -1
  301. package/dist/primitives/Composer/contexts.cjs +60 -0
  302. package/dist/primitives/Composer/{contexts.mjs.map → contexts.cjs.map} +1 -1
  303. package/dist/primitives/Composer/contexts.js +18 -30
  304. package/dist/primitives/Composer/contexts.js.map +1 -1
  305. package/dist/primitives/Composer/{index.mjs → index.cjs} +305 -273
  306. package/dist/primitives/Composer/{index.mjs.map → index.cjs.map} +1 -1
  307. package/dist/primitives/Composer/index.js +272 -304
  308. package/dist/primitives/Composer/index.js.map +1 -1
  309. package/dist/primitives/Composer/{utils.mjs → utils.cjs} +79 -64
  310. package/dist/primitives/Composer/{utils.mjs.map → utils.cjs.map} +1 -1
  311. package/dist/primitives/Composer/utils.js +63 -78
  312. package/dist/primitives/Composer/utils.js.map +1 -1
  313. package/dist/primitives/EmojiPicker/contexts.cjs +19 -0
  314. package/dist/primitives/EmojiPicker/{contexts.mjs.map → contexts.cjs.map} +1 -1
  315. package/dist/primitives/EmojiPicker/contexts.js +6 -9
  316. package/dist/primitives/EmojiPicker/contexts.js.map +1 -1
  317. package/dist/primitives/EmojiPicker/{index.mjs → index.cjs} +96 -92
  318. package/dist/primitives/EmojiPicker/{index.mjs.map → index.cjs.map} +1 -1
  319. package/dist/primitives/EmojiPicker/index.js +91 -95
  320. package/dist/primitives/EmojiPicker/index.js.map +1 -1
  321. package/dist/primitives/EmojiPicker/{utils.mjs → utils.cjs} +14 -10
  322. package/dist/primitives/EmojiPicker/{utils.mjs.map → utils.cjs.map} +1 -1
  323. package/dist/primitives/EmojiPicker/utils.js +9 -13
  324. package/dist/primitives/EmojiPicker/utils.js.map +1 -1
  325. package/dist/primitives/FileSize.cjs +36 -0
  326. package/dist/primitives/{FileSize.mjs.map → FileSize.cjs.map} +1 -1
  327. package/dist/primitives/FileSize.js +10 -12
  328. package/dist/primitives/FileSize.js.map +1 -1
  329. package/dist/primitives/{Timestamp.mjs → Timestamp.cjs} +27 -25
  330. package/dist/primitives/{Timestamp.mjs.map → Timestamp.cjs.map} +1 -1
  331. package/dist/primitives/Timestamp.js +24 -26
  332. package/dist/primitives/Timestamp.js.map +1 -1
  333. package/dist/primitives/index.cjs +20 -0
  334. package/dist/primitives/index.cjs.map +1 -0
  335. package/dist/primitives/index.js +10 -19
  336. package/dist/primitives/index.js.map +1 -1
  337. package/dist/primitives/internal/Emoji.cjs +32 -0
  338. package/dist/primitives/internal/{Emoji.mjs.map → Emoji.cjs.map} +1 -1
  339. package/dist/primitives/internal/Emoji.js +9 -11
  340. package/dist/primitives/internal/Emoji.js.map +1 -1
  341. package/dist/shared.cjs +13 -0
  342. package/dist/{shared.mjs.map → shared.cjs.map} +1 -1
  343. package/dist/shared.js +6 -8
  344. package/dist/shared.js.map +1 -1
  345. package/dist/slate/plugins/{auto-formatting.mjs → auto-formatting.cjs} +18 -16
  346. package/dist/slate/plugins/{auto-formatting.mjs.map → auto-formatting.cjs.map} +1 -1
  347. package/dist/slate/plugins/auto-formatting.js +15 -17
  348. package/dist/slate/plugins/auto-formatting.js.map +1 -1
  349. package/dist/slate/plugins/{auto-links.mjs → auto-links.cjs} +43 -40
  350. package/dist/slate/plugins/{auto-links.mjs.map → auto-links.cjs.map} +1 -1
  351. package/dist/slate/plugins/auto-links.js +39 -42
  352. package/dist/slate/plugins/auto-links.js.map +1 -1
  353. package/dist/slate/plugins/{custom-links.mjs → custom-links.cjs} +19 -16
  354. package/dist/slate/plugins/{custom-links.mjs.map → custom-links.cjs.map} +1 -1
  355. package/dist/slate/plugins/custom-links.js +15 -18
  356. package/dist/slate/plugins/custom-links.js.map +1 -1
  357. package/dist/slate/plugins/empty-clear-formatting.cjs +18 -0
  358. package/dist/slate/plugins/{empty-clear-formatting.mjs.map → empty-clear-formatting.cjs.map} +1 -1
  359. package/dist/slate/plugins/empty-clear-formatting.js +5 -7
  360. package/dist/slate/plugins/empty-clear-formatting.js.map +1 -1
  361. package/dist/slate/plugins/mentions.cjs +129 -0
  362. package/dist/slate/plugins/{mentions.mjs.map → mentions.cjs.map} +1 -1
  363. package/dist/slate/plugins/mentions.js +35 -42
  364. package/dist/slate/plugins/mentions.js.map +1 -1
  365. package/dist/slate/plugins/normalize.cjs +28 -0
  366. package/dist/slate/plugins/normalize.cjs.map +1 -0
  367. package/dist/slate/plugins/normalize.js +8 -10
  368. package/dist/slate/plugins/normalize.js.map +1 -1
  369. package/dist/slate/plugins/{paste.mjs → paste.cjs} +14 -12
  370. package/dist/slate/plugins/{paste.mjs.map → paste.cjs.map} +1 -1
  371. package/dist/slate/plugins/paste.js +11 -13
  372. package/dist/slate/plugins/paste.js.map +1 -1
  373. package/dist/slate/utils/get-character.cjs +50 -0
  374. package/dist/slate/utils/{get-character.mjs.map → get-character.cjs.map} +1 -1
  375. package/dist/slate/utils/get-character.js +10 -13
  376. package/dist/slate/utils/get-character.js.map +1 -1
  377. package/dist/slate/utils/get-dom-range.cjs +17 -0
  378. package/dist/slate/utils/{get-dom-range.mjs.map → get-dom-range.cjs.map} +1 -1
  379. package/dist/slate/utils/get-dom-range.js +3 -5
  380. package/dist/slate/utils/get-dom-range.js.map +1 -1
  381. package/dist/slate/utils/{get-match-range.mjs → get-match-range.cjs} +14 -12
  382. package/dist/slate/utils/{get-match-range.mjs.map → get-match-range.cjs.map} +1 -1
  383. package/dist/slate/utils/get-match-range.js +11 -13
  384. package/dist/slate/utils/get-match-range.js.map +1 -1
  385. package/dist/slate/utils/is-empty-string.cjs +8 -0
  386. package/dist/slate/utils/is-empty-string.cjs.map +1 -0
  387. package/dist/slate/utils/is-empty-string.js +1 -3
  388. package/dist/slate/utils/is-empty-string.js.map +1 -1
  389. package/dist/slate/utils/is-empty.cjs +27 -0
  390. package/dist/slate/utils/{is-empty.mjs.map → is-empty.cjs.map} +1 -1
  391. package/dist/slate/utils/is-empty.js +8 -10
  392. package/dist/slate/utils/is-empty.js.map +1 -1
  393. package/dist/slate/utils/{is-text.mjs → is-text.cjs} +5 -2
  394. package/dist/slate/utils/{is-text.mjs.map → is-text.cjs.map} +1 -1
  395. package/dist/slate/utils/is-text.js +1 -4
  396. package/dist/slate/utils/is-text.js.map +1 -1
  397. package/dist/slate/utils/{is-whitespace-character.mjs → is-whitespace-character.cjs} +4 -2
  398. package/dist/slate/utils/{is-whitespace-character.mjs.map → is-whitespace-character.cjs.map} +1 -1
  399. package/dist/slate/utils/is-whitespace-character.js +1 -3
  400. package/dist/slate/utils/is-whitespace-character.js.map +1 -1
  401. package/dist/slate/utils/marks.cjs +62 -0
  402. package/dist/slate/utils/{marks.mjs.map → marks.cjs.map} +1 -1
  403. package/dist/slate/utils/marks.js +12 -19
  404. package/dist/slate/utils/marks.js.map +1 -1
  405. package/dist/slate/utils/selection-contains-inlines.cjs +36 -0
  406. package/dist/slate/utils/selection-contains-inlines.cjs.map +1 -0
  407. package/dist/slate/utils/selection-contains-inlines.js +7 -9
  408. package/dist/slate/utils/selection-contains-inlines.js.map +1 -1
  409. package/dist/utils/{Persist.mjs → Persist.cjs} +26 -22
  410. package/dist/utils/{Persist.mjs.map → Persist.cjs.map} +1 -1
  411. package/dist/utils/Persist.js +21 -25
  412. package/dist/utils/Persist.js.map +1 -1
  413. package/dist/utils/Portal.cjs +29 -0
  414. package/dist/utils/{Portal.mjs.map → Portal.cjs.map} +1 -1
  415. package/dist/utils/Portal.js +9 -11
  416. package/dist/utils/Portal.js.map +1 -1
  417. package/dist/utils/{capitalize.mjs → capitalize.cjs} +4 -2
  418. package/dist/utils/capitalize.cjs.map +1 -0
  419. package/dist/utils/capitalize.js +1 -3
  420. package/dist/utils/capitalize.js.map +1 -1
  421. package/dist/utils/{clamp.mjs → clamp.cjs} +4 -2
  422. package/dist/utils/clamp.cjs.map +1 -0
  423. package/dist/utils/clamp.js +1 -3
  424. package/dist/utils/clamp.js.map +1 -1
  425. package/dist/utils/{class-names.mjs → class-names.cjs} +4 -2
  426. package/dist/utils/{class-names.mjs.map → class-names.cjs.map} +1 -1
  427. package/dist/utils/class-names.js +1 -3
  428. package/dist/utils/class-names.js.map +1 -1
  429. package/dist/utils/{data-transfer.mjs → data-transfer.cjs} +6 -4
  430. package/dist/utils/{data-transfer.mjs.map → data-transfer.cjs.map} +1 -1
  431. package/dist/utils/data-transfer.js +3 -5
  432. package/dist/utils/data-transfer.js.map +1 -1
  433. package/dist/utils/{download.mjs → download.cjs} +4 -2
  434. package/dist/utils/download.cjs.map +1 -0
  435. package/dist/utils/download.js +1 -3
  436. package/dist/utils/download.js.map +1 -1
  437. package/dist/utils/exists.cjs +8 -0
  438. package/dist/utils/exists.cjs.map +1 -0
  439. package/dist/utils/exists.js +1 -3
  440. package/dist/utils/exists.js.map +1 -1
  441. package/dist/utils/{find-last-index.mjs → find-last-index.cjs} +4 -2
  442. package/dist/utils/find-last-index.cjs.map +1 -0
  443. package/dist/utils/find-last-index.js +1 -3
  444. package/dist/utils/find-last-index.js.map +1 -1
  445. package/dist/utils/{format-file-size.mjs → format-file-size.cjs} +6 -4
  446. package/dist/utils/format-file-size.cjs.map +1 -0
  447. package/dist/utils/format-file-size.js +3 -5
  448. package/dist/utils/format-file-size.js.map +1 -1
  449. package/dist/utils/{get-initials.mjs → get-initials.cjs} +4 -2
  450. package/dist/utils/get-initials.cjs.map +1 -0
  451. package/dist/utils/get-initials.js +1 -3
  452. package/dist/utils/get-initials.js.map +1 -1
  453. package/dist/utils/intl.cjs +30 -0
  454. package/dist/utils/{intl.mjs.map → intl.cjs.map} +1 -1
  455. package/dist/utils/intl.js +6 -11
  456. package/dist/utils/intl.js.map +1 -1
  457. package/dist/utils/{is-apple.mjs → is-apple.cjs} +4 -2
  458. package/dist/utils/is-apple.cjs.map +1 -0
  459. package/dist/utils/is-apple.js +1 -3
  460. package/dist/utils/is-apple.js.map +1 -1
  461. package/dist/utils/{is-key.mjs → is-key.cjs} +6 -4
  462. package/dist/utils/{is-key.mjs.map → is-key.cjs.map} +1 -1
  463. package/dist/utils/is-key.js +3 -5
  464. package/dist/utils/is-key.js.map +1 -1
  465. package/dist/utils/{memoize.mjs → memoize.cjs} +6 -4
  466. package/dist/utils/memoize.cjs.map +1 -0
  467. package/dist/utils/memoize.js +3 -5
  468. package/dist/utils/memoize.js.map +1 -1
  469. package/dist/utils/{pluralize.mjs → pluralize.cjs} +4 -2
  470. package/dist/utils/pluralize.cjs.map +1 -0
  471. package/dist/utils/pluralize.js +1 -3
  472. package/dist/utils/pluralize.js.map +1 -1
  473. package/dist/utils/{request-idle-callback.mjs → request-idle-callback.cjs} +5 -2
  474. package/dist/utils/{request-idle-callback.mjs.map → request-idle-callback.cjs.map} +1 -1
  475. package/dist/utils/request-idle-callback.js +1 -4
  476. package/dist/utils/request-idle-callback.js.map +1 -1
  477. package/dist/utils/{request-submit.mjs → request-submit.cjs} +4 -2
  478. package/dist/utils/request-submit.cjs.map +1 -0
  479. package/dist/utils/request-submit.js +1 -3
  480. package/dist/utils/request-submit.js.map +1 -1
  481. package/dist/utils/{url.mjs → url.cjs} +4 -2
  482. package/dist/utils/url.cjs.map +1 -0
  483. package/dist/utils/url.js +1 -3
  484. package/dist/utils/url.js.map +1 -1
  485. package/dist/utils/{use-controllable-state.mjs → use-controllable-state.cjs} +11 -9
  486. package/dist/utils/{use-controllable-state.mjs.map → use-controllable-state.cjs.map} +1 -1
  487. package/dist/utils/use-controllable-state.js +8 -10
  488. package/dist/utils/use-controllable-state.js.map +1 -1
  489. package/dist/utils/use-index.cjs +32 -0
  490. package/dist/utils/{use-index.mjs.map → use-index.cjs.map} +1 -1
  491. package/dist/utils/use-index.js +11 -13
  492. package/dist/utils/use-index.js.map +1 -1
  493. package/dist/utils/use-initial.cjs +11 -0
  494. package/dist/utils/{use-initial.mjs.map → use-initial.cjs.map} +1 -1
  495. package/dist/utils/use-initial.js +3 -5
  496. package/dist/utils/use-initial.js.map +1 -1
  497. package/dist/utils/{use-interval.mjs → use-interval.cjs} +8 -6
  498. package/dist/utils/use-interval.cjs.map +1 -0
  499. package/dist/utils/use-interval.js +5 -7
  500. package/dist/utils/use-interval.js.map +1 -1
  501. package/dist/utils/use-latest.cjs +14 -0
  502. package/dist/utils/{use-latest.mjs.map → use-latest.cjs.map} +1 -1
  503. package/dist/utils/use-latest.js +4 -6
  504. package/dist/utils/use-latest.js.map +1 -1
  505. package/dist/utils/use-observable.cjs +15 -0
  506. package/dist/utils/{use-observable.mjs.map → use-observable.cjs.map} +1 -1
  507. package/dist/utils/use-observable.js +5 -7
  508. package/dist/utils/use-observable.js.map +1 -1
  509. package/dist/utils/{use-refs.mjs → use-refs.cjs} +6 -4
  510. package/dist/utils/{use-refs.mjs.map → use-refs.cjs.map} +1 -1
  511. package/dist/utils/use-refs.js +3 -5
  512. package/dist/utils/use-refs.js.map +1 -1
  513. package/dist/utils/use-rerender.cjs +14 -0
  514. package/dist/utils/{use-rerender.mjs.map → use-rerender.cjs.map} +1 -1
  515. package/dist/utils/use-rerender.js +3 -5
  516. package/dist/utils/use-rerender.js.map +1 -1
  517. package/dist/utils/{use-visible.mjs → use-visible.cjs} +11 -8
  518. package/dist/utils/{use-visible.mjs.map → use-visible.cjs.map} +1 -1
  519. package/dist/utils/use-visible.js +7 -10
  520. package/dist/utils/use-visible.js.map +1 -1
  521. package/dist/utils/{use-window-focus.mjs → use-window-focus.cjs} +6 -4
  522. package/dist/utils/use-window-focus.cjs.map +1 -0
  523. package/dist/utils/use-window-focus.js +3 -5
  524. package/dist/utils/use-window-focus.js.map +1 -1
  525. package/dist/utils/{visually-hidden.mjs → visually-hidden.cjs} +4 -2
  526. package/dist/utils/visually-hidden.cjs.map +1 -0
  527. package/dist/utils/visually-hidden.js +1 -3
  528. package/dist/utils/visually-hidden.js.map +1 -1
  529. package/dist/utils/{wrap.mjs → wrap.cjs} +4 -2
  530. package/dist/utils/wrap.cjs.map +1 -0
  531. package/dist/utils/wrap.js +1 -3
  532. package/dist/utils/wrap.js.map +1 -1
  533. package/dist/version.cjs +10 -0
  534. package/dist/{version.mjs.map → version.cjs.map} +1 -1
  535. package/dist/version.js +3 -7
  536. package/dist/version.js.map +1 -1
  537. package/package.json +28 -27
  538. package/styles/dark/attributes.css.d.cts +1 -0
  539. package/styles/dark/media-query.css.d.cts +1 -0
  540. package/styles.css.d.cts +1 -0
  541. package/dist/_private/index.mjs +0 -55
  542. package/dist/_private/index.mjs.map +0 -1
  543. package/dist/components/HistoryVersionSummary.mjs +0 -43
  544. package/dist/components/HistoryVersionSummaryList.mjs +0 -23
  545. package/dist/components/InboxNotificationList.mjs +0 -40
  546. package/dist/components/internal/Avatar.mjs +0 -46
  547. package/dist/components/internal/Button.mjs +0 -76
  548. package/dist/components/internal/Dropdown.mjs +0 -67
  549. package/dist/components/internal/Emoji.mjs +0 -17
  550. package/dist/components/internal/EmojiPicker.mjs +0 -184
  551. package/dist/components/internal/List.mjs +0 -34
  552. package/dist/components/internal/Room.mjs +0 -22
  553. package/dist/components/internal/Tooltip.mjs +0 -109
  554. package/dist/components/internal/User.mjs +0 -26
  555. package/dist/components.mjs +0 -43
  556. package/dist/config.mjs +0 -36
  557. package/dist/icon.mjs +0 -33
  558. package/dist/icon.mjs.map +0 -1
  559. package/dist/icons/ArrowCornerDownRight.mjs +0 -14
  560. package/dist/icons/ArrowCornerUpRight.mjs +0 -14
  561. package/dist/icons/ArrowCornerUpRight.mjs.map +0 -1
  562. package/dist/icons/ArrowDown.mjs +0 -14
  563. package/dist/icons/ArrowDown.mjs.map +0 -1
  564. package/dist/icons/ArrowUp.mjs +0 -14
  565. package/dist/icons/ArrowUp.mjs.map +0 -1
  566. package/dist/icons/Blockquote.mjs +0 -14
  567. package/dist/icons/Blockquote.mjs.map +0 -1
  568. package/dist/icons/Bold.mjs +0 -14
  569. package/dist/icons/Check.mjs +0 -14
  570. package/dist/icons/Check.mjs.map +0 -1
  571. package/dist/icons/ChevronDown.mjs +0 -14
  572. package/dist/icons/ChevronLeft.mjs +0 -14
  573. package/dist/icons/ChevronRight.mjs +0 -14
  574. package/dist/icons/ChevronUp.mjs +0 -14
  575. package/dist/icons/Code.mjs +0 -14
  576. package/dist/icons/Code.mjs.map +0 -1
  577. package/dist/icons/Comment.mjs +0 -14
  578. package/dist/icons/Cross.mjs +0 -19
  579. package/dist/icons/Cross.mjs.map +0 -1
  580. package/dist/icons/Delete.mjs +0 -14
  581. package/dist/icons/Edit.mjs +0 -14
  582. package/dist/icons/Ellipsis.mjs +0 -29
  583. package/dist/icons/Ellipsis.mjs.map +0 -1
  584. package/dist/icons/Emoji.mjs +0 -32
  585. package/dist/icons/Emoji.mjs.map +0 -1
  586. package/dist/icons/EmojiAdd.mjs +0 -35
  587. package/dist/icons/EmojiAdd.mjs.map +0 -1
  588. package/dist/icons/H1.mjs +0 -14
  589. package/dist/icons/H2.mjs +0 -14
  590. package/dist/icons/H2.mjs.map +0 -1
  591. package/dist/icons/H3.mjs +0 -14
  592. package/dist/icons/Italic.mjs +0 -14
  593. package/dist/icons/Lengthen.mjs +0 -14
  594. package/dist/icons/Lengthen.mjs.map +0 -1
  595. package/dist/icons/ListOrdered.mjs +0 -14
  596. package/dist/icons/ListUnordered.mjs +0 -37
  597. package/dist/icons/ListUnordered.mjs.map +0 -1
  598. package/dist/icons/Mention.mjs +0 -19
  599. package/dist/icons/Mention.mjs.map +0 -1
  600. package/dist/icons/QuestionMark.mjs +0 -24
  601. package/dist/icons/QuestionMark.mjs.map +0 -1
  602. package/dist/icons/Redo.mjs +0 -19
  603. package/dist/icons/Redo.mjs.map +0 -1
  604. package/dist/icons/Resolve.mjs +0 -21
  605. package/dist/icons/Resolve.mjs.map +0 -1
  606. package/dist/icons/Resolved.mjs +0 -23
  607. package/dist/icons/Resolved.mjs.map +0 -1
  608. package/dist/icons/Restore.mjs +0 -19
  609. package/dist/icons/Restore.mjs.map +0 -1
  610. package/dist/icons/Search.mjs +0 -14
  611. package/dist/icons/Send.mjs +0 -14
  612. package/dist/icons/Send.mjs.map +0 -1
  613. package/dist/icons/Shorten.mjs +0 -14
  614. package/dist/icons/SparklesText.mjs +0 -19
  615. package/dist/icons/Spinner.mjs +0 -15
  616. package/dist/icons/Spinner.mjs.map +0 -1
  617. package/dist/icons/Strikethrough.mjs +0 -14
  618. package/dist/icons/Text.mjs +0 -14
  619. package/dist/icons/Translate.mjs +0 -19
  620. package/dist/icons/Underline.mjs +0 -14
  621. package/dist/icons/Underline.mjs.map +0 -1
  622. package/dist/icons/Undo.mjs +0 -19
  623. package/dist/icons/Undo.mjs.map +0 -1
  624. package/dist/icons/Warning.mjs +0 -21
  625. package/dist/icons/Warning.mjs.map +0 -1
  626. package/dist/icons/index.mjs +0 -46
  627. package/dist/icons/index.mjs.map +0 -1
  628. package/dist/index.mjs +0 -16
  629. package/dist/primitives/Composer/contexts.mjs +0 -48
  630. package/dist/primitives/EmojiPicker/contexts.mjs +0 -16
  631. package/dist/primitives/FileSize.mjs +0 -34
  632. package/dist/primitives/index.mjs +0 -11
  633. package/dist/primitives/index.mjs.map +0 -1
  634. package/dist/primitives/internal/Emoji.mjs +0 -30
  635. package/dist/shared.mjs +0 -11
  636. package/dist/slate/plugins/empty-clear-formatting.mjs +0 -16
  637. package/dist/slate/plugins/mentions.mjs +0 -122
  638. package/dist/slate/plugins/normalize.mjs +0 -26
  639. package/dist/slate/plugins/normalize.mjs.map +0 -1
  640. package/dist/slate/utils/get-character.mjs +0 -47
  641. package/dist/slate/utils/get-dom-range.mjs +0 -15
  642. package/dist/slate/utils/is-empty-string.mjs +0 -6
  643. package/dist/slate/utils/is-empty-string.mjs.map +0 -1
  644. package/dist/slate/utils/is-empty.mjs +0 -25
  645. package/dist/slate/utils/marks.mjs +0 -55
  646. package/dist/slate/utils/selection-contains-inlines.mjs +0 -34
  647. package/dist/slate/utils/selection-contains-inlines.mjs.map +0 -1
  648. package/dist/utils/Portal.mjs +0 -27
  649. package/dist/utils/capitalize.mjs.map +0 -1
  650. package/dist/utils/clamp.mjs.map +0 -1
  651. package/dist/utils/download.mjs.map +0 -1
  652. package/dist/utils/exists.mjs +0 -6
  653. package/dist/utils/exists.mjs.map +0 -1
  654. package/dist/utils/find-last-index.mjs.map +0 -1
  655. package/dist/utils/format-file-size.mjs.map +0 -1
  656. package/dist/utils/get-initials.mjs.map +0 -1
  657. package/dist/utils/intl.mjs +0 -25
  658. package/dist/utils/is-apple.mjs.map +0 -1
  659. package/dist/utils/memoize.mjs.map +0 -1
  660. package/dist/utils/pluralize.mjs.map +0 -1
  661. package/dist/utils/request-submit.mjs.map +0 -1
  662. package/dist/utils/url.mjs.map +0 -1
  663. package/dist/utils/use-index.mjs +0 -30
  664. package/dist/utils/use-initial.mjs +0 -9
  665. package/dist/utils/use-interval.mjs.map +0 -1
  666. package/dist/utils/use-latest.mjs +0 -12
  667. package/dist/utils/use-observable.mjs +0 -13
  668. package/dist/utils/use-rerender.mjs +0 -12
  669. package/dist/utils/use-window-focus.mjs.map +0 -1
  670. package/dist/utils/visually-hidden.mjs.map +0 -1
  671. package/dist/utils/wrap.mjs.map +0 -1
  672. package/dist/version.mjs +0 -6
  673. /package/dist/_private/{index.d.mts → index.d.cts} +0 -0
  674. /package/dist/{index.d.mts → index.d.cts} +0 -0
  675. /package/dist/primitives/{index.d.mts → index.d.cts} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../src/primitives/Composer/index.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n type CommentAttachment,\n type CommentBody,\n type CommentLocalAttachment,\n createCommentAttachmentId,\n type EventSource,\n makeEventSource,\n} from \"@liveblocks/core\";\nimport {\n useClientOrNull,\n useLayoutEffect,\n useMentionSuggestions,\n useResolveMentionSuggestions,\n useRoomOrNull,\n useSyncSource,\n} from \"@liveblocks/react/_private\";\nimport { Slot, Slottable } from \"@radix-ui/react-slot\";\nimport * as TogglePrimitive from \"@radix-ui/react-toggle\";\nimport type {\n AriaAttributes,\n ChangeEvent,\n FocusEvent,\n FormEvent,\n KeyboardEvent,\n MouseEvent,\n PointerEvent,\n SyntheticEvent,\n} from \"react\";\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport type {\n Descendant as SlateDescendant,\n Element as SlateElement,\n} from \"slate\";\nimport {\n createEditor,\n Editor as SlateEditor,\n insertText as insertSlateText,\n Range as SlateRange,\n Transforms as SlateTransforms,\n} from \"slate\";\nimport { withHistory } from \"slate-history\";\nimport type {\n RenderElementProps,\n RenderElementSpecificProps,\n RenderLeafProps,\n RenderPlaceholderProps,\n} from \"slate-react\";\nimport {\n Editable,\n ReactEditor,\n Slate,\n useSelected,\n useSlateStatic,\n withReact,\n} from \"slate-react\";\n\nimport { useLiveblocksUIConfig } from \"../../config\";\nimport { withAutoFormatting } from \"../../slate/plugins/auto-formatting\";\nimport { withAutoLinks } from \"../../slate/plugins/auto-links\";\nimport { withCustomLinks } from \"../../slate/plugins/custom-links\";\nimport { withEmptyClearFormatting } from \"../../slate/plugins/empty-clear-formatting\";\nimport type { MentionDraft } from \"../../slate/plugins/mentions\";\nimport {\n getMentionDraftAtSelection,\n insertMention,\n insertMentionCharacter,\n MENTION_CHARACTER,\n withMentions,\n} from \"../../slate/plugins/mentions\";\nimport { withNormalize } from \"../../slate/plugins/normalize\";\nimport { withPaste } from \"../../slate/plugins/paste\";\nimport { getDOMRange } from \"../../slate/utils/get-dom-range\";\nimport { isEmpty as isEditorEmpty } from \"../../slate/utils/is-empty\";\nimport {\n getMarks,\n leaveMarkEdge,\n toggleMark as toggleEditorMark,\n} from \"../../slate/utils/marks\";\nimport type {\n ComposerBody as ComposerBodyData,\n ComposerBodyAutoLink,\n ComposerBodyCustomLink,\n ComposerBodyMark,\n ComposerBodyMarks,\n ComposerBodyMention,\n} from \"../../types\";\nimport { isKey } from \"../../utils/is-key\";\nimport { Persist, useAnimationPersist, usePersist } from \"../../utils/Persist\";\nimport { Portal } from \"../../utils/Portal\";\nimport { requestSubmit } from \"../../utils/request-submit\";\nimport { useIndex } from \"../../utils/use-index\";\nimport { useInitial } from \"../../utils/use-initial\";\nimport { useObservable } from \"../../utils/use-observable\";\nimport { useRefs } from \"../../utils/use-refs\";\nimport { toAbsoluteUrl } from \"../Comment/utils\";\nimport {\n ComposerAttachmentsContext,\n ComposerContext,\n ComposerEditorContext,\n ComposerFloatingToolbarContext,\n ComposerSuggestionsContext,\n useComposer,\n useComposerAttachmentsContext,\n useComposerEditorContext,\n useComposerFloatingToolbarContext,\n useComposerSuggestionsContext,\n} from \"./contexts\";\nimport type {\n ComposerAttachFilesProps,\n ComposerAttachmentsDropAreaProps,\n ComposerEditorComponents,\n ComposerEditorElementProps,\n ComposerEditorFloatingToolbarWrapperProps,\n ComposerEditorLinkWrapperProps,\n ComposerEditorMentionSuggestionsWrapperProps,\n ComposerEditorMentionWrapperProps,\n ComposerEditorProps,\n ComposerFloatingToolbarProps,\n ComposerFormProps,\n ComposerLinkProps,\n ComposerMarkToggleProps,\n ComposerMentionProps,\n ComposerSubmitProps,\n ComposerSuggestionsListItemProps,\n ComposerSuggestionsListProps,\n ComposerSuggestionsProps,\n FloatingPosition,\n} from \"./types\";\nimport {\n commentBodyToComposerBody,\n composerBodyToCommentBody,\n getSideAndAlignFromFloatingPlacement,\n useComposerAttachmentsDropArea,\n useComposerAttachmentsManager,\n useContentZIndex,\n useFloatingWithOptions,\n} from \"./utils\";\n\nconst MENTION_SUGGESTIONS_POSITION: FloatingPosition = \"top\";\n\nconst FLOATING_TOOLBAR_POSITION: FloatingPosition = \"top\";\n\nconst COMPOSER_MENTION_NAME = \"ComposerMention\";\nconst COMPOSER_LINK_NAME = \"ComposerLink\";\nconst COMPOSER_FLOATING_TOOLBAR_NAME = \"ComposerFloatingToolbar\";\nconst COMPOSER_SUGGESTIONS_NAME = \"ComposerSuggestions\";\nconst COMPOSER_SUGGESTIONS_LIST_NAME = \"ComposerSuggestionsList\";\nconst COMPOSER_SUGGESTIONS_LIST_ITEM_NAME = \"ComposerSuggestionsListItem\";\nconst COMPOSER_SUBMIT_NAME = \"ComposerSubmit\";\nconst COMPOSER_EDITOR_NAME = \"ComposerEditor\";\nconst COMPOSER_ATTACH_FILES_NAME = \"ComposerAttachFiles\";\nconst COMPOSER_ATTACHMENTS_DROP_AREA_NAME = \"ComposerAttachmentsDropArea\";\nconst COMPOSER_MARK_TOGGLE_NAME = \"ComposerMarkToggle\";\nconst COMPOSER_FORM_NAME = \"ComposerForm\";\n\nconst emptyCommentBody: CommentBody = {\n version: 1,\n content: [{ type: \"paragraph\", children: [{ text: \"\" }] }],\n};\n\nfunction createComposerEditor({\n createAttachments,\n pasteFilesAsAttachments,\n}: {\n createAttachments: (files: File[]) => void;\n pasteFilesAsAttachments?: boolean;\n}) {\n return withNormalize(\n withMentions(\n withCustomLinks(\n withAutoLinks(\n withAutoFormatting(\n withEmptyClearFormatting(\n withPaste(withHistory(withReact(createEditor())), {\n createAttachments,\n pasteFilesAsAttachments,\n })\n )\n )\n )\n )\n )\n );\n}\n\nfunction ComposerEditorMentionWrapper({\n Mention,\n attributes,\n children,\n element,\n}: ComposerEditorMentionWrapperProps) {\n const isSelected = useSelected();\n\n return (\n <span {...attributes}>\n {element.id ? (\n <Mention userId={element.id} isSelected={isSelected} />\n ) : null}\n {children}\n </span>\n );\n}\n\nfunction ComposerEditorLinkWrapper({\n Link,\n attributes,\n element,\n children,\n}: ComposerEditorLinkWrapperProps) {\n const href = useMemo(\n () => toAbsoluteUrl(element.url) ?? element.url,\n [element.url]\n );\n\n return (\n <span {...attributes}>\n <Link href={href}>{children}</Link>\n </span>\n );\n}\n\nfunction ComposerEditorMentionSuggestionsWrapper({\n id,\n itemId,\n userIds,\n selectedUserId,\n setSelectedUserId,\n mentionDraft,\n setMentionDraft,\n onItemSelect,\n position = MENTION_SUGGESTIONS_POSITION,\n dir,\n MentionSuggestions,\n}: ComposerEditorMentionSuggestionsWrapperProps) {\n const editor = useSlateStatic();\n const { onEditorChange } = useComposerEditorContext();\n const { isFocused } = useComposer();\n const { portalContainer } = useLiveblocksUIConfig();\n const [contentRef, contentZIndex] = useContentZIndex();\n const isOpen =\n isFocused && mentionDraft?.range !== undefined && userIds !== undefined;\n const {\n refs: { setReference, setFloating },\n strategy,\n isPositioned,\n placement,\n x,\n y,\n } = useFloatingWithOptions({\n position,\n dir,\n alignment: \"start\",\n open: isOpen,\n });\n\n useObservable(onEditorChange, () => {\n setMentionDraft(getMentionDraftAtSelection(editor));\n });\n\n useLayoutEffect(() => {\n if (!mentionDraft) {\n setReference(null);\n\n return;\n }\n\n const domRange = getDOMRange(editor, mentionDraft.range);\n setReference(domRange ?? null);\n }, [setReference, editor, mentionDraft]);\n\n return (\n <Persist>\n {isOpen ? (\n <ComposerSuggestionsContext.Provider\n value={{\n id,\n itemId,\n selectedValue: selectedUserId,\n setSelectedValue: setSelectedUserId,\n onItemSelect,\n placement,\n dir,\n ref: contentRef,\n }}\n >\n <Portal\n ref={setFloating}\n container={portalContainer}\n style={{\n position: strategy,\n top: 0,\n left: 0,\n transform: isPositioned\n ? `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`\n : \"translate3d(0, -200%, 0)\",\n minWidth: \"max-content\",\n zIndex: contentZIndex,\n }}\n >\n <MentionSuggestions\n userIds={userIds}\n selectedUserId={selectedUserId}\n />\n </Portal>\n </ComposerSuggestionsContext.Provider>\n ) : null}\n </Persist>\n );\n}\n\nfunction ComposerEditorFloatingToolbarWrapper({\n id,\n position = FLOATING_TOOLBAR_POSITION,\n dir,\n FloatingToolbar,\n hasFloatingToolbarRange,\n setHasFloatingToolbarRange,\n}: ComposerEditorFloatingToolbarWrapperProps) {\n const editor = useSlateStatic();\n const { onEditorChange } = useComposerEditorContext();\n const { isFocused } = useComposer();\n const { portalContainer } = useLiveblocksUIConfig();\n const [contentRef, contentZIndex] = useContentZIndex();\n const [isPointerDown, setPointerDown] = useState(false);\n const isOpen = isFocused && !isPointerDown && hasFloatingToolbarRange;\n const {\n refs: { setReference, setFloating },\n strategy,\n isPositioned,\n placement,\n x,\n y,\n } = useFloatingWithOptions({\n type: \"range\",\n position,\n dir,\n alignment: \"center\",\n open: isOpen,\n });\n\n useLayoutEffect(() => {\n if (!isFocused) {\n return;\n }\n\n const handlePointerDown = () => setPointerDown(true);\n const handlePointerUp = () => setPointerDown(false);\n\n document.addEventListener(\"pointerdown\", handlePointerDown);\n document.addEventListener(\"pointerup\", handlePointerUp);\n\n return () => {\n document.removeEventListener(\"pointerdown\", handlePointerDown);\n document.removeEventListener(\"pointerup\", handlePointerUp);\n };\n }, [isFocused]);\n\n useObservable(onEditorChange, () => {\n // Detach from previous selection range (if any) to avoid sudden jumps\n setReference(null);\n\n // Then, wait for the next render to ensure the selection is updated\n requestAnimationFrame(() => {\n const domSelection = window.getSelection();\n\n // Finally, show the toolbar if there's a selection range\n if (\n !editor.selection ||\n SlateRange.isCollapsed(editor.selection) ||\n !domSelection ||\n !domSelection.rangeCount\n ) {\n setHasFloatingToolbarRange(false);\n setReference(null);\n } else {\n setHasFloatingToolbarRange(true);\n\n const domRange = domSelection.getRangeAt(0);\n setReference(domRange);\n }\n });\n });\n\n return (\n <Persist>\n {isOpen ? (\n <ComposerFloatingToolbarContext.Provider\n value={{\n id,\n placement,\n dir,\n ref: contentRef,\n }}\n >\n <Portal\n ref={setFloating}\n container={portalContainer}\n style={{\n position: strategy,\n top: 0,\n left: 0,\n transform: isPositioned\n ? `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`\n : \"translate3d(0, -200%, 0)\",\n minWidth: \"max-content\",\n zIndex: contentZIndex,\n }}\n >\n <FloatingToolbar />\n </Portal>\n </ComposerFloatingToolbarContext.Provider>\n ) : null}\n </Persist>\n );\n}\n\n/**\n * Displays a floating toolbar attached to the selection within `Composer.Editor`.\n *\n * @example\n * <Composer.FloatingToolbar>\n * <Composer.MarkToggle mark=\"bold\">Bold</Composer.MarkToggle>\n * <Composer.MarkToggle mark=\"italic\">Italic</Composer.MarkToggle>\n * </Composer.FloatingToolbar>\n */\nconst ComposerFloatingToolbar = forwardRef<\n HTMLDivElement,\n ComposerFloatingToolbarProps\n>(({ children, onPointerDown, style, asChild, ...props }, forwardedRef) => {\n const [isPresent] = usePersist();\n const ref = useRef<HTMLDivElement>(null);\n const {\n id,\n ref: contentRef,\n placement,\n dir,\n } = useComposerFloatingToolbarContext(COMPOSER_FLOATING_TOOLBAR_NAME);\n const mergedRefs = useRefs(forwardedRef, contentRef, ref);\n const [side, align] = useMemo(\n () => getSideAndAlignFromFloatingPlacement(placement),\n [placement]\n );\n const Component = asChild ? Slot : \"div\";\n useAnimationPersist(ref);\n\n const handlePointerDown = useCallback(\n (event: PointerEvent<HTMLDivElement>) => {\n onPointerDown?.(event);\n\n event.preventDefault();\n event.stopPropagation();\n },\n [onPointerDown]\n );\n\n return (\n <Component\n dir={dir}\n role=\"toolbar\"\n id={id}\n aria-label=\"Floating toolbar\"\n {...props}\n onPointerDown={handlePointerDown}\n data-state={isPresent ? \"open\" : \"closed\"}\n data-side={side}\n data-align={align}\n style={{\n display: \"flex\",\n flexDirection: \"row\",\n maxWidth: \"var(--lb-composer-floating-available-width)\",\n overflowX: \"auto\",\n ...style,\n }}\n ref={mergedRefs}\n >\n {children}\n </Component>\n );\n});\n\nfunction ComposerEditorElement({\n Mention,\n Link,\n ...props\n}: ComposerEditorElementProps) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const { attributes, children, element } = props;\n\n switch (element.type) {\n case \"mention\":\n return (\n <ComposerEditorMentionWrapper\n Mention={Mention}\n {...(props as RenderElementSpecificProps<ComposerBodyMention>)}\n />\n );\n case \"auto-link\":\n case \"custom-link\":\n return (\n <ComposerEditorLinkWrapper\n Link={Link}\n {...(props as RenderElementSpecificProps<\n ComposerBodyAutoLink | ComposerBodyCustomLink\n >)}\n />\n );\n case \"paragraph\":\n return (\n <p {...attributes} style={{ position: \"relative\" }}>\n {children}\n </p>\n );\n default:\n return null;\n }\n}\n\n// <code><s><em><strong>text</strong></s></em></code>\nfunction ComposerEditorLeaf({ attributes, children, leaf }: RenderLeafProps) {\n if (leaf.bold) {\n children = <strong>{children}</strong>;\n }\n\n if (leaf.italic) {\n children = <em>{children}</em>;\n }\n\n if (leaf.strikethrough) {\n children = <s>{children}</s>;\n }\n\n if (leaf.code) {\n children = <code>{children}</code>;\n }\n\n return <span {...attributes}>{children}</span>;\n}\n\nfunction ComposerEditorPlaceholder({\n attributes,\n children,\n}: RenderPlaceholderProps) {\n const { opacity: _opacity, ...style } = attributes.style;\n\n return (\n <span {...attributes} style={style} data-placeholder=\"\">\n {children}\n </span>\n );\n}\n\n/**\n * Displays mentions within `Composer.Editor`.\n *\n * @example\n * <Composer.Mention>@{userId}</Composer.Mention>\n */\nconst ComposerMention = forwardRef<HTMLSpanElement, ComposerMentionProps>(\n ({ children, asChild, ...props }, forwardedRef) => {\n const Component = asChild ? Slot : \"span\";\n const isSelected = useSelected();\n\n return (\n <Component\n data-selected={isSelected || undefined}\n {...props}\n ref={forwardedRef}\n >\n {children}\n </Component>\n );\n }\n);\n\n/**\n * Displays links within `Composer.Editor`.\n *\n * @example\n * <Composer.Link href={href}>{children}</Composer.Link>\n */\nconst ComposerLink = forwardRef<HTMLAnchorElement, ComposerLinkProps>(\n ({ children, asChild, ...props }, forwardedRef) => {\n const Component = asChild ? Slot : \"a\";\n\n return (\n <Component\n target=\"_blank\"\n rel=\"noopener noreferrer nofollow\"\n {...props}\n ref={forwardedRef}\n >\n {children}\n </Component>\n );\n }\n);\n\n/**\n * Contains suggestions within `Composer.Editor`.\n */\nconst ComposerSuggestions = forwardRef<\n HTMLDivElement,\n ComposerSuggestionsProps\n>(({ children, style, asChild, ...props }, forwardedRef) => {\n const [isPresent] = usePersist();\n const ref = useRef<HTMLDivElement>(null);\n const {\n ref: contentRef,\n placement,\n dir,\n } = useComposerSuggestionsContext(COMPOSER_SUGGESTIONS_NAME);\n const mergedRefs = useRefs(forwardedRef, contentRef, ref);\n const [side, align] = useMemo(\n () => getSideAndAlignFromFloatingPlacement(placement),\n [placement]\n );\n const Component = asChild ? Slot : \"div\";\n useAnimationPersist(ref);\n\n return (\n <Component\n dir={dir}\n {...props}\n data-state={isPresent ? \"open\" : \"closed\"}\n data-side={side}\n data-align={align}\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n maxHeight: \"var(--lb-composer-floating-available-height)\",\n overflowY: \"auto\",\n ...style,\n }}\n ref={mergedRefs}\n >\n {children}\n </Component>\n );\n});\n\n/**\n * Displays a list of suggestions within `Composer.Editor`.\n *\n * @example\n * <Composer.SuggestionsList>\n * {userIds.map((userId) => (\n * <Composer.SuggestionsListItem key={userId} value={userId}>\n * @{userId}\n * </Composer.SuggestionsListItem>\n * ))}\n * </Composer.SuggestionsList>\n */\nconst ComposerSuggestionsList = forwardRef<\n HTMLUListElement,\n ComposerSuggestionsListProps\n>(({ children, asChild, ...props }, forwardedRef) => {\n const { id } = useComposerSuggestionsContext(COMPOSER_SUGGESTIONS_LIST_NAME);\n const Component = asChild ? Slot : \"ul\";\n\n return (\n <Component\n role=\"listbox\"\n id={id}\n aria-label=\"Suggestions list\"\n {...props}\n ref={forwardedRef}\n >\n {children}\n </Component>\n );\n});\n\n/**\n * Displays a suggestion within `Composer.SuggestionsList`.\n *\n * @example\n * <Composer.SuggestionsListItem key={userId} value={userId}>\n * @{userId}\n * </Composer.SuggestionsListItem>\n */\nconst ComposerSuggestionsListItem = forwardRef<\n HTMLLIElement,\n ComposerSuggestionsListItemProps\n>(\n (\n {\n value,\n children,\n onPointerMove,\n onPointerDown,\n onClick,\n asChild,\n ...props\n },\n forwardedRef\n ) => {\n const ref = useRef<HTMLLIElement>(null);\n const mergedRefs = useRefs(forwardedRef, ref);\n const { selectedValue, setSelectedValue, itemId, onItemSelect } =\n useComposerSuggestionsContext(COMPOSER_SUGGESTIONS_LIST_ITEM_NAME);\n const Component = asChild ? Slot : \"li\";\n const isSelected = useMemo(\n () => selectedValue === value,\n [selectedValue, value]\n );\n // TODO: Support props.id if provided, it will need to be sent up to Composer.Editor to use it in aria-activedescendant\n const id = useMemo(() => itemId(value), [itemId, value]);\n\n useEffect(() => {\n if (ref?.current && isSelected) {\n ref.current.scrollIntoView({ block: \"nearest\" });\n }\n }, [isSelected]);\n\n const handlePointerMove = useCallback(\n (event: PointerEvent<HTMLLIElement>) => {\n onPointerMove?.(event);\n\n if (!event.isDefaultPrevented()) {\n setSelectedValue(value);\n }\n },\n [onPointerMove, setSelectedValue, value]\n );\n\n const handlePointerDown = useCallback(\n (event: PointerEvent<HTMLLIElement>) => {\n onPointerDown?.(event);\n\n event.preventDefault();\n event.stopPropagation();\n },\n [onPointerDown]\n );\n\n const handleClick = useCallback(\n (event: MouseEvent<HTMLLIElement>) => {\n onClick?.(event);\n\n const wasDefaultPrevented = event.isDefaultPrevented();\n\n event.preventDefault();\n event.stopPropagation();\n\n if (!wasDefaultPrevented) {\n onItemSelect(value);\n }\n },\n [onClick, onItemSelect, value]\n );\n\n return (\n <Component\n role=\"option\"\n id={id}\n data-selected={isSelected || undefined}\n aria-selected={isSelected || undefined}\n onPointerMove={handlePointerMove}\n onPointerDown={handlePointerDown}\n onClick={handleClick}\n {...props}\n ref={mergedRefs}\n >\n {children}\n </Component>\n );\n }\n);\n\nconst defaultEditorComponents: ComposerEditorComponents = {\n Link: ({ href, children }) => {\n return <ComposerLink href={href}>{children}</ComposerLink>;\n },\n Mention: ({ userId }) => {\n return (\n <ComposerMention>\n {MENTION_CHARACTER}\n {userId}\n </ComposerMention>\n );\n },\n MentionSuggestions: ({ userIds }) => {\n return userIds.length > 0 ? (\n <ComposerSuggestions>\n <ComposerSuggestionsList>\n {userIds.map((userId) => (\n <ComposerSuggestionsListItem key={userId} value={userId}>\n {userId}\n </ComposerSuggestionsListItem>\n ))}\n </ComposerSuggestionsList>\n </ComposerSuggestions>\n ) : null;\n },\n};\n\n/**\n * Displays the composer's editor.\n *\n * @example\n * <Composer.Editor placeholder=\"Write a comment…\" />\n */\nconst ComposerEditor = forwardRef<HTMLDivElement, ComposerEditorProps>(\n (\n {\n defaultValue,\n onKeyDown,\n onFocus,\n onBlur,\n disabled,\n autoFocus,\n components,\n dir,\n ...props\n },\n forwardedRef\n ) => {\n const client = useClientOrNull();\n const { editor, validate, setFocused, onEditorChange, roomId } =\n useComposerEditorContext();\n const {\n submit,\n focus,\n blur,\n select,\n canSubmit,\n isDisabled: isComposerDisabled,\n isFocused,\n } = useComposer();\n const isDisabled = isComposerDisabled || disabled;\n const initialBody = useInitial(defaultValue ?? emptyCommentBody);\n const initialEditorValue = useMemo(() => {\n return commentBodyToComposerBody(initialBody);\n }, [initialBody]);\n const { Link, Mention, MentionSuggestions, FloatingToolbar } = useMemo(\n () => ({ ...defaultEditorComponents, ...components }),\n [components]\n );\n\n const [hasFloatingToolbarRange, setHasFloatingToolbarRange] =\n useState(false);\n // If used with LiveblocksProvider but without resolveMentionSuggestions,\n // we can skip the mention suggestions logic entirely\n const resolveMentionSuggestions = useResolveMentionSuggestions();\n const hasResolveMentionSuggestions = client\n ? resolveMentionSuggestions\n : true;\n const [mentionDraft, setMentionDraft] = useState<MentionDraft>();\n const mentionSuggestions = useMentionSuggestions(\n roomId,\n mentionDraft?.text\n );\n const [\n selectedMentionSuggestionIndex,\n setPreviousSelectedMentionSuggestionIndex,\n setNextSelectedMentionSuggestionIndex,\n setSelectedMentionSuggestionIndex,\n ] = useIndex(0, mentionSuggestions?.length ?? 0);\n const id = useId();\n const floatingToolbarId = `liveblocks-floating-toolbar-${id}`;\n const suggestionsListId = `liveblocks-suggestions-list-${id}`;\n const suggestionsListItemId = useCallback(\n (userId?: string) =>\n userId ? `liveblocks-suggestions-list-item-${id}-${userId}` : undefined,\n [id]\n );\n\n const renderElement = useCallback(\n (props: RenderElementProps) => {\n return (\n <ComposerEditorElement Mention={Mention} Link={Link} {...props} />\n );\n },\n [Link, Mention]\n );\n\n const handleChange = useCallback(\n (value: SlateDescendant[]) => {\n validate(value as SlateElement[]);\n\n // Our multi-component setup requires us to instantiate the editor in `Composer.Form`\n // but we can only listen to changes here in `Composer.Editor` via `Slate`, so we use\n // an event source to notify `Composer.Form` of changes.\n onEditorChange.notify();\n },\n [validate, onEditorChange]\n );\n\n const createMention = useCallback(\n (userId?: string) => {\n if (!mentionDraft || !userId) {\n return;\n }\n\n SlateTransforms.select(editor, mentionDraft.range);\n insertMention(editor, userId);\n setMentionDraft(undefined);\n setSelectedMentionSuggestionIndex(0);\n },\n [editor, mentionDraft, setSelectedMentionSuggestionIndex]\n );\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\n // Allow leaving marks with ArrowLeft\n if (isKey(event, \"ArrowLeft\")) {\n leaveMarkEdge(editor, \"start\");\n }\n\n // Allow leaving marks with ArrowRight\n if (isKey(event, \"ArrowRight\")) {\n leaveMarkEdge(editor, \"end\");\n }\n\n if (mentionDraft && mentionSuggestions?.length) {\n // Select the next mention suggestion on ArrowDown\n if (isKey(event, \"ArrowDown\")) {\n event.preventDefault();\n setNextSelectedMentionSuggestionIndex();\n }\n\n // Select the previous mention suggestion on ArrowUp\n if (isKey(event, \"ArrowUp\")) {\n event.preventDefault();\n setPreviousSelectedMentionSuggestionIndex();\n }\n\n // Create a mention on Enter/Tab\n if (isKey(event, \"Enter\") || isKey(event, \"Tab\")) {\n event.preventDefault();\n\n const userId = mentionSuggestions?.[selectedMentionSuggestionIndex];\n createMention(userId);\n }\n\n // Close the suggestions on Escape\n if (isKey(event, \"Escape\")) {\n event.preventDefault();\n setMentionDraft(undefined);\n setSelectedMentionSuggestionIndex(0);\n }\n } else {\n if (hasFloatingToolbarRange) {\n // Close the floating toolbar on Escape\n if (isKey(event, \"Escape\")) {\n event.preventDefault();\n setHasFloatingToolbarRange(false);\n }\n }\n\n // Blur the editor on Escape\n if (isKey(event, \"Escape\")) {\n blur();\n }\n\n // Submit the editor on Enter\n if (isKey(event, \"Enter\", { shift: false })) {\n // Even if submitting is not possible, don't do anything else on Enter. (e.g. creating a new line)\n event.preventDefault();\n\n if (canSubmit) {\n submit();\n }\n }\n\n // Create a new line on Shift + Enter\n if (isKey(event, \"Enter\", { shift: true })) {\n event.preventDefault();\n editor.insertBreak();\n }\n\n // Toggle bold on Command/Control + B\n if (isKey(event, \"b\", { mod: true })) {\n event.preventDefault();\n toggleEditorMark(editor, \"bold\");\n }\n\n // Toggle italic on Command/Control + I\n if (isKey(event, \"i\", { mod: true })) {\n event.preventDefault();\n toggleEditorMark(editor, \"italic\");\n }\n\n // Toggle strikethrough on Command/Control + Shift + S\n if (isKey(event, \"s\", { mod: true, shift: true })) {\n event.preventDefault();\n toggleEditorMark(editor, \"strikethrough\");\n }\n\n // Toggle code on Command/Control + E\n if (isKey(event, \"e\", { mod: true })) {\n event.preventDefault();\n toggleEditorMark(editor, \"code\");\n }\n }\n },\n [\n onKeyDown,\n mentionDraft,\n mentionSuggestions,\n hasFloatingToolbarRange,\n editor,\n setNextSelectedMentionSuggestionIndex,\n setPreviousSelectedMentionSuggestionIndex,\n selectedMentionSuggestionIndex,\n createMention,\n setSelectedMentionSuggestionIndex,\n blur,\n canSubmit,\n submit,\n ]\n );\n\n const handleFocus = useCallback(\n (event: FocusEvent<HTMLDivElement>) => {\n onFocus?.(event);\n\n if (!event.isDefaultPrevented()) {\n setFocused(true);\n }\n },\n [onFocus, setFocused]\n );\n\n const handleBlur = useCallback(\n (event: FocusEvent<HTMLDivElement>) => {\n onBlur?.(event);\n\n if (!event.isDefaultPrevented()) {\n setFocused(false);\n }\n },\n [onBlur, setFocused]\n );\n\n const selectedMentionSuggestionUserId = useMemo(\n () => mentionSuggestions?.[selectedMentionSuggestionIndex],\n [selectedMentionSuggestionIndex, mentionSuggestions]\n );\n const setSelectedMentionSuggestionUserId = useCallback(\n (userId: string) => {\n const index = mentionSuggestions?.indexOf(userId);\n\n if (index !== undefined && index >= 0) {\n setSelectedMentionSuggestionIndex(index);\n }\n },\n [setSelectedMentionSuggestionIndex, mentionSuggestions]\n );\n\n const additionalProps: AriaAttributes = useMemo(\n () =>\n mentionDraft\n ? {\n role: \"combobox\",\n \"aria-autocomplete\": \"list\",\n \"aria-expanded\": true,\n \"aria-controls\": suggestionsListId,\n \"aria-activedescendant\": suggestionsListItemId(\n selectedMentionSuggestionUserId\n ),\n }\n : hasFloatingToolbarRange\n ? {\n \"aria-haspopup\": true,\n \"aria-controls\": floatingToolbarId,\n }\n : {},\n [\n mentionDraft,\n suggestionsListId,\n suggestionsListItemId,\n selectedMentionSuggestionUserId,\n hasFloatingToolbarRange,\n floatingToolbarId,\n ]\n );\n\n useImperativeHandle(forwardedRef, () => {\n return ReactEditor.toDOMNode(editor, editor) as HTMLDivElement;\n }, [editor]);\n\n // Manually focus the editor when `autoFocus` is true\n useLayoutEffect(() => {\n if (autoFocus) {\n focus();\n }\n }, [autoFocus, editor, focus]);\n\n // Manually add a selection in the editor if the selection\n // is still empty after being focused\n useLayoutEffect(() => {\n if (isFocused && editor.selection === null) {\n select();\n }\n }, [editor, select, isFocused]);\n\n return (\n <Slate\n editor={editor}\n initialValue={initialEditorValue}\n onChange={handleChange}\n >\n <Editable\n dir={dir}\n enterKeyHint={mentionDraft ? \"enter\" : \"send\"}\n autoCapitalize=\"sentences\"\n aria-label=\"Composer editor\"\n data-focused={isFocused || undefined}\n data-disabled={isDisabled || undefined}\n {...additionalProps}\n {...props}\n readOnly={isDisabled}\n disabled={isDisabled}\n onKeyDown={handleKeyDown}\n onFocus={handleFocus}\n onBlur={handleBlur}\n renderElement={renderElement}\n renderLeaf={ComposerEditorLeaf}\n renderPlaceholder={ComposerEditorPlaceholder}\n />\n {hasResolveMentionSuggestions && (\n <ComposerEditorMentionSuggestionsWrapper\n dir={dir}\n mentionDraft={mentionDraft}\n setMentionDraft={setMentionDraft}\n selectedUserId={selectedMentionSuggestionUserId}\n setSelectedUserId={setSelectedMentionSuggestionUserId}\n userIds={mentionSuggestions}\n id={suggestionsListId}\n itemId={suggestionsListItemId}\n onItemSelect={createMention}\n MentionSuggestions={MentionSuggestions}\n />\n )}\n {FloatingToolbar && (\n <ComposerEditorFloatingToolbarWrapper\n dir={dir}\n id={floatingToolbarId}\n hasFloatingToolbarRange={hasFloatingToolbarRange}\n setHasFloatingToolbarRange={setHasFloatingToolbarRange}\n FloatingToolbar={FloatingToolbar}\n />\n )}\n </Slate>\n );\n }\n);\n\nconst MAX_ATTACHMENTS = 10;\nconst MAX_ATTACHMENT_SIZE = 1024 * 1024 * 1024; // 1 GB\n\nfunction prepareAttachment(file: File): CommentLocalAttachment {\n return {\n type: \"localAttachment\",\n status: \"idle\",\n id: createCommentAttachmentId(),\n name: file.name,\n size: file.size,\n mimeType: file.type,\n file,\n };\n}\n\n/**\n * Surrounds the composer's content and handles submissions.\n *\n * @example\n * <Composer.Form onComposerSubmit={({ body }) => {}}>\n *\t <Composer.Editor />\n * <Composer.Submit />\n * </Composer.Form>\n */\nconst ComposerForm = forwardRef<HTMLFormElement, ComposerFormProps>(\n (\n {\n children,\n onSubmit,\n onComposerSubmit,\n defaultAttachments = [],\n pasteFilesAsAttachments,\n preventUnsavedChanges = true,\n disabled,\n asChild,\n roomId: _roomId,\n ...props\n },\n forwardedRef\n ) => {\n const Component = asChild ? Slot : \"form\";\n const [isEmpty, setEmpty] = useState(true);\n const [isSubmitting, setSubmitting] = useState(false);\n const [isFocused, setFocused] = useState(false);\n const room = useRoomOrNull();\n\n const roomId = _roomId !== undefined ? _roomId : room?.id;\n if (roomId === undefined) {\n throw new Error(\"Composer.Form must be a descendant of RoomProvider.\");\n }\n\n // Later: Offer as Composer.Form props: { maxAttachments: number; maxAttachmentSize: number; supportedAttachmentMimeTypes: string[]; }\n const maxAttachments = MAX_ATTACHMENTS;\n const maxAttachmentSize = MAX_ATTACHMENT_SIZE;\n\n const {\n attachments,\n isUploadingAttachments,\n addAttachments,\n removeAttachment,\n clearAttachments,\n } = useComposerAttachmentsManager(defaultAttachments, {\n maxFileSize: maxAttachmentSize,\n roomId,\n });\n const numberOfAttachments = attachments.length;\n const hasMaxAttachments = numberOfAttachments >= maxAttachments;\n\n const isDisabled = useMemo(() => {\n return isSubmitting || disabled === true;\n }, [isSubmitting, disabled]);\n const canSubmit = useMemo(() => {\n return !isEmpty && !isUploadingAttachments;\n }, [isEmpty, isUploadingAttachments]);\n const [marks, setMarks] = useState<ComposerBodyMarks>(getMarks);\n\n const ref = useRef<HTMLFormElement>(null);\n const mergedRefs = useRefs(forwardedRef, ref);\n const fileInputRef = useRef<HTMLInputElement>(null);\n const syncSource = useSyncSource();\n\n // Mark the composer as a pending update when it has unsubmitted (draft)\n // text or attachments\n const isPending = !preventUnsavedChanges\n ? false\n : !isEmpty || isUploadingAttachments || attachments.length > 0;\n\n useEffect(() => {\n syncSource?.setSyncStatus(\n isPending ? \"has-local-changes\" : \"synchronized\"\n );\n }, [syncSource, isPending]);\n\n const createAttachments = useCallback(\n (files: File[]) => {\n if (!files.length) {\n return;\n }\n\n const numberOfAcceptedFiles = Math.max(\n 0,\n maxAttachments - numberOfAttachments\n );\n\n files.splice(numberOfAcceptedFiles);\n\n const attachments = files.map((file) => prepareAttachment(file));\n\n addAttachments(attachments);\n },\n [addAttachments, maxAttachments, numberOfAttachments]\n );\n\n const createAttachmentsRef = useRef(createAttachments);\n\n useEffect(() => {\n createAttachmentsRef.current = createAttachments;\n }, [createAttachments]);\n\n const stableCreateAttachments = useCallback((files: File[]) => {\n createAttachmentsRef.current(files);\n }, []);\n\n const editor = useInitial(() =>\n createComposerEditor({\n createAttachments: stableCreateAttachments,\n pasteFilesAsAttachments,\n })\n );\n const onEditorChange = useInitial(makeEventSource) as EventSource<void>;\n\n const validate = useCallback(\n (value: SlateElement[]) => {\n setEmpty(isEditorEmpty(editor, value));\n },\n [editor]\n );\n\n const submit = useCallback(() => {\n if (!canSubmit) {\n return;\n }\n\n // We need to wait for the next frame in some cases like when composing diacritics,\n // we want any native handling to be done first while still being handled on `keydown`.\n requestAnimationFrame(() => {\n if (ref.current) {\n requestSubmit(ref.current);\n }\n });\n }, [canSubmit]);\n\n const clear = useCallback(() => {\n SlateTransforms.delete(editor, {\n at: {\n anchor: SlateEditor.start(editor, []),\n focus: SlateEditor.end(editor, []),\n },\n });\n }, [editor]);\n\n const select = useCallback(() => {\n SlateTransforms.select(editor, SlateEditor.end(editor, []));\n }, [editor]);\n\n const focus = useCallback(\n (resetSelection = true) => {\n try {\n if (!ReactEditor.isFocused(editor)) {\n SlateTransforms.select(\n editor,\n resetSelection || !editor.selection\n ? SlateEditor.end(editor, [])\n : editor.selection\n );\n ReactEditor.focus(editor);\n }\n } catch {\n // Slate's DOM-specific methods will throw if the editor's DOM\n // node no longer exists. This action doesn't make sense on an\n // unmounted editor so we can safely ignore it.\n }\n },\n [editor]\n );\n\n const blur = useCallback(() => {\n try {\n ReactEditor.blur(editor);\n } catch {\n // Slate's DOM-specific methods will throw if the editor's DOM\n // node no longer exists. This action doesn't make sense on an\n // unmounted editor so we can safely ignore it.\n }\n }, [editor]);\n\n const createMention = useCallback(() => {\n if (disabled) {\n return;\n }\n\n focus();\n insertMentionCharacter(editor);\n }, [disabled, editor, focus]);\n\n const insertText = useCallback(\n (text: string) => {\n if (disabled) {\n return;\n }\n\n focus(false);\n insertSlateText(editor, text);\n },\n [disabled, editor, focus]\n );\n\n const attachFiles = useCallback(() => {\n if (disabled) {\n return;\n }\n\n if (fileInputRef.current) {\n fileInputRef.current.click();\n }\n }, [disabled]);\n\n const handleAttachmentsInputChange = useCallback(\n (event: ChangeEvent<HTMLInputElement>) => {\n if (disabled) {\n return;\n }\n\n if (event.target.files) {\n createAttachments(Array.from(event.target.files));\n\n // Reset the input value to allow selecting the same file(s) again\n event.target.value = \"\";\n }\n },\n [createAttachments, disabled]\n );\n\n const onSubmitEnd = useCallback(() => {\n clear();\n blur();\n clearAttachments();\n setSubmitting(false);\n }, [blur, clear, clearAttachments]);\n\n const handleSubmit = useCallback(\n (event: FormEvent<HTMLFormElement>) => {\n if (disabled) {\n return;\n }\n\n // In some situations (e.g. pressing Enter while composing diacritics), it's possible\n // for the form to be submitted as empty even though we already checked whether the\n // editor was empty when handling the key press.\n const isEmpty = isEditorEmpty(editor, editor.children);\n\n // We even prevent the user's `onSubmit` handler from being called if the editor is empty.\n if (isEmpty) {\n event.preventDefault();\n\n return;\n }\n\n onSubmit?.(event);\n\n if (!onComposerSubmit || event.isDefaultPrevented()) {\n event.preventDefault();\n\n return;\n }\n\n const body = composerBodyToCommentBody(\n editor.children as ComposerBodyData\n );\n // Only non-local attachments are included to be submitted.\n const commentAttachments: CommentAttachment[] = attachments\n .filter(\n (attachment) =>\n attachment.type === \"attachment\" ||\n (attachment.type === \"localAttachment\" &&\n attachment.status === \"uploaded\")\n )\n .map((attachment) => {\n return {\n id: attachment.id,\n type: \"attachment\",\n mimeType: attachment.mimeType,\n size: attachment.size,\n name: attachment.name,\n };\n });\n\n const promise = onComposerSubmit(\n { body, attachments: commentAttachments },\n event\n );\n\n event.preventDefault();\n\n if (promise) {\n setSubmitting(true);\n promise.then(onSubmitEnd);\n } else {\n onSubmitEnd();\n }\n },\n [disabled, editor, attachments, onComposerSubmit, onSubmit, onSubmitEnd]\n );\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n const toggleMark = useCallback(\n (mark: ComposerBodyMark) => {\n toggleEditorMark(editor, mark);\n },\n [editor]\n );\n\n useObservable(onEditorChange, () => {\n setMarks(getMarks(editor));\n });\n\n return (\n <ComposerEditorContext.Provider\n value={{\n editor,\n validate,\n setFocused,\n onEditorChange,\n roomId,\n }}\n >\n <ComposerAttachmentsContext.Provider\n value={{\n createAttachments,\n isUploadingAttachments,\n hasMaxAttachments,\n maxAttachments,\n maxAttachmentSize,\n }}\n >\n <ComposerContext.Provider\n value={{\n isDisabled,\n isFocused,\n isEmpty,\n canSubmit,\n submit,\n clear,\n select,\n focus,\n blur,\n createMention,\n insertText,\n attachments,\n attachFiles,\n removeAttachment,\n toggleMark,\n marks,\n }}\n >\n <Component {...props} onSubmit={handleSubmit} ref={mergedRefs}>\n <input\n type=\"file\"\n multiple\n ref={fileInputRef}\n onChange={handleAttachmentsInputChange}\n onClick={stopPropagation}\n tabIndex={-1}\n style={{ display: \"none\" }}\n />\n <Slottable>{children}</Slottable>\n </Component>\n </ComposerContext.Provider>\n </ComposerAttachmentsContext.Provider>\n </ComposerEditorContext.Provider>\n );\n }\n);\n\n/**\n * A button to submit the composer.\n *\n * @example\n * <Composer.Submit>Send</Composer.Submit>\n */\nconst ComposerSubmit = forwardRef<HTMLButtonElement, ComposerSubmitProps>(\n ({ children, disabled, asChild, ...props }, forwardedRef) => {\n const Component = asChild ? Slot : \"button\";\n const { canSubmit, isDisabled: isComposerDisabled } = useComposer();\n const isDisabled = isComposerDisabled || disabled || !canSubmit;\n\n return (\n <Component\n type=\"submit\"\n {...props}\n ref={forwardedRef}\n disabled={isDisabled}\n >\n {children}\n </Component>\n );\n }\n);\n\n/**\n * A button which opens a file picker to create attachments.\n *\n * @example\n * <Composer.AttachFiles>Attach files</Composer.AttachFiles>\n */\nconst ComposerAttachFiles = forwardRef<\n HTMLButtonElement,\n ComposerAttachFilesProps\n>(({ children, onClick, disabled, asChild, ...props }, forwardedRef) => {\n const Component = asChild ? Slot : \"button\";\n const { hasMaxAttachments } = useComposerAttachmentsContext();\n const { isDisabled: isComposerDisabled, attachFiles } = useComposer();\n const isDisabled = isComposerDisabled || hasMaxAttachments || disabled;\n\n const handleClick = useCallback(\n (event: MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n\n if (!event.isDefaultPrevented()) {\n attachFiles();\n }\n },\n [attachFiles, onClick]\n );\n\n return (\n <Component\n type=\"button\"\n {...props}\n onClick={handleClick}\n ref={forwardedRef}\n disabled={isDisabled}\n >\n {children}\n </Component>\n );\n});\n\n/**\n * A drop area which accepts files to create attachments.\n *\n * @example\n * <Composer.AttachmentsDropArea>\n * Drop files here\n * </Composer.AttachmentsDropArea>\n */\nconst ComposerAttachmentsDropArea = forwardRef<\n HTMLDivElement,\n ComposerAttachmentsDropAreaProps\n>(\n (\n {\n onDragEnter,\n onDragLeave,\n onDragOver,\n onDrop,\n disabled,\n asChild,\n ...props\n },\n forwardedRef\n ) => {\n const Component = asChild ? Slot : \"div\";\n const { isDisabled: isComposerDisabled } = useComposer();\n const isDisabled = isComposerDisabled || disabled;\n const [, dropAreaProps] = useComposerAttachmentsDropArea({\n onDragEnter,\n onDragLeave,\n onDragOver,\n onDrop,\n disabled: isDisabled,\n });\n\n return (\n <Component\n {...dropAreaProps}\n data-disabled={isDisabled ? \"\" : undefined}\n {...props}\n ref={forwardedRef}\n />\n );\n }\n);\n\n/**\n * A toggle button which toggles a specific text mark.\n *\n * @example\n * <Composer.MarkToggle mark=\"bold\">\n * Bold\n * </Composer.MarkToggle>\n */\nconst ComposerMarkToggle = forwardRef<\n HTMLButtonElement,\n ComposerMarkToggleProps\n>(\n (\n { children, mark, onValueChange, onClick, asChild, ...props },\n forwardedRef\n ) => {\n const Component = asChild ? Slot : \"button\";\n const { marks, toggleMark } = useComposer();\n\n const handleClick = useCallback(\n (event: MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n\n if (!event.isDefaultPrevented()) {\n toggleMark(mark);\n onValueChange?.(mark);\n }\n },\n [mark, onClick, onValueChange, toggleMark]\n );\n\n return (\n <TogglePrimitive.Root\n asChild\n pressed={marks[mark]}\n onClick={handleClick}\n {...props}\n >\n <Component {...props} ref={forwardedRef}>\n {children}\n </Component>\n </TogglePrimitive.Root>\n );\n }\n);\n\nif (process.env.NODE_ENV !== \"production\") {\n ComposerAttachFiles.displayName = COMPOSER_ATTACH_FILES_NAME;\n ComposerAttachmentsDropArea.displayName = COMPOSER_ATTACHMENTS_DROP_AREA_NAME;\n ComposerEditor.displayName = COMPOSER_EDITOR_NAME;\n ComposerFloatingToolbar.displayName = COMPOSER_FLOATING_TOOLBAR_NAME;\n ComposerForm.displayName = COMPOSER_FORM_NAME;\n ComposerMention.displayName = COMPOSER_MENTION_NAME;\n ComposerLink.displayName = COMPOSER_LINK_NAME;\n ComposerSubmit.displayName = COMPOSER_SUBMIT_NAME;\n ComposerSuggestions.displayName = COMPOSER_SUGGESTIONS_NAME;\n ComposerSuggestionsList.displayName = COMPOSER_SUGGESTIONS_LIST_NAME;\n ComposerSuggestionsListItem.displayName = COMPOSER_SUGGESTIONS_LIST_ITEM_NAME;\n ComposerMarkToggle.displayName = COMPOSER_MARK_TOGGLE_NAME;\n}\n\n// NOTE: Every export from this file will be available publicly as Composer.*\nexport {\n ComposerAttachFiles as AttachFiles,\n ComposerAttachmentsDropArea as AttachmentsDropArea,\n ComposerEditor as Editor,\n ComposerFloatingToolbar as FloatingToolbar,\n ComposerForm as Form,\n ComposerLink as Link,\n ComposerMarkToggle as MarkToggle,\n ComposerMention as Mention,\n ComposerSubmit as Submit,\n ComposerSuggestions as Suggestions,\n ComposerSuggestionsList as SuggestionsList,\n ComposerSuggestionsListItem as SuggestionsListItem,\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAqJA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAsC;AAC3B;AAEX;AAEA;AAA8B;AAC5B;AAEF;AAIE;AAAO;AACL;AACE;AACE;AACE;AACE;AACoD;AAChD;AACA;AACD;AACH;AACF;AACF;AACF;AACF;AAEJ;AAEA;AAAsC;AACpC;AACA;AACA;AAEF;AACE;AAEA;AACG;AAAS;AACP;AACE;AAAwB;AAAI;AAC3B;AACH;AAAA;AAGP;AAEA;AAAmC;AACjC;AACA;AACA;AAEF;AACE;AAAa;AACiC;AAChC;AAGd;AACG;AAAS;AACP;AAAK;AAAa;AAAS;AAGlC;AAEA;AAAiD;AAC/C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACW;AACX;AAEF;AACE;AACA;AACA;AACA;AACA;AACA;AAEA;AAAM;AAC8B;AAClC;AACA;AACA;AACA;AACA;AACyB;AACzB;AACA;AACW;AACL;AAGR;AACE;AAAkD;AAGpD;AACE;AACE;AAEA;AAAA;AAGF;AACA;AAA6B;AAG/B;AACG;AAEI;AACQ;AACL;AACA;AACe;AACG;AAClB;AACA;AACA;AACK;AACP;AAEC;AACM;AACM;AACJ;AACK;AACL;AACC;AAGF;AACM;AACF;AACV;AAEC;AACC;AACA;AACF;AACF;AAEA;AAGV;AAEA;AAA8C;AAC5C;AACW;AACX;AACA;AACA;AAEF;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAM;AAC8B;AAClC;AACA;AACA;AACA;AACA;AACyB;AACnB;AACN;AACA;AACW;AACL;AAGR;AACE;AACE;AAAA;AAGF;AACA;AAEA;AACA;AAEA;AACE;AACA;AAAyD;AAC3D;AAGF;AAEE;AAGA;AACE;AAGA;AAME;AACA;AAAiB;AAEjB;AAEA;AACA;AAAqB;AACvB;AACD;AAGH;AACG;AAEI;AACQ;AACL;AACA;AACA;AACK;AACP;AAEC;AACM;AACM;AACJ;AACK;AACL;AACC;AAGF;AACM;AACF;AACV;AAEiB;AACnB;AAEA;AAGV;AAWM;AAIJ;AACA;AACA;AAAM;AACJ;AACK;AACL;AACA;AAEF;AACA;AAAsB;AACgC;AAC1C;AAEZ;AACA;AAEA;AAA0B;AAEtB;AAEA;AACA;AAAsB;AACxB;AACc;AAGhB;AACG;AACC;AACK;AACL;AACW;AACP;AACW;AACkB;AACtB;AACC;AACL;AACI;AACM;AACL;AACC;AACR;AACL;AACK;AAEJ;AAGP;AAEA;AAA+B;AAC7B;AACA;AAEF;AAEE;AAEA;AAAsB;AAElB;AACG;AACC;AACK;AACP;AAEC;AAEH;AACG;AACC;AACK;AAGP;AAGF;AACG;AAAM;AAA0C;AAC9C;AACH;AAGF;AAAO;AAEb;AAGA;AACE;AACE;AAAY;AAAQ;AAAS;AAG/B;AACE;AAAY;AAAI;AAAS;AAG3B;AACE;AAAY;AAAG;AAAS;AAG1B;AACE;AAAY;AAAM;AAAS;AAG7B;AAAQ;AAAS;AAAa;AAChC;AAEA;AAAmC;AACjC;AAEF;AACE;AAEA;AACG;AAAS;AAAY;AAA+B;AAClD;AAGP;AAQA;AAAwB;AAEpB;AACA;AAEA;AACG;AAC8B;AACzB;AACC;AAEJ;AACH;AAGN;AAQA;AAAqB;AAEjB;AAEA;AACG;AACQ;AACH;AACA;AACC;AAEJ;AACH;AAGN;AAKM;AAIJ;AACA;AACA;AAAM;AACC;AACL;AACA;AAEF;AACA;AAAsB;AACgC;AAC1C;AAEZ;AACA;AAEA;AACG;AACC;AACI;AAC6B;AACtB;AACC;AACL;AACI;AACM;AACJ;AACA;AACR;AACL;AACK;AAEJ;AAGP;AAcM;AAIJ;AACA;AAEA;AACG;AACM;AACL;AACW;AACP;AACC;AAEJ;AAGP;AAUA;AAAoC;AAKhC;AACE;AACA;AACA;AACA;AACA;AACA;AACG;AAIL;AACA;AACA;AAEA;AACA;AAAmB;AACO;AACH;AAGvB;AAEA;AACE;AACE;AAA+C;AACjD;AAGF;AAA0B;AAEtB;AAEA;AACE;AAAsB;AACxB;AACF;AACuC;AAGzC;AAA0B;AAEtB;AAEA;AACA;AAAsB;AACxB;AACc;AAGhB;AAAoB;AAEhB;AAEA;AAEA;AACA;AAEA;AACE;AAAkB;AACpB;AACF;AAC6B;AAG/B;AACG;AACM;AACL;AAC6B;AACA;AACd;AACA;AACN;AACL;AACC;AAEJ;AACH;AAGN;AAEA;AAA0D;AAEtD;AAAQ;AAAa;AAAa;AAAS;AAC7C;AAEE;AACG;AACE;AAAA;AACA;AAAA;AACH;AAEJ;AAEE;AACG;AACE;AAEI;AAAgD;AAC9C;AAEJ;AACH;AAEA;AAER;AAQA;AAAuB;AAEnB;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACG;AAIL;AACA;AAEA;AAAM;AACJ;AACA;AACA;AACA;AACA;AACY;AACZ;AAEF;AACA;AACA;AACE;AAA4C;AAE9C;AAA+D;AACV;AACxC;AAGb;AAIA;AACA;AAGA;AACA;AAA2B;AACzB;AACc;AAEhB;AAAM;AACJ;AACA;AACA;AACA;AAEF;AACA;AACA;AACA;AAA8B;AAEoC;AAC7D;AAGL;AAAsB;AAElB;AACG;AAAsB;AAAkB;AAAgB;AAAO;AAEpE;AACc;AAGhB;AAAqB;AAEjB;AAKA;AAAsB;AACxB;AACyB;AAG3B;AAAsB;AAElB;AACE;AAAA;AAGF;AACA;AACA;AACA;AAAmC;AACrC;AACwD;AAG1D;AAAsB;AAElB;AAEA;AACE;AAAA;AAIF;AACE;AAA6B;AAI/B;AACE;AAA2B;AAG7B;AAEE;AACE;AACA;AAAsC;AAIxC;AACE;AACA;AAA0C;AAI5C;AACE;AAEA;AACA;AAAoB;AAItB;AACE;AACA;AACA;AAAmC;AACrC;AAEA;AAEE;AACE;AACA;AAAgC;AAClC;AAIF;AACE;AAAK;AAIP;AAEE;AAEA;AACE;AAAO;AACT;AAIF;AACE;AACA;AAAmB;AAIrB;AACE;AACA;AAA+B;AAIjC;AACE;AACA;AAAiC;AAInC;AACE;AACA;AAAwC;AAI1C;AACE;AACA;AAA+B;AACjC;AACF;AACF;AACA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF;AAGF;AAAoB;AAEhB;AAEA;AACE;AAAe;AACjB;AACF;AACoB;AAGtB;AAAmB;AAEf;AAEA;AACE;AAAgB;AAClB;AACF;AACmB;AAGrB;AAAwC;AACX;AACwB;AAErD;AAA2C;AAEvC;AAEA;AACE;AAAuC;AACzC;AACF;AACsD;AAGxD;AAAwC;AAGhC;AACQ;AACe;AACJ;AACA;AACQ;AACvB;AACF;AAGA;AACmB;AACA;AAElB;AACT;AACE;AACA;AACA;AACA;AACA;AACA;AACF;AAGF;AACE;AAA2C;AAI7C;AACE;AACE;AAAM;AACR;AAKF;AACE;AACE;AAAO;AACT;AAGF;AACG;AACC;AACc;AACJ;AAEV;AAAC;AACC;AACuC;AACxB;AACJ;AACgB;AACE;AACzB;AACA;AACM;AACA;AACC;AACF;AACD;AACR;AACY;AACO;AACrB;AAEG;AACC;AACA;AACA;AACgB;AACG;AACV;AACL;AACI;AACM;AACd;AACF;AAGC;AACC;AACI;AACJ;AACA;AACA;AACF;AAAA;AAEJ;AAGN;AAEA;AACA;AAEA;AACE;AAAO;AACC;AACE;AACsB;AACnB;AACA;AACI;AACf;AAEJ;AAWA;AAAqB;AAEjB;AACE;AACA;AACA;AACsB;AACtB;AACwB;AACxB;AACA;AACQ;AACL;AAIL;AACA;AACA;AACA;AACA;AAEA;AACA;AACE;AAAqE;AAIvE;AACA;AAEA;AAAM;AACJ;AACA;AACA;AACA;AACA;AACoD;AACvC;AACb;AAEF;AACA;AAEA;AACE;AAAoC;AAEtC;AACE;AAAoB;AAEtB;AAEA;AACA;AACA;AACA;AAIA;AAIA;AACE;AAAY;AACwB;AACpC;AAGF;AAA0B;AAEtB;AACE;AAAA;AAGF;AAAmC;AACjC;AACiB;AAGnB;AAEA;AAEA;AAA0B;AAC5B;AACoD;AAGtD;AAEA;AACE;AAA+B;AAGjC;AACE;AAAkC;AAGpC;AAAe;AACQ;AACA;AACnB;AACD;AAEH;AAEA;AAAiB;AAEb;AAAqC;AACvC;AACO;AAGT;AACE;AACE;AAAA;AAKF;AACE;AACE;AAAyB;AAC3B;AACD;AAGH;AACE;AAA+B;AACzB;AACkC;AACH;AACnC;AACD;AAGH;AACE;AAA0D;AAG5D;AAAc;AAEV;AACE;AACE;AAAgB;AACd;AAGW;AAEb;AAAwB;AAC1B;AACA;AAIF;AACF;AACO;AAGT;AACE;AACE;AAAuB;AACvB;AAIF;AAGF;AACE;AACE;AAAA;AAGF;AACA;AAA6B;AAG/B;AAAmB;AAEf;AACE;AAAA;AAGF;AACA;AAA4B;AAC9B;AACwB;AAG1B;AACE;AACE;AAAA;AAGF;AACE;AAA2B;AAC7B;AAGF;AAAqC;AAEjC;AACE;AAAA;AAGF;AACE;AAGA;AAAqB;AACvB;AACF;AAC4B;AAG9B;AACE;AACA;AACA;AACA;AAAmB;AAGrB;AAAqB;AAEjB;AACE;AAAA;AAMF;AAGA;AACE;AAEA;AAAA;AAGF;AAEA;AACE;AAEA;AAAA;AAGF;AAAa;AACJ;AAGT;AACG;AAI2B;AAG1B;AAAO;AACU;AACT;AACe;AACJ;AACA;AACnB;AAGJ;AAAgB;AAC0B;AACxC;AAGF;AAEA;AACE;AACA;AAAwB;AAExB;AAAY;AACd;AACF;AACuE;AAGzE;AACE;AAAsB;AAGxB;AAAmB;AAEf;AAA6B;AAC/B;AACO;AAGT;AACE;AAAyB;AAG3B;AACG;AACQ;AACL;AACA;AACA;AACA;AACA;AACF;AAEC;AACQ;AACL;AACA;AACA;AACA;AACA;AACF;AAEC;AACQ;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF;AAEC;AAAc;AAAiB;AAAmB;AACjD;AAAC;AACM;AACG;AACH;AACK;AACD;AACC;AACe;AAC3B;AACC;AAAW;AAAS;AAAA;AACvB;AACF;AACF;AACF;AAGN;AAQA;AAAuB;AAEnB;AACA;AACA;AAEA;AACG;AACM;AACD;AACC;AACK;AAET;AACH;AAGN;AAQM;AAIJ;AACA;AACA;AACA;AAEA;AAAoB;AAEhB;AAEA;AACE;AAAY;AACd;AACF;AACqB;AAGvB;AACG;AACM;AACD;AACK;AACJ;AACK;AAET;AAGP;AAUA;AAAoC;AAKhC;AACE;AACA;AACA;AACA;AACA;AACA;AACG;AAIL;AACA;AACA;AACA;AAAyD;AACvD;AACA;AACA;AACA;AACU;AAGZ;AACG;AACK;AAC6B;AAC7B;AACC;AACP;AAGN;AAUA;AAA2B;AAQvB;AACA;AAEA;AAAoB;AAEhB;AAEA;AACE;AACA;AAAoB;AACtB;AACF;AACyC;AAG3C;AACG;AACQ;AACQ;AACN;AACL;AAEH;AAAc;AAAY;AACxB;AACH;AACF;AAGN;AAEA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":["../../../src/primitives/Composer/index.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n type CommentAttachment,\n type CommentBody,\n type CommentLocalAttachment,\n createCommentAttachmentId,\n type EventSource,\n makeEventSource,\n} from \"@liveblocks/core\";\nimport {\n useClientOrNull,\n useLayoutEffect,\n useMentionSuggestions,\n useResolveMentionSuggestions,\n useRoomOrNull,\n useSyncSource,\n} from \"@liveblocks/react/_private\";\nimport { Slot, Slottable } from \"@radix-ui/react-slot\";\nimport * as TogglePrimitive from \"@radix-ui/react-toggle\";\nimport type {\n AriaAttributes,\n ChangeEvent,\n FocusEvent,\n FormEvent,\n KeyboardEvent,\n MouseEvent,\n PointerEvent,\n SyntheticEvent,\n} from \"react\";\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport type {\n Descendant as SlateDescendant,\n Element as SlateElement,\n} from \"slate\";\nimport {\n createEditor,\n Editor as SlateEditor,\n insertText as insertSlateText,\n Range as SlateRange,\n Transforms as SlateTransforms,\n} from \"slate\";\nimport { withHistory } from \"slate-history\";\nimport type {\n RenderElementProps,\n RenderElementSpecificProps,\n RenderLeafProps,\n RenderPlaceholderProps,\n} from \"slate-react\";\nimport {\n Editable,\n ReactEditor,\n Slate,\n useSelected,\n useSlateStatic,\n withReact,\n} from \"slate-react\";\n\nimport { useLiveblocksUIConfig } from \"../../config\";\nimport { withAutoFormatting } from \"../../slate/plugins/auto-formatting\";\nimport { withAutoLinks } from \"../../slate/plugins/auto-links\";\nimport { withCustomLinks } from \"../../slate/plugins/custom-links\";\nimport { withEmptyClearFormatting } from \"../../slate/plugins/empty-clear-formatting\";\nimport type { MentionDraft } from \"../../slate/plugins/mentions\";\nimport {\n getMentionDraftAtSelection,\n insertMention,\n insertMentionCharacter,\n MENTION_CHARACTER,\n withMentions,\n} from \"../../slate/plugins/mentions\";\nimport { withNormalize } from \"../../slate/plugins/normalize\";\nimport { withPaste } from \"../../slate/plugins/paste\";\nimport { getDOMRange } from \"../../slate/utils/get-dom-range\";\nimport { isEmpty as isEditorEmpty } from \"../../slate/utils/is-empty\";\nimport {\n getMarks,\n leaveMarkEdge,\n toggleMark as toggleEditorMark,\n} from \"../../slate/utils/marks\";\nimport type {\n ComposerBody as ComposerBodyData,\n ComposerBodyAutoLink,\n ComposerBodyCustomLink,\n ComposerBodyMark,\n ComposerBodyMarks,\n ComposerBodyMention,\n} from \"../../types\";\nimport { isKey } from \"../../utils/is-key\";\nimport { Persist, useAnimationPersist, usePersist } from \"../../utils/Persist\";\nimport { Portal } from \"../../utils/Portal\";\nimport { requestSubmit } from \"../../utils/request-submit\";\nimport { useIndex } from \"../../utils/use-index\";\nimport { useInitial } from \"../../utils/use-initial\";\nimport { useObservable } from \"../../utils/use-observable\";\nimport { useRefs } from \"../../utils/use-refs\";\nimport { toAbsoluteUrl } from \"../Comment/utils\";\nimport {\n ComposerAttachmentsContext,\n ComposerContext,\n ComposerEditorContext,\n ComposerFloatingToolbarContext,\n ComposerSuggestionsContext,\n useComposer,\n useComposerAttachmentsContext,\n useComposerEditorContext,\n useComposerFloatingToolbarContext,\n useComposerSuggestionsContext,\n} from \"./contexts\";\nimport type {\n ComposerAttachFilesProps,\n ComposerAttachmentsDropAreaProps,\n ComposerEditorComponents,\n ComposerEditorElementProps,\n ComposerEditorFloatingToolbarWrapperProps,\n ComposerEditorLinkWrapperProps,\n ComposerEditorMentionSuggestionsWrapperProps,\n ComposerEditorMentionWrapperProps,\n ComposerEditorProps,\n ComposerFloatingToolbarProps,\n ComposerFormProps,\n ComposerLinkProps,\n ComposerMarkToggleProps,\n ComposerMentionProps,\n ComposerSubmitProps,\n ComposerSuggestionsListItemProps,\n ComposerSuggestionsListProps,\n ComposerSuggestionsProps,\n FloatingPosition,\n} from \"./types\";\nimport {\n commentBodyToComposerBody,\n composerBodyToCommentBody,\n getSideAndAlignFromFloatingPlacement,\n useComposerAttachmentsDropArea,\n useComposerAttachmentsManager,\n useContentZIndex,\n useFloatingWithOptions,\n} from \"./utils\";\n\nconst MENTION_SUGGESTIONS_POSITION: FloatingPosition = \"top\";\n\nconst FLOATING_TOOLBAR_POSITION: FloatingPosition = \"top\";\n\nconst COMPOSER_MENTION_NAME = \"ComposerMention\";\nconst COMPOSER_LINK_NAME = \"ComposerLink\";\nconst COMPOSER_FLOATING_TOOLBAR_NAME = \"ComposerFloatingToolbar\";\nconst COMPOSER_SUGGESTIONS_NAME = \"ComposerSuggestions\";\nconst COMPOSER_SUGGESTIONS_LIST_NAME = \"ComposerSuggestionsList\";\nconst COMPOSER_SUGGESTIONS_LIST_ITEM_NAME = \"ComposerSuggestionsListItem\";\nconst COMPOSER_SUBMIT_NAME = \"ComposerSubmit\";\nconst COMPOSER_EDITOR_NAME = \"ComposerEditor\";\nconst COMPOSER_ATTACH_FILES_NAME = \"ComposerAttachFiles\";\nconst COMPOSER_ATTACHMENTS_DROP_AREA_NAME = \"ComposerAttachmentsDropArea\";\nconst COMPOSER_MARK_TOGGLE_NAME = \"ComposerMarkToggle\";\nconst COMPOSER_FORM_NAME = \"ComposerForm\";\n\nconst emptyCommentBody: CommentBody = {\n version: 1,\n content: [{ type: \"paragraph\", children: [{ text: \"\" }] }],\n};\n\nfunction createComposerEditor({\n createAttachments,\n pasteFilesAsAttachments,\n}: {\n createAttachments: (files: File[]) => void;\n pasteFilesAsAttachments?: boolean;\n}) {\n return withNormalize(\n withMentions(\n withCustomLinks(\n withAutoLinks(\n withAutoFormatting(\n withEmptyClearFormatting(\n withPaste(withHistory(withReact(createEditor())), {\n createAttachments,\n pasteFilesAsAttachments,\n })\n )\n )\n )\n )\n )\n );\n}\n\nfunction ComposerEditorMentionWrapper({\n Mention,\n attributes,\n children,\n element,\n}: ComposerEditorMentionWrapperProps) {\n const isSelected = useSelected();\n\n return (\n <span {...attributes}>\n {element.id ? (\n <Mention userId={element.id} isSelected={isSelected} />\n ) : null}\n {children}\n </span>\n );\n}\n\nfunction ComposerEditorLinkWrapper({\n Link,\n attributes,\n element,\n children,\n}: ComposerEditorLinkWrapperProps) {\n const href = useMemo(\n () => toAbsoluteUrl(element.url) ?? element.url,\n [element.url]\n );\n\n return (\n <span {...attributes}>\n <Link href={href}>{children}</Link>\n </span>\n );\n}\n\nfunction ComposerEditorMentionSuggestionsWrapper({\n id,\n itemId,\n userIds,\n selectedUserId,\n setSelectedUserId,\n mentionDraft,\n setMentionDraft,\n onItemSelect,\n position = MENTION_SUGGESTIONS_POSITION,\n dir,\n MentionSuggestions,\n}: ComposerEditorMentionSuggestionsWrapperProps) {\n const editor = useSlateStatic();\n const { onEditorChange } = useComposerEditorContext();\n const { isFocused } = useComposer();\n const { portalContainer } = useLiveblocksUIConfig();\n const [contentRef, contentZIndex] = useContentZIndex();\n const isOpen =\n isFocused && mentionDraft?.range !== undefined && userIds !== undefined;\n const {\n refs: { setReference, setFloating },\n strategy,\n isPositioned,\n placement,\n x,\n y,\n } = useFloatingWithOptions({\n position,\n dir,\n alignment: \"start\",\n open: isOpen,\n });\n\n useObservable(onEditorChange, () => {\n setMentionDraft(getMentionDraftAtSelection(editor));\n });\n\n useLayoutEffect(() => {\n if (!mentionDraft) {\n setReference(null);\n\n return;\n }\n\n const domRange = getDOMRange(editor, mentionDraft.range);\n setReference(domRange ?? null);\n }, [setReference, editor, mentionDraft]);\n\n return (\n <Persist>\n {isOpen ? (\n <ComposerSuggestionsContext.Provider\n value={{\n id,\n itemId,\n selectedValue: selectedUserId,\n setSelectedValue: setSelectedUserId,\n onItemSelect,\n placement,\n dir,\n ref: contentRef,\n }}\n >\n <Portal\n ref={setFloating}\n container={portalContainer}\n style={{\n position: strategy,\n top: 0,\n left: 0,\n transform: isPositioned\n ? `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`\n : \"translate3d(0, -200%, 0)\",\n minWidth: \"max-content\",\n zIndex: contentZIndex,\n }}\n >\n <MentionSuggestions\n userIds={userIds}\n selectedUserId={selectedUserId}\n />\n </Portal>\n </ComposerSuggestionsContext.Provider>\n ) : null}\n </Persist>\n );\n}\n\nfunction ComposerEditorFloatingToolbarWrapper({\n id,\n position = FLOATING_TOOLBAR_POSITION,\n dir,\n FloatingToolbar,\n hasFloatingToolbarRange,\n setHasFloatingToolbarRange,\n}: ComposerEditorFloatingToolbarWrapperProps) {\n const editor = useSlateStatic();\n const { onEditorChange } = useComposerEditorContext();\n const { isFocused } = useComposer();\n const { portalContainer } = useLiveblocksUIConfig();\n const [contentRef, contentZIndex] = useContentZIndex();\n const [isPointerDown, setPointerDown] = useState(false);\n const isOpen = isFocused && !isPointerDown && hasFloatingToolbarRange;\n const {\n refs: { setReference, setFloating },\n strategy,\n isPositioned,\n placement,\n x,\n y,\n } = useFloatingWithOptions({\n type: \"range\",\n position,\n dir,\n alignment: \"center\",\n open: isOpen,\n });\n\n useLayoutEffect(() => {\n if (!isFocused) {\n return;\n }\n\n const handlePointerDown = () => setPointerDown(true);\n const handlePointerUp = () => setPointerDown(false);\n\n document.addEventListener(\"pointerdown\", handlePointerDown);\n document.addEventListener(\"pointerup\", handlePointerUp);\n\n return () => {\n document.removeEventListener(\"pointerdown\", handlePointerDown);\n document.removeEventListener(\"pointerup\", handlePointerUp);\n };\n }, [isFocused]);\n\n useObservable(onEditorChange, () => {\n // Detach from previous selection range (if any) to avoid sudden jumps\n setReference(null);\n\n // Then, wait for the next render to ensure the selection is updated\n requestAnimationFrame(() => {\n const domSelection = window.getSelection();\n\n // Finally, show the toolbar if there's a selection range\n if (\n !editor.selection ||\n SlateRange.isCollapsed(editor.selection) ||\n !domSelection ||\n !domSelection.rangeCount\n ) {\n setHasFloatingToolbarRange(false);\n setReference(null);\n } else {\n setHasFloatingToolbarRange(true);\n\n const domRange = domSelection.getRangeAt(0);\n setReference(domRange);\n }\n });\n });\n\n return (\n <Persist>\n {isOpen ? (\n <ComposerFloatingToolbarContext.Provider\n value={{\n id,\n placement,\n dir,\n ref: contentRef,\n }}\n >\n <Portal\n ref={setFloating}\n container={portalContainer}\n style={{\n position: strategy,\n top: 0,\n left: 0,\n transform: isPositioned\n ? `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`\n : \"translate3d(0, -200%, 0)\",\n minWidth: \"max-content\",\n zIndex: contentZIndex,\n }}\n >\n <FloatingToolbar />\n </Portal>\n </ComposerFloatingToolbarContext.Provider>\n ) : null}\n </Persist>\n );\n}\n\n/**\n * Displays a floating toolbar attached to the selection within `Composer.Editor`.\n *\n * @example\n * <Composer.FloatingToolbar>\n * <Composer.MarkToggle mark=\"bold\">Bold</Composer.MarkToggle>\n * <Composer.MarkToggle mark=\"italic\">Italic</Composer.MarkToggle>\n * </Composer.FloatingToolbar>\n */\nconst ComposerFloatingToolbar = forwardRef<\n HTMLDivElement,\n ComposerFloatingToolbarProps\n>(({ children, onPointerDown, style, asChild, ...props }, forwardedRef) => {\n const [isPresent] = usePersist();\n const ref = useRef<HTMLDivElement>(null);\n const {\n id,\n ref: contentRef,\n placement,\n dir,\n } = useComposerFloatingToolbarContext(COMPOSER_FLOATING_TOOLBAR_NAME);\n const mergedRefs = useRefs(forwardedRef, contentRef, ref);\n const [side, align] = useMemo(\n () => getSideAndAlignFromFloatingPlacement(placement),\n [placement]\n );\n const Component = asChild ? Slot : \"div\";\n useAnimationPersist(ref);\n\n const handlePointerDown = useCallback(\n (event: PointerEvent<HTMLDivElement>) => {\n onPointerDown?.(event);\n\n event.preventDefault();\n event.stopPropagation();\n },\n [onPointerDown]\n );\n\n return (\n <Component\n dir={dir}\n role=\"toolbar\"\n id={id}\n aria-label=\"Floating toolbar\"\n {...props}\n onPointerDown={handlePointerDown}\n data-state={isPresent ? \"open\" : \"closed\"}\n data-side={side}\n data-align={align}\n style={{\n display: \"flex\",\n flexDirection: \"row\",\n maxWidth: \"var(--lb-composer-floating-available-width)\",\n overflowX: \"auto\",\n ...style,\n }}\n ref={mergedRefs}\n >\n {children}\n </Component>\n );\n});\n\nfunction ComposerEditorElement({\n Mention,\n Link,\n ...props\n}: ComposerEditorElementProps) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const { attributes, children, element } = props;\n\n switch (element.type) {\n case \"mention\":\n return (\n <ComposerEditorMentionWrapper\n Mention={Mention}\n {...(props as RenderElementSpecificProps<ComposerBodyMention>)}\n />\n );\n case \"auto-link\":\n case \"custom-link\":\n return (\n <ComposerEditorLinkWrapper\n Link={Link}\n {...(props as RenderElementSpecificProps<\n ComposerBodyAutoLink | ComposerBodyCustomLink\n >)}\n />\n );\n case \"paragraph\":\n return (\n <p {...attributes} style={{ position: \"relative\" }}>\n {children}\n </p>\n );\n default:\n return null;\n }\n}\n\n// <code><s><em><strong>text</strong></s></em></code>\nfunction ComposerEditorLeaf({ attributes, children, leaf }: RenderLeafProps) {\n if (leaf.bold) {\n children = <strong>{children}</strong>;\n }\n\n if (leaf.italic) {\n children = <em>{children}</em>;\n }\n\n if (leaf.strikethrough) {\n children = <s>{children}</s>;\n }\n\n if (leaf.code) {\n children = <code>{children}</code>;\n }\n\n return <span {...attributes}>{children}</span>;\n}\n\nfunction ComposerEditorPlaceholder({\n attributes,\n children,\n}: RenderPlaceholderProps) {\n const { opacity: _opacity, ...style } = attributes.style;\n\n return (\n <span {...attributes} style={style} data-placeholder=\"\">\n {children}\n </span>\n );\n}\n\n/**\n * Displays mentions within `Composer.Editor`.\n *\n * @example\n * <Composer.Mention>@{userId}</Composer.Mention>\n */\nconst ComposerMention = forwardRef<HTMLSpanElement, ComposerMentionProps>(\n ({ children, asChild, ...props }, forwardedRef) => {\n const Component = asChild ? Slot : \"span\";\n const isSelected = useSelected();\n\n return (\n <Component\n data-selected={isSelected || undefined}\n {...props}\n ref={forwardedRef}\n >\n {children}\n </Component>\n );\n }\n);\n\n/**\n * Displays links within `Composer.Editor`.\n *\n * @example\n * <Composer.Link href={href}>{children}</Composer.Link>\n */\nconst ComposerLink = forwardRef<HTMLAnchorElement, ComposerLinkProps>(\n ({ children, asChild, ...props }, forwardedRef) => {\n const Component = asChild ? Slot : \"a\";\n\n return (\n <Component\n target=\"_blank\"\n rel=\"noopener noreferrer nofollow\"\n {...props}\n ref={forwardedRef}\n >\n {children}\n </Component>\n );\n }\n);\n\n/**\n * Contains suggestions within `Composer.Editor`.\n */\nconst ComposerSuggestions = forwardRef<\n HTMLDivElement,\n ComposerSuggestionsProps\n>(({ children, style, asChild, ...props }, forwardedRef) => {\n const [isPresent] = usePersist();\n const ref = useRef<HTMLDivElement>(null);\n const {\n ref: contentRef,\n placement,\n dir,\n } = useComposerSuggestionsContext(COMPOSER_SUGGESTIONS_NAME);\n const mergedRefs = useRefs(forwardedRef, contentRef, ref);\n const [side, align] = useMemo(\n () => getSideAndAlignFromFloatingPlacement(placement),\n [placement]\n );\n const Component = asChild ? Slot : \"div\";\n useAnimationPersist(ref);\n\n return (\n <Component\n dir={dir}\n {...props}\n data-state={isPresent ? \"open\" : \"closed\"}\n data-side={side}\n data-align={align}\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n maxHeight: \"var(--lb-composer-floating-available-height)\",\n overflowY: \"auto\",\n ...style,\n }}\n ref={mergedRefs}\n >\n {children}\n </Component>\n );\n});\n\n/**\n * Displays a list of suggestions within `Composer.Editor`.\n *\n * @example\n * <Composer.SuggestionsList>\n * {userIds.map((userId) => (\n * <Composer.SuggestionsListItem key={userId} value={userId}>\n * @{userId}\n * </Composer.SuggestionsListItem>\n * ))}\n * </Composer.SuggestionsList>\n */\nconst ComposerSuggestionsList = forwardRef<\n HTMLUListElement,\n ComposerSuggestionsListProps\n>(({ children, asChild, ...props }, forwardedRef) => {\n const { id } = useComposerSuggestionsContext(COMPOSER_SUGGESTIONS_LIST_NAME);\n const Component = asChild ? Slot : \"ul\";\n\n return (\n <Component\n role=\"listbox\"\n id={id}\n aria-label=\"Suggestions list\"\n {...props}\n ref={forwardedRef}\n >\n {children}\n </Component>\n );\n});\n\n/**\n * Displays a suggestion within `Composer.SuggestionsList`.\n *\n * @example\n * <Composer.SuggestionsListItem key={userId} value={userId}>\n * @{userId}\n * </Composer.SuggestionsListItem>\n */\nconst ComposerSuggestionsListItem = forwardRef<\n HTMLLIElement,\n ComposerSuggestionsListItemProps\n>(\n (\n {\n value,\n children,\n onPointerMove,\n onPointerDown,\n onClick,\n asChild,\n ...props\n },\n forwardedRef\n ) => {\n const ref = useRef<HTMLLIElement>(null);\n const mergedRefs = useRefs(forwardedRef, ref);\n const { selectedValue, setSelectedValue, itemId, onItemSelect } =\n useComposerSuggestionsContext(COMPOSER_SUGGESTIONS_LIST_ITEM_NAME);\n const Component = asChild ? Slot : \"li\";\n const isSelected = useMemo(\n () => selectedValue === value,\n [selectedValue, value]\n );\n // TODO: Support props.id if provided, it will need to be sent up to Composer.Editor to use it in aria-activedescendant\n const id = useMemo(() => itemId(value), [itemId, value]);\n\n useEffect(() => {\n if (ref?.current && isSelected) {\n ref.current.scrollIntoView({ block: \"nearest\" });\n }\n }, [isSelected]);\n\n const handlePointerMove = useCallback(\n (event: PointerEvent<HTMLLIElement>) => {\n onPointerMove?.(event);\n\n if (!event.isDefaultPrevented()) {\n setSelectedValue(value);\n }\n },\n [onPointerMove, setSelectedValue, value]\n );\n\n const handlePointerDown = useCallback(\n (event: PointerEvent<HTMLLIElement>) => {\n onPointerDown?.(event);\n\n event.preventDefault();\n event.stopPropagation();\n },\n [onPointerDown]\n );\n\n const handleClick = useCallback(\n (event: MouseEvent<HTMLLIElement>) => {\n onClick?.(event);\n\n const wasDefaultPrevented = event.isDefaultPrevented();\n\n event.preventDefault();\n event.stopPropagation();\n\n if (!wasDefaultPrevented) {\n onItemSelect(value);\n }\n },\n [onClick, onItemSelect, value]\n );\n\n return (\n <Component\n role=\"option\"\n id={id}\n data-selected={isSelected || undefined}\n aria-selected={isSelected || undefined}\n onPointerMove={handlePointerMove}\n onPointerDown={handlePointerDown}\n onClick={handleClick}\n {...props}\n ref={mergedRefs}\n >\n {children}\n </Component>\n );\n }\n);\n\nconst defaultEditorComponents: ComposerEditorComponents = {\n Link: ({ href, children }) => {\n return <ComposerLink href={href}>{children}</ComposerLink>;\n },\n Mention: ({ userId }) => {\n return (\n <ComposerMention>\n {MENTION_CHARACTER}\n {userId}\n </ComposerMention>\n );\n },\n MentionSuggestions: ({ userIds }) => {\n return userIds.length > 0 ? (\n <ComposerSuggestions>\n <ComposerSuggestionsList>\n {userIds.map((userId) => (\n <ComposerSuggestionsListItem key={userId} value={userId}>\n {userId}\n </ComposerSuggestionsListItem>\n ))}\n </ComposerSuggestionsList>\n </ComposerSuggestions>\n ) : null;\n },\n};\n\n/**\n * Displays the composer's editor.\n *\n * @example\n * <Composer.Editor placeholder=\"Write a comment…\" />\n */\nconst ComposerEditor = forwardRef<HTMLDivElement, ComposerEditorProps>(\n (\n {\n defaultValue,\n onKeyDown,\n onFocus,\n onBlur,\n disabled,\n autoFocus,\n components,\n dir,\n ...props\n },\n forwardedRef\n ) => {\n const client = useClientOrNull();\n const { editor, validate, setFocused, onEditorChange, roomId } =\n useComposerEditorContext();\n const {\n submit,\n focus,\n blur,\n select,\n canSubmit,\n isDisabled: isComposerDisabled,\n isFocused,\n } = useComposer();\n const isDisabled = isComposerDisabled || disabled;\n const initialBody = useInitial(defaultValue ?? emptyCommentBody);\n const initialEditorValue = useMemo(() => {\n return commentBodyToComposerBody(initialBody);\n }, [initialBody]);\n const { Link, Mention, MentionSuggestions, FloatingToolbar } = useMemo(\n () => ({ ...defaultEditorComponents, ...components }),\n [components]\n );\n\n const [hasFloatingToolbarRange, setHasFloatingToolbarRange] =\n useState(false);\n // If used with LiveblocksProvider but without resolveMentionSuggestions,\n // we can skip the mention suggestions logic entirely\n const resolveMentionSuggestions = useResolveMentionSuggestions();\n const hasResolveMentionSuggestions = client\n ? resolveMentionSuggestions\n : true;\n const [mentionDraft, setMentionDraft] = useState<MentionDraft>();\n const mentionSuggestions = useMentionSuggestions(\n roomId,\n mentionDraft?.text\n );\n const [\n selectedMentionSuggestionIndex,\n setPreviousSelectedMentionSuggestionIndex,\n setNextSelectedMentionSuggestionIndex,\n setSelectedMentionSuggestionIndex,\n ] = useIndex(0, mentionSuggestions?.length ?? 0);\n const id = useId();\n const floatingToolbarId = `liveblocks-floating-toolbar-${id}`;\n const suggestionsListId = `liveblocks-suggestions-list-${id}`;\n const suggestionsListItemId = useCallback(\n (userId?: string) =>\n userId ? `liveblocks-suggestions-list-item-${id}-${userId}` : undefined,\n [id]\n );\n\n const renderElement = useCallback(\n (props: RenderElementProps) => {\n return (\n <ComposerEditorElement Mention={Mention} Link={Link} {...props} />\n );\n },\n [Link, Mention]\n );\n\n const handleChange = useCallback(\n (value: SlateDescendant[]) => {\n validate(value as SlateElement[]);\n\n // Our multi-component setup requires us to instantiate the editor in `Composer.Form`\n // but we can only listen to changes here in `Composer.Editor` via `Slate`, so we use\n // an event source to notify `Composer.Form` of changes.\n onEditorChange.notify();\n },\n [validate, onEditorChange]\n );\n\n const createMention = useCallback(\n (userId?: string) => {\n if (!mentionDraft || !userId) {\n return;\n }\n\n SlateTransforms.select(editor, mentionDraft.range);\n insertMention(editor, userId);\n setMentionDraft(undefined);\n setSelectedMentionSuggestionIndex(0);\n },\n [editor, mentionDraft, setSelectedMentionSuggestionIndex]\n );\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\n // Allow leaving marks with ArrowLeft\n if (isKey(event, \"ArrowLeft\")) {\n leaveMarkEdge(editor, \"start\");\n }\n\n // Allow leaving marks with ArrowRight\n if (isKey(event, \"ArrowRight\")) {\n leaveMarkEdge(editor, \"end\");\n }\n\n if (mentionDraft && mentionSuggestions?.length) {\n // Select the next mention suggestion on ArrowDown\n if (isKey(event, \"ArrowDown\")) {\n event.preventDefault();\n setNextSelectedMentionSuggestionIndex();\n }\n\n // Select the previous mention suggestion on ArrowUp\n if (isKey(event, \"ArrowUp\")) {\n event.preventDefault();\n setPreviousSelectedMentionSuggestionIndex();\n }\n\n // Create a mention on Enter/Tab\n if (isKey(event, \"Enter\") || isKey(event, \"Tab\")) {\n event.preventDefault();\n\n const userId = mentionSuggestions?.[selectedMentionSuggestionIndex];\n createMention(userId);\n }\n\n // Close the suggestions on Escape\n if (isKey(event, \"Escape\")) {\n event.preventDefault();\n setMentionDraft(undefined);\n setSelectedMentionSuggestionIndex(0);\n }\n } else {\n if (hasFloatingToolbarRange) {\n // Close the floating toolbar on Escape\n if (isKey(event, \"Escape\")) {\n event.preventDefault();\n setHasFloatingToolbarRange(false);\n }\n }\n\n // Blur the editor on Escape\n if (isKey(event, \"Escape\")) {\n blur();\n }\n\n // Submit the editor on Enter\n if (isKey(event, \"Enter\", { shift: false })) {\n // Even if submitting is not possible, don't do anything else on Enter. (e.g. creating a new line)\n event.preventDefault();\n\n if (canSubmit) {\n submit();\n }\n }\n\n // Create a new line on Shift + Enter\n if (isKey(event, \"Enter\", { shift: true })) {\n event.preventDefault();\n editor.insertBreak();\n }\n\n // Toggle bold on Command/Control + B\n if (isKey(event, \"b\", { mod: true })) {\n event.preventDefault();\n toggleEditorMark(editor, \"bold\");\n }\n\n // Toggle italic on Command/Control + I\n if (isKey(event, \"i\", { mod: true })) {\n event.preventDefault();\n toggleEditorMark(editor, \"italic\");\n }\n\n // Toggle strikethrough on Command/Control + Shift + S\n if (isKey(event, \"s\", { mod: true, shift: true })) {\n event.preventDefault();\n toggleEditorMark(editor, \"strikethrough\");\n }\n\n // Toggle code on Command/Control + E\n if (isKey(event, \"e\", { mod: true })) {\n event.preventDefault();\n toggleEditorMark(editor, \"code\");\n }\n }\n },\n [\n onKeyDown,\n mentionDraft,\n mentionSuggestions,\n hasFloatingToolbarRange,\n editor,\n setNextSelectedMentionSuggestionIndex,\n setPreviousSelectedMentionSuggestionIndex,\n selectedMentionSuggestionIndex,\n createMention,\n setSelectedMentionSuggestionIndex,\n blur,\n canSubmit,\n submit,\n ]\n );\n\n const handleFocus = useCallback(\n (event: FocusEvent<HTMLDivElement>) => {\n onFocus?.(event);\n\n if (!event.isDefaultPrevented()) {\n setFocused(true);\n }\n },\n [onFocus, setFocused]\n );\n\n const handleBlur = useCallback(\n (event: FocusEvent<HTMLDivElement>) => {\n onBlur?.(event);\n\n if (!event.isDefaultPrevented()) {\n setFocused(false);\n }\n },\n [onBlur, setFocused]\n );\n\n const selectedMentionSuggestionUserId = useMemo(\n () => mentionSuggestions?.[selectedMentionSuggestionIndex],\n [selectedMentionSuggestionIndex, mentionSuggestions]\n );\n const setSelectedMentionSuggestionUserId = useCallback(\n (userId: string) => {\n const index = mentionSuggestions?.indexOf(userId);\n\n if (index !== undefined && index >= 0) {\n setSelectedMentionSuggestionIndex(index);\n }\n },\n [setSelectedMentionSuggestionIndex, mentionSuggestions]\n );\n\n const additionalProps: AriaAttributes = useMemo(\n () =>\n mentionDraft\n ? {\n role: \"combobox\",\n \"aria-autocomplete\": \"list\",\n \"aria-expanded\": true,\n \"aria-controls\": suggestionsListId,\n \"aria-activedescendant\": suggestionsListItemId(\n selectedMentionSuggestionUserId\n ),\n }\n : hasFloatingToolbarRange\n ? {\n \"aria-haspopup\": true,\n \"aria-controls\": floatingToolbarId,\n }\n : {},\n [\n mentionDraft,\n suggestionsListId,\n suggestionsListItemId,\n selectedMentionSuggestionUserId,\n hasFloatingToolbarRange,\n floatingToolbarId,\n ]\n );\n\n useImperativeHandle(forwardedRef, () => {\n return ReactEditor.toDOMNode(editor, editor) as HTMLDivElement;\n }, [editor]);\n\n // Manually focus the editor when `autoFocus` is true\n useLayoutEffect(() => {\n if (autoFocus) {\n focus();\n }\n }, [autoFocus, editor, focus]);\n\n // Manually add a selection in the editor if the selection\n // is still empty after being focused\n useLayoutEffect(() => {\n if (isFocused && editor.selection === null) {\n select();\n }\n }, [editor, select, isFocused]);\n\n return (\n <Slate\n editor={editor}\n initialValue={initialEditorValue}\n onChange={handleChange}\n >\n <Editable\n dir={dir}\n enterKeyHint={mentionDraft ? \"enter\" : \"send\"}\n autoCapitalize=\"sentences\"\n aria-label=\"Composer editor\"\n data-focused={isFocused || undefined}\n data-disabled={isDisabled || undefined}\n {...additionalProps}\n {...props}\n readOnly={isDisabled}\n disabled={isDisabled}\n onKeyDown={handleKeyDown}\n onFocus={handleFocus}\n onBlur={handleBlur}\n renderElement={renderElement}\n renderLeaf={ComposerEditorLeaf}\n renderPlaceholder={ComposerEditorPlaceholder}\n />\n {hasResolveMentionSuggestions && (\n <ComposerEditorMentionSuggestionsWrapper\n dir={dir}\n mentionDraft={mentionDraft}\n setMentionDraft={setMentionDraft}\n selectedUserId={selectedMentionSuggestionUserId}\n setSelectedUserId={setSelectedMentionSuggestionUserId}\n userIds={mentionSuggestions}\n id={suggestionsListId}\n itemId={suggestionsListItemId}\n onItemSelect={createMention}\n MentionSuggestions={MentionSuggestions}\n />\n )}\n {FloatingToolbar && (\n <ComposerEditorFloatingToolbarWrapper\n dir={dir}\n id={floatingToolbarId}\n hasFloatingToolbarRange={hasFloatingToolbarRange}\n setHasFloatingToolbarRange={setHasFloatingToolbarRange}\n FloatingToolbar={FloatingToolbar}\n />\n )}\n </Slate>\n );\n }\n);\n\nconst MAX_ATTACHMENTS = 10;\nconst MAX_ATTACHMENT_SIZE = 1024 * 1024 * 1024; // 1 GB\n\nfunction prepareAttachment(file: File): CommentLocalAttachment {\n return {\n type: \"localAttachment\",\n status: \"idle\",\n id: createCommentAttachmentId(),\n name: file.name,\n size: file.size,\n mimeType: file.type,\n file,\n };\n}\n\n/**\n * Surrounds the composer's content and handles submissions.\n *\n * @example\n * <Composer.Form onComposerSubmit={({ body }) => {}}>\n *\t <Composer.Editor />\n * <Composer.Submit />\n * </Composer.Form>\n */\nconst ComposerForm = forwardRef<HTMLFormElement, ComposerFormProps>(\n (\n {\n children,\n onSubmit,\n onComposerSubmit,\n defaultAttachments = [],\n pasteFilesAsAttachments,\n preventUnsavedChanges = true,\n disabled,\n asChild,\n roomId: _roomId,\n ...props\n },\n forwardedRef\n ) => {\n const Component = asChild ? Slot : \"form\";\n const [isEmpty, setEmpty] = useState(true);\n const [isSubmitting, setSubmitting] = useState(false);\n const [isFocused, setFocused] = useState(false);\n const room = useRoomOrNull();\n\n const roomId = _roomId !== undefined ? _roomId : room?.id;\n if (roomId === undefined) {\n throw new Error(\"Composer.Form must be a descendant of RoomProvider.\");\n }\n\n // Later: Offer as Composer.Form props: { maxAttachments: number; maxAttachmentSize: number; supportedAttachmentMimeTypes: string[]; }\n const maxAttachments = MAX_ATTACHMENTS;\n const maxAttachmentSize = MAX_ATTACHMENT_SIZE;\n\n const {\n attachments,\n isUploadingAttachments,\n addAttachments,\n removeAttachment,\n clearAttachments,\n } = useComposerAttachmentsManager(defaultAttachments, {\n maxFileSize: maxAttachmentSize,\n roomId,\n });\n const numberOfAttachments = attachments.length;\n const hasMaxAttachments = numberOfAttachments >= maxAttachments;\n\n const isDisabled = useMemo(() => {\n return isSubmitting || disabled === true;\n }, [isSubmitting, disabled]);\n const canSubmit = useMemo(() => {\n return !isEmpty && !isUploadingAttachments;\n }, [isEmpty, isUploadingAttachments]);\n const [marks, setMarks] = useState<ComposerBodyMarks>(getMarks);\n\n const ref = useRef<HTMLFormElement>(null);\n const mergedRefs = useRefs(forwardedRef, ref);\n const fileInputRef = useRef<HTMLInputElement>(null);\n const syncSource = useSyncSource();\n\n // Mark the composer as a pending update when it has unsubmitted (draft)\n // text or attachments\n const isPending = !preventUnsavedChanges\n ? false\n : !isEmpty || isUploadingAttachments || attachments.length > 0;\n\n useEffect(() => {\n syncSource?.setSyncStatus(\n isPending ? \"has-local-changes\" : \"synchronized\"\n );\n }, [syncSource, isPending]);\n\n const createAttachments = useCallback(\n (files: File[]) => {\n if (!files.length) {\n return;\n }\n\n const numberOfAcceptedFiles = Math.max(\n 0,\n maxAttachments - numberOfAttachments\n );\n\n files.splice(numberOfAcceptedFiles);\n\n const attachments = files.map((file) => prepareAttachment(file));\n\n addAttachments(attachments);\n },\n [addAttachments, maxAttachments, numberOfAttachments]\n );\n\n const createAttachmentsRef = useRef(createAttachments);\n\n useEffect(() => {\n createAttachmentsRef.current = createAttachments;\n }, [createAttachments]);\n\n const stableCreateAttachments = useCallback((files: File[]) => {\n createAttachmentsRef.current(files);\n }, []);\n\n const editor = useInitial(() =>\n createComposerEditor({\n createAttachments: stableCreateAttachments,\n pasteFilesAsAttachments,\n })\n );\n const onEditorChange = useInitial(makeEventSource) as EventSource<void>;\n\n const validate = useCallback(\n (value: SlateElement[]) => {\n setEmpty(isEditorEmpty(editor, value));\n },\n [editor]\n );\n\n const submit = useCallback(() => {\n if (!canSubmit) {\n return;\n }\n\n // We need to wait for the next frame in some cases like when composing diacritics,\n // we want any native handling to be done first while still being handled on `keydown`.\n requestAnimationFrame(() => {\n if (ref.current) {\n requestSubmit(ref.current);\n }\n });\n }, [canSubmit]);\n\n const clear = useCallback(() => {\n SlateTransforms.delete(editor, {\n at: {\n anchor: SlateEditor.start(editor, []),\n focus: SlateEditor.end(editor, []),\n },\n });\n }, [editor]);\n\n const select = useCallback(() => {\n SlateTransforms.select(editor, SlateEditor.end(editor, []));\n }, [editor]);\n\n const focus = useCallback(\n (resetSelection = true) => {\n try {\n if (!ReactEditor.isFocused(editor)) {\n SlateTransforms.select(\n editor,\n resetSelection || !editor.selection\n ? SlateEditor.end(editor, [])\n : editor.selection\n );\n ReactEditor.focus(editor);\n }\n } catch {\n // Slate's DOM-specific methods will throw if the editor's DOM\n // node no longer exists. This action doesn't make sense on an\n // unmounted editor so we can safely ignore it.\n }\n },\n [editor]\n );\n\n const blur = useCallback(() => {\n try {\n ReactEditor.blur(editor);\n } catch {\n // Slate's DOM-specific methods will throw if the editor's DOM\n // node no longer exists. This action doesn't make sense on an\n // unmounted editor so we can safely ignore it.\n }\n }, [editor]);\n\n const createMention = useCallback(() => {\n if (disabled) {\n return;\n }\n\n focus();\n insertMentionCharacter(editor);\n }, [disabled, editor, focus]);\n\n const insertText = useCallback(\n (text: string) => {\n if (disabled) {\n return;\n }\n\n focus(false);\n insertSlateText(editor, text);\n },\n [disabled, editor, focus]\n );\n\n const attachFiles = useCallback(() => {\n if (disabled) {\n return;\n }\n\n if (fileInputRef.current) {\n fileInputRef.current.click();\n }\n }, [disabled]);\n\n const handleAttachmentsInputChange = useCallback(\n (event: ChangeEvent<HTMLInputElement>) => {\n if (disabled) {\n return;\n }\n\n if (event.target.files) {\n createAttachments(Array.from(event.target.files));\n\n // Reset the input value to allow selecting the same file(s) again\n event.target.value = \"\";\n }\n },\n [createAttachments, disabled]\n );\n\n const onSubmitEnd = useCallback(() => {\n clear();\n blur();\n clearAttachments();\n setSubmitting(false);\n }, [blur, clear, clearAttachments]);\n\n const handleSubmit = useCallback(\n (event: FormEvent<HTMLFormElement>) => {\n if (disabled) {\n return;\n }\n\n // In some situations (e.g. pressing Enter while composing diacritics), it's possible\n // for the form to be submitted as empty even though we already checked whether the\n // editor was empty when handling the key press.\n const isEmpty = isEditorEmpty(editor, editor.children);\n\n // We even prevent the user's `onSubmit` handler from being called if the editor is empty.\n if (isEmpty) {\n event.preventDefault();\n\n return;\n }\n\n onSubmit?.(event);\n\n if (!onComposerSubmit || event.isDefaultPrevented()) {\n event.preventDefault();\n\n return;\n }\n\n const body = composerBodyToCommentBody(\n editor.children as ComposerBodyData\n );\n // Only non-local attachments are included to be submitted.\n const commentAttachments: CommentAttachment[] = attachments\n .filter(\n (attachment) =>\n attachment.type === \"attachment\" ||\n (attachment.type === \"localAttachment\" &&\n attachment.status === \"uploaded\")\n )\n .map((attachment) => {\n return {\n id: attachment.id,\n type: \"attachment\",\n mimeType: attachment.mimeType,\n size: attachment.size,\n name: attachment.name,\n };\n });\n\n const promise = onComposerSubmit(\n { body, attachments: commentAttachments },\n event\n );\n\n event.preventDefault();\n\n if (promise) {\n setSubmitting(true);\n promise.then(onSubmitEnd);\n } else {\n onSubmitEnd();\n }\n },\n [disabled, editor, attachments, onComposerSubmit, onSubmit, onSubmitEnd]\n );\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n const toggleMark = useCallback(\n (mark: ComposerBodyMark) => {\n toggleEditorMark(editor, mark);\n },\n [editor]\n );\n\n useObservable(onEditorChange, () => {\n setMarks(getMarks(editor));\n });\n\n return (\n <ComposerEditorContext.Provider\n value={{\n editor,\n validate,\n setFocused,\n onEditorChange,\n roomId,\n }}\n >\n <ComposerAttachmentsContext.Provider\n value={{\n createAttachments,\n isUploadingAttachments,\n hasMaxAttachments,\n maxAttachments,\n maxAttachmentSize,\n }}\n >\n <ComposerContext.Provider\n value={{\n isDisabled,\n isFocused,\n isEmpty,\n canSubmit,\n submit,\n clear,\n select,\n focus,\n blur,\n createMention,\n insertText,\n attachments,\n attachFiles,\n removeAttachment,\n toggleMark,\n marks,\n }}\n >\n <Component {...props} onSubmit={handleSubmit} ref={mergedRefs}>\n <input\n type=\"file\"\n multiple\n ref={fileInputRef}\n onChange={handleAttachmentsInputChange}\n onClick={stopPropagation}\n tabIndex={-1}\n style={{ display: \"none\" }}\n />\n <Slottable>{children}</Slottable>\n </Component>\n </ComposerContext.Provider>\n </ComposerAttachmentsContext.Provider>\n </ComposerEditorContext.Provider>\n );\n }\n);\n\n/**\n * A button to submit the composer.\n *\n * @example\n * <Composer.Submit>Send</Composer.Submit>\n */\nconst ComposerSubmit = forwardRef<HTMLButtonElement, ComposerSubmitProps>(\n ({ children, disabled, asChild, ...props }, forwardedRef) => {\n const Component = asChild ? Slot : \"button\";\n const { canSubmit, isDisabled: isComposerDisabled } = useComposer();\n const isDisabled = isComposerDisabled || disabled || !canSubmit;\n\n return (\n <Component\n type=\"submit\"\n {...props}\n ref={forwardedRef}\n disabled={isDisabled}\n >\n {children}\n </Component>\n );\n }\n);\n\n/**\n * A button which opens a file picker to create attachments.\n *\n * @example\n * <Composer.AttachFiles>Attach files</Composer.AttachFiles>\n */\nconst ComposerAttachFiles = forwardRef<\n HTMLButtonElement,\n ComposerAttachFilesProps\n>(({ children, onClick, disabled, asChild, ...props }, forwardedRef) => {\n const Component = asChild ? Slot : \"button\";\n const { hasMaxAttachments } = useComposerAttachmentsContext();\n const { isDisabled: isComposerDisabled, attachFiles } = useComposer();\n const isDisabled = isComposerDisabled || hasMaxAttachments || disabled;\n\n const handleClick = useCallback(\n (event: MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n\n if (!event.isDefaultPrevented()) {\n attachFiles();\n }\n },\n [attachFiles, onClick]\n );\n\n return (\n <Component\n type=\"button\"\n {...props}\n onClick={handleClick}\n ref={forwardedRef}\n disabled={isDisabled}\n >\n {children}\n </Component>\n );\n});\n\n/**\n * A drop area which accepts files to create attachments.\n *\n * @example\n * <Composer.AttachmentsDropArea>\n * Drop files here\n * </Composer.AttachmentsDropArea>\n */\nconst ComposerAttachmentsDropArea = forwardRef<\n HTMLDivElement,\n ComposerAttachmentsDropAreaProps\n>(\n (\n {\n onDragEnter,\n onDragLeave,\n onDragOver,\n onDrop,\n disabled,\n asChild,\n ...props\n },\n forwardedRef\n ) => {\n const Component = asChild ? Slot : \"div\";\n const { isDisabled: isComposerDisabled } = useComposer();\n const isDisabled = isComposerDisabled || disabled;\n const [, dropAreaProps] = useComposerAttachmentsDropArea({\n onDragEnter,\n onDragLeave,\n onDragOver,\n onDrop,\n disabled: isDisabled,\n });\n\n return (\n <Component\n {...dropAreaProps}\n data-disabled={isDisabled ? \"\" : undefined}\n {...props}\n ref={forwardedRef}\n />\n );\n }\n);\n\n/**\n * A toggle button which toggles a specific text mark.\n *\n * @example\n * <Composer.MarkToggle mark=\"bold\">\n * Bold\n * </Composer.MarkToggle>\n */\nconst ComposerMarkToggle = forwardRef<\n HTMLButtonElement,\n ComposerMarkToggleProps\n>(\n (\n { children, mark, onValueChange, onClick, asChild, ...props },\n forwardedRef\n ) => {\n const Component = asChild ? Slot : \"button\";\n const { marks, toggleMark } = useComposer();\n\n const handleClick = useCallback(\n (event: MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n\n if (!event.isDefaultPrevented()) {\n toggleMark(mark);\n onValueChange?.(mark);\n }\n },\n [mark, onClick, onValueChange, toggleMark]\n );\n\n return (\n <TogglePrimitive.Root\n asChild\n pressed={marks[mark]}\n onClick={handleClick}\n {...props}\n >\n <Component {...props} ref={forwardedRef}>\n {children}\n </Component>\n </TogglePrimitive.Root>\n );\n }\n);\n\nif (process.env.NODE_ENV !== \"production\") {\n ComposerAttachFiles.displayName = COMPOSER_ATTACH_FILES_NAME;\n ComposerAttachmentsDropArea.displayName = COMPOSER_ATTACHMENTS_DROP_AREA_NAME;\n ComposerEditor.displayName = COMPOSER_EDITOR_NAME;\n ComposerFloatingToolbar.displayName = COMPOSER_FLOATING_TOOLBAR_NAME;\n ComposerForm.displayName = COMPOSER_FORM_NAME;\n ComposerMention.displayName = COMPOSER_MENTION_NAME;\n ComposerLink.displayName = COMPOSER_LINK_NAME;\n ComposerSubmit.displayName = COMPOSER_SUBMIT_NAME;\n ComposerSuggestions.displayName = COMPOSER_SUGGESTIONS_NAME;\n ComposerSuggestionsList.displayName = COMPOSER_SUGGESTIONS_LIST_NAME;\n ComposerSuggestionsListItem.displayName = COMPOSER_SUGGESTIONS_LIST_ITEM_NAME;\n ComposerMarkToggle.displayName = COMPOSER_MARK_TOGGLE_NAME;\n}\n\n// NOTE: Every export from this file will be available publicly as Composer.*\nexport {\n ComposerAttachFiles as AttachFiles,\n ComposerAttachmentsDropArea as AttachmentsDropArea,\n ComposerEditor as Editor,\n ComposerFloatingToolbar as FloatingToolbar,\n ComposerForm as Form,\n ComposerLink as Link,\n ComposerMarkToggle as MarkToggle,\n ComposerMention as Mention,\n ComposerSubmit as Submit,\n ComposerSuggestions as Suggestions,\n ComposerSuggestionsList as SuggestionsList,\n ComposerSuggestionsListItem as SuggestionsListItem,\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAqJA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAsC;AAC3B;AAEX;AAEA;AAA8B;AAC5B;AAEF;AAIE;AAAO;AACL;AACE;AACE;AACE;AACE;AACoD;AAChD;AACA;AACD;AACH;AACF;AACF;AACF;AACF;AAEJ;AAEA;AAAsC;AACpC;AACA;AACA;AAEF;AACE;AAEA;AACG;AAAS;AACP;AACE;AAAwB;AAAI;AAC3B;AACH;AAAA;AAGP;AAEA;AAAmC;AACjC;AACA;AACA;AAEF;AACE;AAAa;AACiC;AAChC;AAGd;AACG;AAAS;AACP;AAAK;AAAa;AAAS;AAGlC;AAEA;AAAiD;AAC/C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACW;AACX;AAEF;AACE;AACA;AACA;AACA;AACA;AACA;AAEA;AAAM;AAC8B;AAClC;AACA;AACA;AACA;AACA;AACyB;AACzB;AACA;AACW;AACL;AAGR;AACE;AAAkD;AAGpD;AACE;AACE;AAEA;AAAA;AAGF;AACA;AAA6B;AAG/B;AACG;AAEI;AACQ;AACL;AACA;AACe;AACG;AAClB;AACA;AACA;AACK;AACP;AAEC;AACM;AACM;AACJ;AACK;AACL;AACC;AAGF;AACM;AACF;AACV;AAEC;AACC;AACA;AACF;AACF;AAEA;AAGV;AAEA;AAA8C;AAC5C;AACW;AACX;AACA;AACA;AAEF;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAM;AAC8B;AAClC;AACA;AACA;AACA;AACA;AACyB;AACnB;AACN;AACA;AACW;AACL;AAGR;AACE;AACE;AAAA;AAGF;AACA;AAEA;AACA;AAEA;AACE;AACA;AAAyD;AAC3D;AAGF;AAEE;AAGA;AACE;AAGA;AAME;AACA;AAAiB;AAEjB;AAEA;AACA;AAAqB;AACvB;AACD;AAGH;AACG;AAEI;AACQ;AACL;AACA;AACA;AACK;AACP;AAEC;AACM;AACM;AACJ;AACK;AACL;AACC;AAGF;AACM;AACF;AACV;AAEiB;AACnB;AAEA;AAGV;AAWM;AAIJ;AACA;AACA;AAAM;AACJ;AACK;AACL;AACA;AAEF;AACA;AAAsB;AACgC;AAC1C;AAEZ;AACA;AAEA;AAA0B;AAEtB;AAEA;AACA;AAAsB;AACxB;AACc;AAGhB;AACG;AACC;AACK;AACL;AACW;AACP;AACW;AACkB;AACtB;AACC;AACL;AACI;AACM;AACL;AACC;AACR;AACL;AACK;AAEJ;AAGP;AAEA;AAA+B;AAC7B;AACA;AAEF;AAEE;AAEA;AAAsB;AAElB;AACG;AACC;AACK;AACP;AAEC;AAEH;AACG;AACC;AACK;AAGP;AAGF;AACG;AAAM;AAA0C;AAC9C;AACH;AAGF;AAAO;AAEb;AAGA;AACE;AACE;AAAY;AAAQ;AAAS;AAG/B;AACE;AAAY;AAAI;AAAS;AAG3B;AACE;AAAY;AAAG;AAAS;AAG1B;AACE;AAAY;AAAM;AAAS;AAG7B;AAAQ;AAAS;AAAa;AAChC;AAEA;AAAmC;AACjC;AAEF;AACE;AAEA;AACG;AAAS;AAAY;AAA+B;AAClD;AAGP;AAQA;AAAwB;AAEpB;AACA;AAEA;AACG;AAC8B;AACzB;AACC;AAEJ;AACH;AAGN;AAQA;AAAqB;AAEjB;AAEA;AACG;AACQ;AACH;AACA;AACC;AAEJ;AACH;AAGN;AAKM;AAIJ;AACA;AACA;AAAM;AACC;AACL;AACA;AAEF;AACA;AAAsB;AACgC;AAC1C;AAEZ;AACA;AAEA;AACG;AACC;AACI;AAC6B;AACtB;AACC;AACL;AACI;AACM;AACJ;AACA;AACR;AACL;AACK;AAEJ;AAGP;AAcM;AAIJ;AACA;AAEA;AACG;AACM;AACL;AACW;AACP;AACC;AAEJ;AAGP;AAUA;AAAoC;AAKhC;AACE;AACA;AACA;AACA;AACA;AACA;AACG;AAIL;AACA;AACA;AAEA;AACA;AAAmB;AACO;AACH;AAGvB;AAEA;AACE;AACE;AAA+C;AACjD;AAGF;AAA0B;AAEtB;AAEA;AACE;AAAsB;AACxB;AACF;AACuC;AAGzC;AAA0B;AAEtB;AAEA;AACA;AAAsB;AACxB;AACc;AAGhB;AAAoB;AAEhB;AAEA;AAEA;AACA;AAEA;AACE;AAAkB;AACpB;AACF;AAC6B;AAG/B;AACG;AACM;AACL;AAC6B;AACA;AACd;AACA;AACN;AACL;AACC;AAEJ;AACH;AAGN;AAEA;AAA0D;AAEtD;AAAQ;AAAa;AAAa;AAAS;AAC7C;AAEE;AACG;AACE;AAAA;AACA;AAAA;AACH;AAEJ;AAEE;AACG;AACE;AAEI;AAAgD;AAC9C;AAEJ;AACH;AAEA;AAER;AAQA;AAAuB;AAEnB;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACG;AAIL;AACA;AAEA;AAAM;AACJ;AACA;AACA;AACA;AACA;AACY;AACZ;AAEF;AACA;AACA;AACE;AAA4C;AAE9C;AAA+D;AACV;AACxC;AAGb;AAIA;AACA;AAGA;AACA;AAA2B;AACzB;AACc;AAEhB;AAAM;AACJ;AACA;AACA;AACA;AAEF;AACA;AACA;AACA;AAA8B;AAEoC;AAC7D;AAGL;AAAsB;AAElB;AACG;AAAsB;AAAkB;AAAgB;AAAO;AAEpE;AACc;AAGhB;AAAqB;AAEjB;AAKA;AAAsB;AACxB;AACyB;AAG3B;AAAsB;AAElB;AACE;AAAA;AAGF;AACA;AACA;AACA;AAAmC;AACrC;AACwD;AAG1D;AAAsB;AAElB;AAEA;AACE;AAAA;AAIF;AACE;AAA6B;AAI/B;AACE;AAA2B;AAG7B;AAEE;AACE;AACA;AAAsC;AAIxC;AACE;AACA;AAA0C;AAI5C;AACE;AAEA;AACA;AAAoB;AAItB;AACE;AACA;AACA;AAAmC;AACrC;AAEA;AAEE;AACE;AACA;AAAgC;AAClC;AAIF;AACE;AAAK;AAIP;AAEE;AAEA;AACE;AAAO;AACT;AAIF;AACE;AACA;AAAmB;AAIrB;AACE;AACA;AAA+B;AAIjC;AACE;AACA;AAAiC;AAInC;AACE;AACA;AAAwC;AAI1C;AACE;AACA;AAA+B;AACjC;AACF;AACF;AACA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF;AAGF;AAAoB;AAEhB;AAEA;AACE;AAAe;AACjB;AACF;AACoB;AAGtB;AAAmB;AAEf;AAEA;AACE;AAAgB;AAClB;AACF;AACmB;AAGrB;AAAwC;AACX;AACwB;AAErD;AAA2C;AAEvC;AAEA;AACE;AAAuC;AACzC;AACF;AACsD;AAGxD;AAAwC;AAGhC;AACQ;AACe;AACJ;AACA;AACQ;AACvB;AACF;AAGA;AACmB;AACA;AAElB;AACT;AACE;AACA;AACA;AACA;AACA;AACA;AACF;AAGF;AACE;AAA2C;AAI7C;AACE;AACE;AAAM;AACR;AAKF;AACE;AACE;AAAO;AACT;AAGF;AACG;AACC;AACc;AACJ;AAEV;AAAC;AACC;AACuC;AACxB;AACJ;AACgB;AACE;AACzB;AACA;AACM;AACA;AACC;AACF;AACD;AACR;AACY;AACO;AACrB;AAEG;AACC;AACA;AACA;AACgB;AACG;AACV;AACL;AACI;AACM;AACd;AACF;AAGC;AACC;AACI;AACJ;AACA;AACA;AACF;AAAA;AAEJ;AAGN;AAEA;AACA;AAEA;AACE;AAAO;AACC;AACE;AACsB;AACnB;AACA;AACI;AACf;AAEJ;AAWA;AAAqB;AAEjB;AACE;AACA;AACA;AACsB;AACtB;AACwB;AACxB;AACA;AACQ;AACL;AAIL;AACA;AACA;AACA;AACA;AAEA;AACA;AACE;AAAqE;AAIvE;AACA;AAEA;AAAM;AACJ;AACA;AACA;AACA;AACA;AACoD;AACvC;AACb;AAEF;AACA;AAEA;AACE;AAAoC;AAEtC;AACE;AAAoB;AAEtB;AAEA;AACA;AACA;AACA;AAIA;AAIA;AACE;AAAY;AACwB;AACpC;AAGF;AAA0B;AAEtB;AACE;AAAA;AAGF;AAAmC;AACjC;AACiB;AAGnB;AAEA;AAEA;AAA0B;AAC5B;AACoD;AAGtD;AAEA;AACE;AAA+B;AAGjC;AACE;AAAkC;AAGpC;AAAe;AACQ;AACA;AACnB;AACD;AAEH;AAEA;AAAiB;AAEb;AAAqC;AACvC;AACO;AAGT;AACE;AACE;AAAA;AAKF;AACE;AACE;AAAyB;AAC3B;AACD;AAGH;AACE;AAA+B;AACzB;AACkC;AACH;AACnC;AACD;AAGH;AACE;AAA0D;AAG5D;AAAc;AAEV;AACE;AACE;AAAgB;AACd;AAGW;AAEb;AAAwB;AAC1B;AACA;AAIF;AACF;AACO;AAGT;AACE;AACE;AAAuB;AACvB;AAIF;AAGF;AACE;AACE;AAAA;AAGF;AACA;AAA6B;AAG/B;AAAmB;AAEf;AACE;AAAA;AAGF;AACA;AAA4B;AAC9B;AACwB;AAG1B;AACE;AACE;AAAA;AAGF;AACE;AAA2B;AAC7B;AAGF;AAAqC;AAEjC;AACE;AAAA;AAGF;AACE;AAGA;AAAqB;AACvB;AACF;AAC4B;AAG9B;AACE;AACA;AACA;AACA;AAAmB;AAGrB;AAAqB;AAEjB;AACE;AAAA;AAMF;AAGA;AACE;AAEA;AAAA;AAGF;AAEA;AACE;AAEA;AAAA;AAGF;AAAa;AACJ;AAGT;AACG;AAI2B;AAG1B;AAAO;AACU;AACT;AACe;AACJ;AACA;AACnB;AAGJ;AAAgB;AAC0B;AACxC;AAGF;AAEA;AACE;AACA;AAAwB;AAExB;AAAY;AACd;AACF;AACuE;AAGzE;AACE;AAAsB;AAGxB;AAAmB;AAEf;AAA6B;AAC/B;AACO;AAGT;AACE;AAAyB;AAG3B;AACG;AACQ;AACL;AACA;AACA;AACA;AACA;AACF;AAEC;AACQ;AACL;AACA;AACA;AACA;AACA;AACF;AAEC;AACQ;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF;AAEC;AAAc;AAAiB;AAAmB;AACjD;AAAC;AACM;AACG;AACH;AACK;AACD;AACC;AACe;AAC3B;AACC;AAAW;AAAS;AAAA;AACvB;AACF;AACF;AACF;AAGN;AAQA;AAAuB;AAEnB;AACA;AACA;AAEA;AACG;AACM;AACD;AACC;AACK;AAET;AACH;AAGN;AAQM;AAIJ;AACA;AACA;AACA;AAEA;AAAoB;AAEhB;AAEA;AACE;AAAY;AACd;AACF;AACqB;AAGvB;AACG;AACM;AACD;AACK;AACJ;AACK;AAET;AAGP;AAUA;AAAoC;AAKhC;AACE;AACA;AACA;AACA;AACA;AACA;AACG;AAIL;AACA;AACA;AACA;AAAyD;AACvD;AACA;AACA;AACA;AACU;AAGZ;AACG;AACK;AAC6B;AAC7B;AACC;AACP;AAGN;AAUA;AAA2B;AAQvB;AACA;AAEA;AAAoB;AAEhB;AAEA;AACE;AACA;AAAoB;AACtB;AACF;AACyC;AAG3C;AACG;AACQ;AACQ;AACN;AACL;AAEH;AAAc;AAAY;AACxB;AACH;AACF;AAGN;AAEA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF;;"}
@@ -1,19 +1,21 @@
1
- import { inline, flip, hide, shift, limitShift, offset, size, autoUpdate, useFloating } from '@floating-ui/react-dom';
2
- import { makeEventSource, kInternal, HttpError } from '@liveblocks/core';
3
- import { useClient } from '@liveblocks/react';
4
- import { useLayoutEffect } from '@liveblocks/react/_private';
5
- import { useState, useCallback, useMemo, useEffect, useSyncExternalStore } from 'react';
6
- import { FLOATING_ELEMENT_COLLISION_PADDING, FLOATING_ELEMENT_SIDE_OFFSET } from '../../constants.mjs';
7
- import { isComposerBodyAutoLink } from '../../slate/plugins/auto-links.mjs';
8
- import { isComposerBodyCustomLink } from '../../slate/plugins/custom-links.mjs';
9
- import { isComposerBodyMention } from '../../slate/plugins/mentions.mjs';
10
- import { isText } from '../../slate/utils/is-text.mjs';
11
- import { getFiles } from '../../utils/data-transfer.mjs';
12
- import { exists } from '../../utils/exists.mjs';
13
- import { useInitial } from '../../utils/use-initial.mjs';
14
- import { useLatest } from '../../utils/use-latest.mjs';
15
- import { isCommentBodyMention, isCommentBodyLink, isCommentBodyText } from '../Comment/utils.mjs';
16
- import { useComposer, useComposerAttachmentsContext } from './contexts.mjs';
1
+ 'use strict';
2
+
3
+ var reactDom = require('@floating-ui/react-dom');
4
+ var core = require('@liveblocks/core');
5
+ var react$1 = require('@liveblocks/react');
6
+ var _private = require('@liveblocks/react/_private');
7
+ var react = require('react');
8
+ var constants = require('../../constants.cjs');
9
+ var autoLinks = require('../../slate/plugins/auto-links.cjs');
10
+ var customLinks = require('../../slate/plugins/custom-links.cjs');
11
+ var mentions = require('../../slate/plugins/mentions.cjs');
12
+ var isText = require('../../slate/utils/is-text.cjs');
13
+ var dataTransfer = require('../../utils/data-transfer.cjs');
14
+ var exists = require('../../utils/exists.cjs');
15
+ var useInitial = require('../../utils/use-initial.cjs');
16
+ var useLatest = require('../../utils/use-latest.cjs');
17
+ var utils = require('../Comment/utils.cjs');
18
+ var contexts = require('./contexts.cjs');
17
19
 
18
20
  function composerBodyMentionToCommentBodyMention(mention) {
19
21
  return {
@@ -64,25 +66,25 @@ function composerBodyToCommentBody(body) {
64
66
  return null;
65
67
  }
66
68
  const children = block.children.map((inline2) => {
67
- if (isComposerBodyMention(inline2)) {
69
+ if (mentions.isComposerBodyMention(inline2)) {
68
70
  return composerBodyMentionToCommentBodyMention(inline2);
69
71
  }
70
- if (isComposerBodyAutoLink(inline2)) {
72
+ if (autoLinks.isComposerBodyAutoLink(inline2)) {
71
73
  return composerBodyAutoLinkToCommentBodyLink(inline2);
72
74
  }
73
- if (isComposerBodyCustomLink(inline2)) {
75
+ if (customLinks.isComposerBodyCustomLink(inline2)) {
74
76
  return composerBodyCustomLinkToCommentBodyLink(inline2);
75
77
  }
76
- if (isText(inline2)) {
78
+ if (isText.isText(inline2)) {
77
79
  return inline2;
78
80
  }
79
81
  return null;
80
- }).filter(exists);
82
+ }).filter(exists.exists);
81
83
  return {
82
84
  ...block,
83
85
  children
84
86
  };
85
- }).filter(exists)
87
+ }).filter(exists.exists)
86
88
  };
87
89
  }
88
90
  const emptyComposerBody = [];
@@ -95,22 +97,22 @@ function commentBodyToComposerBody(body) {
95
97
  return null;
96
98
  }
97
99
  const children = block.children.map((inline2) => {
98
- if (isCommentBodyMention(inline2)) {
100
+ if (utils.isCommentBodyMention(inline2)) {
99
101
  return commentBodyMentionToComposerBodyMention(inline2);
100
102
  }
101
- if (isCommentBodyLink(inline2)) {
103
+ if (utils.isCommentBodyLink(inline2)) {
102
104
  return commentBodyLinkToComposerBodyLink(inline2);
103
105
  }
104
- if (isCommentBodyText(inline2)) {
106
+ if (utils.isCommentBodyText(inline2)) {
105
107
  return inline2;
106
108
  }
107
109
  return null;
108
- }).filter(exists);
110
+ }).filter(exists.exists);
109
111
  return {
110
112
  ...block,
111
113
  children
112
114
  };
113
- }).filter(exists);
115
+ }).filter(exists.exists);
114
116
  }
115
117
  function getRtlFloatingAlignment(alignment) {
116
118
  switch (alignment) {
@@ -127,10 +129,10 @@ function getSideAndAlignFromFloatingPlacement(placement) {
127
129
  return [side, align];
128
130
  }
129
131
  function useContentZIndex() {
130
- const [content, setContent] = useState(null);
131
- const contentRef = useCallback(setContent, [setContent]);
132
- const [contentZIndex, setContentZIndex] = useState();
133
- useLayoutEffect(() => {
132
+ const [content, setContent] = react.useState(null);
133
+ const contentRef = react.useCallback(setContent, [setContent]);
134
+ const [contentZIndex, setContentZIndex] = react.useState();
135
+ _private.useLayoutEffect(() => {
134
136
  if (content) {
135
137
  setContentZIndex(window.getComputedStyle(content).zIndex);
136
138
  }
@@ -144,20 +146,20 @@ function useFloatingWithOptions({
144
146
  dir,
145
147
  open
146
148
  }) {
147
- const floatingOptions = useMemo(() => {
149
+ const floatingOptions = react.useMemo(() => {
148
150
  const detectOverflowOptions = {
149
- padding: FLOATING_ELEMENT_COLLISION_PADDING
151
+ padding: constants.FLOATING_ELEMENT_COLLISION_PADDING
150
152
  };
151
153
  const middleware = [
152
- type === "range" ? inline(detectOverflowOptions) : null,
153
- flip({ ...detectOverflowOptions, crossAxis: false }),
154
- hide(detectOverflowOptions),
155
- shift({
154
+ type === "range" ? reactDom.inline(detectOverflowOptions) : null,
155
+ reactDom.flip({ ...detectOverflowOptions, crossAxis: false }),
156
+ reactDom.hide(detectOverflowOptions),
157
+ reactDom.shift({
156
158
  ...detectOverflowOptions,
157
- limiter: limitShift()
159
+ limiter: reactDom.limitShift()
158
160
  }),
159
- type === "range" ? offset(FLOATING_ELEMENT_SIDE_OFFSET) : null,
160
- size({
161
+ type === "range" ? reactDom.offset(constants.FLOATING_ELEMENT_SIDE_OFFSET) : null,
162
+ reactDom.size({
161
163
  ...detectOverflowOptions,
162
164
  apply({ availableWidth, availableHeight, elements }) {
163
165
  elements.floating.style.setProperty(
@@ -176,13 +178,13 @@ function useFloatingWithOptions({
176
178
  placement: alignment === "center" ? position : `${position}-${dir === "rtl" ? getRtlFloatingAlignment(alignment) : alignment}`,
177
179
  middleware,
178
180
  whileElementsMounted: (...args) => {
179
- return autoUpdate(...args, {
181
+ return reactDom.autoUpdate(...args, {
180
182
  animationFrame: true
181
183
  });
182
184
  }
183
185
  };
184
186
  }, [alignment, position, dir, type]);
185
- return useFloating({
187
+ return reactDom.useFloating({
186
188
  ...floatingOptions,
187
189
  open
188
190
  });
@@ -194,12 +196,12 @@ function useComposerAttachmentsDropArea({
194
196
  onDrop,
195
197
  disabled
196
198
  }) {
197
- const { isDisabled: isComposerDisabled } = useComposer();
199
+ const { isDisabled: isComposerDisabled } = contexts.useComposer();
198
200
  const isDisabled = isComposerDisabled || disabled;
199
- const { createAttachments } = useComposerAttachmentsContext();
200
- const [isDraggingOver, setDraggingOver] = useState(false);
201
- const latestIsDraggingOver = useLatest(isDraggingOver);
202
- const handleDragEnter = useCallback(
201
+ const { createAttachments } = contexts.useComposerAttachmentsContext();
202
+ const [isDraggingOver, setDraggingOver] = react.useState(false);
203
+ const latestIsDraggingOver = useLatest.useLatest(isDraggingOver);
204
+ const handleDragEnter = react.useCallback(
203
205
  (event) => {
204
206
  onDragEnter?.(event);
205
207
  if (latestIsDraggingOver.current || isDisabled || event.isDefaultPrevented()) {
@@ -215,7 +217,7 @@ function useComposerAttachmentsDropArea({
215
217
  },
216
218
  [onDragEnter, isDisabled]
217
219
  );
218
- const handleDragLeave = useCallback(
220
+ const handleDragLeave = react.useCallback(
219
221
  (event) => {
220
222
  onDragLeave?.(event);
221
223
  if (!latestIsDraggingOver.current || isDisabled || event.isDefaultPrevented()) {
@@ -230,7 +232,7 @@ function useComposerAttachmentsDropArea({
230
232
  },
231
233
  [onDragLeave, isDisabled]
232
234
  );
233
- const handleDragOver = useCallback(
235
+ const handleDragOver = react.useCallback(
234
236
  (event) => {
235
237
  onDragOver?.(event);
236
238
  if (isDisabled || event.isDefaultPrevented()) {
@@ -241,7 +243,7 @@ function useComposerAttachmentsDropArea({
241
243
  },
242
244
  [onDragOver, isDisabled]
243
245
  );
244
- const handleDrop = useCallback(
246
+ const handleDrop = react.useCallback(
245
247
  (event) => {
246
248
  onDrop?.(event);
247
249
  if (!latestIsDraggingOver.current || isDisabled || event.isDefaultPrevented()) {
@@ -250,7 +252,7 @@ function useComposerAttachmentsDropArea({
250
252
  event.preventDefault();
251
253
  event.stopPropagation();
252
254
  setDraggingOver(false);
253
- const files = getFiles(event.dataTransfer);
255
+ const files = dataTransfer.getFiles(event.dataTransfer);
254
256
  createAttachments(files);
255
257
  },
256
258
  [onDrop, isDisabled, createAttachments]
@@ -278,7 +280,7 @@ class AttachmentTooLargeError extends Error {
278
280
  function createComposerAttachmentsManager(client, roomId, options) {
279
281
  const attachments = /* @__PURE__ */ new Map();
280
282
  const abortControllers = /* @__PURE__ */ new Map();
281
- const eventSource = makeEventSource();
283
+ const eventSource = core.makeEventSource();
282
284
  let cachedSnapshot = null;
283
285
  function notifySubscribers() {
284
286
  cachedSnapshot = null;
@@ -287,7 +289,7 @@ function createComposerAttachmentsManager(client, roomId, options) {
287
289
  function uploadAttachment(attachment) {
288
290
  const abortController = new AbortController();
289
291
  abortControllers.set(attachment.id, abortController);
290
- client[kInternal].httpClient.uploadAttachment({
292
+ client[core.kInternal].httpClient.uploadAttachment({
291
293
  roomId,
292
294
  attachment,
293
295
  signal: abortController.signal
@@ -302,7 +304,7 @@ function createComposerAttachmentsManager(client, roomId, options) {
302
304
  attachments.set(attachment.id, {
303
305
  ...attachment,
304
306
  status: "error",
305
- error: error instanceof HttpError && error.status === 413 ? new AttachmentTooLargeError("File is too large.", "server") : error
307
+ error: error instanceof core.HttpError && error.status === 413 ? new AttachmentTooLargeError("File is too large.", "server") : error
306
308
  });
307
309
  notifySubscribers();
308
310
  }
@@ -373,30 +375,30 @@ function preventBeforeUnloadDefault(event) {
373
375
  event.preventDefault();
374
376
  }
375
377
  function useComposerAttachmentsManager(defaultAttachments, options) {
376
- const client = useClient();
377
- const frozenDefaultAttachments = useInitial(defaultAttachments);
378
- const frozenAttachmentsManager = useInitial(
378
+ const client = react$1.useClient();
379
+ const frozenDefaultAttachments = useInitial.useInitial(defaultAttachments);
380
+ const frozenAttachmentsManager = useInitial.useInitial(
379
381
  () => createComposerAttachmentsManager(client, options.roomId, options)
380
382
  );
381
- useEffect(() => {
383
+ react.useEffect(() => {
382
384
  frozenAttachmentsManager.addAttachments(frozenDefaultAttachments);
383
385
  }, [frozenDefaultAttachments, frozenAttachmentsManager]);
384
- useEffect(() => {
386
+ react.useEffect(() => {
385
387
  return () => {
386
388
  frozenAttachmentsManager.clear();
387
389
  };
388
390
  }, [frozenAttachmentsManager]);
389
- const attachments = useSyncExternalStore(
391
+ const attachments = react.useSyncExternalStore(
390
392
  frozenAttachmentsManager.subscribe,
391
393
  frozenAttachmentsManager.getSnapshot,
392
394
  frozenAttachmentsManager.getSnapshot
393
395
  );
394
- const isUploadingAttachments = useMemo(() => {
396
+ const isUploadingAttachments = react.useMemo(() => {
395
397
  return attachments.some(
396
398
  (attachment) => attachment.type === "localAttachment" && attachment.status === "uploading"
397
399
  );
398
400
  }, [attachments]);
399
- useEffect(() => {
401
+ react.useEffect(() => {
400
402
  if (!isUploadingAttachments) {
401
403
  return;
402
404
  }
@@ -414,5 +416,18 @@ function useComposerAttachmentsManager(defaultAttachments, options) {
414
416
  };
415
417
  }
416
418
 
417
- export { AttachmentTooLargeError, commentBodyLinkToComposerBodyLink, commentBodyMentionToComposerBodyMention, commentBodyToComposerBody, composerBodyAutoLinkToCommentBodyLink, composerBodyCustomLinkToCommentBodyLink, composerBodyMentionToCommentBodyMention, composerBodyToCommentBody, getRtlFloatingAlignment, getSideAndAlignFromFloatingPlacement, useComposerAttachmentsDropArea, useComposerAttachmentsManager, useContentZIndex, useFloatingWithOptions };
418
- //# sourceMappingURL=utils.mjs.map
419
+ exports.AttachmentTooLargeError = AttachmentTooLargeError;
420
+ exports.commentBodyLinkToComposerBodyLink = commentBodyLinkToComposerBodyLink;
421
+ exports.commentBodyMentionToComposerBodyMention = commentBodyMentionToComposerBodyMention;
422
+ exports.commentBodyToComposerBody = commentBodyToComposerBody;
423
+ exports.composerBodyAutoLinkToCommentBodyLink = composerBodyAutoLinkToCommentBodyLink;
424
+ exports.composerBodyCustomLinkToCommentBodyLink = composerBodyCustomLinkToCommentBodyLink;
425
+ exports.composerBodyMentionToCommentBodyMention = composerBodyMentionToCommentBodyMention;
426
+ exports.composerBodyToCommentBody = composerBodyToCommentBody;
427
+ exports.getRtlFloatingAlignment = getRtlFloatingAlignment;
428
+ exports.getSideAndAlignFromFloatingPlacement = getSideAndAlignFromFloatingPlacement;
429
+ exports.useComposerAttachmentsDropArea = useComposerAttachmentsDropArea;
430
+ exports.useComposerAttachmentsManager = useComposerAttachmentsManager;
431
+ exports.useContentZIndex = useContentZIndex;
432
+ exports.useFloatingWithOptions = useFloatingWithOptions;
433
+ //# sourceMappingURL=utils.cjs.map