@djangocfg/ui-tools 2.1.404 → 2.1.408

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 (336) hide show
  1. package/README.md +9 -11
  2. package/dist/file-icon/index.cjs +449 -61
  3. package/dist/file-icon/index.cjs.map +1 -1
  4. package/dist/file-icon/index.d.cts +56 -18
  5. package/dist/file-icon/index.d.ts +56 -18
  6. package/dist/file-icon/index.mjs +448 -62
  7. package/dist/file-icon/index.mjs.map +1 -1
  8. package/dist/tree/index.cjs +49 -22
  9. package/dist/tree/index.cjs.map +1 -1
  10. package/dist/tree/index.d.cts +9 -3
  11. package/dist/tree/index.d.ts +9 -3
  12. package/dist/tree/index.mjs +49 -22
  13. package/dist/tree/index.mjs.map +1 -1
  14. package/dist/{types-B_zhyAqR.d.cts → types-eEu8SeiQ.d.cts} +4 -0
  15. package/dist/{types-B_zhyAqR.d.ts → types-eEu8SeiQ.d.ts} +4 -0
  16. package/package.json +13 -16
  17. package/src/components/FloatingToolbar/index.tsx +37 -3
  18. package/src/lib/page-snapshot/__tests__/capture-integration.test.ts +85 -0
  19. package/src/lib/page-snapshot/__tests__/engine.test.ts +36 -0
  20. package/src/lib/page-snapshot/__tests__/redaction-integration.test.ts +99 -0
  21. package/src/lib/page-snapshot/__tests__/tokens.test.ts +17 -0
  22. package/src/lib/page-snapshot/capture/__tests__/budget.test.ts +49 -0
  23. package/src/lib/page-snapshot/capture/__tests__/chrome-filter.test.ts +47 -0
  24. package/src/lib/page-snapshot/capture/__tests__/fold.test.ts +66 -0
  25. package/src/lib/page-snapshot/capture/__tests__/scope.test.ts +74 -0
  26. package/src/lib/page-snapshot/capture/__tests__/walk.test.ts +129 -0
  27. package/src/lib/page-snapshot/capture/accessible-name.ts +73 -0
  28. package/src/lib/page-snapshot/capture/budget.ts +95 -0
  29. package/src/lib/page-snapshot/capture/chrome-filter.ts +81 -0
  30. package/src/lib/page-snapshot/capture/classify.ts +111 -0
  31. package/src/lib/page-snapshot/capture/dom-utils.ts +111 -0
  32. package/src/lib/page-snapshot/capture/fold.ts +96 -0
  33. package/src/lib/page-snapshot/capture/scope.ts +169 -0
  34. package/src/lib/page-snapshot/capture/walk.ts +250 -0
  35. package/src/lib/page-snapshot/cst/__tests__/serialize.test.ts +50 -0
  36. package/src/lib/page-snapshot/cst/directives.ts +47 -0
  37. package/src/lib/page-snapshot/cst/payload.ts +50 -0
  38. package/src/lib/page-snapshot/cst/serialize.ts +84 -0
  39. package/src/lib/page-snapshot/cst/types.ts +115 -0
  40. package/src/lib/page-snapshot/engine.ts +176 -0
  41. package/src/lib/page-snapshot/index.ts +93 -0
  42. package/src/lib/page-snapshot/react/PageSnapshotChip.tsx +72 -0
  43. package/src/lib/page-snapshot/react/PageSnapshotPreview.tsx +78 -0
  44. package/src/lib/page-snapshot/react/__tests__/PageSnapshotChip.test.tsx +54 -0
  45. package/src/lib/page-snapshot/react/__tests__/provider.test.tsx +103 -0
  46. package/src/lib/page-snapshot/react/__tests__/use-page-snapshot-toggle.test.tsx +62 -0
  47. package/src/lib/page-snapshot/react/provider.tsx +162 -0
  48. package/src/lib/page-snapshot/react/use-page-snapshot-toggle.ts +47 -0
  49. package/src/lib/page-snapshot/react/use-page-snapshot.ts +67 -0
  50. package/src/lib/page-snapshot/redaction/__tests__/audit.test.ts +25 -0
  51. package/src/lib/page-snapshot/redaction/__tests__/heuristics.test.ts +73 -0
  52. package/src/lib/page-snapshot/redaction/__tests__/luhn.test.ts +26 -0
  53. package/src/lib/page-snapshot/redaction/__tests__/patterns.test.ts +60 -0
  54. package/src/lib/page-snapshot/redaction/audit.ts +58 -0
  55. package/src/lib/page-snapshot/redaction/heuristics.ts +75 -0
  56. package/src/lib/page-snapshot/redaction/index.ts +75 -0
  57. package/src/lib/page-snapshot/redaction/luhn.ts +25 -0
  58. package/src/lib/page-snapshot/redaction/patterns.ts +111 -0
  59. package/src/lib/page-snapshot/refs/__tests__/registry.test.ts +24 -0
  60. package/src/lib/page-snapshot/refs/registry.ts +46 -0
  61. package/src/lib/page-snapshot/staleness/__tests__/hash.test.ts +34 -0
  62. package/src/lib/page-snapshot/staleness/hash.ts +20 -0
  63. package/src/lib/page-snapshot/tokens.ts +15 -0
  64. package/src/tools/AudioPlayer/context/PlayerProvider.tsx +13 -14
  65. package/src/tools/AudioPlayer/hooks/useAudioElementEvents.ts +55 -6
  66. package/src/tools/AudioPlayer/lazy.tsx +13 -27
  67. package/src/tools/AudioPlayer/parts/Meta/TimeDisplay.tsx +2 -5
  68. package/src/tools/Chat/README.md +267 -39
  69. package/src/tools/Chat/composer/Composer.tsx +471 -0
  70. package/src/tools/Chat/composer/ComposerActionBar.tsx +65 -0
  71. package/src/tools/Chat/composer/ComposerBanner.tsx +128 -0
  72. package/src/tools/Chat/composer/ComposerButton.tsx +64 -0
  73. package/src/tools/Chat/composer/ComposerFooter.tsx +90 -0
  74. package/src/tools/Chat/composer/ComposerMenuButton.tsx +62 -0
  75. package/src/tools/Chat/composer/ComposerModelPicker.tsx +104 -0
  76. package/src/tools/Chat/composer/ComposerRichTextarea.tsx +88 -0
  77. package/src/tools/Chat/composer/ComposerToolPill.tsx +95 -0
  78. package/src/tools/Chat/composer/index.ts +45 -0
  79. package/src/tools/Chat/composer/size-context.tsx +26 -0
  80. package/src/tools/Chat/composer/types.ts +143 -0
  81. package/src/tools/Chat/composer/useComposerActions.tsx +164 -0
  82. package/src/tools/Chat/context/ChatProvider.tsx +54 -3
  83. package/src/tools/Chat/core/__tests__/metadata.test.ts +69 -0
  84. package/src/tools/Chat/core/index.ts +23 -1
  85. package/src/tools/Chat/core/markdown.ts +1 -1
  86. package/src/tools/Chat/core/metadata.ts +47 -0
  87. package/src/tools/Chat/core/payload-dispatch.ts +1 -1
  88. package/src/tools/Chat/core/transport/http.ts +71 -32
  89. package/src/tools/Chat/core/transport/sse.ts +18 -10
  90. package/src/tools/Chat/highlight/HighlightOverlay.tsx +101 -0
  91. package/src/tools/Chat/highlight/README.md +103 -0
  92. package/src/tools/Chat/highlight/SpotlightCanvas.tsx +153 -0
  93. package/src/tools/Chat/highlight/__tests__/HighlightOverlay.test.tsx +112 -0
  94. package/src/tools/Chat/highlight/__tests__/resolveRef.test.ts +55 -0
  95. package/src/tools/Chat/highlight/index.ts +21 -0
  96. package/src/tools/Chat/highlight/resolveRef.ts +42 -0
  97. package/src/tools/Chat/highlight/types.ts +49 -0
  98. package/src/tools/Chat/highlight/useHighlightTargets.ts +128 -0
  99. package/src/tools/Chat/hooks/index.ts +0 -5
  100. package/src/tools/Chat/hooks/useAutoFocusOnStreamEnd.ts +28 -47
  101. package/src/tools/Chat/hooks/useChat.ts +47 -14
  102. package/src/tools/Chat/hooks/useChatComposer.ts +2 -2
  103. package/src/tools/Chat/hooks/useChatLayout.ts +1 -1
  104. package/src/tools/Chat/hooks/useStreamEndFocus.ts +54 -0
  105. package/src/tools/Chat/index.ts +25 -219
  106. package/src/tools/Chat/launcher/ChatDock.tsx +1 -1
  107. package/src/tools/Chat/launcher/ChatLauncher.tsx +1 -1
  108. package/src/tools/Chat/launcher/{ChatHeader.tsx → header/ChatHeader.tsx} +24 -11
  109. package/src/tools/Chat/launcher/{ChatHeaderActionButton.tsx → header/ChatHeaderActionButton.tsx} +34 -3
  110. package/src/tools/Chat/launcher/{ChatHeaderLanguageButton.tsx → header/ChatHeaderLanguageButton.tsx} +2 -2
  111. package/src/tools/Chat/launcher/{ChatHeaderModeToggle.tsx → header/ChatHeaderModeToggle.tsx} +1 -1
  112. package/src/tools/Chat/launcher/{ChatHeaderResetButton.tsx → header/ChatHeaderResetButton.tsx} +2 -1
  113. package/src/tools/Chat/launcher/{HeaderSlots.tsx → header/HeaderSlots.tsx} +3 -3
  114. package/src/tools/Chat/launcher/header/index.ts +26 -0
  115. package/src/tools/Chat/launcher/index.ts +3 -10
  116. package/src/tools/Chat/lazy.tsx +38 -284
  117. package/src/tools/Chat/{components → messages}/MessageBubble.tsx +58 -5
  118. package/src/tools/Chat/{components → messages}/MessageList.tsx +8 -25
  119. package/src/tools/Chat/messages/blocks/MessageBlocks.tsx +131 -0
  120. package/src/tools/Chat/messages/blocks/builtin.tsx +91 -0
  121. package/src/tools/Chat/messages/blocks/index.ts +12 -0
  122. package/src/tools/Chat/messages/blocks/registry.tsx +42 -0
  123. package/src/tools/Chat/messages/blocks/renderers/AudioBlock.tsx +20 -0
  124. package/src/tools/Chat/messages/blocks/renderers/CodeBlock.tsx +19 -0
  125. package/src/tools/Chat/messages/blocks/renderers/GalleryBlock.tsx +26 -0
  126. package/src/tools/Chat/messages/blocks/renderers/ImageBlock.tsx +27 -0
  127. package/src/tools/Chat/messages/blocks/renderers/JsonBlock.tsx +12 -0
  128. package/src/tools/Chat/messages/blocks/renderers/LottieBlock.tsx +11 -0
  129. package/src/tools/Chat/messages/blocks/renderers/MapBlock.tsx +36 -0
  130. package/src/tools/Chat/messages/blocks/renderers/MermaidBlock.tsx +11 -0
  131. package/src/tools/Chat/messages/blocks/renderers/VideoBlock.tsx +24 -0
  132. package/src/tools/Chat/messages/blocks/renderers/types.ts +8 -0
  133. package/src/tools/Chat/{components → messages}/index.ts +11 -5
  134. package/src/tools/Chat/public.ts +212 -0
  135. package/src/tools/Chat/shell/ChatRoot.tsx +326 -0
  136. package/src/tools/Chat/{components → shell}/EmptyState.tsx +4 -2
  137. package/src/tools/Chat/shell/index.ts +15 -0
  138. package/src/tools/Chat/types/block.ts +120 -0
  139. package/src/tools/Chat/types/config.ts +0 -5
  140. package/src/tools/Chat/types/index.ts +17 -0
  141. package/src/tools/Chat/types/message.ts +3 -0
  142. package/src/tools/Chat/utils/index.ts +4 -0
  143. package/src/tools/CodeEditor/README.md +4 -6
  144. package/src/tools/CodeEditor/components/DiffEditor.tsx +48 -13
  145. package/src/tools/CodeEditor/components/Editor.tsx +96 -44
  146. package/src/tools/CodeEditor/context/EditorProvider.tsx +34 -17
  147. package/src/tools/CodeEditor/hooks/useEditorTheme.ts +92 -99
  148. package/src/tools/CodeEditor/hooks/useMonaco.ts +37 -22
  149. package/src/tools/CodeEditor/lazy.tsx +6 -0
  150. package/src/tools/CodeEditor/lib/index.ts +1 -1
  151. package/src/tools/CodeEditor/lib/themes.ts +3 -39
  152. package/src/tools/CronScheduler/CronScheduler.client.tsx +230 -61
  153. package/src/tools/CronScheduler/components/CustomInput.tsx +21 -4
  154. package/src/tools/CronScheduler/components/DayChips.tsx +13 -11
  155. package/src/tools/CronScheduler/components/MonthDayGrid.tsx +4 -4
  156. package/src/tools/CronScheduler/components/SchedulePreview.tsx +7 -3
  157. package/src/tools/CronScheduler/components/TimeSelector.tsx +1 -1
  158. package/src/tools/CronScheduler/index.tsx +1 -1
  159. package/src/tools/CronScheduler/types/index.ts +8 -3
  160. package/src/tools/CronScheduler/utils/cron-humanize.ts +61 -16
  161. package/src/tools/CronScheduler/utils/cron-parser.ts +13 -4
  162. package/src/tools/FileIcon/FileIcon.tsx +24 -39
  163. package/src/tools/FileIcon/get-file-icon.ts +73 -0
  164. package/src/tools/FileIcon/icons/icon-data.ts +399 -0
  165. package/src/tools/FileIcon/index.ts +4 -0
  166. package/src/tools/FileIcon/loader.ts +17 -35
  167. package/src/tools/FileIcon/specialFolders.ts +18 -0
  168. package/src/tools/Gallery/components/lightbox/GalleryLightbox.tsx +112 -35
  169. package/src/tools/Gallery/components/media/GalleryVideo.tsx +21 -2
  170. package/src/tools/Gallery/components/preview/GalleryCarousel.tsx +11 -1
  171. package/src/tools/Gallery/hooks/usePreloadImages.ts +54 -7
  172. package/src/tools/ImageViewer/components/ImageInfo.tsx +12 -1
  173. package/src/tools/ImageViewer/components/ImageToolbar.tsx +51 -43
  174. package/src/tools/ImageViewer/components/ImageViewer.tsx +106 -26
  175. package/src/tools/ImageViewer/hooks/useImageLoading.ts +13 -0
  176. package/src/tools/ImageViewer/utils/constants.ts +3 -0
  177. package/src/tools/ImageViewer/utils/index.ts +1 -0
  178. package/src/tools/JsonForm/JsonSchemaForm.tsx +4 -1
  179. package/src/tools/JsonForm/templates/ArrayFieldTemplate.tsx +5 -3
  180. package/src/tools/JsonForm/templates/BaseInputTemplate.tsx +7 -4
  181. package/src/tools/JsonForm/templates/ErrorListTemplate.tsx +3 -1
  182. package/src/tools/JsonForm/templates/ObjectFieldTemplate.tsx +23 -3
  183. package/src/tools/JsonForm/widgets/ColorWidget.tsx +20 -12
  184. package/src/tools/JsonForm/widgets/NumberWidget.tsx +14 -9
  185. package/src/tools/JsonForm/widgets/RadioWidget.tsx +78 -0
  186. package/src/tools/JsonForm/widgets/SelectWidget.tsx +1 -0
  187. package/src/tools/JsonForm/widgets/SliderWidget.tsx +7 -4
  188. package/src/tools/JsonForm/widgets/TextWidget.tsx +41 -17
  189. package/src/tools/JsonForm/widgets/index.ts +1 -0
  190. package/src/tools/JsonTree/components/JsonContent.tsx +115 -40
  191. package/src/tools/LottiePlayer/LottiePlayer.client.tsx +177 -72
  192. package/src/tools/LottiePlayer/index.tsx +14 -4
  193. package/src/tools/LottiePlayer/lazy.tsx +11 -3
  194. package/src/tools/LottiePlayer/types.ts +31 -1
  195. package/src/tools/LottiePlayer/useLottie.ts +32 -9
  196. package/src/tools/LottiePlayer/usePrefersReducedMotion.ts +46 -0
  197. package/src/tools/Map/components/LayerSwitcher.tsx +54 -21
  198. package/src/tools/Map/components/MapCluster.tsx +28 -21
  199. package/src/tools/Map/components/MapContainer.tsx +11 -4
  200. package/src/tools/Map/components/MapLegend.tsx +46 -15
  201. package/src/tools/Map/components/MapMarker.tsx +31 -2
  202. package/src/tools/Map/hooks/useMapEvents.ts +64 -105
  203. package/src/tools/MarkdownEditor/MarkdownEditor.tsx +61 -6
  204. package/src/tools/MarkdownEditor/MentionList.tsx +37 -4
  205. package/src/tools/MarkdownEditor/createMentionSuggestion.ts +11 -0
  206. package/src/tools/MarkdownEditor/lazy.tsx +32 -7
  207. package/src/tools/MarkdownEditor/styles.css +13 -0
  208. package/src/tools/MarkdownMessage/CodeBlock.tsx +40 -17
  209. package/src/tools/MarkdownMessage/MarkdownMessage.tsx +26 -6
  210. package/src/tools/MarkdownMessage/components.tsx +22 -9
  211. package/src/tools/MarkdownMessage/types.ts +24 -1
  212. package/src/tools/Mermaid/Mermaid.client.tsx +27 -5
  213. package/src/tools/Mermaid/components/MermaidErrorPanel.tsx +31 -0
  214. package/src/tools/Mermaid/components/MermaidFullscreenModal.tsx +14 -17
  215. package/src/tools/Mermaid/hooks/useMermaidRenderer.ts +264 -168
  216. package/src/tools/Mermaid/hooks/useMermaidValidation.ts +76 -10
  217. package/src/tools/Mermaid/index.tsx +6 -0
  218. package/src/tools/Mermaid/utils/mermaid-helpers.ts +141 -18
  219. package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/SchemaFields/FieldRow.tsx +11 -1
  220. package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/SchemaFields/buildTree.ts +49 -20
  221. package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/index.tsx +7 -0
  222. package/src/tools/OpenapiViewer/components/DocsLayout/grouping.ts +7 -4
  223. package/src/tools/OpenapiViewer/constants.ts +3 -0
  224. package/src/tools/OpenapiViewer/hooks/useOpenApiSchema.ts +73 -11
  225. package/src/tools/OpenapiViewer/utils/schemaExport.ts +26 -6
  226. package/src/tools/PrettyCode/PrettyCode.client.tsx +23 -16
  227. package/src/tools/PrettyCode/lazy.tsx +1 -1
  228. package/src/tools/SpeechRecognition/README.md +1 -1
  229. package/src/tools/SpeechRecognition/__tests__/language.test.ts +9 -3
  230. package/src/tools/SpeechRecognition/components/RecordingPulse.tsx +59 -0
  231. package/src/tools/SpeechRecognition/components/index.ts +2 -0
  232. package/src/tools/SpeechRecognition/core/engine/external.ts +24 -7
  233. package/src/tools/SpeechRecognition/core/language.ts +23 -6
  234. package/src/tools/SpeechRecognition/hooks/usePushToTalk.ts +36 -5
  235. package/src/tools/SpeechRecognition/hooks/useSpeechRecognition.ts +18 -11
  236. package/src/tools/SpeechRecognition/widgets/VoiceComposerSlot.tsx +94 -26
  237. package/src/tools/SpeechRecognition/widgets/index.ts +1 -1
  238. package/src/tools/Tree/README.md +4 -8
  239. package/src/tools/Tree/TreeRoot.tsx +22 -10
  240. package/src/tools/Tree/components/TreeContent.tsx +24 -4
  241. package/src/tools/Tree/components/TreeLabel.tsx +8 -2
  242. package/src/tools/Tree/components/TreeRow.tsx +16 -6
  243. package/src/tools/Tree/data/flatten.ts +10 -4
  244. package/src/tools/Tree/types.ts +4 -0
  245. package/src/tools/Uploader/components/UploadAddButton.tsx +29 -6
  246. package/src/tools/Uploader/components/UploadDropzone.tsx +63 -7
  247. package/src/tools/Uploader/components/UploadPageDropOverlay.tsx +19 -5
  248. package/src/tools/Uploader/components/UploadPreviewItem.tsx +47 -17
  249. package/src/tools/Uploader/components/UploadPreviewList.tsx +24 -12
  250. package/src/tools/Uploader/utils/formatters.ts +8 -3
  251. package/src/tools/VideoPlayer/README.md +87 -230
  252. package/src/tools/VideoPlayer/VideoPlayer.tsx +82 -0
  253. package/src/tools/VideoPlayer/canvas/canvas-dispatcher.tsx +34 -0
  254. package/src/tools/VideoPlayer/canvas/hls-canvas.tsx +39 -0
  255. package/src/tools/VideoPlayer/canvas/iframe-canvas.tsx +33 -0
  256. package/src/tools/VideoPlayer/canvas/index.ts +12 -0
  257. package/src/tools/VideoPlayer/canvas/jsx-augmentation.ts +47 -0
  258. package/src/tools/VideoPlayer/canvas/native-canvas.tsx +38 -0
  259. package/src/tools/VideoPlayer/canvas/vimeo-canvas.tsx +40 -0
  260. package/src/tools/VideoPlayer/canvas/youtube-canvas.tsx +78 -0
  261. package/src/tools/VideoPlayer/index.ts +51 -65
  262. package/src/tools/VideoPlayer/lazy.tsx +11 -54
  263. package/src/tools/VideoPlayer/parts/controls-bar.tsx +35 -0
  264. package/src/tools/VideoPlayer/parts/fullscreen.tsx +19 -0
  265. package/src/tools/VideoPlayer/parts/index.ts +15 -0
  266. package/src/tools/VideoPlayer/parts/pip.tsx +19 -0
  267. package/src/tools/VideoPlayer/parts/play-button.tsx +19 -0
  268. package/src/tools/VideoPlayer/parts/playback-rate.tsx +31 -0
  269. package/src/tools/VideoPlayer/parts/poster.tsx +3 -0
  270. package/src/tools/VideoPlayer/parts/seek-bar.tsx +26 -0
  271. package/src/tools/VideoPlayer/parts/volume.tsx +32 -0
  272. package/src/tools/VideoPlayer/styles/video-player.css +141 -0
  273. package/src/tools/VideoPlayer/types.ts +82 -0
  274. package/src/tools/VideoPlayer/utils/parse-embed-url.ts +70 -0
  275. package/src/tools/VideoPlayer/utils/vimeo-id.ts +24 -0
  276. package/src/tools/VideoPlayer/utils/youtube-id.ts +64 -0
  277. package/src/tools/index.ts +37 -29
  278. package/src/tools/Chat/components/AudioToggle.tsx +0 -78
  279. package/src/tools/Chat/components/ChatRoot.tsx +0 -305
  280. package/src/tools/Chat/components/Composer.tsx +0 -216
  281. package/src/tools/Chat/hooks/useChatScroll.ts +0 -145
  282. package/src/tools/Chat/types.ts +0 -9
  283. package/src/tools/JsonTree/components/JsonToolbar.tsx +0 -95
  284. package/src/tools/JsonTree/hooks/useElementCorner.ts +0 -84
  285. package/src/tools/JsonTree/hooks/useNavbarHeight.ts +0 -83
  286. package/src/tools/OpenapiViewer/components/DocsLayout/schemaFields.ts +0 -121
  287. package/src/tools/Tour/README.md +0 -373
  288. package/src/tools/Tour/components/Tour.tsx +0 -12
  289. package/src/tools/Tour/components/TourContent.tsx +0 -171
  290. package/src/tools/Tour/components/TourNavigation.tsx +0 -77
  291. package/src/tools/Tour/components/TourProgress.tsx +0 -88
  292. package/src/tools/Tour/components/TourSpotlight.tsx +0 -199
  293. package/src/tools/Tour/components/index.ts +0 -5
  294. package/src/tools/Tour/context/TourContext.ts +0 -19
  295. package/src/tools/Tour/context/TourProvider.tsx +0 -292
  296. package/src/tools/Tour/context/index.ts +0 -2
  297. package/src/tools/Tour/hooks/index.ts +0 -3
  298. package/src/tools/Tour/hooks/useKeyboardNavigation.ts +0 -59
  299. package/src/tools/Tour/hooks/useStepTarget.ts +0 -121
  300. package/src/tools/Tour/hooks/useTour.ts +0 -42
  301. package/src/tools/Tour/index.ts +0 -38
  302. package/src/tools/Tour/types/index.ts +0 -224
  303. package/src/tools/Tour/utils/dom.ts +0 -98
  304. package/src/tools/Tour/utils/index.ts +0 -3
  305. package/src/tools/Tour/utils/logger.ts +0 -3
  306. package/src/tools/Tour/utils/scrollIntoView.ts +0 -24
  307. package/src/tools/VideoPlayer/components/VideoControls.tsx +0 -138
  308. package/src/tools/VideoPlayer/components/VideoErrorFallback.tsx +0 -172
  309. package/src/tools/VideoPlayer/components/VideoPlayer.tsx +0 -201
  310. package/src/tools/VideoPlayer/components/index.ts +0 -14
  311. package/src/tools/VideoPlayer/context/VideoPlayerContext.tsx +0 -52
  312. package/src/tools/VideoPlayer/context/index.ts +0 -8
  313. package/src/tools/VideoPlayer/hooks/index.ts +0 -12
  314. package/src/tools/VideoPlayer/hooks/useVideoPlayerSettings.ts +0 -71
  315. package/src/tools/VideoPlayer/hooks/useVideoPositionCache.ts +0 -117
  316. package/src/tools/VideoPlayer/providers/NativeProvider.tsx +0 -284
  317. package/src/tools/VideoPlayer/providers/StreamProvider.tsx +0 -505
  318. package/src/tools/VideoPlayer/providers/VidstackProvider.tsx +0 -397
  319. package/src/tools/VideoPlayer/providers/index.ts +0 -8
  320. package/src/tools/VideoPlayer/types/index.ts +0 -38
  321. package/src/tools/VideoPlayer/types/player.ts +0 -116
  322. package/src/tools/VideoPlayer/types/provider.ts +0 -93
  323. package/src/tools/VideoPlayer/types/sources.ts +0 -97
  324. package/src/tools/VideoPlayer/utils/debug.ts +0 -14
  325. package/src/tools/VideoPlayer/utils/fileSource.ts +0 -78
  326. package/src/tools/VideoPlayer/utils/index.ts +0 -12
  327. package/src/tools/VideoPlayer/utils/resolvers.ts +0 -75
  328. /package/src/tools/Chat/{config.ts → constants.ts} +0 -0
  329. /package/src/tools/Chat/launcher/{ChatHeaderAudioToggle.tsx → header/ChatHeaderAudioToggle.tsx} +0 -0
  330. /package/src/tools/Chat/{components → messages}/Attachments.tsx +0 -0
  331. /package/src/tools/Chat/{components → messages}/JumpToLatest.tsx +0 -0
  332. /package/src/tools/Chat/{components → messages}/MessageActions.tsx +0 -0
  333. /package/src/tools/Chat/{components → messages}/Sources.tsx +0 -0
  334. /package/src/tools/Chat/{components → messages}/StreamingIndicator.tsx +0 -0
  335. /package/src/tools/Chat/{components → messages}/ToolCalls.tsx +0 -0
  336. /package/src/tools/Chat/{components → shell}/ErrorBanner.tsx +0 -0
@@ -51,11 +51,11 @@ export function MyChat() {
51
51
  - **Rich attachments.** `AttachmentsGrid` for thumbnails, `AttachmentsList` for custom renderers; `onAttachmentOpen` for lightbox.
52
52
  - **Tool-payload dispatcher.** `dispatchToolPayload(matchers, fallback)` — pluggable predicates render `<LazyJsonTree>` / `<LazyMap>` / etc.
53
53
  - **Persisted dock prefs.** `headerSlots.modeToggle.persistAs: 'my.key'` stores `mode` / `side` / `width` in localStorage; the toggle lets users flip popover ↔ side and survives reloads. (`useChatDockPrefs()` is now owned by the launcher internally — no longer a consumer-facing hook.)
54
- - **UX guards.** Auto-focus composer on dock open, two-step Escape (textarea blur → close), click-to-focus on empty message area (Slack / Linear style), `useHotkey('mod+/')` toggle.
54
+ - **UX guards.** Auto-focus composer on dock open, two-step Escape (textarea blur → close), click-to-focus on empty message area **and** on the composer surface padding (Slack / Linear / ChatGPT style), `useHotkey('mod+/')` toggle.
55
55
  - **ChatGPT-style autoscroll.** `MessageList` follows the bottom while the user is within `atBottomThreshold` px (default 120). Every user-sent message bumps `scrollAnchorId` and re-anchors the viewport with `behavior: 'smooth'` — sending no longer leaves your own bubble stuck above the fold. Scrolling up by hand breaks the lock; `<JumpToLatest>` brings it back.
56
- - **Voice composer slot.** `<VoiceComposerSlot />` drops into `composerToolbarEnd` with **zero props** — reads/writes the composer through the `ComposerHandle` registered in chat context. The built-in `<Composer>` and TipTap-backed `MarkdownEditor` register themselves automatically; custom composers wire it via `useRegisterComposer({ focus, moveCursorToEnd, getValue, setValue })`. Auto-gates on Firefox / in-app WebViews / missing `getUserMedia`, preserves typed prefix, 90-second countdown, silence auto-stop, Esc / Enter hotkeys, start / stop earcons. See [`SpeechRecognition`](../SpeechRecognition/README.md).
56
+ - **Voice composer slot.** `<VoiceComposerSlot />` drops into `composer.slots.blockStart` with **zero props** — reads/writes the composer through the `ComposerHandle` registered in chat context. The built-in `<Composer>` and TipTap-backed `MarkdownEditor` register themselves automatically; custom composers wire it via `useRegisterComposer({ focus, moveCursorToEnd, getValue, setValue })`. Auto-gates on Firefox / in-app WebViews / missing `getUserMedia`, preserves typed prefix, 90-second countdown, silence auto-stop, Esc / Enter hotkeys, start / stop earcons. See [`SpeechRecognition`](../SpeechRecognition/README.md).
57
57
  - **Language flag button.** `headerSlots.languagePicker: true` slots a 28×28 country flag into the dock header — opens a searchable `<Combobox>` with 66 BCP-47 tags from the Chrome Web Speech catalogue. Selection persists via `useSpeechPrefs`, picked up by every `useSpeechRecognition` downstream. (Raw `<ChatHeaderLanguageButton>` still exported for custom shells.)
58
- - **Auto-focus on stream end.** `useAutoFocusOnStreamEnd()` (active inside `ChatRoot` by default) re-focuses the composer on the streaming → idle edge — type → send → read → keep typing without reaching for the mouse.
58
+ - **Auto-focus on stream end.** `<ChatProvider>` re-focuses the registered composer on the streaming → idle edge — type → send → read → keep typing without reaching for the mouse. Works for **every** usage pattern (`ChatRoot`, hand-rolled `ChatProvider` + `Composer`, headless), not just `ChatRoot`. Opt out with `<ChatProvider autoFocusOnStreamEnd={false}>`. The standalone `useAutoFocusOnStreamEnd()` hook is still exported for advanced cases (focus a non-composer target, drive `isStreaming` from your own store).
59
59
  - **Centralized colors.** Role-aware className tokens (`BUBBLE_SURFACE` / `ANCHOR` / `TOGGLE` / `DESTRUCTIVE_SURFACE`) + hooks (`useChatBubbleStyles`, `useChatRoleStyles`, `useChatDestructiveStyles`).
60
60
  - **Responsive.** FAB `size='responsive'` (default): phone → `sm`, tablet → `md`, desktop → `lg`. Side mode is desktop-only and falls back to popover below `lg`.
61
61
  - **Mobile fullscreen.** Dock auto-fills viewport below 768px via `useIsMobile`. Heights use `dvh/svh/lvh` so iOS Safari URL bar doesn't clip the chat.
@@ -68,7 +68,7 @@ Transport (interface) ← Pydantic-AI / HTTP+SSE / Wails / mock
68
68
 
69
69
  Reducer (pure state machine)
70
70
 
71
- Hooks (useChat / useChatComposer / useChatScroll / useChatHistory / useChatLayout)
71
+ Hooks (useChat / useChatComposer / useChatHistory / useChatLayout)
72
72
 
73
73
  ChatProvider (context)
74
74
 
@@ -79,18 +79,25 @@ ChatRoot (one-line preset) ◄── optionally wrapped by ──► ChatLau
79
79
 
80
80
  `ChatLauncher` mounts the `ChatProvider` itself — pass `transport` / `config` / `audio` / `initialSessionId` / `autoCreateSession` / `streaming` / `debug` to the launcher and use `<ChatRoot />` without props as the child. `ChatRoot` detects the ambient provider and reuses it; standalone `<ChatRoot transport={…}>` still works for non-launcher embeds. This is what makes declarative `headerSlots` (which render in the dock header) able to call `useChatContext()` and read `sessionId` / `clearMessages` / etc.
81
81
 
82
+ `ChatProvider` also owns chat-wide UX behaviour that must hold regardless of which preset wraps it — notably **stream-end composer re-focus** (`autoFocusOnStreamEnd`, default `true`). Putting it in the provider means a hand-rolled `ChatProvider` + `MessageList` + `Composer` layout behaves identically to `ChatRoot` with no extra wiring.
83
+
82
84
  Module boundaries:
83
85
 
84
86
  | Layer | May import | May NOT import |
85
87
  | ---------------- | -------------------------------- | ------------------------ |
86
88
  | `types/` | — | anything |
87
- | `core/transport` | `types/` | React, hooks, components |
89
+ | `constants.ts` | | anything |
90
+ | `core/transport` | `types/` | React, hooks, UI |
88
91
  | `core/reducer` | `types/` | React, transport |
89
- | `hooks` | `core/*`, `ui-core` hooks | components |
90
- | `context` | `hooks` | components |
91
- | `styles/` | `types/` | hooks, components |
92
- | `components` | `hooks`, `context`, `styles`, `ui-core` UI | transport implementations |
93
- | `launcher/` | `components`, `styles`, `ui-core` UI | transport implementations |
92
+ | `hooks` | `core/*`, `ui-core` hooks | UI folders |
93
+ | `context` | `hooks` | UI folders |
94
+ | `styles/` | `types/` | hooks, UI folders |
95
+ | `utils/` | `types/` | React, UI folders |
96
+ | `messages/` | `hooks`, `context`, `styles`, `ui-core` UI | transport implementations |
97
+ | `composer/` | `hooks`, `context`, `styles`, `messages`, `ui-core` UI | transport implementations |
98
+ | `shell/` | `messages`, `composer`, `hooks`, `context`, `ui-core` UI | transport implementations |
99
+ | `launcher/` | `shell`, `messages`, `composer`, `styles`, `ui-core` UI | transport implementations |
100
+ | `launcher/header/` | `context`, `hooks`, `launcher` siblings | transport implementations |
94
101
 
95
102
  ## Types
96
103
 
@@ -107,6 +114,7 @@ Single source of truth in [`types/`](./types/index.ts). Split by domain — impo
107
114
  | `events` | `ChatStreamEvent` SSE union |
108
115
  | `session` | `SessionInfo`, `HistoryPage`, `Stream/Send/CreateSessionOptions` |
109
116
  | `transport` | `ChatTransport` |
117
+ | `block` | `MessageBlock` union + `BlockAppearance` (see Message blocks) |
110
118
 
111
119
  ## Launcher (FAB + Dock + Greeting)
112
120
 
@@ -525,6 +533,58 @@ function MyError() {
525
533
  }
526
534
  ```
527
535
 
536
+ ## Message blocks
537
+
538
+ A message can carry typed, serializable rich content beyond its markdown
539
+ `content`: an optional `blocks: MessageBlock[]`. `MessageBlock` is a
540
+ discriminated union on `kind` — `text`, `markdown`, `audio`, `video`,
541
+ `image`, `gallery`, `map`, `json`, `mermaid`, `code`, `lottie`, plus a
542
+ `custom` escape hatch. Payloads are plain JSON, so blocks survive history
543
+ persistence and SSE transport.
544
+
545
+ `<MessageBubble>` renders blocks **after** the markdown bubble, before
546
+ `toolCalls`. `text`/`markdown` blocks keep the bubble surface; media
547
+ blocks render full-width below it. Legacy messages (no `blocks`) render
548
+ byte-for-byte unchanged.
549
+
550
+ ```ts
551
+ const msg: ChatMessage = {
552
+ id: 'm-42', role: 'assistant', createdAt: Date.now(), content: '',
553
+ blocks: [
554
+ { kind: 'markdown', id: 'b1', markdown: 'Recording from **vps-audi**:' },
555
+ { kind: 'audio', id: 'b2', src: 'https://cdn…/call.mp3', title: 'Call · 04:12' },
556
+ { kind: 'map', id: 'b3', caption: 'Server', center: { lat: 52.52, lng: 13.405 }, zoom: 11 },
557
+ ],
558
+ };
559
+ ```
560
+
561
+ ### The registry
562
+
563
+ Each `kind` maps to a `BlockRenderer` in a `BlockRegistry` — same idea as
564
+ `AttachmentRendererMap`, but keyed by the discriminant. Built-in renderers
565
+ cover the in-house tools (`BUILTIN_BLOCK_REGISTRY`); each is reached
566
+ through a `React.lazy` chunk, so a chat with no map block never downloads
567
+ MapLibre.
568
+
569
+ Merge host overrides with `createBlockRegistry`:
570
+
571
+ ```ts
572
+ const registry = createBlockRegistry({
573
+ json: (block) => <MyJsonCard data={block.data} />, // override one kind
574
+ });
575
+ ```
576
+
577
+ Pass it via `<ChatRoot messages={{ blockRegistry }}>` — it is threaded
578
+ through context to every `<MessageBubble>`. `<MessageBubble>` also accepts
579
+ a direct `blockRegistry` prop (prop beats context) for standalone /
580
+ Storybook use. An unknown `kind` is skipped silently (lenient default);
581
+ `<MessageBlocks strict>` surfaces a dev notice. Each block is wrapped in
582
+ an error boundary so one malformed block can't blank the transcript.
583
+
584
+ Exports (`@djangocfg/ui-tools/chat`): `MessageBlocks`,
585
+ `createBlockRegistry`, `BUILTIN_BLOCK_REGISTRY`, and the `MessageBlock` /
586
+ `BlockRegistry` / `BlockRenderer` / `BlockRenderContext` types.
587
+
528
588
  ## Transport contract
529
589
 
530
590
  A single I/O seam.
@@ -564,11 +624,161 @@ for await (const event of parseSSE(res, { map: createPydanticAISSEMap() })) {
564
624
  }
565
625
  ```
566
626
 
567
- ## Slots
627
+ ## `ChatRoot` props
628
+
629
+ `<ChatRootProps>` groups ~13 keys by concern — no flat `composer*` namespace:
630
+
631
+ ```tsx
632
+ <ChatRoot
633
+ // core wiring
634
+ transport={transport}
635
+ config={{ greeting: 'Hi!' }}
636
+ session={{ initialId, autoCreate: true }}
637
+ streaming
638
+ audio={{}}
639
+ debug
640
+
641
+ // presentation
642
+ appearance="compact" // 'compact' | 'full' — scales the whole chat
643
+ className="…"
644
+ listClassName="px-6 pt-6" // padding inside the scroll viewport
645
+
646
+ // composition (grouped)
647
+ slots={{
648
+ banner: <QuotaWarning />,
649
+ header: (ctx) => <MyHeader sessionId={ctx.sessionId} />, // node or fn
650
+ empty: ({ setValue, focus }) => <MyEmpty seed={setValue} />, // node or fn
651
+ jumpToLatest: <MyPill />,
652
+ }}
653
+ composer={{
654
+ size: 'lg', // 'sm' | 'md' | 'lg'
655
+ layout: 'stacked', // 'stacked' | 'inline'
656
+ className: '…',
657
+ hidden: false, // unmount the composer (human-in-the-loop pause)
658
+ showAttachmentButton: true,
659
+ onPickFiles: () => openPicker(),
660
+ slots: { actionsStart, actionsEnd, blockStart }, // ComposerSlots
661
+ footer: { showCounter: true } /* | false to hide */,
662
+ render: ({ composer, config }) => <MyComposer composer={composer} />,
663
+ }}
664
+ messages={{
665
+ render: (m, i) => <MyBubble message={m} />,
666
+ renderAfter: (m) => <SideChannelWidget messageId={m.id} />,
667
+ toolCallsProps: { defaultExpanded: true },
668
+ attachmentRenderers: { image: MyImageTile },
669
+ onAttachmentOpen: (a) => openLightbox(a),
670
+ }}
671
+
672
+ // behavior
673
+ focusOnEmptyClick // default true
674
+ />
675
+ ```
676
+
677
+ The `slots.header` / `slots.empty` accept either a `ReactNode` or a render
678
+ function — there is no separate `renderHeader` / `renderEmpty` prop and no
679
+ "which one wins" precedence. `composer.render` fully replaces the built-in
680
+ `<Composer>`; it receives `{ composer, config }` — the live composer hook
681
+ plus the same config object. See **[Slots inventory](#slots-inventory)** below.
682
+
683
+ ## Composer slot system
684
+
685
+ `<Composer>` is a single bordered input surface — textarea on top, an
686
+ action bar pinned to the bottom inside the same frame (attach
687
+ bottom-left, mic + send bottom-right). Two layouts:
688
+
689
+ - `layout="stacked"` (default) — Telegram-style two-tier surface.
690
+ - `layout="inline"` — compact single row. `size="sm"` defaults to this.
568
691
 
569
- `<ChatRoot>` exposes named-prop slots `header`, `footer`, `banner`, `empty`, `composerToolbarStart/End`, `composerAttachmentTray`, `jumpToLatest`. None are required.
692
+ ### Tier Adeclarative actions
570
693
 
571
- See **[Slots inventory](#slots-inventory)** below for the full list, plus `hideComposer` / `hideToolCalls` / `renderToolCall` / `renderAfterCalls` patterns.
694
+ Pass `ComposerAction[]` arrays; the composer renders consistent,
695
+ correctly-aligned, fully-labelled buttons. Built-in send/stop/attach are
696
+ themselves descriptors — host extras land between attach and mic/send.
697
+
698
+ ```tsx
699
+ <Composer
700
+ composer={composer}
701
+ composerSlots={{
702
+ actionsStart: [{ id: 'emoji', icon: <Smile />, label: 'Emoji', onClick }],
703
+ actionsEnd: [{ id: 'model', icon: <Sparkles />, label: 'Model', onClick }],
704
+ blockStart: <ReplyBanner />, // full-width row above the textarea
705
+ }}
706
+ />
707
+ ```
708
+
709
+ `ComposerAction` fields: `id`, `icon`, `label` (required — `aria-label` +
710
+ tooltip), `onClick`, `disabled?`, `pressed?` (→ `aria-pressed`),
711
+ `variant?`, `hideWhen?` (`streaming` | `empty` | `hasText` | `disabled`),
712
+ `order?`. Memoize the arrays so the action bar does not churn.
713
+
714
+ ### Tier B — slot replacement
715
+
716
+ Replace a primitive entirely via `slots` / tweak its props via
717
+ `slotProps`:
718
+
719
+ ```tsx
720
+ <Composer composer={composer}
721
+ slots={{ SendButton: MyBrandedSend, Textarea: MyEditor }}
722
+ slotProps={{ textarea: { className: 'font-mono' } }}
723
+ />
724
+ ```
725
+
726
+ Swappable: `SendButton`, `AttachButton`, `Textarea`, `ActionBar`.
727
+
728
+ ### mic ↔ send swap
729
+
730
+ `micSendSwap` (default `true`) — Telegram behaviour: an action with
731
+ `id: 'mic'` (or `hideWhen: 'hasText'`) shows only while the draft is
732
+ empty; once there is text, send takes its place. Set `false` to keep
733
+ both visible (voice-message hosts).
734
+
735
+ ### Footer toolbar
736
+
737
+ `<ComposerFooter>` is the quiet strip below the surface — three zones:
738
+ `start` (auto keyboard hint), `center` (host extras), `end` (auto char
739
+ counter that only appears near `maxLength`). Configure via the
740
+ `footer` prop on `<Composer>` or `composer.footer` on `<ChatRoot>`;
741
+ pass `false` to hide.
742
+
743
+ ### Composer kit — ready-made slot widgets
744
+
745
+ ChatGPT / Gemini-style controls that drop straight into `composerSlots`.
746
+ All are exported from `@djangocfg/ui-tools/chat` and size-aware (they
747
+ inherit the composer `size` via context, no prop needed).
748
+
749
+ | Component | Slot | What it is |
750
+ |---|---|---|
751
+ | `<ComposerMenuButton items={MenuItem[]}>` | `inlineStart` | The ChatGPT `+` button — opens a declarative `MenuBuilder` dropdown (sections, submenus, shortcuts). |
752
+ | `<ComposerToolPill icon label active onRemove>` | `inlineStart` | Gemini-style capsule for a selected tool/mode with an optional `×` to clear it. |
753
+ | `<ComposerModelPicker value options onChange>` | `inlineEnd` | "Flash-Lite ▾" pill — opens a radio-group model picker. |
754
+ | `<ComposerBanner variant title description actions onDismiss>` | `blockStart` | Standalone notice bubble above the composer (upsell / quota / info). |
755
+ | `<ComposerRichTextarea mentions>` | `slots.Textarea` (Tier B) | Ready-made TipTap chat editor — unstyled, no toolbar, size-matched height, Enter-to-send, `@`-mention support. |
756
+
757
+ ```tsx
758
+ <Composer
759
+ composer={composer}
760
+ composerSlots={{
761
+ blockStart: <ComposerBanner variant="upgrade" title="Free plan limit" … />,
762
+ inlineStart: <ComposerMenuButton items={MENU_ITEMS} />,
763
+ inlineEnd: <ComposerModelPicker value={model} options={MODELS} onChange={setModel} />,
764
+ }}
765
+ />
766
+ ```
767
+
768
+ ### `appearance` — compact vs full
769
+
770
+ `<Composer appearance="full">` layers extra spaciousness (radius,
771
+ padding, taller textarea, larger text) over the chosen `size` — for a
772
+ full-page ChatGPT/Gemini surface. `compact` (default) keeps the embedded
773
+ docked-chat geometry. Orthogonal to `size`; `<ChatRoot appearance="full">`
774
+ threads it to both the composer and the message bubbles.
775
+
776
+ ### Click-to-focus surface
777
+
778
+ The whole input panel reads as a text field — the padding around the
779
+ editor shows a text caret and a `mousedown` on the bare surface (not a
780
+ button) focuses the editor. Works for both the plain `<textarea>` and the
781
+ TipTap (`contenteditable`) backend.
572
782
 
573
783
  ## Three usage patterns
574
784
 
@@ -627,7 +837,7 @@ type HttpTransportConfig, type MockTransportOptions, type ParseSSEOptions,
627
837
  type PydanticAIChatTransportOpts, type PydanticAIEvent, type ToolIdQueue
628
838
 
629
839
  // Hooks
630
- useChat, useChatComposer, useChatScroll, useChatHistory, useChatLayout,
840
+ useChat, useChatComposer, useChatHistory, useChatLayout,
631
841
  useChatLightbox, useAutoFocusOnStreamEnd, useRegisterComposer,
632
842
  useChatReset, useVisitorFingerprint, useChatUnread, useChatUnreadNotifier,
633
843
  createBrowserNotifier, createCrossTabNotifier, createTitleRotator, createFaviconBadge,
@@ -682,22 +892,41 @@ JumpToLatest, StreamingIndicator
682
892
  // `MessageList` exposes `atBottomThreshold` (default 120 px) and
683
893
  // `scrollAnchorId` props for ChatGPT-style autoscroll — see "What you get".
684
894
 
895
+ // Composer kit — slot widgets + types
896
+ ComposerButton, ComposerActionBar, ComposerFooter,
897
+ ComposerMenuButton, ComposerToolPill, ComposerModelPicker,
898
+ ComposerBanner, ComposerRichTextarea, useComposerActions, useResolvedComposerSize
899
+ type ComposerProps, type ComposerSize, type ComposerAppearance,
900
+ type ComposerLayout, type ComposerAction, type ComposerActionVisibility,
901
+ type ComposerSlots, type ComposerSlotComponents, type ComposerSlotProps,
902
+ type ComposerFooterProps, type ComposerMenuButtonProps, type ComposerToolPillProps,
903
+ type ComposerModelPickerProps, type ComposerModelOption,
904
+ type ComposerBannerProps, type ComposerBannerAction, type ComposerRichTextareaProps,
905
+ type ComposerTextareaProps, type SendButtonProps, type AttachButtonProps
906
+
907
+ // Message blocks
908
+ MessageBlocks, createBlockRegistry, BUILTIN_BLOCK_REGISTRY
909
+ type MessageBlock, type BlockAppearance, type BlockRegistry,
910
+ type BlockRenderer, type BlockRenderContext
911
+
685
912
  // Lazy preset
686
913
  LazyChat
687
914
  ```
688
915
 
689
916
  ## Storybook
690
917
 
691
- Stories live next to components open `@djangocfg/playground`:
918
+ Stories are grouped into five feature sub-groups under `UI Tools/Chat`,
919
+ plus `Overview` (MDX) and `Showcase` (a one-screen living demo):
692
920
 
693
- - `Tools/Chat/Basic`Default + Composition patterns.
694
- - `Tools/Chat/Bubbles` every bubble state in one screen.
695
- - `Tools/Chat/ToolCalls`streaming panels + JsonTree payload dispatch.
696
- - `Tools/Chat/Personas` per-message persona overrides, multi-user transcripts.
697
- - `Tools/Chat/Launcher`Default / Playground / LiveChatStyle / MobileFullscreen / WithLivePush / VariantsAndSizes.
698
- - `Tools/Chat/Header` `ChatHeader` standalone, persistent dock prefs, side mode.
699
- - `Tools/Chat/Audio & Actions` audio toggle auto-inject, reset with `window.dialog.confirm`.
700
- - `Tools/Chat/Voice composer` — `<VoiceComposerSlot>` wired into the composer toolbar with a mock STT engine.
921
+ - **Getting Started** `ChatRoot`, `Composition` (bring-your-own-layout),
922
+ `Appearance` (compact / full / huge).
923
+ - **Messages**`Bubbles`, `Markdown`, `Message Blocks`,
924
+ `Tool Calls & Sources`, `Streaming`, `Personas`.
925
+ - **Composer**`Playground`, `Layout & Actions`, `Menu & Tools`,
926
+ `Banner`, `Mentions`, `Speech & Attachments`.
927
+ - **Launcher** `Playground`, `Parts`, `Header`,
928
+ `Unread & Notifications`.
929
+ - **Transports** — the three shipped transports with a stubbed `fetchImpl`.
701
930
 
702
931
  ---
703
932
 
@@ -705,37 +934,36 @@ Stories live next to components — open `@djangocfg/playground`:
705
934
 
706
935
  ## Slots inventory
707
936
 
708
- | Slot | Position | Render-prop variant |
937
+ | Key | Position | Type |
709
938
  |---|---|---|
710
- | `header` | Above messages | `renderHeader({ messages })` |
711
- | `footer` | Below composer | `renderFooter({ canSend })` |
712
- | `banner` | Top of message list | `renderBanner({ error, dismiss, retry })` |
713
- | `empty` | Empty state | `renderEmpty({ config, send })` |
714
- | `composerToolbarStart` / `composerToolbarEnd` | Composer toolbar | |
715
- | `composerAttachmentTray` | Above composer textarea | `renderAttachmentTray({ attachments })` |
716
- | `jumpToLatest` | Sticky overlay | `renderJumpToLatest({ unread, scrollToBottom })` |
717
- | `renderToolCall` | Per tool-call panel | `(call) => ReactNode` |
718
- | `renderAfterCalls` | After all tool panels | `(calls) => ReactNode` — **only renders when the message has tool calls** |
719
- | `renderAfterMessage` | Below every assistant bubble | `(message) => ReactNode` — fires for every message, independent of `toolCalls` |
939
+ | `slots.banner` | Top of message list | `ReactNode` |
940
+ | `slots.header` | Above messages | `ReactNode \| (ctx) => ReactNode` |
941
+ | `slots.empty` | Empty state | `ReactNode \| ({ setValue, focus }) => ReactNode` |
942
+ | `slots.jumpToLatest` | Sticky overlay | `ReactNode` |
943
+ | `composer.slots.actionsStart` / `actionsEnd` | Composer action clusters | `ComposerAction[]` |
944
+ | `composer.slots.blockStart` | Above composer textarea | `ReactNode` |
945
+ | `composer.footer` | Below composer | `ComposerFooterProps \| false` |
946
+ | `composer.render` | Replace `<Composer>` | `({ composer, config }) => ReactNode` |
947
+ | `messages.render` | Replace each bubble | `(m, i) => ReactNode` |
948
+ | `messages.renderAfter` | Below every assistant bubble | `(m) => ReactNode` — fires for every message, independent of `toolCalls` |
720
949
 
721
950
  Flags:
722
951
 
723
- - `hideComposer` — agent-pause / human-in-the-loop pause; composer is unmounted.
724
- - `hideToolCalls` — show only `renderAfterCalls` rich UI without raw tool panels.
952
+ - `composer.hidden` — agent-pause / human-in-the-loop pause; composer is unmounted.
725
953
 
726
- ### Which slot for product widgets — `renderAfterCalls` vs `renderAfterMessage`?
954
+ ### Which slot for product widgets — `renderAfterCalls` vs `messages.renderAfter`?
727
955
 
728
956
  Both put custom content under the assistant bubble; the difference is **what triggers them**.
729
957
 
730
958
  - `renderAfterCalls` is gated on `message.toolCalls?.length > 0`. Use it when the widget is **derived from raw tool output** (read `call.output`) and you can rely on the host streaming the `tool_call` / `tool_result` SSE frames. Admin / dev flows typically work this way.
731
- - `renderAfterMessage` fires **for every message**, regardless of `toolCalls`. Use it when the widget is driven by a side channel — e.g. typed `ui_payload` SSE frames the host emits independently of the raw tool surface. This is the correct slot when the public-prod stream **hides** `tool_call` events for security: the message lands with `toolCalls === undefined`, so `renderAfterCalls` would never mount, but `renderAfterMessage` still runs and the widget renders from the side channel.
959
+ - `messages.renderAfter` fires **for every message**, regardless of `toolCalls`. Use it when the widget is driven by a side channel — e.g. typed `ui_payload` SSE frames the host emits independently of the raw tool surface. This is the correct slot when the public-prod stream **hides** `tool_call` events for security: the message lands with `toolCalls === undefined`, so `renderAfterCalls` would never mount, but `messages.renderAfter` still runs and the widget renders from the side channel.
732
960
 
733
961
  Recommended pairing for a "vehicle cards" / "tax breakdown" / "chart" widget on a public chat:
734
962
 
735
963
  ```tsx
736
964
  <ChatRoot
737
965
  transport={transport}
738
- renderAfterMessage={(m) => <VehicleCardsForMessage messageId={m.id} />}
966
+ messages={{ renderAfter: (m) => <VehicleCardsForMessage messageId={m.id} /> }}
739
967
  />
740
968
  ```
741
969