@flanksource/clicky-ui 0.3.29 → 0.3.31

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 (346) hide show
  1. package/dist/ai.cjs +48 -3
  2. package/dist/ai.cjs.map +1 -1
  3. package/dist/ai.js +46 -1
  4. package/dist/ai.js.map +1 -1
  5. package/dist/comments/CommentCard.cjs +110 -262
  6. package/dist/comments/CommentCard.cjs.map +1 -1
  7. package/dist/comments/CommentCard.d.ts +3 -1
  8. package/dist/comments/CommentCard.d.ts.map +1 -1
  9. package/dist/comments/CommentCard.js +105 -257
  10. package/dist/comments/CommentCard.js.map +1 -1
  11. package/dist/comments/CommentCardParts.cjs +95 -0
  12. package/dist/comments/CommentCardParts.cjs.map +1 -0
  13. package/dist/comments/CommentCardParts.d.ts +17 -0
  14. package/dist/comments/CommentCardParts.d.ts.map +1 -0
  15. package/dist/comments/CommentCardParts.js +95 -0
  16. package/dist/comments/CommentCardParts.js.map +1 -0
  17. package/dist/comments/CommentSidePanel.cjs +14 -7
  18. package/dist/comments/CommentSidePanel.cjs.map +1 -1
  19. package/dist/comments/CommentSidePanel.d.ts +3 -1
  20. package/dist/comments/CommentSidePanel.d.ts.map +1 -1
  21. package/dist/comments/CommentSidePanel.js +14 -7
  22. package/dist/comments/CommentSidePanel.js.map +1 -1
  23. package/dist/comments/CommentThread.cjs +2 -0
  24. package/dist/comments/CommentThread.cjs.map +1 -1
  25. package/dist/comments/CommentThread.d.ts +2 -1
  26. package/dist/comments/CommentThread.d.ts.map +1 -1
  27. package/dist/comments/CommentThread.js +2 -0
  28. package/dist/comments/CommentThread.js.map +1 -1
  29. package/dist/comments/CommentThreadList.cjs +50 -34
  30. package/dist/comments/CommentThreadList.cjs.map +1 -1
  31. package/dist/comments/CommentThreadList.d.ts +3 -1
  32. package/dist/comments/CommentThreadList.d.ts.map +1 -1
  33. package/dist/comments/CommentThreadList.js +50 -34
  34. package/dist/comments/CommentThreadList.js.map +1 -1
  35. package/dist/components/ComboboxMenu.cjs +4 -1
  36. package/dist/components/ComboboxMenu.cjs.map +1 -1
  37. package/dist/components/ComboboxMenu.d.ts.map +1 -1
  38. package/dist/components/ComboboxMenu.js +5 -2
  39. package/dist/components/ComboboxMenu.js.map +1 -1
  40. package/dist/components/ComboboxTags.cjs +5 -1
  41. package/dist/components/ComboboxTags.cjs.map +1 -1
  42. package/dist/components/ComboboxTags.d.ts.map +1 -1
  43. package/dist/components/ComboboxTags.js +6 -2
  44. package/dist/components/ComboboxTags.js.map +1 -1
  45. package/dist/components/ConnectionLoggingPolicy.cjs +24 -35
  46. package/dist/components/ConnectionLoggingPolicy.cjs.map +1 -1
  47. package/dist/components/ConnectionLoggingPolicy.d.ts.map +1 -1
  48. package/dist/components/ConnectionLoggingPolicy.js +24 -35
  49. package/dist/components/ConnectionLoggingPolicy.js.map +1 -1
  50. package/dist/components/DateField.d.ts +1 -1
  51. package/dist/components/DatePicker.d.ts +1 -1
  52. package/dist/components/DateTimePicker.d.ts +1 -1
  53. package/dist/components/MultiSelect.cjs.map +1 -1
  54. package/dist/components/MultiSelect.d.ts +7 -0
  55. package/dist/components/MultiSelect.d.ts.map +1 -1
  56. package/dist/components/MultiSelect.js.map +1 -1
  57. package/dist/components/filter-bar-multi.cjs +10 -1
  58. package/dist/components/filter-bar-multi.cjs.map +1 -1
  59. package/dist/components/filter-bar-multi.d.ts.map +1 -1
  60. package/dist/components/filter-bar-multi.js +11 -2
  61. package/dist/components/filter-bar-multi.js.map +1 -1
  62. package/dist/components/mdx-editor-callout-model.d.ts +1 -1
  63. package/dist/data/MarkdownEditor.model.d.ts +1 -1
  64. package/dist/data/ai/ChatWindow.catalogs.cjs +11 -5
  65. package/dist/data/ai/ChatWindow.catalogs.cjs.map +1 -1
  66. package/dist/data/ai/ChatWindow.catalogs.d.ts +2 -1
  67. package/dist/data/ai/ChatWindow.catalogs.d.ts.map +1 -1
  68. package/dist/data/ai/ChatWindow.catalogs.js +11 -5
  69. package/dist/data/ai/ChatWindow.catalogs.js.map +1 -1
  70. package/dist/data/ai/ChatWindow.cjs +1 -0
  71. package/dist/data/ai/ChatWindow.cjs.map +1 -1
  72. package/dist/data/ai/ChatWindow.d.ts.map +1 -1
  73. package/dist/data/ai/ChatWindow.js +1 -0
  74. package/dist/data/ai/ChatWindow.js.map +1 -1
  75. package/dist/data/ai/PromptRunEditor/VariablesField.cjs +79 -0
  76. package/dist/data/ai/PromptRunEditor/VariablesField.cjs.map +1 -0
  77. package/dist/data/ai/PromptRunEditor/VariablesField.d.ts +8 -0
  78. package/dist/data/ai/PromptRunEditor/VariablesField.d.ts.map +1 -0
  79. package/dist/data/ai/PromptRunEditor/VariablesField.js +79 -0
  80. package/dist/data/ai/PromptRunEditor/VariablesField.js.map +1 -0
  81. package/dist/data/ai/PromptRunEditor/index.cjs +61 -69
  82. package/dist/data/ai/PromptRunEditor/index.cjs.map +1 -1
  83. package/dist/data/ai/PromptRunEditor/index.d.ts +11 -1
  84. package/dist/data/ai/PromptRunEditor/index.d.ts.map +1 -1
  85. package/dist/data/ai/PromptRunEditor/index.js +61 -69
  86. package/dist/data/ai/PromptRunEditor/index.js.map +1 -1
  87. package/dist/data/ai/PromptRunEditor/model.cjs.map +1 -1
  88. package/dist/data/ai/PromptRunEditor/model.d.ts +2 -0
  89. package/dist/data/ai/PromptRunEditor/model.d.ts.map +1 -1
  90. package/dist/data/ai/PromptRunEditor/model.js.map +1 -1
  91. package/dist/data/ai/SessionViewer.model.cjs +23 -8
  92. package/dist/data/ai/SessionViewer.model.cjs.map +1 -1
  93. package/dist/data/ai/SessionViewer.model.d.ts +8 -0
  94. package/dist/data/ai/SessionViewer.model.d.ts.map +1 -1
  95. package/dist/data/ai/SessionViewer.model.js +23 -8
  96. package/dist/data/ai/SessionViewer.model.js.map +1 -1
  97. package/dist/data/ai/SessionViewer.rows.cjs +9 -1
  98. package/dist/data/ai/SessionViewer.rows.cjs.map +1 -1
  99. package/dist/data/ai/SessionViewer.rows.js +9 -1
  100. package/dist/data/ai/SessionViewer.rows.js.map +1 -1
  101. package/dist/data/ai/SpecRuntimeEditor/ModelSection.cjs +4 -3
  102. package/dist/data/ai/SpecRuntimeEditor/ModelSection.cjs.map +1 -1
  103. package/dist/data/ai/SpecRuntimeEditor/ModelSection.d.ts.map +1 -1
  104. package/dist/data/ai/SpecRuntimeEditor/ModelSection.js +2 -1
  105. package/dist/data/ai/SpecRuntimeEditor/ModelSection.js.map +1 -1
  106. package/dist/data/ai/SpecRuntimeEditor/PermissionModeField.cjs +2 -2
  107. package/dist/data/ai/SpecRuntimeEditor/PermissionModeField.cjs.map +1 -1
  108. package/dist/data/ai/SpecRuntimeEditor/PermissionModeField.js +1 -1
  109. package/dist/data/ai/SpecRuntimeEditor/VerifySection.cjs +24 -2
  110. package/dist/data/ai/SpecRuntimeEditor/VerifySection.cjs.map +1 -1
  111. package/dist/data/ai/SpecRuntimeEditor/VerifySection.d.ts.map +1 -1
  112. package/dist/data/ai/SpecRuntimeEditor/VerifySection.js +25 -3
  113. package/dist/data/ai/SpecRuntimeEditor/VerifySection.js.map +1 -1
  114. package/dist/data/ai/SpecRuntimeEditor/index.cjs +4 -3
  115. package/dist/data/ai/SpecRuntimeEditor/index.cjs.map +1 -1
  116. package/dist/data/ai/SpecRuntimeEditor/index.d.ts.map +1 -1
  117. package/dist/data/ai/SpecRuntimeEditor/index.js +2 -1
  118. package/dist/data/ai/SpecRuntimeEditor/index.js.map +1 -1
  119. package/dist/data/ai/SpecRuntimeEditor/summaries.cjs.map +1 -1
  120. package/dist/data/ai/SpecRuntimeEditor/summaries.d.ts.map +1 -1
  121. package/dist/data/ai/SpecRuntimeEditor/summaries.js.map +1 -1
  122. package/dist/data/ai/SpecRuntimeEditor.model.cjs +4 -0
  123. package/dist/data/ai/SpecRuntimeEditor.model.cjs.map +1 -1
  124. package/dist/data/ai/SpecRuntimeEditor.model.d.ts +4 -0
  125. package/dist/data/ai/SpecRuntimeEditor.model.d.ts.map +1 -1
  126. package/dist/data/ai/SpecRuntimeEditor.model.js +4 -0
  127. package/dist/data/ai/SpecRuntimeEditor.model.js.map +1 -1
  128. package/dist/data/ai/index.d.ts +3 -2
  129. package/dist/data/ai/index.d.ts.map +1 -1
  130. package/dist/data/ai/runtime-profile.cjs.map +1 -1
  131. package/dist/data/ai/runtime-profile.d.ts +9 -7
  132. package/dist/data/ai/runtime-profile.d.ts.map +1 -1
  133. package/dist/data/ai/runtime-profile.js.map +1 -1
  134. package/dist/data/ai/runtime-profiles/OrderedPresetSelect.cjs +111 -0
  135. package/dist/data/ai/runtime-profiles/OrderedPresetSelect.cjs.map +1 -0
  136. package/dist/data/ai/runtime-profiles/OrderedPresetSelect.d.ts +7 -0
  137. package/dist/data/ai/runtime-profiles/OrderedPresetSelect.d.ts.map +1 -0
  138. package/dist/data/ai/runtime-profiles/OrderedPresetSelect.js +111 -0
  139. package/dist/data/ai/runtime-profiles/OrderedPresetSelect.js.map +1 -0
  140. package/dist/data/ai/runtime-profiles/PermissionStrategiesEditor.cjs +313 -0
  141. package/dist/data/ai/runtime-profiles/PermissionStrategiesEditor.cjs.map +1 -0
  142. package/dist/data/ai/runtime-profiles/PermissionStrategiesEditor.d.ts +8 -0
  143. package/dist/data/ai/runtime-profiles/PermissionStrategiesEditor.d.ts.map +1 -0
  144. package/dist/data/ai/runtime-profiles/PermissionStrategiesEditor.js +313 -0
  145. package/dist/data/ai/runtime-profiles/PermissionStrategiesEditor.js.map +1 -0
  146. package/dist/data/ai/runtime-profiles/PermissionStrategyConditionRow.cjs +98 -0
  147. package/dist/data/ai/runtime-profiles/PermissionStrategyConditionRow.cjs.map +1 -0
  148. package/dist/data/ai/runtime-profiles/PermissionStrategyConditionRow.d.ts +11 -0
  149. package/dist/data/ai/runtime-profiles/PermissionStrategyConditionRow.d.ts.map +1 -0
  150. package/dist/data/ai/runtime-profiles/PermissionStrategyConditionRow.js +98 -0
  151. package/dist/data/ai/runtime-profiles/PermissionStrategyConditionRow.js.map +1 -0
  152. package/dist/data/ai/runtime-profiles/PresetSpecEditor.cjs +35 -0
  153. package/dist/data/ai/runtime-profiles/PresetSpecEditor.cjs.map +1 -0
  154. package/dist/data/ai/runtime-profiles/PresetSpecEditor.d.ts +11 -0
  155. package/dist/data/ai/runtime-profiles/PresetSpecEditor.d.ts.map +1 -0
  156. package/dist/data/ai/runtime-profiles/PresetSpecEditor.js +35 -0
  157. package/dist/data/ai/runtime-profiles/PresetSpecEditor.js.map +1 -0
  158. package/dist/data/ai/runtime-profiles/PresetWorkspace.cjs +179 -0
  159. package/dist/data/ai/runtime-profiles/PresetWorkspace.cjs.map +1 -0
  160. package/dist/data/ai/runtime-profiles/PresetWorkspace.d.ts +22 -0
  161. package/dist/data/ai/runtime-profiles/PresetWorkspace.d.ts.map +1 -0
  162. package/dist/data/ai/runtime-profiles/PresetWorkspace.js +179 -0
  163. package/dist/data/ai/runtime-profiles/PresetWorkspace.js.map +1 -0
  164. package/dist/data/ai/runtime-profiles/ProfileSpecEditor.cjs +57 -0
  165. package/dist/data/ai/runtime-profiles/ProfileSpecEditor.cjs.map +1 -0
  166. package/dist/data/ai/runtime-profiles/ProfileSpecEditor.d.ts +18 -0
  167. package/dist/data/ai/runtime-profiles/ProfileSpecEditor.d.ts.map +1 -0
  168. package/dist/data/ai/runtime-profiles/ProfileSpecEditor.js +57 -0
  169. package/dist/data/ai/runtime-profiles/ProfileSpecEditor.js.map +1 -0
  170. package/dist/data/ai/runtime-profiles/ProfileWorkspace.cjs +135 -0
  171. package/dist/data/ai/runtime-profiles/ProfileWorkspace.cjs.map +1 -0
  172. package/dist/data/ai/runtime-profiles/ProfileWorkspace.d.ts +23 -0
  173. package/dist/data/ai/runtime-profiles/ProfileWorkspace.d.ts.map +1 -0
  174. package/dist/data/ai/runtime-profiles/ProfileWorkspace.js +135 -0
  175. package/dist/data/ai/runtime-profiles/ProfileWorkspace.js.map +1 -0
  176. package/dist/data/ai/runtime-profiles/ResolutionInspector.cjs +85 -0
  177. package/dist/data/ai/runtime-profiles/ResolutionInspector.cjs.map +1 -0
  178. package/dist/data/ai/runtime-profiles/ResolutionInspector.d.ts +7 -0
  179. package/dist/data/ai/runtime-profiles/ResolutionInspector.d.ts.map +1 -0
  180. package/dist/data/ai/runtime-profiles/ResolutionInspector.js +85 -0
  181. package/dist/data/ai/runtime-profiles/ResolutionInspector.js.map +1 -0
  182. package/dist/data/ai/runtime-profiles/ResolutionTrace.cjs +42 -0
  183. package/dist/data/ai/runtime-profiles/ResolutionTrace.cjs.map +1 -0
  184. package/dist/data/ai/runtime-profiles/ResolutionTrace.d.ts +6 -0
  185. package/dist/data/ai/runtime-profiles/ResolutionTrace.d.ts.map +1 -0
  186. package/dist/data/ai/runtime-profiles/ResolutionTrace.js +42 -0
  187. package/dist/data/ai/runtime-profiles/ResolutionTrace.js.map +1 -0
  188. package/dist/data/ai/runtime-profiles/RuntimeLibraryList.cjs +93 -0
  189. package/dist/data/ai/runtime-profiles/RuntimeLibraryList.cjs.map +1 -0
  190. package/dist/data/ai/runtime-profiles/RuntimeLibraryList.d.ts +18 -0
  191. package/dist/data/ai/runtime-profiles/RuntimeLibraryList.d.ts.map +1 -0
  192. package/dist/data/ai/runtime-profiles/RuntimeLibraryList.js +93 -0
  193. package/dist/data/ai/runtime-profiles/RuntimeLibraryList.js.map +1 -0
  194. package/dist/data/ai/runtime-profiles/RuntimePersistenceBar.cjs +44 -0
  195. package/dist/data/ai/runtime-profiles/RuntimePersistenceBar.cjs.map +1 -0
  196. package/dist/data/ai/runtime-profiles/RuntimePersistenceBar.d.ts +6 -0
  197. package/dist/data/ai/runtime-profiles/RuntimePersistenceBar.d.ts.map +1 -0
  198. package/dist/data/ai/runtime-profiles/RuntimePersistenceBar.js +44 -0
  199. package/dist/data/ai/runtime-profiles/RuntimePersistenceBar.js.map +1 -0
  200. package/dist/data/ai/runtime-profiles/RuntimeProfilePicker.cjs +198 -0
  201. package/dist/data/ai/runtime-profiles/RuntimeProfilePicker.cjs.map +1 -0
  202. package/dist/data/ai/runtime-profiles/RuntimeProfilePicker.d.ts +12 -0
  203. package/dist/data/ai/runtime-profiles/RuntimeProfilePicker.d.ts.map +1 -0
  204. package/dist/data/ai/runtime-profiles/RuntimeProfilePicker.js +198 -0
  205. package/dist/data/ai/runtime-profiles/RuntimeProfilePicker.js.map +1 -0
  206. package/dist/data/ai/runtime-profiles/RuntimeProfilePicker.model.cjs +97 -0
  207. package/dist/data/ai/runtime-profiles/RuntimeProfilePicker.model.cjs.map +1 -0
  208. package/dist/data/ai/runtime-profiles/RuntimeProfilePicker.model.d.ts +26 -0
  209. package/dist/data/ai/runtime-profiles/RuntimeProfilePicker.model.d.ts.map +1 -0
  210. package/dist/data/ai/runtime-profiles/RuntimeProfilePicker.model.js +97 -0
  211. package/dist/data/ai/runtime-profiles/RuntimeProfilePicker.model.js.map +1 -0
  212. package/dist/data/ai/runtime-profiles/RuntimeProfilesWorkspace.cjs +143 -0
  213. package/dist/data/ai/runtime-profiles/RuntimeProfilesWorkspace.cjs.map +1 -0
  214. package/dist/data/ai/runtime-profiles/RuntimeProfilesWorkspace.d.ts +25 -0
  215. package/dist/data/ai/runtime-profiles/RuntimeProfilesWorkspace.d.ts.map +1 -0
  216. package/dist/data/ai/runtime-profiles/RuntimeProfilesWorkspace.js +143 -0
  217. package/dist/data/ai/runtime-profiles/RuntimeProfilesWorkspace.js.map +1 -0
  218. package/dist/data/ai/runtime-profiles/RuntimeStatusNotice.cjs +41 -0
  219. package/dist/data/ai/runtime-profiles/RuntimeStatusNotice.cjs.map +1 -0
  220. package/dist/data/ai/runtime-profiles/RuntimeStatusNotice.d.ts +8 -0
  221. package/dist/data/ai/runtime-profiles/RuntimeStatusNotice.d.ts.map +1 -0
  222. package/dist/data/ai/runtime-profiles/RuntimeStatusNotice.js +41 -0
  223. package/dist/data/ai/runtime-profiles/RuntimeStatusNotice.js.map +1 -0
  224. package/dist/data/ai/runtime-profiles/index.d.ts +20 -0
  225. package/dist/data/ai/runtime-profiles/index.d.ts.map +1 -0
  226. package/dist/data/ai/runtime-profiles/types.d.ts +50 -0
  227. package/dist/data/ai/runtime-profiles/types.d.ts.map +1 -0
  228. package/dist/data/ai/runtime-profiles/use-permission-catalog.cjs +37 -0
  229. package/dist/data/ai/runtime-profiles/use-permission-catalog.cjs.map +1 -0
  230. package/dist/data/ai/runtime-profiles/use-permission-catalog.d.ts +5 -0
  231. package/dist/data/ai/runtime-profiles/use-permission-catalog.d.ts.map +1 -0
  232. package/dist/data/ai/runtime-profiles/use-permission-catalog.js +37 -0
  233. package/dist/data/ai/runtime-profiles/use-permission-catalog.js.map +1 -0
  234. package/dist/data/ai/runtime-profiles/use-resolution.cjs +43 -0
  235. package/dist/data/ai/runtime-profiles/use-resolution.cjs.map +1 -0
  236. package/dist/data/ai/runtime-profiles/use-resolution.d.ts +4 -0
  237. package/dist/data/ai/runtime-profiles/use-resolution.d.ts.map +1 -0
  238. package/dist/data/ai/runtime-profiles/use-resolution.js +43 -0
  239. package/dist/data/ai/runtime-profiles/use-resolution.js.map +1 -0
  240. package/dist/data/ai/runtime-profiles/use-runtime-families.cjs +38 -0
  241. package/dist/data/ai/runtime-profiles/use-runtime-families.cjs.map +1 -0
  242. package/dist/data/ai/runtime-profiles/use-runtime-families.d.ts +3 -0
  243. package/dist/data/ai/runtime-profiles/use-runtime-families.d.ts.map +1 -0
  244. package/dist/data/ai/runtime-profiles/use-runtime-families.js +38 -0
  245. package/dist/data/ai/runtime-profiles/use-runtime-families.js.map +1 -0
  246. package/dist/data/ai/runtime-profiles/use-runtime-profile-picker.cjs +107 -0
  247. package/dist/data/ai/runtime-profiles/use-runtime-profile-picker.cjs.map +1 -0
  248. package/dist/data/ai/runtime-profiles/use-runtime-profile-picker.d.ts +35 -0
  249. package/dist/data/ai/runtime-profiles/use-runtime-profile-picker.d.ts.map +1 -0
  250. package/dist/data/ai/runtime-profiles/use-runtime-profile-picker.js +107 -0
  251. package/dist/data/ai/runtime-profiles/use-runtime-profile-picker.js.map +1 -0
  252. package/dist/data/ai/use-session-scroll.cjs.map +1 -1
  253. package/dist/data/ai/use-session-scroll.d.ts +2 -2
  254. package/dist/data/ai/use-session-scroll.d.ts.map +1 -1
  255. package/dist/data/ai/use-session-scroll.js.map +1 -1
  256. package/dist/data/badge-variants.d.ts +1 -1
  257. package/dist/data/runtime/RuntimeBar.cjs +3 -2
  258. package/dist/data/runtime/RuntimeBar.cjs.map +1 -1
  259. package/dist/data/runtime/RuntimeBar.d.ts.map +1 -1
  260. package/dist/data/runtime/RuntimeBar.js +3 -2
  261. package/dist/data/runtime/RuntimeBar.js.map +1 -1
  262. package/dist/data/runtime/runtime-field-support.cjs +3 -3
  263. package/dist/data/runtime/runtime-field-support.cjs.map +1 -1
  264. package/dist/data/runtime/runtime-field-support.js +1 -1
  265. package/dist/data/runtime/runtime-mode.cjs +14 -47
  266. package/dist/data/runtime/runtime-mode.cjs.map +1 -1
  267. package/dist/data/runtime/runtime-mode.d.ts +5 -7
  268. package/dist/data/runtime/runtime-mode.d.ts.map +1 -1
  269. package/dist/data/runtime/runtime-mode.js +7 -39
  270. package/dist/data/runtime/runtime-mode.js.map +1 -1
  271. package/dist/data/test-runner/TestRunner.cjs +6 -4
  272. package/dist/data/test-runner/TestRunner.cjs.map +1 -1
  273. package/dist/data/test-runner/TestRunner.d.ts +10 -1
  274. package/dist/data/test-runner/TestRunner.d.ts.map +1 -1
  275. package/dist/data/test-runner/TestRunner.js +6 -4
  276. package/dist/data/test-runner/TestRunner.js.map +1 -1
  277. package/dist/data/verification/VerificationResults.cjs +99 -0
  278. package/dist/data/verification/VerificationResults.cjs.map +1 -0
  279. package/dist/data/verification/VerificationResults.d.ts +27 -0
  280. package/dist/data/verification/VerificationResults.d.ts.map +1 -0
  281. package/dist/data/verification/VerificationResults.js +99 -0
  282. package/dist/data/verification/VerificationResults.js.map +1 -0
  283. package/dist/data/verification/adapterViews.cjs +116 -0
  284. package/dist/data/verification/adapterViews.cjs.map +1 -0
  285. package/dist/data/verification/adapterViews.d.ts +13 -0
  286. package/dist/data/verification/adapterViews.d.ts.map +1 -0
  287. package/dist/data/verification/adapterViews.js +116 -0
  288. package/dist/data/verification/adapterViews.js.map +1 -0
  289. package/dist/data/verification/adapters.cjs +26 -0
  290. package/dist/data/verification/adapters.cjs.map +1 -0
  291. package/dist/data/verification/adapters.d.ts +6 -0
  292. package/dist/data/verification/adapters.d.ts.map +1 -0
  293. package/dist/data/verification/adapters.js +26 -0
  294. package/dist/data/verification/adapters.js.map +1 -0
  295. package/dist/data/verification/index.d.ts +5 -0
  296. package/dist/data/verification/index.d.ts.map +1 -0
  297. package/dist/data/verification/verify-report.cjs +58 -0
  298. package/dist/data/verification/verify-report.cjs.map +1 -0
  299. package/dist/data/verification/verify-report.d.ts +96 -0
  300. package/dist/data/verification/verify-report.d.ts.map +1 -0
  301. package/dist/data/verification/verify-report.js +58 -0
  302. package/dist/data/verification/verify-report.js.map +1 -0
  303. package/dist/data/verification/verifyReportTests.cjs +83 -0
  304. package/dist/data/verification/verifyReportTests.cjs.map +1 -0
  305. package/dist/data/verification/verifyReportTests.d.ts +13 -0
  306. package/dist/data/verification/verifyReportTests.d.ts.map +1 -0
  307. package/dist/data/verification/verifyReportTests.js +83 -0
  308. package/dist/data/verification/verifyReportTests.js.map +1 -0
  309. package/dist/data/version-info.cjs +3 -3
  310. package/dist/data/version-info.js +3 -3
  311. package/dist/data.cjs +10 -0
  312. package/dist/data.cjs.map +1 -1
  313. package/dist/data.d.ts +1 -0
  314. package/dist/data.d.ts.map +1 -1
  315. package/dist/data.js +10 -0
  316. package/dist/data.js.map +1 -1
  317. package/dist/index.cjs +62 -0
  318. package/dist/index.cjs.map +1 -1
  319. package/dist/index.js +62 -0
  320. package/dist/index.js.map +1 -1
  321. package/dist/lib/permission-strategies.cjs +155 -0
  322. package/dist/lib/permission-strategies.cjs.map +1 -0
  323. package/dist/lib/permission-strategies.d.ts +35 -0
  324. package/dist/lib/permission-strategies.d.ts.map +1 -0
  325. package/dist/lib/permission-strategies.js +155 -0
  326. package/dist/lib/permission-strategies.js.map +1 -0
  327. package/dist/lib/runtime-family.cjs +51 -0
  328. package/dist/lib/runtime-family.cjs.map +1 -0
  329. package/dist/lib/runtime-family.d.ts +25 -0
  330. package/dist/lib/runtime-family.d.ts.map +1 -0
  331. package/dist/lib/runtime-family.js +51 -0
  332. package/dist/lib/runtime-family.js.map +1 -0
  333. package/dist/lib/runtime-profile-model.cjs +129 -0
  334. package/dist/lib/runtime-profile-model.cjs.map +1 -0
  335. package/dist/lib/runtime-profile-model.d.ts +30 -0
  336. package/dist/lib/runtime-profile-model.d.ts.map +1 -0
  337. package/dist/lib/runtime-profile-model.js +129 -0
  338. package/dist/lib/runtime-profile-model.js.map +1 -0
  339. package/dist/styles.css +1 -1
  340. package/dist/utils.cjs +52 -0
  341. package/dist/utils.cjs.map +1 -1
  342. package/dist/utils.d.ts +5 -0
  343. package/dist/utils.d.ts.map +1 -1
  344. package/dist/utils.js +53 -1
  345. package/dist/utils.js.map +1 -1
  346. package/package.json +1 -1
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const jsxRuntime = require("react/jsx-runtime");
4
+ const Badge = require("../data/Badge.cjs");
5
+ const utils = require("../lib/utils.cjs");
6
+ const commentUtils = require("./comment-utils.cjs");
7
+ const UiThumbsUp = require("../icons/components/UiThumbsUp.cjs");
8
+ const UiThumbsDown = require("../icons/components/UiThumbsDown.cjs");
9
+ function RatingChip({ rating }) {
10
+ if (!rating) return null;
11
+ const positive = rating === "positive";
12
+ return /* @__PURE__ */ jsxRuntime.jsx(
13
+ Badge.Badge,
14
+ {
15
+ variant: "soft",
16
+ tone: positive ? "success" : "danger",
17
+ size: "xs",
18
+ icon: positive ? UiThumbsUp.UiThumbsUp : UiThumbsDown.UiThumbsDown,
19
+ children: positive ? "Positive rating" : "Negative rating"
20
+ }
21
+ );
22
+ }
23
+ function FacetBadges({
24
+ comment,
25
+ config,
26
+ compact
27
+ }) {
28
+ const chips = (config.facets ?? []).flatMap((facet) => {
29
+ var _a;
30
+ const option = commentUtils.resolveFacetOption(facet, (_a = comment.facets) == null ? void 0 : _a[facet.key]);
31
+ if (!option) return [];
32
+ return [
33
+ /* @__PURE__ */ jsxRuntime.jsx(
34
+ Badge.Badge,
35
+ {
36
+ variant: "soft",
37
+ tone: commentUtils.toneToBadgeTone(option.tone),
38
+ size: "xs",
39
+ children: compact ? option.short ?? option.label : option.label
40
+ },
41
+ facet.key
42
+ )
43
+ ];
44
+ });
45
+ return chips.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: chips }) : null;
46
+ }
47
+ function ChecklistChips({
48
+ comment,
49
+ onChecklistToggle
50
+ }) {
51
+ var _a;
52
+ if (!((_a = comment.checklist) == null ? void 0 : _a.length)) return null;
53
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1", children: comment.checklist.map((item, index) => {
54
+ const done = /done|complete|resolved/i.test(item.status);
55
+ const active = /progress|doing/i.test(item.status);
56
+ return /* @__PURE__ */ jsxRuntime.jsx(
57
+ "button",
58
+ {
59
+ type: "button",
60
+ onClick: () => onChecklistToggle == null ? void 0 : onChecklistToggle(index),
61
+ disabled: !onChecklistToggle,
62
+ className: utils.cn(
63
+ "inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[10px] transition-opacity",
64
+ onChecklistToggle && "cursor-pointer hover:opacity-80",
65
+ done ? "bg-green-100 text-green-800 line-through dark:bg-green-500/20 dark:text-green-300" : active ? "bg-yellow-100 text-yellow-800 dark:bg-yellow-500/20 dark:text-yellow-300" : "bg-muted text-muted-foreground"
66
+ ),
67
+ children: item.label
68
+ },
69
+ index
70
+ );
71
+ }) });
72
+ }
73
+ function RefChips({ comment }) {
74
+ var _a;
75
+ if (!((_a = comment.refs) == null ? void 0 : _a.length)) return null;
76
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1.5", children: comment.refs.map((group, index) => /* @__PURE__ */ jsxRuntime.jsxs(
77
+ "span",
78
+ {
79
+ className: "inline-flex items-center gap-1 rounded bg-muted px-1.5 py-0.5 text-[10px] text-muted-foreground",
80
+ children: [
81
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-medium", children: [
82
+ group.label,
83
+ ":"
84
+ ] }),
85
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: group.mono ? "font-mono" : void 0, children: group.items.join(", ") })
86
+ ]
87
+ },
88
+ index
89
+ )) });
90
+ }
91
+ exports.ChecklistChips = ChecklistChips;
92
+ exports.FacetBadges = FacetBadges;
93
+ exports.RatingChip = RatingChip;
94
+ exports.RefChips = RefChips;
95
+ //# sourceMappingURL=CommentCardParts.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CommentCardParts.cjs","sources":["../../src/comments/CommentCardParts.tsx"],"sourcesContent":["import { Badge } from \"../data/Badge\";\nimport { cn } from \"../lib/utils\";\nimport { UiThumbsDown, UiThumbsUp } from \"../icons\";\nimport { resolveFacetOption, toneToBadgeTone } from \"./comment-utils\";\nimport type { Comment, CommentConfig, CommentRating } from \"./comment-types\";\n\nexport function RatingChip({ rating }: { rating: CommentRating | undefined }) {\n if (!rating) return null;\n const positive = rating === \"positive\";\n return (\n <Badge\n variant=\"soft\"\n tone={positive ? \"success\" : \"danger\"}\n size=\"xs\"\n icon={positive ? UiThumbsUp : UiThumbsDown}\n >\n {positive ? \"Positive rating\" : \"Negative rating\"}\n </Badge>\n );\n}\n\nexport function FacetBadges({\n comment,\n config,\n compact,\n}: {\n comment: Comment;\n config: CommentConfig;\n compact?: boolean;\n}) {\n const chips = (config.facets ?? []).flatMap((facet) => {\n const option = resolveFacetOption(facet, comment.facets?.[facet.key]);\n if (!option) return [];\n return [\n <Badge\n key={facet.key}\n variant=\"soft\"\n tone={toneToBadgeTone(option.tone)}\n size=\"xs\"\n >\n {compact ? (option.short ?? option.label) : option.label}\n </Badge>,\n ];\n });\n return chips.length > 0 ? <>{chips}</> : null;\n}\n\nexport function ChecklistChips({\n comment,\n onChecklistToggle,\n}: {\n comment: Comment;\n onChecklistToggle?: (index: number) => void;\n}) {\n if (!comment.checklist?.length) return null;\n return (\n <div className=\"flex flex-wrap gap-1\">\n {comment.checklist.map((item, index) => {\n const done = /done|complete|resolved/i.test(item.status);\n const active = /progress|doing/i.test(item.status);\n return (\n <button\n key={index}\n type=\"button\"\n onClick={() => onChecklistToggle?.(index)}\n disabled={!onChecklistToggle}\n className={cn(\n \"inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[10px] transition-opacity\",\n onChecklistToggle && \"cursor-pointer hover:opacity-80\",\n done\n ? \"bg-green-100 text-green-800 line-through dark:bg-green-500/20 dark:text-green-300\"\n : active\n ? \"bg-yellow-100 text-yellow-800 dark:bg-yellow-500/20 dark:text-yellow-300\"\n : \"bg-muted text-muted-foreground\",\n )}\n >\n {item.label}\n </button>\n );\n })}\n </div>\n );\n}\n\nexport function RefChips({ comment }: { comment: Comment }) {\n if (!comment.refs?.length) return null;\n return (\n <div className=\"flex flex-wrap gap-1.5\">\n {comment.refs.map((group, index) => (\n <span\n key={index}\n className=\"inline-flex items-center gap-1 rounded bg-muted px-1.5 py-0.5 text-[10px] text-muted-foreground\"\n >\n <span className=\"font-medium\">{group.label}:</span>\n <span className={group.mono ? \"font-mono\" : undefined}>\n {group.items.join(\", \")}\n </span>\n </span>\n ))}\n </div>\n );\n}\n"],"names":["jsx","Badge","UiThumbsUp","UiThumbsDown","resolveFacetOption","toneToBadgeTone","Fragment","cn","jsxs"],"mappings":";;;;;;;;AAMO,SAAS,WAAW,EAAE,UAAiD;AAC5E,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,WAAW,WAAW;AAC5B,SACEA,2BAAAA;AAAAA,IAACC,MAAAA;AAAAA,IAAA;AAAA,MACC,SAAQ;AAAA,MACR,MAAM,WAAW,YAAY;AAAA,MAC7B,MAAK;AAAA,MACL,MAAM,WAAWC,WAAAA,aAAaC,aAAAA;AAAAA,MAE7B,qBAAW,oBAAoB;AAAA,IAAA;AAAA,EAAA;AAGtC;AAEO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,SAAS,OAAO,UAAU,CAAA,GAAI,QAAQ,CAAC,UAAU;;AACrD,UAAM,SAASC,aAAAA,mBAAmB,QAAO,aAAQ,WAAR,mBAAiB,MAAM,IAAI;AACpE,QAAI,CAAC,OAAQ,QAAO,CAAA;AACpB,WAAO;AAAA,MACLJ,2BAAAA;AAAAA,QAACC,MAAAA;AAAAA,QAAA;AAAA,UAEC,SAAQ;AAAA,UACR,MAAMI,aAAAA,gBAAgB,OAAO,IAAI;AAAA,UACjC,MAAK;AAAA,UAEJ,UAAA,UAAW,OAAO,SAAS,OAAO,QAAS,OAAO;AAAA,QAAA;AAAA,QAL9C,MAAM;AAAA,MAAA;AAAA,IAMb;AAAA,EAEJ,CAAC;AACD,SAAO,MAAM,SAAS,IAAIL,2BAAAA,IAAAM,WAAAA,UAAA,EAAG,iBAAM,IAAM;AAC3C;AAEO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AACF,GAGG;;AACD,MAAI,GAAC,aAAQ,cAAR,mBAAmB,QAAQ,QAAO;AACvC,SACEN,+BAAC,SAAI,WAAU,wBACZ,kBAAQ,UAAU,IAAI,CAAC,MAAM,UAAU;AACtC,UAAM,OAAO,0BAA0B,KAAK,KAAK,MAAM;AACvD,UAAM,SAAS,kBAAkB,KAAK,KAAK,MAAM;AACjD,WACEA,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QAEC,MAAK;AAAA,QACL,SAAS,MAAM,uDAAoB;AAAA,QACnC,UAAU,CAAC;AAAA,QACX,WAAWO,MAAAA;AAAAA,UACT;AAAA,UACA,qBAAqB;AAAA,UACrB,OACI,sFACA,SACE,6EACA;AAAA,QAAA;AAAA,QAGP,UAAA,KAAK;AAAA,MAAA;AAAA,MAdD;AAAA,IAAA;AAAA,EAiBX,CAAC,EAAA,CACH;AAEJ;AAEO,SAAS,SAAS,EAAE,WAAiC;;AAC1D,MAAI,GAAC,aAAQ,SAAR,mBAAc,QAAQ,QAAO;AAClC,SACEP,+BAAC,SAAI,WAAU,0BACZ,kBAAQ,KAAK,IAAI,CAAC,OAAO,UACxBQ,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MAEC,WAAU;AAAA,MAEV,UAAA;AAAA,QAAAA,2BAAAA,KAAC,QAAA,EAAK,WAAU,eAAe,UAAA;AAAA,UAAA,MAAM;AAAA,UAAM;AAAA,QAAA,GAAC;AAAA,QAC5CR,2BAAAA,IAAC,QAAA,EAAK,WAAW,MAAM,OAAO,cAAc,QACzC,UAAA,MAAM,MAAM,KAAK,IAAI,EAAA,CACxB;AAAA,MAAA;AAAA,IAAA;AAAA,IANK;AAAA,EAAA,CAQR,GACH;AAEJ;;;;;"}
@@ -0,0 +1,17 @@
1
+ import { Comment, CommentConfig, CommentRating } from './comment-types';
2
+ export declare function RatingChip({ rating }: {
3
+ rating: CommentRating | undefined;
4
+ }): import("react").JSX.Element | null;
5
+ export declare function FacetBadges({ comment, config, compact, }: {
6
+ comment: Comment;
7
+ config: CommentConfig;
8
+ compact?: boolean;
9
+ }): import("react").JSX.Element | null;
10
+ export declare function ChecklistChips({ comment, onChecklistToggle, }: {
11
+ comment: Comment;
12
+ onChecklistToggle?: (index: number) => void;
13
+ }): import("react").JSX.Element | null;
14
+ export declare function RefChips({ comment }: {
15
+ comment: Comment;
16
+ }): import("react").JSX.Element | null;
17
+ //# sourceMappingURL=CommentCardParts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CommentCardParts.d.ts","sourceRoot":"","sources":["../../src/comments/CommentCardParts.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAE7E,wBAAgB,UAAU,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,aAAa,GAAG,SAAS,CAAA;CAAE,sCAa3E;AAED,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,MAAM,EACN,OAAO,GACR,EAAE;IACD,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,sCAgBA;AAED,wBAAgB,cAAc,CAAC,EAC7B,OAAO,EACP,iBAAiB,GAClB,EAAE;IACD,OAAO,EAAE,OAAO,CAAC;IACjB,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7C,sCA6BA;AAED,wBAAgB,QAAQ,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,sCAiBzD"}
@@ -0,0 +1,95 @@
1
+ import { jsx, Fragment, jsxs } from "react/jsx-runtime";
2
+ import { Badge } from "../data/Badge.js";
3
+ import { cn } from "../lib/utils.js";
4
+ import { resolveFacetOption, toneToBadgeTone } from "./comment-utils.js";
5
+ import { UiThumbsUp } from "../icons/components/UiThumbsUp.js";
6
+ import { UiThumbsDown } from "../icons/components/UiThumbsDown.js";
7
+ function RatingChip({ rating }) {
8
+ if (!rating) return null;
9
+ const positive = rating === "positive";
10
+ return /* @__PURE__ */ jsx(
11
+ Badge,
12
+ {
13
+ variant: "soft",
14
+ tone: positive ? "success" : "danger",
15
+ size: "xs",
16
+ icon: positive ? UiThumbsUp : UiThumbsDown,
17
+ children: positive ? "Positive rating" : "Negative rating"
18
+ }
19
+ );
20
+ }
21
+ function FacetBadges({
22
+ comment,
23
+ config,
24
+ compact
25
+ }) {
26
+ const chips = (config.facets ?? []).flatMap((facet) => {
27
+ var _a;
28
+ const option = resolveFacetOption(facet, (_a = comment.facets) == null ? void 0 : _a[facet.key]);
29
+ if (!option) return [];
30
+ return [
31
+ /* @__PURE__ */ jsx(
32
+ Badge,
33
+ {
34
+ variant: "soft",
35
+ tone: toneToBadgeTone(option.tone),
36
+ size: "xs",
37
+ children: compact ? option.short ?? option.label : option.label
38
+ },
39
+ facet.key
40
+ )
41
+ ];
42
+ });
43
+ return chips.length > 0 ? /* @__PURE__ */ jsx(Fragment, { children: chips }) : null;
44
+ }
45
+ function ChecklistChips({
46
+ comment,
47
+ onChecklistToggle
48
+ }) {
49
+ var _a;
50
+ if (!((_a = comment.checklist) == null ? void 0 : _a.length)) return null;
51
+ return /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1", children: comment.checklist.map((item, index) => {
52
+ const done = /done|complete|resolved/i.test(item.status);
53
+ const active = /progress|doing/i.test(item.status);
54
+ return /* @__PURE__ */ jsx(
55
+ "button",
56
+ {
57
+ type: "button",
58
+ onClick: () => onChecklistToggle == null ? void 0 : onChecklistToggle(index),
59
+ disabled: !onChecklistToggle,
60
+ className: cn(
61
+ "inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[10px] transition-opacity",
62
+ onChecklistToggle && "cursor-pointer hover:opacity-80",
63
+ done ? "bg-green-100 text-green-800 line-through dark:bg-green-500/20 dark:text-green-300" : active ? "bg-yellow-100 text-yellow-800 dark:bg-yellow-500/20 dark:text-yellow-300" : "bg-muted text-muted-foreground"
64
+ ),
65
+ children: item.label
66
+ },
67
+ index
68
+ );
69
+ }) });
70
+ }
71
+ function RefChips({ comment }) {
72
+ var _a;
73
+ if (!((_a = comment.refs) == null ? void 0 : _a.length)) return null;
74
+ return /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: comment.refs.map((group, index) => /* @__PURE__ */ jsxs(
75
+ "span",
76
+ {
77
+ className: "inline-flex items-center gap-1 rounded bg-muted px-1.5 py-0.5 text-[10px] text-muted-foreground",
78
+ children: [
79
+ /* @__PURE__ */ jsxs("span", { className: "font-medium", children: [
80
+ group.label,
81
+ ":"
82
+ ] }),
83
+ /* @__PURE__ */ jsx("span", { className: group.mono ? "font-mono" : void 0, children: group.items.join(", ") })
84
+ ]
85
+ },
86
+ index
87
+ )) });
88
+ }
89
+ export {
90
+ ChecklistChips,
91
+ FacetBadges,
92
+ RatingChip,
93
+ RefChips
94
+ };
95
+ //# sourceMappingURL=CommentCardParts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CommentCardParts.js","sources":["../../src/comments/CommentCardParts.tsx"],"sourcesContent":["import { Badge } from \"../data/Badge\";\nimport { cn } from \"../lib/utils\";\nimport { UiThumbsDown, UiThumbsUp } from \"../icons\";\nimport { resolveFacetOption, toneToBadgeTone } from \"./comment-utils\";\nimport type { Comment, CommentConfig, CommentRating } from \"./comment-types\";\n\nexport function RatingChip({ rating }: { rating: CommentRating | undefined }) {\n if (!rating) return null;\n const positive = rating === \"positive\";\n return (\n <Badge\n variant=\"soft\"\n tone={positive ? \"success\" : \"danger\"}\n size=\"xs\"\n icon={positive ? UiThumbsUp : UiThumbsDown}\n >\n {positive ? \"Positive rating\" : \"Negative rating\"}\n </Badge>\n );\n}\n\nexport function FacetBadges({\n comment,\n config,\n compact,\n}: {\n comment: Comment;\n config: CommentConfig;\n compact?: boolean;\n}) {\n const chips = (config.facets ?? []).flatMap((facet) => {\n const option = resolveFacetOption(facet, comment.facets?.[facet.key]);\n if (!option) return [];\n return [\n <Badge\n key={facet.key}\n variant=\"soft\"\n tone={toneToBadgeTone(option.tone)}\n size=\"xs\"\n >\n {compact ? (option.short ?? option.label) : option.label}\n </Badge>,\n ];\n });\n return chips.length > 0 ? <>{chips}</> : null;\n}\n\nexport function ChecklistChips({\n comment,\n onChecklistToggle,\n}: {\n comment: Comment;\n onChecklistToggle?: (index: number) => void;\n}) {\n if (!comment.checklist?.length) return null;\n return (\n <div className=\"flex flex-wrap gap-1\">\n {comment.checklist.map((item, index) => {\n const done = /done|complete|resolved/i.test(item.status);\n const active = /progress|doing/i.test(item.status);\n return (\n <button\n key={index}\n type=\"button\"\n onClick={() => onChecklistToggle?.(index)}\n disabled={!onChecklistToggle}\n className={cn(\n \"inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[10px] transition-opacity\",\n onChecklistToggle && \"cursor-pointer hover:opacity-80\",\n done\n ? \"bg-green-100 text-green-800 line-through dark:bg-green-500/20 dark:text-green-300\"\n : active\n ? \"bg-yellow-100 text-yellow-800 dark:bg-yellow-500/20 dark:text-yellow-300\"\n : \"bg-muted text-muted-foreground\",\n )}\n >\n {item.label}\n </button>\n );\n })}\n </div>\n );\n}\n\nexport function RefChips({ comment }: { comment: Comment }) {\n if (!comment.refs?.length) return null;\n return (\n <div className=\"flex flex-wrap gap-1.5\">\n {comment.refs.map((group, index) => (\n <span\n key={index}\n className=\"inline-flex items-center gap-1 rounded bg-muted px-1.5 py-0.5 text-[10px] text-muted-foreground\"\n >\n <span className=\"font-medium\">{group.label}:</span>\n <span className={group.mono ? \"font-mono\" : undefined}>\n {group.items.join(\", \")}\n </span>\n </span>\n ))}\n </div>\n );\n}\n"],"names":[],"mappings":";;;;;;AAMO,SAAS,WAAW,EAAE,UAAiD;AAC5E,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,WAAW,WAAW;AAC5B,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,SAAQ;AAAA,MACR,MAAM,WAAW,YAAY;AAAA,MAC7B,MAAK;AAAA,MACL,MAAM,WAAW,aAAa;AAAA,MAE7B,qBAAW,oBAAoB;AAAA,IAAA;AAAA,EAAA;AAGtC;AAEO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,SAAS,OAAO,UAAU,CAAA,GAAI,QAAQ,CAAC,UAAU;;AACrD,UAAM,SAAS,mBAAmB,QAAO,aAAQ,WAAR,mBAAiB,MAAM,IAAI;AACpE,QAAI,CAAC,OAAQ,QAAO,CAAA;AACpB,WAAO;AAAA,MACL;AAAA,QAAC;AAAA,QAAA;AAAA,UAEC,SAAQ;AAAA,UACR,MAAM,gBAAgB,OAAO,IAAI;AAAA,UACjC,MAAK;AAAA,UAEJ,UAAA,UAAW,OAAO,SAAS,OAAO,QAAS,OAAO;AAAA,QAAA;AAAA,QAL9C,MAAM;AAAA,MAAA;AAAA,IAMb;AAAA,EAEJ,CAAC;AACD,SAAO,MAAM,SAAS,IAAI,oBAAA,UAAA,EAAG,iBAAM,IAAM;AAC3C;AAEO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AACF,GAGG;;AACD,MAAI,GAAC,aAAQ,cAAR,mBAAmB,QAAQ,QAAO;AACvC,SACE,oBAAC,SAAI,WAAU,wBACZ,kBAAQ,UAAU,IAAI,CAAC,MAAM,UAAU;AACtC,UAAM,OAAO,0BAA0B,KAAK,KAAK,MAAM;AACvD,UAAM,SAAS,kBAAkB,KAAK,KAAK,MAAM;AACjD,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QAEC,MAAK;AAAA,QACL,SAAS,MAAM,uDAAoB;AAAA,QACnC,UAAU,CAAC;AAAA,QACX,WAAW;AAAA,UACT;AAAA,UACA,qBAAqB;AAAA,UACrB,OACI,sFACA,SACE,6EACA;AAAA,QAAA;AAAA,QAGP,UAAA,KAAK;AAAA,MAAA;AAAA,MAdD;AAAA,IAAA;AAAA,EAiBX,CAAC,EAAA,CACH;AAEJ;AAEO,SAAS,SAAS,EAAE,WAAiC;;AAC1D,MAAI,GAAC,aAAQ,SAAR,mBAAc,QAAQ,QAAO;AAClC,SACE,oBAAC,SAAI,WAAU,0BACZ,kBAAQ,KAAK,IAAI,CAAC,OAAO,UACxB;AAAA,IAAC;AAAA,IAAA;AAAA,MAEC,WAAU;AAAA,MAEV,UAAA;AAAA,QAAA,qBAAC,QAAA,EAAK,WAAU,eAAe,UAAA;AAAA,UAAA,MAAM;AAAA,UAAM;AAAA,QAAA,GAAC;AAAA,QAC5C,oBAAC,QAAA,EAAK,WAAW,MAAM,OAAO,cAAc,QACzC,UAAA,MAAM,MAAM,KAAK,IAAI,EAAA,CACxB;AAAA,MAAA;AAAA,IAAA;AAAA,IANK;AAAA,EAAA,CAQR,GACH;AAEJ;"}
@@ -85,7 +85,8 @@ function AllComments({
85
85
  ctx,
86
86
  comments,
87
87
  label,
88
- emptyLabel
88
+ emptyLabel,
89
+ threadToMarkdown
89
90
  }) {
90
91
  const ordered = react.useMemo(() => {
91
92
  const anchorOrder = new Map(orderedAnchors(ctx).map((a, i) => [a, i]));
@@ -141,7 +142,8 @@ function AllComments({
141
142
  onMouseLeave: () => ctx.setHighlightAnchor(null),
142
143
  onClick: (event) => activateThread(event, c.anchor ?? commentTypes.DOCUMENT_ANCHOR)
143
144
  }),
144
- ...handlers
145
+ ...handlers,
146
+ ...threadToMarkdown ? { threadToMarkdown } : {}
145
147
  }
146
148
  )
147
149
  }
@@ -152,7 +154,8 @@ function FocusedComments({
152
154
  comments: visible,
153
155
  anchor,
154
156
  label,
155
- compact
157
+ compact,
158
+ threadToMarkdown
156
159
  }) {
157
160
  const comments = commentUtils.selectAnchorThreads(visible, anchor);
158
161
  const hasComments = comments.length > 0;
@@ -173,7 +176,8 @@ function FocusedComments({
173
176
  autoFocusComposer: !hasComments,
174
177
  defaultExpanded: hasComments,
175
178
  composerPlaceholder: hasComments ? "Add another top-level comment…" : "Add a comment…",
176
- ...ctx.callbacks
179
+ ...ctx.callbacks,
180
+ ...threadToMarkdown ? { threadToMarkdown } : {}
177
181
  }
178
182
  )
179
183
  ] });
@@ -223,7 +227,8 @@ function CommentSidePanel(props) {
223
227
  const visible = showResolved ? ctx.comments : unresolved;
224
228
  const total = commentUtils.getRoots(visible).length;
225
229
  const resolvedCount = commentUtils.getRoots(ctx.comments).length - commentUtils.getRoots(unresolved).length;
226
- if (ctx.railMode === "closed" && total === 0 && resolvedCount === 0) return null;
230
+ if (ctx.railMode === "closed" && total === 0 && resolvedCount === 0)
231
+ return null;
227
232
  return /* @__PURE__ */ jsxRuntime.jsxs(
228
233
  "aside",
229
234
  {
@@ -281,7 +286,8 @@ function CommentSidePanel(props) {
281
286
  ctx,
282
287
  comments: visible,
283
288
  label,
284
- emptyLabel: resolvedCount > 0 ? "No open comments." : "No comments yet."
289
+ emptyLabel: resolvedCount > 0 ? "No open comments." : "No comments yet.",
290
+ ...props.threadToMarkdown ? { threadToMarkdown: props.threadToMarkdown } : {}
285
291
  }
286
292
  ) : ctx.railMode === "focused" && ctx.focusedAnchor ? /* @__PURE__ */ jsxRuntime.jsx(
287
293
  "div",
@@ -297,7 +303,8 @@ function CommentSidePanel(props) {
297
303
  comments: visible,
298
304
  anchor: ctx.focusedAnchor,
299
305
  label: label(ctx.focusedAnchor),
300
- ...props.compact !== void 0 ? { compact: props.compact } : {}
306
+ ...props.compact !== void 0 ? { compact: props.compact } : {},
307
+ ...props.threadToMarkdown ? { threadToMarkdown: props.threadToMarkdown } : {}
301
308
  }
302
309
  )
303
310
  }
@@ -1 +1 @@
1
- {"version":3,"file":"CommentSidePanel.cjs","sources":["../../src/comments/CommentSidePanel.tsx"],"sourcesContent":["import { useEffect, useMemo, useRef, useState, type MouseEvent } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon } from \"../data/Icon\";\nimport { UiComment } from \"../icons\";\nimport { CommentThread } from \"./CommentThread\";\nimport { CommentThreadList } from \"./CommentThreadList\";\nimport {\n useCommentContextOptional,\n type CommentContextValue,\n} from \"./comment-context\";\nimport {\n buildThreadListHandlers,\n getRoots,\n selectAnchorThreads,\n selectUnresolvedThreads,\n sortReplies,\n buildReplyMap,\n} from \"./comment-utils\";\nimport {\n DOCUMENT_ANCHOR,\n type Comment,\n type CommentAnchor,\n} from \"./comment-types\";\n\nexport type CommentSidePanelProps = {\n /** Explicit label per anchor key. */\n anchorLabels?: Record<CommentAnchor, string>;\n /** Fallback label formatter for anchors without an explicit label. */\n formatAnchorLabel?: (anchor: CommentAnchor) => string;\n compact?: boolean;\n /** Position the focused thread beside its registered content anchor. */\n focusedAlignment?: \"flow\" | \"anchor\";\n className?: string;\n};\n\nfunction defaultAnchorLabel(anchor: CommentAnchor): string {\n if (anchor === DOCUMENT_ANCHOR) return \"General\";\n return anchor\n .replace(/\\[\\d+\\]/g, \"\")\n .replaceAll(\".\", \" › \")\n .replaceAll(\"_\", \" \")\n .trim();\n}\n\nfunction useAnchorLabel(props: CommentSidePanelProps) {\n return (anchor: CommentAnchor): string =>\n props.anchorLabels?.[anchor] ??\n props.formatAnchorLabel?.(anchor) ??\n defaultAnchorLabel(anchor);\n}\n\nfunction LocationMeta({ label }: { label: string }) {\n return (\n <span\n data-testid=\"comment-location-meta\"\n className=\"inline-flex items-center rounded-full bg-muted px-2 py-1 text-[10px] font-medium text-muted-foreground\"\n >\n {label}\n </span>\n );\n}\n\nfunction RailToggle({\n active,\n onClick,\n children,\n testId,\n}: {\n active?: boolean;\n onClick: () => void;\n children: React.ReactNode;\n testId?: string;\n}) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n data-testid={testId}\n className={cn(\n \"inline-flex items-center gap-1.5 rounded-full border px-3 py-1.5 text-xs font-medium shadow-sm transition-colors\",\n active\n ? \"border-primary bg-primary text-primary-foreground\"\n : \"border-border bg-background text-muted-foreground hover:text-foreground\",\n )}\n >\n <Icon icon={UiComment} className=\"text-xs\" />\n {children}\n </button>\n );\n}\n\nfunction orderedAnchors(ctx: CommentContextValue): string[] {\n return Object.keys(ctx.commentMeta).sort((a, b) => {\n if (a === DOCUMENT_ANCHOR) return -1;\n if (b === DOCUMENT_ANCHOR) return 1;\n const at = ctx.getAnchorTop(a);\n const bt = ctx.getAnchorTop(b);\n if (at == null && bt == null) return a.localeCompare(b);\n if (at == null) return 1;\n if (bt == null) return -1;\n if (at !== bt) return at - bt;\n return a.localeCompare(b);\n });\n}\n\nfunction orderComments(\n comments: Comment[],\n anchorOrder: Map<string, number>,\n): Comment[] {\n const replyMap = buildReplyMap(comments);\n const roots = getRoots(comments).sort((a, b) => {\n const ai =\n anchorOrder.get(a.anchor ?? DOCUMENT_ANCHOR) ?? Number.MAX_SAFE_INTEGER;\n const bi =\n anchorOrder.get(b.anchor ?? DOCUMENT_ANCHOR) ?? Number.MAX_SAFE_INTEGER;\n if (ai !== bi) return ai - bi;\n if (a.createdAt !== b.createdAt)\n return a.createdAt.localeCompare(b.createdAt);\n return String(a.id).localeCompare(String(b.id));\n });\n return roots.flatMap((root) => [\n root,\n ...sortReplies(replyMap.get(root.id) ?? []),\n ]);\n}\n\nfunction AllComments({\n ctx,\n comments,\n label,\n emptyLabel,\n}: {\n ctx: CommentContextValue;\n comments: Comment[];\n label: (a: CommentAnchor) => string;\n emptyLabel: string;\n}) {\n const ordered = useMemo(() => {\n const anchorOrder = new Map(orderedAnchors(ctx).map((a, i) => [a, i]));\n return orderComments(comments, anchorOrder);\n }, [ctx, comments]);\n const handlers = buildThreadListHandlers(ordered, ctx.config, ctx.callbacks);\n\n function activateThread(\n event: MouseEvent<HTMLDivElement>,\n anchor: CommentAnchor,\n ) {\n const target = event.target as Element;\n if (\n target.closest(\n 'button, a, input, textarea, select, [contenteditable=\"true\"]',\n )\n )\n return;\n const roleButton = target.closest('[role=\"button\"]');\n if (roleButton && roleButton !== target.closest(\"[data-comment-kind]\"))\n return;\n if (anchor !== DOCUMENT_ANCHOR) {\n const found = ctx.scrollToAnchor(anchor, {\n behavior: \"smooth\",\n block: \"start\",\n offset: 12,\n });\n if (!found) return;\n }\n ctx.focusAnchor(anchor);\n }\n\n if (ordered.length === 0) {\n return (\n <p className=\"rounded-lg bg-muted/40 px-3 py-2 text-xs text-muted-foreground\">\n {emptyLabel}\n </p>\n );\n }\n\n return (\n <div\n data-testid=\"comment-all-rail\"\n className=\"space-y-3 overflow-y-auto pr-1\"\n >\n <CommentThreadList\n comments={ordered}\n config={ctx.config}\n compact\n renderRootMeta={(c) => {\n const anchor = c.anchor ?? DOCUMENT_ANCHOR;\n const available =\n anchor === DOCUMENT_ANCHOR || ctx.getAnchorTop(anchor) != null;\n return (\n <LocationMeta\n label={`${label(anchor)}${available ? \"\" : \" · Unavailable\"}`}\n />\n );\n }}\n getThreadProps={(c) => ({\n \"data-testid\": \"comment-feed-item\",\n onMouseEnter: () =>\n ctx.setHighlightAnchor(c.anchor ?? DOCUMENT_ANCHOR),\n onMouseLeave: () => ctx.setHighlightAnchor(null),\n onClick: (event) =>\n activateThread(event, c.anchor ?? DOCUMENT_ANCHOR),\n })}\n {...handlers}\n />\n </div>\n );\n}\n\nfunction FocusedComments({\n ctx,\n comments: visible,\n anchor,\n label,\n compact,\n}: {\n ctx: CommentContextValue;\n comments: Comment[];\n anchor: CommentAnchor;\n label: string;\n compact?: boolean;\n}) {\n const comments = selectAnchorThreads(visible, anchor);\n const hasComments = comments.length > 0;\n return (\n <div className=\"space-y-3\" data-comment-anchor={anchor}>\n <LocationMeta\n label={\n anchor === DOCUMENT_ANCHOR\n ? \"Whole-page comment\"\n : `Attached to ${label}`\n }\n />\n <CommentThread\n comments={comments}\n config={ctx.config}\n anchor={anchor}\n compact={compact ?? false}\n autoFocusComposer={!hasComments}\n defaultExpanded={hasComments}\n composerPlaceholder={\n hasComments ? \"Add another top-level comment…\" : \"Add a comment…\"\n }\n {...ctx.callbacks}\n />\n </div>\n );\n}\n\n/**\n * A controlled comment rail driven by {@link CommentProvider}. Shows a focused\n * thread for the active anchor, the full document feed in anchor order, or a\n * toggle when collapsed. Renders nothing outside a provider or when empty.\n */\nexport function CommentSidePanel(props: CommentSidePanelProps) {\n const ctx = useCommentContextOptional();\n const label = useAnchorLabel(props);\n const railRef = useRef<HTMLElement>(null);\n const focusedRef = useRef<HTMLDivElement>(null);\n const [focusedOffset, setFocusedOffset] = useState<number | null>(null);\n const [showResolved, setShowResolved] = useState(false);\n const focusedAnchor = ctx?.railMode === \"focused\" ? ctx.focusedAnchor : null;\n\n useEffect(() => {\n if (!ctx || props.focusedAlignment !== \"anchor\" || !focusedAnchor) {\n setFocusedOffset(null);\n return;\n }\n const content = ctx.contentRef.current;\n const rail = railRef.current;\n const focused = focusedRef.current;\n if (!content || !rail || !focused) return;\n\n const update = () => {\n const anchorTop = ctx.getAnchorTop(focusedAnchor);\n if (anchorTop == null) {\n setFocusedOffset(null);\n return;\n }\n const desiredTop = anchorTop + content.getBoundingClientRect().top;\n const currentOffset = Number.parseFloat(focused.style.top) || 0;\n const nextOffset =\n currentOffset + desiredTop - focused.getBoundingClientRect().top;\n setFocusedOffset(Math.max(0, nextOffset));\n };\n update();\n content.addEventListener(\"scroll\", update, { passive: true });\n window.addEventListener(\"resize\", update);\n const observer =\n typeof ResizeObserver === \"undefined\" ? null : new ResizeObserver(update);\n observer?.observe(content);\n observer?.observe(rail);\n return () => {\n content.removeEventListener(\"scroll\", update);\n window.removeEventListener(\"resize\", update);\n observer?.disconnect();\n };\n }, [ctx, focusedAnchor, props.focusedAlignment]);\n\n if (!ctx) return null;\n\n // Threads, not cards: a reply is part of its root, never a separate entry.\n const unresolved = selectUnresolvedThreads(ctx.comments, ctx.config);\n const visible = showResolved ? ctx.comments : unresolved;\n const total = getRoots(visible).length;\n const resolvedCount = getRoots(ctx.comments).length - getRoots(unresolved).length;\n if (ctx.railMode === \"closed\" && total === 0 && resolvedCount === 0) return null;\n\n return (\n <aside\n ref={railRef}\n data-testid=\"comment-side-panel\"\n className={cn(\"relative w-[320px] space-y-3\", props.className)}\n >\n <div\n data-testid=\"comment-rail-header\"\n className=\"sticky top-0 z-20 flex items-center gap-2 bg-background py-2\"\n >\n {(total > 0 || ctx.railMode === \"all\") && (\n <RailToggle\n active={ctx.railMode === \"all\"}\n onClick={ctx.openCommentList}\n testId=\"comment-open-all\"\n >\n {ctx.railMode === \"closed\"\n ? `Open comments (${total})`\n : `All comments (${total})`}\n </RailToggle>\n )}\n {resolvedCount > 0 && (\n <button\n type=\"button\"\n aria-pressed={showResolved}\n onClick={() => setShowResolved((shown) => !shown)}\n className={cn(\n \"rounded-full border px-2 py-1 text-xs font-medium transition-colors\",\n showResolved\n ? \"border-primary bg-primary text-primary-foreground\"\n : \"border-border bg-background text-muted-foreground hover:text-foreground\",\n )}\n >\n Resolved ({resolvedCount})\n </button>\n )}\n {ctx.railMode !== \"closed\" && (\n <button\n type=\"button\"\n onClick={ctx.closeRail}\n className=\"ml-auto rounded-md px-2 py-1 text-xs font-medium text-muted-foreground hover:bg-muted hover:text-foreground\"\n >\n {ctx.railMode === \"all\" ? \"Close\" : \"Hide\"}\n </button>\n )}\n </div>\n {ctx.railMode === \"all\" ? (\n <AllComments\n ctx={ctx}\n comments={visible}\n label={label}\n emptyLabel={resolvedCount > 0 ? \"No open comments.\" : \"No comments yet.\"}\n />\n ) : ctx.railMode === \"focused\" && ctx.focusedAnchor ? (\n <div\n ref={focusedRef}\n data-testid=\"comment-focused-rail\"\n className=\"relative space-y-3\"\n style={focusedOffset == null ? undefined : { top: focusedOffset }}\n >\n <FocusedComments\n ctx={ctx}\n comments={visible}\n anchor={ctx.focusedAnchor}\n label={label(ctx.focusedAnchor)}\n {...(props.compact !== undefined ? { compact: props.compact } : {})}\n />\n </div>\n ) : null}\n </aside>\n );\n}\n"],"names":["DOCUMENT_ANCHOR","jsx","jsxs","cn","Icon","UiComment","buildReplyMap","getRoots","sortReplies","useMemo","buildThreadListHandlers","CommentThreadList","selectAnchorThreads","CommentThread","useCommentContextOptional","useRef","useState","useEffect","selectUnresolvedThreads"],"mappings":"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"}
1
+ {"version":3,"file":"CommentSidePanel.cjs","sources":["../../src/comments/CommentSidePanel.tsx"],"sourcesContent":["import { useEffect, useMemo, useRef, useState, type MouseEvent } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon } from \"../data/Icon\";\nimport { UiComment } from \"../icons\";\nimport { CommentThread } from \"./CommentThread\";\nimport { CommentThreadList } from \"./CommentThreadList\";\nimport {\n useCommentContextOptional,\n type CommentContextValue,\n} from \"./comment-context\";\nimport {\n buildThreadListHandlers,\n getRoots,\n selectAnchorThreads,\n selectUnresolvedThreads,\n sortReplies,\n buildReplyMap,\n} from \"./comment-utils\";\nimport {\n DOCUMENT_ANCHOR,\n type Comment,\n type CommentAnchor,\n} from \"./comment-types\";\n\nexport type CommentSidePanelProps = {\n /** Explicit label per anchor key. */\n anchorLabels?: Record<CommentAnchor, string>;\n /** Fallback label formatter for anchors without an explicit label. */\n formatAnchorLabel?: (anchor: CommentAnchor) => string;\n compact?: boolean;\n /** Position the focused thread beside its registered content anchor. */\n focusedAlignment?: \"flow\" | \"anchor\";\n className?: string;\n /** Serialize one whole thread for Copy and its maximized Markdown tab. */\n threadToMarkdown?: (thread: readonly Comment[]) => string;\n};\n\nfunction defaultAnchorLabel(anchor: CommentAnchor): string {\n if (anchor === DOCUMENT_ANCHOR) return \"General\";\n return anchor\n .replace(/\\[\\d+\\]/g, \"\")\n .replaceAll(\".\", \" › \")\n .replaceAll(\"_\", \" \")\n .trim();\n}\n\nfunction useAnchorLabel(props: CommentSidePanelProps) {\n return (anchor: CommentAnchor): string =>\n props.anchorLabels?.[anchor] ??\n props.formatAnchorLabel?.(anchor) ??\n defaultAnchorLabel(anchor);\n}\n\nfunction LocationMeta({ label }: { label: string }) {\n return (\n <span\n data-testid=\"comment-location-meta\"\n className=\"inline-flex items-center rounded-full bg-muted px-2 py-1 text-[10px] font-medium text-muted-foreground\"\n >\n {label}\n </span>\n );\n}\n\nfunction RailToggle({\n active,\n onClick,\n children,\n testId,\n}: {\n active?: boolean;\n onClick: () => void;\n children: React.ReactNode;\n testId?: string;\n}) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n data-testid={testId}\n className={cn(\n \"inline-flex items-center gap-1.5 rounded-full border px-3 py-1.5 text-xs font-medium shadow-sm transition-colors\",\n active\n ? \"border-primary bg-primary text-primary-foreground\"\n : \"border-border bg-background text-muted-foreground hover:text-foreground\",\n )}\n >\n <Icon icon={UiComment} className=\"text-xs\" />\n {children}\n </button>\n );\n}\n\nfunction orderedAnchors(ctx: CommentContextValue): string[] {\n return Object.keys(ctx.commentMeta).sort((a, b) => {\n if (a === DOCUMENT_ANCHOR) return -1;\n if (b === DOCUMENT_ANCHOR) return 1;\n const at = ctx.getAnchorTop(a);\n const bt = ctx.getAnchorTop(b);\n if (at == null && bt == null) return a.localeCompare(b);\n if (at == null) return 1;\n if (bt == null) return -1;\n if (at !== bt) return at - bt;\n return a.localeCompare(b);\n });\n}\n\nfunction orderComments(\n comments: Comment[],\n anchorOrder: Map<string, number>,\n): Comment[] {\n const replyMap = buildReplyMap(comments);\n const roots = getRoots(comments).sort((a, b) => {\n const ai =\n anchorOrder.get(a.anchor ?? DOCUMENT_ANCHOR) ?? Number.MAX_SAFE_INTEGER;\n const bi =\n anchorOrder.get(b.anchor ?? DOCUMENT_ANCHOR) ?? Number.MAX_SAFE_INTEGER;\n if (ai !== bi) return ai - bi;\n if (a.createdAt !== b.createdAt)\n return a.createdAt.localeCompare(b.createdAt);\n return String(a.id).localeCompare(String(b.id));\n });\n return roots.flatMap((root) => [\n root,\n ...sortReplies(replyMap.get(root.id) ?? []),\n ]);\n}\n\nfunction AllComments({\n ctx,\n comments,\n label,\n emptyLabel,\n threadToMarkdown,\n}: {\n ctx: CommentContextValue;\n comments: Comment[];\n label: (a: CommentAnchor) => string;\n emptyLabel: string;\n threadToMarkdown?: (thread: readonly Comment[]) => string;\n}) {\n const ordered = useMemo(() => {\n const anchorOrder = new Map(orderedAnchors(ctx).map((a, i) => [a, i]));\n return orderComments(comments, anchorOrder);\n }, [ctx, comments]);\n const handlers = buildThreadListHandlers(ordered, ctx.config, ctx.callbacks);\n\n function activateThread(\n event: MouseEvent<HTMLDivElement>,\n anchor: CommentAnchor,\n ) {\n const target = event.target as Element;\n if (\n target.closest(\n 'button, a, input, textarea, select, [contenteditable=\"true\"]',\n )\n )\n return;\n const roleButton = target.closest('[role=\"button\"]');\n if (roleButton && roleButton !== target.closest(\"[data-comment-kind]\"))\n return;\n if (anchor !== DOCUMENT_ANCHOR) {\n const found = ctx.scrollToAnchor(anchor, {\n behavior: \"smooth\",\n block: \"start\",\n offset: 12,\n });\n if (!found) return;\n }\n ctx.focusAnchor(anchor);\n }\n\n if (ordered.length === 0) {\n return (\n <p className=\"rounded-lg bg-muted/40 px-3 py-2 text-xs text-muted-foreground\">\n {emptyLabel}\n </p>\n );\n }\n\n return (\n <div\n data-testid=\"comment-all-rail\"\n className=\"space-y-3 overflow-y-auto pr-1\"\n >\n <CommentThreadList\n comments={ordered}\n config={ctx.config}\n compact\n renderRootMeta={(c) => {\n const anchor = c.anchor ?? DOCUMENT_ANCHOR;\n const available =\n anchor === DOCUMENT_ANCHOR || ctx.getAnchorTop(anchor) != null;\n return (\n <LocationMeta\n label={`${label(anchor)}${available ? \"\" : \" · Unavailable\"}`}\n />\n );\n }}\n getThreadProps={(c) => ({\n \"data-testid\": \"comment-feed-item\",\n onMouseEnter: () =>\n ctx.setHighlightAnchor(c.anchor ?? DOCUMENT_ANCHOR),\n onMouseLeave: () => ctx.setHighlightAnchor(null),\n onClick: (event) =>\n activateThread(event, c.anchor ?? DOCUMENT_ANCHOR),\n })}\n {...handlers}\n {...(threadToMarkdown ? { threadToMarkdown } : {})}\n />\n </div>\n );\n}\n\nfunction FocusedComments({\n ctx,\n comments: visible,\n anchor,\n label,\n compact,\n threadToMarkdown,\n}: {\n ctx: CommentContextValue;\n comments: Comment[];\n anchor: CommentAnchor;\n label: string;\n compact?: boolean;\n threadToMarkdown?: (thread: readonly Comment[]) => string;\n}) {\n const comments = selectAnchorThreads(visible, anchor);\n const hasComments = comments.length > 0;\n return (\n <div className=\"space-y-3\" data-comment-anchor={anchor}>\n <LocationMeta\n label={\n anchor === DOCUMENT_ANCHOR\n ? \"Whole-page comment\"\n : `Attached to ${label}`\n }\n />\n <CommentThread\n comments={comments}\n config={ctx.config}\n anchor={anchor}\n compact={compact ?? false}\n autoFocusComposer={!hasComments}\n defaultExpanded={hasComments}\n composerPlaceholder={\n hasComments ? \"Add another top-level comment…\" : \"Add a comment…\"\n }\n {...ctx.callbacks}\n {...(threadToMarkdown ? { threadToMarkdown } : {})}\n />\n </div>\n );\n}\n\n/**\n * A controlled comment rail driven by {@link CommentProvider}. Shows a focused\n * thread for the active anchor, the full document feed in anchor order, or a\n * toggle when collapsed. Renders nothing outside a provider or when empty.\n */\nexport function CommentSidePanel(props: CommentSidePanelProps) {\n const ctx = useCommentContextOptional();\n const label = useAnchorLabel(props);\n const railRef = useRef<HTMLElement>(null);\n const focusedRef = useRef<HTMLDivElement>(null);\n const [focusedOffset, setFocusedOffset] = useState<number | null>(null);\n const [showResolved, setShowResolved] = useState(false);\n const focusedAnchor = ctx?.railMode === \"focused\" ? ctx.focusedAnchor : null;\n\n useEffect(() => {\n if (!ctx || props.focusedAlignment !== \"anchor\" || !focusedAnchor) {\n setFocusedOffset(null);\n return;\n }\n const content = ctx.contentRef.current;\n const rail = railRef.current;\n const focused = focusedRef.current;\n if (!content || !rail || !focused) return;\n\n const update = () => {\n const anchorTop = ctx.getAnchorTop(focusedAnchor);\n if (anchorTop == null) {\n setFocusedOffset(null);\n return;\n }\n const desiredTop = anchorTop + content.getBoundingClientRect().top;\n const currentOffset = Number.parseFloat(focused.style.top) || 0;\n const nextOffset =\n currentOffset + desiredTop - focused.getBoundingClientRect().top;\n setFocusedOffset(Math.max(0, nextOffset));\n };\n update();\n content.addEventListener(\"scroll\", update, { passive: true });\n window.addEventListener(\"resize\", update);\n const observer =\n typeof ResizeObserver === \"undefined\" ? null : new ResizeObserver(update);\n observer?.observe(content);\n observer?.observe(rail);\n return () => {\n content.removeEventListener(\"scroll\", update);\n window.removeEventListener(\"resize\", update);\n observer?.disconnect();\n };\n }, [ctx, focusedAnchor, props.focusedAlignment]);\n\n if (!ctx) return null;\n\n // Threads, not cards: a reply is part of its root, never a separate entry.\n const unresolved = selectUnresolvedThreads(ctx.comments, ctx.config);\n const visible = showResolved ? ctx.comments : unresolved;\n const total = getRoots(visible).length;\n const resolvedCount =\n getRoots(ctx.comments).length - getRoots(unresolved).length;\n if (ctx.railMode === \"closed\" && total === 0 && resolvedCount === 0)\n return null;\n\n return (\n <aside\n ref={railRef}\n data-testid=\"comment-side-panel\"\n className={cn(\"relative w-[320px] space-y-3\", props.className)}\n >\n <div\n data-testid=\"comment-rail-header\"\n className=\"sticky top-0 z-20 flex items-center gap-2 bg-background py-2\"\n >\n {(total > 0 || ctx.railMode === \"all\") && (\n <RailToggle\n active={ctx.railMode === \"all\"}\n onClick={ctx.openCommentList}\n testId=\"comment-open-all\"\n >\n {ctx.railMode === \"closed\"\n ? `Open comments (${total})`\n : `All comments (${total})`}\n </RailToggle>\n )}\n {resolvedCount > 0 && (\n <button\n type=\"button\"\n aria-pressed={showResolved}\n onClick={() => setShowResolved((shown) => !shown)}\n className={cn(\n \"rounded-full border px-2 py-1 text-xs font-medium transition-colors\",\n showResolved\n ? \"border-primary bg-primary text-primary-foreground\"\n : \"border-border bg-background text-muted-foreground hover:text-foreground\",\n )}\n >\n Resolved ({resolvedCount})\n </button>\n )}\n {ctx.railMode !== \"closed\" && (\n <button\n type=\"button\"\n onClick={ctx.closeRail}\n className=\"ml-auto rounded-md px-2 py-1 text-xs font-medium text-muted-foreground hover:bg-muted hover:text-foreground\"\n >\n {ctx.railMode === \"all\" ? \"Close\" : \"Hide\"}\n </button>\n )}\n </div>\n {ctx.railMode === \"all\" ? (\n <AllComments\n ctx={ctx}\n comments={visible}\n label={label}\n emptyLabel={\n resolvedCount > 0 ? \"No open comments.\" : \"No comments yet.\"\n }\n {...(props.threadToMarkdown\n ? { threadToMarkdown: props.threadToMarkdown }\n : {})}\n />\n ) : ctx.railMode === \"focused\" && ctx.focusedAnchor ? (\n <div\n ref={focusedRef}\n data-testid=\"comment-focused-rail\"\n className=\"relative space-y-3\"\n style={focusedOffset == null ? undefined : { top: focusedOffset }}\n >\n <FocusedComments\n ctx={ctx}\n comments={visible}\n anchor={ctx.focusedAnchor}\n label={label(ctx.focusedAnchor)}\n {...(props.compact !== undefined ? { compact: props.compact } : {})}\n {...(props.threadToMarkdown\n ? { threadToMarkdown: props.threadToMarkdown }\n : {})}\n />\n </div>\n ) : null}\n </aside>\n );\n}\n"],"names":["DOCUMENT_ANCHOR","jsx","jsxs","cn","Icon","UiComment","buildReplyMap","getRoots","sortReplies","useMemo","buildThreadListHandlers","CommentThreadList","selectAnchorThreads","CommentThread","useCommentContextOptional","useRef","useState","useEffect","selectUnresolvedThreads"],"mappings":";;;;;;;;;;;;AAqCA,SAAS,mBAAmB,QAA+B;AACzD,MAAI,WAAWA,aAAAA,gBAAiB,QAAO;AACvC,SAAO,OACJ,QAAQ,YAAY,EAAE,EACtB,WAAW,KAAK,KAAK,EACrB,WAAW,KAAK,GAAG,EACnB,KAAA;AACL;AAEA,SAAS,eAAe,OAA8B;AACpD,SAAO,CAAC,WAAA;;AACN,wBAAM,iBAAN,mBAAqB,cACrB,WAAM,sBAAN,+BAA0B,YAC1B,mBAAmB,MAAM;AAAA;AAC7B;AAEA,SAAS,aAAa,EAAE,SAA4B;AAClD,SACEC,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,eAAY;AAAA,MACZ,WAAU;AAAA,MAET,UAAA;AAAA,IAAA;AAAA,EAAA;AAGP;AAEA,SAAS,WAAW;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,SACEC,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL;AAAA,MACA,eAAa;AAAA,MACb,WAAWC,MAAAA;AAAAA,QACT;AAAA,QACA,SACI,sDACA;AAAA,MAAA;AAAA,MAGN,UAAA;AAAA,QAAAF,2BAAAA,IAACG,KAAAA,MAAA,EAAK,MAAMC,UAAAA,WAAW,WAAU,WAAU;AAAA,QAC1C;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGP;AAEA,SAAS,eAAe,KAAoC;AAC1D,SAAO,OAAO,KAAK,IAAI,WAAW,EAAE,KAAK,CAAC,GAAG,MAAM;AACjD,QAAI,MAAML,aAAAA,gBAAiB,QAAO;AAClC,QAAI,MAAMA,aAAAA,gBAAiB,QAAO;AAClC,UAAM,KAAK,IAAI,aAAa,CAAC;AAC7B,UAAM,KAAK,IAAI,aAAa,CAAC;AAC7B,QAAI,MAAM,QAAQ,MAAM,KAAM,QAAO,EAAE,cAAc,CAAC;AACtD,QAAI,MAAM,KAAM,QAAO;AACvB,QAAI,MAAM,KAAM,QAAO;AACvB,QAAI,OAAO,GAAI,QAAO,KAAK;AAC3B,WAAO,EAAE,cAAc,CAAC;AAAA,EAC1B,CAAC;AACH;AAEA,SAAS,cACP,UACA,aACW;AACX,QAAM,WAAWM,aAAAA,cAAc,QAAQ;AACvC,QAAM,QAAQC,aAAAA,SAAS,QAAQ,EAAE,KAAK,CAAC,GAAG,MAAM;AAC9C,UAAM,KACJ,YAAY,IAAI,EAAE,UAAUP,aAAAA,eAAe,KAAK,OAAO;AACzD,UAAM,KACJ,YAAY,IAAI,EAAE,UAAUA,aAAAA,eAAe,KAAK,OAAO;AACzD,QAAI,OAAO,GAAI,QAAO,KAAK;AAC3B,QAAI,EAAE,cAAc,EAAE;AACpB,aAAO,EAAE,UAAU,cAAc,EAAE,SAAS;AAC9C,WAAO,OAAO,EAAE,EAAE,EAAE,cAAc,OAAO,EAAE,EAAE,CAAC;AAAA,EAChD,CAAC;AACD,SAAO,MAAM,QAAQ,CAAC,SAAS;AAAA,IAC7B;AAAA,IACA,GAAGQ,aAAAA,YAAY,SAAS,IAAI,KAAK,EAAE,KAAK,CAAA,CAAE;AAAA,EAAA,CAC3C;AACH;AAEA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,QAAM,UAAUC,MAAAA,QAAQ,MAAM;AAC5B,UAAM,cAAc,IAAI,IAAI,eAAe,GAAG,EAAE,IAAI,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;AACrE,WAAO,cAAc,UAAU,WAAW;AAAA,EAC5C,GAAG,CAAC,KAAK,QAAQ,CAAC;AAClB,QAAM,WAAWC,aAAAA,wBAAwB,SAAS,IAAI,QAAQ,IAAI,SAAS;AAE3E,WAAS,eACP,OACA,QACA;AACA,UAAM,SAAS,MAAM;AACrB,QACE,OAAO;AAAA,MACL;AAAA,IAAA;AAGF;AACF,UAAM,aAAa,OAAO,QAAQ,iBAAiB;AACnD,QAAI,cAAc,eAAe,OAAO,QAAQ,qBAAqB;AACnE;AACF,QAAI,WAAWV,aAAAA,iBAAiB;AAC9B,YAAM,QAAQ,IAAI,eAAe,QAAQ;AAAA,QACvC,UAAU;AAAA,QACV,OAAO;AAAA,QACP,QAAQ;AAAA,MAAA,CACT;AACD,UAAI,CAAC,MAAO;AAAA,IACd;AACA,QAAI,YAAY,MAAM;AAAA,EACxB;AAEA,MAAI,QAAQ,WAAW,GAAG;AACxB,WACEC,2BAAAA,IAAC,KAAA,EAAE,WAAU,kEACV,UAAA,YACH;AAAA,EAEJ;AAEA,SACEA,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,eAAY;AAAA,MACZ,WAAU;AAAA,MAEV,UAAAA,2BAAAA;AAAAA,QAACU,kBAAAA;AAAAA,QAAA;AAAA,UACC,UAAU;AAAA,UACV,QAAQ,IAAI;AAAA,UACZ,SAAO;AAAA,UACP,gBAAgB,CAAC,MAAM;AACrB,kBAAM,SAAS,EAAE,UAAUX,aAAAA;AAC3B,kBAAM,YACJ,WAAWA,aAAAA,mBAAmB,IAAI,aAAa,MAAM,KAAK;AAC5D,mBACEC,2BAAAA;AAAAA,cAAC;AAAA,cAAA;AAAA,gBACC,OAAO,GAAG,MAAM,MAAM,CAAC,GAAG,YAAY,KAAK,gBAAgB;AAAA,cAAA;AAAA,YAAA;AAAA,UAGjE;AAAA,UACA,gBAAgB,CAAC,OAAO;AAAA,YACtB,eAAe;AAAA,YACf,cAAc,MACZ,IAAI,mBAAmB,EAAE,UAAUD,aAAAA,eAAe;AAAA,YACpD,cAAc,MAAM,IAAI,mBAAmB,IAAI;AAAA,YAC/C,SAAS,CAAC,UACR,eAAe,OAAO,EAAE,UAAUA,aAAAA,eAAe;AAAA,UAAA;AAAA,UAEpD,GAAG;AAAA,UACH,GAAI,mBAAmB,EAAE,qBAAqB,CAAA;AAAA,QAAC;AAAA,MAAA;AAAA,IAClD;AAAA,EAAA;AAGN;AAEA,SAAS,gBAAgB;AAAA,EACvB;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAOG;AACD,QAAM,WAAWY,aAAAA,oBAAoB,SAAS,MAAM;AACpD,QAAM,cAAc,SAAS,SAAS;AACtC,SACEV,2BAAAA,KAAC,OAAA,EAAI,WAAU,aAAY,uBAAqB,QAC9C,UAAA;AAAA,IAAAD,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC,OACE,WAAWD,aAAAA,kBACP,uBACA,eAAe,KAAK;AAAA,MAAA;AAAA,IAAA;AAAA,IAG5BC,2BAAAA;AAAAA,MAACY,cAAAA;AAAAA,MAAA;AAAA,QACC;AAAA,QACA,QAAQ,IAAI;AAAA,QACZ;AAAA,QACA,SAAS,WAAW;AAAA,QACpB,mBAAmB,CAAC;AAAA,QACpB,iBAAiB;AAAA,QACjB,qBACE,cAAc,mCAAmC;AAAA,QAElD,GAAG,IAAI;AAAA,QACP,GAAI,mBAAmB,EAAE,qBAAqB,CAAA;AAAA,MAAC;AAAA,IAAA;AAAA,EAClD,GACF;AAEJ;AAOO,SAAS,iBAAiB,OAA8B;AAC7D,QAAM,MAAMC,eAAAA,0BAAA;AACZ,QAAM,QAAQ,eAAe,KAAK;AAClC,QAAM,UAAUC,MAAAA,OAAoB,IAAI;AACxC,QAAM,aAAaA,MAAAA,OAAuB,IAAI;AAC9C,QAAM,CAAC,eAAe,gBAAgB,IAAIC,MAAAA,SAAwB,IAAI;AACtE,QAAM,CAAC,cAAc,eAAe,IAAIA,MAAAA,SAAS,KAAK;AACtD,QAAM,iBAAgB,2BAAK,cAAa,YAAY,IAAI,gBAAgB;AAExEC,QAAAA,UAAU,MAAM;AACd,QAAI,CAAC,OAAO,MAAM,qBAAqB,YAAY,CAAC,eAAe;AACjE,uBAAiB,IAAI;AACrB;AAAA,IACF;AACA,UAAM,UAAU,IAAI,WAAW;AAC/B,UAAM,OAAO,QAAQ;AACrB,UAAM,UAAU,WAAW;AAC3B,QAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,QAAS;AAEnC,UAAM,SAAS,MAAM;AACnB,YAAM,YAAY,IAAI,aAAa,aAAa;AAChD,UAAI,aAAa,MAAM;AACrB,yBAAiB,IAAI;AACrB;AAAA,MACF;AACA,YAAM,aAAa,YAAY,QAAQ,sBAAA,EAAwB;AAC/D,YAAM,gBAAgB,OAAO,WAAW,QAAQ,MAAM,GAAG,KAAK;AAC9D,YAAM,aACJ,gBAAgB,aAAa,QAAQ,wBAAwB;AAC/D,uBAAiB,KAAK,IAAI,GAAG,UAAU,CAAC;AAAA,IAC1C;AACA,WAAA;AACA,YAAQ,iBAAiB,UAAU,QAAQ,EAAE,SAAS,MAAM;AAC5D,WAAO,iBAAiB,UAAU,MAAM;AACxC,UAAM,WACJ,OAAO,mBAAmB,cAAc,OAAO,IAAI,eAAe,MAAM;AAC1E,yCAAU,QAAQ;AAClB,yCAAU,QAAQ;AAClB,WAAO,MAAM;AACX,cAAQ,oBAAoB,UAAU,MAAM;AAC5C,aAAO,oBAAoB,UAAU,MAAM;AAC3C,2CAAU;AAAA,IACZ;AAAA,EACF,GAAG,CAAC,KAAK,eAAe,MAAM,gBAAgB,CAAC;AAE/C,MAAI,CAAC,IAAK,QAAO;AAGjB,QAAM,aAAaC,aAAAA,wBAAwB,IAAI,UAAU,IAAI,MAAM;AACnE,QAAM,UAAU,eAAe,IAAI,WAAW;AAC9C,QAAM,QAAQX,aAAAA,SAAS,OAAO,EAAE;AAChC,QAAM,gBACJA,aAAAA,SAAS,IAAI,QAAQ,EAAE,SAASA,aAAAA,SAAS,UAAU,EAAE;AACvD,MAAI,IAAI,aAAa,YAAY,UAAU,KAAK,kBAAkB;AAChE,WAAO;AAET,SACEL,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAK;AAAA,MACL,eAAY;AAAA,MACZ,WAAWC,MAAAA,GAAG,gCAAgC,MAAM,SAAS;AAAA,MAE7D,UAAA;AAAA,QAAAD,2BAAAA;AAAAA,UAAC;AAAA,UAAA;AAAA,YACC,eAAY;AAAA,YACZ,WAAU;AAAA,YAER,UAAA;AAAA,eAAA,QAAQ,KAAK,IAAI,aAAa,UAC9BD,2BAAAA;AAAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,QAAQ,IAAI,aAAa;AAAA,kBACzB,SAAS,IAAI;AAAA,kBACb,QAAO;AAAA,kBAEN,cAAI,aAAa,WACd,kBAAkB,KAAK,MACvB,iBAAiB,KAAK;AAAA,gBAAA;AAAA,cAAA;AAAA,cAG7B,gBAAgB,KACfC,2BAAAA;AAAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,MAAK;AAAA,kBACL,gBAAc;AAAA,kBACd,SAAS,MAAM,gBAAgB,CAAC,UAAU,CAAC,KAAK;AAAA,kBAChD,WAAWC,MAAAA;AAAAA,oBACT;AAAA,oBACA,eACI,sDACA;AAAA,kBAAA;AAAA,kBAEP,UAAA;AAAA,oBAAA;AAAA,oBACY;AAAA,oBAAc;AAAA,kBAAA;AAAA,gBAAA;AAAA,cAAA;AAAA,cAG5B,IAAI,aAAa,YAChBF,2BAAAA;AAAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,MAAK;AAAA,kBACL,SAAS,IAAI;AAAA,kBACb,WAAU;AAAA,kBAET,UAAA,IAAI,aAAa,QAAQ,UAAU;AAAA,gBAAA;AAAA,cAAA;AAAA,YACtC;AAAA,UAAA;AAAA,QAAA;AAAA,QAGH,IAAI,aAAa,QAChBA,2BAAAA;AAAAA,UAAC;AAAA,UAAA;AAAA,YACC;AAAA,YACA,UAAU;AAAA,YACV;AAAA,YACA,YACE,gBAAgB,IAAI,sBAAsB;AAAA,YAE3C,GAAI,MAAM,mBACP,EAAE,kBAAkB,MAAM,iBAAA,IAC1B,CAAA;AAAA,UAAC;AAAA,QAAA,IAEL,IAAI,aAAa,aAAa,IAAI,gBACpCA,2BAAAA;AAAAA,UAAC;AAAA,UAAA;AAAA,YACC,KAAK;AAAA,YACL,eAAY;AAAA,YACZ,WAAU;AAAA,YACV,OAAO,iBAAiB,OAAO,SAAY,EAAE,KAAK,cAAA;AAAA,YAElD,UAAAA,2BAAAA;AAAAA,cAAC;AAAA,cAAA;AAAA,gBACC;AAAA,gBACA,UAAU;AAAA,gBACV,QAAQ,IAAI;AAAA,gBACZ,OAAO,MAAM,IAAI,aAAa;AAAA,gBAC7B,GAAI,MAAM,YAAY,SAAY,EAAE,SAAS,MAAM,QAAA,IAAY,CAAA;AAAA,gBAC/D,GAAI,MAAM,mBACP,EAAE,kBAAkB,MAAM,iBAAA,IAC1B,CAAA;AAAA,cAAC;AAAA,YAAA;AAAA,UACP;AAAA,QAAA,IAEA;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGV;;"}
@@ -1,4 +1,4 @@
1
- import { CommentAnchor } from './comment-types';
1
+ import { Comment, CommentAnchor } from './comment-types';
2
2
  export type CommentSidePanelProps = {
3
3
  /** Explicit label per anchor key. */
4
4
  anchorLabels?: Record<CommentAnchor, string>;
@@ -8,6 +8,8 @@ export type CommentSidePanelProps = {
8
8
  /** Position the focused thread beside its registered content anchor. */
9
9
  focusedAlignment?: "flow" | "anchor";
10
10
  className?: string;
11
+ /** Serialize one whole thread for Copy and its maximized Markdown tab. */
12
+ threadToMarkdown?: (thread: readonly Comment[]) => string;
11
13
  };
12
14
  /**
13
15
  * A controlled comment rail driven by {@link CommentProvider}. Shows a focused
@@ -1 +1 @@
1
- {"version":3,"file":"CommentSidePanel.d.ts","sourceRoot":"","sources":["../../src/comments/CommentSidePanel.tsx"],"names":[],"mappings":"AAkBA,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,iBAAiB,CAAC;AAEzB,MAAM,MAAM,qBAAqB,GAAG;IAClC,qCAAqC;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;IAC7C,sEAAsE;IACtE,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,MAAM,CAAC;IACtD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,wEAAwE;IACxE,gBAAgB,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAwNF;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,sCA6H5D"}
1
+ {"version":3,"file":"CommentSidePanel.d.ts","sourceRoot":"","sources":["../../src/comments/CommentSidePanel.tsx"],"names":[],"mappings":"AAkBA,OAAO,EAEL,KAAK,OAAO,EACZ,KAAK,aAAa,EACnB,MAAM,iBAAiB,CAAC;AAEzB,MAAM,MAAM,qBAAqB,GAAG;IAClC,qCAAqC;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;IAC7C,sEAAsE;IACtE,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,MAAM,CAAC;IACtD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,wEAAwE;IACxE,gBAAgB,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,KAAK,MAAM,CAAC;CAC3D,CAAC;AA8NF;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,sCAuI5D"}
@@ -83,7 +83,8 @@ function AllComments({
83
83
  ctx,
84
84
  comments,
85
85
  label,
86
- emptyLabel
86
+ emptyLabel,
87
+ threadToMarkdown
87
88
  }) {
88
89
  const ordered = useMemo(() => {
89
90
  const anchorOrder = new Map(orderedAnchors(ctx).map((a, i) => [a, i]));
@@ -139,7 +140,8 @@ function AllComments({
139
140
  onMouseLeave: () => ctx.setHighlightAnchor(null),
140
141
  onClick: (event) => activateThread(event, c.anchor ?? DOCUMENT_ANCHOR)
141
142
  }),
142
- ...handlers
143
+ ...handlers,
144
+ ...threadToMarkdown ? { threadToMarkdown } : {}
143
145
  }
144
146
  )
145
147
  }
@@ -150,7 +152,8 @@ function FocusedComments({
150
152
  comments: visible,
151
153
  anchor,
152
154
  label,
153
- compact
155
+ compact,
156
+ threadToMarkdown
154
157
  }) {
155
158
  const comments = selectAnchorThreads(visible, anchor);
156
159
  const hasComments = comments.length > 0;
@@ -171,7 +174,8 @@ function FocusedComments({
171
174
  autoFocusComposer: !hasComments,
172
175
  defaultExpanded: hasComments,
173
176
  composerPlaceholder: hasComments ? "Add another top-level comment…" : "Add a comment…",
174
- ...ctx.callbacks
177
+ ...ctx.callbacks,
178
+ ...threadToMarkdown ? { threadToMarkdown } : {}
175
179
  }
176
180
  )
177
181
  ] });
@@ -221,7 +225,8 @@ function CommentSidePanel(props) {
221
225
  const visible = showResolved ? ctx.comments : unresolved;
222
226
  const total = getRoots(visible).length;
223
227
  const resolvedCount = getRoots(ctx.comments).length - getRoots(unresolved).length;
224
- if (ctx.railMode === "closed" && total === 0 && resolvedCount === 0) return null;
228
+ if (ctx.railMode === "closed" && total === 0 && resolvedCount === 0)
229
+ return null;
225
230
  return /* @__PURE__ */ jsxs(
226
231
  "aside",
227
232
  {
@@ -279,7 +284,8 @@ function CommentSidePanel(props) {
279
284
  ctx,
280
285
  comments: visible,
281
286
  label,
282
- emptyLabel: resolvedCount > 0 ? "No open comments." : "No comments yet."
287
+ emptyLabel: resolvedCount > 0 ? "No open comments." : "No comments yet.",
288
+ ...props.threadToMarkdown ? { threadToMarkdown: props.threadToMarkdown } : {}
283
289
  }
284
290
  ) : ctx.railMode === "focused" && ctx.focusedAnchor ? /* @__PURE__ */ jsx(
285
291
  "div",
@@ -295,7 +301,8 @@ function CommentSidePanel(props) {
295
301
  comments: visible,
296
302
  anchor: ctx.focusedAnchor,
297
303
  label: label(ctx.focusedAnchor),
298
- ...props.compact !== void 0 ? { compact: props.compact } : {}
304
+ ...props.compact !== void 0 ? { compact: props.compact } : {},
305
+ ...props.threadToMarkdown ? { threadToMarkdown: props.threadToMarkdown } : {}
299
306
  }
300
307
  )
301
308
  }
@@ -1 +1 @@
1
- {"version":3,"file":"CommentSidePanel.js","sources":["../../src/comments/CommentSidePanel.tsx"],"sourcesContent":["import { useEffect, useMemo, useRef, useState, type MouseEvent } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon } from \"../data/Icon\";\nimport { UiComment } from \"../icons\";\nimport { CommentThread } from \"./CommentThread\";\nimport { CommentThreadList } from \"./CommentThreadList\";\nimport {\n useCommentContextOptional,\n type CommentContextValue,\n} from \"./comment-context\";\nimport {\n buildThreadListHandlers,\n getRoots,\n selectAnchorThreads,\n selectUnresolvedThreads,\n sortReplies,\n buildReplyMap,\n} from \"./comment-utils\";\nimport {\n DOCUMENT_ANCHOR,\n type Comment,\n type CommentAnchor,\n} from \"./comment-types\";\n\nexport type CommentSidePanelProps = {\n /** Explicit label per anchor key. */\n anchorLabels?: Record<CommentAnchor, string>;\n /** Fallback label formatter for anchors without an explicit label. */\n formatAnchorLabel?: (anchor: CommentAnchor) => string;\n compact?: boolean;\n /** Position the focused thread beside its registered content anchor. */\n focusedAlignment?: \"flow\" | \"anchor\";\n className?: string;\n};\n\nfunction defaultAnchorLabel(anchor: CommentAnchor): string {\n if (anchor === DOCUMENT_ANCHOR) return \"General\";\n return anchor\n .replace(/\\[\\d+\\]/g, \"\")\n .replaceAll(\".\", \" › \")\n .replaceAll(\"_\", \" \")\n .trim();\n}\n\nfunction useAnchorLabel(props: CommentSidePanelProps) {\n return (anchor: CommentAnchor): string =>\n props.anchorLabels?.[anchor] ??\n props.formatAnchorLabel?.(anchor) ??\n defaultAnchorLabel(anchor);\n}\n\nfunction LocationMeta({ label }: { label: string }) {\n return (\n <span\n data-testid=\"comment-location-meta\"\n className=\"inline-flex items-center rounded-full bg-muted px-2 py-1 text-[10px] font-medium text-muted-foreground\"\n >\n {label}\n </span>\n );\n}\n\nfunction RailToggle({\n active,\n onClick,\n children,\n testId,\n}: {\n active?: boolean;\n onClick: () => void;\n children: React.ReactNode;\n testId?: string;\n}) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n data-testid={testId}\n className={cn(\n \"inline-flex items-center gap-1.5 rounded-full border px-3 py-1.5 text-xs font-medium shadow-sm transition-colors\",\n active\n ? \"border-primary bg-primary text-primary-foreground\"\n : \"border-border bg-background text-muted-foreground hover:text-foreground\",\n )}\n >\n <Icon icon={UiComment} className=\"text-xs\" />\n {children}\n </button>\n );\n}\n\nfunction orderedAnchors(ctx: CommentContextValue): string[] {\n return Object.keys(ctx.commentMeta).sort((a, b) => {\n if (a === DOCUMENT_ANCHOR) return -1;\n if (b === DOCUMENT_ANCHOR) return 1;\n const at = ctx.getAnchorTop(a);\n const bt = ctx.getAnchorTop(b);\n if (at == null && bt == null) return a.localeCompare(b);\n if (at == null) return 1;\n if (bt == null) return -1;\n if (at !== bt) return at - bt;\n return a.localeCompare(b);\n });\n}\n\nfunction orderComments(\n comments: Comment[],\n anchorOrder: Map<string, number>,\n): Comment[] {\n const replyMap = buildReplyMap(comments);\n const roots = getRoots(comments).sort((a, b) => {\n const ai =\n anchorOrder.get(a.anchor ?? DOCUMENT_ANCHOR) ?? Number.MAX_SAFE_INTEGER;\n const bi =\n anchorOrder.get(b.anchor ?? DOCUMENT_ANCHOR) ?? Number.MAX_SAFE_INTEGER;\n if (ai !== bi) return ai - bi;\n if (a.createdAt !== b.createdAt)\n return a.createdAt.localeCompare(b.createdAt);\n return String(a.id).localeCompare(String(b.id));\n });\n return roots.flatMap((root) => [\n root,\n ...sortReplies(replyMap.get(root.id) ?? []),\n ]);\n}\n\nfunction AllComments({\n ctx,\n comments,\n label,\n emptyLabel,\n}: {\n ctx: CommentContextValue;\n comments: Comment[];\n label: (a: CommentAnchor) => string;\n emptyLabel: string;\n}) {\n const ordered = useMemo(() => {\n const anchorOrder = new Map(orderedAnchors(ctx).map((a, i) => [a, i]));\n return orderComments(comments, anchorOrder);\n }, [ctx, comments]);\n const handlers = buildThreadListHandlers(ordered, ctx.config, ctx.callbacks);\n\n function activateThread(\n event: MouseEvent<HTMLDivElement>,\n anchor: CommentAnchor,\n ) {\n const target = event.target as Element;\n if (\n target.closest(\n 'button, a, input, textarea, select, [contenteditable=\"true\"]',\n )\n )\n return;\n const roleButton = target.closest('[role=\"button\"]');\n if (roleButton && roleButton !== target.closest(\"[data-comment-kind]\"))\n return;\n if (anchor !== DOCUMENT_ANCHOR) {\n const found = ctx.scrollToAnchor(anchor, {\n behavior: \"smooth\",\n block: \"start\",\n offset: 12,\n });\n if (!found) return;\n }\n ctx.focusAnchor(anchor);\n }\n\n if (ordered.length === 0) {\n return (\n <p className=\"rounded-lg bg-muted/40 px-3 py-2 text-xs text-muted-foreground\">\n {emptyLabel}\n </p>\n );\n }\n\n return (\n <div\n data-testid=\"comment-all-rail\"\n className=\"space-y-3 overflow-y-auto pr-1\"\n >\n <CommentThreadList\n comments={ordered}\n config={ctx.config}\n compact\n renderRootMeta={(c) => {\n const anchor = c.anchor ?? DOCUMENT_ANCHOR;\n const available =\n anchor === DOCUMENT_ANCHOR || ctx.getAnchorTop(anchor) != null;\n return (\n <LocationMeta\n label={`${label(anchor)}${available ? \"\" : \" · Unavailable\"}`}\n />\n );\n }}\n getThreadProps={(c) => ({\n \"data-testid\": \"comment-feed-item\",\n onMouseEnter: () =>\n ctx.setHighlightAnchor(c.anchor ?? DOCUMENT_ANCHOR),\n onMouseLeave: () => ctx.setHighlightAnchor(null),\n onClick: (event) =>\n activateThread(event, c.anchor ?? DOCUMENT_ANCHOR),\n })}\n {...handlers}\n />\n </div>\n );\n}\n\nfunction FocusedComments({\n ctx,\n comments: visible,\n anchor,\n label,\n compact,\n}: {\n ctx: CommentContextValue;\n comments: Comment[];\n anchor: CommentAnchor;\n label: string;\n compact?: boolean;\n}) {\n const comments = selectAnchorThreads(visible, anchor);\n const hasComments = comments.length > 0;\n return (\n <div className=\"space-y-3\" data-comment-anchor={anchor}>\n <LocationMeta\n label={\n anchor === DOCUMENT_ANCHOR\n ? \"Whole-page comment\"\n : `Attached to ${label}`\n }\n />\n <CommentThread\n comments={comments}\n config={ctx.config}\n anchor={anchor}\n compact={compact ?? false}\n autoFocusComposer={!hasComments}\n defaultExpanded={hasComments}\n composerPlaceholder={\n hasComments ? \"Add another top-level comment…\" : \"Add a comment…\"\n }\n {...ctx.callbacks}\n />\n </div>\n );\n}\n\n/**\n * A controlled comment rail driven by {@link CommentProvider}. Shows a focused\n * thread for the active anchor, the full document feed in anchor order, or a\n * toggle when collapsed. Renders nothing outside a provider or when empty.\n */\nexport function CommentSidePanel(props: CommentSidePanelProps) {\n const ctx = useCommentContextOptional();\n const label = useAnchorLabel(props);\n const railRef = useRef<HTMLElement>(null);\n const focusedRef = useRef<HTMLDivElement>(null);\n const [focusedOffset, setFocusedOffset] = useState<number | null>(null);\n const [showResolved, setShowResolved] = useState(false);\n const focusedAnchor = ctx?.railMode === \"focused\" ? ctx.focusedAnchor : null;\n\n useEffect(() => {\n if (!ctx || props.focusedAlignment !== \"anchor\" || !focusedAnchor) {\n setFocusedOffset(null);\n return;\n }\n const content = ctx.contentRef.current;\n const rail = railRef.current;\n const focused = focusedRef.current;\n if (!content || !rail || !focused) return;\n\n const update = () => {\n const anchorTop = ctx.getAnchorTop(focusedAnchor);\n if (anchorTop == null) {\n setFocusedOffset(null);\n return;\n }\n const desiredTop = anchorTop + content.getBoundingClientRect().top;\n const currentOffset = Number.parseFloat(focused.style.top) || 0;\n const nextOffset =\n currentOffset + desiredTop - focused.getBoundingClientRect().top;\n setFocusedOffset(Math.max(0, nextOffset));\n };\n update();\n content.addEventListener(\"scroll\", update, { passive: true });\n window.addEventListener(\"resize\", update);\n const observer =\n typeof ResizeObserver === \"undefined\" ? null : new ResizeObserver(update);\n observer?.observe(content);\n observer?.observe(rail);\n return () => {\n content.removeEventListener(\"scroll\", update);\n window.removeEventListener(\"resize\", update);\n observer?.disconnect();\n };\n }, [ctx, focusedAnchor, props.focusedAlignment]);\n\n if (!ctx) return null;\n\n // Threads, not cards: a reply is part of its root, never a separate entry.\n const unresolved = selectUnresolvedThreads(ctx.comments, ctx.config);\n const visible = showResolved ? ctx.comments : unresolved;\n const total = getRoots(visible).length;\n const resolvedCount = getRoots(ctx.comments).length - getRoots(unresolved).length;\n if (ctx.railMode === \"closed\" && total === 0 && resolvedCount === 0) return null;\n\n return (\n <aside\n ref={railRef}\n data-testid=\"comment-side-panel\"\n className={cn(\"relative w-[320px] space-y-3\", props.className)}\n >\n <div\n data-testid=\"comment-rail-header\"\n className=\"sticky top-0 z-20 flex items-center gap-2 bg-background py-2\"\n >\n {(total > 0 || ctx.railMode === \"all\") && (\n <RailToggle\n active={ctx.railMode === \"all\"}\n onClick={ctx.openCommentList}\n testId=\"comment-open-all\"\n >\n {ctx.railMode === \"closed\"\n ? `Open comments (${total})`\n : `All comments (${total})`}\n </RailToggle>\n )}\n {resolvedCount > 0 && (\n <button\n type=\"button\"\n aria-pressed={showResolved}\n onClick={() => setShowResolved((shown) => !shown)}\n className={cn(\n \"rounded-full border px-2 py-1 text-xs font-medium transition-colors\",\n showResolved\n ? \"border-primary bg-primary text-primary-foreground\"\n : \"border-border bg-background text-muted-foreground hover:text-foreground\",\n )}\n >\n Resolved ({resolvedCount})\n </button>\n )}\n {ctx.railMode !== \"closed\" && (\n <button\n type=\"button\"\n onClick={ctx.closeRail}\n className=\"ml-auto rounded-md px-2 py-1 text-xs font-medium text-muted-foreground hover:bg-muted hover:text-foreground\"\n >\n {ctx.railMode === \"all\" ? \"Close\" : \"Hide\"}\n </button>\n )}\n </div>\n {ctx.railMode === \"all\" ? (\n <AllComments\n ctx={ctx}\n comments={visible}\n label={label}\n emptyLabel={resolvedCount > 0 ? \"No open comments.\" : \"No comments yet.\"}\n />\n ) : ctx.railMode === \"focused\" && ctx.focusedAnchor ? (\n <div\n ref={focusedRef}\n data-testid=\"comment-focused-rail\"\n className=\"relative space-y-3\"\n style={focusedOffset == null ? undefined : { top: focusedOffset }}\n >\n <FocusedComments\n ctx={ctx}\n comments={visible}\n anchor={ctx.focusedAnchor}\n label={label(ctx.focusedAnchor)}\n {...(props.compact !== undefined ? { compact: props.compact } : {})}\n />\n </div>\n ) : null}\n </aside>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"CommentSidePanel.js","sources":["../../src/comments/CommentSidePanel.tsx"],"sourcesContent":["import { useEffect, useMemo, useRef, useState, type MouseEvent } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon } from \"../data/Icon\";\nimport { UiComment } from \"../icons\";\nimport { CommentThread } from \"./CommentThread\";\nimport { CommentThreadList } from \"./CommentThreadList\";\nimport {\n useCommentContextOptional,\n type CommentContextValue,\n} from \"./comment-context\";\nimport {\n buildThreadListHandlers,\n getRoots,\n selectAnchorThreads,\n selectUnresolvedThreads,\n sortReplies,\n buildReplyMap,\n} from \"./comment-utils\";\nimport {\n DOCUMENT_ANCHOR,\n type Comment,\n type CommentAnchor,\n} from \"./comment-types\";\n\nexport type CommentSidePanelProps = {\n /** Explicit label per anchor key. */\n anchorLabels?: Record<CommentAnchor, string>;\n /** Fallback label formatter for anchors without an explicit label. */\n formatAnchorLabel?: (anchor: CommentAnchor) => string;\n compact?: boolean;\n /** Position the focused thread beside its registered content anchor. */\n focusedAlignment?: \"flow\" | \"anchor\";\n className?: string;\n /** Serialize one whole thread for Copy and its maximized Markdown tab. */\n threadToMarkdown?: (thread: readonly Comment[]) => string;\n};\n\nfunction defaultAnchorLabel(anchor: CommentAnchor): string {\n if (anchor === DOCUMENT_ANCHOR) return \"General\";\n return anchor\n .replace(/\\[\\d+\\]/g, \"\")\n .replaceAll(\".\", \" › \")\n .replaceAll(\"_\", \" \")\n .trim();\n}\n\nfunction useAnchorLabel(props: CommentSidePanelProps) {\n return (anchor: CommentAnchor): string =>\n props.anchorLabels?.[anchor] ??\n props.formatAnchorLabel?.(anchor) ??\n defaultAnchorLabel(anchor);\n}\n\nfunction LocationMeta({ label }: { label: string }) {\n return (\n <span\n data-testid=\"comment-location-meta\"\n className=\"inline-flex items-center rounded-full bg-muted px-2 py-1 text-[10px] font-medium text-muted-foreground\"\n >\n {label}\n </span>\n );\n}\n\nfunction RailToggle({\n active,\n onClick,\n children,\n testId,\n}: {\n active?: boolean;\n onClick: () => void;\n children: React.ReactNode;\n testId?: string;\n}) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n data-testid={testId}\n className={cn(\n \"inline-flex items-center gap-1.5 rounded-full border px-3 py-1.5 text-xs font-medium shadow-sm transition-colors\",\n active\n ? \"border-primary bg-primary text-primary-foreground\"\n : \"border-border bg-background text-muted-foreground hover:text-foreground\",\n )}\n >\n <Icon icon={UiComment} className=\"text-xs\" />\n {children}\n </button>\n );\n}\n\nfunction orderedAnchors(ctx: CommentContextValue): string[] {\n return Object.keys(ctx.commentMeta).sort((a, b) => {\n if (a === DOCUMENT_ANCHOR) return -1;\n if (b === DOCUMENT_ANCHOR) return 1;\n const at = ctx.getAnchorTop(a);\n const bt = ctx.getAnchorTop(b);\n if (at == null && bt == null) return a.localeCompare(b);\n if (at == null) return 1;\n if (bt == null) return -1;\n if (at !== bt) return at - bt;\n return a.localeCompare(b);\n });\n}\n\nfunction orderComments(\n comments: Comment[],\n anchorOrder: Map<string, number>,\n): Comment[] {\n const replyMap = buildReplyMap(comments);\n const roots = getRoots(comments).sort((a, b) => {\n const ai =\n anchorOrder.get(a.anchor ?? DOCUMENT_ANCHOR) ?? Number.MAX_SAFE_INTEGER;\n const bi =\n anchorOrder.get(b.anchor ?? DOCUMENT_ANCHOR) ?? Number.MAX_SAFE_INTEGER;\n if (ai !== bi) return ai - bi;\n if (a.createdAt !== b.createdAt)\n return a.createdAt.localeCompare(b.createdAt);\n return String(a.id).localeCompare(String(b.id));\n });\n return roots.flatMap((root) => [\n root,\n ...sortReplies(replyMap.get(root.id) ?? []),\n ]);\n}\n\nfunction AllComments({\n ctx,\n comments,\n label,\n emptyLabel,\n threadToMarkdown,\n}: {\n ctx: CommentContextValue;\n comments: Comment[];\n label: (a: CommentAnchor) => string;\n emptyLabel: string;\n threadToMarkdown?: (thread: readonly Comment[]) => string;\n}) {\n const ordered = useMemo(() => {\n const anchorOrder = new Map(orderedAnchors(ctx).map((a, i) => [a, i]));\n return orderComments(comments, anchorOrder);\n }, [ctx, comments]);\n const handlers = buildThreadListHandlers(ordered, ctx.config, ctx.callbacks);\n\n function activateThread(\n event: MouseEvent<HTMLDivElement>,\n anchor: CommentAnchor,\n ) {\n const target = event.target as Element;\n if (\n target.closest(\n 'button, a, input, textarea, select, [contenteditable=\"true\"]',\n )\n )\n return;\n const roleButton = target.closest('[role=\"button\"]');\n if (roleButton && roleButton !== target.closest(\"[data-comment-kind]\"))\n return;\n if (anchor !== DOCUMENT_ANCHOR) {\n const found = ctx.scrollToAnchor(anchor, {\n behavior: \"smooth\",\n block: \"start\",\n offset: 12,\n });\n if (!found) return;\n }\n ctx.focusAnchor(anchor);\n }\n\n if (ordered.length === 0) {\n return (\n <p className=\"rounded-lg bg-muted/40 px-3 py-2 text-xs text-muted-foreground\">\n {emptyLabel}\n </p>\n );\n }\n\n return (\n <div\n data-testid=\"comment-all-rail\"\n className=\"space-y-3 overflow-y-auto pr-1\"\n >\n <CommentThreadList\n comments={ordered}\n config={ctx.config}\n compact\n renderRootMeta={(c) => {\n const anchor = c.anchor ?? DOCUMENT_ANCHOR;\n const available =\n anchor === DOCUMENT_ANCHOR || ctx.getAnchorTop(anchor) != null;\n return (\n <LocationMeta\n label={`${label(anchor)}${available ? \"\" : \" · Unavailable\"}`}\n />\n );\n }}\n getThreadProps={(c) => ({\n \"data-testid\": \"comment-feed-item\",\n onMouseEnter: () =>\n ctx.setHighlightAnchor(c.anchor ?? DOCUMENT_ANCHOR),\n onMouseLeave: () => ctx.setHighlightAnchor(null),\n onClick: (event) =>\n activateThread(event, c.anchor ?? DOCUMENT_ANCHOR),\n })}\n {...handlers}\n {...(threadToMarkdown ? { threadToMarkdown } : {})}\n />\n </div>\n );\n}\n\nfunction FocusedComments({\n ctx,\n comments: visible,\n anchor,\n label,\n compact,\n threadToMarkdown,\n}: {\n ctx: CommentContextValue;\n comments: Comment[];\n anchor: CommentAnchor;\n label: string;\n compact?: boolean;\n threadToMarkdown?: (thread: readonly Comment[]) => string;\n}) {\n const comments = selectAnchorThreads(visible, anchor);\n const hasComments = comments.length > 0;\n return (\n <div className=\"space-y-3\" data-comment-anchor={anchor}>\n <LocationMeta\n label={\n anchor === DOCUMENT_ANCHOR\n ? \"Whole-page comment\"\n : `Attached to ${label}`\n }\n />\n <CommentThread\n comments={comments}\n config={ctx.config}\n anchor={anchor}\n compact={compact ?? false}\n autoFocusComposer={!hasComments}\n defaultExpanded={hasComments}\n composerPlaceholder={\n hasComments ? \"Add another top-level comment…\" : \"Add a comment…\"\n }\n {...ctx.callbacks}\n {...(threadToMarkdown ? { threadToMarkdown } : {})}\n />\n </div>\n );\n}\n\n/**\n * A controlled comment rail driven by {@link CommentProvider}. Shows a focused\n * thread for the active anchor, the full document feed in anchor order, or a\n * toggle when collapsed. Renders nothing outside a provider or when empty.\n */\nexport function CommentSidePanel(props: CommentSidePanelProps) {\n const ctx = useCommentContextOptional();\n const label = useAnchorLabel(props);\n const railRef = useRef<HTMLElement>(null);\n const focusedRef = useRef<HTMLDivElement>(null);\n const [focusedOffset, setFocusedOffset] = useState<number | null>(null);\n const [showResolved, setShowResolved] = useState(false);\n const focusedAnchor = ctx?.railMode === \"focused\" ? ctx.focusedAnchor : null;\n\n useEffect(() => {\n if (!ctx || props.focusedAlignment !== \"anchor\" || !focusedAnchor) {\n setFocusedOffset(null);\n return;\n }\n const content = ctx.contentRef.current;\n const rail = railRef.current;\n const focused = focusedRef.current;\n if (!content || !rail || !focused) return;\n\n const update = () => {\n const anchorTop = ctx.getAnchorTop(focusedAnchor);\n if (anchorTop == null) {\n setFocusedOffset(null);\n return;\n }\n const desiredTop = anchorTop + content.getBoundingClientRect().top;\n const currentOffset = Number.parseFloat(focused.style.top) || 0;\n const nextOffset =\n currentOffset + desiredTop - focused.getBoundingClientRect().top;\n setFocusedOffset(Math.max(0, nextOffset));\n };\n update();\n content.addEventListener(\"scroll\", update, { passive: true });\n window.addEventListener(\"resize\", update);\n const observer =\n typeof ResizeObserver === \"undefined\" ? null : new ResizeObserver(update);\n observer?.observe(content);\n observer?.observe(rail);\n return () => {\n content.removeEventListener(\"scroll\", update);\n window.removeEventListener(\"resize\", update);\n observer?.disconnect();\n };\n }, [ctx, focusedAnchor, props.focusedAlignment]);\n\n if (!ctx) return null;\n\n // Threads, not cards: a reply is part of its root, never a separate entry.\n const unresolved = selectUnresolvedThreads(ctx.comments, ctx.config);\n const visible = showResolved ? ctx.comments : unresolved;\n const total = getRoots(visible).length;\n const resolvedCount =\n getRoots(ctx.comments).length - getRoots(unresolved).length;\n if (ctx.railMode === \"closed\" && total === 0 && resolvedCount === 0)\n return null;\n\n return (\n <aside\n ref={railRef}\n data-testid=\"comment-side-panel\"\n className={cn(\"relative w-[320px] space-y-3\", props.className)}\n >\n <div\n data-testid=\"comment-rail-header\"\n className=\"sticky top-0 z-20 flex items-center gap-2 bg-background py-2\"\n >\n {(total > 0 || ctx.railMode === \"all\") && (\n <RailToggle\n active={ctx.railMode === \"all\"}\n onClick={ctx.openCommentList}\n testId=\"comment-open-all\"\n >\n {ctx.railMode === \"closed\"\n ? `Open comments (${total})`\n : `All comments (${total})`}\n </RailToggle>\n )}\n {resolvedCount > 0 && (\n <button\n type=\"button\"\n aria-pressed={showResolved}\n onClick={() => setShowResolved((shown) => !shown)}\n className={cn(\n \"rounded-full border px-2 py-1 text-xs font-medium transition-colors\",\n showResolved\n ? \"border-primary bg-primary text-primary-foreground\"\n : \"border-border bg-background text-muted-foreground hover:text-foreground\",\n )}\n >\n Resolved ({resolvedCount})\n </button>\n )}\n {ctx.railMode !== \"closed\" && (\n <button\n type=\"button\"\n onClick={ctx.closeRail}\n className=\"ml-auto rounded-md px-2 py-1 text-xs font-medium text-muted-foreground hover:bg-muted hover:text-foreground\"\n >\n {ctx.railMode === \"all\" ? \"Close\" : \"Hide\"}\n </button>\n )}\n </div>\n {ctx.railMode === \"all\" ? (\n <AllComments\n ctx={ctx}\n comments={visible}\n label={label}\n emptyLabel={\n resolvedCount > 0 ? \"No open comments.\" : \"No comments yet.\"\n }\n {...(props.threadToMarkdown\n ? { threadToMarkdown: props.threadToMarkdown }\n : {})}\n />\n ) : ctx.railMode === \"focused\" && ctx.focusedAnchor ? (\n <div\n ref={focusedRef}\n data-testid=\"comment-focused-rail\"\n className=\"relative space-y-3\"\n style={focusedOffset == null ? undefined : { top: focusedOffset }}\n >\n <FocusedComments\n ctx={ctx}\n comments={visible}\n anchor={ctx.focusedAnchor}\n label={label(ctx.focusedAnchor)}\n {...(props.compact !== undefined ? { compact: props.compact } : {})}\n {...(props.threadToMarkdown\n ? { threadToMarkdown: props.threadToMarkdown }\n : {})}\n />\n </div>\n ) : null}\n </aside>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -17,6 +17,7 @@ function CommentThread({
17
17
  hideComposer = false,
18
18
  renderRootMeta,
19
19
  renderBody,
20
+ threadToMarkdown,
20
21
  onCreate,
21
22
  onReply,
22
23
  onUpdateStatus,
@@ -41,6 +42,7 @@ function CommentThread({
41
42
  defaultExpanded,
42
43
  ...renderRootMeta ? { renderRootMeta } : {},
43
44
  ...renderBody ? { renderBody } : {},
45
+ ...threadToMarkdown ? { threadToMarkdown } : {},
44
46
  ...listHandlers
45
47
  }
46
48
  ),