@djangocfg/ui-tools 2.1.417 → 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 (335) hide show
  1. package/dist/audio-player/index.cjs +1 -2
  2. package/dist/audio-player/index.cjs.map +1 -1
  3. package/dist/audio-player/index.d.cts +3 -11
  4. package/dist/audio-player/index.d.ts +3 -11
  5. package/dist/audio-player/index.mjs +1 -2
  6. package/dist/audio-player/index.mjs.map +1 -1
  7. package/dist/file-icon/index.cjs +3 -3
  8. package/dist/file-icon/index.cjs.map +1 -1
  9. package/dist/file-icon/index.mjs +3 -3
  10. package/dist/file-icon/index.mjs.map +1 -1
  11. package/dist/tree/index.cjs +0 -3
  12. package/dist/tree/index.cjs.map +1 -1
  13. package/dist/tree/index.mjs +0 -3
  14. package/dist/tree/index.mjs.map +1 -1
  15. package/package.json +117 -36
  16. package/src/common/FloatingToolbar/actions/CopyAction.tsx +31 -0
  17. package/src/{components → common}/FloatingToolbar/actions/DownloadAction.tsx +15 -10
  18. package/src/common/FloatingToolbar/actions/ExpandAction.tsx +33 -0
  19. package/src/common/FloatingToolbar/actions/FullscreenAction.tsx +38 -0
  20. package/src/{components → common}/FloatingToolbar/index.tsx +39 -0
  21. package/src/lib/http.ts +64 -0
  22. package/src/tools/chat/index.ts +1 -1
  23. package/src/tools/chat/launcher/ChatFAB.tsx +66 -74
  24. package/src/tools/chat/launcher/header/ChatHeaderActionButton.tsx +2 -3
  25. package/src/tools/chat/lazy.tsx +1 -1
  26. package/src/tools/chat/messages/MessageBubble.tsx +1 -1
  27. package/src/tools/chat/messages/blocks/builtin.tsx +1 -1
  28. package/src/tools/chat/messages/blocks/renderers/CodeBlock.tsx +2 -2
  29. package/src/tools/chat/messages/blocks/renderers/JsonBlock.tsx +12 -1
  30. package/src/tools/data/DataGrid/lazy.tsx +1 -1
  31. package/src/tools/data/DataTable/lazy.tsx +1 -1
  32. package/src/tools/data/JsonTree/JsonViewer.tsx +720 -0
  33. package/src/tools/data/JsonTree/README.md +126 -73
  34. package/src/tools/data/JsonTree/index.tsx +3 -95
  35. package/src/tools/data/JsonTree/lazy.tsx +10 -50
  36. package/src/tools/data/JsonTree/types.ts +82 -63
  37. package/src/tools/data/Kanban/lazy.tsx +1 -1
  38. package/src/tools/data/Listbox/lazy.tsx +1 -1
  39. package/src/tools/data/Masonry/lazy.tsx +1 -1
  40. package/src/tools/data/Timeline/lazy.tsx +1 -1
  41. package/src/tools/data/Tree/components/TreeRow.tsx +0 -11
  42. package/src/tools/data/Tree/lazy.tsx +1 -1
  43. package/src/tools/dev/Map/lazy.tsx +1 -1
  44. package/src/tools/dev/Mermaid/Mermaid.client.tsx +2 -2
  45. package/src/tools/dev/Mermaid/lazy.tsx +1 -1
  46. package/src/tools/dev/api/ApiRefTable/ApiRefTable.tsx +65 -0
  47. package/src/tools/dev/api/ApiRefTable/README.md +31 -0
  48. package/src/tools/dev/api/ApiRefTable/components/Row.tsx +96 -0
  49. package/src/tools/dev/api/ApiRefTable/components/TypeDisplay.tsx +44 -0
  50. package/src/tools/dev/api/ApiRefTable/index.ts +6 -0
  51. package/src/tools/dev/api/ApiRefTable/lazy.tsx +21 -0
  52. package/src/tools/dev/api/ApiRefTable/types.ts +82 -0
  53. package/src/tools/dev/api/ApiRefTable/utils.ts +42 -0
  54. package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/ApiIntroSection.tsx +1 -1
  55. package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/CodeSamples/index.tsx +1 -1
  56. package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Header/index.tsx +1 -1
  57. package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Responses/ResponseBody.tsx +7 -21
  58. package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/RequestPanel.tsx +1 -1
  59. package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/PrettyView.tsx +13 -19
  60. package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/types.ts +1 -1
  61. package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/lazy.tsx +1 -1
  62. package/src/tools/dev/api/RequestViewer/README.md +33 -0
  63. package/src/tools/dev/api/RequestViewer/RequestViewer.tsx +121 -0
  64. package/src/tools/dev/api/RequestViewer/components/BodyTab.tsx +44 -0
  65. package/src/tools/dev/api/RequestViewer/components/EmptyState.tsx +13 -0
  66. package/src/tools/dev/api/RequestViewer/components/HeadersTab.tsx +78 -0
  67. package/src/tools/dev/api/RequestViewer/components/TimingTab.tsx +113 -0
  68. package/src/tools/dev/api/RequestViewer/components/utils.ts +31 -0
  69. package/src/tools/dev/api/RequestViewer/index.ts +16 -0
  70. package/src/tools/dev/api/RequestViewer/lazy.tsx +30 -0
  71. package/src/tools/dev/api/RequestViewer/types.ts +81 -0
  72. package/src/tools/dev/code/DiffViewer/DiffViewer.tsx +144 -0
  73. package/src/tools/dev/code/DiffViewer/README.md +33 -0
  74. package/src/tools/dev/code/DiffViewer/components/CopyButton.tsx +49 -0
  75. package/src/tools/dev/code/DiffViewer/components/DiffLineContent.tsx +48 -0
  76. package/src/tools/dev/code/DiffViewer/components/SplitView.tsx +220 -0
  77. package/src/tools/dev/code/DiffViewer/components/UnifiedView.tsx +154 -0
  78. package/src/tools/dev/code/DiffViewer/hooks/useDiff.ts +47 -0
  79. package/src/tools/dev/code/DiffViewer/hooks/useHighlighter.ts +54 -0
  80. package/src/tools/dev/code/DiffViewer/index.ts +22 -0
  81. package/src/tools/dev/code/DiffViewer/lazy.tsx +22 -0
  82. package/src/tools/dev/code/DiffViewer/types.ts +109 -0
  83. package/src/tools/dev/code/DiffViewer/utils/computeDiff.ts +159 -0
  84. package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/CollapseToggle.tsx +1 -1
  85. package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/MarkdownMessage.tsx +1 -1
  86. package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/components.tsx +2 -2
  87. package/src/tools/dev/{PrettyCode → code/PrettyCode}/PrettyCode.client.tsx +2 -2
  88. package/src/tools/dev/{PrettyCode → code/PrettyCode}/lazy.tsx +1 -1
  89. package/src/tools/dev/ops/EnvTable/EnvTable.tsx +228 -0
  90. package/src/tools/dev/ops/EnvTable/README.md +29 -0
  91. package/src/tools/dev/ops/EnvTable/hooks/useEnvMask.ts +121 -0
  92. package/src/tools/dev/ops/EnvTable/index.ts +12 -0
  93. package/src/tools/dev/ops/EnvTable/lazy.tsx +21 -0
  94. package/src/tools/dev/ops/EnvTable/types.ts +76 -0
  95. package/src/tools/dev/ops/LogViewer/LogViewer.tsx +194 -0
  96. package/src/tools/dev/ops/LogViewer/README.md +30 -0
  97. package/src/tools/dev/ops/LogViewer/components/LogRow.tsx +151 -0
  98. package/src/tools/dev/ops/LogViewer/components/Toolbar.tsx +199 -0
  99. package/src/tools/dev/ops/LogViewer/hooks/useAutoScroll.ts +68 -0
  100. package/src/tools/dev/ops/LogViewer/hooks/useLogFilter.ts +58 -0
  101. package/src/tools/dev/ops/LogViewer/index.ts +18 -0
  102. package/src/tools/dev/ops/LogViewer/lazy.tsx +25 -0
  103. package/src/tools/dev/ops/LogViewer/types.ts +142 -0
  104. package/src/tools/dev/ops/LogViewer/utils/ansi.ts +231 -0
  105. package/src/tools/forms/CodeEditor/components/Editor.tsx +19 -0
  106. package/src/tools/forms/CodeEditor/hooks/useEditorTheme.ts +13 -73
  107. package/src/tools/forms/CodeEditor/lazy.tsx +1 -1
  108. package/src/tools/forms/CodeEditor/types/index.ts +7 -0
  109. package/src/tools/forms/FileUpload/lazy.tsx +1 -1
  110. package/src/tools/forms/JsonEditor/JsonEditor.tsx +115 -0
  111. package/src/tools/forms/JsonEditor/index.ts +1 -0
  112. package/src/tools/forms/JsonEditor/lazy.tsx +24 -0
  113. package/src/tools/forms/JsonForm/index.ts +1 -1
  114. package/src/tools/forms/JsonForm/lazy.tsx +1 -1
  115. package/src/tools/forms/MarkdownEditor/MarkdownEditor.tsx +40 -0
  116. package/src/tools/forms/MarkdownEditor/lazy.tsx +1 -1
  117. package/src/tools/forms/MarkdownEditor/styles.css +174 -21
  118. package/src/tools/forms/NotionEditor/CustomKeymap.ts +48 -0
  119. package/src/tools/forms/NotionEditor/LinkDialog.tsx +133 -0
  120. package/src/tools/forms/NotionEditor/NotionEditor.tsx +304 -0
  121. package/src/tools/forms/NotionEditor/README.md +237 -0
  122. package/src/tools/forms/NotionEditor/SlashExtension.ts +32 -0
  123. package/src/tools/forms/NotionEditor/SlashList.tsx +136 -0
  124. package/src/tools/forms/NotionEditor/TaskItemView.tsx +41 -0
  125. package/src/tools/forms/NotionEditor/createSlashSuggestion.ts +121 -0
  126. package/src/tools/forms/NotionEditor/extensions.ts +105 -0
  127. package/src/tools/forms/NotionEditor/index.ts +1 -0
  128. package/src/tools/forms/NotionEditor/lazy.tsx +44 -0
  129. package/src/tools/forms/NotionEditor/slashItems.ts +159 -0
  130. package/src/tools/forms/NotionEditor/styles.css +478 -0
  131. package/src/tools/forms/NotionEditor/types.ts +28 -0
  132. package/src/tools/index.ts +153 -13
  133. package/src/tools/input/Combobox/lazy.tsx +1 -1
  134. package/src/tools/input/CronScheduler/components/CronPreview.README.md +28 -0
  135. package/src/tools/input/CronScheduler/components/CronPreview.tsx +136 -0
  136. package/src/tools/input/CronScheduler/components/index.ts +3 -0
  137. package/src/tools/input/CronScheduler/index.tsx +5 -1
  138. package/src/tools/input/CronScheduler/lazy.tsx +5 -1
  139. package/src/tools/input/CronScheduler/utils/cron-next-runs.ts +122 -0
  140. package/src/tools/input/CronScheduler/utils/index.ts +1 -0
  141. package/src/tools/input/Scroller/lazy.tsx +1 -1
  142. package/src/tools/input/Sortable/lazy.tsx +1 -1
  143. package/src/tools/input/SpeechRecognition/lazy.tsx +1 -1
  144. package/src/tools/input/SpeechRecognition/widgets/VoiceComposerSlot.tsx +41 -36
  145. package/src/tools/media/AudioPlayer/PlayerShell.tsx +3 -11
  146. package/src/tools/media/AudioPlayer/types.ts +4 -11
  147. package/src/tools/media/ImageViewer/components/ImageToolbar.tsx +58 -47
  148. package/src/tools/media/ImageViewer/components/ImageViewer.tsx +35 -19
  149. package/src/tools/media/ImageViewer/lazy.tsx +1 -1
  150. package/src/tools/media/ImageViewer/types.ts +4 -0
  151. package/src/tools/media/LottiePlayer/lazy.tsx +1 -1
  152. package/src/tools/media/VideoPlayer/VideoPlayer.tsx +47 -1
  153. package/src/tools/media/VideoPlayer/parts/fullscreen.tsx +21 -4
  154. package/src/tools/media/VideoPlayer/parts/pip.tsx +21 -4
  155. package/src/tools/media/VideoPlayer/parts/play-button.tsx +21 -4
  156. package/src/tools/media/VideoPlayer/parts/playback-rate.tsx +19 -3
  157. package/src/tools/media/VideoPlayer/parts/volume.tsx +237 -18
  158. package/src/tools/media/VideoPlayer/styles/video-player.css +87 -7
  159. package/src/tools/media/VideoPlayer/types.ts +4 -0
  160. package/src/tools/overlay/ResponsiveDialog/lazy.tsx +1 -1
  161. package/src/tools/overlay/ScrollSpy/lazy.tsx +1 -1
  162. package/src/tools/overlay/SelectionToolbar/lazy.tsx +1 -1
  163. package/src/tools/overlay/Tour/lazy.tsx +1 -1
  164. package/src/tools/visual/Marquee/lazy.tsx +1 -1
  165. package/src/tools/visual/QRCode/lazy.tsx +1 -1
  166. package/src/tools/visual/charts/ActivityGraph/ActivityGraph.tsx +195 -0
  167. package/src/tools/visual/charts/ActivityGraph/README.md +28 -0
  168. package/src/tools/visual/charts/ActivityGraph/index.ts +8 -0
  169. package/src/tools/visual/charts/ActivityGraph/lazy.tsx +21 -0
  170. package/src/tools/visual/charts/ActivityGraph/types.ts +59 -0
  171. package/src/tools/visual/charts/ActivityGraph/utils.ts +88 -0
  172. package/src/tools/visual/charts/CommitGraph/CommitGraph.tsx +80 -0
  173. package/src/tools/visual/charts/CommitGraph/README.md +28 -0
  174. package/src/tools/visual/charts/CommitGraph/components/CommitDetail.tsx +107 -0
  175. package/src/tools/visual/charts/CommitGraph/components/CommitRow.tsx +122 -0
  176. package/src/tools/visual/charts/CommitGraph/components/Rails.tsx +171 -0
  177. package/src/tools/visual/charts/CommitGraph/hooks/useGraphLayout.ts +169 -0
  178. package/src/tools/visual/charts/CommitGraph/hooks/useLaneColors.ts +45 -0
  179. package/src/tools/visual/charts/CommitGraph/index.ts +14 -0
  180. package/src/tools/visual/charts/CommitGraph/lazy.tsx +25 -0
  181. package/src/tools/visual/charts/CommitGraph/types.ts +85 -0
  182. package/src/tools/visual/charts/CommitGraph/utils.ts +53 -0
  183. package/src/tools/visual/{Gauge → charts/Gauge}/lazy.tsx +1 -1
  184. package/src/tools/visual/charts/Sparkline/README.md +29 -0
  185. package/src/tools/visual/charts/Sparkline/Sparkline.tsx +217 -0
  186. package/src/tools/visual/charts/Sparkline/index.ts +9 -0
  187. package/src/tools/visual/charts/Sparkline/lazy.tsx +26 -0
  188. package/src/tools/visual/charts/Sparkline/types.ts +58 -0
  189. package/src/tools/visual/design/ColorPalette/ColorPalette.tsx +129 -0
  190. package/src/tools/visual/design/ColorPalette/README.md +34 -0
  191. package/src/tools/visual/design/ColorPalette/components/Swatch.tsx +102 -0
  192. package/src/tools/visual/design/ColorPalette/hooks/useCopyToClipboard.ts +41 -0
  193. package/src/tools/visual/design/ColorPalette/index.ts +12 -0
  194. package/src/tools/visual/design/ColorPalette/lazy.tsx +21 -0
  195. package/src/tools/visual/design/ColorPalette/types.ts +63 -0
  196. package/src/tools/visual/design/ColorPalette/utils.ts +83 -0
  197. package/src/tools/visual/{ColorPicker → design/ColorPicker}/lazy.tsx +1 -1
  198. package/src/tools/visual/{FileIcon → design/FileIcon}/treeAdapter.tsx +1 -1
  199. package/src/tools/visual/{Fps → indicators/Fps}/lazy.tsx +1 -1
  200. package/src/tools/visual/{Rating → indicators/Rating}/lazy.tsx +1 -1
  201. package/src/tools/visual/indicators/StatusIndicator/README.md +28 -0
  202. package/src/tools/visual/indicators/StatusIndicator/StatusIndicator.tsx +83 -0
  203. package/src/tools/visual/indicators/StatusIndicator/index.ts +14 -0
  204. package/src/tools/visual/indicators/StatusIndicator/lazy.tsx +21 -0
  205. package/src/tools/visual/indicators/StatusIndicator/types.ts +133 -0
  206. package/src/components/FloatingToolbar/actions/CopyAction.tsx +0 -22
  207. package/src/components/FloatingToolbar/actions/ExpandAction.tsx +0 -25
  208. package/src/components/FloatingToolbar/actions/FullscreenAction.tsx +0 -30
  209. package/src/tools/data/JsonTree/components/JsonContent.tsx +0 -197
  210. package/src/tools/data/JsonTree/hooks/useJsonExpand.ts +0 -50
  211. /package/src/{components → common}/FloatingToolbar/FloatingToolbar.css +0 -0
  212. /package/src/{components → common}/FloatingToolbar/actions/index.ts +0 -0
  213. /package/src/{components → common}/FloatingToolbar/hooks/useElementCorner.ts +0 -0
  214. /package/src/{components → common}/FloatingToolbar/hooks/useScrollIsolation.ts +0 -0
  215. /package/src/{components → common}/index.ts +0 -0
  216. /package/src/{components → common}/lazy-wrapper.tsx +0 -0
  217. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/README.md +0 -0
  218. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/DocsView.tsx +0 -0
  219. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/CodeSamples/LanguageTabs.tsx +0 -0
  220. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/CodeSamples/useCodeSnippet.ts +0 -0
  221. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Header/MetaActions.tsx +0 -0
  222. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Header/MethodBadge.tsx +0 -0
  223. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Header/PathDisplay.tsx +0 -0
  224. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Parameters/ParamGroup.tsx +0 -0
  225. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Parameters/ParamRow.tsx +0 -0
  226. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Parameters/index.tsx +0 -0
  227. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/RequestBody/index.tsx +0 -0
  228. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Responses/ResponseRow.tsx +0 -0
  229. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Responses/StatusTag.tsx +0 -0
  230. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Responses/index.tsx +0 -0
  231. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/SchemaFields/FieldRow.tsx +0 -0
  232. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/SchemaFields/buildTree.ts +0 -0
  233. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/SchemaFields/index.tsx +0 -0
  234. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/SchemaFields/types.ts +0 -0
  235. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Section/SectionHeader.tsx +0 -0
  236. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Section/defaults.ts +0 -0
  237. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Section/index.tsx +0 -0
  238. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/context.tsx +0 -0
  239. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/hooks/useSectionHash.ts +0 -0
  240. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/index.tsx +0 -0
  241. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/store/index.ts +0 -0
  242. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/store/selectors.ts +0 -0
  243. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/types.ts +0 -0
  244. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/SchemaCopyMenu.tsx +0 -0
  245. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/BrandHeader.tsx +0 -0
  246. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/CategoryBlock.tsx +0 -0
  247. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/EndpointRow.tsx +0 -0
  248. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/SchemaSection.tsx +0 -0
  249. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/SearchInput.tsx +0 -0
  250. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/SidebarBody.tsx +0 -0
  251. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/Toolbar.tsx +0 -0
  252. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/buildVM.ts +0 -0
  253. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/index.tsx +0 -0
  254. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/types.ts +0 -0
  255. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/useDebouncedValue.ts +0 -0
  256. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/SlideInPlayground.tsx +0 -0
  257. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/TryItSheet.tsx +0 -0
  258. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/anchor.ts +0 -0
  259. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/grouping.ts +0 -0
  260. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/index.tsx +0 -0
  261. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/sidebarLabel.ts +0 -0
  262. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/index.ts +0 -0
  263. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/BodyFormEditor.tsx +0 -0
  264. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/EndpointDraftSync.tsx +0 -0
  265. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/EndpointResetButton.tsx +0 -0
  266. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/PreviewView.tsx +0 -0
  267. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/RawView.tsx +0 -0
  268. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/StatusBar.tsx +0 -0
  269. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/ViewTabs.tsx +0 -0
  270. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/detectContent.ts +0 -0
  271. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/index.tsx +0 -0
  272. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/useResponseView.ts +0 -0
  273. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/SendButton.tsx +0 -0
  274. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ui.tsx +0 -0
  275. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/constants.ts +0 -0
  276. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/context/PlaygroundContext.tsx +0 -0
  277. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/hooks/index.ts +0 -0
  278. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/hooks/useDocsUrlSync.ts +0 -0
  279. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/hooks/useEndpointDraft.ts +0 -0
  280. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/hooks/useMobile.ts +0 -0
  281. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/hooks/useOpenApiSchema.ts +0 -0
  282. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/index.tsx +0 -0
  283. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/types.ts +0 -0
  284. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/apiKeyManager.ts +0 -0
  285. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/codeSamples.ts +0 -0
  286. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/formatters.ts +0 -0
  287. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/index.ts +0 -0
  288. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/operationToHar.ts +0 -0
  289. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/sampler.ts +0 -0
  290. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/schemaExport.ts +0 -0
  291. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/scrollParent.ts +0 -0
  292. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/url.ts +0 -0
  293. /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/versionManager.ts +0 -0
  294. /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/ActionRow.tsx +0 -0
  295. /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/ChatMessageRow.tsx +0 -0
  296. /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/CodeBlock.tsx +0 -0
  297. /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/README.md +0 -0
  298. /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/index.ts +0 -0
  299. /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/linkRules.ts +0 -0
  300. /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/plainText.ts +0 -0
  301. /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/sanitize.ts +0 -0
  302. /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/types.ts +0 -0
  303. /package/src/tools/dev/{PrettyCode → code/PrettyCode}/README.md +0 -0
  304. /package/src/tools/dev/{PrettyCode → code/PrettyCode}/index.tsx +0 -0
  305. /package/src/tools/dev/{PrettyCode → code/PrettyCode}/registerPrismLanguages.ts +0 -0
  306. /package/src/tools/visual/{Gauge → charts/Gauge}/Gauge.tsx +0 -0
  307. /package/src/tools/visual/{Gauge → charts/Gauge}/index.ts +0 -0
  308. /package/src/tools/visual/{Gauge → charts/Gauge}/types.ts +0 -0
  309. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/ColorPicker.tsx +0 -0
  310. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/context/ColorPickerContext.tsx +0 -0
  311. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/context/ColorPickerStore.tsx +0 -0
  312. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/context/index.ts +0 -0
  313. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/index.ts +0 -0
  314. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/lib/color-utils.ts +0 -0
  315. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerAlphaSlider.tsx +0 -0
  316. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerArea.tsx +0 -0
  317. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerEyeDropper.tsx +0 -0
  318. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerFormatSelect.tsx +0 -0
  319. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerHueSlider.tsx +0 -0
  320. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerInput.tsx +0 -0
  321. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerSwatch.tsx +0 -0
  322. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/index.ts +0 -0
  323. /package/src/tools/visual/{ColorPicker → design/ColorPicker}/types.ts +0 -0
  324. /package/src/tools/visual/{FileIcon → design/FileIcon}/FileIcon.tsx +0 -0
  325. /package/src/tools/visual/{FileIcon → design/FileIcon}/get-file-icon.ts +0 -0
  326. /package/src/tools/visual/{FileIcon → design/FileIcon}/icons/icon-data.ts +0 -0
  327. /package/src/tools/visual/{FileIcon → design/FileIcon}/index.ts +0 -0
  328. /package/src/tools/visual/{FileIcon → design/FileIcon}/loader.ts +0 -0
  329. /package/src/tools/visual/{FileIcon → design/FileIcon}/specialFolders.ts +0 -0
  330. /package/src/tools/visual/{Fps → indicators/Fps}/Fps.tsx +0 -0
  331. /package/src/tools/visual/{Fps → indicators/Fps}/index.ts +0 -0
  332. /package/src/tools/visual/{Fps → indicators/Fps}/types.ts +0 -0
  333. /package/src/tools/visual/{Rating → indicators/Rating}/Rating.tsx +0 -0
  334. /package/src/tools/visual/{Rating → indicators/Rating}/index.ts +0 -0
  335. /package/src/tools/visual/{Rating → indicators/Rating}/types.ts +0 -0
@@ -0,0 +1,33 @@
1
+ # DiffViewer
2
+
3
+ Line-by-line diff viewer with unified or split layout. Reuses the `prism-react-renderer` instance from `PrettyCode` for optional syntax highlighting — no second highlighter is loaded.
4
+
5
+ Pass either `oldCode` + `newCode` (computed diff) or a pre-built `patch` string (unified format).
6
+
7
+ ```tsx
8
+ import { DiffViewer } from '@djangocfg/ui-tools/diff-viewer';
9
+
10
+ <DiffViewer
11
+ oldCode="const x = 1;"
12
+ newCode="const x = 2;\nconst y = 3;"
13
+ language="ts"
14
+ layout="unified"
15
+ />
16
+ ```
17
+
18
+ ## Props
19
+
20
+ | Prop | Type | Default | Description |
21
+ |---|---|---|---|
22
+ | `oldCode` / `newCode` | `string` | — | Source pair to diff. Mutually exclusive with `patch`. |
23
+ | `patch` | `string` | — | Pre-computed unified diff. Mutually exclusive with `oldCode`/`newCode`. |
24
+ | `layout` | `'unified' \| 'split'` | `'unified'` | Single column vs side-by-side. |
25
+ | `language` | `Language \| string` | — | Prism language key for highlighting. Omit for plain monospace. |
26
+ | `oldTitle` | `string` | — | LHS file header label. |
27
+ | `newTitle` | `string` | — | RHS file header label. |
28
+
29
+ Storybook: `apps/storybook/stories/ui-tools/dev/DiffViewer.stories.tsx`
30
+
31
+ ---
32
+
33
+ Adapted from jalcoui (MIT).
@@ -0,0 +1,49 @@
1
+ // Adapted from jalcoui (MIT) — github.com/jal-co/ui
2
+
3
+ 'use client';
4
+
5
+ import * as React from 'react';
6
+ import { Check, Copy } from 'lucide-react';
7
+ import { cn } from '@djangocfg/ui-core/lib';
8
+
9
+ interface CopyButtonProps extends Omit<React.ComponentProps<'button'>, 'value'> {
10
+ value: string;
11
+ }
12
+
13
+ /**
14
+ * Tiny copy-to-clipboard button used in the DiffViewer header. Local
15
+ * component (not a hoist of `CopyAction` from `FloatingToolbar`) so the
16
+ * viewer can render without any provider context.
17
+ *
18
+ * Uses semantic tokens — the diff viewer adapts to the host theme,
19
+ * unlike `PrettyCode` which forces dark.
20
+ */
21
+ export function CopyButton({ value, className, ...props }: CopyButtonProps) {
22
+ const [copied, setCopied] = React.useState(false);
23
+
24
+ const handleCopy = React.useCallback(() => {
25
+ void navigator.clipboard.writeText(value).then(() => {
26
+ setCopied(true);
27
+ window.setTimeout(() => setCopied(false), 1500);
28
+ });
29
+ }, [value]);
30
+
31
+ return (
32
+ <button
33
+ type="button"
34
+ onClick={handleCopy}
35
+ data-slot="diff-viewer-copy-button"
36
+ className={cn(
37
+ 'inline-flex items-center gap-1.5 rounded-md px-2 py-1 text-xs transition-colors',
38
+ 'text-muted-foreground hover:text-foreground hover:bg-muted',
39
+ 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/50',
40
+ className,
41
+ )}
42
+ aria-label={copied ? 'Copied' : 'Copy code'}
43
+ {...props}
44
+ >
45
+ {copied ? <Check className="size-3.5" /> : <Copy className="size-3.5" />}
46
+ {copied ? 'Copied' : 'Copy'}
47
+ </button>
48
+ );
49
+ }
@@ -0,0 +1,48 @@
1
+ // Adapted from jalcoui (MIT) — github.com/jal-co/ui
2
+
3
+ 'use client';
4
+
5
+ import * as React from 'react';
6
+ import { Highlight, type Language, type PrismTheme } from 'prism-react-renderer';
7
+
8
+ interface DiffLineContentProps {
9
+ content: string;
10
+ language: Language | null;
11
+ /**
12
+ * Prism palette resolved by the parent `DiffViewer` against the host
13
+ * theme. Forwarded here so we don't run a theme-detection hook on
14
+ * every line (a big diff can be thousands of rows).
15
+ */
16
+ prismTheme: PrismTheme;
17
+ }
18
+
19
+ /**
20
+ * Single-line content cell. When `language` is non-null the line is
21
+ * tokenized by `prism-react-renderer` (the same instance PrettyCode
22
+ * uses). When null we render plain text — cheap path for `language`-less
23
+ * diffs and very large lists.
24
+ *
25
+ * Each line tokenizes independently. For diffs > a few thousand lines
26
+ * this can get warm; in practice the LCS already drops to context lines
27
+ * before we get there.
28
+ */
29
+ export const DiffLineContent = React.memo(function DiffLineContent({
30
+ content,
31
+ language,
32
+ prismTheme,
33
+ }: DiffLineContentProps) {
34
+ if (!language) {
35
+ return <>{content || ' '}</>;
36
+ }
37
+ return (
38
+ <Highlight theme={prismTheme} code={content || ' '} language={language}>
39
+ {({ tokens, getTokenProps }) => (
40
+ <>
41
+ {tokens[0]?.map((token, key) => (
42
+ <span key={key} {...getTokenProps({ token })} />
43
+ ))}
44
+ </>
45
+ )}
46
+ </Highlight>
47
+ );
48
+ });
@@ -0,0 +1,220 @@
1
+ // Adapted from jalcoui (MIT) — github.com/jal-co/ui
2
+
3
+ 'use client';
4
+
5
+ import * as React from 'react';
6
+ import type { Language, PrismTheme } from 'prism-react-renderer';
7
+ import { Virtuoso } from 'react-virtuoso';
8
+ import { cn } from '@djangocfg/ui-core/lib';
9
+ import { DIFF_TONE_CLASSES, type DiffLine } from '../types';
10
+ import { DiffLineContent } from './DiffLineContent';
11
+
12
+ interface SplitViewProps {
13
+ lines: DiffLine[];
14
+ numWidth: number;
15
+ language: Language | null;
16
+ prismTheme: PrismTheme;
17
+ }
18
+
19
+ // See UnifiedView for context — same threshold + viewport size keeps both
20
+ // layouts behaviorally aligned.
21
+ const VIRTUALIZE_THRESHOLD = 100;
22
+ const VIRTUAL_VIEWPORT_HEIGHT = 480;
23
+
24
+ /**
25
+ * Align consecutive `removed` / `added` runs into a pair of columns.
26
+ * Pure-add rows leave the left column empty; pure-remove rows leave the
27
+ * right column empty. Context rows duplicate on both sides.
28
+ *
29
+ * The pairing is the same shape jalcoui ships — we keep it so downstream
30
+ * consumers' visual baseline doesn't move.
31
+ */
32
+ function pairLines(lines: DiffLine[]): Array<{
33
+ left: DiffLine | null;
34
+ right: DiffLine | null;
35
+ }> {
36
+ const pairs: Array<{ left: DiffLine | null; right: DiffLine | null }> = [];
37
+
38
+ let i = 0;
39
+ while (i < lines.length) {
40
+ const line = lines[i];
41
+ if (line.type === 'context') {
42
+ pairs.push({ left: line, right: line });
43
+ i++;
44
+ continue;
45
+ }
46
+ if (line.type === 'removed') {
47
+ const removed: DiffLine[] = [];
48
+ while (i < lines.length && lines[i].type === 'removed') {
49
+ removed.push(lines[i]);
50
+ i++;
51
+ }
52
+ const added: DiffLine[] = [];
53
+ while (i < lines.length && lines[i].type === 'added') {
54
+ added.push(lines[i]);
55
+ i++;
56
+ }
57
+ const maxLen = Math.max(removed.length, added.length);
58
+ for (let j = 0; j < maxLen; j++) {
59
+ pairs.push({
60
+ left: j < removed.length ? removed[j] : null,
61
+ right: j < added.length ? added[j] : null,
62
+ });
63
+ }
64
+ continue;
65
+ }
66
+ // line.type === 'added' with no preceding removed run
67
+ pairs.push({ left: null, right: line });
68
+ i++;
69
+ }
70
+
71
+ return pairs;
72
+ }
73
+
74
+ function sidePrefix(side: 'old' | 'new', type: DiffLine['type'] | undefined) {
75
+ if (!type || type === 'context') return ' ';
76
+ if (side === 'old' && type === 'removed') return '-';
77
+ if (side === 'new' && type === 'added') return '+';
78
+ return ' ';
79
+ }
80
+
81
+ interface HalfProps {
82
+ line: DiffLine | null;
83
+ side: 'old' | 'new';
84
+ numWidth: number;
85
+ language: Language | null;
86
+ prismTheme: PrismTheme;
87
+ }
88
+
89
+ function Half({ line, side, numWidth, language, prismTheme }: HalfProps) {
90
+ const tone = line ? DIFF_TONE_CLASSES[line.type] : DIFF_TONE_CLASSES.context;
91
+ const gutterCh = `calc(${numWidth}ch + 1rem)`;
92
+ return (
93
+ <div
94
+ className={cn('grid items-start min-w-0', tone.row)}
95
+ style={{
96
+ gridTemplateColumns: `${gutterCh} 1.5rem minmax(0, 1fr)`,
97
+ }}
98
+ >
99
+ <div
100
+ className={cn(
101
+ 'select-none px-2 text-right tabular-nums whitespace-nowrap',
102
+ tone.num,
103
+ )}
104
+ >
105
+ {(side === 'old' ? line?.oldNumber : line?.newNumber) ?? ''}
106
+ </div>
107
+ <div
108
+ className={cn(
109
+ 'select-none text-center whitespace-nowrap',
110
+ tone.num,
111
+ )}
112
+ >
113
+ {sidePrefix(side, line?.type)}
114
+ </div>
115
+ <div
116
+ className={cn(
117
+ 'whitespace-pre px-3 overflow-x-auto',
118
+ line ? tone.text : 'text-muted-foreground/40',
119
+ )}
120
+ >
121
+ {line ? (
122
+ <DiffLineContent
123
+ content={line.content}
124
+ language={language}
125
+ prismTheme={prismTheme}
126
+ />
127
+ ) : (
128
+ ' '
129
+ )}
130
+ </div>
131
+ </div>
132
+ );
133
+ }
134
+
135
+ interface PairRowProps {
136
+ pair: { left: DiffLine | null; right: DiffLine | null };
137
+ numWidth: number;
138
+ language: Language | null;
139
+ prismTheme: PrismTheme;
140
+ }
141
+
142
+ function PairRow({ pair, numWidth, language, prismTheme }: PairRowProps) {
143
+ return (
144
+ <div className="grid grid-cols-2 font-mono text-[13px] leading-relaxed">
145
+ <div className="border-r border-border/40 min-w-0">
146
+ <Half
147
+ line={pair.left}
148
+ side="old"
149
+ numWidth={numWidth}
150
+ language={language}
151
+ prismTheme={prismTheme}
152
+ />
153
+ </div>
154
+ <div className="min-w-0">
155
+ <Half
156
+ line={pair.right}
157
+ side="new"
158
+ numWidth={numWidth}
159
+ language={language}
160
+ prismTheme={prismTheme}
161
+ />
162
+ </div>
163
+ </div>
164
+ );
165
+ }
166
+
167
+ /**
168
+ * Side-by-side diff. Left half = old, right half = new. Each row is a
169
+ * single grid wrapping two `<Half>` halves so a `<Virtuoso>` list can
170
+ * virtualize the whole stack with naturally synchronized scrolling.
171
+ *
172
+ * Both halves receive the SAME globally-computed `numWidth` so the two
173
+ * gutter columns are pixel-identical regardless of which side has the
174
+ * longer line numbers.
175
+ */
176
+ export function SplitView({
177
+ lines,
178
+ numWidth,
179
+ language,
180
+ prismTheme,
181
+ }: SplitViewProps) {
182
+ const pairs = React.useMemo(() => pairLines(lines), [lines]);
183
+
184
+ if (pairs.length > VIRTUALIZE_THRESHOLD) {
185
+ return (
186
+ <div data-slot="diff-viewer-split">
187
+ <Virtuoso
188
+ data={pairs}
189
+ style={{ height: VIRTUAL_VIEWPORT_HEIGHT }}
190
+ // See UnifiedView for why `initialItemCount` is required —
191
+ // without it, embedded iframes start with a zero-height list.
192
+ initialItemCount={Math.min(pairs.length, 30)}
193
+ itemContent={(_, pair) => (
194
+ <PairRow
195
+ pair={pair}
196
+ numWidth={numWidth}
197
+ language={language}
198
+ prismTheme={prismTheme}
199
+ />
200
+ )}
201
+ increaseViewportBy={{ top: 200, bottom: 400 }}
202
+ />
203
+ </div>
204
+ );
205
+ }
206
+
207
+ return (
208
+ <div data-slot="diff-viewer-split">
209
+ {pairs.map((pair, idx) => (
210
+ <PairRow
211
+ key={idx}
212
+ pair={pair}
213
+ numWidth={numWidth}
214
+ language={language}
215
+ prismTheme={prismTheme}
216
+ />
217
+ ))}
218
+ </div>
219
+ );
220
+ }
@@ -0,0 +1,154 @@
1
+ // Adapted from jalcoui (MIT) — github.com/jal-co/ui
2
+
3
+ 'use client';
4
+
5
+ import * as React from 'react';
6
+ import type { Language, PrismTheme } from 'prism-react-renderer';
7
+ import { Virtuoso } from 'react-virtuoso';
8
+ import { cn } from '@djangocfg/ui-core/lib';
9
+ import { DIFF_TONE_CLASSES, type DiffLine } from '../types';
10
+ import { DiffLineContent } from './DiffLineContent';
11
+
12
+ interface UnifiedViewProps {
13
+ lines: DiffLine[];
14
+ numWidth: number;
15
+ language: Language | null;
16
+ prismTheme: PrismTheme;
17
+ }
18
+
19
+ function linePrefix(type: DiffLine['type']) {
20
+ if (type === 'added') return '+';
21
+ if (type === 'removed') return '-';
22
+ return ' ';
23
+ }
24
+
25
+ // Threshold above which we switch from a plain DOM table to a virtualized
26
+ // list. Mirrors LogViewer — under this size the DOM stays debuggable;
27
+ // above it tokenization + layout of thousands of rows starts to dominate
28
+ // scroll.
29
+ const VIRTUALIZE_THRESHOLD = 100;
30
+ // Height of the scrolling viewport when virtualized. Kept here (not a prop)
31
+ // because every existing consumer expects the viewer to expand to its
32
+ // content; only the >100-line path needs a fixed window to virtualize.
33
+ const VIRTUAL_VIEWPORT_HEIGHT = 480;
34
+
35
+ interface RowProps {
36
+ line: DiffLine;
37
+ numWidth: number;
38
+ language: Language | null;
39
+ prismTheme: PrismTheme;
40
+ }
41
+
42
+ /**
43
+ * One unified-diff row. CSS grid (not a table cell) so a `<Virtuoso>`
44
+ * list can virtualize identical rows without a host `<table>` (the
45
+ * `display: table-row-group` virtual scrollers force on `<tbody>` doesn't
46
+ * play with arbitrary row heights).
47
+ */
48
+ function Row({ line, numWidth, language, prismTheme }: RowProps) {
49
+ const tone = DIFF_TONE_CLASSES[line.type];
50
+ const gutterCh = `calc(${numWidth}ch + 1rem)`;
51
+ return (
52
+ <div
53
+ className={cn(
54
+ 'grid items-start font-mono text-[13px] leading-relaxed',
55
+ tone.row,
56
+ )}
57
+ style={{
58
+ gridTemplateColumns: `${gutterCh} ${gutterCh} 1.5rem 1fr`,
59
+ }}
60
+ >
61
+ <div
62
+ className={cn(
63
+ 'select-none px-2 text-right tabular-nums whitespace-nowrap',
64
+ tone.num,
65
+ )}
66
+ >
67
+ {line.oldNumber ?? ''}
68
+ </div>
69
+ <div
70
+ className={cn(
71
+ 'select-none px-2 text-right tabular-nums whitespace-nowrap',
72
+ tone.num,
73
+ )}
74
+ >
75
+ {line.newNumber ?? ''}
76
+ </div>
77
+ <div
78
+ className={cn(
79
+ 'select-none text-center whitespace-nowrap',
80
+ tone.num,
81
+ )}
82
+ >
83
+ {linePrefix(line.type)}
84
+ </div>
85
+ <div className={cn('whitespace-pre px-3', tone.text)}>
86
+ <DiffLineContent
87
+ content={line.content}
88
+ language={language}
89
+ prismTheme={prismTheme}
90
+ />
91
+ </div>
92
+ </div>
93
+ );
94
+ }
95
+
96
+ /**
97
+ * Single-column unified diff. Two gutters on the left carry the old / new
98
+ * line numbers, the third (narrow) column is the +/-/space prefix, then
99
+ * the content. Background tint per row signals the change kind.
100
+ *
101
+ * The gutter widths come from the globally-computed `numWidth` (passed
102
+ * down from the viewer root). Using CSS grid with the same explicit
103
+ * `gridTemplateColumns` on every row guarantees pixel-identical gutters
104
+ * across all rows, even when content sizes vary.
105
+ *
106
+ * Diffs above {@link VIRTUALIZE_THRESHOLD} lines render through
107
+ * `<Virtuoso>` so 1k–10k-line diffs don't lock the main thread.
108
+ */
109
+ export function UnifiedView({
110
+ lines,
111
+ numWidth,
112
+ language,
113
+ prismTheme,
114
+ }: UnifiedViewProps) {
115
+ if (lines.length > VIRTUALIZE_THRESHOLD) {
116
+ return (
117
+ <div data-slot="diff-viewer-unified">
118
+ <Virtuoso
119
+ data={lines}
120
+ style={{ height: VIRTUAL_VIEWPORT_HEIGHT }}
121
+ // `initialItemCount` forces SSR-style initial render so rows
122
+ // appear immediately on first paint instead of waiting for
123
+ // ResizeObserver — without it, embedded iframes (Storybook,
124
+ // docs sites) sometimes start at zero height and the list
125
+ // stays empty until a window resize.
126
+ initialItemCount={Math.min(lines.length, 30)}
127
+ itemContent={(_, line) => (
128
+ <Row
129
+ line={line}
130
+ numWidth={numWidth}
131
+ language={language}
132
+ prismTheme={prismTheme}
133
+ />
134
+ )}
135
+ increaseViewportBy={{ top: 200, bottom: 400 }}
136
+ />
137
+ </div>
138
+ );
139
+ }
140
+
141
+ return (
142
+ <div data-slot="diff-viewer-unified">
143
+ {lines.map((line, i) => (
144
+ <Row
145
+ key={i}
146
+ line={line}
147
+ numWidth={numWidth}
148
+ language={language}
149
+ prismTheme={prismTheme}
150
+ />
151
+ ))}
152
+ </div>
153
+ );
154
+ }
@@ -0,0 +1,47 @@
1
+ // Adapted from jalcoui (MIT) — github.com/jal-co/ui
2
+
3
+ import { useMemo } from 'react';
4
+ import {
5
+ computeStats,
6
+ diffLines,
7
+ lineNumberWidth,
8
+ parseUnifiedPatch,
9
+ } from '../utils/computeDiff';
10
+ import type { DiffInput, DiffLine, DiffStats } from '../types';
11
+
12
+ interface UseDiffOptions {
13
+ input: DiffInput;
14
+ /** Context lines around each change-hunk. @default 3 */
15
+ context?: number;
16
+ }
17
+
18
+ interface UseDiffResult {
19
+ lines: DiffLine[];
20
+ numWidth: number;
21
+ stats: DiffStats;
22
+ }
23
+
24
+ /**
25
+ * Memoize the diff computation so a re-render of the viewer (e.g. tab
26
+ * switch, header copy click) doesn't re-run the LCS. The dependency
27
+ * surface intentionally narrows to the two input strings / patch — the
28
+ * `context` knob too, since a different window emits a different line
29
+ * list.
30
+ */
31
+ export function useDiff({ input, context = 3 }: UseDiffOptions): UseDiffResult {
32
+ const isPatch = 'patch' in input && typeof input.patch === 'string';
33
+ const oldCode = isPatch ? '' : input.oldCode;
34
+ const newCode = isPatch ? '' : input.newCode;
35
+ const patch = isPatch ? (input as { patch: string }).patch : '';
36
+
37
+ return useMemo(() => {
38
+ const lines = isPatch
39
+ ? parseUnifiedPatch(patch)
40
+ : diffLines(oldCode, newCode, context);
41
+ return {
42
+ lines,
43
+ numWidth: lineNumberWidth(lines),
44
+ stats: computeStats(lines),
45
+ };
46
+ }, [isPatch, patch, oldCode, newCode, context]);
47
+ }
@@ -0,0 +1,54 @@
1
+ // Adapted from jalcoui (MIT) — github.com/jal-co/ui
2
+ //
3
+ // Shared tokenizer for DiffViewer. Reuses the same `prism-react-renderer`
4
+ // bundle that `PrettyCode` ships — no second highlighter is loaded. We
5
+ // also re-import `PrettyCode`'s grammar-registration hook so `bash`,
6
+ // `ruby`, `java`, `php` work in diffs without duplicating the dynamic
7
+ // imports.
8
+
9
+ import { useMemo } from 'react';
10
+ import type { Language } from 'prism-react-renderer';
11
+ import { useEnsurePrismLanguages } from '../../PrettyCode/registerPrismLanguages';
12
+
13
+ /**
14
+ * Normalize a free-form language string into a Prism language key. Falls
15
+ * back to `text` when the key isn't one Prism knows about.
16
+ */
17
+ export function normalizeLanguage(language: string | undefined): Language {
18
+ if (!language) return 'text' as Language;
19
+ const lang = language.toLowerCase();
20
+ switch (lang) {
21
+ case 'js':
22
+ return 'javascript' as Language;
23
+ case 'ts':
24
+ return 'typescript' as Language;
25
+ case 'py':
26
+ return 'python' as Language;
27
+ case 'rb':
28
+ return 'ruby' as Language;
29
+ case 'sh':
30
+ case 'shell':
31
+ return 'bash' as Language;
32
+ case 'html':
33
+ case 'xml':
34
+ return 'markup' as Language;
35
+ case 'md':
36
+ return 'markdown' as Language;
37
+ case 'yml':
38
+ return 'yaml' as Language;
39
+ case 'golang':
40
+ return 'go' as Language;
41
+ default:
42
+ return lang as Language;
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Subscribe to PrettyCode's extra-grammar loader and return the resolved
48
+ * Prism language key. The component re-renders once `bash`/`ruby`/… are
49
+ * registered so the first paint isn't stuck on plain text.
50
+ */
51
+ export function useDiffLanguage(language: string | undefined): Language {
52
+ useEnsurePrismLanguages();
53
+ return useMemo(() => normalizeLanguage(language), [language]);
54
+ }
@@ -0,0 +1,22 @@
1
+ // Adapted from jalcoui (MIT) — github.com/jal-co/ui
2
+
3
+ export { DiffViewer } from './DiffViewer';
4
+ export { DIFF_TONE_CLASSES } from './types';
5
+ export {
6
+ diffLines,
7
+ parseUnifiedPatch,
8
+ computeStats as computeDiffStats,
9
+ lineNumberWidth as diffLineNumberWidth,
10
+ } from './utils/computeDiff';
11
+ export { useDiff } from './hooks/useDiff';
12
+ export { normalizeLanguage as normalizeDiffLanguage } from './hooks/useHighlighter';
13
+
14
+ export type {
15
+ DiffLayout,
16
+ DiffLine,
17
+ DiffLineType,
18
+ DiffStats,
19
+ DiffInput,
20
+ DiffToneClasses,
21
+ DiffViewerProps,
22
+ } from './types';
@@ -0,0 +1,22 @@
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 { DiffViewerProps } from './types';
7
+
8
+ export const LazyDiffViewer = createLazyComponent<DiffViewerProps>(
9
+ () =>
10
+ import('./DiffViewer').then((mod) => ({ default: mod.DiffViewer })),
11
+ {
12
+ displayName: 'LazyDiffViewer',
13
+ fallback: (
14
+ <div
15
+ data-slot="diff-viewer-skeleton"
16
+ className="h-48 w-full animate-pulse rounded-xl border border-border/60 bg-muted"
17
+ />
18
+ ),
19
+ },
20
+ );
21
+
22
+ export type { DiffViewerProps } from './types';