@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
@@ -3,21 +3,24 @@
3
3
  import React, { useCallback, useMemo, useRef } from 'react';
4
4
 
5
5
  import { Input } from '@djangocfg/ui-core/components';
6
+ import { cn } from '@djangocfg/ui-core/lib';
6
7
  import { useAppT } from '@djangocfg/i18n';
7
8
  import { WidgetProps } from '@rjsf/utils';
8
9
 
10
+ import { useWidgetEnv } from './_useWidgetEnv';
11
+
9
12
  /**
10
- * Color input widget for JSON Schema Form
11
- * Supports HSL format (h s% l%) and HEX format
12
- * Click on color box to open native color picker directly
13
+ * Color input widget for JSON Schema Form.
14
+ *
15
+ * Supports HSL format (h s% l%) and HEX format. Click on the color box
16
+ * to open the native color picker directly. Honors `density` and
17
+ * `ui:disabledWhen` via `useWidgetEnv`.
13
18
  */
14
19
  export function ColorWidget(props: WidgetProps) {
15
20
  const {
16
21
  id,
17
22
  placeholder,
18
23
  required,
19
- disabled,
20
- readonly,
21
24
  autofocus,
22
25
  value,
23
26
  onChange,
@@ -26,6 +29,7 @@ export function ColorWidget(props: WidgetProps) {
26
29
  options,
27
30
  rawErrors,
28
31
  } = props;
32
+ const { disabled, compact, tooltipText } = useWidgetEnv(props);
29
33
 
30
34
  const t = useAppT();
31
35
  const pickColorLabel = useMemo(() => t('tools.color.pick'), [t]);
@@ -173,10 +177,10 @@ export function ColorWidget(props: WidgetProps) {
173
177
 
174
178
  // Click on color box opens native color picker
175
179
  const handleColorBoxClick = useCallback(() => {
176
- if (!disabled && !readonly) {
180
+ if (!disabled) {
177
181
  colorInputRef.current?.click();
178
182
  }
179
- }, [disabled, readonly]);
183
+ }, [disabled]);
180
184
 
181
185
  return (
182
186
  <div className="flex items-center gap-2">
@@ -185,8 +189,11 @@ export function ColorWidget(props: WidgetProps) {
185
189
  <button
186
190
  type="button"
187
191
  onClick={handleColorBoxClick}
188
- disabled={disabled || readonly}
189
- className="h-10 w-10 shrink-0 rounded-md border-2 border-input cursor-pointer hover:border-ring focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
192
+ disabled={disabled}
193
+ className={cn(
194
+ 'shrink-0 rounded-md border-2 border-input cursor-pointer hover:border-ring focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
195
+ compact ? 'h-7 w-7' : 'h-10 w-10',
196
+ )}
190
197
  style={{ backgroundColor: previewColor }}
191
198
  aria-label={pickColorLabel}
192
199
  />
@@ -197,7 +204,7 @@ export function ColorWidget(props: WidgetProps) {
197
204
  value={hexValue}
198
205
  onChange={handleColorPickerChange}
199
206
  className="absolute inset-0 opacity-0 w-full h-full cursor-pointer"
200
- disabled={disabled || readonly}
207
+ disabled={disabled}
201
208
  tabIndex={-1}
202
209
  />
203
210
  </div>
@@ -208,14 +215,15 @@ export function ColorWidget(props: WidgetProps) {
208
215
  type="text"
209
216
  placeholder={placeholder || (format === 'hsl' ? '217 91% 60%' : '#3b82f6')}
210
217
  disabled={disabled}
211
- readOnly={readonly}
212
218
  autoFocus={autofocus}
213
219
  value={safeValue}
214
220
  required={required}
215
221
  onChange={handleChange}
216
222
  onBlur={handleBlur}
217
223
  onFocus={handleFocus}
218
- className={`flex-1 font-mono text-sm ${hasError ? 'border-destructive' : ''}`}
224
+ title={tooltipText}
225
+ aria-invalid={hasError || undefined}
226
+ className={cn('flex-1 font-mono text-sm', hasError && 'border-destructive', compact && 'h-7 text-xs')}
219
227
  />
220
228
  </div>
221
229
  );
@@ -3,19 +3,21 @@
3
3
  import React, { useCallback, useMemo } from 'react';
4
4
 
5
5
  import { Input } from '@djangocfg/ui-core/components';
6
+ import { cn } from '@djangocfg/ui-core/lib';
6
7
  import { WidgetProps } from '@rjsf/utils';
7
8
 
9
+ import { useWidgetEnv } from './_useWidgetEnv';
10
+
8
11
  /**
9
- * Number input widget for JSON Schema Form
10
- * Handles integer and number fields
12
+ * Number input widget for JSON Schema Form.
13
+ * Handles `integer` and `number` fields. Honors `density` and
14
+ * `ui:disabledWhen` via `useWidgetEnv`.
11
15
  */
12
16
  export function NumberWidget(props: WidgetProps) {
13
17
  const {
14
18
  id,
15
19
  placeholder,
16
20
  required,
17
- disabled,
18
- readonly,
19
21
  autofocus,
20
22
  value,
21
23
  onChange,
@@ -25,11 +27,12 @@ export function NumberWidget(props: WidgetProps) {
25
27
  schema,
26
28
  rawErrors,
27
29
  } = props;
30
+ const { disabled, compact, tooltipText } = useWidgetEnv(props);
28
31
 
29
32
  // Memoize widget configuration
30
33
  const config = useMemo(() => ({
31
34
  isInteger: schema.type === 'integer',
32
- step: schema.type === 'integer' ? '1' : 'any',
35
+ step: schema.multipleOf ?? (schema.type === 'integer' ? 1 : 'any'),
33
36
  min: schema.minimum,
34
37
  max: schema.maximum,
35
38
  emptyValue: options?.emptyValue,
@@ -39,11 +42,12 @@ export function NumberWidget(props: WidgetProps) {
39
42
  const safeValue = useMemo(() => {
40
43
  if (value === null || value === undefined || value === '') return '';
41
44
  if (typeof value === 'number' && !isNaN(value)) return value;
42
- return '';
45
+ const coerced = Number(value);
46
+ return isNaN(coerced) ? '' : coerced;
43
47
  }, [value]);
44
48
 
45
49
  const hasError = useMemo(() => {
46
- return rawErrors && rawErrors.length > 0;
50
+ return Boolean(rawErrors && rawErrors.length > 0);
47
51
  }, [rawErrors]);
48
52
 
49
53
  const handleChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
@@ -73,7 +77,6 @@ export function NumberWidget(props: WidgetProps) {
73
77
  type="number"
74
78
  placeholder={placeholder}
75
79
  disabled={disabled}
76
- readOnly={readonly}
77
80
  autoFocus={autofocus}
78
81
  value={safeValue}
79
82
  required={required}
@@ -83,7 +86,9 @@ export function NumberWidget(props: WidgetProps) {
83
86
  step={config.step}
84
87
  min={config.min}
85
88
  max={config.max}
86
- className={hasError ? 'border-destructive' : ''}
89
+ title={tooltipText}
90
+ aria-invalid={hasError || undefined}
91
+ className={cn(hasError && 'border-destructive', compact && 'h-7 text-xs')}
87
92
  />
88
93
  );
89
94
  }
@@ -0,0 +1,78 @@
1
+ "use client"
2
+
3
+ import React, { useCallback, useMemo } from 'react';
4
+
5
+ import { Label, RadioGroup, RadioGroupItem } from '@djangocfg/ui-core/components';
6
+ import { cn } from '@djangocfg/ui-core/lib';
7
+ import { WidgetProps } from '@rjsf/utils';
8
+
9
+ import { useWidgetEnv } from './_useWidgetEnv';
10
+
11
+ /**
12
+ * Radio group widget for JSON Schema Form.
13
+ *
14
+ * Renders `enum` fields as a vertical list of radio buttons — an
15
+ * alternative to `SelectWidget` for small option sets. Opt in via
16
+ * `uiSchema`:
17
+ *
18
+ * { plan: { 'ui:widget': 'radio' } }
19
+ *
20
+ * Set `ui:options.inline = true` to lay the options out in a row.
21
+ * Honors `density` and `ui:disabledWhen` via `useWidgetEnv`.
22
+ */
23
+ export function RadioWidget(props: WidgetProps) {
24
+ const { id, value, options, onChange, onBlur, onFocus } = props;
25
+ const { disabled, compact, tooltipText } = useWidgetEnv(props);
26
+
27
+ const enumOptions = useMemo(() => {
28
+ const opts = options?.enumOptions;
29
+ if (!Array.isArray(opts)) return [];
30
+ return opts.filter((opt) => opt && opt.value !== undefined);
31
+ }, [options]);
32
+
33
+ const inline = options?.inline === true;
34
+
35
+ const safeValue = useMemo(() => {
36
+ if (value === null || value === undefined) return '';
37
+ return String(value);
38
+ }, [value]);
39
+
40
+ const handleChange = useCallback((next: string) => {
41
+ onChange(next);
42
+ onBlur(id, next);
43
+ }, [onChange, onBlur, id]);
44
+
45
+ if (enumOptions.length === 0) {
46
+ return null;
47
+ }
48
+
49
+ return (
50
+ <RadioGroup
51
+ value={safeValue}
52
+ onValueChange={handleChange}
53
+ disabled={disabled}
54
+ onFocus={() => onFocus(id, value)}
55
+ title={tooltipText}
56
+ className={cn(
57
+ inline ? 'flex flex-row flex-wrap gap-x-4 gap-y-2' : 'grid gap-2',
58
+ compact && 'gap-1.5',
59
+ )}
60
+ >
61
+ {enumOptions.map((option: { value: unknown; label?: string }) => {
62
+ const optValue = String(option.value);
63
+ const optId = `${id}-${optValue}`;
64
+ return (
65
+ <div key={optValue || '__empty__'} className="flex items-center gap-2">
66
+ <RadioGroupItem value={optValue} id={optId} disabled={disabled} />
67
+ <Label
68
+ htmlFor={optId}
69
+ className={cn('cursor-pointer font-normal', compact && 'text-xs')}
70
+ >
71
+ {option.label || optValue}
72
+ </Label>
73
+ </div>
74
+ );
75
+ })}
76
+ </RadioGroup>
77
+ );
78
+ }
@@ -66,6 +66,7 @@ export function SelectWidget(props: WidgetProps) {
66
66
  disabled={disabled}
67
67
  readOnly={disabled}
68
68
  title={tooltipText}
69
+ aria-invalid={hasError || undefined}
69
70
  className={`flex h-10 w-full rounded-md border ${
70
71
  hasError ? 'border-destructive' : 'border-input'
71
72
  } bg-transparent px-3 py-2 text-base shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm`}
@@ -54,21 +54,24 @@ export function SliderWidget(props: WidgetProps) {
54
54
  return { min, max, step, unit, showInput };
55
55
  }, [schema, options]);
56
56
 
57
- // Parse value - handle string values like "0.5rem"
57
+ // Parse value - handle string values like "0.5rem". The result is
58
+ // clamped to [min, max] so an out-of-range value never pushes the
59
+ // Radix thumb off the track.
58
60
  const numericValue = useMemo(() => {
61
+ const clamp = (n: number) => Math.min(config.max, Math.max(config.min, n));
59
62
  if (value === null || value === undefined || value === '') {
60
63
  return config.min;
61
64
  }
62
65
  if (typeof value === 'number') {
63
- return value;
66
+ return isNaN(value) ? config.min : clamp(value);
64
67
  }
65
68
  if (typeof value === 'string') {
66
69
  // Extract number from string like "0.5rem"
67
70
  const parsed = parseFloat(value);
68
- return isNaN(parsed) ? config.min : parsed;
71
+ return isNaN(parsed) ? config.min : clamp(parsed);
69
72
  }
70
73
  return config.min;
71
- }, [value, config.min]);
74
+ }, [value, config.min, config.max]);
72
75
 
73
76
  const hasError = useMemo(() => {
74
77
  return rawErrors && rawErrors.length > 0;
@@ -2,20 +2,41 @@
2
2
 
3
3
  import React, { useCallback, useMemo } from 'react';
4
4
 
5
- import { Input } from '@djangocfg/ui-core/components';
5
+ import { Input, Textarea } from '@djangocfg/ui-core/components';
6
+ import { cn } from '@djangocfg/ui-core/lib';
6
7
  import { WidgetProps } from '@rjsf/utils';
7
8
 
9
+ import { useWidgetEnv } from './_useWidgetEnv';
10
+
8
11
  /**
9
- * Text input widget for JSON Schema Form
10
- * Handles string fields with optional textarea for multiline
12
+ * Text input widget for JSON Schema Form.
13
+ *
14
+ * Handles `string` fields. Switches to a multiline `Textarea` when
15
+ * `options.widget === 'textarea'` (see `TextareaWidget`). Maps the
16
+ * schema `format` to a native input type (`email`, `url`, `tel`,
17
+ * `password`, `date`, `datetime-local`, `time`). Honors `density`
18
+ * and `ui:disabledWhen` via `useWidgetEnv`.
11
19
  */
20
+
21
+ /** Maps JSON Schema `format` values to native `<input type>` values. */
22
+ const FORMAT_INPUT_TYPE: Record<string, string> = {
23
+ email: 'email',
24
+ uri: 'url',
25
+ url: 'url',
26
+ tel: 'tel',
27
+ phone: 'tel',
28
+ password: 'password',
29
+ date: 'date',
30
+ 'date-time': 'datetime-local',
31
+ datetime: 'datetime-local',
32
+ time: 'time',
33
+ };
34
+
12
35
  export function TextWidget(props: WidgetProps) {
13
36
  const {
14
37
  id,
15
38
  placeholder,
16
39
  required,
17
- disabled,
18
- readonly,
19
40
  autofocus,
20
41
  value,
21
42
  onChange,
@@ -25,13 +46,16 @@ export function TextWidget(props: WidgetProps) {
25
46
  schema,
26
47
  rawErrors,
27
48
  } = props;
49
+ const { disabled, compact, tooltipText } = useWidgetEnv(props);
28
50
 
29
51
  // Memoize widget configuration
30
52
  const config = useMemo(() => ({
31
53
  isTextarea: options?.widget === 'textarea',
32
- rows: options?.rows || 3,
54
+ rows: typeof options?.rows === 'number' ? options.rows : 3,
33
55
  emptyValue: options?.emptyValue,
34
- }), [options]);
56
+ inputType:
57
+ (typeof schema.format === 'string' && FORMAT_INPUT_TYPE[schema.format]) || 'text',
58
+ }), [options, schema.format]);
35
59
 
36
60
  // Ensure value is always a string
37
61
  const safeValue = useMemo(() => {
@@ -40,7 +64,7 @@ export function TextWidget(props: WidgetProps) {
40
64
  }, [value]);
41
65
 
42
66
  const hasError = useMemo(() => {
43
- return rawErrors && rawErrors.length > 0;
67
+ return Boolean(rawErrors && rawErrors.length > 0);
44
68
  }, [rawErrors]);
45
69
 
46
70
  const handleChange = useCallback((event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
@@ -58,14 +82,10 @@ export function TextWidget(props: WidgetProps) {
58
82
 
59
83
  if (config.isTextarea) {
60
84
  return (
61
- <textarea
85
+ <Textarea
62
86
  id={id}
63
- className={`flex min-h-[80px] w-full rounded-md border ${
64
- hasError ? 'border-destructive' : 'border-input'
65
- } bg-transparent px-3 py-2 text-base shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm`}
66
87
  placeholder={placeholder}
67
- disabled={disabled || readonly}
68
- readOnly={readonly}
88
+ disabled={disabled}
69
89
  autoFocus={autofocus}
70
90
  value={safeValue}
71
91
  required={required}
@@ -73,6 +93,9 @@ export function TextWidget(props: WidgetProps) {
73
93
  onBlur={handleBlur}
74
94
  onFocus={handleFocus}
75
95
  rows={config.rows}
96
+ title={tooltipText}
97
+ aria-invalid={hasError || undefined}
98
+ className={cn(hasError && 'border-destructive', compact && 'text-xs')}
76
99
  />
77
100
  );
78
101
  }
@@ -80,17 +103,18 @@ export function TextWidget(props: WidgetProps) {
80
103
  return (
81
104
  <Input
82
105
  id={id}
83
- type="text"
106
+ type={config.inputType}
84
107
  placeholder={placeholder}
85
108
  disabled={disabled}
86
- readOnly={readonly}
87
109
  autoFocus={autofocus}
88
110
  value={safeValue}
89
111
  required={required}
90
112
  onChange={handleChange}
91
113
  onBlur={handleBlur}
92
114
  onFocus={handleFocus}
93
- className={hasError ? 'border-destructive' : ''}
115
+ title={tooltipText}
116
+ aria-invalid={hasError || undefined}
117
+ className={cn(hasError && 'border-destructive', compact && 'h-7 text-xs')}
94
118
  />
95
119
  );
96
120
  }
@@ -10,6 +10,7 @@ export { TextareaWidget } from './TextareaWidget';
10
10
  export { NumberWidget } from './NumberWidget';
11
11
  export { CheckboxWidget } from './CheckboxWidget';
12
12
  export { SelectWidget } from './SelectWidget';
13
+ export { RadioWidget } from './RadioWidget';
13
14
  export { SwitchWidget } from './SwitchWidget';
14
15
  export { ColorWidget } from './ColorWidget';
15
16
  export { SliderWidget } from './SliderWidget';
@@ -2,33 +2,78 @@
2
2
 
3
3
  import React, { memo } from 'react';
4
4
  import { CommonExternalProps, JSONTree } from 'react-json-tree';
5
+ import { useResolvedTheme } from '@djangocfg/ui-core/hooks';
5
6
 
6
- // JSON inspector uses a fixed dark palette regardless of the host
7
- // theme — same convention as PrettyCode and devtool-style data
8
- // renderers (Chrome DevTools, Insomnia, Bruno). Syntax highlighting
9
- // has its own contrast model; mixing it with semantic UI tokens on
10
- // a light surface flattens keys/values into low-contrast pastels.
11
- const JSON_TREE_SURFACE_BG = '#0d1117';
12
- const JSON_TREE_THEME = {
13
- scheme: 'djangocfg-dark',
14
- base00: 'transparent',
15
- base01: '#1a1a1a',
16
- base02: '#2a2a2a',
17
- base03: '#6b7280',
18
- base04: '#9ca3af',
19
- base05: '#e5e7eb',
20
- base06: '#f3f4f6',
21
- base07: '#ffffff',
22
- base08: '#ef4444', // null, undefined
23
- base09: '#f97316', // numbers
24
- base0A: '#eab308', // strings
25
- base0B: '#22c55e', // booleans
26
- base0C: '#06b6d4', // dates, regex
27
- base0D: '#3b82f6', // keys
28
- base0E: '#a855f7', // functions
29
- base0F: '#f43f5e', // deprecations
7
+ // JSON inspector keeps its own syntax-highlight contrast model rather
8
+ // than reusing semantic UI tokens — same convention as Chrome DevTools,
9
+ // Insomnia and Bruno. It still follows the host light/dark theme, but
10
+ // each mode gets a hand-tuned base16 palette so keys/values stay
11
+ // high-contrast instead of flattening into pastels.
12
+ interface JsonTreePalette {
13
+ surface: string;
14
+ fg: string; // base05 — default text
15
+ title: string; // base06 — title
16
+ muted: string; // base04 — collection counts, meta
17
+ string: string; // base0A — strings + link color
18
+ theme: Record<string, string>;
19
+ }
20
+
21
+ const DARK_PALETTE: JsonTreePalette = {
22
+ surface: '#0d1117',
23
+ fg: '#e5e7eb',
24
+ title: '#f3f4f6',
25
+ muted: '#9ca3af',
26
+ string: '#eab308',
27
+ theme: {
28
+ scheme: 'djangocfg-dark',
29
+ base00: 'transparent',
30
+ base01: '#1a1a1a',
31
+ base02: '#2a2a2a',
32
+ base03: '#6b7280',
33
+ base04: '#9ca3af',
34
+ base05: '#e5e7eb',
35
+ base06: '#f3f4f6',
36
+ base07: '#ffffff',
37
+ base08: '#ef4444', // null, undefined
38
+ base09: '#f97316', // numbers
39
+ base0A: '#eab308', // strings
40
+ base0B: '#22c55e', // booleans
41
+ base0C: '#06b6d4', // dates, regex
42
+ base0D: '#3b82f6', // keys
43
+ base0E: '#a855f7', // functions
44
+ base0F: '#f43f5e', // deprecations
45
+ },
46
+ };
47
+
48
+ const LIGHT_PALETTE: JsonTreePalette = {
49
+ surface: '#ffffff',
50
+ fg: '#1f2937',
51
+ title: '#111827',
52
+ muted: '#6b7280',
53
+ string: '#b45309',
54
+ theme: {
55
+ scheme: 'djangocfg-light',
56
+ base00: 'transparent',
57
+ base01: '#f3f4f6',
58
+ base02: '#e5e7eb',
59
+ base03: '#9ca3af',
60
+ base04: '#6b7280',
61
+ base05: '#1f2937',
62
+ base06: '#111827',
63
+ base07: '#000000',
64
+ base08: '#dc2626', // null, undefined
65
+ base09: '#c2410c', // numbers
66
+ base0A: '#b45309', // strings
67
+ base0B: '#15803d', // booleans
68
+ base0C: '#0e7490', // dates, regex
69
+ base0D: '#1d4ed8', // keys
70
+ base0E: '#7e22ce', // functions
71
+ base0F: '#be123c', // deprecations
72
+ },
30
73
  };
31
74
 
75
+ const TRUNCATION_SUFFIX = '…';
76
+
32
77
  interface JsonContentProps {
33
78
  data: unknown;
34
79
  renderKey: number;
@@ -49,6 +94,7 @@ interface JsonContentProps {
49
94
  *
50
95
  * Memoised: re-renders only when any prop changes. `data` is compared
51
96
  * by reference — the parent should not mutate the object in place.
97
+ * Light/dark palette follows the host theme via `useResolvedTheme`.
52
98
  */
53
99
  const JsonContent = memo(({
54
100
  data,
@@ -64,52 +110,81 @@ const JsonContent = memo(({
64
110
  shouldExpandNodeInitially,
65
111
  jsonTreeProps = {},
66
112
  }: JsonContentProps) => {
113
+ const resolvedTheme = useResolvedTheme();
114
+ const palette = resolvedTheme === 'dark' ? DARK_PALETTE : LIGHT_PALETTE;
115
+
67
116
  const getItemString = showCollectionInfo
68
117
  ? (nodeType: string, nodeData: unknown) => {
69
118
  if (nodeType === 'Array') {
70
119
  const length = Array.isArray(nodeData) ? nodeData.length : 0;
71
- return length > 0 ? <span className="text-xs" style={{ color: '#9ca3af' }}>({length})</span> : null;
120
+ return length > 0 ? <span className="text-xs" style={{ color: palette.muted }}>({length})</span> : null;
72
121
  }
73
122
  if (nodeType === 'Object') {
74
123
  const keys = nodeData && typeof nodeData === 'object' ? Object.keys(nodeData) : [];
75
- return keys.length > 0 ? <span className="text-xs" style={{ color: '#9ca3af' }}>{`{${keys.length}}`}</span> : null;
124
+ return keys.length > 0 ? <span className="text-xs" style={{ color: palette.muted }}>{`{${keys.length}}`}</span> : null;
76
125
  }
77
126
  return null;
78
127
  }
79
128
  : () => null;
80
129
 
81
- const postprocessValue = (value: unknown) => {
82
- if (typeof value === 'string' && value.length > maxStringLength) {
83
- return value.substring(0, maxStringLength) + '... (truncated)';
130
+ const isUrl = (value: unknown): value is string =>
131
+ typeof value === 'string' && (value.startsWith('http://') || value.startsWith('https://'));
132
+
133
+ // Truncation lives in valueRenderer (not postprocessValue) so the full
134
+ // string stays intact for copy/download and is still reachable via the
135
+ // `title` tooltip. URLs render as clickable links.
136
+ const valueRenderer = (displayValue: unknown, rawValue: unknown) => {
137
+ if (isUrl(rawValue)) {
138
+ const truncated =
139
+ rawValue.length > maxStringLength
140
+ ? rawValue.slice(0, maxStringLength) + TRUNCATION_SUFFIX
141
+ : rawValue;
142
+ return (
143
+ <a
144
+ href={rawValue}
145
+ target="_blank"
146
+ rel="noopener noreferrer"
147
+ title={rawValue}
148
+ style={{ color: palette.string, textDecoration: 'underline' }}
149
+ onClick={(e) => e.stopPropagation()}
150
+ >
151
+ {`"${truncated}"`}
152
+ </a>
153
+ );
154
+ }
155
+ if (typeof rawValue === 'string' && rawValue.length > maxStringLength) {
156
+ return (
157
+ <span title={rawValue}>
158
+ {`"${rawValue.slice(0, maxStringLength)}${TRUNCATION_SUFFIX}"`}
159
+ </span>
160
+ );
84
161
  }
85
- return value;
162
+ return displayValue as React.ReactNode;
86
163
  };
87
164
 
88
- const isCustomNode = (value: unknown) =>
89
- typeof value === 'string' && (value.startsWith('http://') || value.startsWith('https://'));
90
-
91
165
  return (
92
166
  <div
93
- className={`overflow-auto h-full rounded-md ${padding}`}
167
+ role="region"
168
+ aria-label={title ? `JSON: ${title}` : 'JSON data'}
169
+ className={`overflow-auto h-full rounded-md border border-border/60 ${padding}`}
94
170
  style={{
95
- backgroundColor: JSON_TREE_SURFACE_BG,
96
- color: '#e5e7eb',
171
+ backgroundColor: palette.surface,
172
+ color: palette.fg,
97
173
  ...(fontSize ? { fontSize } : null),
98
174
  }}
99
175
  >
100
176
  {showTitle && title && (
101
- <h6 className="text-sm font-semibold mb-2" style={{ color: '#f3f4f6' }}>{title}</h6>
177
+ <h6 className="text-sm font-semibold mb-2" style={{ color: palette.title }}>{title}</h6>
102
178
  )}
103
179
  <JSONTree
104
180
  key={renderKey}
105
181
  data={data}
106
- theme={JSON_TREE_THEME}
182
+ theme={palette.theme}
107
183
  invertTheme={false}
108
184
  hideRoot={true}
109
185
  shouldExpandNodeInitially={shouldExpandNodeInitially}
110
186
  getItemString={getItemString}
111
- postprocessValue={postprocessValue}
112
- isCustomNode={isCustomNode}
187
+ valueRenderer={valueRenderer}
113
188
  collectionLimit={collectionLimit}
114
189
  sortObjectKeys={!preserveKeyOrder}
115
190
  {...jsonTreeProps}