@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.
- package/dist/audio-player/index.cjs +1 -2
- package/dist/audio-player/index.cjs.map +1 -1
- package/dist/audio-player/index.d.cts +3 -11
- package/dist/audio-player/index.d.ts +3 -11
- package/dist/audio-player/index.mjs +1 -2
- package/dist/audio-player/index.mjs.map +1 -1
- package/dist/file-icon/index.cjs +3 -3
- package/dist/file-icon/index.cjs.map +1 -1
- package/dist/file-icon/index.mjs +3 -3
- package/dist/file-icon/index.mjs.map +1 -1
- package/dist/tree/index.cjs +0 -3
- package/dist/tree/index.cjs.map +1 -1
- package/dist/tree/index.mjs +0 -3
- package/dist/tree/index.mjs.map +1 -1
- package/package.json +117 -36
- package/src/common/FloatingToolbar/actions/CopyAction.tsx +31 -0
- package/src/{components → common}/FloatingToolbar/actions/DownloadAction.tsx +15 -10
- package/src/common/FloatingToolbar/actions/ExpandAction.tsx +33 -0
- package/src/common/FloatingToolbar/actions/FullscreenAction.tsx +38 -0
- package/src/{components → common}/FloatingToolbar/index.tsx +39 -0
- package/src/lib/http.ts +64 -0
- package/src/tools/chat/index.ts +1 -1
- package/src/tools/chat/launcher/ChatFAB.tsx +66 -74
- package/src/tools/chat/launcher/header/ChatHeaderActionButton.tsx +2 -3
- package/src/tools/chat/lazy.tsx +1 -1
- package/src/tools/chat/messages/MessageBubble.tsx +1 -1
- package/src/tools/chat/messages/blocks/builtin.tsx +1 -1
- package/src/tools/chat/messages/blocks/renderers/CodeBlock.tsx +2 -2
- package/src/tools/chat/messages/blocks/renderers/JsonBlock.tsx +12 -1
- package/src/tools/data/DataGrid/lazy.tsx +1 -1
- package/src/tools/data/DataTable/lazy.tsx +1 -1
- package/src/tools/data/JsonTree/JsonViewer.tsx +720 -0
- package/src/tools/data/JsonTree/README.md +126 -73
- package/src/tools/data/JsonTree/index.tsx +3 -95
- package/src/tools/data/JsonTree/lazy.tsx +10 -50
- package/src/tools/data/JsonTree/types.ts +82 -63
- package/src/tools/data/Kanban/lazy.tsx +1 -1
- package/src/tools/data/Listbox/lazy.tsx +1 -1
- package/src/tools/data/Masonry/lazy.tsx +1 -1
- package/src/tools/data/Timeline/lazy.tsx +1 -1
- package/src/tools/data/Tree/components/TreeRow.tsx +0 -11
- package/src/tools/data/Tree/lazy.tsx +1 -1
- package/src/tools/dev/Map/lazy.tsx +1 -1
- package/src/tools/dev/Mermaid/Mermaid.client.tsx +2 -2
- package/src/tools/dev/Mermaid/lazy.tsx +1 -1
- package/src/tools/dev/api/ApiRefTable/ApiRefTable.tsx +65 -0
- package/src/tools/dev/api/ApiRefTable/README.md +31 -0
- package/src/tools/dev/api/ApiRefTable/components/Row.tsx +96 -0
- package/src/tools/dev/api/ApiRefTable/components/TypeDisplay.tsx +44 -0
- package/src/tools/dev/api/ApiRefTable/index.ts +6 -0
- package/src/tools/dev/api/ApiRefTable/lazy.tsx +21 -0
- package/src/tools/dev/api/ApiRefTable/types.ts +82 -0
- package/src/tools/dev/api/ApiRefTable/utils.ts +42 -0
- package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/ApiIntroSection.tsx +1 -1
- package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/CodeSamples/index.tsx +1 -1
- package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Header/index.tsx +1 -1
- package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Responses/ResponseBody.tsx +7 -21
- package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/RequestPanel.tsx +1 -1
- package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/PrettyView.tsx +13 -19
- package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/types.ts +1 -1
- package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/lazy.tsx +1 -1
- package/src/tools/dev/api/RequestViewer/README.md +33 -0
- package/src/tools/dev/api/RequestViewer/RequestViewer.tsx +121 -0
- package/src/tools/dev/api/RequestViewer/components/BodyTab.tsx +44 -0
- package/src/tools/dev/api/RequestViewer/components/EmptyState.tsx +13 -0
- package/src/tools/dev/api/RequestViewer/components/HeadersTab.tsx +78 -0
- package/src/tools/dev/api/RequestViewer/components/TimingTab.tsx +113 -0
- package/src/tools/dev/api/RequestViewer/components/utils.ts +31 -0
- package/src/tools/dev/api/RequestViewer/index.ts +16 -0
- package/src/tools/dev/api/RequestViewer/lazy.tsx +30 -0
- package/src/tools/dev/api/RequestViewer/types.ts +81 -0
- package/src/tools/dev/code/DiffViewer/DiffViewer.tsx +144 -0
- package/src/tools/dev/code/DiffViewer/README.md +33 -0
- package/src/tools/dev/code/DiffViewer/components/CopyButton.tsx +49 -0
- package/src/tools/dev/code/DiffViewer/components/DiffLineContent.tsx +48 -0
- package/src/tools/dev/code/DiffViewer/components/SplitView.tsx +220 -0
- package/src/tools/dev/code/DiffViewer/components/UnifiedView.tsx +154 -0
- package/src/tools/dev/code/DiffViewer/hooks/useDiff.ts +47 -0
- package/src/tools/dev/code/DiffViewer/hooks/useHighlighter.ts +54 -0
- package/src/tools/dev/code/DiffViewer/index.ts +22 -0
- package/src/tools/dev/code/DiffViewer/lazy.tsx +22 -0
- package/src/tools/dev/code/DiffViewer/types.ts +109 -0
- package/src/tools/dev/code/DiffViewer/utils/computeDiff.ts +159 -0
- package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/CollapseToggle.tsx +1 -1
- package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/MarkdownMessage.tsx +1 -1
- package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/components.tsx +2 -2
- package/src/tools/dev/{PrettyCode → code/PrettyCode}/PrettyCode.client.tsx +2 -2
- package/src/tools/dev/{PrettyCode → code/PrettyCode}/lazy.tsx +1 -1
- package/src/tools/dev/ops/EnvTable/EnvTable.tsx +228 -0
- package/src/tools/dev/ops/EnvTable/README.md +29 -0
- package/src/tools/dev/ops/EnvTable/hooks/useEnvMask.ts +121 -0
- package/src/tools/dev/ops/EnvTable/index.ts +12 -0
- package/src/tools/dev/ops/EnvTable/lazy.tsx +21 -0
- package/src/tools/dev/ops/EnvTable/types.ts +76 -0
- package/src/tools/dev/ops/LogViewer/LogViewer.tsx +194 -0
- package/src/tools/dev/ops/LogViewer/README.md +30 -0
- package/src/tools/dev/ops/LogViewer/components/LogRow.tsx +151 -0
- package/src/tools/dev/ops/LogViewer/components/Toolbar.tsx +199 -0
- package/src/tools/dev/ops/LogViewer/hooks/useAutoScroll.ts +68 -0
- package/src/tools/dev/ops/LogViewer/hooks/useLogFilter.ts +58 -0
- package/src/tools/dev/ops/LogViewer/index.ts +18 -0
- package/src/tools/dev/ops/LogViewer/lazy.tsx +25 -0
- package/src/tools/dev/ops/LogViewer/types.ts +142 -0
- package/src/tools/dev/ops/LogViewer/utils/ansi.ts +231 -0
- package/src/tools/forms/CodeEditor/components/Editor.tsx +19 -0
- package/src/tools/forms/CodeEditor/hooks/useEditorTheme.ts +13 -73
- package/src/tools/forms/CodeEditor/lazy.tsx +1 -1
- package/src/tools/forms/CodeEditor/types/index.ts +7 -0
- package/src/tools/forms/FileUpload/lazy.tsx +1 -1
- package/src/tools/forms/JsonEditor/JsonEditor.tsx +115 -0
- package/src/tools/forms/JsonEditor/index.ts +1 -0
- package/src/tools/forms/JsonEditor/lazy.tsx +24 -0
- package/src/tools/forms/JsonForm/index.ts +1 -1
- package/src/tools/forms/JsonForm/lazy.tsx +1 -1
- package/src/tools/forms/MarkdownEditor/MarkdownEditor.tsx +40 -0
- package/src/tools/forms/MarkdownEditor/lazy.tsx +1 -1
- package/src/tools/forms/MarkdownEditor/styles.css +174 -21
- package/src/tools/forms/NotionEditor/CustomKeymap.ts +48 -0
- package/src/tools/forms/NotionEditor/LinkDialog.tsx +133 -0
- package/src/tools/forms/NotionEditor/NotionEditor.tsx +304 -0
- package/src/tools/forms/NotionEditor/README.md +237 -0
- package/src/tools/forms/NotionEditor/SlashExtension.ts +32 -0
- package/src/tools/forms/NotionEditor/SlashList.tsx +136 -0
- package/src/tools/forms/NotionEditor/TaskItemView.tsx +41 -0
- package/src/tools/forms/NotionEditor/createSlashSuggestion.ts +121 -0
- package/src/tools/forms/NotionEditor/extensions.ts +105 -0
- package/src/tools/forms/NotionEditor/index.ts +1 -0
- package/src/tools/forms/NotionEditor/lazy.tsx +44 -0
- package/src/tools/forms/NotionEditor/slashItems.ts +159 -0
- package/src/tools/forms/NotionEditor/styles.css +478 -0
- package/src/tools/forms/NotionEditor/types.ts +28 -0
- package/src/tools/index.ts +153 -13
- package/src/tools/input/Combobox/lazy.tsx +1 -1
- package/src/tools/input/CronScheduler/components/CronPreview.README.md +28 -0
- package/src/tools/input/CronScheduler/components/CronPreview.tsx +136 -0
- package/src/tools/input/CronScheduler/components/index.ts +3 -0
- package/src/tools/input/CronScheduler/index.tsx +5 -1
- package/src/tools/input/CronScheduler/lazy.tsx +5 -1
- package/src/tools/input/CronScheduler/utils/cron-next-runs.ts +122 -0
- package/src/tools/input/CronScheduler/utils/index.ts +1 -0
- package/src/tools/input/Scroller/lazy.tsx +1 -1
- package/src/tools/input/Sortable/lazy.tsx +1 -1
- package/src/tools/input/SpeechRecognition/lazy.tsx +1 -1
- package/src/tools/input/SpeechRecognition/widgets/VoiceComposerSlot.tsx +41 -36
- package/src/tools/media/AudioPlayer/PlayerShell.tsx +3 -11
- package/src/tools/media/AudioPlayer/types.ts +4 -11
- package/src/tools/media/ImageViewer/components/ImageToolbar.tsx +58 -47
- package/src/tools/media/ImageViewer/components/ImageViewer.tsx +35 -19
- package/src/tools/media/ImageViewer/lazy.tsx +1 -1
- package/src/tools/media/ImageViewer/types.ts +4 -0
- package/src/tools/media/LottiePlayer/lazy.tsx +1 -1
- package/src/tools/media/VideoPlayer/VideoPlayer.tsx +47 -1
- package/src/tools/media/VideoPlayer/parts/fullscreen.tsx +21 -4
- package/src/tools/media/VideoPlayer/parts/pip.tsx +21 -4
- package/src/tools/media/VideoPlayer/parts/play-button.tsx +21 -4
- package/src/tools/media/VideoPlayer/parts/playback-rate.tsx +19 -3
- package/src/tools/media/VideoPlayer/parts/volume.tsx +237 -18
- package/src/tools/media/VideoPlayer/styles/video-player.css +87 -7
- package/src/tools/media/VideoPlayer/types.ts +4 -0
- package/src/tools/overlay/ResponsiveDialog/lazy.tsx +1 -1
- package/src/tools/overlay/ScrollSpy/lazy.tsx +1 -1
- package/src/tools/overlay/SelectionToolbar/lazy.tsx +1 -1
- package/src/tools/overlay/Tour/lazy.tsx +1 -1
- package/src/tools/visual/Marquee/lazy.tsx +1 -1
- package/src/tools/visual/QRCode/lazy.tsx +1 -1
- package/src/tools/visual/charts/ActivityGraph/ActivityGraph.tsx +195 -0
- package/src/tools/visual/charts/ActivityGraph/README.md +28 -0
- package/src/tools/visual/charts/ActivityGraph/index.ts +8 -0
- package/src/tools/visual/charts/ActivityGraph/lazy.tsx +21 -0
- package/src/tools/visual/charts/ActivityGraph/types.ts +59 -0
- package/src/tools/visual/charts/ActivityGraph/utils.ts +88 -0
- package/src/tools/visual/charts/CommitGraph/CommitGraph.tsx +80 -0
- package/src/tools/visual/charts/CommitGraph/README.md +28 -0
- package/src/tools/visual/charts/CommitGraph/components/CommitDetail.tsx +107 -0
- package/src/tools/visual/charts/CommitGraph/components/CommitRow.tsx +122 -0
- package/src/tools/visual/charts/CommitGraph/components/Rails.tsx +171 -0
- package/src/tools/visual/charts/CommitGraph/hooks/useGraphLayout.ts +169 -0
- package/src/tools/visual/charts/CommitGraph/hooks/useLaneColors.ts +45 -0
- package/src/tools/visual/charts/CommitGraph/index.ts +14 -0
- package/src/tools/visual/charts/CommitGraph/lazy.tsx +25 -0
- package/src/tools/visual/charts/CommitGraph/types.ts +85 -0
- package/src/tools/visual/charts/CommitGraph/utils.ts +53 -0
- package/src/tools/visual/{Gauge → charts/Gauge}/lazy.tsx +1 -1
- package/src/tools/visual/charts/Sparkline/README.md +29 -0
- package/src/tools/visual/charts/Sparkline/Sparkline.tsx +217 -0
- package/src/tools/visual/charts/Sparkline/index.ts +9 -0
- package/src/tools/visual/charts/Sparkline/lazy.tsx +26 -0
- package/src/tools/visual/charts/Sparkline/types.ts +58 -0
- package/src/tools/visual/design/ColorPalette/ColorPalette.tsx +129 -0
- package/src/tools/visual/design/ColorPalette/README.md +34 -0
- package/src/tools/visual/design/ColorPalette/components/Swatch.tsx +102 -0
- package/src/tools/visual/design/ColorPalette/hooks/useCopyToClipboard.ts +41 -0
- package/src/tools/visual/design/ColorPalette/index.ts +12 -0
- package/src/tools/visual/design/ColorPalette/lazy.tsx +21 -0
- package/src/tools/visual/design/ColorPalette/types.ts +63 -0
- package/src/tools/visual/design/ColorPalette/utils.ts +83 -0
- package/src/tools/visual/{ColorPicker → design/ColorPicker}/lazy.tsx +1 -1
- package/src/tools/visual/{FileIcon → design/FileIcon}/treeAdapter.tsx +1 -1
- package/src/tools/visual/{Fps → indicators/Fps}/lazy.tsx +1 -1
- package/src/tools/visual/{Rating → indicators/Rating}/lazy.tsx +1 -1
- package/src/tools/visual/indicators/StatusIndicator/README.md +28 -0
- package/src/tools/visual/indicators/StatusIndicator/StatusIndicator.tsx +83 -0
- package/src/tools/visual/indicators/StatusIndicator/index.ts +14 -0
- package/src/tools/visual/indicators/StatusIndicator/lazy.tsx +21 -0
- package/src/tools/visual/indicators/StatusIndicator/types.ts +133 -0
- package/src/components/FloatingToolbar/actions/CopyAction.tsx +0 -22
- package/src/components/FloatingToolbar/actions/ExpandAction.tsx +0 -25
- package/src/components/FloatingToolbar/actions/FullscreenAction.tsx +0 -30
- package/src/tools/data/JsonTree/components/JsonContent.tsx +0 -197
- package/src/tools/data/JsonTree/hooks/useJsonExpand.ts +0 -50
- /package/src/{components → common}/FloatingToolbar/FloatingToolbar.css +0 -0
- /package/src/{components → common}/FloatingToolbar/actions/index.ts +0 -0
- /package/src/{components → common}/FloatingToolbar/hooks/useElementCorner.ts +0 -0
- /package/src/{components → common}/FloatingToolbar/hooks/useScrollIsolation.ts +0 -0
- /package/src/{components → common}/index.ts +0 -0
- /package/src/{components → common}/lazy-wrapper.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/README.md +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/DocsView.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/CodeSamples/LanguageTabs.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/CodeSamples/useCodeSnippet.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Header/MetaActions.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Header/MethodBadge.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Header/PathDisplay.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Parameters/ParamGroup.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Parameters/ParamRow.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Parameters/index.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/RequestBody/index.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Responses/ResponseRow.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Responses/StatusTag.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Responses/index.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/SchemaFields/FieldRow.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/SchemaFields/buildTree.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/SchemaFields/index.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/SchemaFields/types.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Section/SectionHeader.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Section/defaults.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/Section/index.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/context.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/hooks/useSectionHash.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/index.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/store/index.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/store/selectors.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/EndpointDoc/types.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/SchemaCopyMenu.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/BrandHeader.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/CategoryBlock.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/EndpointRow.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/SchemaSection.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/SearchInput.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/SidebarBody.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/Toolbar.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/buildVM.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/index.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/types.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/Sidebar/useDebouncedValue.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/SlideInPlayground.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/TryItSheet.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/anchor.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/grouping.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/index.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/DocsLayout/sidebarLabel.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/index.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/BodyFormEditor.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/EndpointDraftSync.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/EndpointResetButton.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/PreviewView.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/RawView.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/StatusBar.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/ViewTabs.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/detectContent.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/index.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ResponsePanel/useResponseView.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/SendButton.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/components/shared/ui.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/constants.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/context/PlaygroundContext.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/hooks/index.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/hooks/useDocsUrlSync.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/hooks/useEndpointDraft.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/hooks/useMobile.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/hooks/useOpenApiSchema.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/index.tsx +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/types.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/apiKeyManager.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/codeSamples.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/formatters.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/index.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/operationToHar.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/sampler.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/schemaExport.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/scrollParent.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/url.ts +0 -0
- /package/src/tools/dev/{OpenapiViewer → api/OpenapiViewer}/utils/versionManager.ts +0 -0
- /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/ActionRow.tsx +0 -0
- /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/ChatMessageRow.tsx +0 -0
- /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/CodeBlock.tsx +0 -0
- /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/README.md +0 -0
- /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/index.ts +0 -0
- /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/linkRules.ts +0 -0
- /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/plainText.ts +0 -0
- /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/sanitize.ts +0 -0
- /package/src/tools/dev/{MarkdownMessage → code/MarkdownMessage}/types.ts +0 -0
- /package/src/tools/dev/{PrettyCode → code/PrettyCode}/README.md +0 -0
- /package/src/tools/dev/{PrettyCode → code/PrettyCode}/index.tsx +0 -0
- /package/src/tools/dev/{PrettyCode → code/PrettyCode}/registerPrismLanguages.ts +0 -0
- /package/src/tools/visual/{Gauge → charts/Gauge}/Gauge.tsx +0 -0
- /package/src/tools/visual/{Gauge → charts/Gauge}/index.ts +0 -0
- /package/src/tools/visual/{Gauge → charts/Gauge}/types.ts +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/ColorPicker.tsx +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/context/ColorPickerContext.tsx +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/context/ColorPickerStore.tsx +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/context/index.ts +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/index.ts +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/lib/color-utils.ts +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerAlphaSlider.tsx +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerArea.tsx +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerEyeDropper.tsx +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerFormatSelect.tsx +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerHueSlider.tsx +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerInput.tsx +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/ColorPickerSwatch.tsx +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/parts/index.ts +0 -0
- /package/src/tools/visual/{ColorPicker → design/ColorPicker}/types.ts +0 -0
- /package/src/tools/visual/{FileIcon → design/FileIcon}/FileIcon.tsx +0 -0
- /package/src/tools/visual/{FileIcon → design/FileIcon}/get-file-icon.ts +0 -0
- /package/src/tools/visual/{FileIcon → design/FileIcon}/icons/icon-data.ts +0 -0
- /package/src/tools/visual/{FileIcon → design/FileIcon}/index.ts +0 -0
- /package/src/tools/visual/{FileIcon → design/FileIcon}/loader.ts +0 -0
- /package/src/tools/visual/{FileIcon → design/FileIcon}/specialFolders.ts +0 -0
- /package/src/tools/visual/{Fps → indicators/Fps}/Fps.tsx +0 -0
- /package/src/tools/visual/{Fps → indicators/Fps}/index.ts +0 -0
- /package/src/tools/visual/{Fps → indicators/Fps}/types.ts +0 -0
- /package/src/tools/visual/{Rating → indicators/Rating}/Rating.tsx +0 -0
- /package/src/tools/visual/{Rating → indicators/Rating}/index.ts +0 -0
- /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
|
|
12
|
-
*
|
|
13
|
-
*
|
|
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
|
|
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
|
-
*
|
|
70
|
+
* Editor colors — hard-coded dark palette.
|
|
71
71
|
*
|
|
72
|
-
*
|
|
73
|
-
* so
|
|
74
|
-
*
|
|
75
|
-
*
|
|
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
|
-
|
|
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 '../../../
|
|
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 '../../../
|
|
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 };
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* import { JsonSchemaForm } from '@djangocfg/ui-tools/json-form'
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import { createLazyComponent, CardLoadingFallback } from '../../../
|
|
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 '../../../
|
|
26
|
+
import { LoadingFallback } from '../../../common';
|
|
27
27
|
import type { MarkdownEditorProps, MarkdownEditorHandle } from './MarkdownEditor';
|
|
28
28
|
|
|
29
29
|
const MarkdownEditorImpl = lazy(() =>
|