@jini-ai/ui 0.5.4 → 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.
Files changed (270) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/core/theme/validation.js +40 -38
  3. package/dist/features/a2ui/renderer.js +15 -13
  4. package/dist/features/about/react/components/AboutTab.js +64 -34
  5. package/dist/features/about/rules.d.ts +2 -2
  6. package/dist/features/about/rules.js +156 -129
  7. package/dist/features/admin-widgets/components/ImagePreviewModal.d.ts +4 -3
  8. package/dist/features/admin-widgets/components/ImagePreviewModal.js +6 -10
  9. package/dist/features/admin-widgets/components/InfoTip.d.ts +3 -2
  10. package/dist/features/admin-widgets/components/InfoTip.hooks.js +2 -0
  11. package/dist/features/admin-widgets/components/InfoTip.js +34 -7
  12. package/dist/features/admin-widgets/components/InfoTip.rules.d.ts +13 -0
  13. package/dist/features/admin-widgets/components/InfoTip.rules.js +43 -10
  14. package/dist/features/admin-widgets/components/Lightbox/Lightbox.d.ts +30 -0
  15. package/dist/features/admin-widgets/components/Lightbox/Lightbox.hooks.d.ts +40 -0
  16. package/dist/features/admin-widgets/components/Lightbox/Lightbox.hooks.js +128 -0
  17. package/dist/features/admin-widgets/components/Lightbox/Lightbox.js +18 -0
  18. package/dist/features/admin-widgets/components/MiddleTruncate.d.ts +14 -0
  19. package/dist/features/admin-widgets/components/MiddleTruncate.js +12 -0
  20. package/dist/features/admin-widgets/components/MiddleTruncate.rules.d.ts +20 -0
  21. package/dist/features/admin-widgets/components/MiddleTruncate.rules.js +21 -0
  22. package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.d.ts +18 -0
  23. package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.hooks.d.ts +16 -0
  24. package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.hooks.js +45 -0
  25. package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.js +18 -0
  26. package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.rules.d.ts +32 -0
  27. package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.rules.js +26 -0
  28. package/dist/features/admin-widgets/components/Select/Select.hooks.d.ts +21 -0
  29. package/dist/features/admin-widgets/components/Select/Select.hooks.js +24 -2
  30. package/dist/features/admin-widgets/components/Select/Select.js +4 -3
  31. package/dist/features/admin-widgets/components/SuggestInput/SuggestInput.hooks.js +29 -14
  32. package/dist/features/admin-widgets/index.d.ts +14 -2
  33. package/dist/features/admin-widgets/index.js +7 -1
  34. package/dist/features/admin-widgets/styles/admin-widgets.css +1 -0
  35. package/dist/features/asset-grid/react/components/AssetCard.js +7 -1
  36. package/dist/features/asset-grid/react/components/AssetGrid.d.ts +1 -1
  37. package/dist/features/asset-grid/react/components/AssetGrid.js +38 -18
  38. package/dist/features/asset-grid/react/components/useAssetGridFilters.d.ts +21 -0
  39. package/dist/features/asset-grid/react/components/useAssetGridFilters.js +19 -0
  40. package/dist/features/asset-grid/react/hooks/useAssetGridKeyboardShortcuts.js +16 -11
  41. package/dist/features/asset-grid/react/hooks/useAssetGridLiveUpdates.d.ts +2 -0
  42. package/dist/features/asset-grid/react/hooks/useAssetGridLiveUpdates.js +35 -11
  43. package/dist/features/asset-tree-browser/react/components/AssetTreeBrowser.d.ts +6 -6
  44. package/dist/features/asset-tree-browser/react/components/AssetTreeBrowser.js +10 -129
  45. package/dist/features/asset-tree-browser/react/components/AssetTreeBrowserParts.d.ts +50 -0
  46. package/dist/features/asset-tree-browser/react/components/AssetTreeBrowserParts.js +95 -0
  47. package/dist/features/asset-tree-browser/react/components/useAssetTreeBrowserController.d.ts +56 -0
  48. package/dist/features/asset-tree-browser/react/components/useAssetTreeBrowserController.js +80 -0
  49. package/dist/features/asset-tree-browser/rules.js +40 -22
  50. package/dist/features/browser-chrome/rules.js +74 -70
  51. package/dist/features/charts/browser.js +11 -5
  52. package/dist/features/charts/react.js +2 -2
  53. package/dist/features/charts/table.js +2 -2
  54. package/dist/features/command-palette/react/hooks/useCommandPalette.js +3 -9
  55. package/dist/features/connectors/ConnectorsBrowser.d.ts +4 -4
  56. package/dist/features/connectors/ConnectorsBrowser.js +26 -14
  57. package/dist/features/connectors/components/ConnectorCard.js +67 -38
  58. package/dist/features/connectors/components/ConnectorDetailDrawer.js +62 -31
  59. package/dist/features/connectors/components/ConnectorGrid.js +11 -6
  60. package/dist/features/connectors/hooks/useConnectorAuthorization.js +6 -0
  61. package/dist/features/connectors/hooks/useConnectorCatalog.d.ts +2 -0
  62. package/dist/features/connectors/hooks/useConnectorCatalog.js +32 -13
  63. package/dist/features/connectors/hooks/useWiredConnectorsBrowser.d.ts +3 -3
  64. package/dist/features/connectors/rules.d.ts +8 -1
  65. package/dist/features/connectors/rules.js +42 -20
  66. package/dist/features/connectors/types.d.ts +11 -0
  67. package/dist/features/execution/constants.d.ts +4 -10
  68. package/dist/features/execution/constants.js +9 -94
  69. package/dist/features/execution/react/components/ByokProviderForm.d.ts +2 -4
  70. package/dist/features/execution/react/components/ByokProviderForm.js +140 -43
  71. package/dist/features/execution/react/components/ExecutionTab.d.ts +1 -2
  72. package/dist/features/execution/react/components/ExecutionTab.js +52 -30
  73. package/dist/features/execution/react/components/LocalCliAgentCard.js +12 -3
  74. package/dist/features/execution/react/components/LocalCliAgentList.js +14 -3
  75. package/dist/features/execution/react/components/LocalCliAgentSettings.js +14 -3
  76. package/dist/features/execution/react/hooks/useLocalCliAgentCard.js +54 -36
  77. package/dist/features/execution/react/hooks/useReasoningControl.d.ts +1 -1
  78. package/dist/features/execution/react/hooks/useReasoningControl.js +116 -75
  79. package/dist/features/execution/rules.d.ts +13 -2
  80. package/dist/features/execution/rules.js +51 -11
  81. package/dist/features/execution/types.d.ts +6 -42
  82. package/dist/features/execution/types.js +0 -17
  83. package/dist/features/external-mcp/react/components/ExternalMcpTab.d.ts +6 -2
  84. package/dist/features/external-mcp/react/components/ExternalMcpTab.js +9 -2
  85. package/dist/features/file-dropzone/react/components/FileDropzone.js +24 -25
  86. package/dist/features/file-dropzone/react/components/FileDropzoneLightbox.d.ts +2 -2
  87. package/dist/features/file-dropzone/react/components/FileDropzoneLightbox.js +35 -30
  88. package/dist/features/file-dropzone/react/components/FileDropzoneThumbnailGrid.js +30 -24
  89. package/dist/features/file-dropzone/react/components/FileDropzoneZone.d.ts +14 -0
  90. package/dist/features/file-dropzone/react/components/FileDropzoneZone.js +26 -0
  91. package/dist/features/html-editor/canvas-content-wrapper.js +13 -13
  92. package/dist/features/html-editor/canvas-embed-placeholders.js +46 -37
  93. package/dist/features/html-editor/css.js +76 -69
  94. package/dist/features/html-editor/editor-blocks.js +47 -33
  95. package/dist/features/html-editor/editor-serialization.js +6 -5
  96. package/dist/features/html-editor/protected-elements.js +39 -28
  97. package/dist/features/html-editor/react/hooks/useInteractiveHtmlEditor.js +4 -4
  98. package/dist/features/html-editor/source-splice.js +51 -30
  99. package/dist/features/i18n/dictionaries/settings-dialog.ja.js +1 -0
  100. package/dist/features/i18n/dictionaries/settings-dialog.zh-CN.js +1 -0
  101. package/dist/features/i18n/dictionaries/settings-dialog.zh-TW.js +1 -0
  102. package/dist/features/i18n/locale.js +20 -16
  103. package/dist/features/iframe-pool/react/dom-sync.js +8 -6
  104. package/dist/features/integrations/react/components/CodexInstallToggleButton.js +19 -4
  105. package/dist/features/integrations/react/components/IntegrationsTab.js +60 -14
  106. package/dist/features/interactive-ui/interactive-ui.css +1 -1
  107. package/dist/features/interactive-ui/providers/native/data-table.manifest.d.ts +6 -6
  108. package/dist/features/interactive-ui/providers/shadcn/data-table.js +10 -7
  109. package/dist/features/interactive-ui/providers/shadcn/data-table.manifest.d.ts +6 -6
  110. package/dist/features/lexical-rich-text-editor/mention-parser.js +60 -57
  111. package/dist/features/lexical-rich-text-editor/react/hooks/useKeyboardCommands.js +33 -38
  112. package/dist/features/lexical-rich-text-editor/rules.js +87 -74
  113. package/dist/features/lexical-rich-text-editor/serialize.js +27 -25
  114. package/dist/features/mcp-ui/secret-card.js +111 -61
  115. package/dist/features/mcp-ui/surfaces/confirmation.js +39 -21
  116. package/dist/features/mcp-ui/surfaces/document.d.ts +1 -1
  117. package/dist/features/mcp-ui/surfaces/document.js +10 -2
  118. package/dist/features/mcp-ui/surfaces/fields.js +30 -50
  119. package/dist/features/mcp-ui/surfaces/form.d.ts +6 -0
  120. package/dist/features/mcp-ui/surfaces/form.js +43 -21
  121. package/dist/features/mcp-ui/surfaces/outcome.js +30 -20
  122. package/dist/features/mcp-ui/surfaces/text-input.js +33 -21
  123. package/dist/features/mcp-ui/surfaces/tokens.d.ts +6 -1
  124. package/dist/features/mcp-ui/surfaces/tokens.js +5 -2
  125. package/dist/features/media-providers/constants.d.ts +1 -0
  126. package/dist/features/media-providers/constants.js +2 -81
  127. package/dist/features/media-providers/index.d.ts +1 -1
  128. package/dist/features/media-providers/ports.d.ts +2 -0
  129. package/dist/features/media-providers/react/components/MediaProviderCard.d.ts +22 -0
  130. package/dist/features/media-providers/react/components/MediaProviderCard.js +50 -0
  131. package/dist/features/media-providers/react/components/MediaProvidersTab.d.ts +5 -6
  132. package/dist/features/media-providers/react/components/MediaProvidersTab.js +40 -72
  133. package/dist/features/media-providers/react/components/media-providers-tab-labels.d.ts +11 -0
  134. package/dist/features/media-providers/react/components/media-providers-tab-labels.js +57 -0
  135. package/dist/features/media-providers/react/hooks/useMediaProvidersTab.d.ts +4 -2
  136. package/dist/features/media-providers/react/hooks/useMediaProvidersTab.js +37 -23
  137. package/dist/features/media-providers/rules.js +17 -10
  138. package/dist/features/media-providers/types.d.ts +4 -22
  139. package/dist/features/media-providers/types.js +3 -8
  140. package/dist/features/memory/formatters.js +127 -92
  141. package/dist/features/memory/react/components/MemoryConnectedPanel.js +92 -36
  142. package/dist/features/memory/react/components/MemoryList.js +37 -18
  143. package/dist/features/memory/react/hooks/useMemoryExtractions.store.js +42 -36
  144. package/dist/features/notifications/react/components/NotificationsTab.js +28 -28
  145. package/dist/features/observability/long-task.d.ts +0 -12
  146. package/dist/features/observability/long-task.js +15 -19
  147. package/dist/features/observability/resource-error.d.ts +0 -10
  148. package/dist/features/observability/resource-error.js +18 -13
  149. package/dist/features/observability/stuck-run.js +10 -6
  150. package/dist/features/observability/telemetry-url.d.ts +6 -0
  151. package/dist/features/observability/telemetry-url.js +16 -0
  152. package/dist/features/observability/white-screen.js +12 -24
  153. package/dist/features/panel-kit/fetch-query/adapter.react.d.ts +2 -2
  154. package/dist/features/panel-kit/fetch-query/adapter.react.js +4 -2
  155. package/dist/features/panel-kit/fetch-query/adapter.tanstack.js +46 -33
  156. package/dist/features/panel-kit/helpers/standing-draft-local-backup.js +3 -1
  157. package/dist/features/panel-kit/hooks/use-settings-slice.hooks.js +3 -1
  158. package/dist/features/privacy/react/components/PrivacyTab.js +24 -13
  159. package/dist/features/progress-card/components/ProgressCard.js +7 -3
  160. package/dist/features/progress-card/reference-adapters.js +59 -54
  161. package/dist/features/project-locations/react/components/ProjectLocationsTab.js +24 -15
  162. package/dist/features/project-locations/react/hooks/useProjectLocationsTab.d.ts +8 -0
  163. package/dist/features/project-locations/react/hooks/useProjectLocationsTab.js +31 -23
  164. package/dist/features/resource-dashboard/react/components/ResourceBoard.js +6 -47
  165. package/dist/features/resource-dashboard/react/components/ResourceBoardView.d.ts +2 -2
  166. package/dist/features/resource-dashboard/react/components/ResourceBoardView.js +3 -6
  167. package/dist/features/resource-dashboard/react/components/ResourceBoardViewParts.d.ts +15 -0
  168. package/dist/features/resource-dashboard/react/components/ResourceBoardViewParts.js +35 -0
  169. package/dist/features/resource-dashboard/react/components/ResourceCard.js +5 -16
  170. package/dist/features/resource-dashboard/react/components/ResourceCardParts.d.ts +34 -0
  171. package/dist/features/resource-dashboard/react/components/ResourceCardParts.js +34 -0
  172. package/dist/features/resource-dashboard/react/components/ResourceRowList.js +3 -1
  173. package/dist/features/resource-dashboard/react/components/ResourceRowListItem.js +2 -2
  174. package/dist/features/resource-dashboard/react/components/ResourceRowListItemParts.d.ts +19 -0
  175. package/dist/features/resource-dashboard/react/components/ResourceRowListItemParts.js +11 -0
  176. package/dist/features/resource-dashboard/react/components/ResourceRowListView.d.ts +1 -1
  177. package/dist/features/resource-dashboard/react/components/ResourceRowListView.js +4 -4
  178. package/dist/features/resource-dashboard/react/components/ResourceRowListViewParts.d.ts +10 -0
  179. package/dist/features/resource-dashboard/react/components/ResourceRowListViewParts.js +20 -0
  180. package/dist/features/resource-dashboard/react/components/resourceBoardProps.d.ts +48 -0
  181. package/dist/features/resource-dashboard/react/components/resourceBoardProps.js +70 -0
  182. package/dist/features/resource-dashboard/react/components/resourceRowListProps.d.ts +19 -0
  183. package/dist/features/resource-dashboard/react/components/resourceRowListProps.js +14 -0
  184. package/dist/features/resource-dashboard/react/components/translatedErrorLabelProps.d.ts +16 -0
  185. package/dist/features/resource-dashboard/react/components/translatedErrorLabelProps.js +13 -0
  186. package/dist/features/resource-dashboard/rules.js +2 -8
  187. package/dist/features/sketch-editor/dom.js +150 -99
  188. package/dist/features/sketch-editor/react/components/SketchEditor.js +26 -15
  189. package/dist/features/skills/react/components/SkillDraftForm.js +13 -19
  190. package/dist/features/skills/react/components/SkillDraftForm.labels.d.ts +31 -0
  191. package/dist/features/skills/react/components/SkillDraftForm.labels.js +54 -0
  192. package/dist/features/skills/react/components/SkillRow.js +38 -18
  193. package/dist/features/skills/react/components/SkillRow.labels.d.ts +7 -0
  194. package/dist/features/skills/react/components/SkillRow.labels.js +18 -0
  195. package/dist/features/skills/react/components/SkillsTab.js +24 -14
  196. package/dist/features/skills/react/components/SkillsTab.labels.d.ts +7 -0
  197. package/dist/features/skills/react/components/SkillsTab.labels.js +11 -0
  198. package/dist/features/skills/rules.js +32 -23
  199. package/dist/features/source-config-list/agent-handles.js +2 -1
  200. package/dist/features/source-config-list/dependencies.js +53 -49
  201. package/dist/features/source-config-list/index.d.ts +3 -3
  202. package/dist/features/source-config-list/react/components/SourceConfigAddForm.d.ts +6 -5
  203. package/dist/features/source-config-list/react/components/SourceConfigAddForm.js +38 -7
  204. package/dist/features/source-config-list/react/components/SourceConfigField.js +69 -25
  205. package/dist/features/source-config-list/react/components/SourceConfigItemCard.d.ts +6 -5
  206. package/dist/features/source-config-list/react/components/SourceConfigItemCard.js +76 -20
  207. package/dist/features/source-config-list/react/components/SourceConfigListView.d.ts +5 -3
  208. package/dist/features/source-config-list/react/components/SourceConfigListView.js +33 -3
  209. package/dist/features/source-config-list/react/components/SourceConfigTestControl.js +17 -1
  210. package/dist/features/source-config-list/react/components/SourceConfigTrustOptions.d.ts +11 -0
  211. package/dist/features/source-config-list/react/components/SourceConfigTrustOptions.js +12 -0
  212. package/dist/features/source-config-list/types.d.ts +14 -0
  213. package/dist/features/tab-launcher-menu/react/components/TabLauncherMenu.js +25 -1
  214. package/dist/features/tab-launcher-menu/react/hooks/useTabLauncherMenu.js +15 -16
  215. package/dist/features/tab-strip/react/components/TabBar.js +8 -1
  216. package/dist/features/tabbed-dialog/react/components/TabbedDialog.js +8 -30
  217. package/dist/features/tabbed-dialog/react/components/TabbedDialogChrome.d.ts +15 -0
  218. package/dist/features/tabbed-dialog/react/components/TabbedDialogChrome.js +8 -0
  219. package/dist/features/tabbed-dialog/react/components/TabbedDialogHeader.d.ts +12 -0
  220. package/dist/features/tabbed-dialog/react/components/TabbedDialogHeader.js +6 -0
  221. package/dist/features/tabbed-dialog/react/components/TabbedDialogSidebar.d.ts +27 -0
  222. package/dist/features/tabbed-dialog/react/components/TabbedDialogSidebar.js +12 -0
  223. package/dist/features/tabbed-dialog/react/components/tabbedDialogView.d.ts +43 -0
  224. package/dist/features/tabbed-dialog/react/components/tabbedDialogView.js +59 -0
  225. package/dist/features/version-manager/dependencies.d.ts +3 -1
  226. package/dist/features/version-manager/dependencies.js +3 -2
  227. package/dist/features/version-manager/react/components/VersionManagerModal.js +10 -6
  228. package/dist/features/version-manager/react/hooks/useVersionManager.js +7 -4
  229. package/dist/features/viewer-shell/react/components/CommentSidePanel.js +103 -50
  230. package/dist/features/viewer-shell/react/components/MarkdownSplitPane.js +28 -8
  231. package/dist/features/viewer-shell/react/hooks/useCommentReorder.js +22 -16
  232. package/dist/features/viewer-shell/rules.js +19 -23
  233. package/dist/react/components/CustomSelect.d.ts +38 -1
  234. package/dist/react/components/CustomSelect.js +94 -38
  235. package/dist/react/components/OnboardingDropdown.js +20 -8
  236. package/dist/react/components/RemixIcon.stylesheet.js +3 -1
  237. package/dist/react/components/Toast.js +13 -2
  238. package/dist/react/components/TooltipLayer.js +5 -14
  239. package/dist/react/components/WorkingDirPicker.js +78 -50
  240. package/dist/react/components/remixicon-font-recovery.js +38 -30
  241. package/dist/react/components/select-popover.d.ts +8 -6
  242. package/dist/react/components/select-popover.js +33 -29
  243. package/dist/react/mcp-ui/McpUiHost.d.ts +1 -1
  244. package/dist/react/mcp-ui/McpUiHost.js +10 -11
  245. package/dist/react/mcp-ui/host-message-source.d.ts +14 -2
  246. package/dist/react/mcp-ui/host-message-source.js +15 -5
  247. package/dist/react/mcp-ui/mcp-ui-host-frame.d.ts +41 -0
  248. package/dist/react/mcp-ui/mcp-ui-host-frame.js +39 -0
  249. package/dist/renderers/annotation-canvas/react/components/AnnotationCanvas.js +97 -69
  250. package/dist/renderers/preview-modal-shell/react/components/PreviewModalShell.js +59 -30
  251. package/dist/renderers/preview-modal-shell/react/components/icons.js +4 -1
  252. package/dist/renderers/react/components/ArtifactView.js +9 -6
  253. package/dist/renderers/srcdoc/build.d.ts +4 -1
  254. package/dist/renderers/srcdoc/build.js +62 -48
  255. package/dist/styles/admin.css +29 -14
  256. package/dist/styles/lightbox.css +142 -0
  257. package/dist/styles/variables.css +128 -0
  258. package/dist/theme/apply.js +9 -5
  259. package/dist/utils/auto-open-file.d.ts +2 -1
  260. package/dist/utils/auto-open-file.js +69 -85
  261. package/dist/utils/markdown-scroll-sync.js +108 -87
  262. package/dist/utils/polygon-selection.js +25 -26
  263. package/dist/utils/smooth-scroll-to-top.d.ts +1 -1
  264. package/dist/utils/smooth-scroll-to-top.js +2 -32
  265. package/dist/utils/sse.js +26 -26
  266. package/dist/utils/unit-bezier.d.ts +7 -0
  267. package/dist/utils/unit-bezier.js +38 -0
  268. package/package.json +7 -10
  269. package/dist/features/admin-widgets/components/ImagePreviewModal.hooks.d.ts +0 -13
  270. package/dist/features/admin-widgets/components/ImagePreviewModal.hooks.js +0 -46
@@ -1,10 +1,10 @@
1
- import { type ReactNode } from 'react';
1
+ import type { ReactNode } from 'react';
2
2
  import type { AssetTreeDependencies } from '../../ports.js';
3
3
  import type { AssetTreeFileItem, AssetTreeFolderItem, AssetTreeKindConfigMap, AssetTreeNavState, AssetTreeSelectors, AssetTreeToolbarAction } from '../../types.js';
4
- import { useAssetTreeNavigation } from '../hooks/useAssetTreeNavigation.js';
5
- import { useAssetTreePreview } from '../hooks/useAssetTreePreview.js';
6
- import { useAssetTreeRename } from '../hooks/useAssetTreeRename.js';
7
- import { useAssetTreeSelection } from '../hooks/useAssetTreeSelection.js';
4
+ import type { useAssetTreeNavigation } from '../hooks/useAssetTreeNavigation.js';
5
+ import type { useAssetTreePreview } from '../hooks/useAssetTreePreview.js';
6
+ import type { useAssetTreeRename } from '../hooks/useAssetTreeRename.js';
7
+ import type { useAssetTreeSelection } from '../hooks/useAssetTreeSelection.js';
8
8
  export interface AssetTreeBrowserProps<TFile extends AssetTreeFileItem> {
9
9
  files: TFile[];
10
10
  /** Persisted folders, including empty ones — see `AssetTreeFolderItem`'s doc comment. */
@@ -59,5 +59,5 @@ export interface AssetTreeBrowserProps<TFile extends AssetTreeFileItem> {
59
59
  * section, project menu, rotating-tip footer, and file-kind-specific
60
60
  * preview rendering).
61
61
  */
62
- export declare function AssetTreeBrowser<TFile extends AssetTreeFileItem>({ files, folders, selectors, kindConfig, sectionOrder, dependencies, rootLabel, reloading, navState, onNavStateChange, onSelectionChange, onOpenFile, onRenameFile, onDeleteFile, onDeleteFiles, onUploadFiles, getFileUrl, downloadFiles, selectInitialPreviewFile, renderPreviewThumbnail, thumbnailIsInteractive, toolbarActions, emptyStateActions, footer, useAssetTreeNavigation: useAssetTreeNavigationHook, useAssetTreePreview: useAssetTreePreviewHook, useAssetTreeRename: useAssetTreeRenameHook, useAssetTreeSelection: useAssetTreeSelectionHook, }: AssetTreeBrowserProps<TFile>): import("react").JSX.Element;
62
+ export declare function AssetTreeBrowser<TFile extends AssetTreeFileItem>(props: AssetTreeBrowserProps<TFile>): import("react").JSX.Element;
63
63
  //# sourceMappingURL=AssetTreeBrowser.d.ts.map
@@ -1,27 +1,8 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
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, DEFAULT_SECTION_ORDER, EMPTY_TOOLBAR_ACTIONS } from '../../constants.js';
5
- import { createBrowserAssetTreeDependencies } from '../../dependencies.js';
6
- import { basenameForRename, canCopyLocalPath, countFilesUnderDir, resolveKindConfig } from '../../rules.js';
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({ files, folders, selectors, kindConfig = DEFAULT_KIND_CONFIG_MAP, sectionOrder = DEFAULT_SECTION_ORDER, dependencies, rootLabel, reloading = false, navState, onNavStateChange, onSelectionChange, onOpenFile, onRenameFile, onDeleteFile, onDeleteFiles, onUploadFiles, getFileUrl, downloadFiles, selectInitialPreviewFile, renderPreviewThumbnail, thumbnailIsInteractive = false, toolbarActions = EMPTY_TOOLBAR_ACTIONS, emptyStateActions = EMPTY_TOOLBAR_ACTIONS, footer, useAssetTreeNavigation: useAssetTreeNavigationHook = useAssetTreeNavigation, useAssetTreePreview: useAssetTreePreviewHook = useAssetTreePreview, useAssetTreeRename: useAssetTreeRenameHook = useAssetTreeRename, useAssetTreeSelection: useAssetTreeSelectionHook = useAssetTreeSelection, }) {
17
+ export function AssetTreeBrowser(props) {
37
18
  const t = useT();
38
- // KNOWN FOLLOW-UP (flagged by the 2026-07-22 verification pass, not yet
39
- // fixed): this has the same useWiredX gap ConnectorsBrowser had — `deps`
40
- // resolution is still inline instead of behind a `useWiredAssetTreeBrowser`
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
- const previewKindConfig = previewedFile ? resolveKindConfig(selectors.getKind(previewedFile), kindConfig) : null;
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, path: previewedFile.path, kindLabel: t(previewKindConfig.label), kindGlyph: previewKindConfig.glyph, size: selectors.getSize(previewedFile), modifiedAt: selectors.getModifiedAt(previewedFile), onOpen: () => onOpenFile(previewedFile), onClose: preview.clearPreview, downloadHref: getFileUrl?.(previewedFile), renderThumbnail: renderPreviewThumbnail, thumbnailIsInteractive: thumbnailIsInteractive }, previewedFile.path)) : null, rowMenu.menuPos ? (_jsx(AssetTreeRowMenu, { path: rowMenu.menuPos.path, displayName: basenameForRename(rowMenu.menuPos.path, navigation.currentDir), top: rowMenu.menuPos.top, left: rowMenu.menuPos.left, containerRef: rowMenu.containerRef, canCopyLocalPath: !!menuFile && canCopyLocalPath(menuFile, selectors), copied: copyLocalPath.copiedPath === rowMenu.menuPos.path, download: getFileUrl && menuFile
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 prefix = currentDir === '' ? '' : `${currentDir}/`;
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
- if (!f.path.startsWith(prefix))
55
+ for (const f of input.files) {
56
+ const segment = childSegment(f.path, input.prefix);
57
+ if (!segment)
33
58
  continue;
34
- const remainder = f.path.slice(prefix.length);
35
- const slashIdx = remainder.indexOf('/');
36
- if (slashIdx === -1) {
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
- for (const folder of folders) {
46
- if (!folder.path.startsWith(prefix))
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
- const remainder = folder.path.slice(prefix.length);
49
- if (!remainder)
72
+ if (!segment.nested && !segment.head)
50
73
  continue; // the current directory itself
51
- const slashIdx = remainder.indexOf('/');
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) {