@jini-ai/ui 0.5.5 → 0.5.6
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/CHANGELOG.md +4 -0
- package/dist/core/theme/validation.js +40 -38
- package/dist/features/a2ui/renderer.js +15 -13
- package/dist/features/about/react/components/AboutTab.js +64 -34
- package/dist/features/about/rules.d.ts +2 -2
- package/dist/features/about/rules.js +156 -129
- package/dist/features/admin-widgets/components/ImagePreviewModal.d.ts +4 -3
- package/dist/features/admin-widgets/components/ImagePreviewModal.js +6 -10
- package/dist/features/admin-widgets/components/InfoTip.d.ts +3 -2
- package/dist/features/admin-widgets/components/InfoTip.hooks.js +2 -0
- package/dist/features/admin-widgets/components/InfoTip.js +34 -7
- package/dist/features/admin-widgets/components/InfoTip.rules.d.ts +13 -0
- package/dist/features/admin-widgets/components/InfoTip.rules.js +43 -10
- package/dist/features/admin-widgets/components/Lightbox/Lightbox.d.ts +30 -0
- package/dist/features/admin-widgets/components/Lightbox/Lightbox.hooks.d.ts +40 -0
- package/dist/features/admin-widgets/components/Lightbox/Lightbox.hooks.js +128 -0
- package/dist/features/admin-widgets/components/Lightbox/Lightbox.js +18 -0
- package/dist/features/admin-widgets/components/MiddleTruncate.d.ts +14 -0
- package/dist/features/admin-widgets/components/MiddleTruncate.js +12 -0
- package/dist/features/admin-widgets/components/MiddleTruncate.rules.d.ts +20 -0
- package/dist/features/admin-widgets/components/MiddleTruncate.rules.js +21 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.d.ts +18 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.hooks.d.ts +16 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.hooks.js +45 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.js +18 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.rules.d.ts +32 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.rules.js +26 -0
- package/dist/features/admin-widgets/components/SuggestInput/SuggestInput.hooks.js +29 -14
- package/dist/features/admin-widgets/index.d.ts +14 -2
- package/dist/features/admin-widgets/index.js +7 -1
- package/dist/features/admin-widgets/styles/admin-widgets.css +1 -0
- package/dist/features/asset-grid/react/components/AssetCard.js +7 -1
- package/dist/features/asset-grid/react/components/AssetGrid.d.ts +1 -1
- package/dist/features/asset-grid/react/components/AssetGrid.js +38 -18
- package/dist/features/asset-grid/react/components/useAssetGridFilters.d.ts +21 -0
- package/dist/features/asset-grid/react/components/useAssetGridFilters.js +19 -0
- package/dist/features/asset-grid/react/hooks/useAssetGridKeyboardShortcuts.js +16 -11
- package/dist/features/asset-grid/react/hooks/useAssetGridLiveUpdates.d.ts +2 -0
- package/dist/features/asset-grid/react/hooks/useAssetGridLiveUpdates.js +35 -11
- package/dist/features/asset-tree-browser/react/components/AssetTreeBrowser.d.ts +6 -6
- package/dist/features/asset-tree-browser/react/components/AssetTreeBrowser.js +10 -129
- package/dist/features/asset-tree-browser/react/components/AssetTreeBrowserParts.d.ts +50 -0
- package/dist/features/asset-tree-browser/react/components/AssetTreeBrowserParts.js +95 -0
- package/dist/features/asset-tree-browser/react/components/useAssetTreeBrowserController.d.ts +56 -0
- package/dist/features/asset-tree-browser/react/components/useAssetTreeBrowserController.js +80 -0
- package/dist/features/asset-tree-browser/rules.js +40 -22
- package/dist/features/browser-chrome/rules.js +74 -70
- package/dist/features/charts/browser.js +11 -5
- package/dist/features/charts/react.js +2 -2
- package/dist/features/charts/table.js +2 -2
- package/dist/features/command-palette/react/hooks/useCommandPalette.js +3 -9
- package/dist/features/connectors/ConnectorsBrowser.d.ts +4 -4
- package/dist/features/connectors/ConnectorsBrowser.js +26 -14
- package/dist/features/connectors/components/ConnectorCard.js +67 -38
- package/dist/features/connectors/components/ConnectorDetailDrawer.js +62 -31
- package/dist/features/connectors/components/ConnectorGrid.js +11 -6
- package/dist/features/connectors/hooks/useConnectorAuthorization.js +6 -0
- package/dist/features/connectors/hooks/useConnectorCatalog.d.ts +2 -0
- package/dist/features/connectors/hooks/useConnectorCatalog.js +32 -13
- package/dist/features/connectors/hooks/useWiredConnectorsBrowser.d.ts +3 -3
- package/dist/features/connectors/rules.d.ts +8 -1
- package/dist/features/connectors/rules.js +42 -20
- package/dist/features/connectors/types.d.ts +11 -0
- package/dist/features/execution/constants.d.ts +4 -10
- package/dist/features/execution/constants.js +9 -94
- package/dist/features/execution/react/components/ByokProviderForm.d.ts +2 -4
- package/dist/features/execution/react/components/ByokProviderForm.js +140 -43
- package/dist/features/execution/react/components/ExecutionTab.d.ts +1 -2
- package/dist/features/execution/react/components/ExecutionTab.js +52 -30
- package/dist/features/execution/react/components/LocalCliAgentCard.js +12 -3
- package/dist/features/execution/react/components/LocalCliAgentList.js +14 -3
- package/dist/features/execution/react/components/LocalCliAgentSettings.js +14 -3
- package/dist/features/execution/react/hooks/useLocalCliAgentCard.js +54 -36
- package/dist/features/execution/react/hooks/useReasoningControl.js +114 -78
- package/dist/features/execution/rules.d.ts +2 -2
- package/dist/features/execution/rules.js +31 -15
- package/dist/features/execution/types.d.ts +4 -42
- package/dist/features/execution/types.js +0 -17
- package/dist/features/external-mcp/react/components/ExternalMcpTab.d.ts +6 -2
- package/dist/features/external-mcp/react/components/ExternalMcpTab.js +9 -2
- package/dist/features/file-dropzone/react/components/FileDropzone.js +24 -25
- package/dist/features/file-dropzone/react/components/FileDropzoneLightbox.d.ts +2 -2
- package/dist/features/file-dropzone/react/components/FileDropzoneLightbox.js +35 -30
- package/dist/features/file-dropzone/react/components/FileDropzoneThumbnailGrid.js +30 -24
- package/dist/features/file-dropzone/react/components/FileDropzoneZone.d.ts +14 -0
- package/dist/features/file-dropzone/react/components/FileDropzoneZone.js +26 -0
- package/dist/features/html-editor/canvas-content-wrapper.js +13 -13
- package/dist/features/html-editor/canvas-embed-placeholders.js +46 -37
- package/dist/features/html-editor/css.js +76 -69
- package/dist/features/html-editor/editor-blocks.js +47 -33
- package/dist/features/html-editor/editor-serialization.js +6 -5
- package/dist/features/html-editor/protected-elements.js +39 -28
- package/dist/features/html-editor/react/hooks/useInteractiveHtmlEditor.js +4 -4
- package/dist/features/html-editor/source-splice.js +51 -30
- package/dist/features/i18n/dictionaries/settings-dialog.ja.js +1 -0
- package/dist/features/i18n/dictionaries/settings-dialog.zh-CN.js +1 -0
- package/dist/features/i18n/dictionaries/settings-dialog.zh-TW.js +1 -0
- package/dist/features/i18n/locale.js +20 -16
- package/dist/features/iframe-pool/react/dom-sync.js +8 -6
- package/dist/features/integrations/react/components/CodexInstallToggleButton.js +19 -4
- package/dist/features/integrations/react/components/IntegrationsTab.js +60 -14
- package/dist/features/interactive-ui/interactive-ui.css +1 -1
- package/dist/features/interactive-ui/providers/shadcn/data-table.js +10 -7
- package/dist/features/lexical-rich-text-editor/mention-parser.js +60 -57
- package/dist/features/lexical-rich-text-editor/react/hooks/useKeyboardCommands.js +33 -38
- package/dist/features/lexical-rich-text-editor/rules.js +87 -74
- package/dist/features/lexical-rich-text-editor/serialize.js +27 -25
- package/dist/features/mcp-ui/secret-card.js +111 -61
- package/dist/features/mcp-ui/surfaces/confirmation.js +39 -21
- package/dist/features/mcp-ui/surfaces/document.d.ts +1 -1
- package/dist/features/mcp-ui/surfaces/document.js +10 -2
- package/dist/features/mcp-ui/surfaces/fields.js +30 -50
- package/dist/features/mcp-ui/surfaces/form.d.ts +6 -0
- package/dist/features/mcp-ui/surfaces/form.js +43 -21
- package/dist/features/mcp-ui/surfaces/outcome.js +30 -20
- package/dist/features/mcp-ui/surfaces/text-input.js +33 -21
- package/dist/features/mcp-ui/surfaces/tokens.d.ts +6 -1
- package/dist/features/mcp-ui/surfaces/tokens.js +5 -2
- package/dist/features/media-providers/constants.d.ts +1 -0
- package/dist/features/media-providers/constants.js +2 -81
- package/dist/features/media-providers/index.d.ts +1 -1
- package/dist/features/media-providers/ports.d.ts +2 -0
- package/dist/features/media-providers/react/components/MediaProviderCard.d.ts +22 -0
- package/dist/features/media-providers/react/components/MediaProviderCard.js +50 -0
- package/dist/features/media-providers/react/components/MediaProvidersTab.d.ts +5 -6
- package/dist/features/media-providers/react/components/MediaProvidersTab.js +40 -72
- package/dist/features/media-providers/react/components/media-providers-tab-labels.d.ts +11 -0
- package/dist/features/media-providers/react/components/media-providers-tab-labels.js +57 -0
- package/dist/features/media-providers/react/hooks/useMediaProvidersTab.d.ts +4 -2
- package/dist/features/media-providers/react/hooks/useMediaProvidersTab.js +37 -23
- package/dist/features/media-providers/rules.js +17 -10
- package/dist/features/media-providers/types.d.ts +4 -22
- package/dist/features/media-providers/types.js +3 -8
- package/dist/features/memory/formatters.js +127 -92
- package/dist/features/memory/react/components/MemoryConnectedPanel.js +92 -36
- package/dist/features/memory/react/components/MemoryList.js +37 -18
- package/dist/features/memory/react/hooks/useMemoryExtractions.store.js +42 -36
- package/dist/features/notifications/react/components/NotificationsTab.js +28 -28
- package/dist/features/observability/long-task.d.ts +0 -12
- package/dist/features/observability/long-task.js +15 -19
- package/dist/features/observability/resource-error.d.ts +0 -10
- package/dist/features/observability/resource-error.js +18 -13
- package/dist/features/observability/stuck-run.js +10 -6
- package/dist/features/observability/telemetry-url.d.ts +6 -0
- package/dist/features/observability/telemetry-url.js +16 -0
- package/dist/features/observability/white-screen.js +12 -24
- package/dist/features/panel-kit/fetch-query/adapter.react.d.ts +2 -2
- package/dist/features/panel-kit/fetch-query/adapter.react.js +4 -2
- package/dist/features/panel-kit/fetch-query/adapter.tanstack.js +46 -33
- package/dist/features/panel-kit/helpers/standing-draft-local-backup.js +3 -1
- package/dist/features/panel-kit/hooks/use-settings-slice.hooks.js +3 -1
- package/dist/features/privacy/react/components/PrivacyTab.js +24 -13
- package/dist/features/progress-card/components/ProgressCard.js +7 -3
- package/dist/features/progress-card/reference-adapters.js +59 -54
- package/dist/features/project-locations/react/components/ProjectLocationsTab.js +24 -15
- package/dist/features/project-locations/react/hooks/useProjectLocationsTab.d.ts +8 -0
- package/dist/features/project-locations/react/hooks/useProjectLocationsTab.js +31 -23
- package/dist/features/resource-dashboard/react/components/ResourceBoard.js +6 -47
- package/dist/features/resource-dashboard/react/components/ResourceBoardView.d.ts +2 -2
- package/dist/features/resource-dashboard/react/components/ResourceBoardView.js +3 -6
- package/dist/features/resource-dashboard/react/components/ResourceBoardViewParts.d.ts +15 -0
- package/dist/features/resource-dashboard/react/components/ResourceBoardViewParts.js +35 -0
- package/dist/features/resource-dashboard/react/components/ResourceCard.js +5 -16
- package/dist/features/resource-dashboard/react/components/ResourceCardParts.d.ts +34 -0
- package/dist/features/resource-dashboard/react/components/ResourceCardParts.js +34 -0
- package/dist/features/resource-dashboard/react/components/ResourceRowList.js +3 -1
- package/dist/features/resource-dashboard/react/components/ResourceRowListItem.js +2 -2
- package/dist/features/resource-dashboard/react/components/ResourceRowListItemParts.d.ts +19 -0
- package/dist/features/resource-dashboard/react/components/ResourceRowListItemParts.js +11 -0
- package/dist/features/resource-dashboard/react/components/ResourceRowListView.d.ts +1 -1
- package/dist/features/resource-dashboard/react/components/ResourceRowListView.js +4 -4
- package/dist/features/resource-dashboard/react/components/ResourceRowListViewParts.d.ts +10 -0
- package/dist/features/resource-dashboard/react/components/ResourceRowListViewParts.js +20 -0
- package/dist/features/resource-dashboard/react/components/resourceBoardProps.d.ts +48 -0
- package/dist/features/resource-dashboard/react/components/resourceBoardProps.js +70 -0
- package/dist/features/resource-dashboard/react/components/resourceRowListProps.d.ts +19 -0
- package/dist/features/resource-dashboard/react/components/resourceRowListProps.js +14 -0
- package/dist/features/resource-dashboard/react/components/translatedErrorLabelProps.d.ts +16 -0
- package/dist/features/resource-dashboard/react/components/translatedErrorLabelProps.js +13 -0
- package/dist/features/resource-dashboard/rules.js +2 -8
- package/dist/features/sketch-editor/dom.js +150 -99
- package/dist/features/sketch-editor/react/components/SketchEditor.js +26 -15
- package/dist/features/skills/react/components/SkillDraftForm.js +13 -19
- package/dist/features/skills/react/components/SkillDraftForm.labels.d.ts +31 -0
- package/dist/features/skills/react/components/SkillDraftForm.labels.js +54 -0
- package/dist/features/skills/react/components/SkillRow.js +38 -18
- package/dist/features/skills/react/components/SkillRow.labels.d.ts +7 -0
- package/dist/features/skills/react/components/SkillRow.labels.js +18 -0
- package/dist/features/skills/react/components/SkillsTab.js +24 -14
- package/dist/features/skills/react/components/SkillsTab.labels.d.ts +7 -0
- package/dist/features/skills/react/components/SkillsTab.labels.js +11 -0
- package/dist/features/skills/rules.js +32 -23
- package/dist/features/source-config-list/agent-handles.js +2 -1
- package/dist/features/source-config-list/dependencies.js +53 -49
- package/dist/features/source-config-list/index.d.ts +3 -3
- package/dist/features/source-config-list/react/components/SourceConfigAddForm.d.ts +6 -5
- package/dist/features/source-config-list/react/components/SourceConfigAddForm.js +38 -7
- package/dist/features/source-config-list/react/components/SourceConfigField.js +69 -25
- package/dist/features/source-config-list/react/components/SourceConfigItemCard.d.ts +6 -5
- package/dist/features/source-config-list/react/components/SourceConfigItemCard.js +76 -20
- package/dist/features/source-config-list/react/components/SourceConfigListView.d.ts +5 -3
- package/dist/features/source-config-list/react/components/SourceConfigListView.js +33 -3
- package/dist/features/source-config-list/react/components/SourceConfigTestControl.js +17 -1
- package/dist/features/source-config-list/react/components/SourceConfigTrustOptions.d.ts +11 -0
- package/dist/features/source-config-list/react/components/SourceConfigTrustOptions.js +12 -0
- package/dist/features/source-config-list/types.d.ts +14 -0
- package/dist/features/tab-launcher-menu/react/components/TabLauncherMenu.js +25 -1
- package/dist/features/tab-launcher-menu/react/hooks/useTabLauncherMenu.js +15 -16
- package/dist/features/tab-strip/react/components/TabBar.js +8 -1
- package/dist/features/tabbed-dialog/react/components/TabbedDialog.js +8 -30
- package/dist/features/tabbed-dialog/react/components/TabbedDialogChrome.d.ts +15 -0
- package/dist/features/tabbed-dialog/react/components/TabbedDialogChrome.js +8 -0
- package/dist/features/tabbed-dialog/react/components/TabbedDialogHeader.d.ts +12 -0
- package/dist/features/tabbed-dialog/react/components/TabbedDialogHeader.js +6 -0
- package/dist/features/tabbed-dialog/react/components/TabbedDialogSidebar.d.ts +27 -0
- package/dist/features/tabbed-dialog/react/components/TabbedDialogSidebar.js +12 -0
- package/dist/features/tabbed-dialog/react/components/tabbedDialogView.d.ts +43 -0
- package/dist/features/tabbed-dialog/react/components/tabbedDialogView.js +59 -0
- package/dist/features/version-manager/dependencies.d.ts +3 -1
- package/dist/features/version-manager/dependencies.js +3 -2
- package/dist/features/version-manager/react/components/VersionManagerModal.js +10 -6
- package/dist/features/version-manager/react/hooks/useVersionManager.js +7 -4
- package/dist/features/viewer-shell/react/components/CommentSidePanel.js +103 -50
- package/dist/features/viewer-shell/react/components/MarkdownSplitPane.js +28 -8
- package/dist/features/viewer-shell/react/hooks/useCommentReorder.js +22 -16
- package/dist/features/viewer-shell/rules.js +19 -23
- package/dist/react/components/CustomSelect.d.ts +38 -1
- package/dist/react/components/CustomSelect.js +94 -38
- package/dist/react/components/OnboardingDropdown.js +20 -8
- package/dist/react/components/RemixIcon.stylesheet.js +3 -1
- package/dist/react/components/Toast.js +13 -2
- package/dist/react/components/TooltipLayer.js +5 -14
- package/dist/react/components/WorkingDirPicker.js +78 -50
- package/dist/react/components/remixicon-font-recovery.js +38 -30
- package/dist/react/components/select-popover.d.ts +8 -6
- package/dist/react/components/select-popover.js +33 -29
- package/dist/react/mcp-ui/McpUiHost.d.ts +1 -1
- package/dist/react/mcp-ui/McpUiHost.js +10 -11
- package/dist/react/mcp-ui/host-message-source.d.ts +14 -2
- package/dist/react/mcp-ui/host-message-source.js +15 -5
- package/dist/react/mcp-ui/mcp-ui-host-frame.d.ts +41 -0
- package/dist/react/mcp-ui/mcp-ui-host-frame.js +39 -0
- package/dist/renderers/annotation-canvas/react/components/AnnotationCanvas.js +97 -69
- package/dist/renderers/preview-modal-shell/react/components/PreviewModalShell.js +59 -30
- package/dist/renderers/react/components/ArtifactView.js +9 -6
- package/dist/renderers/srcdoc/build.d.ts +4 -1
- package/dist/renderers/srcdoc/build.js +62 -48
- package/dist/styles/admin.css +29 -14
- package/dist/styles/lightbox.css +142 -0
- package/dist/styles/variables.css +128 -0
- package/dist/theme/apply.js +9 -5
- package/dist/utils/auto-open-file.d.ts +2 -1
- package/dist/utils/auto-open-file.js +69 -85
- package/dist/utils/markdown-scroll-sync.js +108 -87
- package/dist/utils/polygon-selection.js +25 -26
- package/dist/utils/smooth-scroll-to-top.d.ts +1 -1
- package/dist/utils/smooth-scroll-to-top.js +2 -32
- package/dist/utils/sse.js +26 -26
- package/dist/utils/unit-bezier.d.ts +7 -0
- package/dist/utils/unit-bezier.js +38 -0
- package/package.json +7 -10
- package/dist/features/admin-widgets/components/ImagePreviewModal.hooks.d.ts +0 -13
- package/dist/features/admin-widgets/components/ImagePreviewModal.hooks.js +0 -46
|
@@ -1,27 +1,8 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs
|
|
2
|
-
import { useEffect, useMemo } from 'react';
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
2
|
import { useT } from '../../../i18n/index.js';
|
|
4
|
-
import { DEFAULT_KIND_CONFIG_MAP
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { useAssetTreeBatchActions } from '../hooks/useAssetTreeBatchActions.js';
|
|
8
|
-
import { useAssetTreeClipboardPasteUpload } from '../hooks/useAssetTreeClipboardPasteUpload.js';
|
|
9
|
-
import { useAssetTreeCopyLocalPath } from '../hooks/useAssetTreeCopyLocalPath.js';
|
|
10
|
-
import { useAssetTreeDragUpload } from '../hooks/useAssetTreeDragUpload.js';
|
|
11
|
-
import { useAssetTreeNavigation } from '../hooks/useAssetTreeNavigation.js';
|
|
12
|
-
import { useAssetTreePreview } from '../hooks/useAssetTreePreview.js';
|
|
13
|
-
import { useAssetTreeRename } from '../hooks/useAssetTreeRename.js';
|
|
14
|
-
import { useAssetTreeRowMenu } from '../hooks/useAssetTreeRowMenu.js';
|
|
15
|
-
import { useAssetTreeSelection } from '../hooks/useAssetTreeSelection.js';
|
|
16
|
-
import { AssetTreeBreadcrumbs } from './AssetTreeBreadcrumbs.js';
|
|
17
|
-
import { AssetTreeEmptyState } from './AssetTreeEmptyState.js';
|
|
18
|
-
import { AssetTreeFileRow } from './AssetTreeFileRow.js';
|
|
19
|
-
import { AssetTreeFolderRow } from './AssetTreeFolderRow.js';
|
|
20
|
-
import { AssetTreeRowMenu } from './AssetTreeRowMenu.js';
|
|
21
|
-
import { AssetTreeSelectionBar } from './AssetTreeSelectionBar.js';
|
|
22
|
-
import { AssetTreeToolbar } from './AssetTreeToolbar.js';
|
|
23
|
-
import { AssetTreeUploadErrorBanner } from './AssetTreeUploadErrorBanner.js';
|
|
24
|
-
import { FilePreviewPane } from './FilePreviewPane.js';
|
|
3
|
+
import { DEFAULT_KIND_CONFIG_MAP } from '../../constants.js';
|
|
4
|
+
import { AssetTreeBrowserBody, AssetTreeBrowserPreview, AssetTreeBrowserRowMenu, AssetTreeBrowserTopbar, } from './AssetTreeBrowserParts.js';
|
|
5
|
+
import { useAssetTreeBrowserController } from './useAssetTreeBrowserController.js';
|
|
25
6
|
/**
|
|
26
7
|
* A directory-navigable file tree: breadcrumbs, a host-supplied toolbar,
|
|
27
8
|
* kind-grouped sections with a pinned Folders section, row selection with
|
|
@@ -33,118 +14,18 @@ import { FilePreviewPane } from './FilePreviewPane.js';
|
|
|
33
14
|
* section, project menu, rotating-tip footer, and file-kind-specific
|
|
34
15
|
* preview rendering).
|
|
35
16
|
*/
|
|
36
|
-
export function AssetTreeBrowser(
|
|
17
|
+
export function AssetTreeBrowser(props) {
|
|
37
18
|
const t = useT();
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
// wrapper. Deliberately not fixed here: unlike ConnectorsBrowser's `deps`
|
|
42
|
-
// (fed to exactly the 3 already-overridable sub-hooks), this `deps` also
|
|
43
|
-
// feeds `useAssetTreeRowMenu`, `useAssetTreeClipboardPasteUpload`, and
|
|
44
|
-
// `useAssetTreeCopyLocalPath` below — none of which currently have their
|
|
45
|
-
// own override props — so collapsing it into one wired hook is a real
|
|
46
|
-
// design decision (what belongs in the wired hook vs. stays overridable)
|
|
47
|
-
// rather than a mechanical port of the ConnectorsBrowser pattern. Lower
|
|
48
|
-
// severity than that one too: these are DOM/clipboard adapters, not
|
|
49
|
-
// remote data fetching.
|
|
50
|
-
const deps = useMemo(() => dependencies ?? createBrowserAssetTreeDependencies(), [dependencies]);
|
|
51
|
-
const navigation = useAssetTreeNavigationHook({
|
|
52
|
-
files,
|
|
53
|
-
folders,
|
|
54
|
-
sectionOrder,
|
|
55
|
-
getKind: selectors.getKind,
|
|
56
|
-
getModifiedAt: selectors.getModifiedAt,
|
|
57
|
-
navState,
|
|
58
|
-
onNavStateChange,
|
|
59
|
-
});
|
|
60
|
-
const preview = useAssetTreePreviewHook(files, selectInitialPreviewFile);
|
|
61
|
-
// Declared before `useAssetTreeSelection` so its in-flight `renaming.path`
|
|
62
|
-
// (if any) can be threaded into selection's prune logic as
|
|
63
|
-
// `pendingRenamePath` — see that hook's doc comment for the race this
|
|
64
|
-
// closes. `onRenamed` referencing `selection` here (declared below) is
|
|
65
|
-
// safe: it's a closure that only actually runs later, once `selection` is
|
|
66
|
-
// fully bound.
|
|
67
|
-
const rename = useAssetTreeRenameHook({
|
|
68
|
-
currentDir: navigation.currentDir,
|
|
69
|
-
onRenameFile,
|
|
70
|
-
onRenamed: (oldPath, renamedFile) => {
|
|
71
|
-
if (preview.previewPath === oldPath)
|
|
72
|
-
preview.setPreviewPath(renamedFile.path);
|
|
73
|
-
selection.renamePath(oldPath, renamedFile.path);
|
|
74
|
-
},
|
|
75
|
-
});
|
|
76
|
-
const selection = useAssetTreeSelectionHook(navigation.filesAtCurrentDir, navigation.currentDir, rename.renaming?.path ?? null);
|
|
77
|
-
const rowMenu = useAssetTreeRowMenu(deps.dom);
|
|
78
|
-
const dragUpload = useAssetTreeDragUpload(onUploadFiles);
|
|
79
|
-
useAssetTreeClipboardPasteUpload({
|
|
80
|
-
dom: deps.dom,
|
|
81
|
-
onUploadFiles,
|
|
82
|
-
onBeforeUpload: dragUpload.clearDropReadError,
|
|
83
|
-
});
|
|
84
|
-
const batchActions = useAssetTreeBatchActions({ selected: selection.selected, onDeleteFiles, downloadFiles });
|
|
85
|
-
const copyLocalPath = useAssetTreeCopyLocalPath(deps.clipboard);
|
|
86
|
-
useEffect(() => {
|
|
87
|
-
onSelectionChange?.(selection.selected);
|
|
88
|
-
}, [selection.selected, onSelectionChange]);
|
|
89
|
-
function findFile(path) {
|
|
90
|
-
return files.find((f) => f.path === path);
|
|
91
|
-
}
|
|
92
|
-
function openPath(path) {
|
|
93
|
-
const target = findFile(path);
|
|
94
|
-
if (target)
|
|
95
|
-
onOpenFile(target);
|
|
96
|
-
}
|
|
97
|
-
const menuFile = rowMenu.menuPos ? (findFile(rowMenu.menuPos.path) ?? null) : null;
|
|
19
|
+
const { files, folders, selectors, kindConfig = DEFAULT_KIND_CONFIG_MAP, getFileUrl } = props;
|
|
20
|
+
const controller = useAssetTreeBrowserController(props, props);
|
|
21
|
+
const { navigation, preview, selection, rowMenu, dragUpload } = controller;
|
|
98
22
|
const hasSelection = selection.selected.size > 0;
|
|
99
|
-
const isEmpty = files.length === 0 && (folders?.length ?? 0) === 0;
|
|
100
23
|
const previewedFile = preview.previewFile;
|
|
101
|
-
|
|
102
|
-
return (_jsxs("div", { className: `asset-tree-panel${previewedFile ? '' : ' no-preview'}${hasSelection ? ' has-selection' : ''}`, children: [reloading ? (_jsx("div", { className: "asset-tree-reloading-overlay", "data-testid": "asset-tree-reloading", children: t('Loading…') })) : null, _jsxs("div", { className: "asset-tree-main", children: [_jsxs("div", { className: "asset-tree-topbar", children: [_jsx("div", { className: "asset-tree-topbar-left", children: _jsx(AssetTreeBreadcrumbs, { currentDir: navigation.currentDir, rootLabel: rootLabel ?? t('Files'), onNavigate: navigation.setCurrentDir }) }), _jsx("div", { className: "asset-tree-topbar-right", children: _jsx(AssetTreeToolbar, { actions: toolbarActions }) })] }), _jsxs("div", { className: "asset-tree-body", "data-testid": "asset-tree-body", onDragEnter: dragUpload.onDragEnter, onDragOver: dragUpload.onDragOver, onDragLeave: dragUpload.onDragLeave, onDrop: dragUpload.onDrop, children: [dragUpload.dropReadError && !preview.previewPath ? (_jsx(AssetTreeUploadErrorBanner, { message: dragUpload.dropReadError, onDismiss: dragUpload.clearDropReadError })) : null, hasSelection ? (_jsx(AssetTreeSelectionBar, { count: selection.selected.size, onClear: selection.clearSelection, onDelete: () => void batchActions.deleteSelected(), deleting: batchActions.deleting, onDownload: downloadFiles ? () => void batchActions.downloadSelected() : undefined, downloading: batchActions.downloading, downloadError: batchActions.downloadError })) : null, isEmpty ? (_jsx(AssetTreeEmptyState, { actions: emptyStateActions })) : (_jsxs(_Fragment, { children: [navigation.dirsAtCurrentDir.length > 0 ? (_jsxs("div", { className: "asset-tree-section", children: [_jsxs("div", { className: "asset-tree-section-label", children: [t('Folders'), _jsx("span", { className: "asset-tree-section-count", children: navigation.dirsAtCurrentDir.length })] }), navigation.dirsAtCurrentDir.map((dirName) => {
|
|
103
|
-
const fullPath = navigation.currentDir === '' ? dirName : `${navigation.currentDir}/${dirName}`;
|
|
104
|
-
return (_jsx(AssetTreeFolderRow, { name: dirName, path: fullPath, fileCount: countFilesUnderDir(files, fullPath), onNavigate: navigation.setCurrentDir }, fullPath));
|
|
105
|
-
})] }, "folders")) : null, navigation.sections.map((section) => {
|
|
106
|
-
const config = resolveKindConfig(section.kind, kindConfig);
|
|
107
|
-
return (_jsxs("div", { className: "asset-tree-section", children: [_jsxs("div", { className: "asset-tree-section-label", children: [t(config.label), _jsx("span", { className: "asset-tree-section-count", children: section.files.length })] }), section.files.map((f) => (_jsx(AssetTreeFileRow, { path: f.path, displayName: basenameForRename(f.path, navigation.currentDir), active: preview.previewPath === f.path, selected: selection.selected.has(f.path), kindLabel: t(config.label), kindGlyph: config.glyph, size: selectors.getSize(f), modifiedAt: selectors.getModifiedAt(f), renaming: rename.renaming?.path === f.path ? rename.renaming : null, onSelectPreview: preview.setPreviewPath, onOpen: openPath, onToggleSelect: selection.toggleSelect, onOpenMenu: rowMenu.openMenuFor, onRenameDraftChange: rename.updateDraft, onCommitRename: () => void rename.commitRename(), onCancelRename: rename.cancelRename }, f.path)))] }, `kind:${section.kind}`));
|
|
108
|
-
})] })), footer] }), dragUpload.draggingFiles ? (_jsx("div", { className: "asset-tree-drop-overlay", "aria-hidden": true, "data-testid": "asset-tree-drop-overlay", children: _jsx("div", { className: "asset-tree-drop-overlay-card", children: _jsx("span", { className: "label", children: t('Drop to upload') }) }) })) : null] }), previewedFile && previewKindConfig ? (_jsx(FilePreviewPane
|
|
24
|
+
return (_jsxs("div", { className: `asset-tree-panel${previewedFile ? '' : ' no-preview'}${hasSelection ? ' has-selection' : ''}`, children: [props.reloading ? (_jsx("div", { className: "asset-tree-reloading-overlay", "data-testid": "asset-tree-reloading", children: t('Loading…') })) : null, _jsxs("div", { className: "asset-tree-main", children: [_jsx(AssetTreeBrowserTopbar, { currentDir: navigation.currentDir, rootLabel: props.rootLabel, onNavigate: navigation.setCurrentDir, toolbarActions: props.toolbarActions }), _jsx(AssetTreeBrowserBody, { controller: controller, files: files, folders: folders, selectors: selectors, kindConfig: kindConfig, downloadFiles: props.downloadFiles, emptyStateActions: props.emptyStateActions, footer: props.footer }), dragUpload.draggingFiles ? (_jsx("div", { className: "asset-tree-drop-overlay", "aria-hidden": true, "data-testid": "asset-tree-drop-overlay", children: _jsx("div", { className: "asset-tree-drop-overlay-card", children: _jsx("span", { className: "label", children: t('Drop to upload') }) }) })) : null] }), previewedFile ? (_jsx(AssetTreeBrowserPreview
|
|
109
25
|
// Keyed on the path so a host's `renderThumbnail` (which may mount
|
|
110
26
|
// a heavy/stateful element like an iframe or canvas) fully
|
|
111
27
|
// remounts when the user switches files, instead of React reusing
|
|
112
28
|
// the same DOM node across two different files.
|
|
113
|
-
, { file: previewedFile,
|
|
114
|
-
? { href: getFileUrl(menuFile), onClick: rowMenu.closeMenu }
|
|
115
|
-
: undefined, onOpen: () => {
|
|
116
|
-
const path = rowMenu.menuPos.path;
|
|
117
|
-
rowMenu.closeMenu();
|
|
118
|
-
openPath(path);
|
|
119
|
-
}, onRename: () => {
|
|
120
|
-
const path = rowMenu.menuPos.path;
|
|
121
|
-
rowMenu.closeMenu();
|
|
122
|
-
rename.startRename(path);
|
|
123
|
-
},
|
|
124
|
-
// Deliberately does NOT close the menu (unlike every other action
|
|
125
|
-
// here) — the origin `DesignFilesPanel`'s equivalent handler did
|
|
126
|
-
// call `setMenuPos(null)` before copying, which meant its
|
|
127
|
-
// "Copied" confirmation label could never actually become visible
|
|
128
|
-
// to a user (it only ever renders inside the now-closed popover).
|
|
129
|
-
// Since the whole point of `copiedPath`/the transient-confirmation
|
|
130
|
-
// UI is to be seen, this keeps the menu open so it can be; the
|
|
131
|
-
// existing outside-dismiss/Escape handling still closes it
|
|
132
|
-
// normally afterward.
|
|
133
|
-
onCopyLocalPath: () => {
|
|
134
|
-
const path = rowMenu.menuPos.path;
|
|
135
|
-
// `canCopyLocalPath` (passed below) already gates the button's
|
|
136
|
-
// `disabled` state on `!!menuFile`, so a click can only reach
|
|
137
|
-
// this handler when `menuFile` is non-null — asserting that
|
|
138
|
-
// instead of re-guarding it here avoids an unreachable `: null`
|
|
139
|
-
// ternary arm (a real click can never fire on a disabled
|
|
140
|
-
// button, so that arm was dead code, not defensive coding).
|
|
141
|
-
const localPath = selectors.getLocalPath?.(menuFile);
|
|
142
|
-
if (localPath)
|
|
143
|
-
void copyLocalPath.copyLocalPath(path, localPath);
|
|
144
|
-
}, onDelete: () => {
|
|
145
|
-
const path = rowMenu.menuPos.path;
|
|
146
|
-
rowMenu.closeMenu();
|
|
147
|
-
onDeleteFile(path);
|
|
148
|
-
} })) : null] }));
|
|
29
|
+
, { file: previewedFile, selectors: selectors, kindConfig: kindConfig, onOpenFile: props.onOpenFile, onClose: preview.clearPreview, getFileUrl: getFileUrl, renderPreviewThumbnail: props.renderPreviewThumbnail, thumbnailIsInteractive: props.thumbnailIsInteractive }, previewedFile.path)) : null, rowMenu.menuPos ? (_jsx(AssetTreeBrowserRowMenu, { controller: controller, menuPos: rowMenu.menuPos, selectors: selectors, getFileUrl: getFileUrl, onDeleteFile: props.onDeleteFile })) : null] }));
|
|
149
30
|
}
|
|
150
31
|
//# sourceMappingURL=AssetTreeBrowser.js.map
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { AssetTreeFileItem, AssetTreeFolderItem, AssetTreeKindConfigMap, AssetTreeMenuPosition, AssetTreeSelectors, AssetTreeToolbarAction } from '../../types.js';
|
|
3
|
+
import type { AssetTreeBrowserController } from './useAssetTreeBrowserController.js';
|
|
4
|
+
interface ControllerProps<TFile> {
|
|
5
|
+
controller: AssetTreeBrowserController<TFile>;
|
|
6
|
+
}
|
|
7
|
+
export interface AssetTreeBrowserTopbarProps {
|
|
8
|
+
currentDir: string;
|
|
9
|
+
rootLabel?: string | undefined;
|
|
10
|
+
onNavigate: (dir: string) => void;
|
|
11
|
+
toolbarActions?: readonly AssetTreeToolbarAction[] | undefined;
|
|
12
|
+
}
|
|
13
|
+
/** Breadcrumbs (root label defaults to `t('Files')`) plus the host toolbar. */
|
|
14
|
+
export declare function AssetTreeBrowserTopbar({ currentDir, rootLabel, onNavigate, toolbarActions, }: AssetTreeBrowserTopbarProps): import("react").JSX.Element;
|
|
15
|
+
export interface AssetTreeBrowserBodyProps<TFile extends AssetTreeFileItem> extends ControllerProps<TFile> {
|
|
16
|
+
files: TFile[];
|
|
17
|
+
folders?: AssetTreeFolderItem[] | undefined;
|
|
18
|
+
selectors: AssetTreeSelectors<TFile>;
|
|
19
|
+
kindConfig: AssetTreeKindConfigMap;
|
|
20
|
+
downloadFiles?: ((paths: string[]) => Promise<{
|
|
21
|
+
blob: Blob;
|
|
22
|
+
filename: string;
|
|
23
|
+
}>) | undefined;
|
|
24
|
+
emptyStateActions?: readonly AssetTreeToolbarAction[] | undefined;
|
|
25
|
+
footer?: ReactNode;
|
|
26
|
+
}
|
|
27
|
+
/** The drop-target listing area: upload-error banner, selection bar, folders + kind sections (or the empty state), footer. */
|
|
28
|
+
export declare function AssetTreeBrowserBody<TFile extends AssetTreeFileItem>(props: AssetTreeBrowserBodyProps<TFile>): import("react").JSX.Element;
|
|
29
|
+
export interface AssetTreeBrowserPreviewProps<TFile extends AssetTreeFileItem> {
|
|
30
|
+
file: TFile;
|
|
31
|
+
selectors: AssetTreeSelectors<TFile>;
|
|
32
|
+
kindConfig: AssetTreeKindConfigMap;
|
|
33
|
+
onOpenFile: (file: TFile) => void;
|
|
34
|
+
onClose: () => void;
|
|
35
|
+
getFileUrl?: ((file: TFile) => string) | undefined;
|
|
36
|
+
renderPreviewThumbnail?: ((file: TFile) => ReactNode) | undefined;
|
|
37
|
+
thumbnailIsInteractive?: boolean | undefined;
|
|
38
|
+
}
|
|
39
|
+
/** `FilePreviewPane` for the previewed `file`, with its kind display config resolved. */
|
|
40
|
+
export declare function AssetTreeBrowserPreview<TFile extends AssetTreeFileItem>({ file, selectors, kindConfig, onOpenFile, onClose, getFileUrl, renderPreviewThumbnail, thumbnailIsInteractive, }: AssetTreeBrowserPreviewProps<TFile>): import("react").JSX.Element;
|
|
41
|
+
export interface AssetTreeBrowserRowMenuProps<TFile extends AssetTreeFileItem> extends ControllerProps<TFile> {
|
|
42
|
+
menuPos: AssetTreeMenuPosition;
|
|
43
|
+
selectors: AssetTreeSelectors<TFile>;
|
|
44
|
+
getFileUrl?: ((file: TFile) => string) | undefined;
|
|
45
|
+
onDeleteFile: (path: string) => void;
|
|
46
|
+
}
|
|
47
|
+
/** The open row context menu for `menuPos.path`, with every action wired. */
|
|
48
|
+
export declare function AssetTreeBrowserRowMenu<TFile extends AssetTreeFileItem>({ controller, menuPos, selectors, getFileUrl, onDeleteFile, }: AssetTreeBrowserRowMenuProps<TFile>): import("react").JSX.Element;
|
|
49
|
+
export {};
|
|
50
|
+
//# sourceMappingURL=AssetTreeBrowserParts.d.ts.map
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useT } from '../../../i18n/index.js';
|
|
3
|
+
import { EMPTY_TOOLBAR_ACTIONS } from '../../constants.js';
|
|
4
|
+
import { basenameForRename, canCopyLocalPath, countFilesUnderDir, resolveKindConfig } from '../../rules.js';
|
|
5
|
+
import { AssetTreeBreadcrumbs } from './AssetTreeBreadcrumbs.js';
|
|
6
|
+
import { AssetTreeEmptyState } from './AssetTreeEmptyState.js';
|
|
7
|
+
import { AssetTreeFileRow } from './AssetTreeFileRow.js';
|
|
8
|
+
import { AssetTreeFolderRow } from './AssetTreeFolderRow.js';
|
|
9
|
+
import { AssetTreeRowMenu } from './AssetTreeRowMenu.js';
|
|
10
|
+
import { AssetTreeSelectionBar } from './AssetTreeSelectionBar.js';
|
|
11
|
+
import { AssetTreeToolbar } from './AssetTreeToolbar.js';
|
|
12
|
+
import { AssetTreeUploadErrorBanner } from './AssetTreeUploadErrorBanner.js';
|
|
13
|
+
import { FilePreviewPane } from './FilePreviewPane.js';
|
|
14
|
+
/** Breadcrumbs (root label defaults to `t('Files')`) plus the host toolbar. */
|
|
15
|
+
export function AssetTreeBrowserTopbar({ currentDir, rootLabel, onNavigate, toolbarActions = EMPTY_TOOLBAR_ACTIONS, }) {
|
|
16
|
+
const t = useT();
|
|
17
|
+
return (_jsxs("div", { className: "asset-tree-topbar", children: [_jsx("div", { className: "asset-tree-topbar-left", children: _jsx(AssetTreeBreadcrumbs, { currentDir: currentDir, rootLabel: rootLabel ?? t('Files'), onNavigate: onNavigate }) }), _jsx("div", { className: "asset-tree-topbar-right", children: _jsx(AssetTreeToolbar, { actions: toolbarActions }) })] }));
|
|
18
|
+
}
|
|
19
|
+
/** The drop-target listing area: upload-error banner, selection bar, folders + kind sections (or the empty state), footer. */
|
|
20
|
+
export function AssetTreeBrowserBody(props) {
|
|
21
|
+
const { controller, downloadFiles, footer } = props;
|
|
22
|
+
const { dragUpload, preview } = controller;
|
|
23
|
+
return (_jsxs("div", { className: "asset-tree-body", "data-testid": "asset-tree-body", onDragEnter: dragUpload.onDragEnter, onDragOver: dragUpload.onDragOver, onDragLeave: dragUpload.onDragLeave, onDrop: dragUpload.onDrop, children: [dragUpload.dropReadError && !preview.previewPath ? (_jsx(AssetTreeUploadErrorBanner, { message: dragUpload.dropReadError, onDismiss: dragUpload.clearDropReadError })) : null, _jsx(AssetTreeBrowserSelectionBar, { controller: controller, downloadFiles: downloadFiles }), _jsx(AssetTreeBrowserListing, { ...props }), footer] }));
|
|
24
|
+
}
|
|
25
|
+
function AssetTreeBrowserSelectionBar({ controller, downloadFiles, }) {
|
|
26
|
+
const { selection, batchActions } = controller;
|
|
27
|
+
if (selection.selected.size === 0)
|
|
28
|
+
return null;
|
|
29
|
+
return (_jsx(AssetTreeSelectionBar, { count: selection.selected.size, onClear: selection.clearSelection, onDelete: () => void batchActions.deleteSelected(), deleting: batchActions.deleting, onDownload: downloadFiles ? () => void batchActions.downloadSelected() : undefined, downloading: batchActions.downloading, downloadError: batchActions.downloadError }));
|
|
30
|
+
}
|
|
31
|
+
function AssetTreeBrowserListing({ controller, files, folders, selectors, kindConfig, emptyStateActions = EMPTY_TOOLBAR_ACTIONS, }) {
|
|
32
|
+
const { navigation } = controller;
|
|
33
|
+
const isEmpty = files.length === 0 && (folders?.length ?? 0) === 0;
|
|
34
|
+
if (isEmpty)
|
|
35
|
+
return _jsx(AssetTreeEmptyState, { actions: emptyStateActions });
|
|
36
|
+
return (_jsxs(_Fragment, { children: [_jsx(AssetTreeFoldersSection, { files: files, dirs: navigation.dirsAtCurrentDir, currentDir: navigation.currentDir, onNavigate: navigation.setCurrentDir }, "folders"), navigation.sections.map((section) => (_jsx(AssetTreeKindSection, { controller: controller, section: section, selectors: selectors, kindConfig: kindConfig }, `kind:${section.kind}`)))] }));
|
|
37
|
+
}
|
|
38
|
+
function AssetTreeFoldersSection({ files, dirs, currentDir, onNavigate, }) {
|
|
39
|
+
const t = useT();
|
|
40
|
+
if (dirs.length === 0)
|
|
41
|
+
return null;
|
|
42
|
+
return (_jsxs("div", { className: "asset-tree-section", children: [_jsxs("div", { className: "asset-tree-section-label", children: [t('Folders'), _jsx("span", { className: "asset-tree-section-count", children: dirs.length })] }), dirs.map((dirName) => {
|
|
43
|
+
const fullPath = currentDir === '' ? dirName : `${currentDir}/${dirName}`;
|
|
44
|
+
return (_jsx(AssetTreeFolderRow, { name: dirName, path: fullPath, fileCount: countFilesUnderDir(files, fullPath), onNavigate: onNavigate }, fullPath));
|
|
45
|
+
})] }));
|
|
46
|
+
}
|
|
47
|
+
function AssetTreeKindSection({ controller, section, selectors, kindConfig, }) {
|
|
48
|
+
const t = useT();
|
|
49
|
+
const { navigation, preview, selection, rename, rowMenu, openPath } = controller;
|
|
50
|
+
const config = resolveKindConfig(section.kind, kindConfig);
|
|
51
|
+
return (_jsxs("div", { className: "asset-tree-section", children: [_jsxs("div", { className: "asset-tree-section-label", children: [t(config.label), _jsx("span", { className: "asset-tree-section-count", children: section.files.length })] }), section.files.map((f) => (_jsx(AssetTreeFileRow, { path: f.path, displayName: basenameForRename(f.path, navigation.currentDir), active: preview.previewPath === f.path, selected: selection.selected.has(f.path), kindLabel: t(config.label), kindGlyph: config.glyph, size: selectors.getSize(f), modifiedAt: selectors.getModifiedAt(f), renaming: rename.renaming?.path === f.path ? rename.renaming : null, onSelectPreview: preview.setPreviewPath, onOpen: openPath, onToggleSelect: selection.toggleSelect, onOpenMenu: rowMenu.openMenuFor, onRenameDraftChange: rename.updateDraft, onCommitRename: () => void rename.commitRename(), onCancelRename: rename.cancelRename }, f.path)))] }));
|
|
52
|
+
}
|
|
53
|
+
/** `FilePreviewPane` for the previewed `file`, with its kind display config resolved. */
|
|
54
|
+
export function AssetTreeBrowserPreview({ file, selectors, kindConfig, onOpenFile, onClose, getFileUrl, renderPreviewThumbnail, thumbnailIsInteractive, }) {
|
|
55
|
+
const t = useT();
|
|
56
|
+
const previewKindConfig = resolveKindConfig(selectors.getKind(file), kindConfig);
|
|
57
|
+
return (_jsx(FilePreviewPane, { file: file, path: file.path, kindLabel: t(previewKindConfig.label), kindGlyph: previewKindConfig.glyph, size: selectors.getSize(file), modifiedAt: selectors.getModifiedAt(file), onOpen: () => onOpenFile(file), onClose: onClose, downloadHref: getFileUrl?.(file), renderThumbnail: renderPreviewThumbnail, thumbnailIsInteractive: thumbnailIsInteractive }));
|
|
58
|
+
}
|
|
59
|
+
/** The open row context menu for `menuPos.path`, with every action wired. */
|
|
60
|
+
export function AssetTreeBrowserRowMenu({ controller, menuPos, selectors, getFileUrl, onDeleteFile, }) {
|
|
61
|
+
const { navigation, rowMenu, rename, copyLocalPath, findFile, openPath } = controller;
|
|
62
|
+
const { path } = menuPos;
|
|
63
|
+
const menuFile = findFile(path) ?? null;
|
|
64
|
+
return (_jsx(AssetTreeRowMenu, { path: path, displayName: basenameForRename(path, navigation.currentDir), top: menuPos.top, left: menuPos.left, containerRef: rowMenu.containerRef, canCopyLocalPath: !!menuFile && canCopyLocalPath(menuFile, selectors), copied: copyLocalPath.copiedPath === path, download: getFileUrl && menuFile ? { href: getFileUrl(menuFile), onClick: rowMenu.closeMenu } : undefined, onOpen: () => {
|
|
65
|
+
rowMenu.closeMenu();
|
|
66
|
+
openPath(path);
|
|
67
|
+
}, onRename: () => {
|
|
68
|
+
rowMenu.closeMenu();
|
|
69
|
+
rename.startRename(path);
|
|
70
|
+
},
|
|
71
|
+
// Deliberately does NOT close the menu (unlike every other action
|
|
72
|
+
// here) — the origin `DesignFilesPanel`'s equivalent handler did
|
|
73
|
+
// call `setMenuPos(null)` before copying, which meant its
|
|
74
|
+
// "Copied" confirmation label could never actually become visible
|
|
75
|
+
// to a user (it only ever renders inside the now-closed popover).
|
|
76
|
+
// Since the whole point of `copiedPath`/the transient-confirmation
|
|
77
|
+
// UI is to be seen, this keeps the menu open so it can be; the
|
|
78
|
+
// existing outside-dismiss/Escape handling still closes it
|
|
79
|
+
// normally afterward.
|
|
80
|
+
onCopyLocalPath: () => {
|
|
81
|
+
// `canCopyLocalPath` (passed below) already gates the button's
|
|
82
|
+
// `disabled` state on `!!menuFile`, so a click can only reach
|
|
83
|
+
// this handler when `menuFile` is non-null — asserting that
|
|
84
|
+
// instead of re-guarding it here avoids an unreachable `: null`
|
|
85
|
+
// ternary arm (a real click can never fire on a disabled
|
|
86
|
+
// button, so that arm was dead code, not defensive coding).
|
|
87
|
+
const localPath = selectors.getLocalPath?.(menuFile);
|
|
88
|
+
if (localPath)
|
|
89
|
+
void copyLocalPath.copyLocalPath(path, localPath);
|
|
90
|
+
}, onDelete: () => {
|
|
91
|
+
rowMenu.closeMenu();
|
|
92
|
+
onDeleteFile(path);
|
|
93
|
+
} }));
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=AssetTreeBrowserParts.js.map
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { AssetTreeDependencies } from '../../ports.js';
|
|
2
|
+
import type { AssetTreeFileItem, AssetTreeFolderItem, AssetTreeNavState, AssetTreeSelectors } from '../../types.js';
|
|
3
|
+
import { type UseAssetTreeBatchActionsResult } from '../hooks/useAssetTreeBatchActions.js';
|
|
4
|
+
import { type UseAssetTreeCopyLocalPathResult } from '../hooks/useAssetTreeCopyLocalPath.js';
|
|
5
|
+
import { type UseAssetTreeDragUploadResult } from '../hooks/useAssetTreeDragUpload.js';
|
|
6
|
+
import { useAssetTreeNavigation, type UseAssetTreeNavigationResult } from '../hooks/useAssetTreeNavigation.js';
|
|
7
|
+
import { useAssetTreePreview, type UseAssetTreePreviewResult } from '../hooks/useAssetTreePreview.js';
|
|
8
|
+
import { useAssetTreeRename, type UseAssetTreeRenameResult } from '../hooks/useAssetTreeRename.js';
|
|
9
|
+
import { type UseAssetTreeRowMenuResult } from '../hooks/useAssetTreeRowMenu.js';
|
|
10
|
+
import { useAssetTreeSelection, type UseAssetTreeSelectionResult } from '../hooks/useAssetTreeSelection.js';
|
|
11
|
+
/** The `AssetTreeBrowser` props every controller run needs. */
|
|
12
|
+
export interface AssetTreeBrowserControllerInput<TFile extends AssetTreeFileItem> {
|
|
13
|
+
files: TFile[];
|
|
14
|
+
selectors: AssetTreeSelectors<TFile>;
|
|
15
|
+
onOpenFile: (file: TFile) => void;
|
|
16
|
+
onRenameFile: (path: string, nextPath: string) => Promise<TFile | null> | TFile | null;
|
|
17
|
+
onDeleteFiles: (paths: string[]) => Promise<void> | void;
|
|
18
|
+
onUploadFiles: (files: File[]) => void;
|
|
19
|
+
}
|
|
20
|
+
/** The optional `AssetTreeBrowser` props the controller consumes, with the same defaults the component documents. */
|
|
21
|
+
export interface AssetTreeBrowserControllerOptions<TFile extends AssetTreeFileItem> {
|
|
22
|
+
folders?: AssetTreeFolderItem[];
|
|
23
|
+
sectionOrder?: readonly string[];
|
|
24
|
+
dependencies?: AssetTreeDependencies;
|
|
25
|
+
navState?: AssetTreeNavState;
|
|
26
|
+
onNavStateChange?: (state: AssetTreeNavState) => void;
|
|
27
|
+
onSelectionChange?: (paths: Set<string>) => void;
|
|
28
|
+
downloadFiles?: (paths: string[]) => Promise<{
|
|
29
|
+
blob: Blob;
|
|
30
|
+
filename: string;
|
|
31
|
+
}>;
|
|
32
|
+
selectInitialPreviewFile?: (files: TFile[]) => TFile | null;
|
|
33
|
+
useAssetTreeNavigation?: typeof useAssetTreeNavigation;
|
|
34
|
+
useAssetTreePreview?: typeof useAssetTreePreview;
|
|
35
|
+
useAssetTreeRename?: typeof useAssetTreeRename;
|
|
36
|
+
useAssetTreeSelection?: typeof useAssetTreeSelection;
|
|
37
|
+
}
|
|
38
|
+
export interface AssetTreeBrowserController<TFile> {
|
|
39
|
+
navigation: UseAssetTreeNavigationResult<TFile>;
|
|
40
|
+
preview: UseAssetTreePreviewResult<TFile>;
|
|
41
|
+
rename: UseAssetTreeRenameResult;
|
|
42
|
+
selection: UseAssetTreeSelectionResult;
|
|
43
|
+
rowMenu: UseAssetTreeRowMenuResult;
|
|
44
|
+
dragUpload: UseAssetTreeDragUploadResult;
|
|
45
|
+
batchActions: UseAssetTreeBatchActionsResult;
|
|
46
|
+
copyLocalPath: UseAssetTreeCopyLocalPathResult;
|
|
47
|
+
findFile: (path: string) => TFile | undefined;
|
|
48
|
+
/** Resolves `path` against `files` and opens it; a path no longer in `files` is a no-op. */
|
|
49
|
+
openPath: (path: string) => void;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Every hook `AssetTreeBrowser` composes, wired together in the one order
|
|
53
|
+
* their cross-references need, so the component itself is pure rendering.
|
|
54
|
+
*/
|
|
55
|
+
export declare function useAssetTreeBrowserController<TFile extends AssetTreeFileItem>(input: AssetTreeBrowserControllerInput<TFile>, { folders, sectionOrder, dependencies, navState, onNavStateChange, onSelectionChange, downloadFiles, selectInitialPreviewFile, useAssetTreeNavigation: useAssetTreeNavigationHook, useAssetTreePreview: useAssetTreePreviewHook, useAssetTreeRename: useAssetTreeRenameHook, useAssetTreeSelection: useAssetTreeSelectionHook, }: AssetTreeBrowserControllerOptions<TFile>): AssetTreeBrowserController<TFile>;
|
|
56
|
+
//# sourceMappingURL=useAssetTreeBrowserController.d.ts.map
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { useEffect, useMemo } from 'react';
|
|
2
|
+
import { DEFAULT_SECTION_ORDER } from '../../constants.js';
|
|
3
|
+
import { createBrowserAssetTreeDependencies } from '../../dependencies.js';
|
|
4
|
+
import { useAssetTreeBatchActions } from '../hooks/useAssetTreeBatchActions.js';
|
|
5
|
+
import { useAssetTreeClipboardPasteUpload } from '../hooks/useAssetTreeClipboardPasteUpload.js';
|
|
6
|
+
import { useAssetTreeCopyLocalPath } from '../hooks/useAssetTreeCopyLocalPath.js';
|
|
7
|
+
import { useAssetTreeDragUpload } from '../hooks/useAssetTreeDragUpload.js';
|
|
8
|
+
import { useAssetTreeNavigation } from '../hooks/useAssetTreeNavigation.js';
|
|
9
|
+
import { useAssetTreePreview } from '../hooks/useAssetTreePreview.js';
|
|
10
|
+
import { useAssetTreeRename } from '../hooks/useAssetTreeRename.js';
|
|
11
|
+
import { useAssetTreeRowMenu } from '../hooks/useAssetTreeRowMenu.js';
|
|
12
|
+
import { useAssetTreeSelection } from '../hooks/useAssetTreeSelection.js';
|
|
13
|
+
/**
|
|
14
|
+
* Every hook `AssetTreeBrowser` composes, wired together in the one order
|
|
15
|
+
* their cross-references need, so the component itself is pure rendering.
|
|
16
|
+
*/
|
|
17
|
+
export function useAssetTreeBrowserController(input, { folders, sectionOrder = DEFAULT_SECTION_ORDER, dependencies, navState, onNavStateChange, onSelectionChange, downloadFiles, selectInitialPreviewFile, useAssetTreeNavigation: useAssetTreeNavigationHook = useAssetTreeNavigation, useAssetTreePreview: useAssetTreePreviewHook = useAssetTreePreview, useAssetTreeRename: useAssetTreeRenameHook = useAssetTreeRename, useAssetTreeSelection: useAssetTreeSelectionHook = useAssetTreeSelection, }) {
|
|
18
|
+
const { files, selectors, onOpenFile, onRenameFile, onDeleteFiles, onUploadFiles } = input;
|
|
19
|
+
// KNOWN FOLLOW-UP (flagged by the 2026-07-22 verification pass, not yet
|
|
20
|
+
// fixed): this has the same useWiredX gap ConnectorsBrowser had — `deps`
|
|
21
|
+
// resolution is still inline instead of behind a `useWiredAssetTreeBrowser`
|
|
22
|
+
// wrapper. Deliberately not fixed here: unlike ConnectorsBrowser's `deps`
|
|
23
|
+
// (fed to exactly the 3 already-overridable sub-hooks), this `deps` also
|
|
24
|
+
// feeds `useAssetTreeRowMenu`, `useAssetTreeClipboardPasteUpload`, and
|
|
25
|
+
// `useAssetTreeCopyLocalPath` below — none of which currently have their
|
|
26
|
+
// own override props — so collapsing it into one wired hook is a real
|
|
27
|
+
// design decision (what belongs in the wired hook vs. stays overridable)
|
|
28
|
+
// rather than a mechanical port of the ConnectorsBrowser pattern. Lower
|
|
29
|
+
// severity than that one too: these are DOM/clipboard adapters, not
|
|
30
|
+
// remote data fetching.
|
|
31
|
+
const deps = useMemo(() => dependencies ?? createBrowserAssetTreeDependencies(), [dependencies]);
|
|
32
|
+
const navigation = useAssetTreeNavigationHook({
|
|
33
|
+
files,
|
|
34
|
+
folders,
|
|
35
|
+
sectionOrder,
|
|
36
|
+
getKind: selectors.getKind,
|
|
37
|
+
getModifiedAt: selectors.getModifiedAt,
|
|
38
|
+
navState,
|
|
39
|
+
onNavStateChange,
|
|
40
|
+
});
|
|
41
|
+
const preview = useAssetTreePreviewHook(files, selectInitialPreviewFile);
|
|
42
|
+
// Declared before `useAssetTreeSelection` so its in-flight `renaming.path`
|
|
43
|
+
// (if any) can be threaded into selection's prune logic as
|
|
44
|
+
// `pendingRenamePath` — see that hook's doc comment for the race this
|
|
45
|
+
// closes. `onRenamed` referencing `selection` here (declared below) is
|
|
46
|
+
// safe: it's a closure that only actually runs later, once `selection` is
|
|
47
|
+
// fully bound.
|
|
48
|
+
const rename = useAssetTreeRenameHook({
|
|
49
|
+
currentDir: navigation.currentDir,
|
|
50
|
+
onRenameFile,
|
|
51
|
+
onRenamed: (oldPath, renamedFile) => {
|
|
52
|
+
if (preview.previewPath === oldPath)
|
|
53
|
+
preview.setPreviewPath(renamedFile.path);
|
|
54
|
+
selection.renamePath(oldPath, renamedFile.path);
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
const selection = useAssetTreeSelectionHook(navigation.filesAtCurrentDir, navigation.currentDir, rename.renaming?.path ?? null);
|
|
58
|
+
const rowMenu = useAssetTreeRowMenu(deps.dom);
|
|
59
|
+
const dragUpload = useAssetTreeDragUpload(onUploadFiles);
|
|
60
|
+
useAssetTreeClipboardPasteUpload({
|
|
61
|
+
dom: deps.dom,
|
|
62
|
+
onUploadFiles,
|
|
63
|
+
onBeforeUpload: dragUpload.clearDropReadError,
|
|
64
|
+
});
|
|
65
|
+
const batchActions = useAssetTreeBatchActions({ selected: selection.selected, onDeleteFiles, downloadFiles });
|
|
66
|
+
const copyLocalPath = useAssetTreeCopyLocalPath(deps.clipboard);
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
onSelectionChange?.(selection.selected);
|
|
69
|
+
}, [selection.selected, onSelectionChange]);
|
|
70
|
+
function findFile(path) {
|
|
71
|
+
return files.find((f) => f.path === path);
|
|
72
|
+
}
|
|
73
|
+
function openPath(path) {
|
|
74
|
+
const target = findFile(path);
|
|
75
|
+
if (target)
|
|
76
|
+
onOpenFile(target);
|
|
77
|
+
}
|
|
78
|
+
return { navigation, preview, rename, selection, rowMenu, dragUpload, batchActions, copyLocalPath, findFile, openPath };
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=useAssetTreeBrowserController.js.map
|
|
@@ -25,36 +25,54 @@ import { DEFAULT_KIND_GLYPH, DOUBLE_ACTIVATION_WINDOW_MS, ROW_MENU_ESTIMATED_HEI
|
|
|
25
25
|
* this asymmetry looks surprising but is exactly what the source does.
|
|
26
26
|
*/
|
|
27
27
|
export function deriveTreeChildren(files, folders, currentDir) {
|
|
28
|
-
const
|
|
28
|
+
const isRoot = currentDir === '';
|
|
29
|
+
const prefix = isRoot ? '' : `${currentDir}/`;
|
|
29
30
|
const dirs = new Set();
|
|
31
|
+
const localFiles = collectFileChildren({ files, prefix, isRoot, dirs });
|
|
32
|
+
collectFolderChildren({ folders, prefix, dirs });
|
|
33
|
+
return {
|
|
34
|
+
dirsAtCurrentDir: [...dirs].sort((a, b) => a.localeCompare(b)),
|
|
35
|
+
filesAtCurrentDir: localFiles,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/** The first path component of `path` below `prefix`, or `null` when `path` is outside `prefix`. */
|
|
39
|
+
function childSegment(path, prefix) {
|
|
40
|
+
if (!path.startsWith(prefix))
|
|
41
|
+
return null;
|
|
42
|
+
const remainder = path.slice(prefix.length);
|
|
43
|
+
const slashIdx = remainder.indexOf('/');
|
|
44
|
+
if (slashIdx === -1)
|
|
45
|
+
return { head: remainder, nested: false };
|
|
46
|
+
return { head: remainder.slice(0, slashIdx), nested: true };
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* File half of {@link deriveTreeChildren}: adds each nested file's top
|
|
50
|
+
* segment to `dirs` and returns the files listed at this level (every
|
|
51
|
+
* in-prefix file at the root, only one-level-deep files elsewhere).
|
|
52
|
+
*/
|
|
53
|
+
function collectFileChildren(input) {
|
|
30
54
|
const localFiles = [];
|
|
31
|
-
for (const f of files) {
|
|
32
|
-
|
|
55
|
+
for (const f of input.files) {
|
|
56
|
+
const segment = childSegment(f.path, input.prefix);
|
|
57
|
+
if (!segment)
|
|
33
58
|
continue;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if (
|
|
59
|
+
if (segment.nested)
|
|
60
|
+
input.dirs.add(segment.head);
|
|
61
|
+
if (!segment.nested || input.isRoot)
|
|
37
62
|
localFiles.push(f);
|
|
38
|
-
}
|
|
39
|
-
else {
|
|
40
|
-
dirs.add(remainder.slice(0, slashIdx));
|
|
41
|
-
if (currentDir === '')
|
|
42
|
-
localFiles.push(f);
|
|
43
|
-
}
|
|
44
63
|
}
|
|
45
|
-
|
|
46
|
-
|
|
64
|
+
return localFiles;
|
|
65
|
+
}
|
|
66
|
+
/** Folder half of {@link deriveTreeChildren}: adds each persisted folder's top segment below `prefix` to `dirs`. */
|
|
67
|
+
function collectFolderChildren(input) {
|
|
68
|
+
for (const folder of input.folders) {
|
|
69
|
+
const segment = childSegment(folder.path, input.prefix);
|
|
70
|
+
if (!segment)
|
|
47
71
|
continue;
|
|
48
|
-
|
|
49
|
-
if (!remainder)
|
|
72
|
+
if (!segment.nested && !segment.head)
|
|
50
73
|
continue; // the current directory itself
|
|
51
|
-
|
|
52
|
-
dirs.add(slashIdx === -1 ? remainder : remainder.slice(0, slashIdx));
|
|
74
|
+
input.dirs.add(segment.head);
|
|
53
75
|
}
|
|
54
|
-
return {
|
|
55
|
-
dirsAtCurrentDir: [...dirs].sort((a, b) => a.localeCompare(b)),
|
|
56
|
-
filesAtCurrentDir: localFiles,
|
|
57
|
-
};
|
|
58
76
|
}
|
|
59
77
|
/** Total files (at every depth, not just the immediate level) under `dirPath` — what a folder row's "N files" subtitle counts. */
|
|
60
78
|
export function countFilesUnderDir(files, dirPath) {
|