@djangocfg/ui-tools 2.1.418 → 2.1.419
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/package.json +93 -28
- 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/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/hooks/useEditorTheme.ts +13 -73
- package/src/tools/forms/CodeEditor/lazy.tsx +1 -1
- 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/lazy.tsx +1 -1
- package/src/tools/forms/NotionEditor/README.md +237 -0
- package/src/tools/forms/NotionEditor/lazy.tsx +1 -1
- 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/ImageViewer/components/ImageToolbar.tsx +58 -47
- package/src/tools/media/ImageViewer/components/ImageViewer.tsx +27 -19
- package/src/tools/media/ImageViewer/lazy.tsx +1 -1
- package/src/tools/media/LottiePlayer/lazy.tsx +1 -1
- package/src/tools/media/VideoPlayer/VideoPlayer.tsx +28 -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/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,237 @@
|
|
|
1
|
+
# NotionEditor
|
|
2
|
+
|
|
3
|
+
Notion-style WYSIWYG markdown editor built on **TipTap v3**.
|
|
4
|
+
|
|
5
|
+
Lazy-loaded sibling of [`MarkdownEditor`](../MarkdownEditor/) — same
|
|
6
|
+
markdown round-trip, but with a heavier extension stack and the
|
|
7
|
+
floating menus (slash / bubble / drag handle) that users expect from a
|
|
8
|
+
"document" editor.
|
|
9
|
+
|
|
10
|
+
```tsx
|
|
11
|
+
import { NotionEditor } from '@djangocfg/ui-tools/notion-editor';
|
|
12
|
+
|
|
13
|
+
<NotionEditor
|
|
14
|
+
value={markdown}
|
|
15
|
+
onChange={setMarkdown}
|
|
16
|
+
onSave={(md) => writeFile(md)}
|
|
17
|
+
autoFocus
|
|
18
|
+
placeholder="Type '/' for commands…"
|
|
19
|
+
/>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## When to use this vs `MarkdownEditor`
|
|
23
|
+
|
|
24
|
+
| Use case | Pick |
|
|
25
|
+
| --------------------------------------- | ------------------- |
|
|
26
|
+
| Chat composer, single-paragraph input | `MarkdownEditor` |
|
|
27
|
+
| Note / doc surface, multi-paragraph | `NotionEditor` |
|
|
28
|
+
| `.md` file viewer with full editing | `NotionEditor` |
|
|
29
|
+
| Slim mention dropdown, no tables/tasks | `MarkdownEditor` |
|
|
30
|
+
| Slash menu, drag handle, tables, hljs | `NotionEditor` |
|
|
31
|
+
|
|
32
|
+
The two coexist intentionally — `NotionEditor` is ~350 KB minified
|
|
33
|
+
(lowlight common pack + tables + drag handle); `MarkdownEditor` is
|
|
34
|
+
~200 KB. Don't mount NotionEditor inside a chat composer just to get
|
|
35
|
+
features the user will never use.
|
|
36
|
+
|
|
37
|
+
## Features
|
|
38
|
+
|
|
39
|
+
- **Slash menu (`/`)** — 11 commands: Text, H1-H3, Bullet/Numbered/Todo
|
|
40
|
+
lists, Quote, Code block, Divider, Table. Each item shows its
|
|
41
|
+
markdown shorthand (`#`, `- [ ]`, etc.) as a kbd hint. Filtering by
|
|
42
|
+
title + aliases. `Esc` / click-outside close.
|
|
43
|
+
- **Bubble menu** — floating selection toolbar with Bold, Italic,
|
|
44
|
+
Underline, Strike, Code, Highlight, Link. Each button has a Tooltip
|
|
45
|
+
with the keyboard shortcut. Auto-hides inside code blocks and on
|
|
46
|
+
empty selections.
|
|
47
|
+
- **Cmd+K link prompt** — opens a Radix Dialog with URL input and
|
|
48
|
+
Save/Remove/Cancel. Snapshots and restores selection across the
|
|
49
|
+
dialog mount. Rejects unsafe schemes (`javascript:`, `data:`).
|
|
50
|
+
- **Drag handle** — Notion-style ⠿ grip appears on the left of every
|
|
51
|
+
block on hover (powered by `tiptap-extension-global-drag-handle`).
|
|
52
|
+
The icon is rendered as a `mask-image` of `lucide`'s `GripVertical`
|
|
53
|
+
so it matches the rest of the app at the pixel level.
|
|
54
|
+
- **Smart Cmd+A** — first press selects the current text block, second
|
|
55
|
+
press selects the whole document (Notion convention).
|
|
56
|
+
- **Heading-aware placeholder** — empty H1/H2/H3 show "Heading 1/2/3";
|
|
57
|
+
empty paragraphs show the supplied placeholder.
|
|
58
|
+
- **Forced-dark code blocks** — code blocks render on a fixed One Dark
|
|
59
|
+
Pro surface regardless of host theme. Avoids the washed-out
|
|
60
|
+
"light syntax on light page" look every editor hits.
|
|
61
|
+
- **Task list with ui-core `<Checkbox>`** — `taskItem` uses a React
|
|
62
|
+
`NodeView` so the checkbox is the same component used everywhere
|
|
63
|
+
else in the app (theme-aware, focus ring, etc.). Aligned to the
|
|
64
|
+
text cap-height via `align-items: baseline`.
|
|
65
|
+
- **Cmd+S save hook** — `onSave?: (md: string) => void` bound to
|
|
66
|
+
Cmd/Ctrl+S via `useHotkey`, scoped to the editor DOM so it doesn't
|
|
67
|
+
collide with global palettes higher up.
|
|
68
|
+
- **autoFocus** — declarative prop. Pair with `key={path}` upstream
|
|
69
|
+
when the parent wants a fresh focus per file change.
|
|
70
|
+
- **Markdown shortcuts** — StarterKit's input rules cover `#`, `>`,
|
|
71
|
+
`-`, `1.`, `` ``` ``, `---` → matching block on type.
|
|
72
|
+
|
|
73
|
+
## Extension stack
|
|
74
|
+
|
|
75
|
+
Built once per editor instance (see `extensions.ts`). Order matters
|
|
76
|
+
for markdown serialisation — `Markdown` is registered before
|
|
77
|
+
`Highlight`/`TaskList` so the latter use the markdown extension's
|
|
78
|
+
node spec when serialising.
|
|
79
|
+
|
|
80
|
+
- `StarterKit` — paragraph, headings 1-4, bold/italic/code/strike,
|
|
81
|
+
blockquote, ordered+unordered list, link, underline, horizontal
|
|
82
|
+
rule, history. CodeBlock is **disabled** here — replaced by
|
|
83
|
+
`CodeBlockLowlight` for syntax highlighting.
|
|
84
|
+
- `Placeholder` — heading-aware ghost text.
|
|
85
|
+
- `Markdown` — bidirectional serialisation via `@tiptap/markdown`.
|
|
86
|
+
Handles tables, task lists (`- [ ]`), highlight (`==text==`).
|
|
87
|
+
- `Highlight` — `==text==` mark.
|
|
88
|
+
- `TaskList` + `TaskItem.extend({ addNodeView: TaskItemView })`.
|
|
89
|
+
- `Table` + `TableRow` + `TableHeader` + `TableCell`.
|
|
90
|
+
- `CodeBlockLowlight` — uses `lowlight`'s `common` language pack
|
|
91
|
+
(~25 languages). Add more by importing them and registering on the
|
|
92
|
+
shared `lowlight` instance.
|
|
93
|
+
- `GlobalDragHandle` — block grabber. **One handle per page** — see
|
|
94
|
+
the "Known limitations" section below.
|
|
95
|
+
- `SlashExtension` — wraps `@tiptap/suggestion` for the `/` menu.
|
|
96
|
+
- `CustomKeymap` — smart Cmd+A.
|
|
97
|
+
|
|
98
|
+
## Files
|
|
99
|
+
|
|
100
|
+
| File | Purpose |
|
|
101
|
+
| ----------------------------- | ----------------------------------------------------------- |
|
|
102
|
+
| `lazy.tsx` | Subpath entry — `React.lazy` + `forwardRef` for the handle |
|
|
103
|
+
| `NotionEditor.tsx` | Main component + `BubbleSelectionToolbar` |
|
|
104
|
+
| `extensions.ts` | Assembled TipTap stack (factory `notionExtensions()`) |
|
|
105
|
+
| `types.ts` | `NotionEditorProps`, `NotionEditorHandle` |
|
|
106
|
+
| `SlashExtension.ts` | TipTap extension wrapping `@tiptap/suggestion` |
|
|
107
|
+
| `createSlashSuggestion.ts` | Suggestion config — floating-ui popup mount/update/teardown |
|
|
108
|
+
| `SlashList.tsx` | Popover content (listbox + keyboard nav) |
|
|
109
|
+
| `slashItems.ts` | Command list + `filterSlashItems` helper |
|
|
110
|
+
| `CustomKeymap.ts` | Smart Cmd+A extension |
|
|
111
|
+
| `TaskItemView.tsx` | React NodeView for `taskItem` (mounts ui-core Checkbox) |
|
|
112
|
+
| `LinkDialog.tsx` | Cmd+K link prompt (ui-core Dialog) |
|
|
113
|
+
| `styles.css` | Typography + slash/bubble menu + drag handle + lowlight |
|
|
114
|
+
|
|
115
|
+
## Imperative API
|
|
116
|
+
|
|
117
|
+
```tsx
|
|
118
|
+
const ref = useRef<NotionEditorHandle>(null);
|
|
119
|
+
|
|
120
|
+
ref.current?.focus(); // focus the editor surface
|
|
121
|
+
ref.current?.moveCursorToEnd(); // focus + caret at end
|
|
122
|
+
ref.current?.getEditor(); // raw TipTap Editor (escape hatch)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
`NotionEditorHandle` is structurally compatible with `ComposerHandle`
|
|
126
|
+
from `@djangocfg/ui-tools/composer-registry` — the chat suite can
|
|
127
|
+
register a NotionEditor as a composer if you ever want to swap them in
|
|
128
|
+
the chat input (unusual, but allowed).
|
|
129
|
+
|
|
130
|
+
## Saving — dirty / pristine handling
|
|
131
|
+
|
|
132
|
+
The editor is **uncontrolled-ish**: it calls `onChange` on every
|
|
133
|
+
keystroke with the freshly-serialised markdown. The host owns state
|
|
134
|
+
and detects "dirty" however it likes.
|
|
135
|
+
|
|
136
|
+
Two gotchas the host needs to know about:
|
|
137
|
+
|
|
138
|
+
1. **TipTap re-serialises markdown on mount** (trailing newline,
|
|
139
|
+
CRLF → LF normalisation). The first `onChange` after
|
|
140
|
+
`setContent(value)` is byte-different from `value` even though
|
|
141
|
+
nobody typed. If you compare `draft !== savedContent` literally,
|
|
142
|
+
the dirty indicator lights up on every file open. **Fix in the
|
|
143
|
+
host**: normalise both sides before comparing.
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
const norm = (s: string) => s.replace(/\r\n/g, '\n').trimEnd();
|
|
147
|
+
const isDirty = norm(draft) !== norm(saved);
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
2. **Cmd+S only fires when focus is inside the editor**. If the user
|
|
151
|
+
clicked outside (header, sidebar) and presses Cmd+S, this hook
|
|
152
|
+
doesn't fire. Add a window-level `useHotkey('mod+s', save)` in the
|
|
153
|
+
host as a fallback — both paths call the same save fn.
|
|
154
|
+
|
|
155
|
+
See `cmdop/.../document-preview/viewers/text-viewer.tsx` for the
|
|
156
|
+
canonical wiring.
|
|
157
|
+
|
|
158
|
+
## Markdown round-trip
|
|
159
|
+
|
|
160
|
+
| Input | Round-trips? | Notes |
|
|
161
|
+
| ---------------- | ------------ | ---------------------------------- |
|
|
162
|
+
| Headings | ✓ | H1-H4 only (StarterKit config) |
|
|
163
|
+
| Bold/italic/etc. | ✓ | |
|
|
164
|
+
| Inline code | ✓ | |
|
|
165
|
+
| Code blocks | ✓ | Language fence preserved by hljs |
|
|
166
|
+
| Bullet/ordered | ✓ | Nested too |
|
|
167
|
+
| Task lists | ✓ | GFM `- [x]` / `- [ ]` |
|
|
168
|
+
| Blockquote | ✓ | |
|
|
169
|
+
| Horizontal rule | ✓ | `---` |
|
|
170
|
+
| Tables | ✓ | GFM tables — alignment via `:--:` |
|
|
171
|
+
| Links | ✓ | autolinks too |
|
|
172
|
+
| Highlight | ✓ | `==text==` extension syntax |
|
|
173
|
+
| Images | mostly | Round-trip URLs, no upload yet |
|
|
174
|
+
| HTML passthrough | ✗ | Stripped on parse |
|
|
175
|
+
| Footnotes | ✗ | Not in StarterKit |
|
|
176
|
+
|
|
177
|
+
## Known limitations
|
|
178
|
+
|
|
179
|
+
- **One editor per page (drag handle).**
|
|
180
|
+
`tiptap-extension-global-drag-handle` mints a single DOM grabber
|
|
181
|
+
attached to `document.body`. Mounting two `NotionEditor` instances
|
|
182
|
+
on the same page (e.g. a side-by-side diff) makes them fight over
|
|
183
|
+
the handle. If you need multiple editors, render only one with
|
|
184
|
+
drag-handle support.
|
|
185
|
+
|
|
186
|
+
- **Slash popup is portal'd to `document.body`.**
|
|
187
|
+
If the parent unmounts the editor mid-suggestion, the popup gets
|
|
188
|
+
cleaned up by ProseMirror's `onExit` — but a hostile race (route
|
|
189
|
+
change while menu is open) can leave an orphan div. Rare; visible
|
|
190
|
+
only via the inspector.
|
|
191
|
+
|
|
192
|
+
- **No image upload pipeline (yet).**
|
|
193
|
+
`Image` extension is not registered. Pasting an image from the
|
|
194
|
+
clipboard inserts the data-URL into the document (browser default)
|
|
195
|
+
but there's no upload integration. Add `@tiptap/extension-image` +
|
|
196
|
+
a custom paste handler when you have a target storage. See Novel's
|
|
197
|
+
`plugins/upload-images.tsx` for the canonical pattern.
|
|
198
|
+
|
|
199
|
+
- **Bubble menu uses `@tiptap/react/menus`'s `BubbleMenu`** (Tippy
|
|
200
|
+
under the hood). Slash menu uses `floating-ui` directly. Two
|
|
201
|
+
positioning libraries for one editor — kept this way because
|
|
202
|
+
`BubbleMenu` is opinionated about anchor invalidation and Tippy
|
|
203
|
+
handles it correctly; reimplementing on floating-ui would save
|
|
204
|
+
~5 KB but cost a week of edge cases.
|
|
205
|
+
|
|
206
|
+
## Storybook
|
|
207
|
+
|
|
208
|
+
Stories live at `apps/storybook/stories/ui-tools/markdown/NotionEditor.stories.tsx`:
|
|
209
|
+
|
|
210
|
+
- Default (empty editor with placeholder)
|
|
211
|
+
- With sample content (every supported block + serialised output panel)
|
|
212
|
+
- Auto-focus on mount
|
|
213
|
+
- Read-only
|
|
214
|
+
- Compact (240px min-height)
|
|
215
|
+
|
|
216
|
+
Each story renders a right-side panel showing the current serialised
|
|
217
|
+
markdown so you can watch the round-trip live as you type.
|
|
218
|
+
|
|
219
|
+
## Wiring inside a host
|
|
220
|
+
|
|
221
|
+
The canonical host is `cmdop`'s document-preview text viewer:
|
|
222
|
+
|
|
223
|
+
```tsx
|
|
224
|
+
// .md → NotionEditor only (it's already WYSIWYG, no Preview/Source split)
|
|
225
|
+
<div className="mx-auto w-full max-w-[820px] px-6 py-6">
|
|
226
|
+
<NotionEditor
|
|
227
|
+
value={draft}
|
|
228
|
+
onChange={handleChange}
|
|
229
|
+
onSave={save}
|
|
230
|
+
autoFocus
|
|
231
|
+
minHeight={420}
|
|
232
|
+
/>
|
|
233
|
+
</div>
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Use `key={path}` on the wrapper if you remount per file — that's what
|
|
237
|
+
makes `autoFocus` fire on each file open.
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
import { Suspense, forwardRef, lazy } from 'react';
|
|
21
|
-
import { LoadingFallback } from '../../../
|
|
21
|
+
import { LoadingFallback } from '../../../common';
|
|
22
22
|
import type { NotionEditorHandle, NotionEditorProps } from './types';
|
|
23
23
|
|
|
24
24
|
const NotionEditorImpl = lazy(() =>
|
package/src/tools/index.ts
CHANGED
|
@@ -18,10 +18,10 @@
|
|
|
18
18
|
|
|
19
19
|
// Export tools as named exports (all use React.lazy internally)
|
|
20
20
|
export { default as JsonTree } from './data/JsonTree';
|
|
21
|
-
export type {
|
|
21
|
+
export type { JsonTreeProps, JsonValue, JsonAction, JsonSize } from './data/JsonTree';
|
|
22
22
|
export { default as Mermaid } from './dev/Mermaid';
|
|
23
|
-
export { default as PrettyCode } from './dev/PrettyCode';
|
|
24
|
-
export type { Language } from './dev/PrettyCode';
|
|
23
|
+
export { default as PrettyCode } from './dev/code/PrettyCode';
|
|
24
|
+
export type { Language } from './dev/code/PrettyCode';
|
|
25
25
|
export { LottiePlayer, useLottie, usePrefersReducedMotion } from './media/LottiePlayer';
|
|
26
26
|
export type {
|
|
27
27
|
LottiePlayerProps,
|
|
@@ -41,8 +41,8 @@ export * from './forms/JsonForm/templates';
|
|
|
41
41
|
export * from './forms/JsonForm/utils';
|
|
42
42
|
|
|
43
43
|
// Export OpenapiViewer
|
|
44
|
-
export { default as OpenapiViewer } from './dev/OpenapiViewer';
|
|
45
|
-
export type { PlaygroundConfig, SchemaSource, PlaygroundProps } from './dev/OpenapiViewer';
|
|
44
|
+
export { default as OpenapiViewer } from './dev/api/OpenapiViewer';
|
|
45
|
+
export type { PlaygroundConfig, SchemaSource, PlaygroundProps } from './dev/api/OpenapiViewer';
|
|
46
46
|
|
|
47
47
|
// Export VideoPlayer (media-chrome shell with provider-aware canvases)
|
|
48
48
|
export {
|
|
@@ -119,6 +119,8 @@ export {
|
|
|
119
119
|
parseCron,
|
|
120
120
|
isValidCron,
|
|
121
121
|
humanizeCron,
|
|
122
|
+
getNextRuns,
|
|
123
|
+
formatNextRun,
|
|
122
124
|
// Components
|
|
123
125
|
ScheduleTypeSelector,
|
|
124
126
|
TimeSelector,
|
|
@@ -126,6 +128,7 @@ export {
|
|
|
126
128
|
MonthDayGrid,
|
|
127
129
|
CustomInput,
|
|
128
130
|
SchedulePreview,
|
|
131
|
+
CronPreview,
|
|
129
132
|
} from './input/CronScheduler';
|
|
130
133
|
export type {
|
|
131
134
|
CronSchedulerProps,
|
|
@@ -135,6 +138,7 @@ export type {
|
|
|
135
138
|
MonthDay,
|
|
136
139
|
CronSchedulerState,
|
|
137
140
|
CronSchedulerContextValue,
|
|
141
|
+
CronPreviewProps,
|
|
138
142
|
} from './input/CronScheduler';
|
|
139
143
|
|
|
140
144
|
// Export CodeEditor (Monaco ~550KB)
|
|
@@ -380,6 +384,20 @@ export type {
|
|
|
380
384
|
ComboboxOption,
|
|
381
385
|
} from './input/Combobox';
|
|
382
386
|
|
|
387
|
+
// Export ColorPalette (jalcoui port, Phase 1 Wave 3)
|
|
388
|
+
export {
|
|
389
|
+
ColorPalette,
|
|
390
|
+
ColorPaletteSwatch,
|
|
391
|
+
formatColor as colorPaletteFormatColor,
|
|
392
|
+
getReadableContrast as colorPaletteGetReadableContrast,
|
|
393
|
+
} from './visual/design/ColorPalette';
|
|
394
|
+
export type {
|
|
395
|
+
ColorEntry as ColorPaletteEntry,
|
|
396
|
+
ColorFormat as ColorPaletteFormat,
|
|
397
|
+
ColorPaletteMode,
|
|
398
|
+
ColorPaletteProps,
|
|
399
|
+
} from './visual/design/ColorPalette';
|
|
400
|
+
|
|
383
401
|
// Export ColorPicker
|
|
384
402
|
export {
|
|
385
403
|
ColorPicker,
|
|
@@ -392,11 +410,11 @@ export {
|
|
|
392
410
|
ColorPickerEyeDropper,
|
|
393
411
|
ColorPickerFormatSelect,
|
|
394
412
|
ColorPickerInput,
|
|
395
|
-
} from './visual/ColorPicker';
|
|
413
|
+
} from './visual/design/ColorPicker';
|
|
396
414
|
export type {
|
|
397
415
|
ColorPickerProps,
|
|
398
416
|
ColorPickerInputProps,
|
|
399
|
-
} from './visual/ColorPicker';
|
|
417
|
+
} from './visual/design/ColorPicker';
|
|
400
418
|
|
|
401
419
|
// Export FileUpload
|
|
402
420
|
export {
|
|
@@ -420,8 +438,8 @@ export type {
|
|
|
420
438
|
} from './forms/FileUpload';
|
|
421
439
|
|
|
422
440
|
// Export Fps
|
|
423
|
-
export { Fps } from './visual/Fps';
|
|
424
|
-
export type { FpsProps } from './visual/Fps';
|
|
441
|
+
export { Fps } from './visual/indicators/Fps';
|
|
442
|
+
export type { FpsProps } from './visual/indicators/Fps';
|
|
425
443
|
|
|
426
444
|
// Export Gauge
|
|
427
445
|
export {
|
|
@@ -432,8 +450,8 @@ export {
|
|
|
432
450
|
GaugeValueText,
|
|
433
451
|
GaugeLabel,
|
|
434
452
|
GaugeCombined,
|
|
435
|
-
} from './visual/Gauge';
|
|
436
|
-
export type { GaugeProps } from './visual/Gauge';
|
|
453
|
+
} from './visual/charts/Gauge';
|
|
454
|
+
export type { GaugeProps } from './visual/charts/Gauge';
|
|
437
455
|
|
|
438
456
|
// Export Marquee
|
|
439
457
|
export {
|
|
@@ -466,11 +484,133 @@ export type {
|
|
|
466
484
|
export {
|
|
467
485
|
Rating,
|
|
468
486
|
RatingItem,
|
|
469
|
-
} from './visual/Rating';
|
|
487
|
+
} from './visual/indicators/Rating';
|
|
470
488
|
export type {
|
|
471
489
|
RatingProps,
|
|
472
490
|
RatingItemProps,
|
|
473
|
-
} from './visual/Rating';
|
|
491
|
+
} from './visual/indicators/Rating';
|
|
492
|
+
|
|
493
|
+
// Export ActivityGraph (jalcoui port, Phase 1)
|
|
494
|
+
export { ActivityGraph } from './visual/charts/ActivityGraph';
|
|
495
|
+
export type { ActivityGraphProps, ActivityEntry } from './visual/charts/ActivityGraph';
|
|
496
|
+
|
|
497
|
+
// Export CommitGraph (jalcoui port, Phase 1)
|
|
498
|
+
export {
|
|
499
|
+
CommitGraph,
|
|
500
|
+
useLaneColors as useCommitGraphLaneColors,
|
|
501
|
+
useGraphLayout as useCommitGraphLayout,
|
|
502
|
+
pickLaneColor as pickCommitGraphLaneColor,
|
|
503
|
+
ROW_HEIGHT as COMMIT_GRAPH_ROW_HEIGHT,
|
|
504
|
+
} from './visual/charts/CommitGraph';
|
|
505
|
+
export type {
|
|
506
|
+
Commit,
|
|
507
|
+
CommitAuthor,
|
|
508
|
+
CommitGraphProps,
|
|
509
|
+
Edge as CommitGraphEdge,
|
|
510
|
+
EdgeType as CommitGraphEdgeType,
|
|
511
|
+
GraphRow as CommitGraphRow,
|
|
512
|
+
} from './visual/charts/CommitGraph';
|
|
513
|
+
|
|
514
|
+
// Export StatusIndicator (golden sample — jalcoui port, Phase 0)
|
|
515
|
+
export {
|
|
516
|
+
StatusIndicator,
|
|
517
|
+
STATUS_CONFIG,
|
|
518
|
+
TONE_CLASSES as STATUS_TONE_CLASSES,
|
|
519
|
+
statusIndicatorVariants,
|
|
520
|
+
} from './visual/indicators/StatusIndicator';
|
|
521
|
+
export type {
|
|
522
|
+
Status,
|
|
523
|
+
StatusTone,
|
|
524
|
+
StatusIndicatorProps,
|
|
525
|
+
StatusIndicatorSize,
|
|
526
|
+
} from './visual/indicators/StatusIndicator';
|
|
527
|
+
|
|
528
|
+
// Export EnvTable (jalcoui port, Phase 2)
|
|
529
|
+
export {
|
|
530
|
+
EnvTable,
|
|
531
|
+
ENV_TONE_CLASSES,
|
|
532
|
+
getEnvTone,
|
|
533
|
+
maskValue as envMaskValue,
|
|
534
|
+
useEnvMask,
|
|
535
|
+
} from './dev/ops/EnvTable';
|
|
536
|
+
export type {
|
|
537
|
+
EnvTableProps,
|
|
538
|
+
EnvVariable,
|
|
539
|
+
EnvEnvironment,
|
|
540
|
+
EnvBadgeTone,
|
|
541
|
+
} from './dev/ops/EnvTable';
|
|
542
|
+
|
|
543
|
+
// Export LogViewer (jalcoui port, Phase 2 Wave 2)
|
|
544
|
+
export {
|
|
545
|
+
LogViewer,
|
|
546
|
+
LEVEL_LABELS as LOG_LEVEL_LABELS,
|
|
547
|
+
LEVEL_TONE as LOG_LEVEL_TONE,
|
|
548
|
+
LOG_TONE_CLASSES,
|
|
549
|
+
getLevelToneClasses,
|
|
550
|
+
parseAnsi,
|
|
551
|
+
stripAnsi,
|
|
552
|
+
} from './dev/ops/LogViewer';
|
|
553
|
+
export type {
|
|
554
|
+
LogEntry,
|
|
555
|
+
LogLevel,
|
|
556
|
+
LogTone,
|
|
557
|
+
LogToneClasses,
|
|
558
|
+
LogViewerProps,
|
|
559
|
+
AnsiSegment,
|
|
560
|
+
} from './dev/ops/LogViewer';
|
|
561
|
+
|
|
562
|
+
// Export ApiRefTable (jalcoui port, Phase 2)
|
|
563
|
+
export {
|
|
564
|
+
ApiRefTable,
|
|
565
|
+
TYPE_TAG_CLASSES as API_REF_TYPE_TAG_CLASSES,
|
|
566
|
+
classifyTypeToken as classifyApiRefTypeToken,
|
|
567
|
+
splitTypeSignature as splitApiRefTypeSignature,
|
|
568
|
+
} from './dev/api/ApiRefTable';
|
|
569
|
+
export type {
|
|
570
|
+
ApiProp,
|
|
571
|
+
ApiRefTableProps,
|
|
572
|
+
TypeTag as ApiRefTypeTag,
|
|
573
|
+
} from './dev/api/ApiRefTable';
|
|
574
|
+
|
|
575
|
+
// Export DiffViewer (jalcoui port, Phase 2 Wave 3)
|
|
576
|
+
export {
|
|
577
|
+
DiffViewer,
|
|
578
|
+
DIFF_TONE_CLASSES,
|
|
579
|
+
diffLines,
|
|
580
|
+
parseUnifiedPatch,
|
|
581
|
+
computeDiffStats,
|
|
582
|
+
diffLineNumberWidth,
|
|
583
|
+
useDiff,
|
|
584
|
+
normalizeDiffLanguage,
|
|
585
|
+
} from './dev/code/DiffViewer';
|
|
586
|
+
export type {
|
|
587
|
+
DiffLayout,
|
|
588
|
+
DiffLine,
|
|
589
|
+
DiffLineType,
|
|
590
|
+
DiffStats,
|
|
591
|
+
DiffInput,
|
|
592
|
+
DiffToneClasses,
|
|
593
|
+
DiffViewerProps,
|
|
594
|
+
} from './dev/code/DiffViewer';
|
|
595
|
+
|
|
596
|
+
// Export RequestViewer (jalcoui port, Phase 2)
|
|
597
|
+
export { RequestViewer } from './dev/api/RequestViewer';
|
|
598
|
+
export type {
|
|
599
|
+
RequestViewerProps,
|
|
600
|
+
RequestViewerTab,
|
|
601
|
+
NetworkRequest,
|
|
602
|
+
HeaderEntry as RequestViewerHeaderEntry,
|
|
603
|
+
TimingEntry as RequestViewerTimingEntry,
|
|
604
|
+
} from './dev/api/RequestViewer';
|
|
605
|
+
|
|
606
|
+
// Export Sparkline (jalcoui port, Phase 1)
|
|
607
|
+
export { Sparkline } from './visual/charts/Sparkline';
|
|
608
|
+
export type {
|
|
609
|
+
SparklineProps,
|
|
610
|
+
SparklineColor,
|
|
611
|
+
SparklineVariant,
|
|
612
|
+
SparklineDatum,
|
|
613
|
+
} from './visual/charts/Sparkline';
|
|
474
614
|
|
|
475
615
|
// Export DataGrid
|
|
476
616
|
export {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Lazy-loaded Combobox Component
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { createLazyComponent, LoadingFallback } from '../../../
|
|
7
|
+
import { createLazyComponent, LoadingFallback } from '../../../common/lazy-wrapper';
|
|
8
8
|
import type {
|
|
9
9
|
ComboboxProps,
|
|
10
10
|
ComboboxTriggerProps,
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# CronPreview
|
|
2
|
+
|
|
3
|
+
Read-only companion to `CronScheduler`. Renders a human-readable summary of a cron expression and an optional list of upcoming run times. Standalone — no `CronSchedulerProvider` required.
|
|
4
|
+
|
|
5
|
+
Use it in dashboards, list rows, and read-only schedule views.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { CronPreview } from '@djangocfg/ui-tools/cron-scheduler';
|
|
9
|
+
|
|
10
|
+
<CronPreview value="0 9 * * 1-5" />
|
|
11
|
+
<CronPreview value="*/15 * * * *" nextRuns={5} />
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Props
|
|
15
|
+
|
|
16
|
+
| Prop | Type | Default | Description |
|
|
17
|
+
|---|---|---|---|
|
|
18
|
+
| `value` | `string` | — | Standard 5-field cron expression. |
|
|
19
|
+
| `title` | `string` | — | Optional heading above the summary. |
|
|
20
|
+
| `nextRuns` | `number` | `5` | Upcoming run times to display. `0` hides the list. |
|
|
21
|
+
| `showExpression` | `boolean` | `true` | Show the raw cron expression alongside the summary. |
|
|
22
|
+
| `referenceDate` | `Date` | `new Date()` | Base date for computing next runs. |
|
|
23
|
+
|
|
24
|
+
Storybook: `apps/storybook/stories/ui-tools/cron/CronPreview.stories.tsx`
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
Adapted from jalcoui (MIT).
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* CronPreview
|
|
5
|
+
*
|
|
6
|
+
* Read-only sibling of `CronScheduler`. Renders a human-readable summary
|
|
7
|
+
* for a cron expression plus an optional list of upcoming run times.
|
|
8
|
+
*
|
|
9
|
+
* Unlike `SchedulePreview` (which lives inside the editor and pulls its
|
|
10
|
+
* state from `CronSchedulerProvider`), `CronPreview` is fully standalone:
|
|
11
|
+
* pass a value, get a preview. Use it in dashboards, list rows, and
|
|
12
|
+
* read-only schedule views where the heavier editor is not needed.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* <CronPreview value="0 9 * * 1-5" />
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* <CronPreview value="*\/15 * * * *" nextRuns={5} />
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import * as React from 'react';
|
|
22
|
+
import { Calendar } from 'lucide-react';
|
|
23
|
+
import { cn } from '@djangocfg/ui-core/lib';
|
|
24
|
+
import { humanizeCron } from '../utils/cron-humanize';
|
|
25
|
+
import { getNextRuns, formatNextRun } from '../utils/cron-next-runs';
|
|
26
|
+
import { isValidCron } from '../utils/cron-parser';
|
|
27
|
+
|
|
28
|
+
export interface CronPreviewProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'children'> {
|
|
29
|
+
/** Cron expression (standard 5-field format, e.g. `"0 9 * * 1-5"`). */
|
|
30
|
+
value: string;
|
|
31
|
+
/** Optional heading shown above the summary. */
|
|
32
|
+
title?: string;
|
|
33
|
+
/**
|
|
34
|
+
* Number of upcoming run times to display.
|
|
35
|
+
* `0` hides the list. Defaults to `5`.
|
|
36
|
+
*/
|
|
37
|
+
nextRuns?: number;
|
|
38
|
+
/** Show the raw cron expression alongside the summary. Defaults to `true`. */
|
|
39
|
+
showExpression?: boolean;
|
|
40
|
+
/** Base date for computing next runs. Defaults to "now". */
|
|
41
|
+
referenceDate?: Date;
|
|
42
|
+
/** Additional CSS classes for the outer container. */
|
|
43
|
+
className?: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function CronPreview({
|
|
47
|
+
value,
|
|
48
|
+
title,
|
|
49
|
+
nextRuns = 5,
|
|
50
|
+
showExpression = true,
|
|
51
|
+
referenceDate,
|
|
52
|
+
className,
|
|
53
|
+
...rest
|
|
54
|
+
}: CronPreviewProps) {
|
|
55
|
+
const trimmed = (value ?? '').trim();
|
|
56
|
+
const valid = isValidCron(trimmed);
|
|
57
|
+
|
|
58
|
+
const summary = React.useMemo(() => humanizeCron(trimmed), [trimmed]);
|
|
59
|
+
|
|
60
|
+
const runs = React.useMemo(() => {
|
|
61
|
+
if (!valid || nextRuns <= 0) return [];
|
|
62
|
+
return getNextRuns(trimmed, nextRuns, referenceDate ?? new Date());
|
|
63
|
+
}, [trimmed, valid, nextRuns, referenceDate]);
|
|
64
|
+
|
|
65
|
+
if (!valid) {
|
|
66
|
+
return (
|
|
67
|
+
<div
|
|
68
|
+
data-slot="cron-preview"
|
|
69
|
+
className={cn(
|
|
70
|
+
'rounded-xl border border-destructive/30 bg-destructive/5 px-4 py-3 text-sm text-destructive',
|
|
71
|
+
className
|
|
72
|
+
)}
|
|
73
|
+
{...rest}
|
|
74
|
+
>
|
|
75
|
+
Invalid cron expression: <code className="font-mono">{trimmed || '(empty)'}</code>
|
|
76
|
+
</div>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<div
|
|
82
|
+
data-slot="cron-preview"
|
|
83
|
+
role="status"
|
|
84
|
+
aria-live="polite"
|
|
85
|
+
className={cn(
|
|
86
|
+
'overflow-hidden rounded-xl border border-border bg-card text-card-foreground shadow-sm',
|
|
87
|
+
className
|
|
88
|
+
)}
|
|
89
|
+
{...rest}
|
|
90
|
+
>
|
|
91
|
+
{/* Header */}
|
|
92
|
+
<div className="flex items-start justify-between gap-3 border-b border-border/60 px-4 py-3">
|
|
93
|
+
<div className="flex min-w-0 items-start gap-2">
|
|
94
|
+
<Calendar aria-hidden="true" className="mt-0.5 h-4 w-4 shrink-0 text-muted-foreground" />
|
|
95
|
+
<div className="flex min-w-0 flex-col gap-0.5">
|
|
96
|
+
{title && (
|
|
97
|
+
<h3 className="text-sm font-semibold text-foreground">{title}</h3>
|
|
98
|
+
)}
|
|
99
|
+
<p className="text-sm text-muted-foreground">{summary}</p>
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
102
|
+
{showExpression && (
|
|
103
|
+
<code className="shrink-0 rounded-md bg-muted px-2.5 py-1 font-mono text-xs text-foreground">
|
|
104
|
+
{trimmed}
|
|
105
|
+
</code>
|
|
106
|
+
)}
|
|
107
|
+
</div>
|
|
108
|
+
|
|
109
|
+
{/* Next runs */}
|
|
110
|
+
{runs.length > 0 && (
|
|
111
|
+
<div className="px-4 py-3">
|
|
112
|
+
<p className="mb-2 text-[10px] font-medium uppercase tracking-wide text-muted-foreground">
|
|
113
|
+
Next {runs.length === 1 ? 'run' : `${runs.length} runs`}
|
|
114
|
+
</p>
|
|
115
|
+
<ol className="flex flex-col gap-1">
|
|
116
|
+
{runs.map((run, i) => (
|
|
117
|
+
<li
|
|
118
|
+
key={run.toISOString()}
|
|
119
|
+
className="flex items-center gap-2 text-sm"
|
|
120
|
+
>
|
|
121
|
+
<span className="flex size-5 shrink-0 items-center justify-center rounded-full bg-muted text-[10px] font-semibold text-muted-foreground">
|
|
122
|
+
{i + 1}
|
|
123
|
+
</span>
|
|
124
|
+
<span className="font-mono text-xs text-foreground">
|
|
125
|
+
{formatNextRun(run)}
|
|
126
|
+
</span>
|
|
127
|
+
</li>
|
|
128
|
+
))}
|
|
129
|
+
</ol>
|
|
130
|
+
</div>
|
|
131
|
+
)}
|
|
132
|
+
</div>
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export default CronPreview;
|
|
@@ -22,3 +22,6 @@ export type { SchedulePreviewProps } from './SchedulePreview';
|
|
|
22
22
|
|
|
23
23
|
export { CronCheatsheet } from './CronCheatsheet';
|
|
24
24
|
export type { CronCheatsheetProps } from './CronCheatsheet';
|
|
25
|
+
|
|
26
|
+
export { CronPreview } from './CronPreview';
|
|
27
|
+
export type { CronPreviewProps } from './CronPreview';
|