@flamingo-stack/openframe-frontend-core 0.0.508 → 0.0.509

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 (306) hide show
  1. package/dist/chat-protocol/decode.d.ts +58 -0
  2. package/dist/chat-protocol/decode.d.ts.map +1 -0
  3. package/dist/chat-protocol/encode.d.ts +44 -0
  4. package/dist/chat-protocol/encode.d.ts.map +1 -0
  5. package/dist/chat-protocol/env-flag.d.ts +35 -0
  6. package/dist/chat-protocol/env-flag.d.ts.map +1 -0
  7. package/dist/chat-protocol/events.d.ts +216 -0
  8. package/dist/chat-protocol/events.d.ts.map +1 -0
  9. package/dist/chat-protocol/frames.d.ts +213 -0
  10. package/dist/chat-protocol/frames.d.ts.map +1 -0
  11. package/dist/chat-protocol/index.cjs +506 -0
  12. package/dist/chat-protocol/index.cjs.map +1 -0
  13. package/dist/chat-protocol/index.d.ts +18 -0
  14. package/dist/chat-protocol/index.d.ts.map +1 -0
  15. package/dist/chat-protocol/index.js +490 -0
  16. package/dist/chat-protocol/index.js.map +1 -0
  17. package/dist/chat-protocol/ip-normalize.d.ts +44 -0
  18. package/dist/chat-protocol/ip-normalize.d.ts.map +1 -0
  19. package/dist/chat-protocol/nats-decoder.d.ts +26 -0
  20. package/dist/chat-protocol/nats-decoder.d.ts.map +1 -0
  21. package/dist/{chunk-3SQ5KXHQ.cjs → chunk-2T4GTV25.cjs} +9 -9
  22. package/dist/{chunk-3SQ5KXHQ.cjs.map → chunk-2T4GTV25.cjs.map} +1 -1
  23. package/dist/{chunk-CWAOV2FK.cjs → chunk-3CGZPAGR.cjs} +3 -3
  24. package/dist/{chunk-CWAOV2FK.cjs.map → chunk-3CGZPAGR.cjs.map} +1 -1
  25. package/dist/{chunk-TLMJHMXJ.js → chunk-3QSR22IC.js} +12 -12
  26. package/dist/chunk-3QSR22IC.js.map +1 -0
  27. package/dist/{chunk-TWYNR4TZ.cjs → chunk-4G5TLHJD.cjs} +7141 -4799
  28. package/dist/chunk-4G5TLHJD.cjs.map +1 -0
  29. package/dist/{chunk-ADPMHWOE.js → chunk-72XAID7Y.js} +4 -4
  30. package/dist/{chunk-PAGKRNWK.js → chunk-7WZHBQ4J.js} +2 -2
  31. package/dist/{chunk-OCEKO5CW.js → chunk-AEELJC4N.js} +12106 -9764
  32. package/dist/chunk-AEELJC4N.js.map +1 -0
  33. package/dist/{chunk-Z42BGM6Q.cjs → chunk-BT2WWDFP.cjs} +5 -5
  34. package/dist/{chunk-Z42BGM6Q.cjs.map → chunk-BT2WWDFP.cjs.map} +1 -1
  35. package/dist/{chunk-7LEL3RIX.cjs → chunk-C7OY3PQP.cjs} +11 -11
  36. package/dist/{chunk-7LEL3RIX.cjs.map → chunk-C7OY3PQP.cjs.map} +1 -1
  37. package/dist/{chunk-RHGGEKPQ.cjs → chunk-CIOLOQKQ.cjs} +4 -4
  38. package/dist/{chunk-RHGGEKPQ.cjs.map → chunk-CIOLOQKQ.cjs.map} +1 -1
  39. package/dist/{chunk-TSZHM74B.js → chunk-DC2TKS7C.js} +2 -2
  40. package/dist/{chunk-M2GOR3XQ.cjs → chunk-DYPYR7FR.cjs} +87 -87
  41. package/dist/{chunk-M2GOR3XQ.cjs.map → chunk-DYPYR7FR.cjs.map} +1 -1
  42. package/dist/{chunk-I64ABCDX.js → chunk-I2B6X77L.js} +2 -2
  43. package/dist/{chunk-NIZDKTGL.cjs → chunk-K5MSCMDK.cjs} +37 -37
  44. package/dist/{chunk-NIZDKTGL.cjs.map → chunk-K5MSCMDK.cjs.map} +1 -1
  45. package/dist/{chunk-DTYRYB2N.js → chunk-K6QTZ7CZ.js} +2 -2
  46. package/dist/{chunk-4LTMXDUS.js → chunk-KBN7PMFT.js} +2 -2
  47. package/dist/{chunk-TBMV7I5N.js → chunk-KXZO2WZX.js} +2 -2
  48. package/dist/{chunk-QTYZMP6D.cjs → chunk-LBAKLT6T.cjs} +62 -62
  49. package/dist/chunk-LBAKLT6T.cjs.map +1 -0
  50. package/dist/{chunk-KEBYLU3U.js → chunk-LFUPI7VX.js} +2 -2
  51. package/dist/{chunk-LDTR4IVZ.cjs → chunk-M37PBG4N.cjs} +31 -31
  52. package/dist/{chunk-LDTR4IVZ.cjs.map → chunk-M37PBG4N.cjs.map} +1 -1
  53. package/dist/{chunk-WA7RR64F.js → chunk-PO5O654H.js} +6 -5
  54. package/dist/chunk-PO5O654H.js.map +1 -0
  55. package/dist/{chunk-WK4N5VBX.cjs → chunk-QJJISLPA.cjs} +28 -27
  56. package/dist/chunk-QJJISLPA.cjs.map +1 -0
  57. package/dist/{chunk-2F44PLTV.cjs → chunk-T7MCSA55.cjs} +26 -26
  58. package/dist/{chunk-2F44PLTV.cjs.map → chunk-T7MCSA55.cjs.map} +1 -1
  59. package/dist/{chunk-WJQHJD7J.js → chunk-TWSKTJHW.js} +2 -2
  60. package/dist/{chunk-ZSQHZYCO.cjs → chunk-UQDMJ6DH.cjs} +13 -13
  61. package/dist/{chunk-ZSQHZYCO.cjs.map → chunk-UQDMJ6DH.cjs.map} +1 -1
  62. package/dist/{chunk-TZRUCD56.js → chunk-V3ZAAFE3.js} +5 -5
  63. package/dist/{chunk-LRGHJPET.js → chunk-XGIFOHKE.js} +2 -2
  64. package/dist/{chunk-POOMO3PA.cjs → chunk-YQEPRYT5.cjs} +7 -7
  65. package/dist/{chunk-POOMO3PA.cjs.map → chunk-YQEPRYT5.cjs.map} +1 -1
  66. package/dist/components/case-studies/index.cjs +8 -8
  67. package/dist/components/case-studies/index.js +2 -2
  68. package/dist/components/chat/chat-message-enhanced.d.ts.map +1 -1
  69. package/dist/components/chat/chat-message-list.d.ts.map +1 -1
  70. package/dist/components/chat/hooks/index.d.ts +0 -1
  71. package/dist/components/chat/hooks/index.d.ts.map +1 -1
  72. package/dist/components/chat/hooks/use-chat.d.ts.map +1 -1
  73. package/dist/components/chat/hooks/use-chunk-catchup.d.ts.map +1 -1
  74. package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts +15 -48
  75. package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts.map +1 -1
  76. package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts +10 -57
  77. package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts.map +1 -1
  78. package/dist/components/chat/index.cjs +10 -2
  79. package/dist/components/chat/index.cjs.map +1 -1
  80. package/dist/components/chat/index.d.ts +1 -0
  81. package/dist/components/chat/index.d.ts.map +1 -1
  82. package/dist/components/chat/index.js +21 -13
  83. package/dist/components/chat/stream/chat-dialog-store.d.ts +184 -0
  84. package/dist/components/chat/stream/chat-dialog-store.d.ts.map +1 -0
  85. package/dist/components/chat/stream/chat-stream-reducer.d.ts +380 -0
  86. package/dist/components/chat/stream/chat-stream-reducer.d.ts.map +1 -0
  87. package/dist/components/chat/stream/delta-batcher.d.ts +51 -0
  88. package/dist/components/chat/stream/delta-batcher.d.ts.map +1 -0
  89. package/dist/components/chat/stream/index.d.ts +17 -0
  90. package/dist/components/chat/stream/index.d.ts.map +1 -0
  91. package/dist/components/chat/stream/message-mutations.d.ts +77 -0
  92. package/dist/components/chat/stream/message-mutations.d.ts.map +1 -0
  93. package/dist/components/chat/stream/use-chat-stream-reducer.d.ts +22 -0
  94. package/dist/components/chat/stream/use-chat-stream-reducer.d.ts.map +1 -0
  95. package/dist/components/chat/types/api.types.d.ts +1 -81
  96. package/dist/components/chat/types/api.types.d.ts.map +1 -1
  97. package/dist/components/chat/types/processing.types.d.ts +2 -93
  98. package/dist/components/chat/types/processing.types.d.ts.map +1 -1
  99. package/dist/components/chat/types/unified-chat-state.types.d.ts +15 -0
  100. package/dist/components/chat/types/unified-chat-state.types.d.ts.map +1 -1
  101. package/dist/components/chat/utils/extract-incomplete-message-state.d.ts +34 -6
  102. package/dist/components/chat/utils/extract-incomplete-message-state.d.ts.map +1 -1
  103. package/dist/components/chat/utils/history-merge.d.ts.map +1 -1
  104. package/dist/components/chat/utils/index.d.ts +2 -3
  105. package/dist/components/chat/utils/index.d.ts.map +1 -1
  106. package/dist/components/chat/utils/process-historical-messages.d.ts +59 -11
  107. package/dist/components/chat/utils/process-historical-messages.d.ts.map +1 -1
  108. package/dist/components/contact/index.cjs +3 -3
  109. package/dist/components/contact/index.js +2 -2
  110. package/dist/components/docs/index.cjs +5 -5
  111. package/dist/components/docs/index.js +4 -4
  112. package/dist/components/embeds/index.cjs +3 -3
  113. package/dist/components/embeds/index.js +2 -2
  114. package/dist/components/faq/index.cjs +3 -3
  115. package/dist/components/faq/index.js +2 -2
  116. package/dist/components/features/index.cjs +2 -2
  117. package/dist/components/features/index.js +1 -1
  118. package/dist/components/help-center-pages/index.cjs +22 -22
  119. package/dist/components/help-center-pages/index.js +13 -13
  120. package/dist/components/index.cjs +174 -132
  121. package/dist/components/index.cjs.map +1 -1
  122. package/dist/components/index.js +65 -23
  123. package/dist/components/index.js.map +1 -1
  124. package/dist/components/meeting-scheduler/index.cjs +34 -34
  125. package/dist/components/meeting-scheduler/index.js +3 -3
  126. package/dist/components/navigation/index.cjs +2 -2
  127. package/dist/components/navigation/index.js +1 -1
  128. package/dist/components/onboarding-guides/index.cjs +5 -5
  129. package/dist/components/onboarding-guides/index.js +4 -4
  130. package/dist/components/onboarding-guides/onboarding-guide-detail-view.d.ts.map +1 -1
  131. package/dist/components/related-content/index.cjs +3 -3
  132. package/dist/components/related-content/index.js +2 -2
  133. package/dist/components/shared/product-release/release-detail-page.d.ts.map +1 -1
  134. package/dist/components/tickets/index.cjs +6 -6
  135. package/dist/components/tickets/index.js +5 -5
  136. package/dist/components/ui/index.cjs +44 -2
  137. package/dist/components/ui/index.cjs.map +1 -1
  138. package/dist/components/ui/index.d.ts +1 -2
  139. package/dist/components/ui/index.d.ts.map +1 -1
  140. package/dist/components/ui/index.js +55 -13
  141. package/dist/components/ui/markdown/base-components.d.ts +51 -0
  142. package/dist/components/ui/markdown/base-components.d.ts.map +1 -0
  143. package/dist/components/ui/markdown/engine.d.ts +99 -0
  144. package/dist/components/ui/markdown/engine.d.ts.map +1 -0
  145. package/dist/components/ui/markdown/heading-ids.d.ts +65 -0
  146. package/dist/components/ui/markdown/heading-ids.d.ts.map +1 -0
  147. package/dist/components/ui/markdown/index.d.ts +18 -0
  148. package/dist/components/ui/markdown/index.d.ts.map +1 -0
  149. package/dist/components/ui/markdown/mermaid-diagram.d.ts +79 -0
  150. package/dist/components/ui/markdown/mermaid-diagram.d.ts.map +1 -0
  151. package/dist/components/ui/markdown/rich/embed-overrides.d.ts +14 -0
  152. package/dist/components/ui/markdown/rich/embed-overrides.d.ts.map +1 -0
  153. package/dist/components/ui/markdown/rich/rich-markdown-renderer.d.ts +40 -0
  154. package/dist/components/ui/markdown/rich/rich-markdown-renderer.d.ts.map +1 -0
  155. package/dist/components/ui/markdown/rich/shortcodes.d.ts +8 -0
  156. package/dist/components/ui/markdown/rich/shortcodes.d.ts.map +1 -0
  157. package/dist/components/ui/markdown/sanitize.d.ts +153 -0
  158. package/dist/components/ui/markdown/sanitize.d.ts.map +1 -0
  159. package/dist/components/ui/markdown/simple-markdown-renderer.d.ts +23 -0
  160. package/dist/components/ui/markdown/simple-markdown-renderer.d.ts.map +1 -0
  161. package/dist/components/ui/markdown/streaming.d.ts +78 -0
  162. package/dist/components/ui/markdown/streaming.d.ts.map +1 -0
  163. package/dist/components/ui/markdown/text-size.d.ts +34 -0
  164. package/dist/components/ui/markdown/text-size.d.ts.map +1 -0
  165. package/dist/index.cjs +60 -2
  166. package/dist/index.cjs.map +1 -1
  167. package/dist/index.js +71 -13
  168. package/dist/utils/index.cjs +169 -40
  169. package/dist/utils/index.cjs.map +1 -1
  170. package/dist/utils/index.d.ts +1 -0
  171. package/dist/utils/index.d.ts.map +1 -1
  172. package/dist/utils/index.js +162 -41
  173. package/dist/utils/index.js.map +1 -1
  174. package/dist/utils/markdown-fences.d.ts +42 -0
  175. package/dist/utils/markdown-fences.d.ts.map +1 -0
  176. package/dist/utils/markdown-heading-id.d.ts +85 -0
  177. package/dist/utils/markdown-heading-id.d.ts.map +1 -0
  178. package/dist/utils/markdown-section-extractor.d.ts.map +1 -1
  179. package/package.json +7 -1
  180. package/src/chat-protocol/__tests__/__snapshots__/nats-decoder-golden.test.ts.snap +319 -0
  181. package/src/chat-protocol/__tests__/chat-protocol.test.ts +516 -0
  182. package/src/chat-protocol/__tests__/env-flag.test.ts +52 -0
  183. package/src/chat-protocol/__tests__/ip-normalize.test.ts +136 -0
  184. package/src/chat-protocol/__tests__/nats-decoder-golden.test.ts +237 -0
  185. package/src/chat-protocol/decode.ts +278 -0
  186. package/src/chat-protocol/encode.ts +71 -0
  187. package/src/chat-protocol/env-flag.ts +39 -0
  188. package/src/chat-protocol/events.ts +254 -0
  189. package/src/chat-protocol/frames.ts +245 -0
  190. package/src/chat-protocol/index.ts +21 -0
  191. package/src/chat-protocol/ip-normalize.ts +146 -0
  192. package/src/chat-protocol/nats-decoder.ts +264 -0
  193. package/src/components/chat/.chat-message-list.md +10 -6
  194. package/src/components/chat/__tests__/chat-message-list.test.tsx +450 -9
  195. package/src/components/chat/__tests__/chat-message-streaming-memo.test.tsx +207 -0
  196. package/src/components/chat/__tests__/chat-pending-turn.test.tsx +250 -0
  197. package/src/components/chat/chat-message-enhanced.tsx +122 -20
  198. package/src/components/chat/chat-message-list.tsx +515 -133
  199. package/src/components/chat/embeddable-chat.tsx +6 -0
  200. package/src/components/chat/hooks/.index.md +30 -33
  201. package/src/components/chat/hooks/.use-nats-chat-adapter.md +36 -55
  202. package/src/components/chat/hooks/__tests__/__snapshots__/conversation-id-persistence-golden.test.ts.snap +37 -0
  203. package/src/components/chat/hooks/__tests__/__snapshots__/sse-stream-golden.test.ts.snap +0 -0
  204. package/src/components/chat/hooks/__tests__/chunk-catchup-dialog-staleness.test.ts +92 -0
  205. package/src/components/chat/hooks/__tests__/conversation-id-persistence-golden.test.ts +438 -0
  206. package/src/components/chat/hooks/__tests__/sse-stream-golden.test.ts +318 -0
  207. package/src/components/chat/hooks/index.ts +0 -1
  208. package/src/components/chat/hooks/use-chat.ts +8 -0
  209. package/src/components/chat/hooks/use-chunk-catchup.ts +26 -1
  210. package/src/components/chat/hooks/use-nats-chat-adapter.ts +254 -825
  211. package/src/components/chat/hooks/use-sse-chat-adapter.ts +380 -684
  212. package/src/components/chat/index.ts +5 -0
  213. package/src/components/chat/stream/__tests__/__snapshots__/chat-stream-reducer-golden.test.ts.snap +944 -0
  214. package/src/components/chat/stream/__tests__/chat-dialog-store.test.ts +806 -0
  215. package/src/components/chat/stream/__tests__/chat-stream-reducer-golden.test.ts +467 -0
  216. package/src/components/chat/stream/__tests__/chat-stream-reducer.test.ts +1330 -0
  217. package/src/components/chat/stream/__tests__/delta-batcher.test.ts +255 -0
  218. package/src/components/chat/stream/__tests__/use-chat-stream-reducer.test.ts +105 -0
  219. package/src/components/chat/stream/chat-dialog-store.ts +536 -0
  220. package/src/components/chat/stream/chat-stream-reducer.ts +1928 -0
  221. package/src/components/chat/stream/delta-batcher.ts +168 -0
  222. package/src/components/chat/stream/index.ts +55 -0
  223. package/src/components/chat/stream/message-mutations.ts +340 -0
  224. package/src/components/chat/stream/use-chat-stream-reducer.ts +126 -0
  225. package/src/components/chat/thinking-display.tsx +1 -1
  226. package/src/components/chat/types/.api.types.md +39 -49
  227. package/src/components/chat/types/.processing.types.md +29 -58
  228. package/src/components/chat/types/.unified-chat-state.types.md +2 -2
  229. package/src/components/chat/types/api.types.ts +6 -73
  230. package/src/components/chat/types/processing.types.ts +11 -53
  231. package/src/components/chat/types/unified-chat-state.types.ts +16 -0
  232. package/src/components/chat/utils/.extract-incomplete-message-state.md +21 -3
  233. package/src/components/chat/utils/.history-merge.md +44 -3
  234. package/src/components/chat/utils/.index.md +31 -40
  235. package/src/components/chat/utils/__tests__/__snapshots__/process-historical-messages-golden.test.ts.snap +420 -0
  236. package/src/components/chat/utils/__tests__/__snapshots__/segment-accumulator-golden.test.ts.snap +605 -0
  237. package/src/components/chat/utils/__tests__/extract-incomplete-message-state.test.ts +106 -0
  238. package/src/components/chat/utils/__tests__/history-merge.test.ts +160 -0
  239. package/src/components/chat/utils/__tests__/process-historical-messages-approvals.test.ts +61 -0
  240. package/src/components/chat/utils/__tests__/process-historical-messages-golden.test.ts +394 -0
  241. package/src/components/chat/utils/__tests__/segment-accumulator-golden.test.ts +270 -0
  242. package/src/components/chat/utils/extract-incomplete-message-state.ts +93 -6
  243. package/src/components/chat/utils/history-merge.ts +85 -5
  244. package/src/components/chat/utils/index.ts +5 -8
  245. package/src/components/chat/utils/process-historical-messages.ts +361 -385
  246. package/src/components/onboarding-guides/onboarding-guide-detail-view.tsx +22 -4
  247. package/src/components/shared/legal-document/legal-document-page.tsx +1 -1
  248. package/src/components/shared/product-release/release-detail-page.tsx +19 -4
  249. package/src/components/ui/__tests__/__snapshots__/markdown-parity.test.tsx.snap +2420 -0
  250. package/src/components/ui/__tests__/markdown-parity.test.tsx +2540 -0
  251. package/src/components/ui/index.ts +1 -2
  252. package/src/components/ui/markdown/__tests__/mermaid-security.test.ts +176 -0
  253. package/src/components/ui/markdown/__tests__/mermaid-stale-render.test.tsx +151 -0
  254. package/src/components/ui/markdown/__tests__/sanitize-invariant.test.ts +354 -0
  255. package/src/components/ui/markdown/__tests__/sanitize-render.test.tsx +118 -0
  256. package/src/components/ui/markdown/__tests__/streaming.test.tsx +436 -0
  257. package/src/components/ui/markdown/base-components.tsx +360 -0
  258. package/src/components/ui/markdown/engine.tsx +315 -0
  259. package/src/components/ui/markdown/heading-ids.ts +239 -0
  260. package/src/components/ui/markdown/index.ts +49 -0
  261. package/src/components/ui/markdown/mermaid-diagram.tsx +323 -0
  262. package/src/components/ui/markdown/rich/embed-overrides.tsx +199 -0
  263. package/src/components/ui/markdown/rich/rich-markdown-renderer.tsx +184 -0
  264. package/src/components/ui/markdown/rich/shortcodes.ts +170 -0
  265. package/src/components/ui/markdown/sanitize.ts +3584 -0
  266. package/src/components/ui/markdown/simple-markdown-renderer.tsx +28 -0
  267. package/src/components/ui/markdown/streaming.ts +390 -0
  268. package/src/components/ui/markdown/text-size.ts +106 -0
  269. package/src/components/ui/release-changelog-section.tsx +1 -1
  270. package/src/components/ui/ticket-info-section.tsx +1 -1
  271. package/src/utils/index.ts +1 -0
  272. package/src/utils/markdown-fences.ts +127 -0
  273. package/src/utils/markdown-heading-id.ts +348 -0
  274. package/src/utils/markdown-section-extractor.ts +41 -56
  275. package/dist/chunk-OCEKO5CW.js.map +0 -1
  276. package/dist/chunk-QTYZMP6D.cjs.map +0 -1
  277. package/dist/chunk-TLMJHMXJ.js.map +0 -1
  278. package/dist/chunk-TWYNR4TZ.cjs.map +0 -1
  279. package/dist/chunk-WA7RR64F.js.map +0 -1
  280. package/dist/chunk-WK4N5VBX.cjs.map +0 -1
  281. package/dist/components/chat/hooks/use-realtime-chunk-processor.d.ts +0 -6
  282. package/dist/components/chat/hooks/use-realtime-chunk-processor.d.ts.map +0 -1
  283. package/dist/components/chat/utils/chunk-parser.d.ts +0 -25
  284. package/dist/components/chat/utils/chunk-parser.d.ts.map +0 -1
  285. package/dist/components/ui/rich-markdown-renderer.d.ts +0 -34
  286. package/dist/components/ui/rich-markdown-renderer.d.ts.map +0 -1
  287. package/dist/components/ui/simple-markdown-renderer.d.ts +0 -73
  288. package/dist/components/ui/simple-markdown-renderer.d.ts.map +0 -1
  289. package/src/components/chat/hooks/.use-realtime-chunk-processor.md +0 -77
  290. package/src/components/chat/hooks/use-realtime-chunk-processor.ts +0 -489
  291. package/src/components/chat/utils/.chunk-parser.md +0 -62
  292. package/src/components/chat/utils/chunk-parser.ts +0 -262
  293. package/src/components/ui/.simple-markdown-renderer.md +0 -52
  294. package/src/components/ui/rich-markdown-renderer.tsx +0 -1223
  295. package/src/components/ui/simple-markdown-renderer.tsx +0 -964
  296. /package/dist/{chunk-ADPMHWOE.js.map → chunk-72XAID7Y.js.map} +0 -0
  297. /package/dist/{chunk-PAGKRNWK.js.map → chunk-7WZHBQ4J.js.map} +0 -0
  298. /package/dist/{chunk-TSZHM74B.js.map → chunk-DC2TKS7C.js.map} +0 -0
  299. /package/dist/{chunk-I64ABCDX.js.map → chunk-I2B6X77L.js.map} +0 -0
  300. /package/dist/{chunk-DTYRYB2N.js.map → chunk-K6QTZ7CZ.js.map} +0 -0
  301. /package/dist/{chunk-4LTMXDUS.js.map → chunk-KBN7PMFT.js.map} +0 -0
  302. /package/dist/{chunk-TBMV7I5N.js.map → chunk-KXZO2WZX.js.map} +0 -0
  303. /package/dist/{chunk-KEBYLU3U.js.map → chunk-LFUPI7VX.js.map} +0 -0
  304. /package/dist/{chunk-WJQHJD7J.js.map → chunk-TWSKTJHW.js.map} +0 -0
  305. /package/dist/{chunk-TZRUCD56.js.map → chunk-V3ZAAFE3.js.map} +0 -0
  306. /package/dist/{chunk-LRGHJPET.js.map → chunk-XGIFOHKE.js.map} +0 -0
@@ -0,0 +1,28 @@
1
+ "use client";
2
+
3
+ /**
4
+ * SimpleMarkdownRenderer — the chat/doc composition over the unified
5
+ * `MarkdownEngine`. This IS the real component (not a compat alias): the
6
+ * old 966-line standalone implementation was deleted in the unification;
7
+ * its entire prop surface maps 1:1 onto the engine. Chat consumers keep
8
+ * layering `additionalRemarkPlugins` (card/mention links) and
9
+ * `componentOverrides` exactly as before.
10
+ */
11
+ import React from 'react';
12
+ import { MarkdownEngine, type MarkdownEngineProps } from './engine';
13
+ import type { ResolveLinkResult } from '../../../types/doc-source';
14
+
15
+ export type { ResolveLinkResult };
16
+
17
+ export interface SimpleMarkdownRendererProps
18
+ extends Omit<MarkdownEngineProps, 'extraAllowedHtmlTags'> {}
19
+
20
+ /**
21
+ * A type-narrowed ALIAS of the engine, not a wrapper: the composition adds
22
+ * no behavior (it only hides `extraAllowedHtmlTags` from the prop surface),
23
+ * and `MarkdownEngine` is already `memo`'d. Wrapping it in a second `memo`
24
+ * bought nothing and cost an extra shallow-compare pass plus a fiber per
25
+ * chat segment.
26
+ */
27
+ export const SimpleMarkdownRenderer =
28
+ MarkdownEngine as React.NamedExoticComponent<SimpleMarkdownRendererProps>;
@@ -0,0 +1,390 @@
1
+ /**
2
+ * Streaming helpers for the unified markdown engine (pure, no React).
3
+ *
4
+ * Design contract (unification plan §D1 "Streaming rendering performance"):
5
+ * - Markdown is NOT context-free across blocks. The splitter only cuts at
6
+ * boundaries it can PROVE are atomic; when atomicity is unprovable the
7
+ * content is left in one unit (unmemoized) — correctness beats cache hits.
8
+ * - Blocks containing `card://` / `mention://` markers are never memoized:
9
+ * their text is identical before/after the entity ref resolves, so a
10
+ * text-keyed cache would serve the stale unresolved card mid-stream.
11
+ * - On stream completion the engine discards all of this and does ONE
12
+ * authoritative whole-document parse — streaming can never permanently
13
+ * diverge (late reference defs, footnotes, list renumbering self-heal).
14
+ * - Tail completion auto-closes ONLY unterminated fenced code blocks
15
+ * (fence-count based — unambiguous). Inline emphasis/links are NOT
16
+ * auto-closed: a stray `*` in "2 * 3" or a non-link `[` would be
17
+ * mis-wrapped, which is worse than the brief flicker it prevents.
18
+ */
19
+
20
+ import { createFenceTracker, isBlankLine, type FenceTracker } from '../../../utils/markdown-fences'
21
+
22
+ export interface StreamingBlock {
23
+ /** Raw markdown source of this unit (including trailing blank lines). */
24
+ text: string
25
+ /** Position index — cache key component so identical blocks never alias. */
26
+ index: number
27
+ /**
28
+ * 1-based line of this unit's first line WITHIN the whole document.
29
+ * Each unit is parsed by its own `ReactMarkdown`, so hast positions are
30
+ * unit-relative; the engine adds `startLine - 1` back to look ids up in
31
+ * the document-wide heading-id map (see ./heading-ids.ts).
32
+ */
33
+ startLine: number
34
+ /**
35
+ * True when this unit may be render-cached: it is complete (not the
36
+ * trailing unit), atomic, and free of cross-block / late-resolving
37
+ * constructs (card/mention markers, reference definitions/uses,
38
+ * footnotes).
39
+ */
40
+ memoizable: boolean
41
+ }
42
+
43
+ /** Constructs that resolve across blocks or after the text settles. */
44
+ const NON_MEMOIZABLE_RE = /card:\/\/|mention:\/\/|^\s*\[[^\]]*\]:\s|\]\[|\[\^/m
45
+
46
+ /**
47
+ * Raw HTML block-level containers. A blank line inside an OPEN one of these
48
+ * is not a block boundary: cutting there hands react-markdown an unbalanced
49
+ * fragment, so the container's body renders outside the container and the
50
+ * stray close tag is dropped (`<details>` disclosure bodies escaping the
51
+ * widget mid-stream — and the wrong render getting cached).
52
+ */
53
+ const RAW_BLOCK_TAGS = new Set([
54
+ 'details', 'div', 'table', 'section', 'article', 'aside', 'blockquote',
55
+ 'figure', 'form', 'fieldset', 'header', 'footer', 'main', 'nav', 'dl',
56
+ 'ol', 'ul', 'pre', 'video', 'audio', 'picture', 'iframe', 'template',
57
+ 'svg',
58
+ ])
59
+
60
+ /** `<tag …>` / `</tag>` occurrences, used for raw-HTML depth tracking. */
61
+ const HTML_TAG_RE = /<(\/?)([a-zA-Z][a-zA-Z0-9-]*)([^>]*)>/g
62
+
63
+ /**
64
+ * A start tag whose `>` has NOT arrived yet on this line
65
+ * (`<div\n class="x">`). Only the trailing occurrence matters, and only
66
+ * for RAW_BLOCK_TAGS — restricting it there keeps prose like `a <b` from
67
+ * latching the scanner into "inside a tag" forever.
68
+ */
69
+ const DANGLING_OPEN_TAG_RE = /<([a-zA-Z][a-zA-Z0-9-]*)(?:\s[^>]*)?$/
70
+
71
+ /**
72
+ * A line that may START a raw HTML block. CommonMark puts the `<` at column
73
+ * 0..3, but a raw HTML block nested in a list item is indented to the item's
74
+ * CONTENT column (`1. step` → 4, and up to 7 for a wide ordered marker).
75
+ * The old column-0..3 gate missed exactly those, so an unbalanced raw-HTML
76
+ * container nested in a list item never shifted the scanner's depth and its
77
+ * unit was marked memoizable — contradicting the "unbalanced raw-HTML units
78
+ * are never cached" policy this module documents.
79
+ */
80
+ const HTML_BLOCK_START_RE = /^\s{0,7}<\/?[a-zA-Z]/
81
+
82
+ /**
83
+ * Cap on how long the raw-HTML latch may suppress cutting. An unclosed
84
+ * `<div>` (or a start tag whose `>` never arrives) would otherwise pin
85
+ * `htmlDepth > 0` for the ENTIRE remaining message, collapsing it into one
86
+ * ever-growing non-memoizable unit and disabling the atomic-block
87
+ * optimization outright.
88
+ *
89
+ * THE TRADEOFF, STATED HONESTLY: past the cap the splitter resumes cutting
90
+ * even though a container is still open, so a genuinely >200-line authored
91
+ * `<div>` / `<table>` wrapper IS cut mid-container and visibly breaks apart
92
+ * while streaming (its body renders outside the wrapper, the stray close tag
93
+ * is dropped). Those units are still marked non-memoizable, so nothing WRONG
94
+ * is ever cached and the stream-completion whole-document reparse restores
95
+ * the correct structure — but during the stream the render is wrong, not
96
+ * merely uncached. (An earlier comment here claimed "never a wrong render";
97
+ * that was only true below the cap.)
98
+ *
99
+ * The cap is kept because the alternative — never cutting while latched —
100
+ * makes ONE unbounded unit out of every message containing an unclosed tag,
101
+ * which is the common case (an LLM mid-emission always has one) and costs a
102
+ * full reparse of the entire message on every token.
103
+ */
104
+ const HTML_LATCH_LINE_LIMIT = 200
105
+
106
+ /**
107
+ * Two properties of the fence tracker, stated so they stop being accidents.
108
+ * A reviewer confirmed both hold today, but neither was written down, so a
109
+ * future change could quietly break them.
110
+ *
111
+ * 1. EOF ON THE OPENER LINE EMITS AN EMPTY PAIR. When the stream stops exactly
112
+ * on a fence opener, `completeStreamingTail` closes it at EOF and the render
113
+ * contains a bare ```/``` — a momentarily empty `<pre>`. It is cosmetic and
114
+ * self-heals on the next delta. Do NOT "fix" it by suppressing the close:
115
+ * that leaks an unterminated fence into the parse instead, which is worse.
116
+ *
117
+ * 2. THIS SCANNER AND THE SANITIZER'S MASK CAN DISAGREE ABOUT WHICH FENCE IS
118
+ * OPEN, AND BOTH MUST FAIL CLOSED. `scanLine`'s `pendingOpenTag` early
119
+ * return skips `fences.push`, so a fence opened on a line consumed by an
120
+ * unclosed HTML tag is never recorded here — while `sanitize.ts`'s
121
+ * `blankFencedRegions` runs its own tracker over the same text and may see
122
+ * it. The divergence is safe ONLY because each consumer degrades toward
123
+ * doing less: `completeStreamingTail` closes nothing it did not see open,
124
+ * and `blankFencedRegions` blanks nothing it cannot locate, so the output
125
+ * degrades to "render as-is" rather than to a corrupted document. Any
126
+ * change to the early return, to `fences` bookkeeping, or to either
127
+ * consumer must preserve fail-closed behaviour in BOTH directions
128
+ * (scanner-ahead and scanner-behind).
129
+ */
130
+
131
+ /**
132
+ * Line-scanner state shared by `splitStreamingBlocks` and
133
+ * `completeStreamingTail` — ONE implementation of "where are we in the
134
+ * document", so the splitter and the tail-completer can never disagree
135
+ * about which fence is open.
136
+ */
137
+ interface ScanState {
138
+ /**
139
+ * Fenced-code state machine. NOT a local copy: `createFenceTracker` lives
140
+ * in the server-safe `utils/markdown-fences` and is the SAME instance
141
+ * shape the heading scanner uses, so "is this line inside a fence" has
142
+ * exactly one definition. The previous duplicate here (a verbatim
143
+ * `FENCE_RE` plus its own open/close state machine, cross-referenced by a
144
+ * comment) is precisely the drift that produced the `~~~` bug.
145
+ */
146
+ fences: FenceTracker
147
+ /** Depth of currently open raw HTML block containers. */
148
+ htmlDepth: number
149
+ /** Raw-block tag name of a start tag still waiting for its `>`, or null. */
150
+ pendingOpenTag: string | null
151
+ /** Consecutive lines spent with the raw-HTML latch engaged. */
152
+ htmlLatchLines: number
153
+ }
154
+
155
+ function createScanState(): ScanState {
156
+ return {
157
+ fences: createFenceTracker(),
158
+ htmlDepth: 0,
159
+ pendingOpenTag: null,
160
+ htmlLatchLines: 0,
161
+ }
162
+ }
163
+
164
+ /** Raw-HTML state is unbalanced (a container or a start tag is still open). */
165
+ function htmlLatched(state: ScanState): boolean {
166
+ return state.htmlDepth > 0 || state.pendingOpenTag !== null
167
+ }
168
+
169
+ /** True while raw-HTML state forbids cutting (latch cap not yet reached). */
170
+ function htmlBlocksCut(state: ScanState): boolean {
171
+ return htmlLatched(state) && state.htmlLatchLines <= HTML_LATCH_LINE_LIMIT
172
+ }
173
+
174
+ /** Scan `line` from `from` for complete tags, then record any dangling opener. */
175
+ function scanTags(state: ScanState, line: string, from: number): void {
176
+ HTML_TAG_RE.lastIndex = from
177
+ let m: RegExpExecArray | null
178
+ let end = from
179
+ while ((m = HTML_TAG_RE.exec(line)) !== null) {
180
+ end = HTML_TAG_RE.lastIndex
181
+ const tag = m[2].toLowerCase()
182
+ if (!RAW_BLOCK_TAGS.has(tag)) continue
183
+ if (m[1] === '/') {
184
+ if (state.htmlDepth > 0) state.htmlDepth--
185
+ } else if (!m[3].trimEnd().endsWith('/')) {
186
+ state.htmlDepth++
187
+ }
188
+ }
189
+ const dangling = DANGLING_OPEN_TAG_RE.exec(line.slice(end))
190
+ if (dangling && RAW_BLOCK_TAGS.has(dangling[1].toLowerCase())) {
191
+ state.pendingOpenTag = dangling[1].toLowerCase()
192
+ }
193
+ }
194
+
195
+ /** Advance `state` across one raw source line (mutates). */
196
+ function scanLine(state: ScanState, line: string): void {
197
+ // A start tag spanning lines wins over everything: its continuation lines
198
+ // are attribute soup, not markdown.
199
+ if (state.pendingOpenTag !== null) {
200
+ const gt = line.indexOf('>')
201
+ if (gt === -1) {
202
+ state.htmlLatchLines++
203
+ return
204
+ }
205
+ const selfClosing = line.slice(0, gt).trimEnd().endsWith('/')
206
+ const tag = state.pendingOpenTag
207
+ state.pendingOpenTag = null
208
+ if (!selfClosing && RAW_BLOCK_TAGS.has(tag)) state.htmlDepth++
209
+ scanTags(state, line, gt + 1)
210
+ state.htmlLatchLines = htmlLatched(state) ? state.htmlLatchLines + 1 : 0
211
+ return
212
+ }
213
+
214
+ // Fence delimiters and fence content are both opaque to the HTML scanner —
215
+ // only `text` lines carry markup that can shift raw-HTML depth.
216
+ if (state.fences.push(line) !== 'text') return
217
+
218
+ // Depth > 0 means we are INSIDE a container, where the closing tag may sit
219
+ // anywhere on a line (`some text </details>`). Scanning only column-0..3
220
+ // lines there meant such a close never decremented, so the latch stuck.
221
+ // At depth 0 only a line that can BEGIN a raw HTML block is considered, so
222
+ // `a < b` prose can't shift depth.
223
+ if (state.htmlDepth === 0 && !HTML_BLOCK_START_RE.test(line)) return
224
+ scanTags(state, line, 0)
225
+ state.htmlLatchLines = htmlLatched(state) ? state.htmlLatchLines + 1 : 0
226
+ }
227
+
228
+ /**
229
+ * Split streaming markdown into atomic units at blank lines that are
230
+ * provably block boundaries. A blank line does NOT split when:
231
+ * - inside a fenced code block,
232
+ * - the next non-blank line is indented (loose-list / blockquote
233
+ * continuation cannot be ruled out),
234
+ * - the next non-blank line starts a list item or blockquote AND the
235
+ * previous unit ended in a list item or blockquote (loose list /
236
+ * multi-paragraph quote continuation).
237
+ * The FINAL unit is always the live tail (never memoizable).
238
+ *
239
+ * BLANK LINES COME FROM `isBlankLine` (utils/markdown-fences), never from
240
+ * `String.prototype.trim()`. This file is the THIRD consumer of that module
241
+ * (it already instantiates `createFenceTracker`) and makes exactly the
242
+ * CommonMark blank-line decision the helper was minted for, yet it kept four
243
+ * hand-rolled `trim() === ''` tests — so the module's "every blank-line test"
244
+ * SSOT claim was false here. `trim()` strips the full Unicode White_Space set
245
+ * (U+00A0 NBSP, U+000B VT, U+000C FF, U+FEFF BOM), none of which CommonMark
246
+ * treats as blank: `splitStreamingBlocks('foo\n<NBSP>\nbar\n\ntail')` returned
247
+ * THREE units where the non-blank filler control (`foo\nx\nbar\n\ntail`)
248
+ * returns TWO — one NBSP line cut a paragraph into two `ReactMarkdown` units on
249
+ * the STREAMING path, rendering two `<p>` where the non-streaming and SEO twins
250
+ * render one. Not a security hole (the fence tracker and `htmlBlocksCut` still
251
+ * gate the cut), but a live divergence. It survived because the swallow sweep
252
+ * drove only `SimpleMarkdownRenderer`; the sweep now drives this splitter too,
253
+ * in both the exotic-blank and CRLF spellings.
254
+ */
255
+ export function splitStreamingBlocks(content: string): StreamingBlock[] {
256
+ const lines = content.split('\n')
257
+ const units: string[][] = []
258
+ const unitTouchedHtml: boolean[] = []
259
+ let current: string[] = []
260
+ let currentTouchedHtml = false
261
+ const state = createScanState()
262
+
263
+ const isListOrQuote = (line: string) =>
264
+ /^\s{0,3}(?:[-+*]\s|\d{1,9}[.)]\s|>)/.test(line)
265
+
266
+ /**
267
+ * FIRST non-blank line of the accumulated unit — i.e. what this unit IS.
268
+ *
269
+ * The continuation guard below used the LAST non-blank line instead, which
270
+ * silently failed for every list item carrying a second block. Take the
271
+ * canonical shape of an assistant answer:
272
+ *
273
+ * 1. Install:
274
+ *
275
+ * ```bash
276
+ * npm i
277
+ * ```
278
+ *
279
+ * 2. Run it.
280
+ *
281
+ * At the blank line before `2.` the unit's last non-blank line is the fence
282
+ * closer, not a list marker — so the guard let the cut through and every
283
+ * remaining item became its OWN `<ol>` with no `start` attribute. The visible
284
+ * result is "1. / 1. / 1." while the extracted TEXT stays identical (which is
285
+ * why the equivalence tests missed it), and because those units are complete
286
+ * and atomic they were `memoizable`, so the wrong render was CACHED for the
287
+ * rest of the turn instead of self-healing on the next token.
288
+ *
289
+ * Asking whether the unit STARTS with a marker is the right question: it stays
290
+ * true across items while the list accumulates (each declined cut keeps the
291
+ * same first line), and it is false for a paragraph that merely happens to be
292
+ * followed by a list — so a genuinely new list after prose still cuts.
293
+ */
294
+ const firstNonBlank = (arr: string[]): string | undefined => {
295
+ for (const line of arr) {
296
+ if (!isBlankLine(line)) return line
297
+ }
298
+ return undefined
299
+ }
300
+
301
+ for (let i = 0; i < lines.length; i++) {
302
+ const line = lines[i]
303
+ const depthBefore = state.htmlDepth
304
+ const pendingBefore = state.pendingOpenTag
305
+ scanLine(state, line)
306
+ if (
307
+ state.htmlDepth !== depthBefore ||
308
+ state.pendingOpenTag !== pendingBefore ||
309
+ htmlLatched(state)
310
+ )
311
+ currentTouchedHtml = true
312
+ current.push(line)
313
+
314
+ const isBlank = isBlankLine(line)
315
+ // Never cut inside an open fence, nor inside an unbalanced raw HTML
316
+ // block container / a start tag still waiting for its `>`.
317
+ if (!isBlank || state.fences.openChar() !== null || htmlBlocksCut(state)) continue
318
+
319
+ // Candidate boundary at a blank line outside fences. Look ahead to the
320
+ // next non-blank line to decide whether cutting here is provably safe.
321
+ let j = i + 1
322
+ while (j < lines.length && isBlankLine(lines[j])) j++
323
+ if (j >= lines.length) continue // trailing blanks stay with the tail
324
+
325
+ const next = lines[j]
326
+ if (/^\s/.test(next)) continue // indented continuation — unprovable
327
+ const unitOpener = firstNonBlank(current)
328
+ if (isListOrQuote(next) && unitOpener !== undefined && isListOrQuote(unitOpener)) {
329
+ // Loose list / multi-paragraph blockquote continuation — do not cut.
330
+ continue
331
+ }
332
+
333
+ // A unit whose entire content is whitespace is not a block — with 2+
334
+ // blank lines between blocks the loop reaches a cut point with nothing
335
+ // but blanks accumulated, and emitting it costs a `ReactMarkdown`
336
+ // instance (and a React key) that renders nothing. Leave `current`
337
+ // accumulating so the blanks fold into the NEXT unit; line numbering
338
+ // (and therefore `startLine`) is unaffected either way.
339
+ if (current.every(isBlankLine)) continue
340
+
341
+ units.push(current)
342
+ unitTouchedHtml.push(currentTouchedHtml)
343
+ current = []
344
+ currentTouchedHtml = false
345
+ }
346
+ if (current.length) {
347
+ units.push(current)
348
+ unitTouchedHtml.push(currentTouchedHtml)
349
+ }
350
+
351
+ let cursorLine = 1
352
+ return units.map((unitLines, idx) => {
353
+ const text = unitLines.join('\n')
354
+ const isTail = idx === units.length - 1
355
+ const startLine = cursorLine
356
+ cursorLine += unitLines.length
357
+ return {
358
+ text,
359
+ index: idx,
360
+ startLine,
361
+ // Units carrying UNBALANCED raw HTML are never cached: an open
362
+ // container (or a start tag still awaiting its `>`) is exactly the
363
+ // case where rehype-raw's reparse makes a stale cached render
364
+ // structurally wrong rather than merely late. A raw container that
365
+ // opens AND closes within the unit (`<div>x</div>`) leaves the
366
+ // scanner's depth unchanged, so it stays memoizable — correctly: its
367
+ // parse cannot be invalidated by later tokens.
368
+ memoizable: !isTail && !unitTouchedHtml[idx] && !NON_MEMOIZABLE_RE.test(text),
369
+ }
370
+ })
371
+ }
372
+
373
+ /**
374
+ * Auto-close an unterminated fenced code block at the streaming tail so the
375
+ * half-open fence doesn't flip the rest of the message into code while
376
+ * tokens arrive.
377
+ *
378
+ * Uses the SAME scanner as `splitStreamingBlocks` (never a parallel
379
+ * fence-count heuristic — a naive count treats ``` and ~~~ as
380
+ * interchangeable and appends a spurious closer to `` ```\n~~~\n``` ``),
381
+ * and appends the RECORDED opener so a `~~~` block is closed with `~~~`.
382
+ */
383
+ export function completeStreamingTail(content: string): string {
384
+ const state = createScanState()
385
+ for (const line of content.split('\n')) scanLine(state, line)
386
+ const openChar = state.fences.openChar()
387
+ if (openChar === null) return content
388
+ const closer = openChar.repeat(state.fences.openLength())
389
+ return content.endsWith('\n') ? `${content}${closer}` : `${content}\n${closer}`
390
+ }
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Text-size presets for the unified markdown engine.
3
+ *
4
+ * `default` / `compact` / `large` are carried over verbatim from the old
5
+ * `SimpleMarkdownRenderer`. `article` is NEW — it reproduces the exact
6
+ * typography the old `RichMarkdownRenderer` hardcoded per element, so
7
+ * content surfaces (blog, case studies, releases, legal, docs) keep
8
+ * byte-identical classes through the unification.
9
+ *
10
+ * ODS-TOKENS FLAG (ODS_TOKEN_RULES §Typography / §General): the `article`
11
+ * preset carries raw px classes (`text-[32px] md:text-[40px] …`) because
12
+ * ODS currently has NO composite tokens for long-form prose — `text-h1`/
13
+ * `text-h2` are Azeret Mono UI-label scale and `text-h5` is uppercase,
14
+ * so mapping prose headings onto them would visibly regress articles.
15
+ * The `code` entry of EVERY preset (`text-[13px]` / `text-[14px]` /
16
+ * `text-[16px]`), not just `article`'s, is raw px for the same reason: ODS
17
+ * has no code/mono type scale. `base-components.tsx` carries the matching
18
+ * flag for inline code's `text-[0.9em]` (the mono FAMILY is no longer an
19
+ * exemption — both code surfaces now use `font-mono`).
20
+ * Per the unification plan, the missing prose- and code-typography tokens
21
+ * are FLAGGED here for addition to ODS; the raw-px carry-over is the
22
+ * documented, review-gated exemption recorded in the unification PR.
23
+ * Do NOT copy these px classes anywhere else.
24
+ */
25
+
26
+ export type TextSizeElement =
27
+ | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'
28
+ | 'p' | 'li' | 'blockquote' | 'code' | 'th' | 'td';
29
+
30
+ export type TextSizeClassMap = Partial<Record<TextSizeElement, string>>;
31
+ export type TextSizePreset = 'default' | 'compact' | 'large' | 'article';
32
+ export type TextSizeConfig =
33
+ | TextSizePreset
34
+ | TextSizeClassMap
35
+ | { preset: TextSizePreset; overrides: TextSizeClassMap };
36
+
37
+ export const TEXT_SIZE_PRESETS: Record<TextSizePreset, Record<TextSizeElement, string>> = {
38
+ default: {
39
+ h1: 'text-heading-1',
40
+ h2: 'text-heading-2',
41
+ h3: 'text-2xl md:text-3xl',
42
+ h4: 'text-xl',
43
+ h5: 'text-lg md:text-xl',
44
+ h6: 'text-base md:text-lg',
45
+ p: 'md:text-h4 lg:text-h4',
46
+ li: 'text-base md:text-lg',
47
+ blockquote: 'text-lg',
48
+ code: 'text-[14px]',
49
+ th: 'text-xs md:text-sm',
50
+ td: 'text-xs md:text-sm',
51
+ },
52
+ compact: {
53
+ h1: 'text-heading-2',
54
+ h2: 'text-heading-3',
55
+ h3: 'text-xl md:text-2xl',
56
+ h4: 'text-lg md:text-xl',
57
+ h5: 'text-base md:text-lg',
58
+ h6: 'text-sm md:text-base',
59
+ p: 'text-base md:text-lg',
60
+ li: 'text-base md:text-lg',
61
+ blockquote: 'text-base md:text-lg',
62
+ code: 'text-[13px]',
63
+ th: 'text-xs md:text-sm',
64
+ td: 'text-xs md:text-sm',
65
+ },
66
+ large: {
67
+ h1: 'text-heading-1',
68
+ h2: 'text-heading-1',
69
+ h3: 'text-heading-2',
70
+ h4: 'text-2xl md:text-3xl',
71
+ h5: 'text-xl md:text-2xl',
72
+ h6: 'text-lg md:text-xl',
73
+ p: 'text-h3',
74
+ li: 'text-lg md:text-xl',
75
+ blockquote: 'text-xl md:text-2xl',
76
+ code: 'text-[16px]',
77
+ th: 'text-sm md:text-base',
78
+ td: 'text-sm md:text-base',
79
+ },
80
+ // Old RichMarkdownRenderer typography, byte-for-byte (see header note).
81
+ article: {
82
+ h1: 'text-[32px] md:text-[40px] lg:text-[48px] leading-[1.25]',
83
+ h2: 'text-[28px] md:text-[32px]',
84
+ h3: 'text-[24px] md:text-[28px]',
85
+ h4: 'text-[20px] md:text-[22px]',
86
+ h5: 'text-[18px] md:text-[20px]',
87
+ h6: 'text-[16px] md:text-[18px]',
88
+ // Full class string incl. spacing/leading — `cn` (tailwind-merge)
89
+ // resolves these OVER the base map's `leading-relaxed mb-4`, keeping
90
+ // Rich's article rhythm (`my-4`, `leading-[1.6]`, `font-sans`).
91
+ p: 'font-sans text-[16px] md:text-[18px] lg:text-[20px] leading-[1.6] my-4',
92
+ li: 'text-[16px] md:text-[18px]',
93
+ blockquote: 'text-[1.125em]',
94
+ code: 'text-[14px]',
95
+ th: 'text-xs md:text-sm',
96
+ td: 'text-xs md:text-sm',
97
+ },
98
+ };
99
+
100
+ export function resolveTextSizeConfig(config?: TextSizeConfig): Record<TextSizeElement, string> {
101
+ const defaultSizes = TEXT_SIZE_PRESETS.default;
102
+ if (!config) return defaultSizes;
103
+ if (typeof config === 'string') return TEXT_SIZE_PRESETS[config];
104
+ if ('preset' in config) return { ...TEXT_SIZE_PRESETS[config.preset], ...config.overrides };
105
+ return { ...defaultSizes, ...config };
106
+ }
@@ -4,7 +4,7 @@ import React, { useState } from 'react';
4
4
  import { Badge } from './badge';
5
5
  import { ChevronDown } from 'lucide-react';
6
6
  import { FadePreview } from './fade-preview';
7
- import { RichMarkdownRenderer } from './rich-markdown-renderer';
7
+ import { RichMarkdownRenderer } from './markdown';
8
8
  import type { ChangelogEntry } from '../../types/product-release';
9
9
 
10
10
  interface ReleaseChangelogSectionProps {
@@ -12,7 +12,7 @@ import { TicketDetailSection } from "./ticket-detail-section"
12
12
  import { type TicketAttachment, TicketAttachmentsList } from "./ticket-attachments-list"
13
13
  import type { TicketNote } from "./ticket-note-card"
14
14
  import { TicketNotesSection } from "./ticket-notes-section"
15
- import { SimpleMarkdownRenderer } from "./simple-markdown-renderer"
15
+ import { SimpleMarkdownRenderer } from "./markdown/simple-markdown-renderer"
16
16
 
17
17
  export type { TicketAssigneeOption }
18
18
 
@@ -351,6 +351,7 @@ export * from './humanity-signals'
351
351
  export * from './doc-path-utils'
352
352
  export * from './doc-tree-nav'
353
353
  export * from './tree-builder'
354
+ export * from './markdown-heading-id'
354
355
  export * from './markdown-section-extractor'
355
356
  export * from './markdown-to-plain'
356
357
  export * from './embed-url-converters'