@burdenoff/microfe-files 2026.1014.11 → 2026.1016.1

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 (215) hide show
  1. package/README.md +37 -0
  2. package/dist/config/index.js.map +1 -1
  3. package/dist/files/FilesRoot.js +17 -10
  4. package/dist/files/FilesRoot.js.map +1 -1
  5. package/dist/files/FilesRoutes.d.ts +1 -1
  6. package/dist/files/FilesRoutes.js.map +1 -1
  7. package/dist/files/components/ActionMenu.js.map +1 -1
  8. package/dist/files/components/ConfirmDialog.d.ts +1 -1
  9. package/dist/files/components/ConfirmDialog.js.map +1 -1
  10. package/dist/files/components/ContextMenu.d.ts +1 -1
  11. package/dist/files/components/ContextMenu.js.map +1 -1
  12. package/dist/files/components/CopyDialog.js.map +1 -1
  13. package/dist/files/components/EmptyState.d.ts +1 -1
  14. package/dist/files/components/EmptyState.js.map +1 -1
  15. package/dist/files/components/FileBrowser.js +2 -1
  16. package/dist/files/components/FileBrowser.js.map +1 -1
  17. package/dist/files/components/FileCard.d.ts.map +1 -1
  18. package/dist/files/components/FileCard.js +150 -142
  19. package/dist/files/components/FileCard.js.map +1 -1
  20. package/dist/files/components/FileInfoPanel.d.ts +1 -1
  21. package/dist/files/components/FileInfoPanel.d.ts.map +1 -1
  22. package/dist/files/components/FileInfoPanel.js +3 -7
  23. package/dist/files/components/FileInfoPanel.js.map +1 -1
  24. package/dist/files/components/FileListItem.d.ts.map +1 -1
  25. package/dist/files/components/FileListItem.js +1 -1
  26. package/dist/files/components/FileListItem.js.map +1 -1
  27. package/dist/files/components/FilePreviewModal.d.ts +1 -1
  28. package/dist/files/components/FilePreviewModal.d.ts.map +1 -1
  29. package/dist/files/components/FilePreviewModal.js +5 -0
  30. package/dist/files/components/FilePreviewModal.js.map +1 -1
  31. package/dist/files/components/FileVersionPanel.d.ts.map +1 -1
  32. package/dist/files/components/FileVersionPanel.js +122 -121
  33. package/dist/files/components/FileVersionPanel.js.map +1 -1
  34. package/dist/files/components/FolderCard.d.ts.map +1 -1
  35. package/dist/files/components/FolderCard.js +1 -1
  36. package/dist/files/components/FolderCard.js.map +1 -1
  37. package/dist/files/components/MoveDialog.js +2 -2
  38. package/dist/files/components/MoveDialog.js.map +1 -1
  39. package/dist/files/components/SearchBar.d.ts +1 -1
  40. package/dist/files/components/SearchBar.d.ts.map +1 -1
  41. package/dist/files/components/SearchBar.js +132 -128
  42. package/dist/files/components/SearchBar.js.map +1 -1
  43. package/dist/files/components/ShareDialog.d.ts +1 -1
  44. package/dist/files/components/ShareDialog.js.map +1 -1
  45. package/dist/files/components/StorageBanner.js.map +1 -1
  46. package/dist/files/components/TabBar.d.ts +1 -1
  47. package/dist/files/components/TabBar.js.map +1 -1
  48. package/dist/files/components/Toast.d.ts +1 -1
  49. package/dist/files/components/Toast.js.map +1 -1
  50. package/dist/files/components/UploadQueue.d.ts +1 -1
  51. package/dist/files/components/UploadQueue.js +1 -1
  52. package/dist/files/components/UploadQueue.js.map +1 -1
  53. package/dist/files/components/contextMenuItems.d.ts +4 -4
  54. package/dist/files/components/contextMenuItems.js.map +1 -1
  55. package/dist/files/components/viewers/AudioPlayer.d.ts +1 -1
  56. package/dist/files/components/viewers/AudioPlayer.js.map +1 -1
  57. package/dist/files/components/viewers/CodeViewer.d.ts +1 -1
  58. package/dist/files/components/viewers/CodeViewer.js.map +1 -1
  59. package/dist/files/components/viewers/ImageViewer.d.ts +1 -1
  60. package/dist/files/components/viewers/ImageViewer.js.map +1 -1
  61. package/dist/files/components/viewers/PDFViewer.d.ts +1 -1
  62. package/dist/files/components/viewers/PDFViewer.js.map +1 -1
  63. package/dist/files/components/viewers/TextViewer.d.ts +1 -1
  64. package/dist/files/components/viewers/TextViewer.js.map +1 -1
  65. package/dist/files/components/viewers/VideoPlayer.d.ts +1 -1
  66. package/dist/files/components/viewers/VideoPlayer.js.map +1 -1
  67. package/dist/files/graphql-types.d.ts +2 -17
  68. package/dist/files/graphql-types.d.ts.map +1 -1
  69. package/dist/files/hooks/useBatchOperations.d.ts +6 -1
  70. package/dist/files/hooks/useBatchOperations.d.ts.map +1 -1
  71. package/dist/files/hooks/useBatchOperations.js +8 -7
  72. package/dist/files/hooks/useBatchOperations.js.map +1 -1
  73. package/dist/files/hooks/useBinItems.d.ts.map +1 -1
  74. package/dist/files/hooks/useBinItems.js +14 -12
  75. package/dist/files/hooks/useBinItems.js.map +1 -1
  76. package/dist/files/hooks/useBrowsePage.d.ts +131 -8
  77. package/dist/files/hooks/useBrowsePage.d.ts.map +1 -1
  78. package/dist/files/hooks/useBrowsePage.js +23 -22
  79. package/dist/files/hooks/useBrowsePage.js.map +1 -1
  80. package/dist/files/hooks/useCopyFile.d.ts +22 -1
  81. package/dist/files/hooks/useCopyFile.d.ts.map +1 -1
  82. package/dist/files/hooks/useCopyFile.js +9 -8
  83. package/dist/files/hooks/useCopyFile.js.map +1 -1
  84. package/dist/files/hooks/useCreateFolder.d.ts +23 -1
  85. package/dist/files/hooks/useCreateFolder.d.ts.map +1 -1
  86. package/dist/files/hooks/useCreateFolder.js +16 -9
  87. package/dist/files/hooks/useCreateFolder.js.map +1 -1
  88. package/dist/files/hooks/useCreateFolderShare.d.ts +20 -1
  89. package/dist/files/hooks/useCreateFolderShare.d.ts.map +1 -1
  90. package/dist/files/hooks/useCreateFolderShare.js +22 -7
  91. package/dist/files/hooks/useCreateFolderShare.js.map +1 -1
  92. package/dist/files/hooks/useCreateShare.d.ts +19 -1
  93. package/dist/files/hooks/useCreateShare.d.ts.map +1 -1
  94. package/dist/files/hooks/useCreateShare.js +22 -7
  95. package/dist/files/hooks/useCreateShare.js.map +1 -1
  96. package/dist/files/hooks/useDeleteFile.d.ts +1 -1
  97. package/dist/files/hooks/useDeleteFile.d.ts.map +1 -1
  98. package/dist/files/hooks/useDeleteFile.js +8 -7
  99. package/dist/files/hooks/useDeleteFile.js.map +1 -1
  100. package/dist/files/hooks/useDeleteFolder.d.ts +1 -1
  101. package/dist/files/hooks/useDeleteFolder.d.ts.map +1 -1
  102. package/dist/files/hooks/useDeleteFolder.js +9 -8
  103. package/dist/files/hooks/useDeleteFolder.js.map +1 -1
  104. package/dist/files/hooks/useDragDrop.js.map +1 -1
  105. package/dist/files/hooks/useFileVersions.d.ts +36 -9
  106. package/dist/files/hooks/useFileVersions.d.ts.map +1 -1
  107. package/dist/files/hooks/useFileVersions.js +14 -13
  108. package/dist/files/hooks/useFileVersions.js.map +1 -1
  109. package/dist/files/hooks/useFoldersQuery.d.ts +8 -4
  110. package/dist/files/hooks/useFoldersQuery.d.ts.map +1 -1
  111. package/dist/files/hooks/useFoldersQuery.js +7 -6
  112. package/dist/files/hooks/useFoldersQuery.js.map +1 -1
  113. package/dist/files/hooks/useKeyboardNavigation.js +7 -8
  114. package/dist/files/hooks/useKeyboardNavigation.js.map +1 -1
  115. package/dist/files/hooks/useMoveFile.d.ts +22 -1
  116. package/dist/files/hooks/useMoveFile.d.ts.map +1 -1
  117. package/dist/files/hooks/useMoveFile.js +9 -8
  118. package/dist/files/hooks/useMoveFile.js.map +1 -1
  119. package/dist/files/hooks/useMoveFolder.d.ts +22 -1
  120. package/dist/files/hooks/useMoveFolder.d.ts.map +1 -1
  121. package/dist/files/hooks/useMoveFolder.js +9 -8
  122. package/dist/files/hooks/useMoveFolder.js.map +1 -1
  123. package/dist/files/hooks/usePermanentlyDeleteFile.d.ts +1 -1
  124. package/dist/files/hooks/usePermanentlyDeleteFile.d.ts.map +1 -1
  125. package/dist/files/hooks/usePermanentlyDeleteFile.js +8 -7
  126. package/dist/files/hooks/usePermanentlyDeleteFile.js.map +1 -1
  127. package/dist/files/hooks/usePermanentlyDeleteFolder.d.ts +1 -1
  128. package/dist/files/hooks/usePermanentlyDeleteFolder.d.ts.map +1 -1
  129. package/dist/files/hooks/usePermanentlyDeleteFolder.js +8 -7
  130. package/dist/files/hooks/usePermanentlyDeleteFolder.js.map +1 -1
  131. package/dist/files/hooks/useRecentFiles.d.ts.map +1 -1
  132. package/dist/files/hooks/useRecentFiles.js +13 -11
  133. package/dist/files/hooks/useRecentFiles.js.map +1 -1
  134. package/dist/files/hooks/useRenameFile.d.ts +22 -1
  135. package/dist/files/hooks/useRenameFile.d.ts.map +1 -1
  136. package/dist/files/hooks/useRenameFile.js +9 -8
  137. package/dist/files/hooks/useRenameFile.js.map +1 -1
  138. package/dist/files/hooks/useRenameFolder.d.ts +22 -1
  139. package/dist/files/hooks/useRenameFolder.d.ts.map +1 -1
  140. package/dist/files/hooks/useRenameFolder.js +9 -8
  141. package/dist/files/hooks/useRenameFolder.js.map +1 -1
  142. package/dist/files/hooks/useRestoreFile.d.ts +22 -1
  143. package/dist/files/hooks/useRestoreFile.d.ts.map +1 -1
  144. package/dist/files/hooks/useRestoreFile.js +8 -7
  145. package/dist/files/hooks/useRestoreFile.js.map +1 -1
  146. package/dist/files/hooks/useRestoreFolder.d.ts +22 -1
  147. package/dist/files/hooks/useRestoreFolder.d.ts.map +1 -1
  148. package/dist/files/hooks/useRestoreFolder.js +8 -7
  149. package/dist/files/hooks/useRestoreFolder.js.map +1 -1
  150. package/dist/files/hooks/useSearch.d.ts +2 -3
  151. package/dist/files/hooks/useSearch.d.ts.map +1 -1
  152. package/dist/files/hooks/useSearch.js +14 -12
  153. package/dist/files/hooks/useSearch.js.map +1 -1
  154. package/dist/files/hooks/useStarredItems.d.ts +2 -3
  155. package/dist/files/hooks/useStarredItems.d.ts.map +1 -1
  156. package/dist/files/hooks/useStarredItems.js +12 -10
  157. package/dist/files/hooks/useStarredItems.js.map +1 -1
  158. package/dist/files/hooks/useStorageQuota.d.ts.map +1 -1
  159. package/dist/files/hooks/useStorageQuota.js +17 -16
  160. package/dist/files/hooks/useStorageQuota.js.map +1 -1
  161. package/dist/files/hooks/useToast.js.map +1 -1
  162. package/dist/files/hooks/useToggleStar.d.ts +43 -1
  163. package/dist/files/hooks/useToggleStar.d.ts.map +1 -1
  164. package/dist/files/hooks/useToggleStar.js +9 -8
  165. package/dist/files/hooks/useToggleStar.js.map +1 -1
  166. package/dist/files/hooks/useUploadFile.d.ts +23 -1
  167. package/dist/files/hooks/useUploadFile.d.ts.map +1 -1
  168. package/dist/files/hooks/useUploadFile.js +28 -27
  169. package/dist/files/hooks/useUploadFile.js.map +1 -1
  170. package/dist/files/hooks/useUploadQueueState.d.ts +32 -0
  171. package/dist/files/hooks/useUploadQueueState.d.ts.map +1 -0
  172. package/dist/files/hooks/useUploadQueueState.js +61 -0
  173. package/dist/files/hooks/useUploadQueueState.js.map +1 -0
  174. package/dist/files/index.js +4 -3
  175. package/dist/files/pages/BrowserPage.d.ts +1 -1
  176. package/dist/files/pages/BrowserPage.d.ts.map +1 -1
  177. package/dist/files/pages/BrowserPage.js +383 -387
  178. package/dist/files/pages/BrowserPage.js.map +1 -1
  179. package/dist/files/pages/ShareAccessPage.d.ts +1 -1
  180. package/dist/files/pages/ShareAccessPage.js.map +1 -1
  181. package/dist/files/providers/FilesProvider.js.map +1 -1
  182. package/dist/files/store/filesStore.js.map +1 -1
  183. package/dist/files/types.d.ts.map +1 -1
  184. package/dist/files/utils/events.js.map +1 -1
  185. package/dist/files/utils/fileViewModel.d.ts +7 -0
  186. package/dist/files/utils/fileViewModel.d.ts.map +1 -0
  187. package/dist/files/utils/fileViewModel.js +34 -0
  188. package/dist/files/utils/fileViewModel.js.map +1 -0
  189. package/dist/files/utils/i18n.js.map +1 -1
  190. package/dist/files/utils/index.js +19 -19
  191. package/dist/files/utils/index.js.map +1 -1
  192. package/dist/files/utils/quotaUtils.js +1 -2
  193. package/dist/files/utils/thumbnail.js +19 -23
  194. package/dist/files/utils/thumbnail.js.map +1 -1
  195. package/dist/files/utils/uploadDigest.js +1 -1
  196. package/dist/files/utils/uploadDigest.js.map +1 -1
  197. package/dist/generated/global-operations.d.ts +4 -1
  198. package/dist/generated/global-operations.d.ts.map +1 -1
  199. package/dist/generated/global-types.d.ts +16 -21
  200. package/dist/generated/global-types.d.ts.map +1 -1
  201. package/dist/generated/wspace-operations.d.ts +503 -1784
  202. package/dist/generated/wspace-operations.d.ts.map +1 -1
  203. package/dist/generated/wspace-operations.js +15278 -1110
  204. package/dist/generated/wspace-operations.js.map +1 -1
  205. package/dist/generated/wspace-types.d.ts +90013 -24889
  206. package/dist/generated/wspace-types.d.ts.map +1 -1
  207. package/dist/generated/wspace-types.js +16 -0
  208. package/dist/generated/wspace-types.js.map +1 -0
  209. package/dist/index.d.ts +1 -1
  210. package/dist/index.d.ts.map +1 -1
  211. package/dist/shared/hooks/useTr.js.map +1 -1
  212. package/dist/translations/en.js.map +1 -1
  213. package/dist/utils/nativeBridge.js +1 -2
  214. package/package.json +24 -22
  215. package/dist/files.d.ts +0 -2
package/README.md CHANGED
@@ -27,3 +27,40 @@ native mutation inputs, quota failures and cancellation without network requests
27
27
  ## License
28
28
 
29
29
  Proprietary — Copyright Burdenoff Consultancy Services Pvt. Ltd.
30
+
31
+ ### Supported typed GraphQL generation
32
+
33
+ `bun run codegen` generates the workspace and global outputs from local snapshots
34
+ using the supported Codegen core/plugins and TypedDocumentNode. Domain hooks use
35
+ Apollo 4 directly; no generated React hook fork or global Utils major override is
36
+ required. The four owned projects retain their actual document patterns, scalars
37
+ and schema outputs. `bun run schema:pull` delegates to the canonical development
38
+ Hive-CDN reader (Dev139); ordinary generation does not fetch a gateway or schema.
39
+
40
+ `bun run codegen:watch` uses Node 24 watch paths to regenerate both local projects
41
+ when an operation, schema or config changes. The former `--project default` command
42
+ named no project and failed before watching; this command corrects that behavior.
43
+
44
+ The migration preserves all 32 public root declarations and all 61 operation/fragment
45
+ Document definitions. Refreshed canonical development schemas and private inferred
46
+ hook types are not claimed byte-identical. Explicit view-model conversion refuses
47
+ unsafe BigInt sizes and keeps unavailable download URLs unavailable; previews,
48
+ images and download actions never request an empty location. Private search input
49
+ models now follow the actual single-select controls and canonical API fields.
50
+ Folder-share tokens are read from the hook's already-unwrapped result.
51
+
52
+ Local source/audit/packed and synthetic browser checks do not establish deployed
53
+ permissions, full FilesRoot/ShareDialog acceptance, consent or business effects.
54
+ The separate host sprintf-js finding and prior unresolved operations remain open;
55
+ removing the Files Codegen Braces path does not approve an earlier risk proposal.
56
+
57
+ An additional pure local reducer keeps upload queue cancellation and both display
58
+ flags atomic against the latest state. It preserves existing pause/XHR/process
59
+ ordering; removing an item locally does not claim a server abort. The original
60
+ React Doctor nested-state-updater error and its correction are recorded separately.
61
+ Dependency audit and React diagnostics are separate checks.
62
+
63
+ The refreshed development snapshots are normalized with the published GraphQL
64
+ Document printer, `print(parse(raw))`, preserving their complete loc-free AST,
65
+ including directive applications and description values. They are not claimed
66
+ byte-identical to the raw CDN response; raw hashes/provenance remain in evidence.
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/config/index.ts"],"sourcesContent":["/**\n * Configuration module for files microfrontend\n * This config is typically injected by the shell application at runtime\n */\n\nexport interface FilesConfig {\n /** Full GraphQL endpoint URL (e.g., http://localhost:4003/workspaces/graphql) */\n apiGatewayUrl: string;\n /** Base URL for gateway (optional, used to construct full endpoint) */\n apiGatewayBaseUrl?: string;\n /** Auth token for API requests */\n authToken?: string;\n}\n\n// Default configuration: empty strings so unconfigured callers fail loudly\n// (network error with an obviously-invalid URL) instead of silently hitting\n// `localhost:4003`, which can't be reached from inside containers and\n// previously manifested as a blank screen on /files.\nlet runtimeConfig: FilesConfig = {\n apiGatewayUrl: \"\",\n apiGatewayBaseUrl: \"\",\n authToken: undefined,\n};\n\n/**\n * Get current configuration\n */\nexport const config = new Proxy({} as FilesConfig, {\n get(_, prop: keyof FilesConfig) {\n return runtimeConfig[prop];\n },\n});\n\n/**\n * Set runtime configuration (called by shell app)\n * @param newConfig - Configuration object\n */\nexport function setFilesConfig(newConfig: Partial<FilesConfig>): void {\n runtimeConfig = { ...runtimeConfig, ...newConfig };\n}\n\n/**\n * Build full GraphQL endpoint URL from base URL\n * @param baseUrl - Base gateway URL (e.g., http://localhost:4003)\n * @param supergraph - Supergraph name (workspaces or global)\n * @returns Full GraphQL endpoint URL\n */\nexport function buildGraphQLEndpoint(\n baseUrl: string,\n supergraph: \"workspaces\" | \"global\" = \"workspaces\",\n): string {\n const cleanBase = baseUrl.endsWith(\"/\") ? baseUrl.slice(0, -1) : baseUrl;\n const path =\n supergraph === \"workspaces\" ? \"/workspaces/graphql\" : \"/global/graphql\";\n return `${cleanBase}${path}`;\n}\n\n/**\n * Reset configuration to defaults\n */\nexport function resetFilesConfig(): void {\n runtimeConfig = {\n apiGatewayUrl: \"\",\n apiGatewayBaseUrl: \"\",\n authToken: undefined,\n };\n}\n"],"mappings":";AAkBA,IAAI,IAA6B;CAC/B,eAAe;CACf,mBAAmB;CACnB,WAAW,KAAA;CACZ,EAKY,IAAS,IAAI,MAAM,EAAE,EAAiB,EACjD,IAAI,GAAG,GAAyB;AAC9B,QAAO,EAAc;GAExB,CAAC;AAMF,SAAgB,EAAe,GAAuC;AACpE,KAAgB;EAAE,GAAG;EAAe,GAAG;EAAW;;AASpD,SAAgB,EACd,GACA,IAAsC,cAC9B;AAIR,QAAO,GAHW,EAAQ,SAAS,IAAI,GAAG,EAAQ,MAAM,GAAG,GAAG,GAAG,IAE/D,MAAe,eAAe,wBAAwB;;AAO1D,SAAgB,IAAyB;AACvC,KAAgB;EACd,eAAe;EACf,mBAAmB;EACnB,WAAW,KAAA;EACZ"}
1
+ {"version":3,"file":"index.js","names":["runtimeConfig","config","prop","setFilesConfig","newConfig","buildGraphQLEndpoint","baseUrl","supergraph","resetFilesConfig"],"sources":["../../src/config/index.ts"],"sourcesContent":["/**\n * Configuration module for files microfrontend\n * This config is typically injected by the shell application at runtime\n */\n\nexport interface FilesConfig {\n /** Full GraphQL endpoint URL (e.g., http://localhost:4003/workspaces/graphql) */\n apiGatewayUrl: string;\n /** Base URL for gateway (optional, used to construct full endpoint) */\n apiGatewayBaseUrl?: string;\n /** Auth token for API requests */\n authToken?: string;\n}\n\n// Default configuration: empty strings so unconfigured callers fail loudly\n// (network error with an obviously-invalid URL) instead of silently hitting\n// `localhost:4003`, which can't be reached from inside containers and\n// previously manifested as a blank screen on /files.\nlet runtimeConfig: FilesConfig = {\n apiGatewayUrl: \"\",\n apiGatewayBaseUrl: \"\",\n authToken: undefined,\n};\n\n/**\n * Get current configuration\n */\nexport const config = new Proxy({} as FilesConfig, {\n get(_, prop: keyof FilesConfig) {\n return runtimeConfig[prop];\n },\n});\n\n/**\n * Set runtime configuration (called by shell app)\n * @param newConfig - Configuration object\n */\nexport function setFilesConfig(newConfig: Partial<FilesConfig>): void {\n runtimeConfig = { ...runtimeConfig, ...newConfig };\n}\n\n/**\n * Build full GraphQL endpoint URL from base URL\n * @param baseUrl - Base gateway URL (e.g., http://localhost:4003)\n * @param supergraph - Supergraph name (workspaces or global)\n * @returns Full GraphQL endpoint URL\n */\nexport function buildGraphQLEndpoint(\n baseUrl: string,\n supergraph: \"workspaces\" | \"global\" = \"workspaces\",\n): string {\n const cleanBase = baseUrl.endsWith(\"/\") ? baseUrl.slice(0, -1) : baseUrl;\n const path =\n supergraph === \"workspaces\" ? \"/workspaces/graphql\" : \"/global/graphql\";\n return `${cleanBase}${path}`;\n}\n\n/**\n * Reset configuration to defaults\n */\nexport function resetFilesConfig(): void {\n runtimeConfig = {\n apiGatewayUrl: \"\",\n apiGatewayBaseUrl: \"\",\n authToken: undefined,\n };\n}\n"],"mappings":";AAkBA,IAAIA,IAA6B;CAC/B,eAAe;CACf,mBAAmB;CACnB,WAAW,KAAA;AACb,GAKaC,IAAS,IAAI,MAAM,CAAC,GAAkB,EACjD,IAAI,GAAG,GAAyB;CAC9B,OAAOD,EAAcE;AACvB,EACF,CAAC;AAMD,SAAgBC,EAAe,GAAuC;CACpE,IAAgB;EAAE,GAAGH;EAAe,GAAGI;CAAU;AACnD;AAQA,SAAgBC,EACd,GACA,IAAsC,cAC9B;CAIR,OAAO,GAHWC,EAAQ,SAAS,GAAG,IAAIA,EAAQ,MAAM,GAAG,EAAE,IAAIA,IAE/DC,MAAe,eAAe,wBAAwB;AAE1D;AAKA,SAAgBC,IAAyB;CACvC,IAAgB;EACd,eAAe;EACf,mBAAmB;EACnB,WAAW,KAAA;CACb;AACF"}
@@ -10,39 +10,46 @@ import { FeatureFlagProvider as u } from "@burdenoff/fe-libs/shared/feature-flag
10
10
  import { jsx as d } from "react/jsx-runtime";
11
11
  //#region src/files/FilesRoot.tsx
12
12
  var f = new s({ defaultOptions: { queries: {
13
- staleTime: 1e3 * 60 * 5,
13
+ staleTime: 3e5,
14
14
  refetchOnWindowFocus: !1
15
15
  } } }), p = (s) => {
16
16
  let { registerNavItems: p, registerFooterItems: m, basePath: h = "/", apiGatewayUrl: g, authToken: _, workspaceId: v } = s, y = t();
17
17
  a(() => {
18
- g && r({
19
- apiGatewayUrl: g.includes("/graphql") ? g : n(g, "workspaces"),
20
- apiGatewayBaseUrl: g,
21
- authToken: _
22
- });
18
+ if (g) {
19
+ let e = g.includes("/graphql") ? g : n(g, "workspaces");
20
+ r({
21
+ apiGatewayUrl: e,
22
+ apiGatewayBaseUrl: g,
23
+ authToken: _
24
+ });
25
+ }
23
26
  }, [g, _]);
24
27
  let b = (e, t) => (e.endsWith("/") ? e.slice(0, -1) : e) + (t.startsWith("/") ? t : `/${t}`);
25
28
  return a(() => {
26
- if (p) return p([{
29
+ if (!p) return;
30
+ let e = [{
27
31
  id: "files-browse",
28
32
  label: y("files.nav.allFiles", "All Files"),
29
33
  path: b(h, "browse"),
30
34
  icon: /* @__PURE__ */ d(l, { size: 20 }),
31
35
  order: 10,
32
36
  group: "files"
33
- }]);
37
+ }];
38
+ return p(e);
34
39
  }, [
35
40
  p,
36
41
  h,
37
42
  y
38
43
  ]), a(() => {
39
- if (m) return m([{
44
+ if (!m) return;
45
+ let e = [{
40
46
  id: "files-status",
41
47
  label: y("files.nav.statusReady", "Files Ready"),
42
48
  type: "status",
43
49
  order: 10,
44
50
  section: "left"
45
- }]);
51
+ }];
52
+ return m(e);
46
53
  }, [m, y]), /* @__PURE__ */ d(o, {
47
54
  fallback: /* @__PURE__ */ d("div", {
48
55
  className: "p-6 text-center text-text-secondary",
@@ -1 +1 @@
1
- {"version":3,"file":"FilesRoot.js","names":[],"sources":["../../src/files/FilesRoot.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useEffect } from \"react\";\nimport { ErrorBoundary } from \"@burdenoff/fe-libs/shared/components\";\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport { FolderOpen } from \"lucide-react\";\nimport { FeatureFlagProvider } from \"@burdenoff/fe-libs/shared/feature-flags\";\nimport { FilesProvider } from \"./providers/FilesProvider\";\nimport type { NavItem, FilesRootProps } from \"./types\";\nimport { FilesRoutes } from \"./FilesRoutes\";\nimport { setFilesConfig, buildGraphQLEndpoint } from \"../config\";\nimport { useTr } from \"../shared/hooks/useTr\";\n\n// Create a query client instance.\n//\n// NOTE: every data hook in this MFE is Apollo (it shares the shell's Apollo\n// client) — there are no React Query queries/mutations here. Refetching after a\n// mutation is owned by the shell's Apollo layer (mutationAutoRefreshLink +\n// refetchActiveGatewayQueries in @burdenoff/fe-libs). A previous\n// `mutationCache.onSuccess -> invalidateQueries()` was added here to fix stale\n// lists, but it was inert (no React Query mutations exist to trigger it); the\n// real cause was a stale 15s GraphQL read cache in fe-libs, now fixed there.\n// This provider remains only because shared fe-libs components rendered inside\n// the MFE expect a React Query context.\nconst queryClient = new QueryClient({\n defaultOptions: {\n queries: {\n staleTime: 1000 * 60 * 5, // 5 minutes\n refetchOnWindowFocus: false,\n },\n },\n});\n\n/**\n * Root component for the Files microfrontend.\n *\n * This is the main entry point that host applications import and render.\n * It sets up the necessary providers and renders the internal routing.\n * Automatically registers navigation items with the shell if registration functions are provided.\n *\n * @example\n * ```tsx\n * import { FilesRoot } from '@burdenoff/micro-fe/files';\n *\n * function App() {\n * return (\n * <Route path=\"/files/*\" element={\n * <FilesRoot\n * basePath=\"/files\"\n * navigate={navigate}\n * currentUser={user}\n * workspaceId=\"ws-123\"\n * apiGatewayUrl=\"https://api.example.com\"\n * authToken=\"token\"\n * />\n * } />\n * );\n * }\n * ```\n */\nexport const FilesRoot: FC<FilesRootProps> = (props) => {\n const {\n registerNavItems,\n registerFooterItems,\n basePath = \"/\",\n apiGatewayUrl,\n authToken,\n workspaceId,\n } = props;\n const tr = useTr();\n\n // Initialize runtime configuration from props\n useEffect(() => {\n if (apiGatewayUrl) {\n const fullEndpoint = apiGatewayUrl.includes(\"/graphql\")\n ? apiGatewayUrl\n : buildGraphQLEndpoint(apiGatewayUrl, \"workspaces\");\n\n setFilesConfig({\n apiGatewayUrl: fullEndpoint,\n apiGatewayBaseUrl: apiGatewayUrl,\n authToken,\n });\n }\n }, [apiGatewayUrl, authToken]);\n\n // Helper to join paths correctly, avoiding double slashes\n const joinPath = (base: string, path: string): string => {\n const cleanBase = base.endsWith(\"/\") ? base.slice(0, -1) : base;\n const cleanPath = path.startsWith(\"/\") ? path : `/${path}`;\n return cleanBase + cleanPath;\n };\n\n // Register navigation items with the shell\n useEffect(() => {\n if (!registerNavItems) return;\n\n const navItems: NavItem[] = [\n {\n id: \"files-browse\",\n label: tr(\"files.nav.allFiles\", \"All Files\"),\n path: joinPath(basePath, \"browse\"),\n icon: <FolderOpen size={20} />,\n order: 10,\n group: \"files\",\n },\n ];\n\n // Register and get cleanup function\n const cleanup = registerNavItems(navItems);\n\n // Return cleanup function to unregister on unmount\n return cleanup;\n }, [registerNavItems, basePath, tr]);\n\n // Register footer items (example: storage status in left section)\n useEffect(() => {\n if (!registerFooterItems) return;\n\n const footerItems = [\n {\n id: \"files-status\",\n label: tr(\"files.nav.statusReady\", \"Files Ready\"),\n type: \"status\" as const,\n order: 10,\n section: \"left\" as const,\n },\n ];\n\n const cleanup = registerFooterItems(footerItems);\n return cleanup;\n }, [registerFooterItems, tr]);\n\n return (\n <ErrorBoundary\n fallback={\n <div className=\"p-6 text-center text-text-secondary\">\n {tr(\n \"files.root.errorFallback\",\n \"Something went wrong loading this module. Please refresh the page.\",\n )}\n </div>\n }\n >\n <QueryClientProvider client={queryClient}>\n <FeatureFlagProvider\n workspaceId={workspaceId ?? null}\n gateway=\"global\"\n defaultEnabled={false}\n >\n <FilesProvider {...props}>\n <FilesRoutes />\n </FilesProvider>\n </FeatureFlagProvider>\n </QueryClientProvider>\n </ErrorBoundary>\n );\n};\n"],"mappings":";;;;;;;;;;;AAuBA,IAAM,IAAc,IAAI,EAAY,EAClC,gBAAgB,EACd,SAAS;CACP,WAAW,MAAO,KAAK;CACvB,sBAAsB;CACvB,EACF,EACF,CAAC,EA6BW,KAAiC,MAAU;CACtD,IAAM,EACJ,qBACA,wBACA,cAAW,KACX,kBACA,cACA,mBACE,GACE,IAAK,GAAO;AAGlB,SAAgB;AACd,EAAI,KAKF,EAAe;GACb,eALmB,EAAc,SAAS,WAAW,GACnD,IACA,EAAqB,GAAe,aAAa;GAInD,mBAAmB;GACnB;GACD,CAAC;IAEH,CAAC,GAAe,EAAU,CAAC;CAG9B,IAAM,KAAY,GAAc,OACZ,EAAK,SAAS,IAAI,GAAG,EAAK,MAAM,GAAG,GAAG,GAAG,MACzC,EAAK,WAAW,IAAI,GAAG,IAAO,IAAI;AA4CtD,QAvCA,QAAgB;AACT,QAiBL,QAHgB,EAZY,CAC1B;GACE,IAAI;GACJ,OAAO,EAAG,sBAAsB,YAAY;GAC5C,MAAM,EAAS,GAAU,SAAS;GAClC,MAAM,kBAAC,GAAD,EAAY,MAAM,IAAM,CAAA;GAC9B,OAAO;GACP,OAAO;GACR,CACF,CAGyC;IAIzC;EAAC;EAAkB;EAAU;EAAG,CAAC,EAGpC,QAAgB;AACT,QAaL,QADgB,EAVI,CAClB;GACE,IAAI;GACJ,OAAO,EAAG,yBAAyB,cAAc;GACjD,MAAM;GACN,OAAO;GACP,SAAS;GACV,CACF,CAE+C;IAE/C,CAAC,GAAqB,EAAG,CAAC,EAG3B,kBAAC,GAAD;EACE,UACE,kBAAC,OAAD;GAAK,WAAU;aACZ,EACC,4BACA,qEACD;GACG,CAAA;YAGR,kBAAC,GAAD;GAAqB,QAAQ;aAC3B,kBAAC,GAAD;IACE,aAAa,KAAe;IAC5B,SAAQ;IACR,gBAAgB;cAEhB,kBAAC,GAAD;KAAe,GAAI;eACjB,kBAAC,GAAD,EAAe,CAAA;KACD,CAAA;IACI,CAAA;GACF,CAAA;EACR,CAAA"}
1
+ {"version":3,"file":"FilesRoot.js","names":["queryClient","QueryClient","FilesRoot","props","tr","useTr","apiGatewayUrl","fullEndpoint","buildGraphQLEndpoint","authToken","joinPath","base","path","useEffect","registerNavItems","navItems","basePath","FolderOpen","registerFooterItems","footerItems","ErrorBoundary","QueryClientProvider","FeatureFlagProvider","workspaceId","FilesProvider","FilesRoutes"],"sources":["../../src/files/FilesRoot.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useEffect } from \"react\";\nimport { ErrorBoundary } from \"@burdenoff/fe-libs/shared/components\";\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport { FolderOpen } from \"lucide-react\";\nimport { FeatureFlagProvider } from \"@burdenoff/fe-libs/shared/feature-flags\";\nimport { FilesProvider } from \"./providers/FilesProvider\";\nimport type { NavItem, FilesRootProps } from \"./types\";\nimport { FilesRoutes } from \"./FilesRoutes\";\nimport { setFilesConfig, buildGraphQLEndpoint } from \"../config\";\nimport { useTr } from \"../shared/hooks/useTr\";\n\n// Create a query client instance.\n//\n// NOTE: every data hook in this MFE is Apollo (it shares the shell's Apollo\n// client) — there are no React Query queries/mutations here. Refetching after a\n// mutation is owned by the shell's Apollo layer (mutationAutoRefreshLink +\n// refetchActiveGatewayQueries in @burdenoff/fe-libs). A previous\n// `mutationCache.onSuccess -> invalidateQueries()` was added here to fix stale\n// lists, but it was inert (no React Query mutations exist to trigger it); the\n// real cause was a stale 15s GraphQL read cache in fe-libs, now fixed there.\n// This provider remains only because shared fe-libs components rendered inside\n// the MFE expect a React Query context.\nconst queryClient = new QueryClient({\n defaultOptions: {\n queries: {\n staleTime: 1000 * 60 * 5, // 5 minutes\n refetchOnWindowFocus: false,\n },\n },\n});\n\n/**\n * Root component for the Files microfrontend.\n *\n * This is the main entry point that host applications import and render.\n * It sets up the necessary providers and renders the internal routing.\n * Automatically registers navigation items with the shell if registration functions are provided.\n *\n * @example\n * ```tsx\n * import { FilesRoot } from '@burdenoff/micro-fe/files';\n *\n * function App() {\n * return (\n * <Route path=\"/files/*\" element={\n * <FilesRoot\n * basePath=\"/files\"\n * navigate={navigate}\n * currentUser={user}\n * workspaceId=\"ws-123\"\n * apiGatewayUrl=\"https://api.example.com\"\n * authToken=\"token\"\n * />\n * } />\n * );\n * }\n * ```\n */\nexport const FilesRoot: FC<FilesRootProps> = (props) => {\n const {\n registerNavItems,\n registerFooterItems,\n basePath = \"/\",\n apiGatewayUrl,\n authToken,\n workspaceId,\n } = props;\n const tr = useTr();\n\n // Initialize runtime configuration from props\n useEffect(() => {\n if (apiGatewayUrl) {\n const fullEndpoint = apiGatewayUrl.includes(\"/graphql\")\n ? apiGatewayUrl\n : buildGraphQLEndpoint(apiGatewayUrl, \"workspaces\");\n\n setFilesConfig({\n apiGatewayUrl: fullEndpoint,\n apiGatewayBaseUrl: apiGatewayUrl,\n authToken,\n });\n }\n }, [apiGatewayUrl, authToken]);\n\n // Helper to join paths correctly, avoiding double slashes\n const joinPath = (base: string, path: string): string => {\n const cleanBase = base.endsWith(\"/\") ? base.slice(0, -1) : base;\n const cleanPath = path.startsWith(\"/\") ? path : `/${path}`;\n return cleanBase + cleanPath;\n };\n\n // Register navigation items with the shell\n useEffect(() => {\n if (!registerNavItems) return;\n\n const navItems: NavItem[] = [\n {\n id: \"files-browse\",\n label: tr(\"files.nav.allFiles\", \"All Files\"),\n path: joinPath(basePath, \"browse\"),\n icon: <FolderOpen size={20} />,\n order: 10,\n group: \"files\",\n },\n ];\n\n // Register and get cleanup function\n const cleanup = registerNavItems(navItems);\n\n // Return cleanup function to unregister on unmount\n return cleanup;\n }, [registerNavItems, basePath, tr]);\n\n // Register footer items (example: storage status in left section)\n useEffect(() => {\n if (!registerFooterItems) return;\n\n const footerItems = [\n {\n id: \"files-status\",\n label: tr(\"files.nav.statusReady\", \"Files Ready\"),\n type: \"status\" as const,\n order: 10,\n section: \"left\" as const,\n },\n ];\n\n const cleanup = registerFooterItems(footerItems);\n return cleanup;\n }, [registerFooterItems, tr]);\n\n return (\n <ErrorBoundary\n fallback={\n <div className=\"p-6 text-center text-text-secondary\">\n {tr(\n \"files.root.errorFallback\",\n \"Something went wrong loading this module. Please refresh the page.\",\n )}\n </div>\n }\n >\n <QueryClientProvider client={queryClient}>\n <FeatureFlagProvider\n workspaceId={workspaceId ?? null}\n gateway=\"global\"\n defaultEnabled={false}\n >\n <FilesProvider {...props}>\n <FilesRoutes />\n </FilesProvider>\n </FeatureFlagProvider>\n </QueryClientProvider>\n </ErrorBoundary>\n );\n};\n"],"mappings":";;;;;;;;;;;AAuBA,IAAMA,IAAc,IAAIC,EAAY,EAClC,gBAAgB,EACd,SAAS;CACP,WAAW;CACX,sBAAsB;AACxB,EACF,EACF,CAAC,GA6BYC,KAAiC,MAAU;CACtD,IAAM,EACJ,qBACA,wBACA,cAAW,KACX,kBACA,cACA,mBACEC,GACEC,IAAKC,EAAM;CAGjB,QAAgB;EACd,IAAIC,GAAe;GACjB,IAAMC,IAAeD,EAAc,SAAS,UAAU,IAClDA,IACAE,EAAqBF,GAAe,YAAY;GAEpD,EAAe;IACb,eAAeC;IACf,mBAAmBD;IACnB;GACF,CAAC;EACH;CACF,GAAG,CAACA,GAAeG,CAAS,CAAC;CAG7B,IAAMC,KAAY,GAAc,OACZC,EAAK,SAAS,GAAG,IAAIA,EAAK,MAAM,GAAG,EAAE,IAAIA,MACzCC,EAAK,WAAW,GAAG,IAAIA,IAAO,IAAIA;CA4CtD,OAvCAC,QAAgB;EACd,IAAI,CAACC,GAAkB;EAEvB,IAAMC,IAAsB,CAC1B;GACE,IAAI;GACJ,OAAOX,EAAG,sBAAsB,WAAW;GAC3C,MAAMM,EAASM,GAAU,QAAQ;GACjC,MAAM,kBAACC,GAAD,EAAY,MAAM,GAAK,CAAA;GAC7B,OAAO;GACP,OAAO;EACT,CACF;EAMA,OAHgBH,EAAiBC,CAG1B;CACT,GAAG;EAACD;EAAkBE;EAAUZ;CAAE,CAAC,GAGnCS,QAAgB;EACd,IAAI,CAACK,GAAqB;EAE1B,IAAMC,IAAc,CAClB;GACE,IAAI;GACJ,OAAOf,EAAG,yBAAyB,aAAa;GAChD,MAAM;GACN,OAAO;GACP,SAAS;EACX,CACF;EAGA,OADgBc,EAAoBC,CAC7B;CACT,GAAG,CAACD,GAAqBd,CAAE,CAAC,GAG1B,kBAACgB,GAAD;EACE,UACE,kBAAC,OAAD;GAAK,WAAU;GACZ,UAAAhB,EACC,4BACA,oEACF;EACG,CAAA;EAGP,UAAA,kBAACiB,GAAD;GAAqB,QAAQrB;GAC3B,UAAA,kBAACsB,GAAD;IACE,aAAaC,KAAe;IAC5B,SAAQ;IACR,gBAAgB;IAEhB,UAAA,kBAACC,GAAD;KAAe,GAAIrB;KACjB,UAAA,kBAACsB,GAAD,CAAc,CAAA;IACD,CAAA;GACI,CAAA;EACF,CAAA;CACR,CAAA;AAEnB"}
@@ -8,5 +8,5 @@
8
8
  * - /browse/:folderId → File browser page (specific folder) - eager loaded
9
9
  * - /* → Catch-all redirects to browse
10
10
  */
11
- export declare function FilesRoutes(): import("react").JSX.Element;
11
+ export declare function FilesRoutes(): import('react').JSX.Element;
12
12
  //# sourceMappingURL=FilesRoutes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"FilesRoutes.js","names":[],"sources":["../../src/files/FilesRoutes.tsx"],"sourcesContent":["import { Navigate, Route, Routes, useLocation } from \"react-router\";\nimport { BrowserPage } from \"./pages/BrowserPage\";\nimport { ShareAccessPage } from \"./pages/ShareAccessPage\";\nimport { useFilesContext } from \"./providers/FilesProvider\";\n\n/**\n * Internal router for the Files microfrontend.\n * This component handles routing within the microfrontend using React Router v7.\n *\n * Routes:\n * - / → Redirect to browse\n * - /browse → File browser page (root folder) - eager loaded\n * - /browse/:folderId → File browser page (specific folder) - eager loaded\n * - /* → Catch-all redirects to browse\n */\nexport function FilesRoutes() {\n const { basePath } = useFilesContext();\n const location = useLocation();\n const normalizedBasePath = basePath.replace(/\\/+$/, \"\") || \"/\";\n const absoluteSharePath = `${normalizedBasePath === \"/\" ? \"\" : normalizedBasePath}/share/:token`;\n const absoluteSharePrefix = `${normalizedBasePath === \"/\" ? \"\" : normalizedBasePath}/share/`;\n // Absolute target for default + catch-all redirects. Using a relative `to=\"browse\"`\n // here causes an infinite path-compounding loop when a splat (`path=\"*\"`) matches a\n // host-shell sibling route (e.g. `/files/shared`): React Router resolves the\n // relative path against the splat-matched URL, so each render appends another\n // `/browse` segment (`/files/shared/browse/browse/...`).\n const absoluteBrowsePath = `${normalizedBasePath === \"/\" ? \"\" : normalizedBasePath}/browse`;\n\n if (location.pathname.startsWith(absoluteSharePrefix)) {\n return <ShareAccessPage />;\n }\n\n return (\n <Routes>\n {/* Default route - redirect to browse */}\n <Route index element={<Navigate to={absoluteBrowsePath} replace />} />\n\n {/* Main pages - BrowserPage is eager loaded (primary entry point) */}\n <Route path=\"browse\" element={<BrowserPage />} />\n <Route path=\"browse/:folderId\" element={<BrowserPage />} />\n <Route path=\"share/:token\" element={<ShareAccessPage />} />\n <Route path={absoluteSharePath} element={<ShareAccessPage />} />\n\n {/* Catch-all route - redirect to browse (absolute to avoid splat-relative compounding) */}\n <Route path=\"*\" element={<Navigate to={absoluteBrowsePath} replace />} />\n </Routes>\n );\n}\n"],"mappings":";;;;;;AAeA,SAAgB,IAAc;CAC5B,IAAM,EAAE,gBAAa,GAAiB,EAChC,IAAW,GAAa,EACxB,IAAqB,EAAS,QAAQ,QAAQ,GAAG,IAAI,KACrD,IAAoB,GAAG,MAAuB,MAAM,KAAK,EAAmB,gBAC5E,IAAsB,GAAG,MAAuB,MAAM,KAAK,EAAmB,UAM9E,IAAqB,GAAG,MAAuB,MAAM,KAAK,EAAmB;AAMnF,QAJI,EAAS,SAAS,WAAW,EAAoB,GAC5C,kBAAC,GAAD,EAAmB,CAAA,GAI1B,kBAAC,GAAD,EAAA,UAAA;EAEE,kBAAC,GAAD;GAAO,OAAA;GAAM,SAAS,kBAAC,GAAD;IAAU,IAAI;IAAoB,SAAA;IAAU,CAAA;GAAI,CAAA;EAGtE,kBAAC,GAAD;GAAO,MAAK;GAAS,SAAS,kBAAC,GAAD,EAAe,CAAA;GAAI,CAAA;EACjD,kBAAC,GAAD;GAAO,MAAK;GAAmB,SAAS,kBAAC,GAAD,EAAe,CAAA;GAAI,CAAA;EAC3D,kBAAC,GAAD;GAAO,MAAK;GAAe,SAAS,kBAAC,GAAD,EAAmB,CAAA;GAAI,CAAA;EAC3D,kBAAC,GAAD;GAAO,MAAM;GAAmB,SAAS,kBAAC,GAAD,EAAmB,CAAA;GAAI,CAAA;EAGhE,kBAAC,GAAD;GAAO,MAAK;GAAI,SAAS,kBAAC,GAAD;IAAU,IAAI;IAAoB,SAAA;IAAU,CAAA;GAAI,CAAA;EAClE,EAAA,CAAA"}
1
+ {"version":3,"file":"FilesRoutes.js","names":["FilesRoutes","useFilesContext","location","useLocation","normalizedBasePath","basePath","absoluteSharePath","absoluteSharePrefix","absoluteBrowsePath","ShareAccessPage","Routes","Route","Navigate","BrowserPage"],"sources":["../../src/files/FilesRoutes.tsx"],"sourcesContent":["import { Navigate, Route, Routes, useLocation } from \"react-router\";\nimport { BrowserPage } from \"./pages/BrowserPage\";\nimport { ShareAccessPage } from \"./pages/ShareAccessPage\";\nimport { useFilesContext } from \"./providers/FilesProvider\";\n\n/**\n * Internal router for the Files microfrontend.\n * This component handles routing within the microfrontend using React Router v7.\n *\n * Routes:\n * - / → Redirect to browse\n * - /browse → File browser page (root folder) - eager loaded\n * - /browse/:folderId → File browser page (specific folder) - eager loaded\n * - /* → Catch-all redirects to browse\n */\nexport function FilesRoutes() {\n const { basePath } = useFilesContext();\n const location = useLocation();\n const normalizedBasePath = basePath.replace(/\\/+$/, \"\") || \"/\";\n const absoluteSharePath = `${normalizedBasePath === \"/\" ? \"\" : normalizedBasePath}/share/:token`;\n const absoluteSharePrefix = `${normalizedBasePath === \"/\" ? \"\" : normalizedBasePath}/share/`;\n // Absolute target for default + catch-all redirects. Using a relative `to=\"browse\"`\n // here causes an infinite path-compounding loop when a splat (`path=\"*\"`) matches a\n // host-shell sibling route (e.g. `/files/shared`): React Router resolves the\n // relative path against the splat-matched URL, so each render appends another\n // `/browse` segment (`/files/shared/browse/browse/...`).\n const absoluteBrowsePath = `${normalizedBasePath === \"/\" ? \"\" : normalizedBasePath}/browse`;\n\n if (location.pathname.startsWith(absoluteSharePrefix)) {\n return <ShareAccessPage />;\n }\n\n return (\n <Routes>\n {/* Default route - redirect to browse */}\n <Route index element={<Navigate to={absoluteBrowsePath} replace />} />\n\n {/* Main pages - BrowserPage is eager loaded (primary entry point) */}\n <Route path=\"browse\" element={<BrowserPage />} />\n <Route path=\"browse/:folderId\" element={<BrowserPage />} />\n <Route path=\"share/:token\" element={<ShareAccessPage />} />\n <Route path={absoluteSharePath} element={<ShareAccessPage />} />\n\n {/* Catch-all route - redirect to browse (absolute to avoid splat-relative compounding) */}\n <Route path=\"*\" element={<Navigate to={absoluteBrowsePath} replace />} />\n </Routes>\n );\n}\n"],"mappings":";;;;;;AAeA,SAAgBA,IAAc;CAC5B,IAAM,EAAE,gBAAaC,EAAgB,GAC/BC,IAAWC,EAAY,GACvBC,IAAqBC,EAAS,QAAQ,QAAQ,EAAE,KAAK,KACrDC,IAAoB,GAAGF,MAAuB,MAAM,KAAKA,EAAmB,gBAC5EG,IAAsB,GAAGH,MAAuB,MAAM,KAAKA,EAAmB,UAM9EI,IAAqB,GAAGJ,MAAuB,MAAM,KAAKA,EAAmB;CAMnF,OAJIF,EAAS,SAAS,WAAWK,CAAmB,IAC3C,kBAACE,GAAD,CAAkB,CAAA,IAIzB,kBAACC,GAAD,EAAA,UAAA;EAEE,kBAACC,GAAD;GAAO,OAAA;GAAM,SAAS,kBAACC,GAAD;IAAU,IAAIJ;IAAoB,SAAA;GAAS,CAAA;EAAI,CAAA;EAGrE,kBAACG,GAAD;GAAO,MAAK;GAAS,SAAS,kBAACE,GAAD,CAAc,CAAA;EAAI,CAAA;EAChD,kBAACF,GAAD;GAAO,MAAK;GAAmB,SAAS,kBAACE,GAAD,CAAc,CAAA;EAAI,CAAA;EAC1D,kBAACF,GAAD;GAAO,MAAK;GAAe,SAAS,kBAACF,GAAD,CAAkB,CAAA;EAAI,CAAA;EAC1D,kBAACE,GAAD;GAAO,MAAML;GAAmB,SAAS,kBAACG,GAAD,CAAkB,CAAA;EAAI,CAAA;EAG/D,kBAACE,GAAD;GAAO,MAAK;GAAI,SAAS,kBAACC,GAAD;IAAU,IAAIJ;IAAoB,SAAA;GAAS,CAAA;EAAI,CAAA;CAClE,EAAA,CAAA;AAEZ"}
@@ -1 +1 @@
1
- {"version":3,"file":"ActionMenu.js","names":[],"sources":["../../../src/files/components/ActionMenu.tsx"],"sourcesContent":["import {\n type FC,\n useState,\n useRef,\n useEffect,\n useEffectEvent,\n useCallback,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { MoreVertical } from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { tWithFallback } from \"../utils/i18n\";\n\nexport interface ActionMenuItem {\n label: string;\n icon?: React.ReactNode;\n onClick: () => void;\n variant?: \"default\" | \"danger\";\n divider?: boolean;\n}\n\ninterface ActionMenuProps {\n items: ActionMenuItem[];\n triggerClassName?: string;\n menuClassName?: string;\n align?: \"left\" | \"right\";\n isOpen?: boolean;\n onToggle?: (open: boolean) => void;\n}\n\nexport const ActionMenu: FC<ActionMenuProps> = ({\n items,\n triggerClassName = \"\",\n menuClassName = \"\",\n align = \"right\",\n isOpen: controlledIsOpen,\n onToggle,\n}) => {\n const { t } = useI18n();\n const [internalIsOpen, setInternalIsOpen] = useState(false);\n const [menuPosition, setMenuPosition] = useState<{\n top: number;\n left: number;\n } | null>(null);\n const buttonRef = useRef<HTMLButtonElement>(null);\n const menuRef = useRef<HTMLDivElement>(null);\n\n // Use controlled state if provided, otherwise use internal state\n const isOpen =\n controlledIsOpen !== undefined ? controlledIsOpen : internalIsOpen;\n const setIsOpen = useCallback(\n (open: boolean) => {\n if (onToggle) {\n onToggle(open);\n } else {\n setInternalIsOpen(open);\n }\n },\n [onToggle],\n );\n\n // Calculate menu position when opening\n useEffect(() => {\n if (isOpen && buttonRef.current) {\n const rect = buttonRef.current.getBoundingClientRect();\n const menuWidth = 200; // Approximate menu width\n\n let left = align === \"right\" ? rect.right - menuWidth : rect.left;\n\n // Ensure menu doesn't go off-screen\n if (left < 10) left = 10;\n if (left + menuWidth > window.innerWidth - 10) {\n left = window.innerWidth - menuWidth - 10;\n }\n\n setMenuPosition({\n top: rect.bottom + 4, // 4px gap below button\n left: left,\n });\n }\n }, [isOpen, align]);\n\n const closeMenu = useEffectEvent(() => {\n setIsOpen(false);\n });\n\n // Close menu when clicking outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (menuRef.current && !menuRef.current.contains(event.target as Node)) {\n closeMenu();\n }\n };\n\n if (isOpen) {\n document.addEventListener(\"mousedown\", handleClickOutside);\n return () => {\n document.removeEventListener(\"mousedown\", handleClickOutside);\n };\n }\n }, [isOpen]);\n\n // Close menu on Escape key\n useEffect(() => {\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n closeMenu();\n }\n };\n\n if (isOpen) {\n document.addEventListener(\"keydown\", handleEscape);\n return () => {\n document.removeEventListener(\"keydown\", handleEscape);\n };\n }\n }, [isOpen]);\n\n const handleItemClick = (item: ActionMenuItem) => {\n item.onClick();\n setIsOpen(false);\n };\n\n // Render menu dropdown\n const renderMenu = () => {\n if (!isOpen || !menuPosition) return null;\n\n return createPortal(\n <div\n ref={menuRef}\n className={`fixed z-[9999] min-w-[200px] bg-bg-elevated rounded-lg shadow-lg border border-border-default py-1 animate-in fade-in-0 zoom-in-95 duration-150 ${menuClassName}`}\n style={{\n top: `${menuPosition.top}px`,\n left: `${menuPosition.left}px`,\n }}\n role=\"menu\"\n >\n {items.map((item, index) => (\n <div key={item.label}>\n {item.divider && index > 0 && (\n <div className=\"h-px bg-border-subtle my-1\" />\n )}\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n handleItemClick(item);\n }}\n className={`w-full flex items-center gap-3 px-4 py-2 text-sm transition-all duration-150 ${\n item.variant === \"danger\"\n ? \"text-status-error-text hover:bg-status-error-bg-subtle\"\n : \"text-text-primary hover:bg-action-ghost-bg-hover\"\n }`}\n role=\"menuitem\"\n >\n {item.icon && <span className=\"flex-shrink-0\">{item.icon}</span>}\n <span>{item.label}</span>\n </button>\n </div>\n ))}\n </div>,\n document.body,\n );\n };\n\n return (\n <>\n <button\n type=\"button\"\n ref={buttonRef}\n onClick={(e) => {\n e.stopPropagation();\n setIsOpen(!isOpen);\n }}\n className={`p-1.5 hover:bg-action-ghost-bg-hover rounded transition-colors ${triggerClassName}`}\n aria-label={tWithFallback(\n t,\n \"files.actionMenu.moreActions\",\n \"More actions\",\n )}\n title={tWithFallback(t, \"files.actionMenu.moreActions\", \"More actions\")}\n aria-expanded={isOpen}\n aria-haspopup=\"true\"\n >\n <MoreVertical className=\"size-4 text-text-primary\" />\n </button>\n {renderMenu()}\n </>\n );\n};\n"],"mappings":";;;;;;;AA8BA,IAAa,KAAmC,EAC9C,UACA,sBAAmB,IACnB,mBAAgB,IAChB,WAAQ,SACR,QAAQ,GACR,kBACI;CACJ,IAAM,EAAE,SAAM,GAAS,EACjB,CAAC,GAAgB,KAAqB,EAAS,GAAM,EACrD,CAAC,GAAc,KAAmB,EAG9B,KAAK,EACT,IAAY,EAA0B,KAAK,EAC3C,IAAU,EAAuB,KAAK,EAGtC,IACJ,MAAqB,KAAA,IAA+B,IAAnB,GAC7B,IAAY,GACf,MAAkB;AACjB,EAAI,IACF,EAAS,EAAK,GAEd,EAAkB,EAAK;IAG3B,CAAC,EAAS,CACX;AAGD,SAAgB;AACd,MAAI,KAAU,EAAU,SAAS;GAC/B,IAAM,IAAO,EAAU,QAAQ,uBAAuB,EAGlD,IAAO,MAAU,UAAU,EAAK,QAAQ,MAAY,EAAK;AAQ7D,GALI,IAAO,OAAI,IAAO,KAClB,IAAO,MAAY,OAAO,aAAa,OACzC,IAAO,OAAO,aAAa,MAAY,KAGzC,EAAgB;IACd,KAAK,EAAK,SAAS;IACb;IACP,CAAC;;IAEH,CAAC,GAAQ,EAAM,CAAC;CAEnB,IAAM,IAAY,QAAqB;AACrC,IAAU,GAAM;GAChB;AAmBF,CAhBA,QAAgB;EACd,IAAM,KAAsB,MAAsB;AAChD,GAAI,EAAQ,WAAW,CAAC,EAAQ,QAAQ,SAAS,EAAM,OAAe,IACpE,GAAW;;AAIf,MAAI,EAEF,QADA,SAAS,iBAAiB,aAAa,EAAmB,QAC7C;AACX,YAAS,oBAAoB,aAAa,EAAmB;;IAGhE,CAAC,EAAO,CAAC,EAGZ,QAAgB;EACd,IAAM,KAAgB,MAAyB;AAC7C,GAAI,EAAM,QAAQ,YAChB,GAAW;;AAIf,MAAI,EAEF,QADA,SAAS,iBAAiB,WAAW,EAAa,QACrC;AACX,YAAS,oBAAoB,WAAW,EAAa;;IAGxD,CAAC,EAAO,CAAC;CAEZ,IAAM,KAAmB,MAAyB;AAEhD,EADA,EAAK,SAAS,EACd,EAAU,GAAM;;AA6ClB,QACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,UAAD;EACE,MAAK;EACL,KAAK;EACL,UAAU,MAAM;AAEd,GADA,EAAE,iBAAiB,EACnB,EAAU,CAAC,EAAO;;EAEpB,WAAW,kEAAkE;EAC7E,cAAY,EACV,GACA,gCACA,eACD;EACD,OAAO,EAAc,GAAG,gCAAgC,eAAe;EACvE,iBAAe;EACf,iBAAc;YAEd,kBAAC,GAAD,EAAc,WAAU,4BAA6B,CAAA;EAC9C,CAAA,EA5DP,CAAC,KAAU,CAAC,IAAqB,OAE9B,EACL,kBAAC,OAAD;EACE,KAAK;EACL,WAAW,mJAAmJ;EAC9J,OAAO;GACL,KAAK,GAAG,EAAa,IAAI;GACzB,MAAM,GAAG,EAAa,KAAK;GAC5B;EACD,MAAK;YAEJ,EAAM,KAAK,GAAM,MAChB,kBAAC,OAAD,EAAA,UAAA,CACG,EAAK,WAAW,IAAQ,KACvB,kBAAC,OAAD,EAAK,WAAU,8BAA+B,CAAA,EAEhD,kBAAC,UAAD;GACE,MAAK;GACL,UAAU,MAAM;AAEd,IADA,EAAE,iBAAiB,EACnB,EAAgB,EAAK;;GAEvB,WAAW,gFACT,EAAK,YAAY,WACb,2DACA;GAEN,MAAK;aAXP,CAaG,EAAK,QAAQ,kBAAC,QAAD;IAAM,WAAU;cAAiB,EAAK;IAAY,CAAA,EAChE,kBAAC,QAAD,EAAA,UAAO,EAAK,OAAa,CAAA,CAClB;KACL,EAAA,EApBI,EAAK,MAoBT,CACN;EACE,CAAA,EACN,SAAS,KACV,CAyBE,EAAA,CAAA"}
1
+ {"version":3,"file":"ActionMenu.js","names":["_Fragment","ActionMenu","controlledIsOpen","useI18n","internalIsOpen","setInternalIsOpen","useState","menuPosition","setMenuPosition","buttonRef","useRef","menuRef","isOpen","setIsOpen","useCallback","onToggle","open","rect","left","align","closeMenu","useEffectEvent","useEffect","handleClickOutside","event","handleEscape","handleItemClick","item","Fragment","triggerClassName","tWithFallback","t","MoreVertical","createPortal","menuClassName","items","index","e"],"sources":["../../../src/files/components/ActionMenu.tsx"],"sourcesContent":["import {\n type FC,\n useState,\n useRef,\n useEffect,\n useEffectEvent,\n useCallback,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { MoreVertical } from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { tWithFallback } from \"../utils/i18n\";\n\nexport interface ActionMenuItem {\n label: string;\n icon?: React.ReactNode;\n onClick: () => void;\n variant?: \"default\" | \"danger\";\n divider?: boolean;\n}\n\ninterface ActionMenuProps {\n items: ActionMenuItem[];\n triggerClassName?: string;\n menuClassName?: string;\n align?: \"left\" | \"right\";\n isOpen?: boolean;\n onToggle?: (open: boolean) => void;\n}\n\nexport const ActionMenu: FC<ActionMenuProps> = ({\n items,\n triggerClassName = \"\",\n menuClassName = \"\",\n align = \"right\",\n isOpen: controlledIsOpen,\n onToggle,\n}) => {\n const { t } = useI18n();\n const [internalIsOpen, setInternalIsOpen] = useState(false);\n const [menuPosition, setMenuPosition] = useState<{\n top: number;\n left: number;\n } | null>(null);\n const buttonRef = useRef<HTMLButtonElement>(null);\n const menuRef = useRef<HTMLDivElement>(null);\n\n // Use controlled state if provided, otherwise use internal state\n const isOpen =\n controlledIsOpen !== undefined ? controlledIsOpen : internalIsOpen;\n const setIsOpen = useCallback(\n (open: boolean) => {\n if (onToggle) {\n onToggle(open);\n } else {\n setInternalIsOpen(open);\n }\n },\n [onToggle],\n );\n\n // Calculate menu position when opening\n useEffect(() => {\n if (isOpen && buttonRef.current) {\n const rect = buttonRef.current.getBoundingClientRect();\n const menuWidth = 200; // Approximate menu width\n\n let left = align === \"right\" ? rect.right - menuWidth : rect.left;\n\n // Ensure menu doesn't go off-screen\n if (left < 10) left = 10;\n if (left + menuWidth > window.innerWidth - 10) {\n left = window.innerWidth - menuWidth - 10;\n }\n\n setMenuPosition({\n top: rect.bottom + 4, // 4px gap below button\n left: left,\n });\n }\n }, [isOpen, align]);\n\n const closeMenu = useEffectEvent(() => {\n setIsOpen(false);\n });\n\n // Close menu when clicking outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (menuRef.current && !menuRef.current.contains(event.target as Node)) {\n closeMenu();\n }\n };\n\n if (isOpen) {\n document.addEventListener(\"mousedown\", handleClickOutside);\n return () => {\n document.removeEventListener(\"mousedown\", handleClickOutside);\n };\n }\n }, [isOpen]);\n\n // Close menu on Escape key\n useEffect(() => {\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n closeMenu();\n }\n };\n\n if (isOpen) {\n document.addEventListener(\"keydown\", handleEscape);\n return () => {\n document.removeEventListener(\"keydown\", handleEscape);\n };\n }\n }, [isOpen]);\n\n const handleItemClick = (item: ActionMenuItem) => {\n item.onClick();\n setIsOpen(false);\n };\n\n // Render menu dropdown\n const renderMenu = () => {\n if (!isOpen || !menuPosition) return null;\n\n return createPortal(\n <div\n ref={menuRef}\n className={`fixed z-[9999] min-w-[200px] bg-bg-elevated rounded-lg shadow-lg border border-border-default py-1 animate-in fade-in-0 zoom-in-95 duration-150 ${menuClassName}`}\n style={{\n top: `${menuPosition.top}px`,\n left: `${menuPosition.left}px`,\n }}\n role=\"menu\"\n >\n {items.map((item, index) => (\n <div key={item.label}>\n {item.divider && index > 0 && (\n <div className=\"h-px bg-border-subtle my-1\" />\n )}\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n handleItemClick(item);\n }}\n className={`w-full flex items-center gap-3 px-4 py-2 text-sm transition-all duration-150 ${\n item.variant === \"danger\"\n ? \"text-status-error-text hover:bg-status-error-bg-subtle\"\n : \"text-text-primary hover:bg-action-ghost-bg-hover\"\n }`}\n role=\"menuitem\"\n >\n {item.icon && <span className=\"flex-shrink-0\">{item.icon}</span>}\n <span>{item.label}</span>\n </button>\n </div>\n ))}\n </div>,\n document.body,\n );\n };\n\n return (\n <>\n <button\n type=\"button\"\n ref={buttonRef}\n onClick={(e) => {\n e.stopPropagation();\n setIsOpen(!isOpen);\n }}\n className={`p-1.5 hover:bg-action-ghost-bg-hover rounded transition-colors ${triggerClassName}`}\n aria-label={tWithFallback(\n t,\n \"files.actionMenu.moreActions\",\n \"More actions\",\n )}\n title={tWithFallback(t, \"files.actionMenu.moreActions\", \"More actions\")}\n aria-expanded={isOpen}\n aria-haspopup=\"true\"\n >\n <MoreVertical className=\"size-4 text-text-primary\" />\n </button>\n {renderMenu()}\n </>\n );\n};\n"],"mappings":";;;;;;;AA8BA,IAAaC,KAAmC,EAC9C,UACA,sBAAmB,IACnB,mBAAgB,IAChB,WAAQ,SACR,QAAQC,GACR,kBACI;CACJ,IAAM,EAAE,SAAMC,EAAQ,GAChB,CAACC,GAAgBC,KAAqBC,EAAS,EAAK,GACpD,CAACC,GAAcC,KAAmBF,EAG9B,IAAI,GACRG,IAAYC,EAA0B,IAAI,GAC1CC,IAAUD,EAAuB,IAAI,GAGrCE,IACJV,MAAqB,KAAA,IAA+BE,IAAnBF,GAC7BW,IAAYC,GACf,MAAkB;EACjB,AAAIC,IACFA,EAASC,CAAI,IAEbX,EAAkBW,CAAI;CAE1B,GACA,CAACD,CAAQ,CACX;CAGA,QAAgB;EACd,IAAIH,KAAUH,EAAU,SAAS;GAC/B,IAAMQ,IAAOR,EAAU,QAAQ,sBAAsB,GAGjDS,IAAOC,MAAU,UAAUF,EAAK,QAAQ,MAAYA,EAAK;GAQ7D,AALIC,IAAO,OAAI,IAAO,KAClBA,IAAO,MAAY,OAAO,aAAa,OACzC,IAAO,OAAO,aAAa,MAAY,KAGzCV,EAAgB;IACd,KAAKS,EAAK,SAAS;IACb;GACR,CAAC;EACH;CACF,GAAG,CAACL,GAAQO,CAAK,CAAC;CAElB,IAAMC,IAAYC,QAAqB;EACrC,EAAU,EAAK;CACjB,CAAC;CAmBD,AAhBAC,QAAgB;EACd,IAAMC,KAAsB,MAAsB;GAChD,AAAIZ,EAAQ,WAAW,CAACA,EAAQ,QAAQ,SAASa,EAAM,MAAc,KACnEJ,EAAU;EAEd;EAEA,IAAIR,GAEF,OADA,SAAS,iBAAiB,aAAaW,CAAkB,SAC5C;GACX,SAAS,oBAAoB,aAAaA,CAAkB;EAC9D;CAEJ,GAAG,CAACX,CAAM,CAAC,GAGXU,QAAgB;EACd,IAAMG,KAAgB,MAAyB;GAC7C,AAAID,EAAM,QAAQ,YAChBJ,EAAU;EAEd;EAEA,IAAIR,GAEF,OADA,SAAS,iBAAiB,WAAWa,CAAY,SACpC;GACX,SAAS,oBAAoB,WAAWA,CAAY;EACtD;CAEJ,GAAG,CAACb,CAAM,CAAC;CAEX,IAAMc,KAAmB,MAAyB;EAEhD,AADAC,EAAK,QAAQ,GACbd,EAAU,EAAK;CACjB;CA4CA,OACE,kBAAAb,GAAA,EAAA,UAAA,CACE,kBAAC,UAAD;EACE,MAAK;EACL,KAAKS;EACL,UAAU,MAAM;GAEd,AADA,EAAE,gBAAgB,GAClBI,EAAU,CAACD,CAAM;EACnB;EACA,WAAW,kEAAkEiB;EAC7E,cAAYC,EACVC,GACA,gCACA,cACF;EACA,OAAOD,EAAcC,GAAG,gCAAgC,cAAc;EACtE,iBAAenB;EACf,iBAAc;EAEd,UAAA,kBAACoB,GAAD,EAAc,WAAU,2BAA4B,CAAA;CAC9C,CAAA,GA5DN,CAACpB,KAAU,CAACL,IAAqB,OAE9B0B,EACL,kBAAC,OAAD;EACE,KAAKtB;EACL,WAAW,mJAAmJuB;EAC9J,OAAO;GACL,KAAK,GAAG3B,EAAa,IAAI;GACzB,MAAM,GAAGA,EAAa,KAAK;EAC7B;EACA,MAAK;EAEJ,UAAA4B,EAAM,KAAK,GAAM,MAChB,kBAAC,OAAD,EAAA,UAAA,CACGR,EAAK,WAAWS,IAAQ,KACvB,kBAAC,OAAD,EAAK,WAAU,6BAA8B,CAAA,GAE/C,kBAAC,UAAD;GACE,MAAK;GACL,UAAU,MAAM;IAEd,AADAC,EAAE,gBAAgB,GAClBX,EAAgBC,CAAI;GACtB;GACA,WAAW,gFACTA,EAAK,YAAY,WACb,2DACA;GAEN,MAAK;GAXP,UAAA,CAaGA,EAAK,QAAQ,kBAAC,QAAD;IAAM,WAAU;IAAiB,UAAAA,EAAK;GAAW,CAAA,GAC/D,kBAAC,QAAD,EAAA,UAAOA,EAAK,MAAY,CAAA,CAClB;EACL,CAAA,CAAA,EAAA,GApBKA,EAAK,KAoBV,CACN;CACE,CAAA,GACL,SAAS,IACX,CAyBE,EAAA,CAAA;AAEN"}
@@ -17,6 +17,6 @@ interface ConfirmDialogProps {
17
17
  * to work because we drive `open={true}` and forward dismissal via
18
18
  * `onOpenChange` → `onCancel`.
19
19
  */
20
- export declare function ConfirmDialog({ title, description, confirmLabel, cancelLabel, variant, loading, onConfirm, onCancel, }: ConfirmDialogProps): import("react").JSX.Element;
20
+ export declare function ConfirmDialog({ title, description, confirmLabel, cancelLabel, variant, loading, onConfirm, onCancel, }: ConfirmDialogProps): import('react').JSX.Element;
21
21
  export {};
22
22
  //# sourceMappingURL=ConfirmDialog.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ConfirmDialog.js","names":[],"sources":["../../../src/files/components/ConfirmDialog.tsx"],"sourcesContent":["import { type ReactNode } from \"react\";\nimport { AlertTriangle, Loader2 } from \"lucide-react\";\nimport {\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n Button,\n} from \"@burdenoff/fe-libs/ui\";\n\ninterface ConfirmDialogProps {\n title: string;\n description: ReactNode;\n confirmLabel: string;\n cancelLabel: string;\n variant?: \"danger\" | \"default\";\n loading?: boolean;\n onConfirm: () => void;\n onCancel: () => void;\n}\n\n/**\n * Confirm/alert dialog. Delegates layout + dismissal to\n * `<ResponsiveDialog>` from `@burdenoff/fe-libs/ui` (bottom-sheet on\n * mobile, centred modal on tablet/desktop). Existing call sites that\n * mount this conditionally (`{open && <ConfirmDialog ... />}`) continue\n * to work because we drive `open={true}` and forward dismissal via\n * `onOpenChange` → `onCancel`.\n */\nexport function ConfirmDialog({\n title,\n description,\n confirmLabel,\n cancelLabel,\n variant = \"default\",\n loading = false,\n onConfirm,\n onCancel,\n}: ConfirmDialogProps) {\n return (\n <ResponsiveDialog\n open\n onOpenChange={(next: boolean) => {\n if (!next && !loading) {\n onCancel();\n }\n }}\n >\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <div className=\"flex items-start gap-3\">\n <div className=\"rounded-full bg-status-warning-bg-subtle p-2 text-status-warning-text\">\n <AlertTriangle className=\"size-5\" aria-hidden=\"true\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <ResponsiveDialogTitle>{title}</ResponsiveDialogTitle>\n <ResponsiveDialogDescription asChild>\n <div className=\"mt-2 text-sm leading-6 text-text-secondary\">\n {description}\n </div>\n </ResponsiveDialogDescription>\n </div>\n </div>\n </ResponsiveDialogHeader>\n\n <ResponsiveDialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={onCancel}\n disabled={loading}\n >\n {cancelLabel}\n </Button>\n <Button\n type=\"button\"\n onClick={onConfirm}\n disabled={loading}\n variant={variant === \"danger\" ? \"destructive\" : \"default\"}\n >\n {loading && (\n <Loader2 className=\"size-4 animate-spin\" aria-hidden=\"true\" />\n )}\n {confirmLabel}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n"],"mappings":";;;;AA+BA,SAAgB,EAAc,EAC5B,UACA,gBACA,iBACA,gBACA,aAAU,WACV,aAAU,IACV,cACA,eACqB;AACrB,QACE,kBAAC,GAAD;EACE,MAAA;EACA,eAAe,MAAkB;AAC/B,GAAI,CAAC,KAAQ,CAAC,KACZ,GAAU;;YAId,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,GAAD;KAAe,WAAU;KAAS,eAAY;KAAS,CAAA;IACnD,CAAA,EACN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD,EAAA,UAAwB,GAA8B,CAAA,EACtD,kBAAC,GAAD;KAA6B,SAAA;eAC3B,kBAAC,OAAD;MAAK,WAAU;gBACZ;MACG,CAAA;KACsB,CAAA,CAC1B;MACF;MACiB,CAAA,EAEzB,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;GACE,MAAK;GACL,SAAQ;GACR,SAAS;GACT,UAAU;aAET;GACM,CAAA,EACT,kBAAC,GAAD;GACE,MAAK;GACL,SAAS;GACT,UAAU;GACV,SAAS,MAAY,WAAW,gBAAgB;aAJlD,CAMG,KACC,kBAAC,GAAD;IAAS,WAAU;IAAsB,eAAY;IAAS,CAAA,EAE/D,EACM;KACc,EAAA,CAAA,CACD,EAAA,CAAA;EACT,CAAA"}
1
+ {"version":3,"file":"ConfirmDialog.js","names":["ConfirmDialog","ResponsiveDialog","next","loading","onCancel","ResponsiveDialogContent","ResponsiveDialogHeader","AlertTriangle","ResponsiveDialogTitle","title","ResponsiveDialogDescription","description","ResponsiveDialogFooter","Button","cancelLabel","onConfirm","variant","Loader2","confirmLabel"],"sources":["../../../src/files/components/ConfirmDialog.tsx"],"sourcesContent":["import { type ReactNode } from \"react\";\nimport { AlertTriangle, Loader2 } from \"lucide-react\";\nimport {\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n Button,\n} from \"@burdenoff/fe-libs/ui\";\n\ninterface ConfirmDialogProps {\n title: string;\n description: ReactNode;\n confirmLabel: string;\n cancelLabel: string;\n variant?: \"danger\" | \"default\";\n loading?: boolean;\n onConfirm: () => void;\n onCancel: () => void;\n}\n\n/**\n * Confirm/alert dialog. Delegates layout + dismissal to\n * `<ResponsiveDialog>` from `@burdenoff/fe-libs/ui` (bottom-sheet on\n * mobile, centred modal on tablet/desktop). Existing call sites that\n * mount this conditionally (`{open && <ConfirmDialog ... />}`) continue\n * to work because we drive `open={true}` and forward dismissal via\n * `onOpenChange` → `onCancel`.\n */\nexport function ConfirmDialog({\n title,\n description,\n confirmLabel,\n cancelLabel,\n variant = \"default\",\n loading = false,\n onConfirm,\n onCancel,\n}: ConfirmDialogProps) {\n return (\n <ResponsiveDialog\n open\n onOpenChange={(next: boolean) => {\n if (!next && !loading) {\n onCancel();\n }\n }}\n >\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <div className=\"flex items-start gap-3\">\n <div className=\"rounded-full bg-status-warning-bg-subtle p-2 text-status-warning-text\">\n <AlertTriangle className=\"size-5\" aria-hidden=\"true\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <ResponsiveDialogTitle>{title}</ResponsiveDialogTitle>\n <ResponsiveDialogDescription asChild>\n <div className=\"mt-2 text-sm leading-6 text-text-secondary\">\n {description}\n </div>\n </ResponsiveDialogDescription>\n </div>\n </div>\n </ResponsiveDialogHeader>\n\n <ResponsiveDialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={onCancel}\n disabled={loading}\n >\n {cancelLabel}\n </Button>\n <Button\n type=\"button\"\n onClick={onConfirm}\n disabled={loading}\n variant={variant === \"danger\" ? \"destructive\" : \"default\"}\n >\n {loading && (\n <Loader2 className=\"size-4 animate-spin\" aria-hidden=\"true\" />\n )}\n {confirmLabel}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n"],"mappings":";;;;AA+BA,SAAgBA,EAAc,EAC5B,UACA,gBACA,iBACA,gBACA,aAAU,WACV,aAAU,IACV,cACA,eACqB;CACrB,OACE,kBAACC,GAAD;EACE,MAAA;EACA,eAAe,MAAkB;GAC/B,AAAI,CAACC,KAAQ,CAACC,KACZC,EAAS;EAEb;EAEA,UAAA,kBAACC,GAAD,EAAA,UAAA,CACE,kBAACC,GAAD,EAAA,UACE,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,kBAAC,OAAD;IAAK,WAAU;IACb,UAAA,kBAACC,GAAD;KAAe,WAAU;KAAS,eAAY;IAAQ,CAAA;GACnD,CAAA,GACL,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAACC,GAAD,EAAA,UAAwBC,EAA6B,CAAA,GACrD,kBAACC,GAAD;KAA6B,SAAA;KAC3B,UAAA,kBAAC,OAAD;MAAK,WAAU;MACZ,UAAAC;KACE,CAAA;IACsB,CAAA,CAC1B;GACF,CAAA,CAAA;EACiB,CAAA,EAAA,CAAA,GAExB,kBAACC,GAAD,EAAA,UAAA,CACE,kBAACC,GAAD;GACE,MAAK;GACL,SAAQ;GACR,SAAST;GACT,UAAUD;GAET,UAAAW;EACK,CAAA,GACR,kBAACD,GAAD;GACE,MAAK;GACL,SAASE;GACT,UAAUZ;GACV,SAASa,MAAY,WAAW,gBAAgB;GAJlD,UAAA,CAMGb,KACC,kBAACc,GAAD;IAAS,WAAU;IAAsB,eAAY;GAAQ,CAAA,GAE9DC,CACK;EACc,CAAA,CAAA,EAAA,CAAA,CACD,EAAA,CAAA;CACT,CAAA;AAEtB"}
@@ -10,6 +10,6 @@ interface ContextMenuProps {
10
10
  disabled?: boolean;
11
11
  }[];
12
12
  }
13
- export declare function ContextMenu({ x, y, onClose, items }: ContextMenuProps): import("react").JSX.Element;
13
+ export declare function ContextMenu({ x, y, onClose, items }: ContextMenuProps): import('react').JSX.Element;
14
14
  export {};
15
15
  //# sourceMappingURL=ContextMenu.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ContextMenu.js","names":[],"sources":["../../../src/files/components/ContextMenu.tsx"],"sourcesContent":["import { useEffect, useRef } from \"react\";\n\ninterface ContextMenuProps {\n x: number;\n y: number;\n onClose: () => void;\n items: {\n label: string;\n icon: React.ReactNode;\n onClick: () => void;\n variant?: \"default\" | \"danger\";\n disabled?: boolean;\n }[];\n}\n\nexport function ContextMenu({ x, y, onClose, items }: ContextMenuProps) {\n const menuRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (menuRef.current && !menuRef.current.contains(event.target as Node)) {\n onClose();\n }\n };\n\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n onClose();\n }\n };\n\n document.addEventListener(\"mousedown\", handleClickOutside);\n document.addEventListener(\"keydown\", handleEscape);\n\n return () => {\n document.removeEventListener(\"mousedown\", handleClickOutside);\n document.removeEventListener(\"keydown\", handleEscape);\n };\n }, [onClose]);\n\n return (\n <div\n ref={menuRef}\n className=\"fixed bg-bg-elevated rounded-lg shadow-xl border border-border-default py-1 min-w-48 z-50 animate-in fade-in-0 zoom-in-95 duration-150\"\n style={{\n left: `${x}px`,\n top: `${y}px`,\n }}\n >\n {items.map((item) => (\n <button\n type=\"button\"\n key={item.label}\n onClick={() => {\n item.onClick();\n onClose();\n }}\n disabled={item.disabled}\n className={`\n w-full flex items-center gap-3 px-4 py-2 text-sm transition-all duration-150 text-left\n ${\n item.variant === \"danger\"\n ? \"text-status-error-text hover:bg-status-error-bg-subtle\"\n : \"text-text-primary hover:bg-action-ghost-bg-hover\"\n }\n ${item.disabled ? \"opacity-50 cursor-not-allowed\" : \"cursor-pointer\"}\n `}\n >\n {item.icon}\n {item.label}\n </button>\n ))}\n </div>\n );\n}\n"],"mappings":";;;AAeA,SAAgB,EAAY,EAAE,MAAG,MAAG,YAAS,YAA2B;CACtE,IAAM,IAAU,EAAuB,KAAK;AAwB5C,QAtBA,QAAgB;EACd,IAAM,KAAsB,MAAsB;AAChD,GAAI,EAAQ,WAAW,CAAC,EAAQ,QAAQ,SAAS,EAAM,OAAe,IACpE,GAAS;KAIP,KAAgB,MAAyB;AAC7C,GAAI,EAAM,QAAQ,YAChB,GAAS;;AAOb,SAHA,SAAS,iBAAiB,aAAa,EAAmB,EAC1D,SAAS,iBAAiB,WAAW,EAAa,QAErC;AAEX,GADA,SAAS,oBAAoB,aAAa,EAAmB,EAC7D,SAAS,oBAAoB,WAAW,EAAa;;IAEtD,CAAC,EAAQ,CAAC,EAGX,kBAAC,OAAD;EACE,KAAK;EACL,WAAU;EACV,OAAO;GACL,MAAM,GAAG,EAAE;GACX,KAAK,GAAG,EAAE;GACX;YAEA,EAAM,KAAK,MACV,kBAAC,UAAD;GACE,MAAK;GAEL,eAAe;AAEb,IADA,EAAK,SAAS,EACd,GAAS;;GAEX,UAAU,EAAK;GACf,WAAW;;cAGP,EAAK,YAAY,WACb,2DACA,mDACL;cACC,EAAK,WAAW,kCAAkC,iBAAiB;;aAfzE,CAkBG,EAAK,MACL,EAAK,MACC;KAlBF,EAAK,MAkBH,CACT;EACE,CAAA"}
1
+ {"version":3,"file":"ContextMenu.js","names":["ContextMenu","menuRef","useRef","useEffect","handleClickOutside","event","onClose","handleEscape","x","y","items","item"],"sources":["../../../src/files/components/ContextMenu.tsx"],"sourcesContent":["import { useEffect, useRef } from \"react\";\n\ninterface ContextMenuProps {\n x: number;\n y: number;\n onClose: () => void;\n items: {\n label: string;\n icon: React.ReactNode;\n onClick: () => void;\n variant?: \"default\" | \"danger\";\n disabled?: boolean;\n }[];\n}\n\nexport function ContextMenu({ x, y, onClose, items }: ContextMenuProps) {\n const menuRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (menuRef.current && !menuRef.current.contains(event.target as Node)) {\n onClose();\n }\n };\n\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n onClose();\n }\n };\n\n document.addEventListener(\"mousedown\", handleClickOutside);\n document.addEventListener(\"keydown\", handleEscape);\n\n return () => {\n document.removeEventListener(\"mousedown\", handleClickOutside);\n document.removeEventListener(\"keydown\", handleEscape);\n };\n }, [onClose]);\n\n return (\n <div\n ref={menuRef}\n className=\"fixed bg-bg-elevated rounded-lg shadow-xl border border-border-default py-1 min-w-48 z-50 animate-in fade-in-0 zoom-in-95 duration-150\"\n style={{\n left: `${x}px`,\n top: `${y}px`,\n }}\n >\n {items.map((item) => (\n <button\n type=\"button\"\n key={item.label}\n onClick={() => {\n item.onClick();\n onClose();\n }}\n disabled={item.disabled}\n className={`\n w-full flex items-center gap-3 px-4 py-2 text-sm transition-all duration-150 text-left\n ${\n item.variant === \"danger\"\n ? \"text-status-error-text hover:bg-status-error-bg-subtle\"\n : \"text-text-primary hover:bg-action-ghost-bg-hover\"\n }\n ${item.disabled ? \"opacity-50 cursor-not-allowed\" : \"cursor-pointer\"}\n `}\n >\n {item.icon}\n {item.label}\n </button>\n ))}\n </div>\n );\n}\n"],"mappings":";;;AAeA,SAAgBA,EAAY,EAAE,MAAG,MAAG,YAAS,YAA2B;CACtE,IAAMC,IAAUC,EAAuB,IAAI;CAwB3C,OAtBAC,QAAgB;EACd,IAAMC,KAAsB,MAAsB;GAChD,AAAIH,EAAQ,WAAW,CAACA,EAAQ,QAAQ,SAASI,EAAM,MAAc,KACnEC,EAAQ;EAEZ,GAEMC,KAAgB,MAAyB;GAC7C,AAAIF,EAAM,QAAQ,YAChBC,EAAQ;EAEZ;EAKA,OAHA,SAAS,iBAAiB,aAAaF,CAAkB,GACzD,SAAS,iBAAiB,WAAWG,CAAY,SAEpC;GAEX,AADA,SAAS,oBAAoB,aAAaH,CAAkB,GAC5D,SAAS,oBAAoB,WAAWG,CAAY;EACtD;CACF,GAAG,CAACD,CAAO,CAAC,GAGV,kBAAC,OAAD;EACE,KAAKL;EACL,WAAU;EACV,OAAO;GACL,MAAM,GAAGO,EAAE;GACX,KAAK,GAAGC,EAAE;EACZ;EAEC,UAAAC,EAAM,KAAK,MACV,kBAAC,UAAD;GACE,MAAK;GAEL,eAAe;IAEb,AADAC,EAAK,QAAQ,GACbL,EAAQ;GACV;GACA,UAAUK,EAAK;GACf,WAAW;;cAGPA,EAAK,YAAY,WACb,2DACA,mDACL;cACCA,EAAK,WAAW,kCAAkC,iBAAiB;;GAfzE,UAAA,CAkBGA,EAAK,MACLA,EAAK,KACA;EAlBD,GAAAA,EAAK,KAkBJ,CACT;CACE,CAAA;AAET"}
@@ -1 +1 @@
1
- {"version":3,"file":"CopyDialog.js","names":[],"sources":["../../../src/files/components/CopyDialog.tsx"],"sourcesContent":["import { type FC, useState } from \"react\";\nimport { Folder, Home, ChevronRight, Loader2 } from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogFooter,\n Button,\n Input,\n} from \"@burdenoff/fe-libs/ui\";\nimport type { FileItem, FolderItem } from \"../types\";\nimport { useFoldersQuery } from \"../hooks/useFoldersQuery\";\nimport { tWithFallback } from \"../utils/i18n\";\n\ninterface CopyDialogProps {\n item: FileItem | FolderItem;\n type: \"file\" | \"folder\";\n onClose: () => void;\n onCopy: (\n destinationFolderId: string | null,\n newName?: string,\n ) => Promise<void>;\n isLoading?: boolean;\n}\n\nexport const CopyDialog: FC<CopyDialogProps> = ({\n item,\n type,\n onClose,\n onCopy,\n isLoading = false,\n}) => {\n const { t } = useI18n();\n const [currentFolderId, setCurrentFolderId] = useState<string | null>(null);\n const [breadcrumbs, setBreadcrumbs] = useState<\n Array<{ id: string; name: string }>\n >([]);\n const [selectedDestination, setSelectedDestination] = useState<string | null>(\n null,\n );\n const [newName, setNewName] = useState(\n `${tWithFallback(t, \"files.copyDialog.copyOf\", \"Copy of\")} ${item.name}`,\n );\n\n // Fetch folders in current location\n const { data, loading: loadingFolders } = useFoldersQuery(\n currentFolderId || undefined,\n );\n const folders = (data?.getFolders?.folders || []) as FolderItem[];\n\n const handleFolderClick = (folder: FolderItem) => {\n setCurrentFolderId(folder.id);\n setBreadcrumbs([...breadcrumbs, { id: folder.id, name: folder.name }]);\n };\n\n const handleBreadcrumbClick = (index: number) => {\n if (index === -1) {\n // Go to root\n setCurrentFolderId(null);\n setBreadcrumbs([]);\n } else {\n const crumb = breadcrumbs[index];\n setCurrentFolderId(crumb.id);\n setBreadcrumbs(breadcrumbs.slice(0, index + 1));\n }\n };\n\n const handleCopy = async () => {\n await onCopy(selectedDestination, newName.trim() || undefined);\n onClose();\n };\n\n return (\n <ResponsiveDialog\n open\n onOpenChange={(next: boolean) => {\n if (!next && !isLoading) {\n onClose();\n }\n }}\n >\n <ResponsiveDialogContent className=\"flex max-h-[80vh] w-full max-w-md flex-col gap-0 p-0\">\n {/* Header */}\n <ResponsiveDialogHeader className=\"px-6 py-4 border-b border-border-default text-left\">\n <ResponsiveDialogTitle className=\"text-lg font-semibold text-text-primary\">\n {tWithFallback(t, \"files.copyDialog.makeCopyOf\", \"Make a copy of\")}{\" \"}\n \"{item.name}\"\n </ResponsiveDialogTitle>\n </ResponsiveDialogHeader>\n\n {/* Name input */}\n <div className=\"px-6 py-4 border-b border-border-default\">\n <label className=\"block text-sm font-medium text-text-primary mb-2\">\n {tWithFallback(t, \"files.copyDialog.name\", \"Name\")}\n </label>\n <Input\n type=\"text\"\n value={newName}\n onChange={(e) => setNewName(e.target.value)}\n aria-label={tWithFallback(t, \"files.copyDialog.name\", \"Name\")}\n placeholder={tWithFallback(\n t,\n \"files.copyDialog.enterName\",\n \"Enter name for the copy\",\n )}\n />\n </div>\n\n {/* Breadcrumb navigation */}\n <div className=\"px-6 py-3 border-b border-border-default bg-bg-sunken\">\n <div className=\"flex items-center gap-2 text-sm overflow-x-auto\">\n <button\n type=\"button\"\n onClick={() => handleBreadcrumbClick(-1)}\n className=\"flex items-center gap-1.5 text-text-primary hover:bg-action-ghost-bg-hover px-2 py-1 rounded transition-colors duration-200 whitespace-nowrap\"\n >\n <Home className=\"size-4\" />\n <span>\n {tWithFallback(t, \"files.copyDialog.myDrive\", \"My Drive\")}\n </span>\n </button>\n {breadcrumbs.map((crumb, index) => (\n <div\n key={crumb.id}\n className=\"flex items-center gap-2 whitespace-nowrap\"\n >\n <ChevronRight className=\"size-4 text-text-tertiary\" />\n <button\n type=\"button\"\n onClick={() => handleBreadcrumbClick(index)}\n className={`hover:bg-action-ghost-bg-hover px-2 py-1 rounded transition-colors duration-200 ${\n index === breadcrumbs.length - 1\n ? \"text-text-primary font-medium\"\n : \"text-text-secondary\"\n }`}\n >\n {crumb.name}\n </button>\n </div>\n ))}\n </div>\n </div>\n\n {/* Folder list */}\n <div className=\"flex-1 overflow-y-auto px-6 py-4\">\n {loadingFolders ? (\n <div className=\"flex items-center justify-center py-8\">\n <Loader2 className=\"size-6 text-text-tertiary animate-spin\" />\n </div>\n ) : folders.length === 0 ? (\n <div className=\"text-center py-8\">\n <Folder className=\"size-12 text-text-tertiary mx-auto mb-3\" />\n <p className=\"text-sm text-text-secondary\">\n {tWithFallback(\n t,\n \"files.copyDialog.noFolders\",\n \"No folders here\",\n )}\n </p>\n </div>\n ) : (\n <div className=\"space-y-1\">\n {/* Option to copy to current folder */}\n <button\n type=\"button\"\n onClick={() => setSelectedDestination(currentFolderId)}\n className={`w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-left transition-all duration-200 ${\n selectedDestination === currentFolderId\n ? \"bg-bg-accent border-2 border-action-primary-border\"\n : \"hover:bg-action-ghost-bg-hover border-2 border-transparent\"\n }`}\n >\n <Folder className=\"size-5 text-text-link\" />\n <span className=\"font-medium text-text-primary\">\n {tWithFallback(t, \"files.copyDialog.copyHere\", \"Copy here\")}\n </span>\n </button>\n\n {/* List of subfolders */}\n {folders.map((folder) => (\n <div\n key={folder.id}\n className={`flex items-center justify-between gap-3 px-3 py-2.5 rounded-lg transition-all duration-200 ${\n selectedDestination === folder.id\n ? \"bg-bg-accent border-2 border-action-primary-border\"\n : \"hover:bg-action-ghost-bg-hover border-2 border-transparent\"\n }`}\n >\n <button\n type=\"button\"\n onClick={() => setSelectedDestination(folder.id)}\n className=\"flex items-center gap-3 flex-1 min-w-0\"\n >\n <Folder className=\"size-5 text-text-link flex-shrink-0\" />\n <span className=\"font-medium text-text-primary truncate\">\n {folder.name}\n </span>\n </button>\n <button\n type=\"button\"\n onClick={() => handleFolderClick(folder)}\n className=\"p-1.5 text-text-tertiary hover:text-text-secondary hover:bg-action-ghost-bg-hover rounded transition-colors duration-200 flex-shrink-0\"\n title={tWithFallback(\n t,\n \"files.copyDialog.openFolder\",\n \"Open folder\",\n )}\n aria-label={`Open ${folder.name}`}\n >\n <ChevronRight className=\"size-4\" />\n </button>\n </div>\n ))}\n </div>\n )}\n </div>\n\n {/* Footer */}\n <ResponsiveDialogFooter className=\"px-6 py-4 border-t border-border-default\">\n <Button type=\"button\" variant=\"outline\" onClick={onClose}>\n {tWithFallback(t, \"files.common.actions.cancel\", \"Cancel\")}\n </Button>\n <Button\n type=\"button\"\n onClick={handleCopy}\n disabled={\n isLoading || selectedDestination === undefined || !newName.trim()\n }\n >\n {isLoading && <Loader2 className=\"size-4 animate-spin\" />}\n {isLoading\n ? tWithFallback(t, \"files.copyDialog.copying\", \"Copying...\")\n : tWithFallback(t, \"files.copyDialog.copy\", \"Copy\")}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"CopyDialog.js","names":["CopyDialog","useI18n","currentFolderId","setCurrentFolderId","useState","breadcrumbs","setBreadcrumbs","selectedDestination","setSelectedDestination","newName","setNewName","tWithFallback","t","item","loadingFolders","useFoldersQuery","folders","data","handleFolderClick","folder","handleBreadcrumbClick","index","crumb","ResponsiveDialog","next","isLoading","onClose","ResponsiveDialogContent","ResponsiveDialogHeader","ResponsiveDialogTitle","Input","Home","ChevronRight","Loader2","Folder","ResponsiveDialogFooter","Button","onCopy"],"sources":["../../../src/files/components/CopyDialog.tsx"],"sourcesContent":["import { type FC, useState } from \"react\";\nimport { Folder, Home, ChevronRight, Loader2 } from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogFooter,\n Button,\n Input,\n} from \"@burdenoff/fe-libs/ui\";\nimport type { FileItem, FolderItem } from \"../types\";\nimport { useFoldersQuery } from \"../hooks/useFoldersQuery\";\nimport { tWithFallback } from \"../utils/i18n\";\n\ninterface CopyDialogProps {\n item: FileItem | FolderItem;\n type: \"file\" | \"folder\";\n onClose: () => void;\n onCopy: (\n destinationFolderId: string | null,\n newName?: string,\n ) => Promise<void>;\n isLoading?: boolean;\n}\n\nexport const CopyDialog: FC<CopyDialogProps> = ({\n item,\n type,\n onClose,\n onCopy,\n isLoading = false,\n}) => {\n const { t } = useI18n();\n const [currentFolderId, setCurrentFolderId] = useState<string | null>(null);\n const [breadcrumbs, setBreadcrumbs] = useState<\n Array<{ id: string; name: string }>\n >([]);\n const [selectedDestination, setSelectedDestination] = useState<string | null>(\n null,\n );\n const [newName, setNewName] = useState(\n `${tWithFallback(t, \"files.copyDialog.copyOf\", \"Copy of\")} ${item.name}`,\n );\n\n // Fetch folders in current location\n const { data, loading: loadingFolders } = useFoldersQuery(\n currentFolderId || undefined,\n );\n const folders = (data?.getFolders?.folders || []) as FolderItem[];\n\n const handleFolderClick = (folder: FolderItem) => {\n setCurrentFolderId(folder.id);\n setBreadcrumbs([...breadcrumbs, { id: folder.id, name: folder.name }]);\n };\n\n const handleBreadcrumbClick = (index: number) => {\n if (index === -1) {\n // Go to root\n setCurrentFolderId(null);\n setBreadcrumbs([]);\n } else {\n const crumb = breadcrumbs[index];\n setCurrentFolderId(crumb.id);\n setBreadcrumbs(breadcrumbs.slice(0, index + 1));\n }\n };\n\n const handleCopy = async () => {\n await onCopy(selectedDestination, newName.trim() || undefined);\n onClose();\n };\n\n return (\n <ResponsiveDialog\n open\n onOpenChange={(next: boolean) => {\n if (!next && !isLoading) {\n onClose();\n }\n }}\n >\n <ResponsiveDialogContent className=\"flex max-h-[80vh] w-full max-w-md flex-col gap-0 p-0\">\n {/* Header */}\n <ResponsiveDialogHeader className=\"px-6 py-4 border-b border-border-default text-left\">\n <ResponsiveDialogTitle className=\"text-lg font-semibold text-text-primary\">\n {tWithFallback(t, \"files.copyDialog.makeCopyOf\", \"Make a copy of\")}{\" \"}\n \"{item.name}\"\n </ResponsiveDialogTitle>\n </ResponsiveDialogHeader>\n\n {/* Name input */}\n <div className=\"px-6 py-4 border-b border-border-default\">\n <label className=\"block text-sm font-medium text-text-primary mb-2\">\n {tWithFallback(t, \"files.copyDialog.name\", \"Name\")}\n </label>\n <Input\n type=\"text\"\n value={newName}\n onChange={(e) => setNewName(e.target.value)}\n aria-label={tWithFallback(t, \"files.copyDialog.name\", \"Name\")}\n placeholder={tWithFallback(\n t,\n \"files.copyDialog.enterName\",\n \"Enter name for the copy\",\n )}\n />\n </div>\n\n {/* Breadcrumb navigation */}\n <div className=\"px-6 py-3 border-b border-border-default bg-bg-sunken\">\n <div className=\"flex items-center gap-2 text-sm overflow-x-auto\">\n <button\n type=\"button\"\n onClick={() => handleBreadcrumbClick(-1)}\n className=\"flex items-center gap-1.5 text-text-primary hover:bg-action-ghost-bg-hover px-2 py-1 rounded transition-colors duration-200 whitespace-nowrap\"\n >\n <Home className=\"size-4\" />\n <span>\n {tWithFallback(t, \"files.copyDialog.myDrive\", \"My Drive\")}\n </span>\n </button>\n {breadcrumbs.map((crumb, index) => (\n <div\n key={crumb.id}\n className=\"flex items-center gap-2 whitespace-nowrap\"\n >\n <ChevronRight className=\"size-4 text-text-tertiary\" />\n <button\n type=\"button\"\n onClick={() => handleBreadcrumbClick(index)}\n className={`hover:bg-action-ghost-bg-hover px-2 py-1 rounded transition-colors duration-200 ${\n index === breadcrumbs.length - 1\n ? \"text-text-primary font-medium\"\n : \"text-text-secondary\"\n }`}\n >\n {crumb.name}\n </button>\n </div>\n ))}\n </div>\n </div>\n\n {/* Folder list */}\n <div className=\"flex-1 overflow-y-auto px-6 py-4\">\n {loadingFolders ? (\n <div className=\"flex items-center justify-center py-8\">\n <Loader2 className=\"size-6 text-text-tertiary animate-spin\" />\n </div>\n ) : folders.length === 0 ? (\n <div className=\"text-center py-8\">\n <Folder className=\"size-12 text-text-tertiary mx-auto mb-3\" />\n <p className=\"text-sm text-text-secondary\">\n {tWithFallback(\n t,\n \"files.copyDialog.noFolders\",\n \"No folders here\",\n )}\n </p>\n </div>\n ) : (\n <div className=\"space-y-1\">\n {/* Option to copy to current folder */}\n <button\n type=\"button\"\n onClick={() => setSelectedDestination(currentFolderId)}\n className={`w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-left transition-all duration-200 ${\n selectedDestination === currentFolderId\n ? \"bg-bg-accent border-2 border-action-primary-border\"\n : \"hover:bg-action-ghost-bg-hover border-2 border-transparent\"\n }`}\n >\n <Folder className=\"size-5 text-text-link\" />\n <span className=\"font-medium text-text-primary\">\n {tWithFallback(t, \"files.copyDialog.copyHere\", \"Copy here\")}\n </span>\n </button>\n\n {/* List of subfolders */}\n {folders.map((folder) => (\n <div\n key={folder.id}\n className={`flex items-center justify-between gap-3 px-3 py-2.5 rounded-lg transition-all duration-200 ${\n selectedDestination === folder.id\n ? \"bg-bg-accent border-2 border-action-primary-border\"\n : \"hover:bg-action-ghost-bg-hover border-2 border-transparent\"\n }`}\n >\n <button\n type=\"button\"\n onClick={() => setSelectedDestination(folder.id)}\n className=\"flex items-center gap-3 flex-1 min-w-0\"\n >\n <Folder className=\"size-5 text-text-link flex-shrink-0\" />\n <span className=\"font-medium text-text-primary truncate\">\n {folder.name}\n </span>\n </button>\n <button\n type=\"button\"\n onClick={() => handleFolderClick(folder)}\n className=\"p-1.5 text-text-tertiary hover:text-text-secondary hover:bg-action-ghost-bg-hover rounded transition-colors duration-200 flex-shrink-0\"\n title={tWithFallback(\n t,\n \"files.copyDialog.openFolder\",\n \"Open folder\",\n )}\n aria-label={`Open ${folder.name}`}\n >\n <ChevronRight className=\"size-4\" />\n </button>\n </div>\n ))}\n </div>\n )}\n </div>\n\n {/* Footer */}\n <ResponsiveDialogFooter className=\"px-6 py-4 border-t border-border-default\">\n <Button type=\"button\" variant=\"outline\" onClick={onClose}>\n {tWithFallback(t, \"files.common.actions.cancel\", \"Cancel\")}\n </Button>\n <Button\n type=\"button\"\n onClick={handleCopy}\n disabled={\n isLoading || selectedDestination === undefined || !newName.trim()\n }\n >\n {isLoading && <Loader2 className=\"size-4 animate-spin\" />}\n {isLoading\n ? tWithFallback(t, \"files.copyDialog.copying\", \"Copying...\")\n : tWithFallback(t, \"files.copyDialog.copy\", \"Copy\")}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n};\n"],"mappings":"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"}
@@ -10,6 +10,6 @@ interface EmptyStateProps {
10
10
  * `empty-files` illustration is served by the host shell at
11
11
  * `/illustrations/empty-files.webp`.
12
12
  */
13
- export declare function EmptyState({ type, onUpload, onNewFolder }: EmptyStateProps): import("react").JSX.Element;
13
+ export declare function EmptyState({ type, onUpload, onNewFolder }: EmptyStateProps): import('react').JSX.Element;
14
14
  export {};
15
15
  //# sourceMappingURL=EmptyState.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"EmptyState.js","names":[],"sources":["../../../src/files/components/EmptyState.tsx"],"sourcesContent":["import { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { IllustratedEmptyState, Button } from \"@burdenoff/fe-libs/ui\";\nimport { tWithFallback } from \"../utils/i18n\";\n\ninterface EmptyStateProps {\n type: \"all\" | \"recent\" | \"starred\" | \"bin\";\n onUpload?: () => void;\n onNewFolder?: () => void;\n}\n\n/**\n * Local wrapper that delegates to the on-brand `<IllustratedEmptyState>` from\n * `@burdenoff/fe-libs/ui`. Keeps the microfe-files-specific `type`-keyed config\n * (illustration + i18n keys + per-type action visibility) at the call site. The\n * `empty-files` illustration is served by the host shell at\n * `/illustrations/empty-files.webp`.\n */\nexport function EmptyState({ type, onUpload, onNewFolder }: EmptyStateProps) {\n const { t } = useI18n();\n const configs = {\n all: {\n title: tWithFallback(\n t,\n \"files.empty.all.title\",\n \"No files or folders yet\",\n ),\n description: tWithFallback(\n t,\n \"files.empty.all.description\",\n \"Upload files or create folders to get started\",\n ),\n showActions: true,\n },\n recent: {\n title: tWithFallback(t, \"files.empty.recent.title\", \"No recent files\"),\n description: tWithFallback(\n t,\n \"files.empty.recent.description\",\n \"Files you recently opened will appear here\",\n ),\n showActions: false,\n },\n starred: {\n title: tWithFallback(t, \"files.empty.starred.title\", \"No starred items\"),\n description: tWithFallback(\n t,\n \"files.empty.starred.description\",\n \"Star files and folders to find them easily\",\n ),\n showActions: false,\n },\n bin: {\n title: tWithFallback(t, \"files.empty.bin.title\", \"Bin is empty\"),\n description: tWithFallback(\n t,\n \"files.empty.bin.description\",\n \"Deleted files and folders will appear here\",\n ),\n showActions: false,\n },\n };\n\n const config = configs[type];\n\n const action =\n config.showActions && onUpload ? (\n <div className=\"flex flex-wrap items-center justify-center gap-2\">\n <Button type=\"button\" onClick={onUpload}>\n {tWithFallback(t, \"files.empty.uploadFiles\", \"Upload Files\")}\n </Button>\n {onNewFolder && (\n <Button type=\"button\" variant=\"outline\" onClick={onNewFolder}>\n {tWithFallback(t, \"files.empty.newFolder\", \"New Folder\")}\n </Button>\n )}\n </div>\n ) : undefined;\n\n return (\n <IllustratedEmptyState\n illustration=\"empty-files\"\n title={config.title}\n description={config.description}\n action={action}\n />\n );\n}\n"],"mappings":";;;;;AAiBA,SAAgB,EAAW,EAAE,SAAM,aAAU,kBAAgC;CAC3E,IAAM,EAAE,SAAM,GAAS,EA4CjB,IA3CU;EACd,KAAK;GACH,OAAO,EACL,GACA,yBACA,0BACD;GACD,aAAa,EACX,GACA,+BACA,gDACD;GACD,aAAa;GACd;EACD,QAAQ;GACN,OAAO,EAAc,GAAG,4BAA4B,kBAAkB;GACtE,aAAa,EACX,GACA,kCACA,6CACD;GACD,aAAa;GACd;EACD,SAAS;GACP,OAAO,EAAc,GAAG,6BAA6B,mBAAmB;GACxE,aAAa,EACX,GACA,mCACA,6CACD;GACD,aAAa;GACd;EACD,KAAK;GACH,OAAO,EAAc,GAAG,yBAAyB,eAAe;GAChE,aAAa,EACX,GACA,+BACA,6CACD;GACD,aAAa;GACd;EACF,CAEsB,IAEjB,IACJ,EAAO,eAAe,IACpB,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,GAAD;GAAQ,MAAK;GAAS,SAAS;aAC5B,EAAc,GAAG,2BAA2B,eAAe;GACrD,CAAA,EACR,KACC,kBAAC,GAAD;GAAQ,MAAK;GAAS,SAAQ;GAAU,SAAS;aAC9C,EAAc,GAAG,yBAAyB,aAAa;GACjD,CAAA,CAEP;MACJ,KAAA;AAEN,QACE,kBAAC,GAAD;EACE,cAAa;EACb,OAAO,EAAO;EACd,aAAa,EAAO;EACZ;EACR,CAAA"}
1
+ {"version":3,"file":"EmptyState.js","names":["EmptyState","useI18n","config","tWithFallback","t","type","action","onUpload","Button","onNewFolder","IllustratedEmptyState"],"sources":["../../../src/files/components/EmptyState.tsx"],"sourcesContent":["import { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { IllustratedEmptyState, Button } from \"@burdenoff/fe-libs/ui\";\nimport { tWithFallback } from \"../utils/i18n\";\n\ninterface EmptyStateProps {\n type: \"all\" | \"recent\" | \"starred\" | \"bin\";\n onUpload?: () => void;\n onNewFolder?: () => void;\n}\n\n/**\n * Local wrapper that delegates to the on-brand `<IllustratedEmptyState>` from\n * `@burdenoff/fe-libs/ui`. Keeps the microfe-files-specific `type`-keyed config\n * (illustration + i18n keys + per-type action visibility) at the call site. The\n * `empty-files` illustration is served by the host shell at\n * `/illustrations/empty-files.webp`.\n */\nexport function EmptyState({ type, onUpload, onNewFolder }: EmptyStateProps) {\n const { t } = useI18n();\n const configs = {\n all: {\n title: tWithFallback(\n t,\n \"files.empty.all.title\",\n \"No files or folders yet\",\n ),\n description: tWithFallback(\n t,\n \"files.empty.all.description\",\n \"Upload files or create folders to get started\",\n ),\n showActions: true,\n },\n recent: {\n title: tWithFallback(t, \"files.empty.recent.title\", \"No recent files\"),\n description: tWithFallback(\n t,\n \"files.empty.recent.description\",\n \"Files you recently opened will appear here\",\n ),\n showActions: false,\n },\n starred: {\n title: tWithFallback(t, \"files.empty.starred.title\", \"No starred items\"),\n description: tWithFallback(\n t,\n \"files.empty.starred.description\",\n \"Star files and folders to find them easily\",\n ),\n showActions: false,\n },\n bin: {\n title: tWithFallback(t, \"files.empty.bin.title\", \"Bin is empty\"),\n description: tWithFallback(\n t,\n \"files.empty.bin.description\",\n \"Deleted files and folders will appear here\",\n ),\n showActions: false,\n },\n };\n\n const config = configs[type];\n\n const action =\n config.showActions && onUpload ? (\n <div className=\"flex flex-wrap items-center justify-center gap-2\">\n <Button type=\"button\" onClick={onUpload}>\n {tWithFallback(t, \"files.empty.uploadFiles\", \"Upload Files\")}\n </Button>\n {onNewFolder && (\n <Button type=\"button\" variant=\"outline\" onClick={onNewFolder}>\n {tWithFallback(t, \"files.empty.newFolder\", \"New Folder\")}\n </Button>\n )}\n </div>\n ) : undefined;\n\n return (\n <IllustratedEmptyState\n illustration=\"empty-files\"\n title={config.title}\n description={config.description}\n action={action}\n />\n );\n}\n"],"mappings":";;;;;AAiBA,SAAgBA,EAAW,EAAE,SAAM,aAAU,kBAAgC;CAC3E,IAAM,EAAE,SAAMC,EAAQ,GA4ChBC,IAAS;EA1Cb,KAAK;GACH,OAAOC,EACLC,GACA,yBACA,yBACF;GACA,aAAaD,EACXC,GACA,+BACA,+CACF;GACA,aAAa;EACf;EACA,QAAQ;GACN,OAAOD,EAAcC,GAAG,4BAA4B,iBAAiB;GACrE,aAAaD,EACXC,GACA,kCACA,4CACF;GACA,aAAa;EACf;EACA,SAAS;GACP,OAAOD,EAAcC,GAAG,6BAA6B,kBAAkB;GACvE,aAAaD,EACXC,GACA,mCACA,4CACF;GACA,aAAa;EACf;EACA,KAAK;GACH,OAAOD,EAAcC,GAAG,yBAAyB,cAAc;GAC/D,aAAaD,EACXC,GACA,+BACA,4CACF;GACA,aAAa;EACf;CAGa,EAAQC,IAEjBC,IACJJ,EAAO,eAAeK,IACpB,kBAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CACE,kBAACC,GAAD;GAAQ,MAAK;GAAS,SAASD;GAC5B,UAAAJ,EAAcC,GAAG,2BAA2B,cAAc;EACrD,CAAA,GACPK,KACC,kBAACD,GAAD;GAAQ,MAAK;GAAS,SAAQ;GAAU,SAASC;GAC9C,UAAAN,EAAcC,GAAG,yBAAyB,YAAY;EACjD,CAAA,CAEP;CACH,CAAA,IAAA,KAAA;CAEN,OACE,kBAACM,GAAD;EACE,cAAa;EACb,OAAOR,EAAO;EACd,aAAaA,EAAO;EACZ;CACT,CAAA;AAEL"}
@@ -101,7 +101,8 @@ var c = ({ files: c, folders: l, loading: ue = !1, error: u = null, preserveSort
101
101
  onRestore: p && W(e) ? () => p(e) : void 0,
102
102
  isStarred: e.starred
103
103
  }, k);
104
- } else {
104
+ }
105
+ {
105
106
  let e = I.item;
106
107
  return i({
107
108
  onShare: S && Y(e) ? () => S(e) : void 0,