@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
|
@@ -2,12 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
import { MediaPipButton } from 'media-chrome/react';
|
|
4
4
|
import { cn } from '@djangocfg/ui-core/lib';
|
|
5
|
-
import
|
|
5
|
+
import {
|
|
6
|
+
Tooltip,
|
|
7
|
+
TooltipContent,
|
|
8
|
+
TooltipTrigger,
|
|
9
|
+
} from '@djangocfg/ui-core/components';
|
|
10
|
+
import type { ComponentProps, ReactNode } from 'react';
|
|
6
11
|
|
|
7
|
-
export type PipProps = ComponentProps<typeof MediaPipButton
|
|
12
|
+
export type PipProps = ComponentProps<typeof MediaPipButton> & {
|
|
13
|
+
/** Tooltip copy. Defaults to `"Picture in picture"`. Pass `false` to opt out. */
|
|
14
|
+
readonly label?: ReactNode | false;
|
|
15
|
+
};
|
|
8
16
|
|
|
9
|
-
export function Pip({ className, ...props }: PipProps) {
|
|
10
|
-
|
|
17
|
+
export function Pip({ className, label, ...props }: PipProps) {
|
|
18
|
+
const button = (
|
|
11
19
|
<MediaPipButton
|
|
12
20
|
{...props}
|
|
13
21
|
className={cn(
|
|
@@ -16,4 +24,13 @@ export function Pip({ className, ...props }: PipProps) {
|
|
|
16
24
|
)}
|
|
17
25
|
/>
|
|
18
26
|
);
|
|
27
|
+
|
|
28
|
+
if (label === false) return button;
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<Tooltip>
|
|
32
|
+
<TooltipTrigger asChild>{button}</TooltipTrigger>
|
|
33
|
+
<TooltipContent side="top">{label ?? 'Picture in picture'}</TooltipContent>
|
|
34
|
+
</Tooltip>
|
|
35
|
+
);
|
|
19
36
|
}
|
|
@@ -2,12 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
import { MediaPlayButton } from 'media-chrome/react';
|
|
4
4
|
import { cn } from '@djangocfg/ui-core/lib';
|
|
5
|
-
import
|
|
5
|
+
import {
|
|
6
|
+
Tooltip,
|
|
7
|
+
TooltipContent,
|
|
8
|
+
TooltipTrigger,
|
|
9
|
+
} from '@djangocfg/ui-core/components';
|
|
10
|
+
import type { ComponentProps, ReactNode } from 'react';
|
|
6
11
|
|
|
7
|
-
export type PlayButtonProps = ComponentProps<typeof MediaPlayButton
|
|
12
|
+
export type PlayButtonProps = ComponentProps<typeof MediaPlayButton> & {
|
|
13
|
+
/** Tooltip copy. Defaults to `"Play / Pause"`. Pass `false` to opt out. */
|
|
14
|
+
readonly label?: ReactNode | false;
|
|
15
|
+
};
|
|
8
16
|
|
|
9
|
-
export function PlayButton({ className, ...props }: PlayButtonProps) {
|
|
10
|
-
|
|
17
|
+
export function PlayButton({ className, label, ...props }: PlayButtonProps) {
|
|
18
|
+
const button = (
|
|
11
19
|
<MediaPlayButton
|
|
12
20
|
{...props}
|
|
13
21
|
className={cn(
|
|
@@ -16,4 +24,13 @@ export function PlayButton({ className, ...props }: PlayButtonProps) {
|
|
|
16
24
|
)}
|
|
17
25
|
/>
|
|
18
26
|
);
|
|
27
|
+
|
|
28
|
+
if (label === false) return button;
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<Tooltip>
|
|
32
|
+
<TooltipTrigger asChild>{button}</TooltipTrigger>
|
|
33
|
+
<TooltipContent side="top">{label ?? 'Play / Pause'}</TooltipContent>
|
|
34
|
+
</Tooltip>
|
|
35
|
+
);
|
|
19
36
|
}
|
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
import { MediaPlaybackRateButton } from 'media-chrome/react';
|
|
4
4
|
import { cn } from '@djangocfg/ui-core/lib';
|
|
5
|
-
import
|
|
5
|
+
import {
|
|
6
|
+
Tooltip,
|
|
7
|
+
TooltipContent,
|
|
8
|
+
TooltipTrigger,
|
|
9
|
+
} from '@djangocfg/ui-core/components';
|
|
10
|
+
import type { ComponentProps, ReactNode } from 'react';
|
|
6
11
|
|
|
7
12
|
export type PlaybackRateProps = Omit<
|
|
8
13
|
ComponentProps<typeof MediaPlaybackRateButton>,
|
|
@@ -10,13 +15,15 @@ export type PlaybackRateProps = Omit<
|
|
|
10
15
|
> & {
|
|
11
16
|
/** Space-separated list, e.g. `'0.5 1 1.5 2'`, or an array of numbers. */
|
|
12
17
|
readonly rates?: string | readonly number[];
|
|
18
|
+
/** Tooltip copy. Defaults to `"Playback speed"`. Pass `false` to opt out. */
|
|
19
|
+
readonly label?: ReactNode | false;
|
|
13
20
|
};
|
|
14
21
|
|
|
15
22
|
const DEFAULT_RATES: readonly number[] = [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
|
|
16
23
|
|
|
17
|
-
export function PlaybackRate({ className, rates, ...props }: PlaybackRateProps) {
|
|
24
|
+
export function PlaybackRate({ className, rates, label, ...props }: PlaybackRateProps) {
|
|
18
25
|
const value = rates ?? DEFAULT_RATES;
|
|
19
|
-
|
|
26
|
+
const button = (
|
|
20
27
|
<MediaPlaybackRateButton
|
|
21
28
|
{...props}
|
|
22
29
|
// media-chrome's setter accepts `string | ArrayLike<number>` — the
|
|
@@ -28,4 +35,13 @@ export function PlaybackRate({ className, rates, ...props }: PlaybackRateProps)
|
|
|
28
35
|
)}
|
|
29
36
|
/>
|
|
30
37
|
);
|
|
38
|
+
|
|
39
|
+
if (label === false) return button;
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<Tooltip>
|
|
43
|
+
<TooltipTrigger asChild>{button}</TooltipTrigger>
|
|
44
|
+
<TooltipContent side="top">{label ?? 'Playback speed'}</TooltipContent>
|
|
45
|
+
</Tooltip>
|
|
46
|
+
);
|
|
31
47
|
}
|
|
@@ -1,32 +1,251 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
forwardRef,
|
|
5
|
+
useCallback,
|
|
6
|
+
useEffect,
|
|
7
|
+
useRef,
|
|
8
|
+
useState,
|
|
9
|
+
type ButtonHTMLAttributes,
|
|
10
|
+
type ReactNode,
|
|
11
|
+
} from 'react';
|
|
12
|
+
import { Volume2, VolumeX, Volume1 } from 'lucide-react';
|
|
4
13
|
import { cn } from '@djangocfg/ui-core/lib';
|
|
5
|
-
import
|
|
14
|
+
import {
|
|
15
|
+
Popover,
|
|
16
|
+
PopoverContent,
|
|
17
|
+
PopoverTrigger,
|
|
18
|
+
Slider,
|
|
19
|
+
Tooltip,
|
|
20
|
+
TooltipContent,
|
|
21
|
+
TooltipTrigger,
|
|
22
|
+
} from '@djangocfg/ui-core/components';
|
|
6
23
|
|
|
7
24
|
export interface VolumeProps {
|
|
8
25
|
readonly className?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Reserved for backwards compatibility. The control is always a single
|
|
28
|
+
* icon button that opens a popover with a vertical slider on hover/focus,
|
|
29
|
+
* so this flag is now a no-op. Kept so existing consumers
|
|
30
|
+
* (`<Volume iconOnly />`) don't break.
|
|
31
|
+
*/
|
|
9
32
|
readonly iconOnly?: boolean;
|
|
10
|
-
|
|
11
|
-
readonly
|
|
33
|
+
/** Mute-button tooltip copy. Defaults to `"Volume"`. Pass `false` to opt out. */
|
|
34
|
+
readonly muteLabel?: ReactNode | false;
|
|
12
35
|
}
|
|
13
36
|
|
|
14
|
-
|
|
37
|
+
// Hide the popover slider on iOS Safari — `video.volume` is read-only
|
|
38
|
+
// there (controlled by hardware buttons), so a JS slider does nothing.
|
|
39
|
+
// The trigger still toggles mute, which iOS *does* honour.
|
|
40
|
+
function isIosSafari(): boolean {
|
|
41
|
+
if (typeof navigator === 'undefined') return false;
|
|
42
|
+
const ua = navigator.userAgent;
|
|
43
|
+
const iOS =
|
|
44
|
+
/iPad|iPhone|iPod/.test(ua) ||
|
|
45
|
+
(navigator.platform === 'MacIntel' &&
|
|
46
|
+
(navigator as { maxTouchPoints?: number }).maxTouchPoints! > 1);
|
|
47
|
+
return iOS;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// media-chrome request event names. Dispatched on any descendant of
|
|
51
|
+
// `<media-controller>`; the controller catches them and updates its
|
|
52
|
+
// internal store, which then propagates state back via attributes.
|
|
53
|
+
const MEDIA_VOLUME_REQUEST = 'mediavolumerequest';
|
|
54
|
+
const MEDIA_MUTE_REQUEST = 'mediamuterequest';
|
|
55
|
+
const MEDIA_UNMUTE_REQUEST = 'mediaunmuterequest';
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Click-style trigger that visually matches the rest of the VideoPlayer
|
|
59
|
+
* control bar. Mirrors `.video-player__control` styling from
|
|
60
|
+
* `styles/video-player.css` so it slots in next to `<MediaPlayButton>` &
|
|
61
|
+
* friends without standing out.
|
|
62
|
+
*/
|
|
63
|
+
const TriggerButton = forwardRef<
|
|
64
|
+
HTMLButtonElement,
|
|
65
|
+
ButtonHTMLAttributes<HTMLButtonElement>
|
|
66
|
+
>(function TriggerButton({ className, children, ...rest }, ref) {
|
|
15
67
|
return (
|
|
16
|
-
<
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
{!iconOnly && (
|
|
25
|
-
<MediaVolumeRange
|
|
26
|
-
{...rangeProps}
|
|
27
|
-
className={cn('h-8 w-20', rangeProps?.className)}
|
|
28
|
-
/>
|
|
68
|
+
<button
|
|
69
|
+
ref={ref}
|
|
70
|
+
type="button"
|
|
71
|
+
className={cn(
|
|
72
|
+
'video-player__control',
|
|
73
|
+
'grid h-8 w-8 place-items-center rounded-md',
|
|
74
|
+
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/60',
|
|
75
|
+
className,
|
|
29
76
|
)}
|
|
77
|
+
{...rest}
|
|
78
|
+
>
|
|
79
|
+
{children}
|
|
80
|
+
</button>
|
|
81
|
+
);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* VideoPlayer volume control.
|
|
86
|
+
*
|
|
87
|
+
* - **Click** the trigger → mute / unmute toggle (dispatches a
|
|
88
|
+
* `mediamuterequest` / `mediaunmuterequest` so media-chrome's store
|
|
89
|
+
* stays the single source of truth — no parallel state machine).
|
|
90
|
+
* - **Hover / keyboard focus** → opens a popover containing a vertical
|
|
91
|
+
* `<Slider>` (0..100). Drag = volume change via `mediavolumerequest`.
|
|
92
|
+
* - Icon reflects level (mute / low / high) and mirrors `media.muted`.
|
|
93
|
+
*
|
|
94
|
+
* State is read directly off the underlying `HTMLMediaElement` (located
|
|
95
|
+
* via the closest `<media-controller>`'s `.media` accessor); we never
|
|
96
|
+
* shadow media-chrome's store.
|
|
97
|
+
*/
|
|
98
|
+
export function Volume({ className, muteLabel }: VolumeProps) {
|
|
99
|
+
const triggerRef = useRef<HTMLButtonElement | null>(null);
|
|
100
|
+
const [volume, setVolume] = useState(1);
|
|
101
|
+
const [muted, setMuted] = useState(false);
|
|
102
|
+
const [open, setOpen] = useState(false);
|
|
103
|
+
const [iosSafari] = useState(isIosSafari);
|
|
104
|
+
|
|
105
|
+
// Resolve & track the underlying HTMLMediaElement so we can read live
|
|
106
|
+
// volume / muted. media-chrome fires `mediaelementchange` on the
|
|
107
|
+
// controller whenever the slotted media element swaps (e.g. source
|
|
108
|
+
// change), so we re-bind listeners on each swap.
|
|
109
|
+
useEffect(() => {
|
|
110
|
+
const trigger = triggerRef.current;
|
|
111
|
+
if (!trigger) return;
|
|
112
|
+
const controller = trigger.closest('media-controller') as
|
|
113
|
+
| (HTMLElement & { media?: HTMLMediaElement | null })
|
|
114
|
+
| null;
|
|
115
|
+
if (!controller) return;
|
|
116
|
+
|
|
117
|
+
let media: HTMLMediaElement | null = controller.media ?? null;
|
|
118
|
+
const sync = () => {
|
|
119
|
+
if (!media) return;
|
|
120
|
+
setVolume(media.volume);
|
|
121
|
+
setMuted(media.muted);
|
|
122
|
+
};
|
|
123
|
+
const bind = (el: HTMLMediaElement | null) => {
|
|
124
|
+
if (!el) return;
|
|
125
|
+
el.addEventListener('volumechange', sync);
|
|
126
|
+
sync();
|
|
127
|
+
};
|
|
128
|
+
const unbind = (el: HTMLMediaElement | null) => {
|
|
129
|
+
if (!el) return;
|
|
130
|
+
el.removeEventListener('volumechange', sync);
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
bind(media);
|
|
134
|
+
|
|
135
|
+
const onMediaChange = (e: Event) => {
|
|
136
|
+
unbind(media);
|
|
137
|
+
const detail = (e as CustomEvent).detail as HTMLMediaElement | null;
|
|
138
|
+
media = detail ?? controller.media ?? null;
|
|
139
|
+
bind(media);
|
|
140
|
+
};
|
|
141
|
+
controller.addEventListener('mediaelementchange', onMediaChange);
|
|
142
|
+
|
|
143
|
+
return () => {
|
|
144
|
+
unbind(media);
|
|
145
|
+
controller.removeEventListener('mediaelementchange', onMediaChange);
|
|
146
|
+
};
|
|
147
|
+
}, []);
|
|
148
|
+
|
|
149
|
+
const dispatch = useCallback((name: string, detail?: number) => {
|
|
150
|
+
const trigger = triggerRef.current;
|
|
151
|
+
if (!trigger) return;
|
|
152
|
+
trigger.dispatchEvent(
|
|
153
|
+
new CustomEvent(name, { detail, bubbles: true, composed: true }),
|
|
154
|
+
);
|
|
155
|
+
}, []);
|
|
156
|
+
|
|
157
|
+
const toggleMute = useCallback(() => {
|
|
158
|
+
dispatch(muted ? MEDIA_UNMUTE_REQUEST : MEDIA_MUTE_REQUEST);
|
|
159
|
+
}, [dispatch, muted]);
|
|
160
|
+
|
|
161
|
+
const onSlider = useCallback(
|
|
162
|
+
(value: number) => {
|
|
163
|
+
dispatch(MEDIA_VOLUME_REQUEST, value);
|
|
164
|
+
// If the user nudges the slider above zero, treat that as an
|
|
165
|
+
// implicit unmute — matches what the native HTML5 volume slider does.
|
|
166
|
+
if (value > 0 && muted) dispatch(MEDIA_UNMUTE_REQUEST);
|
|
167
|
+
},
|
|
168
|
+
[dispatch, muted],
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
const effectiveVolume = muted ? 0 : volume;
|
|
172
|
+
const Icon =
|
|
173
|
+
muted || volume === 0 ? VolumeX : volume < 0.5 ? Volume1 : Volume2;
|
|
174
|
+
|
|
175
|
+
const trigger = (
|
|
176
|
+
<TriggerButton
|
|
177
|
+
ref={triggerRef}
|
|
178
|
+
aria-label={muted ? 'Unmute' : 'Mute'}
|
|
179
|
+
aria-pressed={muted}
|
|
180
|
+
onClick={toggleMute}
|
|
181
|
+
>
|
|
182
|
+
<Icon className="h-4 w-4" strokeWidth={1.75} />
|
|
183
|
+
</TriggerButton>
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
// On iOS Safari volume is hardware-only — skip the popover entirely
|
|
187
|
+
// and let the trigger work as a plain mute/unmute button.
|
|
188
|
+
if (iosSafari) {
|
|
189
|
+
if (muteLabel === false) return <div className={cn('flex', className)}>{trigger}</div>;
|
|
190
|
+
return (
|
|
191
|
+
<div className={cn('flex items-center', className)}>
|
|
192
|
+
<Tooltip>
|
|
193
|
+
<TooltipTrigger asChild>{trigger}</TooltipTrigger>
|
|
194
|
+
<TooltipContent side="top">{muteLabel ?? 'Mute / unmute'}</TooltipContent>
|
|
195
|
+
</Tooltip>
|
|
196
|
+
</div>
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return (
|
|
201
|
+
<div
|
|
202
|
+
className={cn('flex items-center', className)}
|
|
203
|
+
// Hover-driven open: opening on pointerenter of the wrapper (not
|
|
204
|
+
// just the button) gives the user a forgiving hit-area when their
|
|
205
|
+
// cursor drifts between trigger and popover. The popover itself
|
|
206
|
+
// also catches pointerenter via Radix portal — so once it's open,
|
|
207
|
+
// moving into it keeps it open.
|
|
208
|
+
onPointerEnter={() => setOpen(true)}
|
|
209
|
+
onPointerLeave={() => setOpen(false)}
|
|
210
|
+
onFocus={() => setOpen(true)}
|
|
211
|
+
onBlur={(e) => {
|
|
212
|
+
// Don't close when focus moves between the trigger and the
|
|
213
|
+
// popover content (both live in this wrapper / its portal).
|
|
214
|
+
if (!e.currentTarget.contains(e.relatedTarget as Node | null)) {
|
|
215
|
+
setOpen(false);
|
|
216
|
+
}
|
|
217
|
+
}}
|
|
218
|
+
>
|
|
219
|
+
<Popover open={open} onOpenChange={setOpen}>
|
|
220
|
+
<PopoverTrigger asChild>{trigger}</PopoverTrigger>
|
|
221
|
+
<PopoverContent
|
|
222
|
+
side="top"
|
|
223
|
+
align="center"
|
|
224
|
+
sideOffset={8}
|
|
225
|
+
// Keep focus on the trigger so click-to-mute still works while
|
|
226
|
+
// the popover is visible; the slider remains keyboard-reachable
|
|
227
|
+
// via Tab once a user explicitly tabs into it.
|
|
228
|
+
onOpenAutoFocus={(e) => e.preventDefault()}
|
|
229
|
+
onCloseAutoFocus={(e) => e.preventDefault()}
|
|
230
|
+
onPointerEnter={() => setOpen(true)}
|
|
231
|
+
onPointerLeave={() => setOpen(false)}
|
|
232
|
+
className="flex w-12 flex-col items-center gap-2 p-3"
|
|
233
|
+
>
|
|
234
|
+
<span className="w-full text-center text-[10px] tabular-nums text-muted-foreground">
|
|
235
|
+
{Math.round(effectiveVolume * 100)}
|
|
236
|
+
</span>
|
|
237
|
+
<Slider
|
|
238
|
+
orientation="vertical"
|
|
239
|
+
min={0}
|
|
240
|
+
max={1}
|
|
241
|
+
step={0.01}
|
|
242
|
+
value={[effectiveVolume]}
|
|
243
|
+
onValueChange={([v]) => onSlider(v)}
|
|
244
|
+
aria-label="Volume"
|
|
245
|
+
className="h-24"
|
|
246
|
+
/>
|
|
247
|
+
</PopoverContent>
|
|
248
|
+
</Popover>
|
|
30
249
|
</div>
|
|
31
250
|
);
|
|
32
251
|
}
|
|
@@ -42,11 +42,6 @@ media-controller {
|
|
|
42
42
|
--media-range-thumb-opacity: 0;
|
|
43
43
|
--media-range-thumb-transition: opacity 0.15s ease;
|
|
44
44
|
|
|
45
|
-
/* Tooltip */
|
|
46
|
-
--media-tooltip-background: var(--popover);
|
|
47
|
-
--media-tooltip-color: var(--popover-foreground);
|
|
48
|
-
--media-tooltip-border-radius: 6px;
|
|
49
|
-
|
|
50
45
|
/* Font */
|
|
51
46
|
--media-font-family: inherit;
|
|
52
47
|
--media-font-size: 12px;
|
|
@@ -87,6 +82,29 @@ media-control-bar {
|
|
|
87
82
|
background: transparent;
|
|
88
83
|
}
|
|
89
84
|
|
|
85
|
+
/*
|
|
86
|
+
* Suppress media-chrome's built-in tooltips. They are sticky elements
|
|
87
|
+
* slotted under each control button's shadow root (exposed via
|
|
88
|
+
* `part="tooltip"`) and paint a permanent "Play" / "Mute" / "Enter
|
|
89
|
+
* fullscreen" label below the bar. We wrap each control with our own
|
|
90
|
+
* Radix-backed <Tooltip> from @djangocfg/ui-core, which fires only on
|
|
91
|
+
* hover/focus and matches the rest of the platform. Reach into the
|
|
92
|
+
* shadow DOM via ::part(tooltip) — a global `media-tooltip` selector
|
|
93
|
+
* cannot pierce the boundary.
|
|
94
|
+
*/
|
|
95
|
+
media-play-button::part(tooltip),
|
|
96
|
+
media-mute-button::part(tooltip),
|
|
97
|
+
media-fullscreen-button::part(tooltip),
|
|
98
|
+
media-pip-button::part(tooltip),
|
|
99
|
+
media-playback-rate-button::part(tooltip),
|
|
100
|
+
media-captions-button::part(tooltip),
|
|
101
|
+
media-airplay-button::part(tooltip),
|
|
102
|
+
media-cast-button::part(tooltip),
|
|
103
|
+
media-seek-forward-button::part(tooltip),
|
|
104
|
+
media-seek-backward-button::part(tooltip) {
|
|
105
|
+
display: none !important;
|
|
106
|
+
}
|
|
107
|
+
|
|
90
108
|
/*
|
|
91
109
|
* Auto-hide. media-chrome flags inactivity by setting `userinactive` on
|
|
92
110
|
* the <media-controller>; it only does so while playback is running, and
|
|
@@ -120,17 +138,79 @@ media-time-range {
|
|
|
120
138
|
--media-preview-background: var(--popover);
|
|
121
139
|
--media-preview-border-radius: 6px;
|
|
122
140
|
--media-text-color: var(--popover-foreground);
|
|
141
|
+
|
|
142
|
+
/* Kill media-chrome's default blue focus rectangle on the range track.
|
|
143
|
+
media-chrome paints a `box-shadow: inset 0 0 0 2px rgb(27 127 204 / .9)`
|
|
144
|
+
via `--media-focus-box-shadow` whenever the inner `<input type=range>`
|
|
145
|
+
matches `:focus-visible`, which wraps the entire seek-bar in a big
|
|
146
|
+
blue rectangle on click/Tab. We opt out of the track-wide ring and
|
|
147
|
+
surface focus on the thumb instead (see :focus-visible below). */
|
|
148
|
+
--media-focus-box-shadow: none;
|
|
123
149
|
}
|
|
124
150
|
|
|
125
|
-
/* Reveal the accent thumb only while hovering / scrubbing the rail
|
|
126
|
-
|
|
151
|
+
/* Reveal the accent thumb only while hovering / scrubbing the rail, OR
|
|
152
|
+
when the rail is keyboard-focused so a11y keyboard users still see
|
|
153
|
+
where focus lives. */
|
|
154
|
+
media-time-range:hover,
|
|
155
|
+
media-time-range:focus-within {
|
|
127
156
|
--media-range-thumb-opacity: 1;
|
|
128
157
|
}
|
|
129
158
|
|
|
159
|
+
/* Keyboard focus indicator: a ring around the thumb (not the track).
|
|
160
|
+
Uses the platform `--ring` semantic token so it matches every other
|
|
161
|
+
focusable surface. */
|
|
162
|
+
media-time-range:focus-within {
|
|
163
|
+
--media-range-thumb-box-shadow: 0 0 0 2px var(--ring);
|
|
164
|
+
}
|
|
165
|
+
|
|
130
166
|
media-time-range::part(preview-box) {
|
|
131
167
|
display: none;
|
|
132
168
|
}
|
|
133
169
|
|
|
170
|
+
/*
|
|
171
|
+
* YouTube iframe bleed-through suppression.
|
|
172
|
+
*
|
|
173
|
+
* YouTube's IFrame embed ToS requires showing some chrome that cannot be
|
|
174
|
+
* hidden via player params: the title bar at the top, the large pause
|
|
175
|
+
* button on the pause screen, and the bottom branding/share tray on
|
|
176
|
+
* hover/pause. We can't remove them, but we CAN make them non-interactive
|
|
177
|
+
* — so the user never triggers YouTube's hover-state, never gets a
|
|
178
|
+
* "More videos" overlay, and clicks never reach the YT iframe.
|
|
179
|
+
*
|
|
180
|
+
* The <youtube-video> custom element renders an inner <iframe>; disable
|
|
181
|
+
* pointer events on it (and on the wrapper itself, just in case the
|
|
182
|
+
* element later swaps layout). The companion `.vp-yt-click-shield` div
|
|
183
|
+
* inside <media-controller> absorbs clicks and converts them into
|
|
184
|
+
* media-chrome play/pause requests — so click-to-toggle still works.
|
|
185
|
+
*
|
|
186
|
+
* Our control bar lives above the shield and re-enables pointer events
|
|
187
|
+
* for the slot, so the controls stay clickable.
|
|
188
|
+
*/
|
|
189
|
+
youtube-video,
|
|
190
|
+
youtube-video iframe {
|
|
191
|
+
pointer-events: none;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.vp-yt-click-shield {
|
|
195
|
+
position: absolute;
|
|
196
|
+
inset: 0;
|
|
197
|
+
cursor: pointer;
|
|
198
|
+
background: transparent;
|
|
199
|
+
pointer-events: auto;
|
|
200
|
+
/* Sit above the iframe but below the slotted control bar. */
|
|
201
|
+
z-index: 1;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/* media-chrome slots its control surfaces directly under
|
|
205
|
+
<media-controller>; raise them above the click-shield and restore
|
|
206
|
+
pointer events so buttons remain interactive. */
|
|
207
|
+
media-controller > media-control-bar,
|
|
208
|
+
media-controller > [slot='centered-chrome'],
|
|
209
|
+
media-controller > [slot='top-chrome'] {
|
|
210
|
+
z-index: 2;
|
|
211
|
+
pointer-events: auto;
|
|
212
|
+
}
|
|
213
|
+
|
|
134
214
|
media-time-range::part(current-box) {
|
|
135
215
|
padding: 2px 6px;
|
|
136
216
|
border-radius: 6px;
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* import { LazyResponsiveDialog, LazyResponsiveDialogContent } from '@djangocfg/ui-tools/responsive-dialog';
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import { createLazyComponent, LoadingFallback } from '../../../
|
|
13
|
+
import { createLazyComponent, LoadingFallback } from '../../../common/lazy-wrapper';
|
|
14
14
|
import type {
|
|
15
15
|
ResponsiveDialogProps,
|
|
16
16
|
ResponsiveDialogContentProps,
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Lazy-loaded ScrollSpy Component
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { createLazyComponent, LoadingFallback } from '../../../
|
|
7
|
+
import { createLazyComponent, LoadingFallback } from '../../../common/lazy-wrapper';
|
|
8
8
|
import type {
|
|
9
9
|
ScrollSpyProps,
|
|
10
10
|
ScrollSpyNavProps,
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Lazy-loaded SelectionToolbar Component
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { createLazyComponent, LoadingFallback } from '../../../
|
|
7
|
+
import { createLazyComponent, LoadingFallback } from '../../../common/lazy-wrapper';
|
|
8
8
|
import type {
|
|
9
9
|
SelectionToolbarProps,
|
|
10
10
|
SelectionToolbarContentProps,
|
|
@@ -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 { MarqueeProps } from './types';
|
|
5
5
|
|
|
6
6
|
export const LazyMarquee = createLazyComponent<MarqueeProps>(
|
|
@@ -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 { QRCodeProps } from './types';
|
|
5
5
|
|
|
6
6
|
export const LazyQRCode = createLazyComponent<QRCodeProps>(
|