@djangocfg/ui-tools 2.1.418 → 2.1.419

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 (304) hide show
  1. package/dist/file-icon/index.cjs +3 -3
  2. package/dist/file-icon/index.cjs.map +1 -1
  3. package/dist/file-icon/index.mjs +3 -3
  4. package/dist/file-icon/index.mjs.map +1 -1
  5. package/package.json +93 -28
  6. package/src/common/FloatingToolbar/actions/CopyAction.tsx +31 -0
  7. package/src/{components → common}/FloatingToolbar/actions/DownloadAction.tsx +15 -10
  8. package/src/common/FloatingToolbar/actions/ExpandAction.tsx +33 -0
  9. package/src/common/FloatingToolbar/actions/FullscreenAction.tsx +38 -0
  10. package/src/{components → common}/FloatingToolbar/index.tsx +39 -0
  11. package/src/lib/http.ts +64 -0
  12. package/src/tools/chat/index.ts +1 -1
  13. package/src/tools/chat/launcher/ChatFAB.tsx +66 -74
  14. package/src/tools/chat/launcher/header/ChatHeaderActionButton.tsx +2 -3
  15. package/src/tools/chat/lazy.tsx +1 -1
  16. package/src/tools/chat/messages/MessageBubble.tsx +1 -1
  17. package/src/tools/chat/messages/blocks/builtin.tsx +1 -1
  18. package/src/tools/chat/messages/blocks/renderers/CodeBlock.tsx +2 -2
  19. package/src/tools/chat/messages/blocks/renderers/JsonBlock.tsx +12 -1
  20. package/src/tools/data/DataGrid/lazy.tsx +1 -1
  21. package/src/tools/data/DataTable/lazy.tsx +1 -1
  22. package/src/tools/data/JsonTree/JsonViewer.tsx +720 -0
  23. package/src/tools/data/JsonTree/README.md +126 -73
  24. package/src/tools/data/JsonTree/index.tsx +3 -95
  25. package/src/tools/data/JsonTree/lazy.tsx +10 -50
  26. package/src/tools/data/JsonTree/types.ts +82 -63
  27. package/src/tools/data/Kanban/lazy.tsx +1 -1
  28. package/src/tools/data/Listbox/lazy.tsx +1 -1
  29. package/src/tools/data/Masonry/lazy.tsx +1 -1
  30. package/src/tools/data/Timeline/lazy.tsx +1 -1
  31. package/src/tools/data/Tree/lazy.tsx +1 -1
  32. package/src/tools/dev/Map/lazy.tsx +1 -1
  33. package/src/tools/dev/Mermaid/Mermaid.client.tsx +2 -2
  34. package/src/tools/dev/Mermaid/lazy.tsx +1 -1
  35. package/src/tools/dev/api/ApiRefTable/ApiRefTable.tsx +65 -0
  36. package/src/tools/dev/api/ApiRefTable/README.md +31 -0
  37. package/src/tools/dev/api/ApiRefTable/components/Row.tsx +96 -0
  38. package/src/tools/dev/api/ApiRefTable/components/TypeDisplay.tsx +44 -0
  39. package/src/tools/dev/api/ApiRefTable/index.ts +6 -0
  40. package/src/tools/dev/api/ApiRefTable/lazy.tsx +21 -0
  41. package/src/tools/dev/api/ApiRefTable/types.ts +82 -0
  42. package/src/tools/dev/api/ApiRefTable/utils.ts +42 -0
  43. package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/ApiIntroSection.tsx +1 -1
  44. package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/CodeSamples/index.tsx +1 -1
  45. package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Header/index.tsx +1 -1
  46. package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Responses/ResponseBody.tsx +7 -21
  47. package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/RequestPanel.tsx +1 -1
  48. package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/PrettyView.tsx +13 -19
  49. package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/types.ts +1 -1
  50. package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/lazy.tsx +1 -1
  51. package/src/tools/dev/api/RequestViewer/README.md +33 -0
  52. package/src/tools/dev/api/RequestViewer/RequestViewer.tsx +121 -0
  53. package/src/tools/dev/api/RequestViewer/components/BodyTab.tsx +44 -0
  54. package/src/tools/dev/api/RequestViewer/components/EmptyState.tsx +13 -0
  55. package/src/tools/dev/api/RequestViewer/components/HeadersTab.tsx +78 -0
  56. package/src/tools/dev/api/RequestViewer/components/TimingTab.tsx +113 -0
  57. package/src/tools/dev/api/RequestViewer/components/utils.ts +31 -0
  58. package/src/tools/dev/api/RequestViewer/index.ts +16 -0
  59. package/src/tools/dev/api/RequestViewer/lazy.tsx +30 -0
  60. package/src/tools/dev/api/RequestViewer/types.ts +81 -0
  61. package/src/tools/dev/code/DiffViewer/DiffViewer.tsx +144 -0
  62. package/src/tools/dev/code/DiffViewer/README.md +33 -0
  63. package/src/tools/dev/code/DiffViewer/components/CopyButton.tsx +49 -0
  64. package/src/tools/dev/code/DiffViewer/components/DiffLineContent.tsx +48 -0
  65. package/src/tools/dev/code/DiffViewer/components/SplitView.tsx +220 -0
  66. package/src/tools/dev/code/DiffViewer/components/UnifiedView.tsx +154 -0
  67. package/src/tools/dev/code/DiffViewer/hooks/useDiff.ts +47 -0
  68. package/src/tools/dev/code/DiffViewer/hooks/useHighlighter.ts +54 -0
  69. package/src/tools/dev/code/DiffViewer/index.ts +22 -0
  70. package/src/tools/dev/code/DiffViewer/lazy.tsx +22 -0
  71. package/src/tools/dev/code/DiffViewer/types.ts +109 -0
  72. package/src/tools/dev/code/DiffViewer/utils/computeDiff.ts +159 -0
  73. package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/CollapseToggle.tsx +1 -1
  74. package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/MarkdownMessage.tsx +1 -1
  75. package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/components.tsx +2 -2
  76. package/src/tools/dev/{PrettyCode → code/PrettyCode}/PrettyCode.client.tsx +2 -2
  77. package/src/tools/dev/{PrettyCode → code/PrettyCode}/lazy.tsx +1 -1
  78. package/src/tools/dev/ops/EnvTable/EnvTable.tsx +228 -0
  79. package/src/tools/dev/ops/EnvTable/README.md +29 -0
  80. package/src/tools/dev/ops/EnvTable/hooks/useEnvMask.ts +121 -0
  81. package/src/tools/dev/ops/EnvTable/index.ts +12 -0
  82. package/src/tools/dev/ops/EnvTable/lazy.tsx +21 -0
  83. package/src/tools/dev/ops/EnvTable/types.ts +76 -0
  84. package/src/tools/dev/ops/LogViewer/LogViewer.tsx +194 -0
  85. package/src/tools/dev/ops/LogViewer/README.md +30 -0
  86. package/src/tools/dev/ops/LogViewer/components/LogRow.tsx +151 -0
  87. package/src/tools/dev/ops/LogViewer/components/Toolbar.tsx +199 -0
  88. package/src/tools/dev/ops/LogViewer/hooks/useAutoScroll.ts +68 -0
  89. package/src/tools/dev/ops/LogViewer/hooks/useLogFilter.ts +58 -0
  90. package/src/tools/dev/ops/LogViewer/index.ts +18 -0
  91. package/src/tools/dev/ops/LogViewer/lazy.tsx +25 -0
  92. package/src/tools/dev/ops/LogViewer/types.ts +142 -0
  93. package/src/tools/dev/ops/LogViewer/utils/ansi.ts +231 -0
  94. package/src/tools/forms/CodeEditor/hooks/useEditorTheme.ts +13 -73
  95. package/src/tools/forms/CodeEditor/lazy.tsx +1 -1
  96. package/src/tools/forms/FileUpload/lazy.tsx +1 -1
  97. package/src/tools/forms/JsonEditor/JsonEditor.tsx +115 -0
  98. package/src/tools/forms/JsonEditor/index.ts +1 -0
  99. package/src/tools/forms/JsonEditor/lazy.tsx +24 -0
  100. package/src/tools/forms/JsonForm/index.ts +1 -1
  101. package/src/tools/forms/JsonForm/lazy.tsx +1 -1
  102. package/src/tools/forms/MarkdownEditor/lazy.tsx +1 -1
  103. package/src/tools/forms/NotionEditor/README.md +237 -0
  104. package/src/tools/forms/NotionEditor/lazy.tsx +1 -1
  105. package/src/tools/index.ts +153 -13
  106. package/src/tools/input/Combobox/lazy.tsx +1 -1
  107. package/src/tools/input/CronScheduler/components/CronPreview.README.md +28 -0
  108. package/src/tools/input/CronScheduler/components/CronPreview.tsx +136 -0
  109. package/src/tools/input/CronScheduler/components/index.ts +3 -0
  110. package/src/tools/input/CronScheduler/index.tsx +5 -1
  111. package/src/tools/input/CronScheduler/lazy.tsx +5 -1
  112. package/src/tools/input/CronScheduler/utils/cron-next-runs.ts +122 -0
  113. package/src/tools/input/CronScheduler/utils/index.ts +1 -0
  114. package/src/tools/input/Scroller/lazy.tsx +1 -1
  115. package/src/tools/input/Sortable/lazy.tsx +1 -1
  116. package/src/tools/input/SpeechRecognition/lazy.tsx +1 -1
  117. package/src/tools/input/SpeechRecognition/widgets/VoiceComposerSlot.tsx +41 -36
  118. package/src/tools/media/ImageViewer/components/ImageToolbar.tsx +58 -47
  119. package/src/tools/media/ImageViewer/components/ImageViewer.tsx +27 -19
  120. package/src/tools/media/ImageViewer/lazy.tsx +1 -1
  121. package/src/tools/media/LottiePlayer/lazy.tsx +1 -1
  122. package/src/tools/media/VideoPlayer/VideoPlayer.tsx +28 -1
  123. package/src/tools/media/VideoPlayer/parts/fullscreen.tsx +21 -4
  124. package/src/tools/media/VideoPlayer/parts/pip.tsx +21 -4
  125. package/src/tools/media/VideoPlayer/parts/play-button.tsx +21 -4
  126. package/src/tools/media/VideoPlayer/parts/playback-rate.tsx +19 -3
  127. package/src/tools/media/VideoPlayer/parts/volume.tsx +237 -18
  128. package/src/tools/media/VideoPlayer/styles/video-player.css +87 -7
  129. package/src/tools/overlay/ResponsiveDialog/lazy.tsx +1 -1
  130. package/src/tools/overlay/ScrollSpy/lazy.tsx +1 -1
  131. package/src/tools/overlay/SelectionToolbar/lazy.tsx +1 -1
  132. package/src/tools/overlay/Tour/lazy.tsx +1 -1
  133. package/src/tools/visual/Marquee/lazy.tsx +1 -1
  134. package/src/tools/visual/QRCode/lazy.tsx +1 -1
  135. package/src/tools/visual/charts/ActivityGraph/ActivityGraph.tsx +195 -0
  136. package/src/tools/visual/charts/ActivityGraph/README.md +28 -0
  137. package/src/tools/visual/charts/ActivityGraph/index.ts +8 -0
  138. package/src/tools/visual/charts/ActivityGraph/lazy.tsx +21 -0
  139. package/src/tools/visual/charts/ActivityGraph/types.ts +59 -0
  140. package/src/tools/visual/charts/ActivityGraph/utils.ts +88 -0
  141. package/src/tools/visual/charts/CommitGraph/CommitGraph.tsx +80 -0
  142. package/src/tools/visual/charts/CommitGraph/README.md +28 -0
  143. package/src/tools/visual/charts/CommitGraph/components/CommitDetail.tsx +107 -0
  144. package/src/tools/visual/charts/CommitGraph/components/CommitRow.tsx +122 -0
  145. package/src/tools/visual/charts/CommitGraph/components/Rails.tsx +171 -0
  146. package/src/tools/visual/charts/CommitGraph/hooks/useGraphLayout.ts +169 -0
  147. package/src/tools/visual/charts/CommitGraph/hooks/useLaneColors.ts +45 -0
  148. package/src/tools/visual/charts/CommitGraph/index.ts +14 -0
  149. package/src/tools/visual/charts/CommitGraph/lazy.tsx +25 -0
  150. package/src/tools/visual/charts/CommitGraph/types.ts +85 -0
  151. package/src/tools/visual/charts/CommitGraph/utils.ts +53 -0
  152. package/src/tools/visual/{Gauge → charts/Gauge}/lazy.tsx +1 -1
  153. package/src/tools/visual/charts/Sparkline/README.md +29 -0
  154. package/src/tools/visual/charts/Sparkline/Sparkline.tsx +217 -0
  155. package/src/tools/visual/charts/Sparkline/index.ts +9 -0
  156. package/src/tools/visual/charts/Sparkline/lazy.tsx +26 -0
  157. package/src/tools/visual/charts/Sparkline/types.ts +58 -0
  158. package/src/tools/visual/design/ColorPalette/ColorPalette.tsx +129 -0
  159. package/src/tools/visual/design/ColorPalette/README.md +34 -0
  160. package/src/tools/visual/design/ColorPalette/components/Swatch.tsx +102 -0
  161. package/src/tools/visual/design/ColorPalette/hooks/useCopyToClipboard.ts +41 -0
  162. package/src/tools/visual/design/ColorPalette/index.ts +12 -0
  163. package/src/tools/visual/design/ColorPalette/lazy.tsx +21 -0
  164. package/src/tools/visual/design/ColorPalette/types.ts +63 -0
  165. package/src/tools/visual/design/ColorPalette/utils.ts +83 -0
  166. package/src/tools/visual/{ColorPicker → design/ColorPicker}/lazy.tsx +1 -1
  167. package/src/tools/visual/{FileIcon → design/FileIcon}/treeAdapter.tsx +1 -1
  168. package/src/tools/visual/{Fps → indicators/Fps}/lazy.tsx +1 -1
  169. package/src/tools/visual/{Rating → indicators/Rating}/lazy.tsx +1 -1
  170. package/src/tools/visual/indicators/StatusIndicator/README.md +28 -0
  171. package/src/tools/visual/indicators/StatusIndicator/StatusIndicator.tsx +83 -0
  172. package/src/tools/visual/indicators/StatusIndicator/index.ts +14 -0
  173. package/src/tools/visual/indicators/StatusIndicator/lazy.tsx +21 -0
  174. package/src/tools/visual/indicators/StatusIndicator/types.ts +133 -0
  175. package/src/components/FloatingToolbar/actions/CopyAction.tsx +0 -22
  176. package/src/components/FloatingToolbar/actions/ExpandAction.tsx +0 -25
  177. package/src/components/FloatingToolbar/actions/FullscreenAction.tsx +0 -30
  178. package/src/tools/data/JsonTree/components/JsonContent.tsx +0 -197
  179. package/src/tools/data/JsonTree/hooks/useJsonExpand.ts +0 -50
  180. /package/src/{components → common}/FloatingToolbar/FloatingToolbar.css +0 -0
  181. /package/src/{components → common}/FloatingToolbar/actions/index.ts +0 -0
  182. /package/src/{components → common}/FloatingToolbar/hooks/useElementCorner.ts +0 -0
  183. /package/src/{components → common}/FloatingToolbar/hooks/useScrollIsolation.ts +0 -0
  184. /package/src/{components → common}/index.ts +0 -0
  185. /package/src/{components → common}/lazy-wrapper.tsx +0 -0
  186. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/README.md +0 -0
  187. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/DocsView.tsx +0 -0
  188. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/CodeSamples/LanguageTabs.tsx +0 -0
  189. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/CodeSamples/useCodeSnippet.ts +0 -0
  190. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Header/MetaActions.tsx +0 -0
  191. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Header/MethodBadge.tsx +0 -0
  192. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Header/PathDisplay.tsx +0 -0
  193. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Parameters/ParamGroup.tsx +0 -0
  194. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Parameters/ParamRow.tsx +0 -0
  195. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Parameters/index.tsx +0 -0
  196. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/RequestBody/index.tsx +0 -0
  197. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Responses/ResponseRow.tsx +0 -0
  198. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Responses/StatusTag.tsx +0 -0
  199. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Responses/index.tsx +0 -0
  200. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/SchemaFields/FieldRow.tsx +0 -0
  201. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/SchemaFields/buildTree.ts +0 -0
  202. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/SchemaFields/index.tsx +0 -0
  203. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/SchemaFields/types.ts +0 -0
  204. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Section/SectionHeader.tsx +0 -0
  205. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Section/defaults.ts +0 -0
  206. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Section/index.tsx +0 -0
  207. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/context.tsx +0 -0
  208. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/hooks/useSectionHash.ts +0 -0
  209. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/index.tsx +0 -0
  210. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/store/index.ts +0 -0
  211. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/store/selectors.ts +0 -0
  212. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/types.ts +0 -0
  213. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/SchemaCopyMenu.tsx +0 -0
  214. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/BrandHeader.tsx +0 -0
  215. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/CategoryBlock.tsx +0 -0
  216. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/EndpointRow.tsx +0 -0
  217. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/SchemaSection.tsx +0 -0
  218. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/SearchInput.tsx +0 -0
  219. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/SidebarBody.tsx +0 -0
  220. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/Toolbar.tsx +0 -0
  221. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/buildVM.ts +0 -0
  222. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/index.tsx +0 -0
  223. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/types.ts +0 -0
  224. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/useDebouncedValue.ts +0 -0
  225. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/SlideInPlayground.tsx +0 -0
  226. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/TryItSheet.tsx +0 -0
  227. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/anchor.ts +0 -0
  228. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/grouping.ts +0 -0
  229. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/index.tsx +0 -0
  230. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/sidebarLabel.ts +0 -0
  231. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/index.ts +0 -0
  232. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/BodyFormEditor.tsx +0 -0
  233. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/EndpointDraftSync.tsx +0 -0
  234. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/EndpointResetButton.tsx +0 -0
  235. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/PreviewView.tsx +0 -0
  236. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/RawView.tsx +0 -0
  237. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/StatusBar.tsx +0 -0
  238. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/ViewTabs.tsx +0 -0
  239. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/detectContent.ts +0 -0
  240. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/index.tsx +0 -0
  241. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/useResponseView.ts +0 -0
  242. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/SendButton.tsx +0 -0
  243. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ui.tsx +0 -0
  244. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/constants.ts +0 -0
  245. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/context/PlaygroundContext.tsx +0 -0
  246. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/hooks/index.ts +0 -0
  247. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/hooks/useDocsUrlSync.ts +0 -0
  248. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/hooks/useEndpointDraft.ts +0 -0
  249. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/hooks/useMobile.ts +0 -0
  250. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/hooks/useOpenApiSchema.ts +0 -0
  251. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/index.tsx +0 -0
  252. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/types.ts +0 -0
  253. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/apiKeyManager.ts +0 -0
  254. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/codeSamples.ts +0 -0
  255. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/formatters.ts +0 -0
  256. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/index.ts +0 -0
  257. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/operationToHar.ts +0 -0
  258. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/sampler.ts +0 -0
  259. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/schemaExport.ts +0 -0
  260. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/scrollParent.ts +0 -0
  261. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/url.ts +0 -0
  262. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/versionManager.ts +0 -0
  263. /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/ActionRow.tsx +0 -0
  264. /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/ChatMessageRow.tsx +0 -0
  265. /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/CodeBlock.tsx +0 -0
  266. /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/README.md +0 -0
  267. /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/index.ts +0 -0
  268. /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/linkRules.ts +0 -0
  269. /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/plainText.ts +0 -0
  270. /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/sanitize.ts +0 -0
  271. /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/types.ts +0 -0
  272. /package/src/tools/dev/{PrettyCode → code/PrettyCode}/README.md +0 -0
  273. /package/src/tools/dev/{PrettyCode → code/PrettyCode}/index.tsx +0 -0
  274. /package/src/tools/dev/{PrettyCode → code/PrettyCode}/registerPrismLanguages.ts +0 -0
  275. /package/src/tools/visual/{Gauge → charts/Gauge}/Gauge.tsx +0 -0
  276. /package/src/tools/visual/{Gauge → charts/Gauge}/index.ts +0 -0
  277. /package/src/tools/visual/{Gauge → charts/Gauge}/types.ts +0 -0
  278. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/ColorPicker.tsx +0 -0
  279. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/context/ColorPickerContext.tsx +0 -0
  280. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/context/ColorPickerStore.tsx +0 -0
  281. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/context/index.ts +0 -0
  282. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/index.ts +0 -0
  283. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/lib/color-utils.ts +0 -0
  284. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerAlphaSlider.tsx +0 -0
  285. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerArea.tsx +0 -0
  286. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerEyeDropper.tsx +0 -0
  287. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerFormatSelect.tsx +0 -0
  288. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerHueSlider.tsx +0 -0
  289. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerInput.tsx +0 -0
  290. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerSwatch.tsx +0 -0
  291. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/index.ts +0 -0
  292. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/types.ts +0 -0
  293. /package/src/tools/visual/{FileIcon → design/FileIcon}/FileIcon.tsx +0 -0
  294. /package/src/tools/visual/{FileIcon → design/FileIcon}/get-file-icon.ts +0 -0
  295. /package/src/tools/visual/{FileIcon → design/FileIcon}/icons/icon-data.ts +0 -0
  296. /package/src/tools/visual/{FileIcon → design/FileIcon}/index.ts +0 -0
  297. /package/src/tools/visual/{FileIcon → design/FileIcon}/loader.ts +0 -0
  298. /package/src/tools/visual/{FileIcon → design/FileIcon}/specialFolders.ts +0 -0
  299. /package/src/tools/visual/{Fps → indicators/Fps}/Fps.tsx +0 -0
  300. /package/src/tools/visual/{Fps → indicators/Fps}/index.ts +0 -0
  301. /package/src/tools/visual/{Fps → indicators/Fps}/types.ts +0 -0
  302. /package/src/tools/visual/{Rating → indicators/Rating}/Rating.tsx +0 -0
  303. /package/src/tools/visual/{Rating → indicators/Rating}/index.ts +0 -0
  304. /package/src/tools/visual/{Rating → indicators/Rating}/types.ts +0 -0
@@ -0,0 +1,121 @@
1
+ // Adapted from jalcoui (MIT) — github.com/jal-co/ui
2
+ //
3
+ // Lightweight HTTP inspector — headers / body / timing in tabs. Renders an
4
+ // already-executed request/response object; never fetches. For an
5
+ // interactive request playground, use OpenapiViewer instead.
6
+ //
7
+ // Requires <UiProviders> mounted at the host root (Tabs use Radix primitives).
8
+
9
+ 'use client';
10
+
11
+ import * as React from 'react';
12
+ import { Clock, FileText, Globe, Activity } from 'lucide-react';
13
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from '@djangocfg/ui-core';
14
+ import { cn } from '@djangocfg/ui-core/lib';
15
+ import { methodColor, statusColor } from '../../../../lib/http';
16
+ import {
17
+ METHOD_TONE_TEXT,
18
+ STATUS_TONE_PILL,
19
+ type RequestViewerProps,
20
+ type RequestViewerTab,
21
+ } from './types';
22
+ import { HeadersTab } from './components/HeadersTab';
23
+ import { BodyTab } from './components/BodyTab';
24
+ import { TimingTab } from './components/TimingTab';
25
+ import { formatDuration } from './components/utils';
26
+
27
+ export function RequestViewer({
28
+ request,
29
+ defaultTab = 'headers',
30
+ className,
31
+ ...props
32
+ }: RequestViewerProps) {
33
+ const headerCount =
34
+ (request.requestHeaders?.length ?? 0) +
35
+ (request.responseHeaders?.length ?? 0);
36
+ const timingCount = request.timing?.length ?? 0;
37
+
38
+ const methodToneCls = METHOD_TONE_TEXT[methodColor(request.method)];
39
+ const statusToneCls = STATUS_TONE_PILL[statusColor(request.status)];
40
+
41
+ return (
42
+ <div
43
+ data-slot="request-viewer"
44
+ className={cn(
45
+ 'overflow-hidden rounded-xl border border-border/60 bg-card shadow-sm',
46
+ className,
47
+ )}
48
+ {...props}
49
+ >
50
+ {/* Request summary */}
51
+ <div className="flex flex-wrap items-center gap-3 border-b border-border/40 px-4 py-3">
52
+ <span
53
+ className={cn(
54
+ 'font-mono text-sm font-bold uppercase',
55
+ methodToneCls,
56
+ )}
57
+ >
58
+ {request.method}
59
+ </span>
60
+ <span className="min-w-0 flex-1 truncate font-mono text-sm text-muted-foreground">
61
+ {request.url}
62
+ </span>
63
+ <span
64
+ className={cn(
65
+ 'inline-flex items-center rounded-md px-2.5 py-0.5 font-mono text-xs font-semibold',
66
+ statusToneCls,
67
+ )}
68
+ >
69
+ {request.status}
70
+ {request.statusText ? ` ${request.statusText}` : null}
71
+ </span>
72
+ {request.duration !== undefined && (
73
+ <span className="inline-flex items-center gap-1 text-xs text-muted-foreground">
74
+ <Clock className="size-3" />
75
+ {formatDuration(request.duration)}
76
+ </span>
77
+ )}
78
+ </div>
79
+
80
+ {/* Tabs */}
81
+ <Tabs defaultValue={defaultTab satisfies RequestViewerTab}>
82
+ <div className="border-b border-border/40 bg-muted/20 px-2 pt-2">
83
+ <TabsList variant="underline">
84
+ <TabsTrigger value="headers">
85
+ <FileText className="size-3.5 mr-1.5" />
86
+ Headers
87
+ {headerCount > 0 && (
88
+ <span className="ml-1.5 rounded-full bg-muted px-1.5 py-0.5 text-[10px] font-semibold leading-none">
89
+ {headerCount}
90
+ </span>
91
+ )}
92
+ </TabsTrigger>
93
+ <TabsTrigger value="body">
94
+ <Globe className="size-3.5 mr-1.5" />
95
+ Body
96
+ </TabsTrigger>
97
+ <TabsTrigger value="timing">
98
+ <Activity className="size-3.5 mr-1.5" />
99
+ Timing
100
+ {timingCount > 0 && (
101
+ <span className="ml-1.5 rounded-full bg-muted px-1.5 py-0.5 text-[10px] font-semibold leading-none">
102
+ {timingCount}
103
+ </span>
104
+ )}
105
+ </TabsTrigger>
106
+ </TabsList>
107
+ </div>
108
+
109
+ <TabsContent value="headers" className="mt-0">
110
+ <HeadersTab request={request} />
111
+ </TabsContent>
112
+ <TabsContent value="body" className="mt-0">
113
+ <BodyTab request={request} />
114
+ </TabsContent>
115
+ <TabsContent value="timing" className="mt-0">
116
+ <TimingTab request={request} />
117
+ </TabsContent>
118
+ </Tabs>
119
+ </div>
120
+ );
121
+ }
@@ -0,0 +1,44 @@
1
+ // Adapted from jalcoui (MIT) — github.com/jal-co/ui
2
+
3
+ 'use client';
4
+
5
+ import * as React from 'react';
6
+ import { JsonTree } from '../../../../data/JsonTree';
7
+ import type { NetworkRequest } from '../types';
8
+ import { byteSize, looksLikeJson, tryParseJson } from './utils';
9
+ import { EmptyState } from './EmptyState';
10
+
11
+ export function BodyTab({ request }: { request: NetworkRequest }) {
12
+ if (!request.responseBody) {
13
+ return <EmptyState message="No response body available." />;
14
+ }
15
+
16
+ const declaredJson = request.contentType?.toLowerCase().includes('json');
17
+ const isJson = declaredJson || looksLikeJson(request.responseBody);
18
+ const parsed = isJson ? tryParseJson(request.responseBody) : null;
19
+
20
+ return (
21
+ <div className="flex flex-col gap-2 p-4">
22
+ {request.contentType && (
23
+ <div className="flex items-center gap-2">
24
+ <span className="rounded-md bg-muted px-2 py-0.5 font-mono text-[10px] font-medium text-muted-foreground">
25
+ {request.contentType}
26
+ </span>
27
+ <span className="text-[10px] text-muted-foreground">
28
+ {byteSize(request.responseBody)}
29
+ </span>
30
+ </div>
31
+ )}
32
+ {parsed !== null ? (
33
+ // JsonTree provides collapsible tree + search/copy for structured bodies.
34
+ <JsonTree data={parsed} bordered toolbar="always" compactHeader />
35
+ ) : (
36
+ <div className="overflow-auto rounded-lg border border-border/60 bg-muted/30">
37
+ <pre className="p-4 text-xs leading-relaxed text-foreground">
38
+ <code>{request.responseBody}</code>
39
+ </pre>
40
+ </div>
41
+ )}
42
+ </div>
43
+ );
44
+ }
@@ -0,0 +1,13 @@
1
+ // Adapted from jalcoui (MIT) — github.com/jal-co/ui
2
+
3
+ 'use client';
4
+
5
+ import * as React from 'react';
6
+
7
+ export function EmptyState({ message }: { message: string }) {
8
+ return (
9
+ <div className="flex items-center justify-center py-10 text-sm text-muted-foreground">
10
+ {message}
11
+ </div>
12
+ );
13
+ }
@@ -0,0 +1,78 @@
1
+ // Adapted from jalcoui (MIT) — github.com/jal-co/ui
2
+
3
+ 'use client';
4
+
5
+ import * as React from 'react';
6
+ import { ArrowDown, ArrowUp, type LucideIcon } from 'lucide-react';
7
+ import { cn } from '@djangocfg/ui-core/lib';
8
+ import type { HeaderEntry, NetworkRequest } from '../types';
9
+ import { EmptyState } from './EmptyState';
10
+
11
+ function HeadersTable({
12
+ title,
13
+ headers,
14
+ icon: Icon,
15
+ }: {
16
+ title: string;
17
+ headers: HeaderEntry[];
18
+ icon: LucideIcon;
19
+ }) {
20
+ if (headers.length === 0) return null;
21
+
22
+ return (
23
+ <div className="flex flex-col gap-2">
24
+ <div className="flex items-center gap-1.5">
25
+ <Icon className="size-3.5 text-muted-foreground" />
26
+ <h4 className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
27
+ {title}
28
+ </h4>
29
+ </div>
30
+ <div className="overflow-hidden rounded-lg border border-border/60">
31
+ {headers.map((header, i) => (
32
+ <div
33
+ key={`${header.name}-${i}`}
34
+ className={cn(
35
+ 'flex gap-4 px-3 py-2 text-sm',
36
+ i !== headers.length - 1 && 'border-b border-border/40',
37
+ )}
38
+ >
39
+ <span className="w-[200px] shrink-0 truncate font-mono text-xs font-medium text-foreground">
40
+ {header.name}
41
+ </span>
42
+ <span className="min-w-0 flex-1 break-all font-mono text-xs text-muted-foreground">
43
+ {header.value}
44
+ </span>
45
+ </div>
46
+ ))}
47
+ </div>
48
+ </div>
49
+ );
50
+ }
51
+
52
+ export function HeadersTab({ request }: { request: NetworkRequest }) {
53
+ const hasRequest = (request.requestHeaders?.length ?? 0) > 0;
54
+ const hasResponse = (request.responseHeaders?.length ?? 0) > 0;
55
+
56
+ if (!hasRequest && !hasResponse) {
57
+ return <EmptyState message="No headers available." />;
58
+ }
59
+
60
+ return (
61
+ <div className="flex flex-col gap-5 p-4">
62
+ {hasRequest && (
63
+ <HeadersTable
64
+ title="Request Headers"
65
+ headers={request.requestHeaders!}
66
+ icon={ArrowUp}
67
+ />
68
+ )}
69
+ {hasResponse && (
70
+ <HeadersTable
71
+ title="Response Headers"
72
+ headers={request.responseHeaders!}
73
+ icon={ArrowDown}
74
+ />
75
+ )}
76
+ </div>
77
+ );
78
+ }
@@ -0,0 +1,113 @@
1
+ // Adapted from jalcoui (MIT) — github.com/jal-co/ui
2
+
3
+ 'use client';
4
+
5
+ import * as React from 'react';
6
+ import { useStylePresets } from '@djangocfg/ui-core/styles/palette';
7
+ import { cn } from '@djangocfg/ui-core/lib';
8
+ import type { NetworkRequest } from '../types';
9
+ import { EmptyState } from './EmptyState';
10
+ import { formatDuration } from './utils';
11
+
12
+ /**
13
+ * Categorical palette for timing phases (DNS, TCP, TLS, …). Stages are not
14
+ * statuses, so we route through `useStylePresets()` — 8 distinguishable hex
15
+ * colors that respect the active theme. Indices wrap modulo length.
16
+ */
17
+ function useStagePalette(): string[] {
18
+ const presets = useStylePresets();
19
+ return React.useMemo(
20
+ () => [
21
+ presets.primary.fill,
22
+ presets.success.fill,
23
+ presets.warning.fill,
24
+ presets.danger.fill,
25
+ presets.info.fill,
26
+ presets.chart3.fill,
27
+ presets.chart4.fill,
28
+ presets.chart5.fill,
29
+ ],
30
+ [presets],
31
+ );
32
+ }
33
+
34
+ export function TimingTab({ request }: { request: NetworkRequest }) {
35
+ const stagePalette = useStagePalette();
36
+
37
+ if (!request.timing || request.timing.length === 0) {
38
+ return <EmptyState message="No timing data available." />;
39
+ }
40
+
41
+ const timing = request.timing;
42
+ const maxDuration = Math.max(...timing.map((t) => t.duration));
43
+ const totalDuration =
44
+ request.duration ?? timing.reduce((sum, t) => sum + t.duration, 0);
45
+
46
+ return (
47
+ <div className="flex flex-col gap-4 p-4">
48
+ {/* Total */}
49
+ <div className="flex items-baseline justify-between">
50
+ <span className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
51
+ Total Duration
52
+ </span>
53
+ <span className="font-mono text-sm font-semibold text-foreground">
54
+ {formatDuration(totalDuration)}
55
+ </span>
56
+ </div>
57
+
58
+ {/* Waterfall */}
59
+ <div className="flex flex-col gap-2.5">
60
+ {timing.map((entry, i) => {
61
+ const percentage =
62
+ maxDuration > 0 ? (entry.duration / maxDuration) * 100 : 0;
63
+ const color = stagePalette[i % stagePalette.length];
64
+
65
+ return (
66
+ <div
67
+ key={`${entry.label}-${i}`}
68
+ className="flex items-center gap-3"
69
+ >
70
+ <span className="w-[120px] shrink-0 truncate text-xs text-muted-foreground">
71
+ {entry.label}
72
+ </span>
73
+ <div className="relative h-5 flex-1 overflow-hidden rounded-md bg-muted/50">
74
+ <div
75
+ className={cn('h-full rounded-md transition-all')}
76
+ style={{
77
+ width: `${Math.max(percentage, 2)}%`,
78
+ opacity: percentage === 0 ? 0.3 : 1,
79
+ backgroundColor: color,
80
+ }}
81
+ />
82
+ </div>
83
+ <span className="w-[64px] shrink-0 text-right font-mono text-xs text-muted-foreground">
84
+ {formatDuration(entry.duration)}
85
+ </span>
86
+ </div>
87
+ );
88
+ })}
89
+ </div>
90
+
91
+ {/* Legend */}
92
+ <div className="flex flex-wrap gap-3 border-t border-border/40 pt-3">
93
+ {timing.map((entry, i) => {
94
+ const color = stagePalette[i % stagePalette.length];
95
+ return (
96
+ <div
97
+ key={`legend-${entry.label}-${i}`}
98
+ className="flex items-center gap-1.5"
99
+ >
100
+ <span
101
+ className="size-2.5 rounded-full"
102
+ style={{ backgroundColor: color }}
103
+ />
104
+ <span className="text-[10px] text-muted-foreground">
105
+ {entry.label}
106
+ </span>
107
+ </div>
108
+ );
109
+ })}
110
+ </div>
111
+ </div>
112
+ );
113
+ }
@@ -0,0 +1,31 @@
1
+ // Adapted from jalcoui (MIT) — github.com/jal-co/ui
2
+
3
+ /** Format milliseconds for human reading: µs / ms / s. */
4
+ export function formatDuration(ms: number): string {
5
+ if (ms < 1) return `${(ms * 1000).toFixed(0)}µs`;
6
+ if (ms < 1000) return `${ms.toFixed(ms < 10 ? 1 : 0)}ms`;
7
+ return `${(ms / 1000).toFixed(2)}s`;
8
+ }
9
+
10
+ export function byteSize(str: string): string {
11
+ const bytes = new Blob([str]).size;
12
+ if (bytes < 1024) return `${bytes} B`;
13
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
14
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
15
+ }
16
+
17
+ export function looksLikeJson(str: string): boolean {
18
+ const trimmed = str.trim();
19
+ return (
20
+ (trimmed.startsWith('{') && trimmed.endsWith('}')) ||
21
+ (trimmed.startsWith('[') && trimmed.endsWith(']'))
22
+ );
23
+ }
24
+
25
+ export function tryParseJson(str: string): unknown | null {
26
+ try {
27
+ return JSON.parse(str);
28
+ } catch {
29
+ return null;
30
+ }
31
+ }
@@ -0,0 +1,16 @@
1
+ // Adapted from jalcoui (MIT) — github.com/jal-co/ui
2
+
3
+ export { RequestViewer } from './RequestViewer';
4
+ export {
5
+ STATUS_TONE_PILL,
6
+ METHOD_TONE_TEXT,
7
+ } from './types';
8
+ export type {
9
+ RequestViewerProps,
10
+ RequestViewerTab,
11
+ NetworkRequest,
12
+ HeaderEntry,
13
+ TimingEntry,
14
+ HttpMethodTone,
15
+ HttpStatusTone,
16
+ } from './types';
@@ -0,0 +1,30 @@
1
+ // Adapted from jalcoui (MIT) — github.com/jal-co/ui
2
+
3
+ 'use client';
4
+
5
+ import { createLazyComponent } from '../../../../common/lazy-wrapper';
6
+ import type { RequestViewerProps } from './types';
7
+
8
+ export const LazyRequestViewer = createLazyComponent<RequestViewerProps>(
9
+ () =>
10
+ import('./RequestViewer').then((mod) => ({
11
+ default: mod.RequestViewer,
12
+ })),
13
+ {
14
+ displayName: 'LazyRequestViewer',
15
+ fallback: (
16
+ <div
17
+ data-slot="request-viewer-skeleton"
18
+ className="h-64 w-full animate-pulse rounded-xl bg-muted"
19
+ />
20
+ ),
21
+ },
22
+ );
23
+
24
+ export type {
25
+ RequestViewerProps,
26
+ RequestViewerTab,
27
+ NetworkRequest,
28
+ HeaderEntry,
29
+ TimingEntry,
30
+ } from './types';
@@ -0,0 +1,81 @@
1
+ // Adapted from jalcoui (MIT) — github.com/jal-co/ui
2
+
3
+ import type * as React from 'react';
4
+ import type { HttpMethodTone, HttpStatusTone } from '../../../../lib/http';
5
+
6
+ /** Single key/value header pair. */
7
+ export interface HeaderEntry {
8
+ name: string;
9
+ value: string;
10
+ }
11
+
12
+ /** A timing phase for the request lifecycle (DNS, TCP, TLS, …). */
13
+ export interface TimingEntry {
14
+ /** Label for this timing phase (e.g. "DNS Lookup", "TLS Handshake"). */
15
+ label: string;
16
+ /** Duration in milliseconds. */
17
+ duration: number;
18
+ }
19
+
20
+ /**
21
+ * A captured network request — already-executed. The viewer never fetches.
22
+ */
23
+ export interface NetworkRequest {
24
+ /** HTTP method (GET, POST, etc.). Case-insensitive. */
25
+ method: string;
26
+ /** Full request URL. */
27
+ url: string;
28
+ /** HTTP status code. */
29
+ status: number;
30
+ /** HTTP status text (e.g. "OK", "Not Found"). */
31
+ statusText?: string;
32
+ /** Request headers. */
33
+ requestHeaders?: HeaderEntry[];
34
+ /** Response headers. */
35
+ responseHeaders?: HeaderEntry[];
36
+ /** Response body as a string (raw text or JSON-encoded text). */
37
+ responseBody?: string;
38
+ /** Content type of the response (used for display hints). */
39
+ contentType?: string;
40
+ /** Timing breakdown for the request lifecycle. */
41
+ timing?: TimingEntry[];
42
+ /** Total request duration in milliseconds. */
43
+ duration?: number;
44
+ }
45
+
46
+ export type RequestViewerTab = 'headers' | 'body' | 'timing';
47
+
48
+ export interface RequestViewerProps
49
+ extends Omit<React.ComponentProps<'div'>, 'children'> {
50
+ /** Network request data to display. */
51
+ request: NetworkRequest;
52
+ /** Initial active tab. Defaults to "headers". */
53
+ defaultTab?: RequestViewerTab;
54
+ }
55
+
56
+ // Re-export the HTTP tone types for callers that need them.
57
+ export type { HttpMethodTone, HttpStatusTone };
58
+
59
+ /**
60
+ * Map an HTTP status tone → background+text class pair for the status pill.
61
+ * Uses opacity-derived surfaces so every theme preset renders correctly
62
+ * even when `--{status}-background` is undefined.
63
+ */
64
+ export const STATUS_TONE_PILL: Record<HttpStatusTone, string> = {
65
+ success: 'bg-success/15 text-success',
66
+ info: 'bg-info/15 text-info',
67
+ warning: 'bg-warning/15 text-warning',
68
+ destructive: 'bg-destructive/15 text-destructive',
69
+ muted: 'bg-muted text-muted-foreground',
70
+ };
71
+
72
+ /**
73
+ * Map an HTTP method tone → text-only class. Method label has no background.
74
+ */
75
+ export const METHOD_TONE_TEXT: Record<HttpMethodTone, string> = {
76
+ success: 'text-success',
77
+ info: 'text-info',
78
+ warning: 'text-warning',
79
+ destructive: 'text-destructive',
80
+ muted: 'text-muted-foreground',
81
+ };
@@ -0,0 +1,144 @@
1
+ // Adapted from jalcoui (MIT) — github.com/jal-co/ui
2
+ //
3
+ // Line-by-line code diff viewer. Supports unified (single column) and
4
+ // split (side-by-side) layouts. Syntax highlighting reuses the same
5
+ // `prism-react-renderer` bundle that the `PrettyCode` tool already
6
+ // pulls in — no second highlighter is loaded.
7
+ //
8
+ // Requires <UiProviders> at the host root (no nested providers here).
9
+ // See CONTRACT.md §5.
10
+ //
11
+ // Unlike `PrettyCode` (intentionally always-dark), DiffViewer adapts to
12
+ // the host theme. Diffs are commonly embedded in documentation pages
13
+ // where forcing a dark surface on a light page reads as a bug. The
14
+ // Prism theme is picked per host theme (`themes.vsDark` for dark,
15
+ // `themes.github` for light) and surface chrome uses semantic tokens.
16
+
17
+ 'use client';
18
+
19
+ import * as React from 'react';
20
+ import { themes, type PrismTheme } from 'prism-react-renderer';
21
+ import { cn } from '@djangocfg/ui-core/lib';
22
+ import { useResolvedTheme } from '@djangocfg/ui-core/hooks';
23
+ import { CopyButton } from './components/CopyButton';
24
+ import { SplitView } from './components/SplitView';
25
+ import { UnifiedView } from './components/UnifiedView';
26
+ import { useDiff } from './hooks/useDiff';
27
+ import { useDiffLanguage } from './hooks/useHighlighter';
28
+ import {
29
+ DIFF_TONE_CLASSES,
30
+ type DiffInput,
31
+ type DiffViewerProps,
32
+ } from './types';
33
+
34
+ export function DiffViewer({
35
+ layout = 'unified',
36
+ language,
37
+ oldTitle,
38
+ newTitle,
39
+ copyable = true,
40
+ context = 3,
41
+ className,
42
+ ...allProps
43
+ }: DiffViewerProps) {
44
+ // Split the diff-input keys off the DOM rest props so we don't spread
45
+ // `oldCode` / `newCode` / `patch` onto the wrapping <div>.
46
+ const { oldCode, newCode, patch, ...divProps } =
47
+ allProps as DiffViewerProps & Record<string, unknown>;
48
+ const input: DiffInput =
49
+ patch !== undefined
50
+ ? ({ patch: patch as string } as DiffInput)
51
+ : ({
52
+ oldCode: (oldCode as string) ?? '',
53
+ newCode: (newCode as string) ?? '',
54
+ } as DiffInput);
55
+
56
+ const { lines, numWidth, stats } = useDiff({ input, context });
57
+
58
+ // Pass `null` when no language → cheap plain-text render path.
59
+ const prismLang = useDiffLanguage(language);
60
+ const resolvedLanguage = language ? prismLang : null;
61
+
62
+ // Pick a Prism palette to match the host theme. Resolved once at the
63
+ // viewer root, then forwarded to every line — keeps the hook out of
64
+ // per-line render paths (could be thousands of rows on big diffs).
65
+ const resolved = useResolvedTheme();
66
+ const prismTheme: PrismTheme =
67
+ resolved === 'dark' ? themes.vsDark : themes.github;
68
+
69
+ // Full text used for the copy button — concatenates current lines as
70
+ // displayed, including removed ones. Mirrors jalcoui's behavior.
71
+ const fullCode = React.useMemo(
72
+ () => lines.map((l) => l.content).join('\n'),
73
+ [lines],
74
+ );
75
+
76
+ const showHeader = Boolean(oldTitle || newTitle);
77
+ const addedTone = DIFF_TONE_CLASSES.added.stat;
78
+ const removedTone = DIFF_TONE_CLASSES.removed.stat;
79
+
80
+ return (
81
+ <div
82
+ data-slot="diff-viewer"
83
+ data-layout={layout}
84
+ className={cn(
85
+ 'relative overflow-hidden rounded-xl border border-border/60 bg-card text-foreground shadow-sm',
86
+ className,
87
+ )}
88
+ {...(divProps as React.ComponentProps<'div'>)}
89
+ >
90
+ {showHeader && (
91
+ <div className="flex items-center justify-between gap-3 border-b border-border/60 bg-muted/40 px-4 py-2.5">
92
+ <div className="flex items-center gap-3 text-sm">
93
+ {oldTitle && (
94
+ <span className="text-muted-foreground">{oldTitle}</span>
95
+ )}
96
+ {oldTitle && newTitle && (
97
+ <span className="text-muted-foreground/60" aria-hidden="true">
98
+
99
+ </span>
100
+ )}
101
+ {newTitle && (
102
+ <span className="font-medium text-foreground">{newTitle}</span>
103
+ )}
104
+ </div>
105
+ <div className="flex items-center gap-3">
106
+ <div className="flex items-center gap-2 text-xs tabular-nums">
107
+ {stats.added > 0 && (
108
+ <span className={addedTone}>+{stats.added}</span>
109
+ )}
110
+ {stats.removed > 0 && (
111
+ <span className={removedTone}>-{stats.removed}</span>
112
+ )}
113
+ </div>
114
+ {copyable && <CopyButton value={fullCode} />}
115
+ </div>
116
+ </div>
117
+ )}
118
+
119
+ {!showHeader && copyable && (
120
+ <div className="absolute right-2 top-2 z-10">
121
+ <CopyButton value={fullCode} />
122
+ </div>
123
+ )}
124
+
125
+ <div className="overflow-x-auto">
126
+ {layout === 'split' ? (
127
+ <SplitView
128
+ lines={lines}
129
+ numWidth={numWidth}
130
+ language={resolvedLanguage}
131
+ prismTheme={prismTheme}
132
+ />
133
+ ) : (
134
+ <UnifiedView
135
+ lines={lines}
136
+ numWidth={numWidth}
137
+ language={resolvedLanguage}
138
+ prismTheme={prismTheme}
139
+ />
140
+ )}
141
+ </div>
142
+ </div>
143
+ );
144
+ }