@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,212 @@
1
+ 'use client';
2
+
3
+ /**
4
+ * Chat — shared "light surface".
5
+ *
6
+ * The single source of truth for everything safe to load synchronously:
7
+ * types, runtime constants, pure `core` + transports, hooks (no UI),
8
+ * notifier, payload-dispatch, logger, utils, styles, context.
9
+ *
10
+ * Both root entry points re-export this module verbatim:
11
+ * - `index.ts` (`@djangocfg/ui-tools`) — `public` + heavy sync components
12
+ * - `lazy.tsx` (`@djangocfg/ui-tools/chat`) — `public` + Lazy* wrappers
13
+ *
14
+ * Heavy UI components must NOT be added here — they belong in `index.ts`
15
+ * (sync) and `lazy.tsx` (lazy) only.
16
+ *
17
+ * `./chat` is the only sanctioned Chat subpath — do not add new subpaths
18
+ * (avoids the dual-bundle / two-React-context trap).
19
+ */
20
+
21
+ // Types
22
+ export type {
23
+ ChatRole,
24
+ ChatMessage,
25
+ ChatPersona,
26
+ ChatToolCall,
27
+ ChatAttachment,
28
+ ChatSource,
29
+ ChatDisplayMode,
30
+ ChatUserContext,
31
+ ChatAssistantContext,
32
+ ChatPrefs,
33
+ ChatConfig,
34
+ ChatLabels,
35
+ ChatTransport,
36
+ ChatStreamEvent,
37
+ CreateSessionOptions,
38
+ SessionInfo,
39
+ HistoryPage,
40
+ StreamOptions,
41
+ SendOptions,
42
+ MessageBlock,
43
+ MessageBlockKind,
44
+ BlockAppearance,
45
+ TextBlock,
46
+ MarkdownBlock,
47
+ AudioBlock,
48
+ VideoBlock,
49
+ ImageBlock,
50
+ GalleryBlock,
51
+ MapBlock,
52
+ JsonBlock,
53
+ MermaidBlock,
54
+ CodeBlock,
55
+ LottieBlock,
56
+ CustomBlock,
57
+ } from './types';
58
+ export { DEFAULT_LABELS } from './types';
59
+
60
+ // Constants — plain runtime constants, no UI imports
61
+ export {
62
+ STORAGE_KEYS,
63
+ CSS_VARS,
64
+ DEFAULT_Z_INDEX,
65
+ LIMITS,
66
+ DEFAULT_SIDEBAR,
67
+ HOTKEYS,
68
+ CHAT_EVENT_NAME,
69
+ type ChatEventDetail,
70
+ } from './constants';
71
+
72
+ // Core (pure) — reducer / id / token buffer / persona / initials
73
+ export {
74
+ reducer,
75
+ initialState,
76
+ createId,
77
+ createTokenBuffer,
78
+ resolvePersona,
79
+ deriveInitials,
80
+ type ChatState,
81
+ type ChatAction,
82
+ type TokenBuffer,
83
+ } from './core';
84
+
85
+ // Transport — pure functions, no UI
86
+ export {
87
+ createHttpTransport,
88
+ createMockTransport,
89
+ parseSSE,
90
+ TransportError,
91
+ createPydanticAIChatTransport,
92
+ createToolIdQueue,
93
+ mapPydanticAIEvent,
94
+ createPydanticAISSEMap,
95
+ type HttpTransportConfig,
96
+ type MockTransportOptions,
97
+ type ParseSSEOptions,
98
+ type PydanticAIChatTransportOpts,
99
+ type PydanticAIEvent,
100
+ type ToolIdQueue,
101
+ } from './core/transport';
102
+
103
+ // Hooks — React state glue, no JSX / UI components
104
+ export {
105
+ useChat,
106
+ useChatComposer,
107
+ useChatHistory,
108
+ useChatLayout,
109
+ useChatAudio,
110
+ useAutoFocusOnStreamEnd,
111
+ useRegisterComposer,
112
+ useChatReset,
113
+ useVisitorFingerprint,
114
+ useChatDockPrefs,
115
+ DEFAULT_DOCK_PREFS,
116
+ useFocusOnEmptyClick,
117
+ useChatUnread,
118
+ useChatUnreadNotifier,
119
+ useChatLightbox,
120
+ type UseChatUnreadOptions,
121
+ type UseChatUnreadReturn,
122
+ type UseChatUnreadNotifierOptions,
123
+ type UseChatConfig,
124
+ type UseChatReturn,
125
+ type UseChatComposerOptions,
126
+ type UseChatComposerReturn,
127
+ type UseChatHistoryOptions,
128
+ type UseChatLayoutConfig,
129
+ type UseChatLayoutReturn,
130
+ type UseAutoFocusOnStreamEndOptions,
131
+ type Focusable,
132
+ type UseChatResetOptions,
133
+ type UseChatResetReturn,
134
+ type UseVisitorFingerprintOptions,
135
+ type ChatDockPrefs,
136
+ type UseChatDockPrefsOptions,
137
+ type UseChatDockPrefsReturn,
138
+ type UseFocusOnEmptyClickOptions,
139
+ type UseChatLightboxReturn,
140
+ type ChatLightboxState,
141
+ type ChatLightboxScope,
142
+ } from './hooks';
143
+
144
+ // Audio
145
+ export {
146
+ useChatAudioPrefs,
147
+ DEFAULT_CHAT_SOUNDS,
148
+ type ChatAudioEvent,
149
+ type ChatAudioSounds,
150
+ type ChatAudioConfig,
151
+ type UseChatAudioReturn,
152
+ } from './core/audio';
153
+
154
+ // Notifier — title rotation + favicon badge + page-visibility + cross-tab
155
+ export {
156
+ createBrowserNotifier,
157
+ createNoopNotifier,
158
+ createTitleRotator,
159
+ createFaviconBadge,
160
+ createCrossTabNotifier,
161
+ isPageHidden,
162
+ onVisibilityChange,
163
+ type ChatNotifier,
164
+ type BrowserNotifierOptions,
165
+ type TitleRotatorOptions,
166
+ type TitleMode,
167
+ type FaviconBadgeOptions,
168
+ type CrossTabNotifierOptions,
169
+ } from './notifier';
170
+
171
+ // Tool-call payload dispatcher — pure
172
+ export {
173
+ dispatchToolPayload,
174
+ isPlainObject,
175
+ isLatLng,
176
+ isGeoJSONFeatureCollection,
177
+ isStringValue,
178
+ type ToolPayloadMatcher,
179
+ type ToolPayloadFallback,
180
+ } from './core/payload-dispatch';
181
+
182
+ // Dev logger (consola-based, namespace "chat:*")
183
+ export { getChatLogger, type ChatLogger, type ChatLogScope } from './core/logger';
184
+
185
+ // Utils — pure helpers
186
+ export { sanitizeDraft, isSubmittableDraft, collectImageAttachments } from './utils';
187
+
188
+ // Styles — role-aware className tokens + hooks
189
+ export {
190
+ BUBBLE_SURFACE,
191
+ ANCHOR,
192
+ TOGGLE,
193
+ DESTRUCTIVE_SURFACE,
194
+ TOOL_CALL,
195
+ useChatBubbleStyles,
196
+ useChatRoleStyles,
197
+ useChatDestructiveStyles,
198
+ type ChatBubbleSurface,
199
+ type ChatBubbleStyles,
200
+ type ChatRoleStyles,
201
+ type ChatDestructiveStyles,
202
+ } from './styles';
203
+
204
+ // Context — provider + hooks for callers wiring custom chat shells
205
+ export {
206
+ ChatProvider,
207
+ useChatContext,
208
+ useChatContextOptional,
209
+ type ChatContextValue,
210
+ type ChatProviderProps,
211
+ type ComposerHandle,
212
+ } from './context';
@@ -0,0 +1,345 @@
1
+ 'use client';
2
+
3
+ import { type ReactNode, useMemo, useRef, useState } from 'react';
4
+
5
+ import { cn } from '@djangocfg/ui-core/lib';
6
+
7
+ import type { ChatAttachment, ChatConfig, ChatMessage, ChatTransport } from '../types';
8
+ import type { ChatAudioConfig } from '../core/audio/types';
9
+ import {
10
+ ChatProvider,
11
+ useChatContext,
12
+ useChatContextOptional,
13
+ type ChatContextValue,
14
+ } from '../context';
15
+ import { useChatComposer, type UseChatComposerReturn } from '../hooks/useChatComposer';
16
+ import { useFocusOnEmptyClick } from '../hooks/useFocusOnEmptyClick';
17
+ import { Composer } from '../composer/Composer';
18
+ import type {
19
+ ComposerAppearance,
20
+ ComposerFooterProps,
21
+ ComposerLayout,
22
+ ComposerSize,
23
+ ComposerSlots,
24
+ } from '../composer/types';
25
+ import { EmptyState } from './EmptyState';
26
+ import { ErrorBanner } from './ErrorBanner';
27
+ import { JumpToLatest } from '../messages/JumpToLatest';
28
+ import { MessageBubble } from '../messages/MessageBubble';
29
+ import { MessageList, type MessageListHandle } from '../messages/MessageList';
30
+ import type { AttachmentRendererMap } from '../messages/Attachments';
31
+ import type { BlockRegistry } from '../messages/blocks';
32
+ import type { ToolCallsProps } from '../messages/ToolCalls';
33
+
34
+ /** Empty-state render API — seeds + focuses the composer from prompt chips. */
35
+ export interface ChatEmptyApi {
36
+ setValue: (v: string) => void;
37
+ focus: () => void;
38
+ }
39
+
40
+ /** Full-replacement render API for the composer slot — the live composer
41
+ * hook plus the resolved {@link ChatComposerConfig} that produced it.
42
+ * One source of truth; no hand-mirrored field list. */
43
+ export interface ChatComposerRenderApi {
44
+ composer: UseChatComposerReturn;
45
+ config: ChatComposerConfig;
46
+ }
47
+
48
+ /** Composer-region configuration for `<ChatRoot composer={…}>`. Groups
49
+ * every knob that forwards into the built-in `<Composer>`. */
50
+ export interface ChatComposerConfig {
51
+ /** Visual size variant. Default `md`. */
52
+ size?: ComposerSize;
53
+ /** Input-surface layout. Default `stacked` (`sm` → `inline`). */
54
+ layout?: ComposerLayout;
55
+ /** Extra className on the `<Composer>` wrapper. */
56
+ className?: string;
57
+ /** Hide the composer entirely (e.g. while waiting for human approval). */
58
+ hidden?: boolean;
59
+ /** Show the paperclip "attach" button. */
60
+ showAttachmentButton?: boolean;
61
+ /** Called when the user clicks the attach button. */
62
+ onPickFiles?: () => void;
63
+ /** Tier A declarative slots — action clusters + raw-node escape hatches. */
64
+ slots?: ComposerSlots;
65
+ /** Footer toolbar below the input surface. `false` hides it. */
66
+ footer?: ComposerFooterProps | false;
67
+ /** Full replacement — receives the live composer hook + this config. */
68
+ render?: (api: ChatComposerRenderApi) => ReactNode;
69
+ }
70
+
71
+ /** Named ReactNode slots for `<ChatRoot slots={…}>`. The `header` / `empty`
72
+ * slots accept either a node or a render fn — no separate `renderX` prop. */
73
+ export interface ChatSlots {
74
+ /** Sticky banner above the message list (e.g. quota warning). */
75
+ banner?: ReactNode;
76
+ /** Header row below the banner — node, or a fn given the chat context. */
77
+ header?: ReactNode | ((ctx: ChatContextValue) => ReactNode);
78
+ /** Replaces the default `<EmptyState>` — node, or a fn given a seed API. */
79
+ empty?: ReactNode | ((api: ChatEmptyApi) => ReactNode);
80
+ /** Replaces the default `<JumpToLatest>` floating pill. */
81
+ jumpToLatest?: ReactNode;
82
+ }
83
+
84
+ /** Message-rendering configuration for `<ChatRoot messages={…}>`. */
85
+ export interface ChatMessagesConfig {
86
+ /** Replace `<MessageBubble>` per message. */
87
+ render?: (m: ChatMessage, i: number) => ReactNode;
88
+ /**
89
+ * Render arbitrary content beneath every default `<MessageBubble>`
90
+ * (not invoked when `render` is set — the host owns layout then).
91
+ */
92
+ renderAfter?: (m: ChatMessage) => ReactNode;
93
+ /** Forwarded into `<MessageBubble toolCallsProps>` to swap payload renderers. */
94
+ toolCallsProps?: Omit<ToolCallsProps, 'calls'>;
95
+ /** Per-type attachment renderers — `{ image, audio, video, file, default }`. */
96
+ attachmentRenderers?: AttachmentRendererMap;
97
+ /** Called when an attachment tile is clicked (e.g. open lightbox). */
98
+ onAttachmentOpen?: (attachment: ChatAttachment) => void;
99
+ /**
100
+ * Registry of `kind` → renderer for `message.blocks`. Merge host
101
+ * overrides over the defaults with `createBlockRegistry({ … })`.
102
+ * Omit to use `BUILTIN_BLOCK_REGISTRY`.
103
+ */
104
+ blockRegistry?: BlockRegistry;
105
+ }
106
+
107
+ export interface ChatRootProps {
108
+ // ---- core wiring -------------------------------------------------------
109
+ /**
110
+ * Transport. Required UNLESS `<ChatRoot>` is rendered inside an
111
+ * existing `<ChatProvider>` (e.g. mounted by `<ChatLauncher>`), in
112
+ * which case the ambient provider is reused and `transport` is
113
+ * ignored.
114
+ */
115
+ transport?: ChatTransport;
116
+ config?: ChatConfig;
117
+ /** Session wiring — pre-existing id to attach, auto-create toggle. */
118
+ session?: { initialId?: string; autoCreate?: boolean };
119
+ streaming?: boolean;
120
+ /** Audio-trigger configuration. Off by default (no `sounds` map). */
121
+ audio?: ChatAudioConfig;
122
+ /**
123
+ * Verbose dev-mode logging via `consola` (namespace `chat:*`).
124
+ * Defaults to `isDev` from `@djangocfg/ui-core/lib`.
125
+ */
126
+ debug?: boolean;
127
+
128
+ // ---- presentation ------------------------------------------------------
129
+ /** Spaciousness of the whole chat — scales bubbles + composer.
130
+ * `compact` (default) for embedded chat, `full` for full-page. */
131
+ appearance?: ComposerAppearance;
132
+ /** Extra className on the `<ChatRoot>` wrapper. */
133
+ className?: string;
134
+ /** Extra className forwarded to the `<MessageList>` scroll container. */
135
+ listClassName?: string;
136
+
137
+ // ---- composition (grouped) --------------------------------------------
138
+ /** Named ReactNode slots — banner, header, empty, jumpToLatest. */
139
+ slots?: ChatSlots;
140
+ /** Composer-region configuration. */
141
+ composer?: ChatComposerConfig;
142
+ /** Message-rendering configuration. */
143
+ messages?: ChatMessagesConfig;
144
+
145
+ // ---- behavior ----------------------------------------------------------
146
+ /**
147
+ * Click in the message area → focus the composer (Slack / ChatGPT).
148
+ * @default true
149
+ */
150
+ focusOnEmptyClick?: boolean;
151
+ /**
152
+ * Contribute extra transport metadata, computed fresh per send.
153
+ * Forwarded to the `<ChatProvider>` this component creates — ignored
154
+ * when mounted under an ambient provider (set it on that provider
155
+ * instead). Used to attach the page-context snapshot.
156
+ */
157
+ getDynamicMetadata?: () => Record<string, unknown> | undefined;
158
+ }
159
+
160
+ export function ChatRoot(props: ChatRootProps) {
161
+ const {
162
+ transport,
163
+ config,
164
+ session,
165
+ streaming,
166
+ audio,
167
+ debug,
168
+ className,
169
+ listClassName,
170
+ getDynamicMetadata,
171
+ ...rest
172
+ } = props;
173
+ // When mounted under a launcher-owned `<ChatProvider>`, reuse that
174
+ // provider instead of wrapping in a second one. This lets host code
175
+ // freely nest `<ChatRoot>` inside `<ChatLauncher>` without losing
176
+ // `headerSlots` access to the same session / clearMessages / audio.
177
+ const ambient = useChatContextOptional();
178
+ if (ambient) {
179
+ return <ChatRootShell className={className} listClassName={listClassName} parts={rest} />;
180
+ }
181
+ if (!transport) {
182
+ throw new Error(
183
+ '<ChatRoot> requires `transport` when mounted outside a <ChatProvider>.',
184
+ );
185
+ }
186
+ return (
187
+ <ChatProvider
188
+ transport={transport}
189
+ config={config}
190
+ initialSessionId={session?.initialId}
191
+ autoCreateSession={session?.autoCreate}
192
+ streaming={streaming}
193
+ audio={audio}
194
+ debug={debug}
195
+ blockRegistry={rest.messages?.blockRegistry}
196
+ getDynamicMetadata={getDynamicMetadata}
197
+ >
198
+ <ChatRootShell className={className} listClassName={listClassName} parts={rest} />
199
+ </ChatProvider>
200
+ );
201
+ }
202
+
203
+ type ChatRootParts = Pick<
204
+ ChatRootProps,
205
+ 'appearance' | 'slots' | 'composer' | 'messages' | 'focusOnEmptyClick'
206
+ >;
207
+
208
+ interface ChatRootShellProps {
209
+ className?: string;
210
+ listClassName?: string;
211
+ parts: ChatRootParts;
212
+ }
213
+
214
+ function ChatRootShell({ className, listClassName, parts }: ChatRootShellProps) {
215
+ const { slots = {}, composer: composerConfig = {}, messages = {} } = parts;
216
+ const chat = useChatContext();
217
+ const composer = useChatComposer({
218
+ onSubmit: (content, attachments) => chat.sendMessage(content, attachments),
219
+ disabled: chat.isStreaming,
220
+ });
221
+ const onMessagesMouseUp = useFocusOnEmptyClick({
222
+ enabled: parts.focusOnEmptyClick !== false,
223
+ });
224
+ // Stream-end composer re-focus is handled by `<ChatProvider>` — it
225
+ // covers every usage pattern, not just `ChatRoot`.
226
+ // MessageList (virtuoso) owns the scroll viewport. We talk to it via
227
+ // the imperative handle (scrollToBottom) and the `onAtBottomChange`
228
+ // callback (drives the pill).
229
+ const listRef = useRef<MessageListHandle | null>(null);
230
+ const [isAtBottom, setIsAtBottom] = useState(true);
231
+ // The id of the most-recent user-sent message — passed as
232
+ // `scrollAnchorId` so every send re-anchors the viewport.
233
+ const lastUserMessageId = useMemo(() => {
234
+ const msgs = chat.messages;
235
+ for (let i = msgs.length - 1; i >= 0; i -= 1) {
236
+ if (msgs[i].role === 'user') return msgs[i].id;
237
+ }
238
+ return null;
239
+ }, [chat.messages]);
240
+ const handleStartReached = chat.hasMore && !chat.isLoadingMore
241
+ ? () => void chat.loadMore()
242
+ : undefined;
243
+
244
+ const greeting = chat.config.greeting ?? 'How can I help?';
245
+ const description = chat.config.description;
246
+ const suggestions = chat.config.suggestions;
247
+
248
+ const headerNode = typeof slots.header === 'function'
249
+ ? slots.header(chat)
250
+ : slots.header;
251
+
252
+ const emptyNode = typeof slots.empty === 'function'
253
+ ? slots.empty({ setValue: composer.setValue, focus: composer.focus })
254
+ : (slots.empty ?? (
255
+ <EmptyState
256
+ greeting={greeting}
257
+ description={description}
258
+ suggestions={suggestions}
259
+ onPickSuggestion={(prompt) => {
260
+ composer.setValue(prompt);
261
+ composer.focus();
262
+ }}
263
+ />
264
+ ));
265
+
266
+ // `appearance` scales the whole chat (bubbles + composer). Default
267
+ // `compact` keeps every embedded chat pixel-identical.
268
+ const appearance: ComposerAppearance = parts.appearance ?? 'compact';
269
+
270
+ const renderItem = messages.render
271
+ ?? ((m: ChatMessage) => (
272
+ <MessageBubble
273
+ key={m.id}
274
+ message={m}
275
+ appearance={appearance}
276
+ toolCallsProps={messages.toolCallsProps}
277
+ attachmentRenderers={messages.attachmentRenderers}
278
+ blockRegistry={messages.blockRegistry}
279
+ onAttachmentOpen={messages.onAttachmentOpen}
280
+ renderAfterMessage={messages.renderAfter}
281
+ onCopy={() => copy(m.content)}
282
+ onRegenerate={() => void chat.regenerate(m.id)}
283
+ onDelete={() => chat.deleteMessage(m.id)}
284
+ />
285
+ ));
286
+
287
+ return (
288
+ <div className={cn('relative flex h-full min-h-0 flex-col overflow-hidden', className)}>
289
+ {slots.banner ?? null}
290
+ {headerNode ?? null}
291
+ <div className="relative flex min-h-0 flex-1 flex-col" onMouseUp={onMessagesMouseUp}>
292
+ <ErrorBanner
293
+ error={chat.error}
294
+ onDismiss={chat.error ? () => chat.clearMessages() : undefined}
295
+ onRetry={chat.error ? () => void chat.regenerate() : undefined}
296
+ />
297
+ <MessageList
298
+ ref={listRef}
299
+ renderItem={renderItem}
300
+ appearance={appearance}
301
+ renderEmpty={() => <>{emptyNode}</>}
302
+ className={listClassName}
303
+ onStartReached={handleStartReached}
304
+ onAtBottomChange={setIsAtBottom}
305
+ scrollAnchorId={lastUserMessageId}
306
+ />
307
+ <div className="pointer-events-none absolute inset-x-0 bottom-2 flex justify-center">
308
+ {slots.jumpToLatest ?? (
309
+ <JumpToLatest
310
+ visible={!isAtBottom}
311
+ onClick={() => listRef.current?.scrollToBottom(true)}
312
+ />
313
+ )}
314
+ </div>
315
+ </div>
316
+ {!composerConfig.hidden && (
317
+ composerConfig.render
318
+ ? composerConfig.render({ composer, config: composerConfig })
319
+ : (
320
+ <Composer
321
+ composer={composer}
322
+ placeholder={chat.config.placeholder}
323
+ showAttachmentButton={composerConfig.showAttachmentButton}
324
+ onPickFiles={composerConfig.onPickFiles}
325
+ size={composerConfig.size}
326
+ appearance={appearance}
327
+ layout={composerConfig.layout}
328
+ className={composerConfig.className}
329
+ composerSlots={composerConfig.slots}
330
+ footer={composerConfig.footer ?? {}}
331
+ />
332
+ )
333
+ )}
334
+ </div>
335
+ );
336
+ }
337
+
338
+ function copy(text: string) {
339
+ if (typeof navigator !== 'undefined' && navigator.clipboard) {
340
+ void navigator.clipboard.writeText(text);
341
+ }
342
+ }
343
+
344
+ // re-export for convenience: composer hook return is a common slot dependency
345
+ export type { UseChatComposerReturn };
@@ -24,7 +24,9 @@ export function EmptyState({
24
24
  <div className="grid size-10 place-items-center rounded-full bg-muted">
25
25
  <Sparkles aria-hidden className="size-5 text-muted-foreground" />
26
26
  </div>
27
- {greeting ? <h2 className="text-base font-semibold">{greeting}</h2> : null}
27
+ {greeting ? (
28
+ <h2 className="text-base font-semibold text-foreground">{greeting}</h2>
29
+ ) : null}
28
30
  {description ? (
29
31
  <p className="max-w-md text-sm text-muted-foreground">{description}</p>
30
32
  ) : null}
@@ -35,7 +37,7 @@ export function EmptyState({
35
37
  key={s.prompt}
36
38
  type="button"
37
39
  onClick={() => onPickSuggestion?.(s.prompt)}
38
- className="rounded-lg border border-border bg-background/60 px-3 py-2 text-left text-xs hover:bg-accent"
40
+ className="rounded-lg border border-border bg-background/60 px-3 py-2 text-left text-xs text-foreground hover:bg-accent hover:text-accent-foreground"
39
41
  >
40
42
  {s.label}
41
43
  </button>
@@ -0,0 +1,15 @@
1
+ 'use client';
2
+
3
+ /** Shell — composition-root pieces (ChatRoot preset, empty / error states). */
4
+
5
+ export {
6
+ ChatRoot,
7
+ type ChatRootProps,
8
+ type ChatComposerConfig,
9
+ type ChatComposerRenderApi,
10
+ type ChatSlots,
11
+ type ChatMessagesConfig,
12
+ type ChatEmptyApi,
13
+ } from './ChatRoot';
14
+ export { EmptyState, type EmptyStateProps } from './EmptyState';
15
+ export { ErrorBanner, type ErrorBannerProps } from './ErrorBanner';