@flamingo-stack/openframe-frontend-core 0.0.204 → 0.0.205

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 (509) hide show
  1. package/dist/{chunk-4CWSZPXH.cjs → chunk-24KCAECR.cjs} +9 -9
  2. package/dist/{chunk-4CWSZPXH.cjs.map → chunk-24KCAECR.cjs.map} +1 -1
  3. package/dist/chunk-27APPAJN.cjs +24 -0
  4. package/dist/chunk-27APPAJN.cjs.map +1 -0
  5. package/dist/{chunk-UC43NICZ.cjs → chunk-664KA5FI.cjs} +2 -35
  6. package/dist/chunk-664KA5FI.cjs.map +1 -0
  7. package/dist/chunk-6RZYJICV.cjs +24 -0
  8. package/dist/chunk-6RZYJICV.cjs.map +1 -0
  9. package/dist/chunk-7L4DWM7P.js +24 -0
  10. package/dist/chunk-7L4DWM7P.js.map +1 -0
  11. package/dist/chunk-BZFW3FOF.cjs +21 -0
  12. package/dist/chunk-BZFW3FOF.cjs.map +1 -0
  13. package/dist/{chunk-N57KWHDB.js → chunk-CIPO6DXK.js} +5 -5
  14. package/dist/chunk-EL5YVPD5.js +21 -0
  15. package/dist/chunk-EL5YVPD5.js.map +1 -0
  16. package/dist/{chunk-ARQ4XP64.cjs → chunk-FDCFI7YT.cjs} +40080 -31492
  17. package/dist/chunk-FDCFI7YT.cjs.map +1 -0
  18. package/dist/chunk-G7UE6RKV.cjs +121 -0
  19. package/dist/chunk-G7UE6RKV.cjs.map +1 -0
  20. package/dist/{chunk-25LVV26X.cjs → chunk-JUZGUQMX.cjs} +178 -50
  21. package/dist/chunk-JUZGUQMX.cjs.map +1 -0
  22. package/dist/{chunk-SZPJ5R5B.js → chunk-KSOOKNBG.js} +1 -34
  23. package/dist/chunk-KSOOKNBG.js.map +1 -0
  24. package/dist/{chunk-RMB5DVED.cjs → chunk-KUZGEA7U.cjs} +83 -66
  25. package/dist/chunk-KUZGEA7U.cjs.map +1 -0
  26. package/dist/chunk-LXC6P2EO.js +63 -0
  27. package/dist/chunk-LXC6P2EO.js.map +1 -0
  28. package/dist/chunk-MJNXIEV2.js +24 -0
  29. package/dist/chunk-MJNXIEV2.js.map +1 -0
  30. package/dist/{chunk-CPXLQ57U.js → chunk-MVGGXOFA.js} +37 -20
  31. package/dist/chunk-MVGGXOFA.js.map +1 -0
  32. package/dist/{chunk-LY34ORX6.js → chunk-O55ZUAX7.js} +39920 -31332
  33. package/dist/chunk-O55ZUAX7.js.map +1 -0
  34. package/dist/chunk-OHPI2HRK.js +47 -0
  35. package/dist/chunk-OHPI2HRK.js.map +1 -0
  36. package/dist/chunk-PLJLE4A4.js +121 -0
  37. package/dist/chunk-PLJLE4A4.js.map +1 -0
  38. package/dist/{chunk-XGL5FKIK.js → chunk-SCN5WFIZ.js} +148 -20
  39. package/dist/chunk-SCN5WFIZ.js.map +1 -0
  40. package/dist/chunk-WBR7H6E3.cjs +47 -0
  41. package/dist/chunk-WBR7H6E3.cjs.map +1 -0
  42. package/dist/chunk-XL4V2PYG.cjs +63 -0
  43. package/dist/chunk-XL4V2PYG.cjs.map +1 -0
  44. package/dist/components/announcement-bar.d.ts.map +1 -1
  45. package/dist/components/chat/chat-attachment-bar.d.ts +66 -0
  46. package/dist/components/chat/chat-attachment-bar.d.ts.map +1 -0
  47. package/dist/components/chat/chat-container.d.ts +21 -1
  48. package/dist/components/chat/chat-container.d.ts.map +1 -1
  49. package/dist/components/chat/chat-input.d.ts.map +1 -1
  50. package/dist/components/chat/chat-message-enhanced.d.ts.map +1 -1
  51. package/dist/components/chat/chat-message-list.d.ts.map +1 -1
  52. package/dist/components/chat/chat-panel-context.d.ts +9 -0
  53. package/dist/components/chat/chat-panel-context.d.ts.map +1 -0
  54. package/dist/components/chat/chat-ticket-list.d.ts +1 -1
  55. package/dist/components/chat/chat-ticket-list.d.ts.map +1 -1
  56. package/dist/components/chat/embeddable-chat.d.ts +42 -0
  57. package/dist/components/chat/embeddable-chat.d.ts.map +1 -0
  58. package/dist/components/chat/entity-cards/admin-content-card.d.ts +34 -0
  59. package/dist/components/chat/entity-cards/admin-content-card.d.ts.map +1 -0
  60. package/dist/components/chat/entity-cards/block-card.d.ts.map +1 -0
  61. package/dist/components/chat/entity-cards/blog-card.d.ts +30 -0
  62. package/dist/components/chat/entity-cards/blog-card.d.ts.map +1 -0
  63. package/dist/components/chat/entity-cards/blog-image-placeholder.d.ts +26 -0
  64. package/dist/components/chat/entity-cards/blog-image-placeholder.d.ts.map +1 -0
  65. package/dist/components/chat/entity-cards/campaign-card-admin.d.ts +33 -0
  66. package/dist/components/chat/entity-cards/campaign-card-admin.d.ts.map +1 -0
  67. package/dist/components/chat/entity-cards/case-study-card.d.ts +20 -0
  68. package/dist/components/chat/entity-cards/case-study-card.d.ts.map +1 -0
  69. package/dist/components/chat/entity-cards/chat-ticket-item.d.ts.map +1 -0
  70. package/dist/components/chat/{chat-video-entity-card.d.ts → entity-cards/chat-video-entity-card.d.ts} +1 -1
  71. package/dist/components/chat/entity-cards/chat-video-entity-card.d.ts.map +1 -0
  72. package/dist/components/chat/entity-cards/customer-interview-card.d.ts +19 -0
  73. package/dist/components/chat/entity-cards/customer-interview-card.d.ts.map +1 -0
  74. package/dist/components/chat/entity-cards/data-room-doc-card.d.ts +47 -0
  75. package/dist/components/chat/entity-cards/data-room-doc-card.d.ts.map +1 -0
  76. package/dist/components/chat/entity-cards/dispatch.d.ts +119 -0
  77. package/dist/components/chat/entity-cards/dispatch.d.ts.map +1 -0
  78. package/dist/components/chat/entity-cards/entity-author-card.d.ts +87 -0
  79. package/dist/components/chat/entity-cards/entity-author-card.d.ts.map +1 -0
  80. package/dist/components/chat/entity-cards/generic-entity-card.d.ts +42 -0
  81. package/dist/components/chat/entity-cards/generic-entity-card.d.ts.map +1 -0
  82. package/dist/components/chat/entity-cards/github-activity-card.d.ts +37 -0
  83. package/dist/components/chat/entity-cards/github-activity-card.d.ts.map +1 -0
  84. package/dist/components/chat/entity-cards/hubspot-ticket-card.d.ts +28 -0
  85. package/dist/components/chat/entity-cards/hubspot-ticket-card.d.ts.map +1 -0
  86. package/dist/components/chat/entity-cards/index.d.ts +32 -0
  87. package/dist/components/chat/entity-cards/index.d.ts.map +1 -0
  88. package/dist/components/chat/entity-cards/investor-update-card.d.ts +19 -0
  89. package/dist/components/chat/entity-cards/investor-update-card.d.ts.map +1 -0
  90. package/dist/components/chat/entity-cards/onboarding-guide-card.d.ts +20 -0
  91. package/dist/components/chat/entity-cards/onboarding-guide-card.d.ts.map +1 -0
  92. package/dist/components/chat/entity-cards/product-release-card-defaults.d.ts +21 -0
  93. package/dist/components/chat/entity-cards/product-release-card-defaults.d.ts.map +1 -0
  94. package/dist/components/chat/entity-cards/product-release-card.d.ts +12 -0
  95. package/dist/components/chat/entity-cards/product-release-card.d.ts.map +1 -0
  96. package/dist/components/chat/entity-cards/program-card-defaults.d.ts +32 -0
  97. package/dist/components/chat/entity-cards/program-card-defaults.d.ts.map +1 -0
  98. package/dist/components/chat/entity-cards/program-card.d.ts +37 -0
  99. package/dist/components/chat/entity-cards/program-card.d.ts.map +1 -0
  100. package/dist/components/chat/entity-cards/roadmap-card.d.ts +28 -0
  101. package/dist/components/chat/entity-cards/roadmap-card.d.ts.map +1 -0
  102. package/dist/components/chat/entity-cards/roadmap-vote-button.d.ts +12 -0
  103. package/dist/components/chat/entity-cards/roadmap-vote-button.d.ts.map +1 -0
  104. package/dist/components/chat/entity-cards/slack-message-card.d.ts +28 -0
  105. package/dist/components/chat/entity-cards/slack-message-card.d.ts.map +1 -0
  106. package/dist/components/chat/entity-cards/task-type-icon.d.ts +6 -0
  107. package/dist/components/chat/entity-cards/task-type-icon.d.ts.map +1 -0
  108. package/dist/components/chat/hooks/index.d.ts +10 -0
  109. package/dist/components/chat/hooks/index.d.ts.map +1 -1
  110. package/dist/components/chat/hooks/use-chat-attachment-image-gallery.d.ts +5 -0
  111. package/dist/components/chat/hooks/use-chat-attachment-image-gallery.d.ts.map +1 -0
  112. package/dist/components/chat/hooks/use-chat-attachments.d.ts +33 -0
  113. package/dist/components/chat/hooks/use-chat-attachments.d.ts.map +1 -0
  114. package/dist/components/chat/hooks/use-chat-card-item.d.ts +7 -0
  115. package/dist/components/chat/hooks/use-chat-card-item.d.ts.map +1 -0
  116. package/dist/components/chat/hooks/use-chat-identity.d.ts +44 -0
  117. package/dist/components/chat/hooks/use-chat-identity.d.ts.map +1 -0
  118. package/dist/components/chat/hooks/use-chat.d.ts +30 -0
  119. package/dist/components/chat/hooks/use-chat.d.ts.map +1 -0
  120. package/dist/components/chat/hooks/use-close-on-navigation.d.ts +2 -0
  121. package/dist/components/chat/hooks/use-close-on-navigation.d.ts.map +1 -0
  122. package/dist/components/chat/hooks/use-embedded-chat.d.ts +174 -0
  123. package/dist/components/chat/hooks/use-embedded-chat.d.ts.map +1 -0
  124. package/dist/components/chat/hooks/use-proxied-image-url.d.ts +18 -0
  125. package/dist/components/chat/hooks/use-proxied-image-url.d.ts.map +1 -0
  126. package/dist/components/chat/hooks/use-slash-commands.d.ts +32 -0
  127. package/dist/components/chat/hooks/use-slash-commands.d.ts.map +1 -0
  128. package/dist/components/chat/hooks/use-sse.d.ts +57 -0
  129. package/dist/components/chat/hooks/use-sse.d.ts.map +1 -0
  130. package/dist/components/chat/index.cjs +393 -0
  131. package/dist/components/chat/index.cjs.map +1 -0
  132. package/dist/components/chat/index.d.ts +5 -3
  133. package/dist/components/chat/index.d.ts.map +1 -1
  134. package/dist/components/chat/index.js +393 -0
  135. package/dist/components/chat/index.js.map +1 -0
  136. package/dist/components/chat/nav-link-anchor-via-runtime.d.ts +33 -0
  137. package/dist/components/chat/nav-link-anchor-via-runtime.d.ts.map +1 -0
  138. package/dist/components/chat/source-action-button.d.ts +39 -0
  139. package/dist/components/chat/source-action-button.d.ts.map +1 -0
  140. package/dist/components/chat/types/chat.types.d.ts +36 -0
  141. package/dist/components/chat/types/chat.types.d.ts.map +1 -1
  142. package/dist/components/chat/types/component.types.d.ts +56 -11
  143. package/dist/components/chat/types/component.types.d.ts.map +1 -1
  144. package/dist/components/chat/types/entities/blog.d.ts +14 -0
  145. package/dist/components/chat/types/entities/blog.d.ts.map +1 -0
  146. package/dist/components/chat/types/entities/case-study.d.ts +10 -0
  147. package/dist/components/chat/types/entities/case-study.d.ts.map +1 -0
  148. package/dist/components/chat/types/entities/content-ref.d.ts +23 -0
  149. package/dist/components/chat/types/entities/content-ref.d.ts.map +1 -0
  150. package/dist/components/chat/types/entities/customer-interview.d.ts +10 -0
  151. package/dist/components/chat/types/entities/customer-interview.d.ts.map +1 -0
  152. package/dist/components/chat/types/entities/data-room-doc.d.ts +37 -0
  153. package/dist/components/chat/types/entities/data-room-doc.d.ts.map +1 -0
  154. package/dist/components/chat/types/entities/github-activity.d.ts +29 -0
  155. package/dist/components/chat/types/entities/github-activity.d.ts.map +1 -0
  156. package/dist/components/chat/types/entities/hubspot-ticket.d.ts +39 -0
  157. package/dist/components/chat/types/entities/hubspot-ticket.d.ts.map +1 -0
  158. package/dist/components/chat/types/entities/index.d.ts +28 -0
  159. package/dist/components/chat/types/entities/index.d.ts.map +1 -0
  160. package/dist/components/chat/types/entities/investor-update.d.ts +83 -0
  161. package/dist/components/chat/types/entities/investor-update.d.ts.map +1 -0
  162. package/dist/components/chat/types/entities/onboarding-guide.d.ts +79 -0
  163. package/dist/components/chat/types/entities/onboarding-guide.d.ts.map +1 -0
  164. package/dist/components/chat/types/entities/program-types.d.ts +303 -0
  165. package/dist/components/chat/types/entities/program-types.d.ts.map +1 -0
  166. package/dist/components/chat/types/entities/roadmap-item.d.ts +41 -0
  167. package/dist/components/chat/types/entities/roadmap-item.d.ts.map +1 -0
  168. package/dist/components/chat/types/entities/slack-message.d.ts +28 -0
  169. package/dist/components/chat/types/entities/slack-message.d.ts.map +1 -0
  170. package/dist/components/chat/types/index.d.ts +1 -0
  171. package/dist/components/chat/types/index.d.ts.map +1 -1
  172. package/dist/components/chat/utils/agent-status-message.d.ts +18 -0
  173. package/dist/components/chat/utils/agent-status-message.d.ts.map +1 -0
  174. package/dist/components/chat/utils/auto-continuation-directive.d.ts +38 -0
  175. package/dist/components/chat/utils/auto-continuation-directive.d.ts.map +1 -0
  176. package/dist/components/chat/utils/chat-attachment-markdown.d.ts +114 -0
  177. package/dist/components/chat/utils/chat-attachment-markdown.d.ts.map +1 -0
  178. package/dist/components/chat/utils/chat-authed-fetch.d.ts +13 -0
  179. package/dist/components/chat/utils/chat-authed-fetch.d.ts.map +1 -0
  180. package/dist/components/chat/utils/chat-nav-resolution.d.ts +72 -0
  181. package/dist/components/chat/utils/chat-nav-resolution.d.ts.map +1 -0
  182. package/dist/components/chat/utils/chat-proxy-auth-storage.d.ts +43 -0
  183. package/dist/components/chat/utils/chat-proxy-auth-storage.d.ts.map +1 -0
  184. package/dist/components/chat/utils/chip-action-class.d.ts +16 -0
  185. package/dist/components/chat/utils/chip-action-class.d.ts.map +1 -0
  186. package/dist/components/chat/utils/chip-styles.d.ts +32 -0
  187. package/dist/components/chat/utils/chip-styles.d.ts.map +1 -0
  188. package/dist/components/chat/utils/clickup-task-type-utils.d.ts +38 -0
  189. package/dist/components/chat/utils/clickup-task-type-utils.d.ts.map +1 -0
  190. package/dist/components/chat/utils/compact-card-classes.d.ts +50 -0
  191. package/dist/components/chat/utils/compact-card-classes.d.ts.map +1 -0
  192. package/dist/components/chat/utils/decide-new-tab.d.ts +39 -0
  193. package/dist/components/chat/utils/decide-new-tab.d.ts.map +1 -0
  194. package/dist/components/chat/utils/external-app-urls.d.ts +14 -0
  195. package/dist/components/chat/utils/external-app-urls.d.ts.map +1 -0
  196. package/dist/components/chat/utils/flatten-assistant-content.d.ts +25 -0
  197. package/dist/components/chat/utils/flatten-assistant-content.d.ts.map +1 -0
  198. package/dist/components/chat/utils/icon-registry.d.ts +67 -0
  199. package/dist/components/chat/utils/icon-registry.d.ts.map +1 -0
  200. package/dist/components/chat/utils/index.d.ts +21 -0
  201. package/dist/components/chat/utils/index.d.ts.map +1 -1
  202. package/dist/components/chat/utils/is-cross-origin-url.d.ts +22 -0
  203. package/dist/components/chat/utils/is-cross-origin-url.d.ts.map +1 -0
  204. package/dist/components/chat/utils/nav-anchor-props.d.ts +54 -0
  205. package/dist/components/chat/utils/nav-anchor-props.d.ts.map +1 -0
  206. package/dist/components/chat/utils/nav-click-handler.d.ts +51 -0
  207. package/dist/components/chat/utils/nav-click-handler.d.ts.map +1 -0
  208. package/dist/components/chat/utils/scroll-anchor.d.ts +30 -0
  209. package/dist/components/chat/utils/scroll-anchor.d.ts.map +1 -0
  210. package/dist/components/chat/utils/slash-dispatch-utils.d.ts +109 -0
  211. package/dist/components/chat/utils/slash-dispatch-utils.d.ts.map +1 -0
  212. package/dist/components/chat/utils/source-icons.d.ts +8 -0
  213. package/dist/components/chat/utils/source-icons.d.ts.map +1 -0
  214. package/dist/components/chat/utils/source-row-cta.d.ts +111 -0
  215. package/dist/components/chat/utils/source-row-cta.d.ts.map +1 -0
  216. package/dist/components/features/figma-prototype-viewer.d.ts.map +1 -1
  217. package/dist/components/features/index.cjs +12 -6
  218. package/dist/components/features/index.cjs.map +1 -1
  219. package/dist/components/features/index.js +11 -5
  220. package/dist/components/features/video.d.ts.map +1 -1
  221. package/dist/components/icons/index.cjs +3 -3
  222. package/dist/components/icons/index.js +2 -2
  223. package/dist/components/index.cjs +274 -8
  224. package/dist/components/index.cjs.map +1 -1
  225. package/dist/components/index.js +273 -7
  226. package/dist/components/interactive-wrapper.d.ts +3 -3
  227. package/dist/components/navigation/index.cjs +12 -6
  228. package/dist/components/navigation/index.cjs.map +1 -1
  229. package/dist/components/navigation/index.js +11 -5
  230. package/dist/components/resizable.d.ts +1 -1
  231. package/dist/components/shared/product-release/product-release-card-skeleton.d.ts +1 -1
  232. package/dist/components/shared/product-release/product-release-card-skeleton.d.ts.map +1 -1
  233. package/dist/components/shared/product-release/product-release-card.d.ts +19 -12
  234. package/dist/components/shared/product-release/product-release-card.d.ts.map +1 -1
  235. package/dist/components/shared/product-release/release-detail-page.d.ts +2 -4
  236. package/dist/components/shared/product-release/release-detail-page.d.ts.map +1 -1
  237. package/dist/components/ui/button/button.d.ts +13 -0
  238. package/dist/components/ui/button/button.d.ts.map +1 -1
  239. package/dist/components/ui/dashboard-info-card.d.ts.map +1 -1
  240. package/dist/components/ui/entity-image.d.ts.map +1 -1
  241. package/dist/components/ui/file-manager/index.cjs +71 -70
  242. package/dist/components/ui/file-manager/index.cjs.map +1 -1
  243. package/dist/components/ui/file-manager/index.js +6 -5
  244. package/dist/components/ui/file-manager/index.js.map +1 -1
  245. package/dist/components/ui/hover-dropdown.d.ts +66 -0
  246. package/dist/components/ui/hover-dropdown.d.ts.map +1 -0
  247. package/dist/components/ui/index.cjs +276 -6
  248. package/dist/components/ui/index.cjs.map +1 -1
  249. package/dist/components/ui/index.d.ts +1 -0
  250. package/dist/components/ui/index.d.ts.map +1 -1
  251. package/dist/components/ui/index.js +278 -8
  252. package/dist/components/ui/simple-markdown-renderer.d.ts.map +1 -1
  253. package/dist/components/ui/square-avatar.d.ts.map +1 -1
  254. package/dist/contexts/chat-runtime-context.d.ts +109 -0
  255. package/dist/contexts/chat-runtime-context.d.ts.map +1 -0
  256. package/dist/contexts/endpoints-runtime-context.d.ts +28 -0
  257. package/dist/contexts/endpoints-runtime-context.d.ts.map +1 -0
  258. package/dist/contexts/index.cjs +30 -0
  259. package/dist/contexts/index.cjs.map +1 -0
  260. package/dist/contexts/index.d.ts +26 -0
  261. package/dist/contexts/index.d.ts.map +1 -0
  262. package/dist/contexts/index.js +30 -0
  263. package/dist/contexts/index.js.map +1 -0
  264. package/dist/contexts/use-outer-or-default.d.ts +29 -0
  265. package/dist/contexts/use-outer-or-default.d.ts.map +1 -0
  266. package/dist/embed-shims/index.cjs +51 -0
  267. package/dist/embed-shims/index.cjs.map +1 -0
  268. package/dist/embed-shims/index.d.ts +31 -0
  269. package/dist/embed-shims/index.d.ts.map +1 -0
  270. package/dist/embed-shims/index.js +51 -0
  271. package/dist/embed-shims/index.js.map +1 -0
  272. package/dist/embed-shims/next-dynamic.cjs +12 -0
  273. package/dist/embed-shims/next-dynamic.cjs.map +1 -0
  274. package/dist/embed-shims/next-dynamic.d.ts +47 -0
  275. package/dist/embed-shims/next-dynamic.d.ts.map +1 -0
  276. package/dist/embed-shims/next-dynamic.js +12 -0
  277. package/dist/embed-shims/next-dynamic.js.map +1 -0
  278. package/dist/embed-shims/next-image.cjs +12 -0
  279. package/dist/embed-shims/next-image.cjs.map +1 -0
  280. package/dist/embed-shims/next-image.d.ts +28 -0
  281. package/dist/embed-shims/next-image.d.ts.map +1 -0
  282. package/dist/embed-shims/next-image.js +12 -0
  283. package/dist/embed-shims/next-image.js.map +1 -0
  284. package/dist/embed-shims/next-link.cjs +14 -0
  285. package/dist/embed-shims/next-link.cjs.map +1 -0
  286. package/dist/embed-shims/next-link.d.ts +22 -0
  287. package/dist/embed-shims/next-link.d.ts.map +1 -0
  288. package/dist/embed-shims/next-link.js +14 -0
  289. package/dist/embed-shims/next-link.js.map +1 -0
  290. package/dist/embed-shims/next-navigation.cjs +30 -0
  291. package/dist/embed-shims/next-navigation.cjs.map +1 -0
  292. package/dist/embed-shims/next-navigation.d.ts +46 -0
  293. package/dist/embed-shims/next-navigation.d.ts.map +1 -0
  294. package/dist/embed-shims/next-navigation.js +30 -0
  295. package/dist/embed-shims/next-navigation.js.map +1 -0
  296. package/dist/hooks/index.cjs +10 -4
  297. package/dist/hooks/index.cjs.map +1 -1
  298. package/dist/hooks/index.d.ts +2 -0
  299. package/dist/hooks/index.d.ts.map +1 -1
  300. package/dist/hooks/index.js +9 -3
  301. package/dist/hooks/use-access-code-integration.d.ts +48 -0
  302. package/dist/hooks/use-access-code-integration.d.ts.map +1 -0
  303. package/dist/hooks/use-contact-submission.d.ts.map +1 -1
  304. package/dist/hooks/use-og-placeholder.d.ts +31 -0
  305. package/dist/hooks/use-og-placeholder.d.ts.map +1 -0
  306. package/dist/hooks/use-toast.d.ts +1 -1
  307. package/dist/index.cjs +367 -7
  308. package/dist/index.cjs.map +1 -1
  309. package/dist/index.js +378 -18
  310. package/dist/types/index.cjs.map +1 -1
  311. package/dist/types/index.js.map +1 -1
  312. package/dist/utils/access-code-client.d.ts +21 -37
  313. package/dist/utils/access-code-client.d.ts.map +1 -1
  314. package/dist/utils/cn.d.ts +0 -27
  315. package/dist/utils/cn.d.ts.map +1 -1
  316. package/dist/utils/color-analysis.d.ts +33 -0
  317. package/dist/utils/color-analysis.d.ts.map +1 -0
  318. package/dist/utils/date-formatters.d.ts +16 -5
  319. package/dist/utils/date-formatters.d.ts.map +1 -1
  320. package/dist/utils/fetch-priority.d.ts +3 -0
  321. package/dist/utils/fetch-priority.d.ts.map +1 -0
  322. package/dist/utils/format.d.ts +192 -1
  323. package/dist/utils/format.d.ts.map +1 -1
  324. package/dist/utils/image-proxy.d.ts +67 -2
  325. package/dist/utils/image-proxy.d.ts.map +1 -1
  326. package/dist/utils/index.cjs +1274 -155
  327. package/dist/utils/index.cjs.map +1 -1
  328. package/dist/utils/index.d.ts +19 -3
  329. package/dist/utils/index.d.ts.map +1 -1
  330. package/dist/utils/index.js +1200 -157
  331. package/dist/utils/index.js.map +1 -1
  332. package/dist/utils/local-storage-adapter.d.ts +46 -0
  333. package/dist/utils/local-storage-adapter.d.ts.map +1 -0
  334. package/dist/utils/source-icons.d.ts +78 -0
  335. package/dist/utils/source-icons.d.ts.map +1 -0
  336. package/package.json +29 -2
  337. package/src/components/announcement-bar.tsx +26 -4
  338. package/src/components/categories-cart.tsx +1 -1
  339. package/src/components/chat/chat-attachment-bar.tsx +323 -0
  340. package/src/components/chat/chat-container.tsx +39 -5
  341. package/src/components/chat/chat-input.tsx +7 -1
  342. package/src/components/chat/chat-message-enhanced.tsx +32 -22
  343. package/src/components/chat/chat-message-list.tsx +53 -4
  344. package/src/components/chat/chat-panel-context.tsx +37 -0
  345. package/src/components/chat/chat-ticket-list.tsx +1 -1
  346. package/src/components/chat/embeddable-chat.tsx +1106 -0
  347. package/src/components/chat/entity-cards/admin-content-card.tsx +155 -0
  348. package/src/components/chat/entity-cards/blog-card.tsx +259 -0
  349. package/src/components/chat/entity-cards/blog-image-placeholder.tsx +52 -0
  350. package/src/components/chat/entity-cards/campaign-card-admin.tsx +113 -0
  351. package/src/components/chat/entity-cards/case-study-card.tsx +192 -0
  352. package/src/components/chat/{chat-ticket-item.tsx → entity-cards/chat-ticket-item.tsx} +2 -2
  353. package/src/components/chat/{chat-video-entity-card.tsx → entity-cards/chat-video-entity-card.tsx} +2 -2
  354. package/src/components/chat/entity-cards/customer-interview-card.tsx +211 -0
  355. package/src/components/chat/entity-cards/data-room-doc-card.tsx +120 -0
  356. package/src/components/chat/entity-cards/dispatch.tsx +1093 -0
  357. package/src/components/chat/entity-cards/entity-author-card.tsx +193 -0
  358. package/src/components/chat/entity-cards/generic-entity-card.tsx +144 -0
  359. package/src/components/chat/entity-cards/github-activity-card.tsx +305 -0
  360. package/src/components/chat/entity-cards/hubspot-ticket-card.tsx +205 -0
  361. package/src/components/chat/entity-cards/index.ts +125 -0
  362. package/src/components/chat/entity-cards/investor-update-card.tsx +150 -0
  363. package/src/components/chat/entity-cards/onboarding-guide-card.tsx +326 -0
  364. package/src/components/chat/entity-cards/product-release-card-defaults.ts +57 -0
  365. package/src/components/chat/entity-cards/product-release-card.tsx +19 -0
  366. package/src/components/chat/entity-cards/program-card-defaults.ts +62 -0
  367. package/src/components/chat/entity-cards/program-card.tsx +451 -0
  368. package/src/components/chat/entity-cards/roadmap-card.tsx +356 -0
  369. package/src/components/chat/entity-cards/roadmap-vote-button.tsx +54 -0
  370. package/src/components/chat/entity-cards/slack-message-card.tsx +182 -0
  371. package/src/components/chat/entity-cards/task-type-icon.tsx +60 -0
  372. package/src/components/chat/hooks/index.ts +22 -0
  373. package/src/components/chat/hooks/use-chat-attachment-image-gallery.tsx +114 -0
  374. package/src/components/chat/hooks/use-chat-attachments.ts +429 -0
  375. package/src/components/chat/hooks/use-chat-card-item.ts +102 -0
  376. package/src/components/chat/hooks/use-chat-identity.ts +139 -0
  377. package/src/components/chat/hooks/use-chat.ts +501 -0
  378. package/src/components/chat/hooks/use-close-on-navigation.ts +87 -0
  379. package/src/components/chat/hooks/use-embedded-chat.ts +1023 -0
  380. package/src/components/chat/hooks/use-proxied-image-url.ts +31 -0
  381. package/src/components/chat/hooks/use-slash-commands.ts +106 -0
  382. package/src/components/chat/hooks/use-sse.ts +143 -0
  383. package/src/components/chat/index.ts +30 -4
  384. package/src/components/chat/nav-link-anchor-via-runtime.tsx +72 -0
  385. package/src/components/chat/source-action-button.tsx +120 -0
  386. package/src/components/chat/types/chat.types.ts +61 -0
  387. package/src/components/chat/types/component.types.ts +57 -11
  388. package/src/components/chat/types/entities/blog.ts +27 -0
  389. package/src/components/chat/types/entities/case-study.ts +14 -0
  390. package/src/components/chat/types/entities/content-ref.ts +23 -0
  391. package/src/components/chat/types/entities/customer-interview.ts +15 -0
  392. package/src/components/chat/types/entities/data-room-doc.ts +37 -0
  393. package/src/components/chat/types/entities/github-activity.ts +36 -0
  394. package/src/components/chat/types/entities/hubspot-ticket.ts +39 -0
  395. package/src/components/chat/types/entities/index.ts +28 -0
  396. package/src/components/chat/types/entities/investor-update.ts +100 -0
  397. package/src/components/chat/types/entities/onboarding-guide.ts +101 -0
  398. package/src/components/chat/types/entities/program-types.ts +433 -0
  399. package/src/components/chat/types/entities/roadmap-item.ts +42 -0
  400. package/src/components/chat/types/entities/slack-message.ts +28 -0
  401. package/src/components/chat/types/index.ts +1 -0
  402. package/src/components/chat/utils/agent-status-message.ts +52 -0
  403. package/src/components/chat/utils/auto-continuation-directive.ts +70 -0
  404. package/src/components/chat/utils/chat-attachment-markdown.ts +190 -0
  405. package/src/components/chat/utils/chat-authed-fetch.ts +73 -0
  406. package/src/components/chat/utils/chat-nav-resolution.ts +151 -0
  407. package/src/components/chat/utils/chat-proxy-auth-storage.ts +148 -0
  408. package/src/components/chat/utils/chip-action-class.ts +19 -0
  409. package/src/components/chat/utils/chip-styles.ts +51 -0
  410. package/src/components/chat/utils/clickup-task-type-utils.ts +59 -0
  411. package/src/components/chat/utils/compact-card-classes.ts +97 -0
  412. package/src/components/chat/utils/decide-new-tab.ts +57 -0
  413. package/src/components/chat/utils/external-app-urls.ts +19 -0
  414. package/src/components/chat/utils/flatten-assistant-content.ts +35 -0
  415. package/src/components/chat/utils/icon-registry.ts +297 -0
  416. package/src/components/chat/utils/index.ts +133 -0
  417. package/src/components/chat/utils/is-cross-origin-url.ts +28 -0
  418. package/src/components/chat/utils/nav-anchor-props.ts +78 -0
  419. package/src/components/chat/utils/nav-click-handler.ts +81 -0
  420. package/src/components/chat/utils/scroll-anchor.ts +35 -0
  421. package/src/components/chat/utils/slash-dispatch-utils.ts +183 -0
  422. package/src/components/chat/utils/source-icons.ts +14 -0
  423. package/src/components/chat/utils/source-row-cta.ts +215 -0
  424. package/src/components/empty-state.tsx +1 -1
  425. package/src/components/features/board/ticket-card.tsx +1 -1
  426. package/src/components/features/figma-prototype-viewer.tsx +2 -1
  427. package/src/components/features/media-gallery-manager.tsx +1 -1
  428. package/src/components/features/parallax-image-showcase.tsx +1 -1
  429. package/src/components/features/release-media-manager.tsx +1 -1
  430. package/src/components/features/seo-editor-preview.tsx +1 -1
  431. package/src/components/features/video.tsx +54 -3
  432. package/src/components/footer-waitlist-button.tsx +1 -1
  433. package/src/components/navigation/header.tsx +1 -1
  434. package/src/components/shared/onboarding/onboarding-step-card.tsx +1 -1
  435. package/src/components/shared/product-release/product-release-card-skeleton.tsx +8 -44
  436. package/src/components/shared/product-release/product-release-card.tsx +31 -116
  437. package/src/components/shared/product-release/release-detail-page.tsx +12 -16
  438. package/src/components/ui/actions-menu.tsx +1 -1
  439. package/src/components/ui/button/button.tsx +41 -11
  440. package/src/components/ui/button/split-button.tsx +1 -1
  441. package/src/components/ui/dashboard-info-card.tsx +2 -3
  442. package/src/components/ui/data-table/data-table-row.tsx +1 -1
  443. package/src/components/ui/entity-image.tsx +2 -8
  444. package/src/components/ui/hover-dropdown.tsx +258 -0
  445. package/src/components/ui/image-gallery-modal.tsx +1 -1
  446. package/src/components/ui/index.ts +1 -0
  447. package/src/components/ui/markdown-editor.tsx +1 -1
  448. package/src/components/ui/more-actions-menu.tsx +1 -1
  449. package/src/components/ui/organization-card.tsx +1 -1
  450. package/src/components/ui/simple-markdown-renderer.tsx +53 -5
  451. package/src/components/ui/square-avatar.tsx +3 -12
  452. package/src/components/ui/tab-navigation.tsx +1 -1
  453. package/src/components/ui/table/table-row.tsx +1 -1
  454. package/src/components/unified-filter-logic.tsx +1 -1
  455. package/src/components/unified-pagination.tsx +1 -1
  456. package/src/components/user-summary-stub.tsx +1 -1
  457. package/src/components/vendor-display-button.tsx +1 -1
  458. package/src/components/vendor-icon.tsx +1 -1
  459. package/src/contexts/chat-runtime-context.tsx +163 -0
  460. package/src/contexts/endpoints-runtime-context.tsx +68 -0
  461. package/src/contexts/index.ts +38 -0
  462. package/src/contexts/use-outer-or-default.ts +42 -0
  463. package/src/embed-shims/index.ts +42 -0
  464. package/src/embed-shims/next-dynamic.tsx +70 -0
  465. package/src/embed-shims/next-image.tsx +114 -0
  466. package/src/embed-shims/next-link.tsx +91 -0
  467. package/src/embed-shims/next-navigation.tsx +201 -0
  468. package/src/hooks/index.ts +9 -0
  469. package/src/hooks/state/use-api-params.ts +1 -1
  470. package/src/hooks/state/use-query-params.ts +1 -1
  471. package/src/hooks/use-access-code-integration.ts +107 -0
  472. package/src/hooks/use-contact-submission.ts +7 -3
  473. package/src/hooks/use-og-placeholder.ts +45 -0
  474. package/src/stories/OnboardingStepCard.stories.tsx +140 -0
  475. package/src/styles/chat-animations.css +65 -0
  476. package/src/styles/index.css +1 -0
  477. package/src/utils/access-code-client.ts +32 -75
  478. package/src/utils/cn.ts +0 -65
  479. package/src/utils/color-analysis.ts +205 -0
  480. package/src/utils/date-formatters.ts +54 -11
  481. package/src/utils/fetch-priority.ts +41 -0
  482. package/src/utils/format.ts +525 -1
  483. package/src/utils/image-proxy.ts +127 -7
  484. package/src/utils/index.ts +145 -5
  485. package/src/utils/local-storage-adapter.ts +105 -0
  486. package/src/utils/source-icons.ts +219 -0
  487. package/dist/chunk-25LVV26X.cjs.map +0 -1
  488. package/dist/chunk-ARQ4XP64.cjs.map +0 -1
  489. package/dist/chunk-CPXLQ57U.js.map +0 -1
  490. package/dist/chunk-LY34ORX6.js.map +0 -1
  491. package/dist/chunk-RMB5DVED.cjs.map +0 -1
  492. package/dist/chunk-SZPJ5R5B.js.map +0 -1
  493. package/dist/chunk-UC43NICZ.cjs.map +0 -1
  494. package/dist/chunk-XGL5FKIK.js.map +0 -1
  495. package/dist/components/chat/block-card.d.ts.map +0 -1
  496. package/dist/components/chat/chat-ticket-item.d.ts.map +0 -1
  497. package/dist/components/chat/chat-video-entity-card.d.ts.map +0 -1
  498. package/dist/utils/dynamic-icons.d.ts +0 -26
  499. package/dist/utils/dynamic-icons.d.ts.map +0 -1
  500. package/dist/utils/format-relative-time.d.ts +0 -21
  501. package/dist/utils/format-relative-time.d.ts.map +0 -1
  502. package/src/utils/.dynamic-icons.md +0 -30
  503. package/src/utils/.format-relative-time.md +0 -36
  504. package/src/utils/dynamic-icons.tsx +0 -120
  505. package/src/utils/format-relative-time.ts +0 -52
  506. /package/dist/{chunk-N57KWHDB.js.map → chunk-CIPO6DXK.js.map} +0 -0
  507. /package/dist/components/chat/{block-card.d.ts → entity-cards/block-card.d.ts} +0 -0
  508. /package/dist/components/chat/{chat-ticket-item.d.ts → entity-cards/chat-ticket-item.d.ts} +0 -0
  509. /package/src/components/chat/{block-card.tsx → entity-cards/block-card.tsx} +0 -0
@@ -0,0 +1,1093 @@
1
+ 'use client'
2
+
3
+ /**
4
+ * Lib-side entity-card dispatch — single switch over canonical chat cards.
5
+ *
6
+ * Lib-portable refactor of the hub's `components/shared/entity-card-dispatch.tsx`.
7
+ * Drops the hub-only imports:
8
+ * - `useNavLink` → click routing flows through `<NavLinkAnchorViaRuntime>`
9
+ * (reads `useRequiredChatRuntime` internally) or
10
+ * the chat-runtime's `handleChatNavClick` helper.
11
+ * - `currentPlatform` → runtime.source supplies the identifier.
12
+ * - `buildContentURL` → URLs arrive pre-composed by the server's
13
+ * RAG mapper (`ref.url`); the card just renders.
14
+ * - `tableIdForDocumentType` → only relevant for the hub-side ContentRef
15
+ * reverse-projection — not needed for chat
16
+ * inline cards.
17
+ * - hub `program-configs` → host provides via `ChatCardRenderOptions.extras`.
18
+ * - `buildProductReleaseCardProps` → ditto, host provides via `extras`.
19
+ *
20
+ * Adding a new chat-inline card type:
21
+ * 1. Implement the `size='sm'` branch + skeleton in `./<card>.tsx` (pure
22
+ * presentation, accepts `href` + `targetPlatform`).
23
+ * 2. Add one entry to `CHAT_CARD_REGISTRY` below.
24
+ *
25
+ * Public entry points consumed by the chat shell:
26
+ * - `renderChatInlineEntityCard(ref, opts)` — top-level marker dispatch
27
+ * (block-card hoist for video refs, otherwise compact card).
28
+ * - `<ChatCardLoader />` — fetch + skeleton + render the compact card for
29
+ * fetch-mode entries.
30
+ */
31
+
32
+ import React, { type ReactNode } from 'react'
33
+ import { useRequiredChatRuntime } from '../../../contexts/chat-runtime-context'
34
+ import type { ChatRef } from '../chat-ref.types'
35
+ import { useChatCardItem } from '../hooks/use-chat-card-item'
36
+ import { handleChatNavClick } from '../utils/nav-click-handler'
37
+ import { resolveSourceRowCTA, resolveSourceIcon } from '../utils/source-row-cta'
38
+ import { resolveHrefForRuntime } from '../utils/chat-nav-resolution'
39
+ import {
40
+ computeIsNewTab,
41
+ newTabAnchorAttrs,
42
+ buildAnchorProps,
43
+ } from '../utils/nav-anchor-props'
44
+ import { safeHref } from '../utils/compact-card-classes'
45
+ import { useChatPanel } from '../chat-panel-context'
46
+ import { getSourceLabel } from '../utils/source-icons'
47
+ import { SourceActionButton } from '../source-action-button'
48
+ import { NavLinkAnchorViaRuntime } from '../nav-link-anchor-via-runtime'
49
+ import { DEFAULT_PROGRAM_CONFIGS } from './program-card-defaults'
50
+ import { defaultBuildProductReleaseCardProps } from './product-release-card-defaults'
51
+ import { ChatVideoEntityCard } from './chat-video-entity-card'
52
+ import { BlockCard } from './block-card'
53
+ import { BlogCard, BlogCardSkeleton } from './blog-card'
54
+ import { CaseStudyCard, CaseStudyCardSkeleton } from './case-study-card'
55
+ import {
56
+ CustomerInterviewCard,
57
+ CustomerInterviewCardSkeleton,
58
+ } from './customer-interview-card'
59
+ import {
60
+ ProductReleaseCard,
61
+ ProductReleaseCardSkeleton,
62
+ type ProductReleaseCardProps,
63
+ } from './product-release-card'
64
+ import {
65
+ ProgramCard,
66
+ ProgramCardSkeleton,
67
+ type ProgramCardProps,
68
+ } from './program-card'
69
+ import {
70
+ InvestorUpdateCard,
71
+ InvestorUpdateCardSkeleton,
72
+ } from './investor-update-card'
73
+ import {
74
+ OnboardingGuideCard,
75
+ OnboardingGuideCardSkeleton,
76
+ } from './onboarding-guide-card'
77
+ import {
78
+ CampaignCardAdmin,
79
+ CampaignCardAdminSkeleton,
80
+ } from './campaign-card-admin'
81
+ import { RoadmapCard, RoadmapCardSkeleton } from './roadmap-card'
82
+ import {
83
+ GitHubActivityCard,
84
+ type GitHubActivityCardAnchorProps,
85
+ } from './github-activity-card'
86
+ import { SlackMessageCard } from './slack-message-card'
87
+ import { HubspotTicketCard } from './hubspot-ticket-card'
88
+ import { DataRoomDocCard } from './data-room-doc-card'
89
+ import {
90
+ GenericEntityCard,
91
+ type GenericEntityCardAnchorProps,
92
+ } from './generic-entity-card'
93
+ import type { GitHubActivityKind } from '../types/entities/github-activity'
94
+ import type { BaseProgramItem, ProgramConfig } from '../types/entities/program-types'
95
+
96
+ // =============================================================================
97
+ // Public option / extras shape
98
+ // =============================================================================
99
+
100
+ /** Optional host-side extras threaded through to render functions whose
101
+ * derived props can't be computed in lib alone (program configs and the
102
+ * product-release prop builder live in hub land). When omitted, the
103
+ * affected card types render `null` from the dispatch — the chat shell's
104
+ * fallback path takes over. */
105
+ export interface ChatCardDispatchExtras {
106
+ /** Per-program-type config map. Keyed by chat documentType
107
+ * (`podcast` / `webinar` / `event`). Each entry is the canonical
108
+ * `<ProgramConfig>` the `<ProgramCard>` expects. */
109
+ programConfigs?: {
110
+ podcast?: ProgramConfig<any>
111
+ webinar?: ProgramConfig<any>
112
+ event?: ProgramConfig<any>
113
+ }
114
+ /** Derive the `<ProductReleaseCard>` prop bundle from a hydrated
115
+ * release row. Hub callers wire `buildProductReleaseCardProps` from
116
+ * `lib/utils/product-release-card-props.ts`. */
117
+ buildProductReleaseCardProps?: (
118
+ release: any,
119
+ ) => Omit<ProductReleaseCardProps, 'size' | 'title' | 'summary' | 'version' | 'anchorProps'>
120
+ }
121
+
122
+ /** Per-card render options threaded through from the chat shell. */
123
+ export interface ChatCardRenderOptions {
124
+ baseRoute?: string
125
+ chipBasePlatform?: string
126
+ /** Host-supplied builders for cards whose derived props live in hub
127
+ * land (programs + product_release). When omitted, these card types
128
+ * render `null` and the shell falls back to title text. */
129
+ extras?: ChatCardDispatchExtras
130
+ /** Pre-computed new-tab decision for the inner anchor's `target`
131
+ * attribute. Required — always computed by `ChatCardLoader` via the
132
+ * same rule source chips use, so the rendered `<a target>` matches
133
+ * whatever `ChatCardNavWrap` + `handleChatNavClick` decide at click
134
+ * time. */
135
+ isNewTab: boolean
136
+ }
137
+
138
+ // =============================================================================
139
+ // Per-type "no-fetch" wrapper components (ChatRef carries everything).
140
+ // Each wrapper receives `isNewTab` as a prop — `ChatCardLoader` computes
141
+ // it ONCE via `computeIsNewTab` against the resolved `chatRef.url` and
142
+ // threads it through `renderOpts`. Wrappers must NOT call
143
+ // `computeIsNewTab` themselves; the parent's decision is the single
144
+ // source of truth for the rendered `<a target>` AND `ChatCardNavWrap`'s
145
+ // close-on-nav gate.
146
+ // =============================================================================
147
+
148
+ function GitHubChatCard({
149
+ chatRef,
150
+ kind,
151
+ isNewTab,
152
+ }: {
153
+ chatRef: ChatRef
154
+ kind: GitHubActivityKind
155
+ isNewTab: boolean
156
+ }) {
157
+ const anchorProps: GitHubActivityCardAnchorProps | undefined = buildAnchorProps(
158
+ chatRef.url,
159
+ isNewTab,
160
+ )
161
+ return (
162
+ <GitHubActivityCard
163
+ item={{
164
+ id: chatRef.id,
165
+ title: chatRef.title,
166
+ url: chatRef.url ?? null,
167
+ dateUpdated: chatRef.date ?? null,
168
+ kind,
169
+ }}
170
+ variant="compact"
171
+ anchorProps={anchorProps}
172
+ />
173
+ )
174
+ }
175
+
176
+ function HubspotTicketChatCard({
177
+ chatRef,
178
+ isNewTab,
179
+ }: {
180
+ chatRef: ChatRef
181
+ isNewTab: boolean
182
+ }) {
183
+ const status =
184
+ typeof chatRef.metadata?.status === 'string' ? (chatRef.metadata.status as string) : undefined
185
+ const statusLabel =
186
+ typeof chatRef.metadata?.statusLabel === 'string'
187
+ ? (chatRef.metadata.statusLabel as string)
188
+ : undefined
189
+ const priority =
190
+ typeof chatRef.metadata?.priority === 'string'
191
+ ? (chatRef.metadata.priority as string)
192
+ : undefined
193
+ const customerCompany =
194
+ typeof chatRef.metadata?.customerCompany === 'string'
195
+ ? (chatRef.metadata.customerCompany as string)
196
+ : undefined
197
+ const customerEmail =
198
+ typeof chatRef.metadata?.customerEmail === 'string'
199
+ ? (chatRef.metadata.customerEmail as string)
200
+ : undefined
201
+ return (
202
+ <HubspotTicketCard
203
+ item={{
204
+ id: chatRef.id,
205
+ title: chatRef.title,
206
+ preview: chatRef.preview,
207
+ status,
208
+ statusLabel,
209
+ priority,
210
+ customerCompany,
211
+ customerEmail,
212
+ url: chatRef.url ?? null,
213
+ dateUpdated: chatRef.date ?? null,
214
+ }}
215
+ variant="compact"
216
+ anchorProps={buildAnchorProps(chatRef.url, isNewTab)}
217
+ />
218
+ )
219
+ }
220
+
221
+ function SlackChatCard({ chatRef, isNewTab }: { chatRef: ChatRef; isNewTab: boolean }) {
222
+ const channelName =
223
+ typeof chatRef.metadata?.channelName === 'string'
224
+ ? (chatRef.metadata.channelName as string)
225
+ : undefined
226
+ return (
227
+ <SlackMessageCard
228
+ item={{
229
+ id: chatRef.id,
230
+ title: chatRef.title,
231
+ preview: chatRef.preview,
232
+ url: chatRef.url ?? null,
233
+ dateUpdated: chatRef.date ?? null,
234
+ channel: channelName,
235
+ }}
236
+ variant="compact"
237
+ anchorProps={buildAnchorProps(chatRef.url, isNewTab)}
238
+ />
239
+ )
240
+ }
241
+
242
+ function DataRoomDocChatCard({
243
+ chatRef,
244
+ baseRoute,
245
+ chipBasePlatform,
246
+ isNewTab,
247
+ }: {
248
+ chatRef: ChatRef
249
+ baseRoute?: string
250
+ chipBasePlatform?: string
251
+ isNewTab: boolean
252
+ }) {
253
+ const path =
254
+ typeof chatRef.metadata?.path === 'string' ? (chatRef.metadata.path as string) : undefined
255
+ // Provenance label. NEVER fall back to "Data room" — that would
256
+ // falsely label non-data-room content (openframe-docs, etc.) as
257
+ // private investor material when `sourceRepo` is missing or
258
+ // unrecognized. Generic "Document" is intentionally neutral so users
259
+ // can't be misled about sensitivity / scope.
260
+ const badgeText = chatRef.sourceRepo ? getSourceLabel(chatRef.sourceRepo) : 'Document'
261
+ return (
262
+ <DataRoomDocCard
263
+ item={{
264
+ id: chatRef.id,
265
+ title: chatRef.title,
266
+ preview: chatRef.preview ?? undefined,
267
+ path,
268
+ url: chatRef.url ?? null,
269
+ sourceRepo: chatRef.sourceRepo ?? null,
270
+ baseRoute,
271
+ chipBasePlatform,
272
+ }}
273
+ badgeText={badgeText}
274
+ anchorProps={buildAnchorProps(chatRef.url, isNewTab)}
275
+ />
276
+ )
277
+ }
278
+
279
+ function GenericFinancialChatCard({
280
+ chatRef,
281
+ badge,
282
+ scheme,
283
+ isNewTab,
284
+ }: {
285
+ chatRef: ChatRef
286
+ badge: string
287
+ scheme: 'cyan' | 'warning' | 'success' | 'error' | 'default'
288
+ isNewTab: boolean
289
+ }) {
290
+ const facts = Array.isArray(chatRef.metadata?.facts)
291
+ ? (chatRef.metadata!.facts as Array<{ label: string; value: string }>)
292
+ : null
293
+ const subtitle =
294
+ typeof chatRef.metadata?.subtitle === 'string'
295
+ ? (chatRef.metadata.subtitle as string)
296
+ : null
297
+ const anchorProps: GenericEntityCardAnchorProps | undefined = buildAnchorProps(
298
+ chatRef.url,
299
+ isNewTab,
300
+ )
301
+ return (
302
+ <GenericEntityCard
303
+ item={{
304
+ id: chatRef.id,
305
+ title: chatRef.title,
306
+ subtitle,
307
+ preview: chatRef.preview ?? null,
308
+ url: chatRef.url ?? null,
309
+ badge: { text: badge, scheme },
310
+ facts,
311
+ dateUpdated: chatRef.date ?? null,
312
+ }}
313
+ anchorProps={anchorProps}
314
+ />
315
+ )
316
+ }
317
+
318
+ function ChatInlineVideoPill({ chatRef }: { chatRef: ChatRef }) {
319
+ const title = chatRef.title || 'Video'
320
+ return (
321
+ <span className="inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-xs align-middle bg-ods-card border border-ods-border text-ods-text-primary">
322
+ <span aria-hidden="true" className="text-ods-text-secondary">▶</span>
323
+ <span className="truncate max-w-[220px]">{title}</span>
324
+ </span>
325
+ )
326
+ }
327
+
328
+ /** Wrap a chat-inline card with the "Ask"/"Display" affordance + source
329
+ * tracking strip. Mirrors the hub's `ChatCardWithDiscuss` layout exactly
330
+ * — the visual contract here drove the lib refactor in the first place. */
331
+ function ChatCardWithDiscuss({
332
+ chatRef,
333
+ onDiscuss,
334
+ onDisplay,
335
+ displayAction,
336
+ children,
337
+ }: {
338
+ chatRef: ChatRef
339
+ onDiscuss?: (ref: ChatRef) => void
340
+ onDisplay?: (ref: ChatRef) => void
341
+ displayAction?: boolean
342
+ children: React.ReactNode
343
+ }) {
344
+ const { Icon: SourceIcon, label: sourceLabel } = resolveSourceIcon({
345
+ sourceRepo: chatRef.sourceRepo,
346
+ documentType: chatRef.type,
347
+ })
348
+ const idDisplay =
349
+ chatRef.id && (chatRef.id.length > 24 ? `${chatRef.id.slice(0, 24)}…` : chatRef.id)
350
+ const useDisplay = displayAction && !!onDisplay
351
+ const cardBody = <span className="block [&>*]:!my-0">{children}</span>
352
+ return (
353
+ <span className="mt-1.5 mb-2 block w-full">
354
+ {cardBody}
355
+ <span className="mt-1 flex items-center justify-between gap-2 pl-0.5">
356
+ <SourceActionButton
357
+ chatRef={chatRef}
358
+ onDiscuss={useDisplay ? onDisplay : onDiscuss}
359
+ label={useDisplay ? 'Display' : undefined}
360
+ density="card"
361
+ />
362
+ {!onDiscuss && !useDisplay ? <span /> : null}
363
+ {idDisplay ? (
364
+ <span
365
+ className="inline-flex items-center gap-1 text-[10px] leading-3 font-mono shrink-0 text-ods-text-secondary opacity-60 hover:opacity-100 hover:text-ods-text-primary transition-opacity"
366
+ title={`${sourceLabel} · ${chatRef.id}`}
367
+ >
368
+ <SourceIcon className="h-3 w-3 shrink-0" />
369
+ <span className="truncate max-w-[180px]">{idDisplay}</span>
370
+ </span>
371
+ ) : null}
372
+ </span>
373
+ </span>
374
+ )
375
+ }
376
+
377
+ // =============================================================================
378
+ // Per-type fetch-mode card body — composed by ChatCardLoader once item is in.
379
+ // =============================================================================
380
+
381
+ /** Anchor-wrapped product-release card. */
382
+ function ProductReleaseChatCard({
383
+ item,
384
+ chatRef,
385
+ buildProps,
386
+ isNewTab,
387
+ }: {
388
+ item: any
389
+ chatRef: ChatRef
390
+ buildProps: NonNullable<ChatCardDispatchExtras['buildProductReleaseCardProps']>
391
+ isNewTab: boolean
392
+ }) {
393
+ const releaseProps = buildProps(item)
394
+ return (
395
+ <ProductReleaseCard
396
+ size="sm"
397
+ title={item.title}
398
+ summary={item.summary}
399
+ version={item.version}
400
+ {...releaseProps}
401
+ anchorProps={buildAnchorProps(chatRef.url, isNewTab)}
402
+ />
403
+ )
404
+ }
405
+
406
+ /** Anchor-wrapped marketing-campaign card. Campaigns have no public
407
+ * viewer; the registry entry's `fallbackHref` synthesizes the admin
408
+ * URL upstream in `ChatCardLoader`, so by the time we render here
409
+ * `chatRef.url` is guaranteed non-null AND the parent's `isNewTab`
410
+ * reflects the actual destination. */
411
+ function CampaignChatCard({
412
+ item,
413
+ chatRef,
414
+ isNewTab,
415
+ }: {
416
+ item: any
417
+ chatRef: ChatRef
418
+ isNewTab: boolean
419
+ }) {
420
+ return (
421
+ <CampaignCardAdmin
422
+ campaign={item}
423
+ anchorProps={buildAnchorProps(chatRef.url, isNewTab)!}
424
+ />
425
+ )
426
+ }
427
+
428
+ // =============================================================================
429
+ // CHAT_CARD_REGISTRY — single source of truth.
430
+ // =============================================================================
431
+
432
+ type ChatCardRegistryEntry =
433
+ | {
434
+ mode: 'no-fetch'
435
+ label: string
436
+ bareInline?: boolean
437
+ displayAction?: boolean
438
+ render: (chatRef: ChatRef, opts: ChatCardRenderOptions) => React.ReactNode
439
+ }
440
+ | {
441
+ mode: 'fetch'
442
+ label: string
443
+ contentRefType: string
444
+ displayAction?: boolean
445
+ skeleton: () => React.ReactNode
446
+ render: (item: any, chatRef: ChatRef, opts: ChatCardRenderOptions) => React.ReactNode
447
+ /** Optional post-fetch URL synthesizer. When `chatRef.url` is null
448
+ * AFTER `resolveSourceRowCTA`, the loader runs this against the
449
+ * hydrated item to produce a fallback hub-internal URL (e.g.
450
+ * `/admin/campaigns/${item.id}` for marketing campaigns). Result
451
+ * is validated via `safeHref` before being attached to the
452
+ * resolved ref — so the wrapper sees a non-null `href`, the
453
+ * pre-computed `isNewTab` reflects the actual destination, and
454
+ * the click goes through `handleChatNavClick` (no silent
455
+ * bypass of embed-mode / close-on-nav). */
456
+ fallbackHref?: (item: any) => string | null
457
+ }
458
+
459
+ type FinancialBadgeScheme = 'cyan' | 'warning' | 'success' | 'error' | 'default'
460
+ interface FinancialBadgeConfig {
461
+ label: string
462
+ badge: string
463
+ scheme?: FinancialBadgeScheme
464
+ }
465
+ const FINANCIAL_CARD_BADGES: Record<string, FinancialBadgeConfig> = {
466
+ financial_kpi: { label: 'Financial KPI', badge: 'KPI', scheme: 'cyan' },
467
+ cap_table: { label: 'Cap table entry', badge: 'Cap table', scheme: 'warning' },
468
+ profit_loss: { label: 'P&L period', badge: 'P&L' },
469
+ balance_sheet: { label: 'Balance sheet', badge: 'Balance sheet' },
470
+ cash_flow: { label: 'Cash flow', badge: 'Cash flow' },
471
+ }
472
+ function financialRegistryEntries(): Record<string, ChatCardRegistryEntry> {
473
+ const out: Record<string, ChatCardRegistryEntry> = {}
474
+ for (const [docType, cfg] of Object.entries(FINANCIAL_CARD_BADGES)) {
475
+ const scheme = cfg.scheme ?? 'default'
476
+ out[docType] = {
477
+ mode: 'no-fetch',
478
+ label: cfg.label,
479
+ render: (chatRef, opts) => (
480
+ <GenericFinancialChatCard
481
+ chatRef={chatRef}
482
+ badge={cfg.badge}
483
+ scheme={scheme}
484
+ isNewTab={opts.isNewTab}
485
+ />
486
+ ),
487
+ }
488
+ }
489
+ return out
490
+ }
491
+
492
+ interface GitHubCardConfig {
493
+ label: string
494
+ kind: GitHubActivityKind
495
+ }
496
+ const GITHUB_CARD_CONFIGS: Record<string, GitHubCardConfig> = {
497
+ github_commit: { label: 'GitHub commit', kind: 'commit' },
498
+ github_commit_public: { label: 'GitHub commit (public)', kind: 'commit' },
499
+ github_pull_request: { label: 'GitHub PR', kind: 'pull_request' },
500
+ github_pull_request_public: { label: 'GitHub PR (public)', kind: 'pull_request' },
501
+ github_pr_review: { label: 'GitHub review', kind: 'pr_review' },
502
+ github_pr_review_public: { label: 'GitHub review (public)', kind: 'pr_review' },
503
+ }
504
+ function githubRegistryEntries(): Record<string, ChatCardRegistryEntry> {
505
+ const out: Record<string, ChatCardRegistryEntry> = {}
506
+ for (const [docType, cfg] of Object.entries(GITHUB_CARD_CONFIGS)) {
507
+ out[docType] = {
508
+ mode: 'no-fetch',
509
+ label: cfg.label,
510
+ render: (chatRef, opts) => (
511
+ <GitHubChatCard chatRef={chatRef} kind={cfg.kind} isNewTab={opts.isNewTab} />
512
+ ),
513
+ }
514
+ }
515
+ return out
516
+ }
517
+
518
+ type ProgramConfigKey = 'podcast' | 'webinar' | 'event'
519
+ interface ProgramCardConfig {
520
+ label: string
521
+ configKey: ProgramConfigKey
522
+ contentRefType: string
523
+ }
524
+ const PROGRAM_CARD_CONFIGS: Record<string, ProgramCardConfig> = {
525
+ podcast: { label: 'Podcast episode', configKey: 'podcast', contentRefType: 'podcast' },
526
+ webinar: { label: 'Webinar', configKey: 'webinar', contentRefType: 'webinar' },
527
+ event: { label: 'Event', configKey: 'event', contentRefType: 'event' },
528
+ }
529
+ function programRegistryEntries(): Record<string, ChatCardRegistryEntry> {
530
+ const out: Record<string, ChatCardRegistryEntry> = {}
531
+ for (const [docType, cfg] of Object.entries(PROGRAM_CARD_CONFIGS)) {
532
+ out[docType] = {
533
+ mode: 'fetch',
534
+ label: cfg.label,
535
+ contentRefType: cfg.contentRefType,
536
+ skeleton: () => <ProgramCardSkeleton size="sm" />,
537
+ render: (item, chatRef, opts) => {
538
+ // Embedder-provided config wins; lib default fills in otherwise
539
+ // so the compact card renders even without `extras`. See
540
+ // `program-card-defaults.ts` for the rationale.
541
+ const config =
542
+ opts?.extras?.programConfigs?.[cfg.configKey] ??
543
+ DEFAULT_PROGRAM_CONFIGS[cfg.configKey]
544
+ return (
545
+ <ProgramCard
546
+ config={config}
547
+ item={item as BaseProgramItem}
548
+ size="sm"
549
+ href={chatRef.url ?? ''}
550
+ targetPlatform={chatRef.targetPlatform ?? null}
551
+ {...newTabAnchorAttrs(opts.isNewTab)}
552
+ />
553
+ )
554
+ },
555
+ }
556
+ }
557
+ return out
558
+ }
559
+
560
+ type RoadmapCardType = 'roadmap_item' | 'delivery_item' | 'internal_task'
561
+ interface RoadmapEntryConfig {
562
+ label: string
563
+ cardType: RoadmapCardType
564
+ contentRefType: string
565
+ }
566
+ const ROADMAP_CARD_CONFIGS: Record<string, RoadmapEntryConfig> = {
567
+ roadmap_item: { label: 'Roadmap item', cardType: 'roadmap_item', contentRefType: 'roadmap_item' },
568
+ delivery_item: {
569
+ label: 'Delivery item',
570
+ cardType: 'delivery_item',
571
+ contentRefType: 'delivery_item',
572
+ },
573
+ internal_task: {
574
+ label: 'Internal task',
575
+ cardType: 'internal_task',
576
+ contentRefType: 'internal_task',
577
+ },
578
+ }
579
+ function roadmapRegistryEntries(): Record<string, ChatCardRegistryEntry> {
580
+ const out: Record<string, ChatCardRegistryEntry> = {}
581
+ for (const [docType, cfg] of Object.entries(ROADMAP_CARD_CONFIGS)) {
582
+ out[docType] = {
583
+ mode: 'fetch',
584
+ label: cfg.label,
585
+ contentRefType: cfg.contentRefType,
586
+ skeleton: () => <RoadmapCardSkeleton size="sm" />,
587
+ render: (item, chatRef, opts) => (
588
+ <RoadmapCard
589
+ item={item}
590
+ href={chatRef.url ?? ''}
591
+ targetPlatform={chatRef.targetPlatform ?? null}
592
+ {...newTabAnchorAttrs(opts.isNewTab)}
593
+ userVote={null}
594
+ onVote={() => {}}
595
+ size="sm"
596
+ cardType={cfg.cardType}
597
+ />
598
+ ),
599
+ }
600
+ }
601
+ return out
602
+ }
603
+
604
+ const CHAT_CARD_REGISTRY: Record<string, ChatCardRegistryEntry> = {
605
+ // ───────── no-fetch: ChatRef carries everything ─────────
606
+ ...githubRegistryEntries(),
607
+ slack_message: {
608
+ mode: 'no-fetch',
609
+ label: 'Slack message',
610
+ render: (chatRef, opts) => (
611
+ <SlackChatCard chatRef={chatRef} isNewTab={opts.isNewTab} />
612
+ ),
613
+ },
614
+ hubspot_ticket: {
615
+ mode: 'no-fetch',
616
+ label: 'HubSpot ticket',
617
+ render: (chatRef, opts) => (
618
+ <HubspotTicketChatCard chatRef={chatRef} isNewTab={opts.isNewTab} />
619
+ ),
620
+ },
621
+ hubspot_ticket_anon: {
622
+ mode: 'no-fetch',
623
+ label: 'HubSpot ticket (anon)',
624
+ render: (chatRef, opts) => (
625
+ <HubspotTicketChatCard chatRef={chatRef} isNewTab={opts.isNewTab} />
626
+ ),
627
+ },
628
+ hubspot_ticket_self: {
629
+ mode: 'no-fetch',
630
+ label: 'HubSpot ticket (self)',
631
+ render: (chatRef, opts) => (
632
+ <HubspotTicketChatCard chatRef={chatRef} isNewTab={opts.isNewTab} />
633
+ ),
634
+ },
635
+ data_room_doc: {
636
+ mode: 'no-fetch',
637
+ label: 'Data-room doc',
638
+ render: (chatRef, opts) => (
639
+ <DataRoomDocChatCard
640
+ chatRef={chatRef}
641
+ baseRoute={opts?.baseRoute}
642
+ chipBasePlatform={opts?.chipBasePlatform}
643
+ isNewTab={opts.isNewTab}
644
+ />
645
+ ),
646
+ },
647
+ markdown: {
648
+ mode: 'no-fetch',
649
+ label: 'Doc page (markdown)',
650
+ render: (chatRef, opts) => (
651
+ <DataRoomDocChatCard
652
+ chatRef={chatRef}
653
+ baseRoute={opts?.baseRoute}
654
+ chipBasePlatform={opts?.chipBasePlatform}
655
+ isNewTab={opts.isNewTab}
656
+ />
657
+ ),
658
+ },
659
+ video: {
660
+ mode: 'no-fetch',
661
+ label: 'Video',
662
+ bareInline: true,
663
+ render: (chatRef) => <ChatInlineVideoPill chatRef={chatRef} />,
664
+ },
665
+ ...financialRegistryEntries(),
666
+
667
+ // ───────── fetch: needs full row from list API ─────────
668
+ blog_post: {
669
+ mode: 'fetch',
670
+ label: 'Blog post',
671
+ contentRefType: 'blog_post_existing',
672
+ skeleton: () => <BlogCardSkeleton size="sm" />,
673
+ render: (item, chatRef, opts) => (
674
+ <BlogCard
675
+ post={item}
676
+ size="sm"
677
+ href={chatRef.url ?? ''}
678
+ targetPlatform={chatRef.targetPlatform ?? null}
679
+ {...newTabAnchorAttrs(opts.isNewTab)}
680
+ hasEmbeddedVideo={chatRef.metadata?.hasEmbeddedVideo === true}
681
+ />
682
+ ),
683
+ },
684
+ case_study: {
685
+ mode: 'fetch',
686
+ label: 'Case study',
687
+ contentRefType: 'case_study',
688
+ skeleton: () => <CaseStudyCardSkeleton size="sm" />,
689
+ render: (item, chatRef, opts) => (
690
+ <CaseStudyCard
691
+ study={item}
692
+ size="sm"
693
+ href={chatRef.url ?? ''}
694
+ targetPlatform={chatRef.targetPlatform ?? null}
695
+ {...newTabAnchorAttrs(opts.isNewTab)}
696
+ />
697
+ ),
698
+ },
699
+ customer_interview: {
700
+ mode: 'fetch',
701
+ label: 'Customer interview',
702
+ contentRefType: 'customer_interview',
703
+ skeleton: () => <CustomerInterviewCardSkeleton size="sm" />,
704
+ render: (item, chatRef, opts) => (
705
+ <CustomerInterviewCard
706
+ interview={item}
707
+ size="sm"
708
+ href={chatRef.url ?? ''}
709
+ targetPlatform={chatRef.targetPlatform ?? null}
710
+ {...newTabAnchorAttrs(opts.isNewTab)}
711
+ />
712
+ ),
713
+ },
714
+ product_release: {
715
+ mode: 'fetch',
716
+ label: 'Product release',
717
+ contentRefType: 'product_release',
718
+ skeleton: () => <ProductReleaseCardSkeleton size="sm" />,
719
+ render: (item, chatRef, opts) => {
720
+ // Embedder-provided builder wins; lib default fills in otherwise
721
+ // (covers `coverImage`, `hasVideoCover`, `formattedDate` — the
722
+ // three fields the compact `size='sm'` card actually reads).
723
+ // Hub-side embedders still pass their richer builder via
724
+ // `extras.buildProductReleaseCardProps` to get lg-only metadata
725
+ // (badge color, changelog counts, etc.).
726
+ const builder =
727
+ opts?.extras?.buildProductReleaseCardProps ?? defaultBuildProductReleaseCardProps
728
+ return (
729
+ <ProductReleaseChatCard
730
+ item={item}
731
+ chatRef={chatRef}
732
+ buildProps={builder}
733
+ isNewTab={opts.isNewTab}
734
+ />
735
+ )
736
+ },
737
+ },
738
+ ...programRegistryEntries(),
739
+ investor_update: {
740
+ mode: 'fetch',
741
+ label: 'Investor update',
742
+ contentRefType: 'investor_update',
743
+ skeleton: () => <InvestorUpdateCardSkeleton size="sm" />,
744
+ render: (item, chatRef, opts) => (
745
+ <InvestorUpdateCard
746
+ update={item}
747
+ size="sm"
748
+ href={chatRef.url ?? ''}
749
+ targetPlatform={chatRef.targetPlatform ?? null}
750
+ {...newTabAnchorAttrs(opts.isNewTab)}
751
+ />
752
+ ),
753
+ },
754
+ onboarding_guide: {
755
+ mode: 'fetch',
756
+ label: 'Onboarding guide',
757
+ contentRefType: 'onboarding_guide',
758
+ displayAction: true,
759
+ skeleton: () => <OnboardingGuideCardSkeleton size="sm" />,
760
+ render: (item, chatRef, opts) => (
761
+ <OnboardingGuideCard
762
+ guide={item}
763
+ size="sm"
764
+ href={chatRef.url ?? ''}
765
+ targetPlatform={chatRef.targetPlatform ?? null}
766
+ {...newTabAnchorAttrs(opts.isNewTab)}
767
+ />
768
+ ),
769
+ },
770
+ marketing_campaign: {
771
+ mode: 'fetch',
772
+ label: 'Marketing campaign',
773
+ contentRefType: 'marketing_campaign',
774
+ skeleton: () => <CampaignCardAdminSkeleton />,
775
+ // No public viewer — synthesize the hub-internal admin URL post-fetch
776
+ // so the wrapper + isNewTab computation see the actual destination.
777
+ fallbackHref: (item: { id?: string }) =>
778
+ item?.id ? `/admin/campaigns/${encodeURIComponent(item.id)}` : null,
779
+ render: (item, chatRef, opts) => (
780
+ <CampaignChatCard
781
+ item={item}
782
+ chatRef={chatRef}
783
+ isNewTab={opts.isNewTab}
784
+ />
785
+ ),
786
+ },
787
+ ...roadmapRegistryEntries(),
788
+ }
789
+
790
+ // =============================================================================
791
+ // ChatCardNavWrap — click-capture interceptor that routes inner-anchor
792
+ // clicks through the chat runtime's nav handler.
793
+ //
794
+ // Single source of truth for click handling on EVERY inline card. The
795
+ // card body provides its own `<a href={absolute}>` (per the
796
+ // pure-presentation contract) — this wrapper intercepts the primary
797
+ // click via `onClickCapture` BEFORE the browser's default navigation
798
+ // fires, and routes through `handleChatNavClick` to apply runtime nav
799
+ // rules (embed-mode `window.open` / cross-platform new-tab / host
800
+ // `runtime.navigation.navigate`). Modifier / non-primary clicks pass
801
+ // through (`handleChatNavClick` returns early so the browser opens
802
+ // the inner anchor's href naturally).
803
+ //
804
+ // Same click model as source chips — chips use `<a onClick={handleChatNavClick}>`
805
+ // directly; cards use `<span onClickCapture={→handleChatNavClick}>` outside
806
+ // the card's own anchor. Both ultimately call `handleChatNavClick` with
807
+ // the same `{href, targetPlatform}` resolved at `ChatCardLoader` via
808
+ // `resolveSourceRowCTA`. The unification:
809
+ // - Same URL composition (`resolveSourceRowCTA`)
810
+ // - Same embed-mode prefix (`resolveHrefForRuntime`)
811
+ // - Same click router (`handleChatNavClick`)
812
+ // - Same conditional close (`ChatPanelContext.closeChat` on same-tab only)
813
+ // =============================================================================
814
+
815
+ /**
816
+ * ChatCardNavWrap — click-capture interceptor for inline cards.
817
+ *
818
+ * `<span onClickCapture>` wrapping the card body. The card renders its
819
+ * own `<a href target rel>` with the canonical pre-resolved href +
820
+ * new-tab decision applied (via `opts.isNewTab` from ChatCardLoader).
821
+ *
822
+ * Job:
823
+ * - PRIMARY clicks → preventDefault + route through `handleChatNavClick`
824
+ * - Modifier-clicks → pass through to the browser's native handling
825
+ * - Same-tab nav → close the chat panel (so the panel doesn't linger
826
+ * over the now-current-page content). New-tab nav leaves it open.
827
+ *
828
+ * Single close path for inline cards. The chip block in
829
+ * `embeddable-chat.tsx` mirrors this logic for source chips. Both
830
+ * gate on `!isNewTab` computed from the same `decideNewTab` rule, so
831
+ * the close decision is consistent across surfaces.
832
+ */
833
+ function ChatCardNavWrap({
834
+ href,
835
+ path,
836
+ targetPlatform,
837
+ isNewTab,
838
+ children,
839
+ }: {
840
+ href: string | null
841
+ /** In-app doc-tree path for `markdown` / `data_room_doc` refs. The
842
+ * runtime's `navigate({path})` opportunistically swaps the active
843
+ * documentation section without a full page nav; null for everything
844
+ * else. Threaded straight through to `handleChatNavClick` so chips
845
+ * and inline cards apply the same routing rule. */
846
+ path: string | null
847
+ targetPlatform: string | null
848
+ /** New-tab decision pre-computed by the parent `ChatCardLoader` —
849
+ * same value the card's `<a target>` already renders with.
850
+ * Consumed here ONLY to decide whether to close the panel. */
851
+ isNewTab: boolean
852
+ children: ReactNode
853
+ }) {
854
+ const runtime = useRequiredChatRuntime()
855
+ const panel = useChatPanel()
856
+ const onClickCapture = (e: React.MouseEvent<HTMLElement>) => {
857
+ if (!href) return
858
+ const targetEl = e.target as HTMLElement
859
+ // Buttons rendered INSIDE the card's outer `<a>` (e.g. RoadmapCard
860
+ // vote buttons, ImageGallery thumbnails) bubble up with
861
+ // `closest('a')` truthy — without this guard, clicking them would
862
+ // route through the chat nav handler and navigate away from the
863
+ // page. The button's own onClick keeps working because we exit
864
+ // before stopPropagation.
865
+ if (targetEl?.closest?.('button')) return
866
+ if (!targetEl?.closest?.('a')) return
867
+
868
+ const handled = handleChatNavClick(e, runtime, { href, path, targetPlatform })
869
+ if (!handled) return
870
+ // Modifier-clicks fall through (handled=false) without stopPropagation
871
+ // so ancestor telemetry handlers still see the bubble.
872
+ e.stopPropagation()
873
+ if (!isNewTab && panel?.closeChat) panel.closeChat()
874
+ }
875
+ return (
876
+ <span className="contents" onClickCapture={onClickCapture}>
877
+ {children}
878
+ </span>
879
+ )
880
+ }
881
+
882
+ // =============================================================================
883
+ // ChatCardLoader — fetch + skeleton + render for fetch-mode entries.
884
+ // =============================================================================
885
+
886
+ interface ChatCardLoaderProps {
887
+ chatRef: ChatRef
888
+ onDiscuss?: (ref: ChatRef) => void
889
+ onDisplay?: (ref: ChatRef) => void
890
+ baseRoute?: string
891
+ chipBasePlatform?: string
892
+ extras?: ChatCardDispatchExtras
893
+ }
894
+
895
+ /**
896
+ * Generic fetch-mode card loader. Looks up the registry entry by
897
+ * `chatRef.type`, fetches the full item via `useChatCardItem`, and
898
+ * routes through skeleton / null / card-render.
899
+ *
900
+ * SINGLE URL-RESOLUTION POINT — same code path source chips already
901
+ * had. Before render dispatch:
902
+ * - Pass the ref through `resolveSourceRowCTA` to compute the
903
+ * canonical `{href, targetPlatform}` (externalUrl → in-app path
904
+ * fallback → null, with embedder `baseRoute` / `chipBasePlatform`
905
+ * awareness).
906
+ * - Pre-resolve href against `runtime.navigation.defaultContentOrigin`
907
+ * in embed mode (so modifier-click + copy-link land on the hub).
908
+ * - Re-attach the resolved values onto the ref so EVERY downstream
909
+ * card — whether it renders an inner `<a>` from `href` prop
910
+ * (BlogCard, ProgramCard, …) or pulls `anchorProps` from
911
+ * `computeIsNewTab` — sees the SAME canonical URL the
912
+ * chip would render.
913
+ *
914
+ * Eliminates the entire "chip works, inline card doesn't" class of bug.
915
+ */
916
+ export function ChatCardLoader({
917
+ chatRef,
918
+ onDiscuss,
919
+ onDisplay,
920
+ baseRoute,
921
+ chipBasePlatform,
922
+ extras,
923
+ }: ChatCardLoaderProps) {
924
+ const runtime = useRequiredChatRuntime()
925
+ const resolvedChatRef = React.useMemo<ChatRef>(() => {
926
+ const cta = resolveSourceRowCTA(
927
+ {
928
+ sourceRepo: chatRef.sourceRepo,
929
+ documentType: chatRef.type,
930
+ id: chatRef.id,
931
+ title: chatRef.title,
932
+ externalUrl: chatRef.url,
933
+ targetPlatform: chatRef.targetPlatform,
934
+ path:
935
+ typeof chatRef.metadata?.path === 'string'
936
+ ? (chatRef.metadata.path as string)
937
+ : null,
938
+ },
939
+ {
940
+ baseRoute,
941
+ chipBasePlatform,
942
+ currentPlatform: runtime.source,
943
+ },
944
+ )
945
+ const finalHref = cta.href ? resolveHrefForRuntime(cta.href, runtime) : null
946
+ return {
947
+ ...chatRef,
948
+ url: finalHref ?? chatRef.url,
949
+ targetPlatform: cta.targetPlatform ?? chatRef.targetPlatform ?? null,
950
+ }
951
+ }, [chatRef, runtime, baseRoute, chipBasePlatform])
952
+
953
+ const entry = CHAT_CARD_REGISTRY[resolvedChatRef.type]
954
+ // Hook order MUST be stable across renders — call the data hook
955
+ // unconditionally regardless of entry mode. For non-fetch types the
956
+ // `contentRefType` is empty so the hook returns `isLoading=false` and
957
+ // `item=undefined`, which we ignore.
958
+ const fetchEntry = entry && entry.mode === 'fetch' ? entry : null
959
+ const { item, isLoading } = useChatCardItem<any>(
960
+ fetchEntry?.contentRefType ?? '',
961
+ fetchEntry ? resolvedChatRef.id : '',
962
+ )
963
+ if (!entry) return null
964
+
965
+ // Apply per-type fallback URL AFTER fetch (e.g. campaign → /admin/...).
966
+ // We mutate `resolvedChatRef.url` BEFORE computing isNewTab so the
967
+ // wrapper's interceptor sees the destination the user will actually
968
+ // visit. `safeHref` blocks `javascript:` / `data:` payloads even
969
+ // though the registry callers compose hub-internal strings today.
970
+ const finalChatRef: ChatRef =
971
+ fetchEntry && !resolvedChatRef.url && item && fetchEntry.fallbackHref
972
+ ? {
973
+ ...resolvedChatRef,
974
+ url: safeHref(fetchEntry.fallbackHref(item)),
975
+ }
976
+ : resolvedChatRef
977
+
978
+ // Pre-compute new-tab decision ONCE here (the same rule chips use).
979
+ // Render branches that pass `target` / `rel` to their card pull this
980
+ // via `renderOpts.isNewTab` so the inner `<a>` agrees with the
981
+ // runtime nav decision in `ChatCardNavWrap` + `handleChatNavClick`.
982
+ const isNewTab = computeIsNewTab(runtime, finalChatRef.url, finalChatRef.targetPlatform ?? null)
983
+ const renderOpts: ChatCardRenderOptions = { baseRoute, chipBasePlatform, extras, isNewTab }
984
+
985
+ // Wrap EVERY rendered card with ChatCardNavWrap so the inner anchor's
986
+ // primary click routes through the chat runtime (same handler as the
987
+ // source chip). The card's `<a href={absolute}>` provides the visible
988
+ // href for hover-preview / copy-link / modifier-click; the wrapper
989
+ // intercepts the primary click and applies runtime nav rules.
990
+ const path =
991
+ typeof finalChatRef.metadata?.path === 'string'
992
+ ? (finalChatRef.metadata.path as string)
993
+ : null
994
+ const navWrap = (children: ReactNode) => (
995
+ <ChatCardNavWrap
996
+ href={finalChatRef.url ?? null}
997
+ path={path}
998
+ targetPlatform={finalChatRef.targetPlatform ?? null}
999
+ isNewTab={isNewTab}
1000
+ >
1001
+ {children}
1002
+ </ChatCardNavWrap>
1003
+ )
1004
+ if (entry.mode === 'no-fetch') {
1005
+ if (entry.bareInline) {
1006
+ return navWrap(entry.render(finalChatRef, renderOpts))
1007
+ }
1008
+ return (
1009
+ <ChatCardWithDiscuss
1010
+ chatRef={finalChatRef}
1011
+ onDiscuss={onDiscuss}
1012
+ onDisplay={onDisplay}
1013
+ displayAction={entry.displayAction}
1014
+ >
1015
+ {navWrap(entry.render(finalChatRef, renderOpts))}
1016
+ </ChatCardWithDiscuss>
1017
+ )
1018
+ }
1019
+ if (isLoading) return <>{entry.skeleton()}</>
1020
+ if (!item) return null
1021
+ return (
1022
+ <ChatCardWithDiscuss
1023
+ chatRef={finalChatRef}
1024
+ onDiscuss={onDiscuss}
1025
+ onDisplay={onDisplay}
1026
+ displayAction={entry.displayAction}
1027
+ >
1028
+ {navWrap(entry.render(item, finalChatRef, renderOpts))}
1029
+ </ChatCardWithDiscuss>
1030
+ )
1031
+ }
1032
+
1033
+ // =============================================================================
1034
+ // Public dispatch entry points
1035
+ // =============================================================================
1036
+
1037
+ /**
1038
+ * Render the chat-inline card for a `[card://<type>:<id>]` marker.
1039
+ *
1040
+ * Single dispatch through `CHAT_CARD_REGISTRY`. The function mirrors the
1041
+ * hub's `renderChatInlineEntityCard` behavior:
1042
+ * - Video-bearing refs return a `<BlockCard>` sentinel so the
1043
+ * `chat-message-enhanced` pre-scan hoists the player out of the
1044
+ * assistant paragraph.
1045
+ * - Other refs render the compact card, optionally wrapped in a
1046
+ * close-on-anchor-click span when `onClose` is supplied.
1047
+ */
1048
+ export function renderChatInlineEntityCard(
1049
+ chatRef: ChatRef,
1050
+ options: {
1051
+ onDiscuss?: (ref: ChatRef) => void
1052
+ onDisplay?: (ref: ChatRef) => void
1053
+ baseRoute?: string
1054
+ chipBasePlatform?: string
1055
+ extras?: ChatCardDispatchExtras
1056
+ } = {},
1057
+ ): React.ReactNode {
1058
+ const { onDiscuss, onDisplay, baseRoute, chipBasePlatform, extras } = options
1059
+ const m = chatRef.metadata ?? {}
1060
+ const hasVideo =
1061
+ (typeof m.videoUrl === 'string' && (m.videoUrl as string).length > 0) ||
1062
+ (typeof m.youtubeUrl === 'string' && (m.youtubeUrl as string).length > 0) ||
1063
+ (typeof m.highlightVideoUrl === 'string' && (m.highlightVideoUrl as string).length > 0)
1064
+
1065
+ const loader = (
1066
+ <ChatCardLoader
1067
+ chatRef={chatRef}
1068
+ onDiscuss={onDiscuss}
1069
+ onDisplay={onDisplay}
1070
+ baseRoute={baseRoute}
1071
+ chipBasePlatform={chipBasePlatform}
1072
+ extras={extras}
1073
+ />
1074
+ )
1075
+
1076
+ if (hasVideo) {
1077
+ return (
1078
+ <BlockCard inline={loader}>
1079
+ <ChatVideoEntityCard chatRef={chatRef} />
1080
+ </BlockCard>
1081
+ )
1082
+ }
1083
+
1084
+ return loader
1085
+ }
1086
+
1087
+ // =============================================================================
1088
+ // NavLink wiring for callers that need to compose anchors (Task 2 + Task 3)
1089
+ // =============================================================================
1090
+
1091
+ /** Re-export so call sites can wrap any subtree with chat-runtime
1092
+ * routing in a single import. */
1093
+ export { NavLinkAnchorViaRuntime }