@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,231 @@
1
+ // Adapted from jalcoui (MIT) — github.com/jal-co/ui
2
+
3
+ // Minimal ANSI SGR (Select Graphic Rendition) parser.
4
+ //
5
+ // Scope: 8-color and 16-color (bright) foreground / background codes plus
6
+ // the structural codes (`0` reset, `1` bold, `2` dim, `3` italic, `4`
7
+ // underline). 256-color and truecolor sequences (`38;5;N`, `38;2;R;G;B`)
8
+ // are recognized at the parser level — we step over their parameters so
9
+ // they don't corrupt the next span — but we do not honor the exact RGB;
10
+ // they fall back to the default foreground. The 16-color palette is more
11
+ // than enough for the typical CLI log surface (`chalk`, `consola`,
12
+ // `pino-pretty`, …), and we trade fidelity for guaranteed semantic-token
13
+ // routing.
14
+
15
+ import type { LogTone } from '../types';
16
+ import { TONE_CLASSES } from '../types';
17
+
18
+ /** A contiguous text segment with resolved style attributes. */
19
+ export interface AnsiSegment {
20
+ text: string;
21
+ /** Resolved tone for color routing — `undefined` means default
22
+ * foreground. */
23
+ tone?: LogTone;
24
+ bold?: boolean;
25
+ dim?: boolean;
26
+ italic?: boolean;
27
+ underline?: boolean;
28
+ }
29
+
30
+ /**
31
+ * Map a raw ANSI SGR color code to a {@link LogTone}. The mapping mirrors
32
+ * the standard chalk-style palette so a log line that says `chalk.red(…)`
33
+ * lights up as `destructive` under every preset.
34
+ *
35
+ * - 30/40 (black) → muted
36
+ * - 31/41 (red) → destructive
37
+ * - 32/42 (green) → primary-tinted via the `success` token family —
38
+ * LogViewer routes green to `info` family via the
39
+ * debug bucket? No: green logs are *positive*, so we
40
+ * reuse the existing semantic `success` (we don't
41
+ * ship a separate `success` tone in TONE_CLASSES, so
42
+ * we collapse to `info` — green is rare and `info`
43
+ * reads as positive on every default preset). For
44
+ * callers who need a true success color, that's what
45
+ * `level: "info"` with `message: "✓ …"` is for.
46
+ * - 33/43 (yellow) → warning
47
+ * - 34/44 (blue) → info
48
+ * - 35/45 (magenta) → debug (categorical, themed via --primary)
49
+ * - 36/46 (cyan) → info
50
+ * - 37/47 (white) → undefined (default fg)
51
+ *
52
+ * The `90+` bright variants and `40+` backgrounds collapse onto the same
53
+ * tones — bright/normal differentiation goes through the `bold` flag and
54
+ * Tailwind weight, not a fresh color scale.
55
+ */
56
+ const COLOR_TONE: Record<number, LogTone | undefined> = {
57
+ 30: 'muted',
58
+ 31: 'destructive',
59
+ 32: 'info', // see note above
60
+ 33: 'warning',
61
+ 34: 'info',
62
+ 35: 'debug',
63
+ 36: 'info',
64
+ 37: undefined,
65
+ 90: 'muted',
66
+ 91: 'destructive',
67
+ 92: 'info',
68
+ 93: 'warning',
69
+ 94: 'info',
70
+ 95: 'debug',
71
+ 96: 'info',
72
+ 97: undefined,
73
+ };
74
+
75
+ // Background colors carry no semantic weight in our log surface — we
76
+ // strip them entirely. Recognise them for parser-correctness only.
77
+ const BG_CODES = new Set([40, 41, 42, 43, 44, 45, 46, 47, 100, 101, 102, 103, 104, 105, 106, 107]);
78
+
79
+ interface State {
80
+ tone?: LogTone;
81
+ bold?: boolean;
82
+ dim?: boolean;
83
+ italic?: boolean;
84
+ underline?: boolean;
85
+ }
86
+
87
+ function applyCode(state: State, code: number): void {
88
+ if (code === 0) {
89
+ state.tone = undefined;
90
+ state.bold = false;
91
+ state.dim = false;
92
+ state.italic = false;
93
+ state.underline = false;
94
+ return;
95
+ }
96
+ if (code === 1) {
97
+ state.bold = true;
98
+ return;
99
+ }
100
+ if (code === 2) {
101
+ state.dim = true;
102
+ return;
103
+ }
104
+ if (code === 3) {
105
+ state.italic = true;
106
+ return;
107
+ }
108
+ if (code === 4) {
109
+ state.underline = true;
110
+ return;
111
+ }
112
+ if (code === 22) {
113
+ state.bold = false;
114
+ state.dim = false;
115
+ return;
116
+ }
117
+ if (code === 23) {
118
+ state.italic = false;
119
+ return;
120
+ }
121
+ if (code === 24) {
122
+ state.underline = false;
123
+ return;
124
+ }
125
+ if (code === 39) {
126
+ state.tone = undefined;
127
+ return;
128
+ }
129
+ if (BG_CODES.has(code) || code === 49) {
130
+ // background — ignore
131
+ return;
132
+ }
133
+ if (code in COLOR_TONE) {
134
+ state.tone = COLOR_TONE[code];
135
+ }
136
+ }
137
+
138
+ // Matches a single SGR escape: `\x1b[…m`. The CSI parameter bytes are
139
+ // digits separated by `;`. The terminator `m` distinguishes SGR from
140
+ // cursor / mode escapes — those are dropped silently.
141
+ //
142
+ // eslint-disable-next-line no-control-regex
143
+ const ANSI_REGEX = /\x1b\[((?:\d+;?)*)m/g;
144
+
145
+ /**
146
+ * Parse an ANSI-tinted string into styled segments. The returned array is
147
+ * cheap to memoize per log entry — segments are short and immutable.
148
+ */
149
+ export function parseAnsi(input: string): AnsiSegment[] {
150
+ if (!input) return [];
151
+ // Fast path — no escape byte at all.
152
+ if (input.indexOf('\x1b') === -1) {
153
+ return [{ text: input }];
154
+ }
155
+
156
+ const segments: AnsiSegment[] = [];
157
+ const state: State = {};
158
+ let cursor = 0;
159
+
160
+ // Reset the global regex's lastIndex (it persists across calls).
161
+ ANSI_REGEX.lastIndex = 0;
162
+
163
+ let match: RegExpExecArray | null;
164
+ while ((match = ANSI_REGEX.exec(input)) !== null) {
165
+ const slice = input.slice(cursor, match.index);
166
+ if (slice) {
167
+ segments.push({ text: slice, ...state });
168
+ }
169
+
170
+ const params = match[1];
171
+ if (params === '') {
172
+ // `\x1b[m` ≡ `\x1b[0m`
173
+ applyCode(state, 0);
174
+ } else {
175
+ const codes = params.split(';').map((p) => Number.parseInt(p, 10) || 0);
176
+ // 256-color / truecolor: step over their tail so the rest of the
177
+ // sequence doesn't get misread.
178
+ for (let i = 0; i < codes.length; i += 1) {
179
+ const code = codes[i];
180
+ if ((code === 38 || code === 48) && codes[i + 1] === 5) {
181
+ // 256-color — skip the index byte
182
+ i += 2;
183
+ continue;
184
+ }
185
+ if ((code === 38 || code === 48) && codes[i + 1] === 2) {
186
+ // truecolor — skip 3 RGB bytes
187
+ i += 4;
188
+ continue;
189
+ }
190
+ applyCode(state, code);
191
+ }
192
+ }
193
+
194
+ cursor = match.index + match[0].length;
195
+ }
196
+
197
+ const tail = input.slice(cursor);
198
+ if (tail) {
199
+ segments.push({ text: tail, ...state });
200
+ }
201
+
202
+ // If the entire string was escape sequences, return at least one empty
203
+ // segment so the renderer has something to key off of.
204
+ return segments.length > 0 ? segments : [{ text: '' }];
205
+ }
206
+
207
+ /**
208
+ * Strip ANSI sequences for plain-text use (copy-to-clipboard, search,
209
+ * download). Keeps every printable character.
210
+ */
211
+ export function stripAnsi(input: string): string {
212
+ if (!input || input.indexOf('\x1b') === -1) return input;
213
+ return input.replace(ANSI_REGEX, '');
214
+ }
215
+
216
+ /**
217
+ * Resolve a segment's Tailwind classes against the LogViewer tone table.
218
+ * Bold / dim / italic / underline come from Tailwind utilities and stack
219
+ * orthogonally on the tone color.
220
+ */
221
+ export function classesForSegment(segment: AnsiSegment): string {
222
+ const parts: string[] = [];
223
+ if (segment.tone) {
224
+ parts.push(TONE_CLASSES[segment.tone].text);
225
+ }
226
+ if (segment.bold) parts.push('font-semibold');
227
+ if (segment.dim) parts.push('opacity-70');
228
+ if (segment.italic) parts.push('italic');
229
+ if (segment.underline) parts.push('underline');
230
+ return parts.join(' ');
231
+ }
@@ -46,6 +46,8 @@ export const Editor = forwardRef<EditorRef, EditorProps>(function Editor(
46
46
  autoHeight = false,
47
47
  minHeight = 100,
48
48
  maxHeight = 600,
49
+ autoFocus = false,
50
+ onSave,
49
51
  },
50
52
  ref
51
53
  ) {
@@ -67,9 +69,11 @@ export const Editor = forwardRef<EditorRef, EditorProps>(function Editor(
67
69
  // without going stale when the parent passes new function identities.
68
70
  const onChangeRef = useRef(onChange);
69
71
  const onMountRef = useRef(onMount);
72
+ const onSaveRef = useRef(onSave);
70
73
  useEffect(() => {
71
74
  onChangeRef.current = onChange;
72
75
  onMountRef.current = onMount;
76
+ onSaveRef.current = onSave;
73
77
  });
74
78
 
75
79
  // Expose editor methods via ref
@@ -126,6 +130,21 @@ export const Editor = forwardRef<EditorRef, EditorProps>(function Editor(
126
130
  updateContentHeight(editor);
127
131
  }
128
132
 
133
+ // Cmd/Ctrl+S → save. Registered as a Monaco command so it wins over
134
+ // the browser's "save page" default whenever the editor has focus.
135
+ // Read through the ref so swapping handlers does not need to rebuild.
136
+ editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS, () => {
137
+ onSaveRef.current?.(editor.getValue());
138
+ });
139
+
140
+ // autoFocus on first mount — Monaco refuses focus during layout
141
+ // measurement otherwise.
142
+ if (autoFocus) {
143
+ // queueMicrotask: defer past Monaco's own post-create layout so the
144
+ // focus call lands on a fully laid-out editor.
145
+ queueMicrotask(() => editorRef.current?.focus());
146
+ }
147
+
129
148
  // Call onMount callback
130
149
  onMountRef.current?.(editor);
131
150
 
@@ -8,12 +8,12 @@ export const EDITOR_BACKGROUND = '#0a0a0a';
8
8
  /**
9
9
  * Hook that registers and returns the Monaco editor theme.
10
10
  *
11
- * The editor is always dark devtool-style regardless of the app theme.
12
- * Colors are read from the document's CSS variables so the editor still
13
- * matches the design tokens, with a dark fallback for SSR.
11
+ * The editor is always dark (Chrome devtools / VSCode convention) its
12
+ * palette does not follow the host app theme. Pass `themeOverride` only
13
+ * if you need a specific Monaco built-in (e.g. `'hc-black'`).
14
14
  *
15
15
  * @param monaco - Monaco namespace (null during loading)
16
- * @param themeOverride - Optional explicit theme name (skips the app theme)
16
+ * @param themeOverride - Optional explicit theme name
17
17
  * @returns Resolved Monaco theme name to pass to editor options
18
18
  */
19
19
  export function useEditorTheme(
@@ -67,16 +67,18 @@ export function useEditorTheme(
67
67
  }
68
68
 
69
69
  /**
70
- * Read editor colors from the document's dark theme CSS variables.
70
+ * Editor colors hard-coded dark palette.
71
71
  *
72
- * Tokens in `tokens.css` are stored wrapped, e.g. `--background: hsl(0 0% 4%)`,
73
- * so we resolve them through the browser by painting onto a probe element and
74
- * reading back the computed (already-rgb) color. This works for any color
75
- * syntax (hsl/oklch/hex).
72
+ * Previously we resolved against CSS variables (`--background`, `--card`,
73
+ * …) so the editor matched the host theme, but the editor MUST be dark
74
+ * regardless of host theme (Chrome devtools / VSCode / Insomnia
75
+ * convention). On a light-themed app `--background` resolves to white,
76
+ * which Monaco then paints under `base: 'vs-dark'` — giving the broken
77
+ * "white Monaco" look. Hard-coding keeps the dark contract honest and
78
+ * removes a layout-time DOM probe.
76
79
  */
77
80
  function readEditorColors() {
78
- // Dark defaults — used during SSR and as a safety net.
79
- const fallback = {
81
+ return {
80
82
  background: EDITOR_BACKGROUND,
81
83
  foreground: '#f5f5f5',
82
84
  card: '#141414',
@@ -85,67 +87,5 @@ function readEditorColors() {
85
87
  lineHighlight: '#1a1a1a',
86
88
  selection: '#264F78',
87
89
  };
88
-
89
- if (typeof document === 'undefined' || typeof window === 'undefined') {
90
- return fallback;
91
- }
92
-
93
- const probe = document.createElement('div');
94
- probe.style.position = 'absolute';
95
- probe.style.pointerEvents = 'none';
96
- probe.style.opacity = '0';
97
- document.body.appendChild(probe);
98
-
99
- /** Resolve a CSS var to a hex color via computed style; '' on failure. */
100
- const resolve = (varName: string): string => {
101
- probe.style.color = `var(${varName})`;
102
- const computed = getComputedStyle(probe).color;
103
- return rgbToHex(computed);
104
- };
105
-
106
- try {
107
- const background = resolve('--background') || fallback.background;
108
- const foreground = resolve('--foreground') || fallback.foreground;
109
- const card = resolve('--card') || fallback.card;
110
- const border = resolve('--border') || fallback.border;
111
- const mutedForeground = resolve('--muted-foreground') || fallback.mutedForeground;
112
- const primary = resolve('--primary');
113
-
114
- return {
115
- background,
116
- foreground,
117
- card,
118
- border,
119
- mutedForeground,
120
- lineHighlight: mixHex(background, foreground, 0.06),
121
- selection: primary ? mixHex(primary, background, 0.55) : fallback.selection,
122
- };
123
- } finally {
124
- probe.remove();
125
- }
126
- }
127
-
128
- /** Convert a computed `rgb(r, g, b)` / `rgba(...)` string to `#rrggbb`. */
129
- function rgbToHex(rgb: string): string {
130
- const match = rgb.match(/(\d+(?:\.\d+)?)/g);
131
- if (!match || match.length < 3) return '';
132
- const [r, g, b] = match.slice(0, 3).map((n) => Math.round(parseFloat(n)));
133
- const toHex = (v: number) => Math.min(255, Math.max(0, v)).toString(16).padStart(2, '0');
134
- return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
135
90
  }
136
91
 
137
- /** Linearly blend `a` toward `b` by `t` (0..1). Both must be `#rrggbb`. */
138
- function mixHex(a: string, b: string, t: number): string {
139
- const pa = parseInt(a.slice(1), 16);
140
- const pb = parseInt(b.slice(1), 16);
141
- if (Number.isNaN(pa) || Number.isNaN(pb)) return a;
142
- const lerp = (shift: number) => {
143
- const ca = (pa >> shift) & 0xff;
144
- const cb = (pb >> shift) & 0xff;
145
- return Math.round(ca + (cb - ca) * t);
146
- };
147
- const r = lerp(16);
148
- const g = lerp(8);
149
- const bch = lerp(0);
150
- return `#${((r << 16) | (g << 8) | bch).toString(16).padStart(6, '0')}`;
151
- }
@@ -20,7 +20,7 @@
20
20
  * and only render `<LazyEditor>` lower in the tree where it's needed.
21
21
  */
22
22
 
23
- import { createLazyComponent, LoadingFallback } from '../../../components';
23
+ import { createLazyComponent, LoadingFallback } from '../../../common';
24
24
  import type { EditorProps, DiffEditorProps } from './types';
25
25
 
26
26
  // ============================================================================
@@ -61,6 +61,13 @@ export interface EditorProps {
61
61
  minHeight?: number;
62
62
  /** Max height in px when autoHeight is enabled (default: 600) */
63
63
  maxHeight?: number;
64
+ /** Focus the editor once Monaco mounts. Pair with `key={path}` upstream
65
+ * for per-file focus reset. */
66
+ autoFocus?: boolean;
67
+ /** Bound to Cmd/Ctrl+S inside the editor via Monaco's command palette.
68
+ * Receives the current value. The browser default is suppressed by
69
+ * Monaco when a command is registered for that chord. */
70
+ onSave?: (value: string) => void;
64
71
  }
65
72
 
66
73
  export interface DiffEditorProps {
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import { createLazyComponent } from '../../../components/lazy-wrapper';
3
+ import { createLazyComponent } from '../../../common/lazy-wrapper';
4
4
  import type { FileUploadProps } from './types';
5
5
 
6
6
  export const LazyFileUpload = createLazyComponent<FileUploadProps>(
@@ -0,0 +1,115 @@
1
+ 'use client';
2
+
3
+ /**
4
+ * JsonEditor — editable JSON tree.
5
+ *
6
+ * Thin wrapper over `json-edit-react` (MIT, CarlosNZ). The library
7
+ * handles the hard parts (inline editing, drag-reorder, JSON-Schema
8
+ * validation, undo/redo, keyboard nav, copy-to-clipboard) — we apply
9
+ * our theme tokens and a sane default surface, nothing more.
10
+ *
11
+ * When to use:
12
+ * - User is *editing* JSON live (debug Store panel, config UI).
13
+ * - You need schema validation or controlled mutations with
14
+ * `onUpdate`.
15
+ *
16
+ * When NOT to use:
17
+ * - Read-only display → use `@djangocfg/ui-tools/json-tree` (≈ 10×
18
+ * lighter bundle, search + copy-path included).
19
+ */
20
+
21
+ import { JsonEditor as RawEditor, type JsonEditorProps as RawProps } from 'json-edit-react';
22
+ import { useMemo } from 'react';
23
+ import { useResolvedTheme } from '@djangocfg/ui-core/hooks';
24
+ import { cn } from '@djangocfg/ui-core/lib';
25
+
26
+ export interface JsonEditorProps extends Omit<RawProps, 'theme'> {
27
+ /** Extra class on the root container. */
28
+ className?: string;
29
+ /**
30
+ * Hide chrome the host already provides. When `false`, no border /
31
+ * background — the editor sits flush in the surrounding pane.
32
+ * Default `true`.
33
+ */
34
+ bordered?: boolean;
35
+ }
36
+
37
+ /**
38
+ * Hand-rolled theme bridge: maps our semantic CSS vars onto
39
+ * json-edit-react's theme slots. Light/dark resolution lives in our
40
+ * `useResolvedTheme`; the library only sees concrete colours.
41
+ *
42
+ * We keep this minimal — most slots inherit `currentColor`, only the
43
+ * data-typed tokens get explicit Tailwind palette values so the
44
+ * keys/strings/numbers stay legible on every host surface.
45
+ */
46
+ function useEditorTheme(): RawProps['theme'] {
47
+ const resolved = useResolvedTheme();
48
+ return useMemo(
49
+ () => ({
50
+ displayName: 'djangocfg',
51
+ styles: {
52
+ container: {
53
+ backgroundColor: 'transparent',
54
+ fontFamily:
55
+ "'SF Mono', ui-monospace, 'JetBrains Mono', Menlo, Consolas, monospace",
56
+ fontSize: '12px',
57
+ },
58
+ property:
59
+ resolved === 'dark' ? 'rgb(167 139 250)' : 'rgb(124 58 237)', // violet-400 / violet-600
60
+ bracket:
61
+ resolved === 'dark' ? 'rgb(148 163 184)' : 'rgb(100 116 139)', // slate-400 / slate-500
62
+ itemCount:
63
+ resolved === 'dark' ? 'rgb(100 116 139)' : 'rgb(148 163 184)',
64
+ string:
65
+ resolved === 'dark' ? 'rgb(52 211 153)' : 'rgb(5 150 105)', // emerald-400 / emerald-600
66
+ number:
67
+ resolved === 'dark' ? 'rgb(56 189 248)' : 'rgb(2 132 199)', // sky-400 / sky-600
68
+ boolean:
69
+ resolved === 'dark' ? 'rgb(251 191 36)' : 'rgb(217 119 6)', // amber-400 / amber-600
70
+ null: {
71
+ color: resolved === 'dark' ? 'rgb(100 116 139)' : 'rgb(148 163 184)',
72
+ fontStyle: 'italic',
73
+ },
74
+ input: {
75
+ backgroundColor:
76
+ resolved === 'dark' ? 'rgb(30 41 59)' : 'rgb(241 245 249)',
77
+ color: resolved === 'dark' ? 'white' : 'rgb(15 23 42)',
78
+ borderRadius: 4,
79
+ padding: '2px 6px',
80
+ },
81
+ inputHighlight:
82
+ resolved === 'dark' ? 'rgba(96, 165, 250, 0.25)' : 'rgba(59, 130, 246, 0.15)',
83
+ iconCollection:
84
+ resolved === 'dark' ? 'rgb(148 163 184)' : 'rgb(100 116 139)',
85
+ iconEdit: 'currentColor',
86
+ iconDelete: 'rgb(239 68 68)',
87
+ iconAdd: 'rgb(34 197 94)',
88
+ iconCopy: 'currentColor',
89
+ iconOk: 'rgb(34 197 94)',
90
+ iconCancel: 'rgb(239 68 68)',
91
+ },
92
+ }),
93
+ [resolved],
94
+ );
95
+ }
96
+
97
+ export function JsonEditor({
98
+ className,
99
+ bordered = true,
100
+ ...props
101
+ }: JsonEditorProps) {
102
+ const theme = useEditorTheme();
103
+ return (
104
+ <div
105
+ className={cn(
106
+ 'json-editor-host w-full',
107
+ bordered &&
108
+ 'overflow-hidden rounded-md border border-border/60 bg-card px-3 py-2',
109
+ className,
110
+ )}
111
+ >
112
+ <RawEditor theme={theme} {...props} />
113
+ </div>
114
+ );
115
+ }
@@ -0,0 +1 @@
1
+ export * from './lazy';
@@ -0,0 +1,24 @@
1
+ 'use client';
2
+
3
+ /**
4
+ * `@djangocfg/ui-tools/json-editor` subpath entrypoint.
5
+ *
6
+ * Heavy editor (~58 KB minified for `json-edit-react` alone). Lazy-load
7
+ * so consumers that only display JSON pay nothing — they should use
8
+ * `@djangocfg/ui-tools/json-tree` instead, which is ~10× lighter.
9
+ */
10
+
11
+ import { createLazyComponent, LoadingFallback } from '../../../common/lazy-wrapper';
12
+ import type { JsonEditorProps } from './JsonEditor';
13
+
14
+ export type { JsonEditorProps } from './JsonEditor';
15
+
16
+ export const LazyJsonEditor = createLazyComponent<JsonEditorProps>(
17
+ () => import('./JsonEditor').then((m) => ({ default: m.JsonEditor })),
18
+ {
19
+ displayName: 'LazyJsonEditor',
20
+ fallback: <LoadingFallback minHeight={120} text="Loading JSON editor…" />,
21
+ },
22
+ );
23
+
24
+ export { LazyJsonEditor as JsonEditor };
@@ -16,7 +16,7 @@
16
16
  *
17
17
  * @example
18
18
  * ```tsx
19
- * import { JsonSchemaForm } from '@/components/JsonForm';
19
+ * import { JsonSchemaForm } from '@/common/JsonForm';
20
20
  *
21
21
  * const schema = {
22
22
  * type: 'object',
@@ -10,7 +10,7 @@
10
10
  * import { JsonSchemaForm } from '@djangocfg/ui-tools/json-form'
11
11
  */
12
12
 
13
- import { createLazyComponent, CardLoadingFallback } from '../../../components';
13
+ import { createLazyComponent, CardLoadingFallback } from '../../../common';
14
14
  import type { JsonSchemaFormProps } from './types';
15
15
 
16
16
  // ============================================================================
@@ -7,6 +7,7 @@ import Mention from '@tiptap/extension-mention';
7
7
  import { Markdown } from '@tiptap/markdown';
8
8
  import type { AnyExtension } from '@tiptap/core';
9
9
  import { forwardRef, useEffect, useImperativeHandle, useMemo, useRef } from 'react';
10
+ import { useHotkey } from '@djangocfg/ui-core/hooks';
10
11
  import {
11
12
  Bold, Italic, Strikethrough, Heading1, Heading2, Heading3,
12
13
  List, ListOrdered, Quote, Minus, Code, type LucideIcon,
@@ -125,6 +126,17 @@ export interface MarkdownEditorProps {
125
126
  * empty draft".
126
127
  */
127
128
  onSubmit?: () => boolean | void;
129
+ /**
130
+ * Focus the editor on mount. Pair with `key={file}` upstream when the
131
+ * host wants a fresh focus per file change (inspector / editor tab).
132
+ */
133
+ autoFocus?: boolean;
134
+ /**
135
+ * Called when the user presses Cmd/Ctrl+S inside the editor. Receives
136
+ * the current markdown. The browser's "save page" default is suppressed
137
+ * only when this handler is supplied — otherwise Cmd+S falls through.
138
+ */
139
+ onSave?: (markdown: string) => void;
128
140
  }
129
141
 
130
142
  /**
@@ -159,6 +171,8 @@ export const MarkdownEditor = forwardRef<MarkdownEditorHandle, MarkdownEditorPro
159
171
  slashCommands,
160
172
  onMentionIdsChange,
161
173
  onSubmit,
174
+ autoFocus = false,
175
+ onSave,
162
176
  },
163
177
  ref,
164
178
  ) {
@@ -380,6 +394,32 @@ export const MarkdownEditor = forwardRef<MarkdownEditorHandle, MarkdownEditorPro
380
394
  editor?.setEditable(!disabled);
381
395
  }, [editor, disabled]);
382
396
 
397
+ // Declarative autoFocus — runs once the editor instance exists. Hosts
398
+ // that want per-file focus reset should pair this with `key={path}`.
399
+ useEffect(() => {
400
+ if (!autoFocus || !editor) return;
401
+ editor.commands.focus('end');
402
+ }, [autoFocus, editor]);
403
+
404
+ // Cmd/Ctrl+S → save. Uses the shared `useHotkey` (inInput=true by
405
+ // default for modifier combos). Guarded to fire only when focus is
406
+ // inside this editor's ProseMirror DOM, so multiple sibling editors
407
+ // don't all fire on one chord.
408
+ const onSaveRef = useRef(onSave);
409
+ onSaveRef.current = onSave;
410
+ useHotkey(
411
+ 'mod+s',
412
+ () => {
413
+ const h = onSaveRef.current;
414
+ if (!h || !editor) return;
415
+ const dom = editor.view.dom;
416
+ const active = document.activeElement;
417
+ if (!active || !dom.contains(active)) return;
418
+ h(getMarkdown(editor));
419
+ },
420
+ { enabled: !!editor && !!onSave },
421
+ );
422
+
383
423
  // Imperative API for hosts that drive the editor without owning a
384
424
  // TipTap ref directly — chat composer registration, voice slot,
385
425
  // focus-on-stream-end.
@@ -23,7 +23,7 @@
23
23
  */
24
24
 
25
25
  import { Suspense, lazy, forwardRef } from 'react';
26
- import { LoadingFallback } from '../../../components';
26
+ import { LoadingFallback } from '../../../common';
27
27
  import type { MarkdownEditorProps, MarkdownEditorHandle } from './MarkdownEditor';
28
28
 
29
29
  const MarkdownEditorImpl = lazy(() =>