@djangocfg/ui-tools 2.1.407 → 2.1.409

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 (297) hide show
  1. package/README.md +9 -10
  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 +8 -13
  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/parts/Meta/TimeDisplay.tsx +2 -5
  67. package/src/tools/Chat/README.md +277 -39
  68. package/src/tools/Chat/composer/Composer.tsx +471 -0
  69. package/src/tools/Chat/composer/ComposerActionBar.tsx +65 -0
  70. package/src/tools/Chat/composer/ComposerBanner.tsx +128 -0
  71. package/src/tools/Chat/composer/ComposerButton.tsx +64 -0
  72. package/src/tools/Chat/composer/ComposerFooter.tsx +90 -0
  73. package/src/tools/Chat/composer/ComposerMenuButton.tsx +62 -0
  74. package/src/tools/Chat/composer/ComposerModelPicker.tsx +104 -0
  75. package/src/tools/Chat/composer/ComposerRichTextarea.tsx +88 -0
  76. package/src/tools/Chat/composer/ComposerToolPill.tsx +95 -0
  77. package/src/tools/Chat/composer/index.ts +45 -0
  78. package/src/tools/Chat/composer/size-context.tsx +26 -0
  79. package/src/tools/Chat/composer/types.ts +143 -0
  80. package/src/tools/Chat/composer/useComposerActions.tsx +164 -0
  81. package/src/tools/Chat/context/ChatProvider.tsx +54 -3
  82. package/src/tools/Chat/core/__tests__/metadata.test.ts +69 -0
  83. package/src/tools/Chat/core/index.ts +23 -1
  84. package/src/tools/Chat/core/markdown.ts +1 -1
  85. package/src/tools/Chat/core/metadata.ts +47 -0
  86. package/src/tools/Chat/core/payload-dispatch.ts +1 -1
  87. package/src/tools/Chat/core/transport/http.ts +71 -32
  88. package/src/tools/Chat/core/transport/sse.ts +18 -10
  89. package/src/tools/Chat/highlight/HighlightOverlay.tsx +101 -0
  90. package/src/tools/Chat/highlight/README.md +103 -0
  91. package/src/tools/Chat/highlight/SpotlightCanvas.tsx +153 -0
  92. package/src/tools/Chat/highlight/__tests__/HighlightOverlay.test.tsx +112 -0
  93. package/src/tools/Chat/highlight/__tests__/resolveRef.test.ts +55 -0
  94. package/src/tools/Chat/highlight/index.ts +21 -0
  95. package/src/tools/Chat/highlight/resolveRef.ts +42 -0
  96. package/src/tools/Chat/highlight/types.ts +49 -0
  97. package/src/tools/Chat/highlight/useHighlightTargets.ts +128 -0
  98. package/src/tools/Chat/hooks/index.ts +0 -5
  99. package/src/tools/Chat/hooks/useAutoFocusOnStreamEnd.ts +28 -47
  100. package/src/tools/Chat/hooks/useChat.ts +47 -14
  101. package/src/tools/Chat/hooks/useChatComposer.ts +2 -2
  102. package/src/tools/Chat/hooks/useChatLayout.ts +1 -1
  103. package/src/tools/Chat/hooks/useStreamEndFocus.ts +54 -0
  104. package/src/tools/Chat/index.ts +25 -219
  105. package/src/tools/Chat/launcher/ChatDock.tsx +1 -1
  106. package/src/tools/Chat/launcher/ChatLauncher.tsx +1 -1
  107. package/src/tools/Chat/launcher/{ChatHeader.tsx → header/ChatHeader.tsx} +24 -11
  108. package/src/tools/Chat/launcher/{ChatHeaderActionButton.tsx → header/ChatHeaderActionButton.tsx} +34 -3
  109. package/src/tools/Chat/launcher/{ChatHeaderLanguageButton.tsx → header/ChatHeaderLanguageButton.tsx} +2 -2
  110. package/src/tools/Chat/launcher/{ChatHeaderModeToggle.tsx → header/ChatHeaderModeToggle.tsx} +1 -1
  111. package/src/tools/Chat/launcher/{ChatHeaderResetButton.tsx → header/ChatHeaderResetButton.tsx} +2 -1
  112. package/src/tools/Chat/launcher/{HeaderSlots.tsx → header/HeaderSlots.tsx} +3 -3
  113. package/src/tools/Chat/launcher/header/index.ts +26 -0
  114. package/src/tools/Chat/launcher/index.ts +3 -10
  115. package/src/tools/Chat/lazy.tsx +38 -284
  116. package/src/tools/Chat/{components → messages}/MessageBubble.tsx +58 -5
  117. package/src/tools/Chat/{components → messages}/MessageList.tsx +8 -25
  118. package/src/tools/Chat/messages/blocks/MessageBlocks.tsx +131 -0
  119. package/src/tools/Chat/messages/blocks/builtin.tsx +91 -0
  120. package/src/tools/Chat/messages/blocks/index.ts +12 -0
  121. package/src/tools/Chat/messages/blocks/registry.tsx +42 -0
  122. package/src/tools/Chat/messages/blocks/renderers/AudioBlock.tsx +20 -0
  123. package/src/tools/Chat/messages/blocks/renderers/CodeBlock.tsx +19 -0
  124. package/src/tools/Chat/messages/blocks/renderers/GalleryBlock.tsx +26 -0
  125. package/src/tools/Chat/messages/blocks/renderers/ImageBlock.tsx +27 -0
  126. package/src/tools/Chat/messages/blocks/renderers/JsonBlock.tsx +12 -0
  127. package/src/tools/Chat/messages/blocks/renderers/LottieBlock.tsx +11 -0
  128. package/src/tools/Chat/messages/blocks/renderers/MapBlock.tsx +36 -0
  129. package/src/tools/Chat/messages/blocks/renderers/MermaidBlock.tsx +11 -0
  130. package/src/tools/Chat/messages/blocks/renderers/VideoBlock.tsx +24 -0
  131. package/src/tools/Chat/messages/blocks/renderers/types.ts +8 -0
  132. package/src/tools/Chat/{components → messages}/index.ts +11 -5
  133. package/src/tools/Chat/public.ts +212 -0
  134. package/src/tools/Chat/shell/ChatRoot.tsx +345 -0
  135. package/src/tools/Chat/{components → shell}/EmptyState.tsx +4 -2
  136. package/src/tools/Chat/shell/index.ts +15 -0
  137. package/src/tools/Chat/types/block.ts +120 -0
  138. package/src/tools/Chat/types/config.ts +0 -5
  139. package/src/tools/Chat/types/index.ts +17 -0
  140. package/src/tools/Chat/types/message.ts +3 -0
  141. package/src/tools/Chat/utils/index.ts +4 -0
  142. package/src/tools/CodeEditor/README.md +4 -6
  143. package/src/tools/CodeEditor/components/DiffEditor.tsx +48 -13
  144. package/src/tools/CodeEditor/components/Editor.tsx +96 -44
  145. package/src/tools/CodeEditor/context/EditorProvider.tsx +34 -17
  146. package/src/tools/CodeEditor/hooks/useEditorTheme.ts +92 -99
  147. package/src/tools/CodeEditor/hooks/useMonaco.ts +37 -22
  148. package/src/tools/CodeEditor/lazy.tsx +6 -0
  149. package/src/tools/CodeEditor/lib/index.ts +1 -1
  150. package/src/tools/CodeEditor/lib/themes.ts +3 -39
  151. package/src/tools/CronScheduler/CronScheduler.client.tsx +230 -61
  152. package/src/tools/CronScheduler/components/CustomInput.tsx +21 -4
  153. package/src/tools/CronScheduler/components/DayChips.tsx +13 -11
  154. package/src/tools/CronScheduler/components/MonthDayGrid.tsx +4 -4
  155. package/src/tools/CronScheduler/components/SchedulePreview.tsx +7 -3
  156. package/src/tools/CronScheduler/components/TimeSelector.tsx +1 -1
  157. package/src/tools/CronScheduler/index.tsx +1 -1
  158. package/src/tools/CronScheduler/types/index.ts +8 -3
  159. package/src/tools/CronScheduler/utils/cron-humanize.ts +61 -16
  160. package/src/tools/CronScheduler/utils/cron-parser.ts +13 -4
  161. package/src/tools/FileIcon/FileIcon.tsx +24 -39
  162. package/src/tools/FileIcon/get-file-icon.ts +73 -0
  163. package/src/tools/FileIcon/icons/icon-data.ts +399 -0
  164. package/src/tools/FileIcon/index.ts +4 -0
  165. package/src/tools/FileIcon/loader.ts +17 -35
  166. package/src/tools/FileIcon/specialFolders.ts +18 -0
  167. package/src/tools/Gallery/components/lightbox/GalleryLightbox.tsx +112 -35
  168. package/src/tools/Gallery/components/media/GalleryVideo.tsx +21 -2
  169. package/src/tools/Gallery/components/preview/GalleryCarousel.tsx +11 -1
  170. package/src/tools/Gallery/hooks/usePreloadImages.ts +54 -7
  171. package/src/tools/ImageViewer/components/ImageInfo.tsx +12 -1
  172. package/src/tools/ImageViewer/components/ImageToolbar.tsx +51 -43
  173. package/src/tools/ImageViewer/components/ImageViewer.tsx +96 -24
  174. package/src/tools/ImageViewer/hooks/useImageLoading.ts +13 -0
  175. package/src/tools/ImageViewer/utils/constants.ts +3 -0
  176. package/src/tools/ImageViewer/utils/index.ts +1 -0
  177. package/src/tools/JsonForm/JsonSchemaForm.tsx +4 -1
  178. package/src/tools/JsonForm/templates/ArrayFieldTemplate.tsx +5 -3
  179. package/src/tools/JsonForm/templates/BaseInputTemplate.tsx +7 -4
  180. package/src/tools/JsonForm/templates/ErrorListTemplate.tsx +3 -1
  181. package/src/tools/JsonForm/templates/ObjectFieldTemplate.tsx +23 -3
  182. package/src/tools/JsonForm/widgets/ColorWidget.tsx +20 -12
  183. package/src/tools/JsonForm/widgets/NumberWidget.tsx +14 -9
  184. package/src/tools/JsonForm/widgets/RadioWidget.tsx +78 -0
  185. package/src/tools/JsonForm/widgets/SelectWidget.tsx +1 -0
  186. package/src/tools/JsonForm/widgets/SliderWidget.tsx +7 -4
  187. package/src/tools/JsonForm/widgets/TextWidget.tsx +41 -17
  188. package/src/tools/JsonForm/widgets/index.ts +1 -0
  189. package/src/tools/JsonTree/components/JsonContent.tsx +115 -40
  190. package/src/tools/LottiePlayer/LottiePlayer.client.tsx +177 -72
  191. package/src/tools/LottiePlayer/index.tsx +14 -4
  192. package/src/tools/LottiePlayer/lazy.tsx +11 -3
  193. package/src/tools/LottiePlayer/types.ts +31 -1
  194. package/src/tools/LottiePlayer/useLottie.ts +32 -9
  195. package/src/tools/LottiePlayer/usePrefersReducedMotion.ts +46 -0
  196. package/src/tools/Map/components/LayerSwitcher.tsx +54 -21
  197. package/src/tools/Map/components/MapCluster.tsx +28 -21
  198. package/src/tools/Map/components/MapContainer.tsx +11 -4
  199. package/src/tools/Map/components/MapLegend.tsx +46 -15
  200. package/src/tools/Map/components/MapMarker.tsx +31 -2
  201. package/src/tools/Map/hooks/useMapEvents.ts +64 -105
  202. package/src/tools/MarkdownEditor/MarkdownEditor.tsx +61 -6
  203. package/src/tools/MarkdownEditor/MentionList.tsx +37 -4
  204. package/src/tools/MarkdownEditor/createMentionSuggestion.ts +11 -0
  205. package/src/tools/MarkdownEditor/lazy.tsx +32 -7
  206. package/src/tools/MarkdownEditor/styles.css +13 -0
  207. package/src/tools/MarkdownMessage/CodeBlock.tsx +40 -17
  208. package/src/tools/MarkdownMessage/MarkdownMessage.tsx +26 -6
  209. package/src/tools/MarkdownMessage/components.tsx +22 -9
  210. package/src/tools/MarkdownMessage/types.ts +24 -1
  211. package/src/tools/Mermaid/Mermaid.client.tsx +27 -5
  212. package/src/tools/Mermaid/components/MermaidErrorPanel.tsx +31 -0
  213. package/src/tools/Mermaid/components/MermaidFullscreenModal.tsx +14 -17
  214. package/src/tools/Mermaid/hooks/useMermaidRenderer.ts +264 -168
  215. package/src/tools/Mermaid/hooks/useMermaidValidation.ts +76 -10
  216. package/src/tools/Mermaid/index.tsx +6 -0
  217. package/src/tools/Mermaid/utils/mermaid-helpers.ts +141 -18
  218. package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/SchemaFields/FieldRow.tsx +11 -1
  219. package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/SchemaFields/buildTree.ts +49 -20
  220. package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/index.tsx +7 -0
  221. package/src/tools/OpenapiViewer/components/DocsLayout/grouping.ts +7 -4
  222. package/src/tools/OpenapiViewer/constants.ts +3 -0
  223. package/src/tools/OpenapiViewer/hooks/useOpenApiSchema.ts +73 -11
  224. package/src/tools/OpenapiViewer/utils/schemaExport.ts +26 -6
  225. package/src/tools/PrettyCode/PrettyCode.client.tsx +23 -16
  226. package/src/tools/PrettyCode/lazy.tsx +1 -1
  227. package/src/tools/SpeechRecognition/README.md +1 -1
  228. package/src/tools/SpeechRecognition/__tests__/language.test.ts +9 -3
  229. package/src/tools/SpeechRecognition/components/RecordingPulse.tsx +59 -0
  230. package/src/tools/SpeechRecognition/components/index.ts +2 -0
  231. package/src/tools/SpeechRecognition/core/engine/external.ts +24 -7
  232. package/src/tools/SpeechRecognition/core/language.ts +23 -6
  233. package/src/tools/SpeechRecognition/hooks/usePushToTalk.ts +36 -5
  234. package/src/tools/SpeechRecognition/hooks/useSpeechRecognition.ts +18 -11
  235. package/src/tools/SpeechRecognition/widgets/VoiceComposerSlot.tsx +94 -26
  236. package/src/tools/SpeechRecognition/widgets/index.ts +1 -1
  237. package/src/tools/Tree/README.md +4 -8
  238. package/src/tools/Tree/TreeRoot.tsx +22 -10
  239. package/src/tools/Tree/components/TreeContent.tsx +24 -4
  240. package/src/tools/Tree/components/TreeLabel.tsx +8 -2
  241. package/src/tools/Tree/components/TreeRow.tsx +16 -6
  242. package/src/tools/Tree/data/flatten.ts +10 -4
  243. package/src/tools/Tree/types.ts +4 -0
  244. package/src/tools/Uploader/components/UploadAddButton.tsx +29 -6
  245. package/src/tools/Uploader/components/UploadDropzone.tsx +63 -7
  246. package/src/tools/Uploader/components/UploadPageDropOverlay.tsx +19 -5
  247. package/src/tools/Uploader/components/UploadPreviewItem.tsx +47 -17
  248. package/src/tools/Uploader/components/UploadPreviewList.tsx +24 -12
  249. package/src/tools/Uploader/utils/formatters.ts +8 -3
  250. package/src/tools/VideoPlayer/canvas/hls-canvas.tsx +1 -0
  251. package/src/tools/VideoPlayer/canvas/{jsx.d.ts → jsx-augmentation.ts} +12 -19
  252. package/src/tools/VideoPlayer/canvas/vimeo-canvas.tsx +1 -0
  253. package/src/tools/VideoPlayer/canvas/youtube-canvas.tsx +1 -0
  254. package/src/tools/VideoPlayer/parts/fullscreen.tsx +1 -1
  255. package/src/tools/VideoPlayer/parts/pip.tsx +1 -1
  256. package/src/tools/VideoPlayer/parts/playback-rate.tsx +1 -1
  257. package/src/tools/VideoPlayer/parts/seek-bar.tsx +2 -2
  258. package/src/tools/VideoPlayer/parts/volume.tsx +2 -2
  259. package/src/tools/index.ts +2 -1
  260. package/src/tools/Chat/components/AudioToggle.tsx +0 -78
  261. package/src/tools/Chat/components/ChatRoot.tsx +0 -305
  262. package/src/tools/Chat/components/Composer.tsx +0 -216
  263. package/src/tools/Chat/hooks/useChatScroll.ts +0 -145
  264. package/src/tools/Chat/types.ts +0 -9
  265. package/src/tools/JsonTree/components/JsonToolbar.tsx +0 -95
  266. package/src/tools/JsonTree/hooks/useElementCorner.ts +0 -84
  267. package/src/tools/JsonTree/hooks/useNavbarHeight.ts +0 -83
  268. package/src/tools/OpenapiViewer/components/DocsLayout/schemaFields.ts +0 -121
  269. package/src/tools/Tour/README.md +0 -373
  270. package/src/tools/Tour/components/Tour.tsx +0 -12
  271. package/src/tools/Tour/components/TourContent.tsx +0 -171
  272. package/src/tools/Tour/components/TourNavigation.tsx +0 -77
  273. package/src/tools/Tour/components/TourProgress.tsx +0 -88
  274. package/src/tools/Tour/components/TourSpotlight.tsx +0 -199
  275. package/src/tools/Tour/components/index.ts +0 -5
  276. package/src/tools/Tour/context/TourContext.ts +0 -19
  277. package/src/tools/Tour/context/TourProvider.tsx +0 -292
  278. package/src/tools/Tour/context/index.ts +0 -2
  279. package/src/tools/Tour/hooks/index.ts +0 -3
  280. package/src/tools/Tour/hooks/useKeyboardNavigation.ts +0 -59
  281. package/src/tools/Tour/hooks/useStepTarget.ts +0 -121
  282. package/src/tools/Tour/hooks/useTour.ts +0 -42
  283. package/src/tools/Tour/index.ts +0 -38
  284. package/src/tools/Tour/types/index.ts +0 -224
  285. package/src/tools/Tour/utils/dom.ts +0 -98
  286. package/src/tools/Tour/utils/index.ts +0 -3
  287. package/src/tools/Tour/utils/logger.ts +0 -3
  288. package/src/tools/Tour/utils/scrollIntoView.ts +0 -24
  289. /package/src/tools/Chat/{config.ts → constants.ts} +0 -0
  290. /package/src/tools/Chat/launcher/{ChatHeaderAudioToggle.tsx → header/ChatHeaderAudioToggle.tsx} +0 -0
  291. /package/src/tools/Chat/{components → messages}/Attachments.tsx +0 -0
  292. /package/src/tools/Chat/{components → messages}/JumpToLatest.tsx +0 -0
  293. /package/src/tools/Chat/{components → messages}/MessageActions.tsx +0 -0
  294. /package/src/tools/Chat/{components → messages}/Sources.tsx +0 -0
  295. /package/src/tools/Chat/{components → messages}/StreamingIndicator.tsx +0 -0
  296. /package/src/tools/Chat/{components → messages}/ToolCalls.tsx +0 -0
  297. /package/src/tools/Chat/{components → shell}/ErrorBanner.tsx +0 -0
@@ -0,0 +1,131 @@
1
+ 'use client';
2
+
3
+ /**
4
+ * `<MessageBlocks>` — walks `message.blocks`, dispatches each through the
5
+ * registry, and renders it under the bubble (text/markdown in a bubble
6
+ * wrapper, media full-width). Per-block error isolation + unknown-kind
7
+ * fallback keep one bad block from blanking the transcript.
8
+ */
9
+
10
+ import { Component, type ReactNode } from 'react';
11
+
12
+ import { cn } from '@djangocfg/ui-core/lib';
13
+
14
+ import type { MessageBlock } from '../../types/block';
15
+ import { useChatBubbleStyles } from '../../styles';
16
+ import { BUILTIN_BLOCK_REGISTRY, type BlockRegistry } from './registry';
17
+
18
+ export interface MessageBlocksProps {
19
+ blocks?: MessageBlock[];
20
+ /** Registry of `kind` → renderer. Defaults to `BUILTIN_BLOCK_REGISTRY`. */
21
+ registry?: BlockRegistry;
22
+ /** Spaciousness forwarded to renderers. */
23
+ appearance?: 'compact' | 'full';
24
+ isUser?: boolean;
25
+ /**
26
+ * When true, an unknown `kind` renders a visible dev notice. When
27
+ * false (default) it is skipped silently — production-lenient.
28
+ */
29
+ strict?: boolean;
30
+ }
31
+
32
+ /** Block kinds rendered inside a chat-bubble surface, not full-width. */
33
+ const PROSE_KINDS = new Set<MessageBlock['kind']>(['text', 'markdown']);
34
+
35
+ interface BoundaryProps {
36
+ kind: string;
37
+ children: ReactNode;
38
+ }
39
+ interface BoundaryState {
40
+ failed: boolean;
41
+ }
42
+
43
+ /** Minimal per-block error boundary. */
44
+ class BlockErrorBoundary extends Component<BoundaryProps, BoundaryState> {
45
+ state: BoundaryState = { failed: false };
46
+
47
+ static getDerivedStateFromError(): BoundaryState {
48
+ return { failed: true };
49
+ }
50
+
51
+ render() {
52
+ if (this.state.failed) {
53
+ return (
54
+ <div className="rounded-lg border border-destructive/30 bg-destructive/5 px-3 py-2 text-xs text-muted-foreground">
55
+ Failed to render a {this.props.kind} block.
56
+ </div>
57
+ );
58
+ }
59
+ return this.props.children;
60
+ }
61
+ }
62
+
63
+ function UnknownBlock({ kind }: { kind: string }) {
64
+ return (
65
+ <div className="rounded-lg border border-dashed border-border px-3 py-2 text-xs text-muted-foreground">
66
+ Unknown block kind: <code className="font-mono">{kind}</code>
67
+ </div>
68
+ );
69
+ }
70
+
71
+ export function MessageBlocks({
72
+ blocks,
73
+ registry = BUILTIN_BLOCK_REGISTRY,
74
+ appearance = 'compact',
75
+ isUser = false,
76
+ strict = false,
77
+ }: MessageBlocksProps) {
78
+ const { surface: bubbleSurface } = useChatBubbleStyles(
79
+ isUser ? 'user' : 'assistant',
80
+ false,
81
+ );
82
+
83
+ if (!blocks?.length) return null;
84
+
85
+ return (
86
+ <div
87
+ className={cn('mt-1.5 flex w-full flex-col gap-2', isUser && 'items-end')}
88
+ >
89
+ {blocks.map((block) => {
90
+ const renderer = registry[block.kind] as
91
+ | ((b: MessageBlock, c: { appearance: 'compact' | 'full'; isUser: boolean }) => ReactNode)
92
+ | undefined;
93
+
94
+ let body: ReactNode;
95
+ if (renderer) {
96
+ body = renderer(block, { appearance, isUser });
97
+ } else if (strict) {
98
+ body = <UnknownBlock kind={block.kind} />;
99
+ } else {
100
+ return null;
101
+ }
102
+
103
+ const isProse = PROSE_KINDS.has(block.kind);
104
+
105
+ return (
106
+ <div key={block.id} data-block-kind={block.kind} className="w-full">
107
+ {block.caption ? (
108
+ <div className="mb-1 text-xs font-medium text-muted-foreground">
109
+ {block.caption}
110
+ </div>
111
+ ) : null}
112
+ <BlockErrorBoundary kind={block.kind}>
113
+ {isProse ? (
114
+ <div
115
+ className={cn(
116
+ 'inline-block max-w-full rounded-2xl px-3.5 py-2 text-sm',
117
+ bubbleSurface,
118
+ )}
119
+ >
120
+ {body}
121
+ </div>
122
+ ) : (
123
+ body
124
+ )}
125
+ </BlockErrorBoundary>
126
+ </div>
127
+ );
128
+ })}
129
+ </div>
130
+ );
131
+ }
@@ -0,0 +1,91 @@
1
+ 'use client';
2
+
3
+ /**
4
+ * Built-in block registry.
5
+ *
6
+ * Each media renderer is reached through a `React.lazy` indirection, so a
7
+ * chat that never shows (say) a map block never downloads MapLibre. This
8
+ * module must NOT statically import any tool — only `React.lazy(() =>
9
+ * import('./renderers/…'))` thunks. The `text`/`markdown` kinds are the
10
+ * sole exception: `MarkdownMessage` is already a Chat dependency.
11
+ */
12
+
13
+ import { lazy, Suspense, type ComponentType } from 'react';
14
+
15
+ import { MarkdownMessage } from '../../../MarkdownMessage';
16
+ import type {
17
+ AudioBlock,
18
+ CodeBlock,
19
+ GalleryBlock,
20
+ ImageBlock,
21
+ JsonBlock,
22
+ LottieBlock,
23
+ MapBlock,
24
+ MarkdownBlock,
25
+ MermaidBlock,
26
+ MessageBlock,
27
+ TextBlock,
28
+ VideoBlock,
29
+ } from '../../types/block';
30
+ import type { BlockRegistry } from './registry';
31
+ import type { BlockRendererProps } from './renderers/types';
32
+
33
+ /** Minimal inline placeholder while a renderer chunk streams in. */
34
+ function BlockFallback() {
35
+ return (
36
+ <div
37
+ role="status"
38
+ aria-live="polite"
39
+ className="h-16 w-full animate-pulse rounded-xl bg-muted/60"
40
+ />
41
+ );
42
+ }
43
+
44
+ /** Wrap a lazily-loaded renderer in a Suspense boundary. */
45
+ function lazyBlock<B extends MessageBlock>(
46
+ loader: () => Promise<{ default: ComponentType<BlockRendererProps<B>> }>,
47
+ ) {
48
+ const Lazy = lazy(loader);
49
+ return function LazyBlockRenderer(props: BlockRendererProps<B>) {
50
+ return (
51
+ <Suspense fallback={<BlockFallback />}>
52
+ <Lazy {...props} />
53
+ </Suspense>
54
+ );
55
+ };
56
+ }
57
+
58
+ const AudioBlockRenderer = lazyBlock<AudioBlock>(() => import('./renderers/AudioBlock'));
59
+ const VideoBlockRenderer = lazyBlock<VideoBlock>(() => import('./renderers/VideoBlock'));
60
+ const ImageBlockRenderer = lazyBlock<ImageBlock>(() => import('./renderers/ImageBlock'));
61
+ const GalleryBlockRenderer = lazyBlock<GalleryBlock>(() => import('./renderers/GalleryBlock'));
62
+ const MapBlockRenderer = lazyBlock<MapBlock>(() => import('./renderers/MapBlock'));
63
+ const JsonBlockRenderer = lazyBlock<JsonBlock>(() => import('./renderers/JsonBlock'));
64
+ const MermaidBlockRenderer = lazyBlock<MermaidBlock>(() => import('./renderers/MermaidBlock'));
65
+ const CodeBlockRenderer = lazyBlock<CodeBlock>(() => import('./renderers/CodeBlock'));
66
+ const LottieBlockRenderer = lazyBlock<LottieBlock>(() => import('./renderers/LottieBlock'));
67
+
68
+ /** Render a `text` / `markdown` block as bubble-styled prose. */
69
+ function renderProse(content: string, isUser: boolean) {
70
+ return <MarkdownMessage content={content} isUser={isUser} size="sm" />;
71
+ }
72
+
73
+ /**
74
+ * The default registry. Host registries are merged over this via
75
+ * `createBlockRegistry(overrides)`.
76
+ */
77
+ export const BUILTIN_BLOCK_REGISTRY: BlockRegistry = {
78
+ text: (block: TextBlock, ctx) => renderProse(block.text, ctx.isUser),
79
+ markdown: (block: MarkdownBlock, ctx) => renderProse(block.markdown, ctx.isUser),
80
+ audio: (block, ctx) => <AudioBlockRenderer block={block} ctx={ctx} />,
81
+ video: (block, ctx) => <VideoBlockRenderer block={block} ctx={ctx} />,
82
+ image: (block, ctx) => <ImageBlockRenderer block={block} ctx={ctx} />,
83
+ gallery: (block, ctx) => <GalleryBlockRenderer block={block} ctx={ctx} />,
84
+ map: (block, ctx) => <MapBlockRenderer block={block} ctx={ctx} />,
85
+ json: (block, ctx) => <JsonBlockRenderer block={block} ctx={ctx} />,
86
+ mermaid: (block, ctx) => <MermaidBlockRenderer block={block} ctx={ctx} />,
87
+ code: (block, ctx) => <CodeBlockRenderer block={block} ctx={ctx} />,
88
+ lottie: (block, ctx) => <LottieBlockRenderer block={block} ctx={ctx} />,
89
+ // `custom` has no built-in renderer — it falls through to the
90
+ // unknown-kind fallback unless the host registers one.
91
+ };
@@ -0,0 +1,12 @@
1
+ 'use client';
2
+
3
+ /** Message blocks — typed rich-content slots rendered under a bubble. */
4
+
5
+ export { MessageBlocks, type MessageBlocksProps } from './MessageBlocks';
6
+ export {
7
+ createBlockRegistry,
8
+ BUILTIN_BLOCK_REGISTRY,
9
+ type BlockRegistry,
10
+ type BlockRenderer,
11
+ type BlockRenderContext,
12
+ } from './registry';
@@ -0,0 +1,42 @@
1
+ 'use client';
2
+
3
+ /**
4
+ * Block registry — maps a `MessageBlock['kind']` to a renderer.
5
+ *
6
+ * Mirrors `AttachmentRendererMap`, but keyed by a discriminant instead of
7
+ * a predicate: cheaper, exhaustively typed, host-extensible. The built-in
8
+ * registry (`BUILTIN_BLOCK_REGISTRY`) lives in `./builtin` so this module
9
+ * stays free of any tool import.
10
+ */
11
+
12
+ import type { ReactNode } from 'react';
13
+
14
+ import type { MessageBlock, MessageBlockKind, BlockAppearance } from '../../types/block';
15
+ import { BUILTIN_BLOCK_REGISTRY } from './builtin';
16
+
17
+ /** Context passed to every renderer alongside the block. */
18
+ export interface BlockRenderContext {
19
+ appearance: BlockAppearance;
20
+ isUser: boolean;
21
+ }
22
+
23
+ /** A renderer for one `kind`. The union is narrowed by the registry key. */
24
+ export type BlockRenderer<K extends MessageBlockKind = MessageBlockKind> = (
25
+ block: Extract<MessageBlock, { kind: K }>,
26
+ ctx: BlockRenderContext,
27
+ ) => ReactNode;
28
+
29
+ /** Partial map of `kind` → renderer. Missing kinds fall back to unknown. */
30
+ export type BlockRegistry = {
31
+ [K in MessageBlockKind]?: BlockRenderer<K>;
32
+ };
33
+
34
+ /**
35
+ * Merge host overrides over the built-in registry. Overrides win by key —
36
+ * `{ map: myMapRenderer }` swaps only the map renderer.
37
+ */
38
+ export function createBlockRegistry(overrides?: BlockRegistry): BlockRegistry {
39
+ return { ...BUILTIN_BLOCK_REGISTRY, ...overrides };
40
+ }
41
+
42
+ export { BUILTIN_BLOCK_REGISTRY };
@@ -0,0 +1,20 @@
1
+ 'use client';
2
+
3
+ /** Audio block — thin chat wrapper around `AudioPlayer`. */
4
+
5
+ import { LazyPlayer } from '../../../../AudioPlayer/lazy';
6
+ import type { AudioBlock } from '../../../types/block';
7
+ import type { BlockRendererProps } from './types';
8
+
9
+ export default function AudioBlockRenderer({ block, ctx }: BlockRendererProps<AudioBlock>) {
10
+ const variant = block.variant ?? (ctx.appearance === 'compact' ? 'compact' : 'default');
11
+ return (
12
+ <LazyPlayer
13
+ src={block.src}
14
+ title={block.title}
15
+ artist={block.artist}
16
+ cover={block.cover}
17
+ variant={variant}
18
+ />
19
+ );
20
+ }
@@ -0,0 +1,19 @@
1
+ 'use client';
2
+
3
+ /** Code block — read-only syntax highlighting via `PrettyCode`. */
4
+
5
+ import { LazyPrettyCode } from '../../../../PrettyCode/lazy';
6
+ import type { Language } from '../../../../PrettyCode/lazy';
7
+ import type { CodeBlock } from '../../../types/block';
8
+ import type { BlockRendererProps } from './types';
9
+
10
+ export default function CodeBlockRenderer({ block, ctx }: BlockRendererProps<CodeBlock>) {
11
+ const compact = ctx.appearance === 'compact';
12
+ return (
13
+ <LazyPrettyCode
14
+ data={block.code}
15
+ language={block.language as Language}
16
+ isCompact={compact}
17
+ />
18
+ );
19
+ }
@@ -0,0 +1,26 @@
1
+ 'use client';
2
+
3
+ /** Gallery block — thin chat wrapper around `Gallery`. */
4
+
5
+ import { Gallery } from '../../../../Gallery';
6
+ import type { GalleryMediaItem } from '../../../../Gallery';
7
+ import type { GalleryBlock } from '../../../types/block';
8
+ import type { BlockRendererProps } from './types';
9
+
10
+ export default function GalleryBlockRenderer({ block, ctx }: BlockRendererProps<GalleryBlock>) {
11
+ const images: GalleryMediaItem[] = block.items.map((item) => ({
12
+ id: item.id,
13
+ src: item.src,
14
+ thumbnail: item.thumbnail,
15
+ alt: item.alt,
16
+ }));
17
+ return (
18
+ <div className="overflow-hidden rounded-xl border border-border">
19
+ <Gallery
20
+ images={images}
21
+ showThumbnails={ctx.appearance !== 'compact'}
22
+ enableLightbox
23
+ />
24
+ </div>
25
+ );
26
+ }
@@ -0,0 +1,27 @@
1
+ 'use client';
2
+
3
+ /** Image block — interactive → `ImageViewer`, otherwise a plain `<img>`. */
4
+
5
+ import { LazyImageViewer } from '../../../../ImageViewer/lazy';
6
+ import type { ImageBlock } from '../../../types/block';
7
+ import type { BlockRendererProps } from './types';
8
+
9
+ export default function ImageBlockRenderer({ block }: BlockRendererProps<ImageBlock>) {
10
+ if (block.interactive) {
11
+ return (
12
+ <div className="overflow-hidden rounded-xl border border-border">
13
+ <LazyImageViewer
14
+ images={[{ file: { name: block.alt ?? 'image', path: block.src }, src: block.src }]}
15
+ />
16
+ </div>
17
+ );
18
+ }
19
+ return (
20
+ // eslint-disable-next-line @next/next/no-img-element
21
+ <img
22
+ src={block.src}
23
+ alt={block.alt ?? ''}
24
+ className="max-h-96 w-auto max-w-full rounded-xl border border-border object-contain"
25
+ />
26
+ );
27
+ }
@@ -0,0 +1,12 @@
1
+ 'use client';
2
+
3
+ /** JSON block — thin chat wrapper around `JsonTree`. */
4
+
5
+ import { LazyJsonTree } from '../../../../JsonTree/lazy';
6
+ import type { JsonBlock } from '../../../types/block';
7
+ import type { BlockRendererProps } from './types';
8
+
9
+ export default function JsonBlockRenderer({ block, ctx }: BlockRendererProps<JsonBlock>) {
10
+ const mode = block.mode ?? (ctx.appearance === 'compact' ? 'compact' : 'full');
11
+ return <LazyJsonTree data={block.data} mode={mode} />;
12
+ }
@@ -0,0 +1,11 @@
1
+ 'use client';
2
+
3
+ /** Lottie block — thin chat wrapper around `LottiePlayer`. */
4
+
5
+ import { LazyLottiePlayer } from '../../../../LottiePlayer/lazy';
6
+ import type { LottieBlock } from '../../../types/block';
7
+ import type { BlockRendererProps } from './types';
8
+
9
+ export default function LottieBlockRenderer({ block, ctx }: BlockRendererProps<LottieBlock>) {
10
+ return <LazyLottiePlayer src={block.src} size={ctx.appearance === 'compact' ? 'sm' : 'md'} />;
11
+ }
@@ -0,0 +1,36 @@
1
+ 'use client';
2
+
3
+ /** Map block — thin chat wrapper around `LazyMapContainer` + `MapMarker`. */
4
+
5
+ import { LazyMapContainer, MapMarker } from '../../../../Map/lazy';
6
+ import type { MarkerData } from '../../../../Map/lazy';
7
+ import type { MapBlock } from '../../../types/block';
8
+ import type { BlockRendererProps } from './types';
9
+
10
+ export default function MapBlockRenderer({ block, ctx }: BlockRendererProps<MapBlock>) {
11
+ const height = ctx.appearance === 'compact' ? 240 : 380;
12
+ return (
13
+ <div
14
+ className="overflow-hidden rounded-xl border border-border"
15
+ style={{ height }}
16
+ >
17
+ <LazyMapContainer
18
+ initialViewport={{
19
+ longitude: block.center.lng,
20
+ latitude: block.center.lat,
21
+ zoom: block.zoom ?? 11,
22
+ }}
23
+ >
24
+ {block.markers?.map((m) => {
25
+ const marker: MarkerData = {
26
+ id: m.id,
27
+ longitude: m.lng,
28
+ latitude: m.lat,
29
+ data: m.label ? { label: m.label } : undefined,
30
+ };
31
+ return <MapMarker key={m.id} marker={marker} ariaLabel={m.label} />;
32
+ })}
33
+ </LazyMapContainer>
34
+ </div>
35
+ );
36
+ }
@@ -0,0 +1,11 @@
1
+ 'use client';
2
+
3
+ /** Mermaid block — thin chat wrapper around `Mermaid`. */
4
+
5
+ import { LazyMermaid } from '../../../../Mermaid/lazy';
6
+ import type { MermaidBlock } from '../../../types/block';
7
+ import type { BlockRendererProps } from './types';
8
+
9
+ export default function MermaidBlockRenderer({ block }: BlockRendererProps<MermaidBlock>) {
10
+ return <LazyMermaid chart={block.chart} />;
11
+ }
@@ -0,0 +1,24 @@
1
+ 'use client';
2
+
3
+ /** Video block — thin chat wrapper around `VideoPlayer`. */
4
+
5
+ import { VideoPlayer } from '../../../../VideoPlayer/VideoPlayer';
6
+ import type { UrlSource } from '../../../../VideoPlayer/types';
7
+ import type { VideoBlock } from '../../../types/block';
8
+ import type { BlockRendererProps } from './types';
9
+
10
+ export default function VideoBlockRenderer({ block }: BlockRendererProps<VideoBlock>) {
11
+ // `poster` lives on the structured source, not as a top-level prop. A
12
+ // raw URL string is auto-classified, but to carry a poster we wrap it
13
+ // in a `UrlSource`.
14
+ const source: UrlSource | string = block.poster
15
+ ? { type: 'url', url: block.src, poster: block.poster, title: block.title }
16
+ : block.src;
17
+ return (
18
+ <VideoPlayer
19
+ source={source}
20
+ aspectRatio={block.aspectRatio ?? 16 / 9}
21
+ className="overflow-hidden rounded-xl"
22
+ />
23
+ );
24
+ }
@@ -0,0 +1,8 @@
1
+ /** Shared prop shape for every per-kind renderer module. */
2
+ import type { MessageBlock } from '../../../types/block';
3
+ import type { BlockRenderContext } from '../registry';
4
+
5
+ export interface BlockRendererProps<B extends MessageBlock = MessageBlock> {
6
+ block: B;
7
+ ctx: BlockRenderContext;
8
+ }
@@ -1,6 +1,7 @@
1
1
  'use client';
2
2
 
3
- export { ChatRoot, type ChatRootProps } from './ChatRoot';
3
+ /** Messages — chat transcript rendering (list, bubble, tool calls, …). */
4
+
4
5
  export {
5
6
  MessageList,
6
7
  type MessageListProps,
@@ -8,7 +9,6 @@ export {
8
9
  } from './MessageList';
9
10
  export { MessageBubble, type MessageBubbleProps } from './MessageBubble';
10
11
  export { MessageActions, type MessageActionsProps } from './MessageActions';
11
- export { Composer, type ComposerProps, type ComposerSize } from './Composer';
12
12
  export { Sources, type SourcesProps } from './Sources';
13
13
  export { ToolCalls, type ToolCallsProps, type ToolPayloadKind } from './ToolCalls';
14
14
  export {
@@ -22,8 +22,14 @@ export {
22
22
  type AttachmentRendererArgs,
23
23
  type AttachmentRendererMap,
24
24
  } from './Attachments';
25
- export { EmptyState, type EmptyStateProps } from './EmptyState';
26
- export { ErrorBanner, type ErrorBannerProps } from './ErrorBanner';
27
25
  export { JumpToLatest, type JumpToLatestProps } from './JumpToLatest';
28
26
  export { StreamingIndicator, type StreamingIndicatorProps } from './StreamingIndicator';
29
- export { AudioToggle, type AudioToggleProps } from './AudioToggle';
27
+ export {
28
+ MessageBlocks,
29
+ type MessageBlocksProps,
30
+ createBlockRegistry,
31
+ BUILTIN_BLOCK_REGISTRY,
32
+ type BlockRegistry,
33
+ type BlockRenderer,
34
+ type BlockRenderContext,
35
+ } from './blocks';