@burdenoff/microfe-files 2026.525.2 → 2026.527.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 (221) hide show
  1. package/dist/files/components/ActionMenu.js +3 -1
  2. package/dist/files/components/ActionMenu.js.map +1 -1
  3. package/dist/files/components/ContextMenu.js +16 -112
  4. package/dist/files/components/ContextMenu.js.map +1 -1
  5. package/dist/files/components/CopyDialog.js +8 -0
  6. package/dist/files/components/CopyDialog.js.map +1 -1
  7. package/dist/files/components/EmptyState.js +2 -0
  8. package/dist/files/components/EmptyState.js.map +1 -1
  9. package/dist/files/components/FileBrowser.js +6 -1
  10. package/dist/files/components/FileBrowser.js.map +1 -1
  11. package/dist/files/components/FileCard.js +4 -0
  12. package/dist/files/components/FileCard.js.map +1 -1
  13. package/dist/files/components/FileInfoPanel.js +2 -0
  14. package/dist/files/components/FileInfoPanel.js.map +1 -1
  15. package/dist/files/components/FileListItem.js +6 -0
  16. package/dist/files/components/FileListItem.js.map +1 -1
  17. package/dist/files/components/FilePreviewModal.js +9 -3
  18. package/dist/files/components/FilePreviewModal.js.map +1 -1
  19. package/dist/files/components/FileVersionPanel.js +5 -0
  20. package/dist/files/components/FileVersionPanel.js.map +1 -1
  21. package/dist/files/components/FolderCard.js +3 -0
  22. package/dist/files/components/FolderCard.js.map +1 -1
  23. package/dist/files/components/MoveDialog.js +8 -0
  24. package/dist/files/components/MoveDialog.js.map +1 -1
  25. package/dist/files/components/SearchBar.js +4 -0
  26. package/dist/files/components/SearchBar.js.map +1 -1
  27. package/dist/files/components/ShareDialog.js +109 -104
  28. package/dist/files/components/ShareDialog.js.map +1 -1
  29. package/dist/files/components/TabBar.js +1 -0
  30. package/dist/files/components/TabBar.js.map +1 -1
  31. package/dist/files/components/Toast.js +1 -0
  32. package/dist/files/components/Toast.js.map +1 -1
  33. package/dist/files/components/UploadQueue.js +5 -0
  34. package/dist/files/components/UploadQueue.js.map +1 -1
  35. package/dist/files/components/contextMenuItems.js +103 -0
  36. package/dist/files/components/contextMenuItems.js.map +1 -0
  37. package/dist/files/components/viewers/AudioPlayer.js +4 -1
  38. package/dist/files/components/viewers/AudioPlayer.js.map +1 -1
  39. package/dist/files/components/viewers/CodeViewer.js +2 -0
  40. package/dist/files/components/viewers/CodeViewer.js.map +1 -1
  41. package/dist/files/components/viewers/ImageViewer.js +4 -0
  42. package/dist/files/components/viewers/ImageViewer.js.map +1 -1
  43. package/dist/files/components/viewers/PDFViewer.js +2 -0
  44. package/dist/files/components/viewers/PDFViewer.js.map +1 -1
  45. package/dist/files/components/viewers/TextViewer.js +4 -2
  46. package/dist/files/components/viewers/TextViewer.js.map +1 -1
  47. package/dist/files/components/viewers/VideoPlayer.js +5 -1
  48. package/dist/files/components/viewers/VideoPlayer.js.map +1 -1
  49. package/dist/files/hooks/useBatchOperations.js.map +1 -1
  50. package/dist/files/hooks/useFileVersions.js.map +1 -1
  51. package/dist/files/pages/BrowserPage.js +18 -2
  52. package/dist/files/pages/BrowserPage.js.map +1 -1
  53. package/dist/files/pages/ShareAccessPage.js +6 -5
  54. package/dist/files/pages/ShareAccessPage.js.map +1 -1
  55. package/dist/files/utils/index.js +1 -1
  56. package/dist/files/utils/index.js.map +1 -1
  57. package/dist/files/utils/thumbnail.js.map +1 -1
  58. package/dist/files.js +2 -1
  59. package/dist/translations/en.js +259 -0
  60. package/dist/translations/en.js.map +1 -0
  61. package/package.json +1 -4
  62. package/dist/config/index.d.ts +0 -33
  63. package/dist/config/index.d.ts.map +0 -1
  64. package/dist/dev/main.d.ts +0 -1
  65. package/dist/dev/main.d.ts.map +0 -1
  66. package/dist/files/FilesRoot.d.ts +0 -31
  67. package/dist/files/FilesRoot.d.ts.map +0 -1
  68. package/dist/files/FilesRoutes.d.ts +0 -12
  69. package/dist/files/FilesRoutes.d.ts.map +0 -1
  70. package/dist/files/components/ActionMenu.d.ts +0 -19
  71. package/dist/files/components/ActionMenu.d.ts.map +0 -1
  72. package/dist/files/components/ConfirmDialog.d.ts +0 -14
  73. package/dist/files/components/ConfirmDialog.d.ts.map +0 -1
  74. package/dist/files/components/ContextMenu.d.ts +0 -59
  75. package/dist/files/components/ContextMenu.d.ts.map +0 -1
  76. package/dist/files/components/CopyDialog.d.ts +0 -12
  77. package/dist/files/components/CopyDialog.d.ts.map +0 -1
  78. package/dist/files/components/EmptyState.d.ts +0 -8
  79. package/dist/files/components/EmptyState.d.ts.map +0 -1
  80. package/dist/files/components/FileBrowser.d.ts +0 -37
  81. package/dist/files/components/FileBrowser.d.ts.map +0 -1
  82. package/dist/files/components/FileCard.d.ts +0 -30
  83. package/dist/files/components/FileCard.d.ts.map +0 -1
  84. package/dist/files/components/FileInfoPanel.d.ts +0 -9
  85. package/dist/files/components/FileInfoPanel.d.ts.map +0 -1
  86. package/dist/files/components/FileListItem.d.ts +0 -29
  87. package/dist/files/components/FileListItem.d.ts.map +0 -1
  88. package/dist/files/components/FilePreviewModal.d.ts +0 -17
  89. package/dist/files/components/FilePreviewModal.d.ts.map +0 -1
  90. package/dist/files/components/FileVersionPanel.d.ts +0 -9
  91. package/dist/files/components/FileVersionPanel.d.ts.map +0 -1
  92. package/dist/files/components/FolderCard.d.ts +0 -34
  93. package/dist/files/components/FolderCard.d.ts.map +0 -1
  94. package/dist/files/components/MoveDialog.d.ts +0 -12
  95. package/dist/files/components/MoveDialog.d.ts.map +0 -1
  96. package/dist/files/components/SearchBar.d.ts +0 -13
  97. package/dist/files/components/SearchBar.d.ts.map +0 -1
  98. package/dist/files/components/ShareDialog.d.ts +0 -24
  99. package/dist/files/components/ShareDialog.d.ts.map +0 -1
  100. package/dist/files/components/TabBar.d.ts +0 -14
  101. package/dist/files/components/TabBar.d.ts.map +0 -1
  102. package/dist/files/components/Toast.d.ts +0 -14
  103. package/dist/files/components/Toast.d.ts.map +0 -1
  104. package/dist/files/components/UploadQueue.d.ts +0 -21
  105. package/dist/files/components/UploadQueue.d.ts.map +0 -1
  106. package/dist/files/components/index.d.ts +0 -43
  107. package/dist/files/components/index.d.ts.map +0 -1
  108. package/dist/files/components/viewers/AudioPlayer.d.ts +0 -8
  109. package/dist/files/components/viewers/AudioPlayer.d.ts.map +0 -1
  110. package/dist/files/components/viewers/CodeViewer.d.ts +0 -16
  111. package/dist/files/components/viewers/CodeViewer.d.ts.map +0 -1
  112. package/dist/files/components/viewers/ImageViewer.d.ts +0 -8
  113. package/dist/files/components/viewers/ImageViewer.d.ts.map +0 -1
  114. package/dist/files/components/viewers/PDFViewer.d.ts +0 -15
  115. package/dist/files/components/viewers/PDFViewer.d.ts.map +0 -1
  116. package/dist/files/components/viewers/TextViewer.d.ts +0 -8
  117. package/dist/files/components/viewers/TextViewer.d.ts.map +0 -1
  118. package/dist/files/components/viewers/VideoPlayer.d.ts +0 -8
  119. package/dist/files/components/viewers/VideoPlayer.d.ts.map +0 -1
  120. package/dist/files/components/viewers/index.d.ts +0 -7
  121. package/dist/files/components/viewers/index.d.ts.map +0 -1
  122. package/dist/files/components/viewers/index.js +0 -6
  123. package/dist/files/graphql-types.d.ts +0 -317
  124. package/dist/files/graphql-types.d.ts.map +0 -1
  125. package/dist/files/hooks/useBatchOperations.d.ts +0 -32
  126. package/dist/files/hooks/useBatchOperations.d.ts.map +0 -1
  127. package/dist/files/hooks/useBinItems.d.ts +0 -11
  128. package/dist/files/hooks/useBinItems.d.ts.map +0 -1
  129. package/dist/files/hooks/useBrowsePage.d.ts +0 -18
  130. package/dist/files/hooks/useBrowsePage.d.ts.map +0 -1
  131. package/dist/files/hooks/useCopyFile.d.ts +0 -14
  132. package/dist/files/hooks/useCopyFile.d.ts.map +0 -1
  133. package/dist/files/hooks/useCreateFolder.d.ts +0 -14
  134. package/dist/files/hooks/useCreateFolder.d.ts.map +0 -1
  135. package/dist/files/hooks/useCreateFolderShare.d.ts +0 -16
  136. package/dist/files/hooks/useCreateFolderShare.d.ts.map +0 -1
  137. package/dist/files/hooks/useCreateShare.d.ts +0 -16
  138. package/dist/files/hooks/useCreateShare.d.ts.map +0 -1
  139. package/dist/files/hooks/useDeleteFile.d.ts +0 -9
  140. package/dist/files/hooks/useDeleteFile.d.ts.map +0 -1
  141. package/dist/files/hooks/useDeleteFolder.d.ts +0 -10
  142. package/dist/files/hooks/useDeleteFolder.d.ts.map +0 -1
  143. package/dist/files/hooks/useDragDrop.d.ts +0 -31
  144. package/dist/files/hooks/useDragDrop.d.ts.map +0 -1
  145. package/dist/files/hooks/useFileVersions.d.ts +0 -52
  146. package/dist/files/hooks/useFileVersions.d.ts.map +0 -1
  147. package/dist/files/hooks/useFiles.d.ts +0 -18
  148. package/dist/files/hooks/useFiles.d.ts.map +0 -1
  149. package/dist/files/hooks/useFolder.d.ts +0 -7
  150. package/dist/files/hooks/useFolder.d.ts.map +0 -1
  151. package/dist/files/hooks/useFolderPath.d.ts +0 -2
  152. package/dist/files/hooks/useFolderPath.d.ts.map +0 -1
  153. package/dist/files/hooks/useFoldersQuery.d.ts +0 -7
  154. package/dist/files/hooks/useFoldersQuery.d.ts.map +0 -1
  155. package/dist/files/hooks/useKeyboardNavigation.d.ts +0 -17
  156. package/dist/files/hooks/useKeyboardNavigation.d.ts.map +0 -1
  157. package/dist/files/hooks/useMoveFile.d.ts +0 -10
  158. package/dist/files/hooks/useMoveFile.d.ts.map +0 -1
  159. package/dist/files/hooks/useMoveFolder.d.ts +0 -10
  160. package/dist/files/hooks/useMoveFolder.d.ts.map +0 -1
  161. package/dist/files/hooks/usePermanentlyDeleteFile.d.ts +0 -9
  162. package/dist/files/hooks/usePermanentlyDeleteFile.d.ts.map +0 -1
  163. package/dist/files/hooks/usePermanentlyDeleteFolder.d.ts +0 -9
  164. package/dist/files/hooks/usePermanentlyDeleteFolder.d.ts.map +0 -1
  165. package/dist/files/hooks/useRecentFiles.d.ts +0 -10
  166. package/dist/files/hooks/useRecentFiles.d.ts.map +0 -1
  167. package/dist/files/hooks/useRenameFile.d.ts +0 -10
  168. package/dist/files/hooks/useRenameFile.d.ts.map +0 -1
  169. package/dist/files/hooks/useRenameFolder.d.ts +0 -10
  170. package/dist/files/hooks/useRenameFolder.d.ts.map +0 -1
  171. package/dist/files/hooks/useRestoreFile.d.ts +0 -9
  172. package/dist/files/hooks/useRestoreFile.d.ts.map +0 -1
  173. package/dist/files/hooks/useRestoreFolder.d.ts +0 -9
  174. package/dist/files/hooks/useRestoreFolder.d.ts.map +0 -1
  175. package/dist/files/hooks/useSearch.d.ts +0 -15
  176. package/dist/files/hooks/useSearch.d.ts.map +0 -1
  177. package/dist/files/hooks/useStarredItems.d.ts +0 -10
  178. package/dist/files/hooks/useStarredItems.d.ts.map +0 -1
  179. package/dist/files/hooks/useToast.d.ts +0 -11
  180. package/dist/files/hooks/useToast.d.ts.map +0 -1
  181. package/dist/files/hooks/useToggleStar.d.ts +0 -10
  182. package/dist/files/hooks/useToggleStar.d.ts.map +0 -1
  183. package/dist/files/hooks/useUploadFile.d.ts +0 -25
  184. package/dist/files/hooks/useUploadFile.d.ts.map +0 -1
  185. package/dist/files/index.d.ts +0 -29
  186. package/dist/files/index.d.ts.map +0 -1
  187. package/dist/files/pages/BrowserPage.d.ts +0 -5
  188. package/dist/files/pages/BrowserPage.d.ts.map +0 -1
  189. package/dist/files/pages/ShareAccessPage.d.ts +0 -2
  190. package/dist/files/pages/ShareAccessPage.d.ts.map +0 -1
  191. package/dist/files/providers/FilesProvider.d.ts +0 -25
  192. package/dist/files/providers/FilesProvider.d.ts.map +0 -1
  193. package/dist/files/store/filesStore.d.ts +0 -99
  194. package/dist/files/store/filesStore.d.ts.map +0 -1
  195. package/dist/files/types.d.ts +0 -266
  196. package/dist/files/types.d.ts.map +0 -1
  197. package/dist/files/utils/events.d.ts +0 -6
  198. package/dist/files/utils/events.d.ts.map +0 -1
  199. package/dist/files/utils/i18n.d.ts +0 -5
  200. package/dist/files/utils/i18n.d.ts.map +0 -1
  201. package/dist/files/utils/index.d.ts +0 -74
  202. package/dist/files/utils/index.d.ts.map +0 -1
  203. package/dist/files/utils/thumbnail.d.ts +0 -5
  204. package/dist/files/utils/thumbnail.d.ts.map +0 -1
  205. package/dist/files.d.ts +0 -2
  206. package/dist/generated/global-operations.d.ts +0 -2
  207. package/dist/generated/global-operations.d.ts.map +0 -1
  208. package/dist/generated/global-types.d.ts +0 -23527
  209. package/dist/generated/global-types.d.ts.map +0 -1
  210. package/dist/generated/wspace-operations.d.ts +0 -2706
  211. package/dist/generated/wspace-operations.d.ts.map +0 -1
  212. package/dist/generated/wspace-types.d.ts +0 -57851
  213. package/dist/generated/wspace-types.d.ts.map +0 -1
  214. package/dist/index.d.ts +0 -30
  215. package/dist/index.d.ts.map +0 -1
  216. package/dist/shared/types/index.d.ts +0 -101
  217. package/dist/shared/types/index.d.ts.map +0 -1
  218. package/dist/translations/en.d.ts +0 -315
  219. package/dist/translations/en.d.ts.map +0 -1
  220. package/dist/utils/nativeBridge.d.ts +0 -3
  221. package/dist/utils/nativeBridge.d.ts.map +0 -1
@@ -36,6 +36,7 @@ var u = ({ items: u, triggerClassName: d = "", menuClassName: f = "", align: p =
36
36
  e.onClick(), w(!1);
37
37
  };
38
38
  return /* @__PURE__ */ s(a, { children: [/* @__PURE__ */ o("button", {
39
+ type: "button",
39
40
  ref: x,
40
41
  onClick: (e) => {
41
42
  e.stopPropagation(), w(!C);
@@ -55,6 +56,7 @@ var u = ({ items: u, triggerClassName: d = "", menuClassName: f = "", align: p =
55
56
  },
56
57
  role: "menu",
57
58
  children: u.map((e, t) => /* @__PURE__ */ s("div", { children: [e.divider && t > 0 && /* @__PURE__ */ o("div", { className: "h-px bg-border-subtle my-1" }), /* @__PURE__ */ s("button", {
59
+ type: "button",
58
60
  onClick: (t) => {
59
61
  t.stopPropagation(), T(e);
60
62
  },
@@ -64,7 +66,7 @@ var u = ({ items: u, triggerClassName: d = "", menuClassName: f = "", align: p =
64
66
  className: "flex-shrink-0",
65
67
  children: e.icon
66
68
  }), /* @__PURE__ */ o("span", { children: e.label })]
67
- })] }, t))
69
+ })] }, e.label))
68
70
  }), document.body)] });
69
71
  };
70
72
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"ActionMenu.js","names":[],"sources":["../../../src/files/components/ActionMenu.tsx"],"sourcesContent":["import { type FC, useState, useRef, useEffect } 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 = (open: boolean) => {\n if (onToggle) {\n onToggle(open);\n } else {\n setInternalIsOpen(open);\n }\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 // Close menu when clicking outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (menuRef.current && !menuRef.current.contains(event.target as Node)) {\n setIsOpen(false);\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 setIsOpen(false);\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={index}>\n {item.divider && index > 0 && (\n <div className=\"h-px bg-border-subtle my-1\" />\n )}\n <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 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":";;;;;;;AAuBA,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,KAAa,MAAkB;AACnC,EAAI,IACF,EAAS,EAAK,GAEd,EAAkB,EAAK;;AA0C3B,CArCA,QAAgB;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,EAGnB,QAAgB;EACd,IAAM,KAAsB,MAAsB;AAChD,GAAI,EAAQ,WAAW,CAAC,EAAQ,QAAQ,SAAS,EAAM,OAAe,IACpE,EAAU,GAAM;;AAIpB,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,EAAU,GAAM;;AAIpB,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;;AA4ClB,QACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,UAAD;EACE,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,EA1DP,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,UAAU,MAAM;AAEd,IADA,EAAE,iBAAiB,EACnB,EAAgB,EAAK;;GAEvB,WAAW,gFACT,EAAK,YAAY,WACb,2DACA;GAEN,MAAK;aAVP,CAYG,EAAK,QAAQ,kBAAC,QAAD;IAAM,WAAU;cAAiB,EAAK;IAAY,CAAA,EAChE,kBAAC,QAAD,EAAA,UAAO,EAAK,OAAa,CAAA,CAClB;KACL,EAAA,EAnBI,EAmBJ,CACN;EACE,CAAA,EACN,SAAS,KACV,CAwBE,EAAA,CAAA"}
1
+ {"version":3,"file":"ActionMenu.js","names":[],"sources":["../../../src/files/components/ActionMenu.tsx"],"sourcesContent":["import { type FC, useState, useRef, useEffect } 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 = (open: boolean) => {\n if (onToggle) {\n onToggle(open);\n } else {\n setInternalIsOpen(open);\n }\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 // Close menu when clicking outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (menuRef.current && !menuRef.current.contains(event.target as Node)) {\n setIsOpen(false);\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 setIsOpen(false);\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":";;;;;;;AAuBA,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,KAAa,MAAkB;AACnC,EAAI,IACF,EAAS,EAAK,GAEd,EAAkB,EAAK;;AA0C3B,CArCA,QAAgB;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,EAGnB,QAAgB;EACd,IAAM,KAAsB,MAAsB;AAChD,GAAI,EAAQ,WAAW,CAAC,EAAQ,QAAQ,SAAS,EAAM,OAAe,IACpE,EAAU,GAAM;;AAIpB,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,EAAU,GAAM;;AAIpB,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,29 +1,28 @@
1
- import { tWithFallback as e } from "../utils/i18n.js";
2
- import { useEffect as t, useRef as n } from "react";
3
- import { Clock as r, Copy as i, Download as a, Edit3 as o, FolderInput as s, Info as c, RotateCcw as l, Share2 as u, Star as d, Trash2 as f } from "lucide-react";
4
- import { jsx as p, jsxs as m } from "react/jsx-runtime";
1
+ import { useEffect as e, useRef as t } from "react";
2
+ import { jsx as n, jsxs as r } from "react/jsx-runtime";
5
3
  //#region src/files/components/ContextMenu.tsx
6
- function h({ x: e, y: r, onClose: i, items: a }) {
7
- let o = n(null);
8
- return t(() => {
4
+ function i({ x: i, y: a, onClose: o, items: s }) {
5
+ let c = t(null);
6
+ return e(() => {
9
7
  let e = (e) => {
10
- o.current && !o.current.contains(e.target) && i();
8
+ c.current && !c.current.contains(e.target) && o();
11
9
  }, t = (e) => {
12
- e.key === "Escape" && i();
10
+ e.key === "Escape" && o();
13
11
  };
14
12
  return document.addEventListener("mousedown", e), document.addEventListener("keydown", t), () => {
15
13
  document.removeEventListener("mousedown", e), document.removeEventListener("keydown", t);
16
14
  };
17
- }, [i]), /* @__PURE__ */ p("div", {
18
- ref: o,
15
+ }, [o]), /* @__PURE__ */ n("div", {
16
+ ref: c,
19
17
  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",
20
18
  style: {
21
- left: `${e}px`,
22
- top: `${r}px`
19
+ left: `${i}px`,
20
+ top: `${a}px`
23
21
  },
24
- children: a.map((e, t) => /* @__PURE__ */ m("button", {
22
+ children: s.map((e) => /* @__PURE__ */ r("button", {
23
+ type: "button",
25
24
  onClick: () => {
26
- e.onClick(), i();
25
+ e.onClick(), o();
27
26
  },
28
27
  disabled: e.disabled,
29
28
  className: `
@@ -32,105 +31,10 @@ function h({ x: e, y: r, onClose: i, items: a }) {
32
31
  ${e.disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"}
33
32
  `,
34
33
  children: [e.icon, e.label]
35
- }, t))
34
+ }, e.label))
36
35
  });
37
36
  }
38
- function g(t, n) {
39
- return [
40
- ...t.onShare ? [{
41
- label: e(n, "files.contextMenu.share", "Share"),
42
- icon: /* @__PURE__ */ p(u, { className: "size-4" }),
43
- onClick: t.onShare
44
- }] : [],
45
- ...t.onDownload ? [{
46
- label: e(n, "files.contextMenu.download", "Download"),
47
- icon: /* @__PURE__ */ p(a, { className: "size-4" }),
48
- onClick: t.onDownload
49
- }] : [],
50
- ...t.onCopy ? [{
51
- label: e(n, "files.contextMenu.makeCopy", "Make a copy"),
52
- icon: /* @__PURE__ */ p(i, { className: "size-4" }),
53
- onClick: t.onCopy
54
- }] : [],
55
- ...t.onRename ? [{
56
- label: e(n, "files.contextMenu.rename", "Rename"),
57
- icon: /* @__PURE__ */ p(o, { className: "size-4" }),
58
- onClick: t.onRename
59
- }] : [],
60
- ...t.onStar ? [{
61
- label: t.isStarred ? e(n, "files.contextMenu.removeStar", "Remove star") : e(n, "files.contextMenu.addToStarred", "Add to starred"),
62
- icon: /* @__PURE__ */ p(d, { className: "size-4" }),
63
- onClick: t.onStar
64
- }] : [],
65
- ...t.onMove ? [{
66
- label: e(n, "files.contextMenu.moveTo", "Move to"),
67
- icon: /* @__PURE__ */ p(s, { className: "size-4" }),
68
- onClick: t.onMove
69
- }] : [],
70
- ...t.onInfo ? [{
71
- label: e(n, "files.contextMenu.fileInfo", "File information"),
72
- icon: /* @__PURE__ */ p(c, { className: "size-4" }),
73
- onClick: t.onInfo
74
- }] : [],
75
- ...t.onActivity ? [{
76
- label: e(n, "files.contextMenu.activity", "Activity"),
77
- icon: /* @__PURE__ */ p(r, { className: "size-4" }),
78
- onClick: t.onActivity
79
- }] : [],
80
- ...t.onRestore ? [{
81
- label: e(n, "files.contextMenu.restore", "Restore"),
82
- icon: /* @__PURE__ */ p(l, { className: "size-4" }),
83
- onClick: t.onRestore
84
- }] : [],
85
- ...t.onDelete ? [{
86
- label: e(n, "files.contextMenu.delete", "Delete"),
87
- icon: /* @__PURE__ */ p(f, { className: "size-4" }),
88
- onClick: t.onDelete,
89
- variant: "danger"
90
- }] : []
91
- ];
92
- }
93
- function _(t, n) {
94
- return [
95
- ...t.onShare ? [{
96
- label: e(n, "files.contextMenu.share", "Share"),
97
- icon: /* @__PURE__ */ p(u, { className: "size-4" }),
98
- onClick: t.onShare
99
- }] : [],
100
- ...t.onRename ? [{
101
- label: e(n, "files.contextMenu.rename", "Rename"),
102
- icon: /* @__PURE__ */ p(o, { className: "size-4" }),
103
- onClick: t.onRename
104
- }] : [],
105
- ...t.onStar ? [{
106
- label: t.isStarred ? e(n, "files.contextMenu.removeStar", "Remove star") : e(n, "files.contextMenu.addToStarred", "Add to starred"),
107
- icon: /* @__PURE__ */ p(d, { className: "size-4" }),
108
- onClick: t.onStar
109
- }] : [],
110
- ...t.onMove ? [{
111
- label: e(n, "files.contextMenu.moveTo", "Move to"),
112
- icon: /* @__PURE__ */ p(s, { className: "size-4" }),
113
- onClick: t.onMove
114
- }] : [],
115
- ...t.onInfo ? [{
116
- label: e(n, "files.contextMenu.folderInfo", "Folder information"),
117
- icon: /* @__PURE__ */ p(c, { className: "size-4" }),
118
- onClick: t.onInfo
119
- }] : [],
120
- ...t.onRestore ? [{
121
- label: e(n, "files.contextMenu.restore", "Restore"),
122
- icon: /* @__PURE__ */ p(l, { className: "size-4" }),
123
- onClick: t.onRestore
124
- }] : [],
125
- ...t.onDelete ? [{
126
- label: e(n, "files.contextMenu.delete", "Delete"),
127
- icon: /* @__PURE__ */ p(f, { className: "size-4" }),
128
- onClick: t.onDelete,
129
- variant: "danger"
130
- }] : []
131
- ];
132
- }
133
37
  //#endregion
134
- export { h as ContextMenu, g as createFileMenuItems, _ as createFolderMenuItems };
38
+ export { i as ContextMenu };
135
39
 
136
40
  //# sourceMappingURL=ContextMenu.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ContextMenu.js","names":[],"sources":["../../../src/files/components/ContextMenu.tsx"],"sourcesContent":["import { useEffect, useRef } from \"react\";\nimport {\n Share2,\n Download,\n Copy,\n Trash2,\n Edit3,\n Star,\n FolderInput,\n Info,\n Clock,\n RotateCcw,\n} from \"lucide-react\";\nimport type { I18nContextValue } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { tWithFallback } from \"../utils/i18n\";\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, index) => (\n <button\n key={index}\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\n// Helper to create menu items\nexport function createFileMenuItems(\n options: {\n onShare?: () => void;\n onDownload?: () => void;\n onCopy?: () => void;\n onRename?: () => void;\n onStar?: () => void;\n onMove?: () => void;\n onInfo?: () => void;\n onActivity?: () => void;\n onRestore?: () => void;\n onDelete?: () => void;\n isStarred?: boolean;\n },\n t: I18nContextValue[\"t\"],\n) {\n return [\n ...(options.onShare\n ? [\n {\n label: tWithFallback(t, \"files.contextMenu.share\", \"Share\"),\n icon: <Share2 className=\"size-4\" />,\n onClick: options.onShare,\n },\n ]\n : []),\n ...(options.onDownload\n ? [\n {\n label: tWithFallback(t, \"files.contextMenu.download\", \"Download\"),\n icon: <Download className=\"size-4\" />,\n onClick: options.onDownload,\n },\n ]\n : []),\n ...(options.onCopy\n ? [\n {\n label: tWithFallback(\n t,\n \"files.contextMenu.makeCopy\",\n \"Make a copy\",\n ),\n icon: <Copy className=\"size-4\" />,\n onClick: options.onCopy,\n },\n ]\n : []),\n ...(options.onRename\n ? [\n {\n label: tWithFallback(t, \"files.contextMenu.rename\", \"Rename\"),\n icon: <Edit3 className=\"size-4\" />,\n onClick: options.onRename,\n },\n ]\n : []),\n ...(options.onStar\n ? [\n {\n label: options.isStarred\n ? tWithFallback(t, \"files.contextMenu.removeStar\", \"Remove star\")\n : tWithFallback(\n t,\n \"files.contextMenu.addToStarred\",\n \"Add to starred\",\n ),\n icon: <Star className=\"size-4\" />,\n onClick: options.onStar,\n },\n ]\n : []),\n ...(options.onMove\n ? [\n {\n label: tWithFallback(t, \"files.contextMenu.moveTo\", \"Move to\"),\n icon: <FolderInput className=\"size-4\" />,\n onClick: options.onMove,\n },\n ]\n : []),\n ...(options.onInfo\n ? [\n {\n label: tWithFallback(\n t,\n \"files.contextMenu.fileInfo\",\n \"File information\",\n ),\n icon: <Info className=\"size-4\" />,\n onClick: options.onInfo,\n },\n ]\n : []),\n ...(options.onActivity\n ? [\n {\n label: tWithFallback(t, \"files.contextMenu.activity\", \"Activity\"),\n icon: <Clock className=\"size-4\" />,\n onClick: options.onActivity,\n },\n ]\n : []),\n ...(options.onRestore\n ? [\n {\n label: tWithFallback(t, \"files.contextMenu.restore\", \"Restore\"),\n icon: <RotateCcw className=\"size-4\" />,\n onClick: options.onRestore,\n },\n ]\n : []),\n ...(options.onDelete\n ? [\n {\n label: tWithFallback(t, \"files.contextMenu.delete\", \"Delete\"),\n icon: <Trash2 className=\"size-4\" />,\n onClick: options.onDelete,\n variant: \"danger\" as const,\n },\n ]\n : []),\n ];\n}\n\nexport function createFolderMenuItems(\n options: {\n onShare?: () => void;\n onRename?: () => void;\n onStar?: () => void;\n onMove?: () => void;\n onInfo?: () => void;\n onRestore?: () => void;\n onDelete?: () => void;\n isStarred?: boolean;\n },\n t: I18nContextValue[\"t\"],\n) {\n return [\n ...(options.onShare\n ? [\n {\n label: tWithFallback(t, \"files.contextMenu.share\", \"Share\"),\n icon: <Share2 className=\"size-4\" />,\n onClick: options.onShare,\n },\n ]\n : []),\n ...(options.onRename\n ? [\n {\n label: tWithFallback(t, \"files.contextMenu.rename\", \"Rename\"),\n icon: <Edit3 className=\"size-4\" />,\n onClick: options.onRename,\n },\n ]\n : []),\n ...(options.onStar\n ? [\n {\n label: options.isStarred\n ? tWithFallback(t, \"files.contextMenu.removeStar\", \"Remove star\")\n : tWithFallback(\n t,\n \"files.contextMenu.addToStarred\",\n \"Add to starred\",\n ),\n icon: <Star className=\"size-4\" />,\n onClick: options.onStar,\n },\n ]\n : []),\n ...(options.onMove\n ? [\n {\n label: tWithFallback(t, \"files.contextMenu.moveTo\", \"Move to\"),\n icon: <FolderInput className=\"size-4\" />,\n onClick: options.onMove,\n },\n ]\n : []),\n ...(options.onInfo\n ? [\n {\n label: tWithFallback(\n t,\n \"files.contextMenu.folderInfo\",\n \"Folder information\",\n ),\n icon: <Info className=\"size-4\" />,\n onClick: options.onInfo,\n },\n ]\n : []),\n ...(options.onRestore\n ? [\n {\n label: tWithFallback(t, \"files.contextMenu.restore\", \"Restore\"),\n icon: <RotateCcw className=\"size-4\" />,\n onClick: options.onRestore,\n },\n ]\n : []),\n ...(options.onDelete\n ? [\n {\n label: tWithFallback(t, \"files.contextMenu.delete\", \"Delete\"),\n icon: <Trash2 className=\"size-4\" />,\n onClick: options.onDelete,\n variant: \"danger\" as const,\n },\n ]\n : []),\n ];\n}\n"],"mappings":"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"}
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"}
@@ -38,6 +38,7 @@ var d = ({ item: d, type: f, onClose: p, onCopy: m, isLoading: h = !1 }) => {
38
38
  "\""
39
39
  ]
40
40
  }), /* @__PURE__ */ c("button", {
41
+ type: "button",
41
42
  onClick: p,
42
43
  className: "p-1 text-text-tertiary hover:text-text-secondary hover:bg-action-ghost-bg-hover rounded transition-colors duration-200",
43
44
  "aria-label": e(g, "files.copyDialog.close", "Close copy dialog"),
@@ -62,12 +63,14 @@ var d = ({ item: d, type: f, onClose: p, onCopy: m, isLoading: h = !1 }) => {
62
63
  children: /* @__PURE__ */ l("div", {
63
64
  className: "flex items-center gap-2 text-sm overflow-x-auto",
64
65
  children: [/* @__PURE__ */ l("button", {
66
+ type: "button",
65
67
  onClick: () => k(-1),
66
68
  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",
67
69
  children: [/* @__PURE__ */ c(a, { className: "size-4" }), /* @__PURE__ */ c("span", { children: e(g, "files.copyDialog.myDrive", "My Drive") })]
68
70
  }), y.map((e, t) => /* @__PURE__ */ l("div", {
69
71
  className: "flex items-center gap-2 whitespace-nowrap",
70
72
  children: [/* @__PURE__ */ c(r, { className: "size-4 text-text-tertiary" }), /* @__PURE__ */ c("button", {
73
+ type: "button",
71
74
  onClick: () => k(t),
72
75
  className: `hover:bg-action-ghost-bg-hover px-2 py-1 rounded transition-colors duration-200 ${t === y.length - 1 ? "text-text-primary font-medium" : "text-text-secondary"}`,
73
76
  children: e.name
@@ -89,6 +92,7 @@ var d = ({ item: d, type: f, onClose: p, onCopy: m, isLoading: h = !1 }) => {
89
92
  }) : /* @__PURE__ */ l("div", {
90
93
  className: "space-y-1",
91
94
  children: [/* @__PURE__ */ l("button", {
95
+ type: "button",
92
96
  onClick: () => S(_),
93
97
  className: `w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-left transition-all duration-200 ${x === _ ? "bg-bg-accent border-2 border-action-primary-border" : "hover:bg-action-ghost-bg-hover border-2 border-transparent"}`,
94
98
  children: [/* @__PURE__ */ c(i, { className: "size-5 text-text-link" }), /* @__PURE__ */ c("span", {
@@ -98,6 +102,7 @@ var d = ({ item: d, type: f, onClose: p, onCopy: m, isLoading: h = !1 }) => {
98
102
  }), D.map((t) => /* @__PURE__ */ l("div", {
99
103
  className: `flex items-center justify-between gap-3 px-3 py-2.5 rounded-lg transition-all duration-200 ${x === t.id ? "bg-bg-accent border-2 border-action-primary-border" : "hover:bg-action-ghost-bg-hover border-2 border-transparent"}`,
100
104
  children: [/* @__PURE__ */ l("button", {
105
+ type: "button",
101
106
  onClick: () => S(t.id),
102
107
  className: "flex items-center gap-3 flex-1 min-w-0",
103
108
  children: [/* @__PURE__ */ c(i, { className: "size-5 text-text-link flex-shrink-0" }), /* @__PURE__ */ c("span", {
@@ -105,6 +110,7 @@ var d = ({ item: d, type: f, onClose: p, onCopy: m, isLoading: h = !1 }) => {
105
110
  children: t.name
106
111
  })]
107
112
  }), /* @__PURE__ */ c("button", {
113
+ type: "button",
108
114
  onClick: () => O(t),
109
115
  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",
110
116
  title: e(g, "files.copyDialog.openFolder", "Open folder"),
@@ -117,10 +123,12 @@ var d = ({ item: d, type: f, onClose: p, onCopy: m, isLoading: h = !1 }) => {
117
123
  /* @__PURE__ */ l("div", {
118
124
  className: "flex items-center justify-end gap-2 px-6 py-4 border-t border-border-default",
119
125
  children: [/* @__PURE__ */ c("button", {
126
+ type: "button",
120
127
  onClick: p,
121
128
  className: "px-4 py-2 text-sm font-medium text-text-primary hover:bg-action-ghost-bg-hover rounded-lg transition-colors duration-200",
122
129
  children: e(g, "files.common.actions.cancel", "Cancel")
123
130
  }), /* @__PURE__ */ l("button", {
131
+ type: "button",
124
132
  onClick: async () => {
125
133
  await m(x, C.trim() || void 0), p();
126
134
  },
@@ -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, X } from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\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 <div\n className=\"fixed inset-0 backdrop-blur-sm flex items-center justify-center z-[100] animate-in fade-in duration-200\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={tWithFallback(t, \"files.copyDialog.title\", \"Copy\")}\n >\n <div className=\"bg-bg-surface rounded-lg shadow-xl w-full max-w-md mx-4 max-h-[80vh] flex flex-col animate-in zoom-in-95 duration-200\">\n {/* Header */}\n <div className=\"flex items-center justify-between px-6 py-4 border-b border-border-default\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tWithFallback(t, \"files.copyDialog.makeCopyOf\", \"Make a copy of\")}{\" \"}\n \"{item.name}\"\n </h2>\n <button\n onClick={onClose}\n className=\"p-1 text-text-tertiary hover:text-text-secondary hover:bg-action-ghost-bg-hover rounded transition-colors duration-200\"\n aria-label={tWithFallback(\n t,\n \"files.copyDialog.close\",\n \"Close copy dialog\",\n )}\n >\n <X className=\"size-5\" />\n </button>\n </div>\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 className=\"w-full px-3 py-2 border border-border-default rounded-lg focus:outline-none focus:ring-2 focus:ring-action-primary-border text-sm transition-colors duration-200\"\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-muted\">\n <div className=\"flex items-center gap-2 text-sm overflow-x-auto\">\n <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 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 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 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 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 <div className=\"flex items-center justify-end gap-2 px-6 py-4 border-t border-border-default\">\n <button\n onClick={onClose}\n className=\"px-4 py-2 text-sm font-medium text-text-primary hover:bg-action-ghost-bg-hover rounded-lg transition-colors duration-200\"\n >\n {tWithFallback(t, \"files.common.actions.cancel\", \"Cancel\")}\n </button>\n <button\n onClick={handleCopy}\n disabled={\n isLoading || selectedDestination === undefined || !newName.trim()\n }\n className=\"px-4 py-2 text-sm font-medium text-text-inverse bg-action-primary-bg rounded-lg hover:bg-action-primary-bg-hover disabled:bg-bg-muted disabled:text-text-tertiary disabled:cursor-not-allowed transition-colors duration-200 flex items-center gap-2\"\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 </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
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, X } from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\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 <div\n className=\"fixed inset-0 backdrop-blur-sm flex items-center justify-center z-[100] animate-in fade-in duration-200\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={tWithFallback(t, \"files.copyDialog.title\", \"Copy\")}\n >\n <div className=\"bg-bg-surface rounded-lg shadow-xl w-full max-w-md mx-4 max-h-[80vh] flex flex-col animate-in zoom-in-95 duration-200\">\n {/* Header */}\n <div className=\"flex items-center justify-between px-6 py-4 border-b border-border-default\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tWithFallback(t, \"files.copyDialog.makeCopyOf\", \"Make a copy of\")}{\" \"}\n \"{item.name}\"\n </h2>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"p-1 text-text-tertiary hover:text-text-secondary hover:bg-action-ghost-bg-hover rounded transition-colors duration-200\"\n aria-label={tWithFallback(\n t,\n \"files.copyDialog.close\",\n \"Close copy dialog\",\n )}\n >\n <X className=\"size-5\" />\n </button>\n </div>\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 className=\"w-full px-3 py-2 border border-border-default rounded-lg focus:outline-none focus:ring-2 focus:ring-action-primary-border text-sm transition-colors duration-200\"\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-muted\">\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 <div className=\"flex items-center justify-end gap-2 px-6 py-4 border-t border-border-default\">\n <button\n type=\"button\"\n onClick={onClose}\n className=\"px-4 py-2 text-sm font-medium text-text-primary hover:bg-action-ghost-bg-hover rounded-lg transition-colors duration-200\"\n >\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 className=\"px-4 py-2 text-sm font-medium text-text-inverse bg-action-primary-bg rounded-lg hover:bg-action-primary-bg-hover disabled:bg-bg-muted disabled:text-text-tertiary disabled:cursor-not-allowed transition-colors duration-200 flex items-center gap-2\"\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 </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
@@ -48,10 +48,12 @@ function c({ type: c, onUpload: l, onNewFolder: u }) {
48
48
  f.showActions && /* @__PURE__ */ o("div", {
49
49
  className: "flex gap-3 animate-in fade-in slide-in-from-bottom-2 duration-300 delay-200",
50
50
  children: [u && /* @__PURE__ */ a("button", {
51
+ type: "button",
51
52
  onClick: u,
52
53
  className: "px-4 py-2 text-sm font-medium text-text-primary bg-bg-surface border border-border-default rounded-lg hover:bg-action-ghost-bg-hover transition-all duration-200",
53
54
  children: e(d, "files.empty.newFolder", "New Folder")
54
55
  }), l && /* @__PURE__ */ a("button", {
56
+ type: "button",
55
57
  onClick: l,
56
58
  className: "px-4 py-2 text-sm font-medium text-action-primary-text bg-action-primary-bg rounded-lg hover:bg-action-primary-bg-hover transition-all duration-200",
57
59
  children: e(d, "files.empty.uploadFiles", "Upload Files")
@@ -1 +1 @@
1
- {"version":3,"file":"EmptyState.js","names":[],"sources":["../../../src/files/components/EmptyState.tsx"],"sourcesContent":["import { FolderOpen, Star, Trash2, Clock } from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { tWithFallback } from \"../utils/i18n\";\n\ninterface EmptyStateProps {\n type: \"all\" | \"recent\" | \"starred\" | \"bin\";\n onUpload?: () => void;\n onNewFolder?: () => void;\n}\n\nexport function EmptyState({ type, onUpload, onNewFolder }: EmptyStateProps) {\n const { t } = useI18n();\n const configs = {\n all: {\n icon: <FolderOpen className=\"size-16 text-text-tertiary\" />,\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 icon: <Clock className=\"size-16 text-text-tertiary\" />,\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 icon: <Star className=\"size-16 text-text-tertiary\" />,\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 icon: <Trash2 className=\"size-16 text-text-tertiary\" />,\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 return (\n <div className=\"flex flex-col items-center justify-center py-20 px-4 animate-in fade-in duration-500\">\n <div className=\"mb-4 animate-in zoom-in duration-300 delay-100\">\n {config.icon}\n </div>\n <h3 className=\"text-lg font-semibold text-text-primary mb-2\">\n {config.title}\n </h3>\n <p className=\"text-sm text-text-secondary mb-6 text-center max-w-md\">\n {config.description}\n </p>\n\n {config.showActions && (\n <div className=\"flex gap-3 animate-in fade-in slide-in-from-bottom-2 duration-300 delay-200\">\n {onNewFolder && (\n <button\n onClick={onNewFolder}\n className=\"px-4 py-2 text-sm font-medium text-text-primary bg-bg-surface border border-border-default rounded-lg hover:bg-action-ghost-bg-hover transition-all duration-200\"\n >\n {tWithFallback(t, \"files.empty.newFolder\", \"New Folder\")}\n </button>\n )}\n {onUpload && (\n <button\n onClick={onUpload}\n className=\"px-4 py-2 text-sm font-medium text-action-primary-text bg-action-primary-bg rounded-lg hover:bg-action-primary-bg-hover transition-all duration-200\"\n >\n {tWithFallback(t, \"files.empty.uploadFiles\", \"Upload Files\")}\n </button>\n )}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;AAUA,SAAgB,EAAW,EAAE,SAAM,aAAU,kBAAgC;CAC3E,IAAM,EAAE,SAAM,GAAS,EAgDjB,IA/CU;EACd,KAAK;GACH,MAAM,kBAAC,GAAD,EAAY,WAAU,8BAA+B,CAAA;GAC3D,OAAO,EACL,GACA,yBACA,0BACD;GACD,aAAa,EACX,GACA,+BACA,gDACD;GACD,aAAa;GACd;EACD,QAAQ;GACN,MAAM,kBAAC,GAAD,EAAO,WAAU,8BAA+B,CAAA;GACtD,OAAO,EAAc,GAAG,4BAA4B,kBAAkB;GACtE,aAAa,EACX,GACA,kCACA,6CACD;GACD,aAAa;GACd;EACD,SAAS;GACP,MAAM,kBAAC,GAAD,EAAM,WAAU,8BAA+B,CAAA;GACrD,OAAO,EAAc,GAAG,6BAA6B,mBAAmB;GACxE,aAAa,EACX,GACA,mCACA,6CACD;GACD,aAAa;GACd;EACD,KAAK;GACH,MAAM,kBAAC,GAAD,EAAQ,WAAU,8BAA+B,CAAA;GACvD,OAAO,EAAc,GAAG,yBAAyB,eAAe;GAChE,aAAa,EACX,GACA,+BACA,6CACD;GACD,aAAa;GACd;EACF,CAEsB;AAEvB,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAO;IACJ,CAAA;GACN,kBAAC,MAAD;IAAI,WAAU;cACX,EAAO;IACL,CAAA;GACL,kBAAC,KAAD;IAAG,WAAU;cACV,EAAO;IACN,CAAA;GAEH,EAAO,eACN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACG,KACC,kBAAC,UAAD;KACE,SAAS;KACT,WAAU;eAET,EAAc,GAAG,yBAAyB,aAAa;KACjD,CAAA,EAEV,KACC,kBAAC,UAAD;KACE,SAAS;KACT,WAAU;eAET,EAAc,GAAG,2BAA2B,eAAe;KACrD,CAAA,CAEP;;GAEJ"}
1
+ {"version":3,"file":"EmptyState.js","names":[],"sources":["../../../src/files/components/EmptyState.tsx"],"sourcesContent":["import { FolderOpen, Star, Trash2, Clock } from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { tWithFallback } from \"../utils/i18n\";\n\ninterface EmptyStateProps {\n type: \"all\" | \"recent\" | \"starred\" | \"bin\";\n onUpload?: () => void;\n onNewFolder?: () => void;\n}\n\nexport function EmptyState({ type, onUpload, onNewFolder }: EmptyStateProps) {\n const { t } = useI18n();\n const configs = {\n all: {\n icon: <FolderOpen className=\"size-16 text-text-tertiary\" />,\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 icon: <Clock className=\"size-16 text-text-tertiary\" />,\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 icon: <Star className=\"size-16 text-text-tertiary\" />,\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 icon: <Trash2 className=\"size-16 text-text-tertiary\" />,\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 return (\n <div className=\"flex flex-col items-center justify-center py-20 px-4 animate-in fade-in duration-500\">\n <div className=\"mb-4 animate-in zoom-in duration-300 delay-100\">\n {config.icon}\n </div>\n <h3 className=\"text-lg font-semibold text-text-primary mb-2\">\n {config.title}\n </h3>\n <p className=\"text-sm text-text-secondary mb-6 text-center max-w-md\">\n {config.description}\n </p>\n\n {config.showActions && (\n <div className=\"flex gap-3 animate-in fade-in slide-in-from-bottom-2 duration-300 delay-200\">\n {onNewFolder && (\n <button\n type=\"button\"\n onClick={onNewFolder}\n className=\"px-4 py-2 text-sm font-medium text-text-primary bg-bg-surface border border-border-default rounded-lg hover:bg-action-ghost-bg-hover transition-all duration-200\"\n >\n {tWithFallback(t, \"files.empty.newFolder\", \"New Folder\")}\n </button>\n )}\n {onUpload && (\n <button\n type=\"button\"\n onClick={onUpload}\n className=\"px-4 py-2 text-sm font-medium text-action-primary-text bg-action-primary-bg rounded-lg hover:bg-action-primary-bg-hover transition-all duration-200\"\n >\n {tWithFallback(t, \"files.empty.uploadFiles\", \"Upload Files\")}\n </button>\n )}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;AAUA,SAAgB,EAAW,EAAE,SAAM,aAAU,kBAAgC;CAC3E,IAAM,EAAE,SAAM,GAAS,EAgDjB,IA/CU;EACd,KAAK;GACH,MAAM,kBAAC,GAAD,EAAY,WAAU,8BAA+B,CAAA;GAC3D,OAAO,EACL,GACA,yBACA,0BACD;GACD,aAAa,EACX,GACA,+BACA,gDACD;GACD,aAAa;GACd;EACD,QAAQ;GACN,MAAM,kBAAC,GAAD,EAAO,WAAU,8BAA+B,CAAA;GACtD,OAAO,EAAc,GAAG,4BAA4B,kBAAkB;GACtE,aAAa,EACX,GACA,kCACA,6CACD;GACD,aAAa;GACd;EACD,SAAS;GACP,MAAM,kBAAC,GAAD,EAAM,WAAU,8BAA+B,CAAA;GACrD,OAAO,EAAc,GAAG,6BAA6B,mBAAmB;GACxE,aAAa,EACX,GACA,mCACA,6CACD;GACD,aAAa;GACd;EACD,KAAK;GACH,MAAM,kBAAC,GAAD,EAAQ,WAAU,8BAA+B,CAAA;GACvD,OAAO,EAAc,GAAG,yBAAyB,eAAe;GAChE,aAAa,EACX,GACA,+BACA,6CACD;GACD,aAAa;GACd;EACF,CAEsB;AAEvB,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAO;IACJ,CAAA;GACN,kBAAC,MAAD;IAAI,WAAU;cACX,EAAO;IACL,CAAA;GACL,kBAAC,KAAD;IAAG,WAAU;cACV,EAAO;IACN,CAAA;GAEH,EAAO,eACN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACG,KACC,kBAAC,UAAD;KACE,MAAK;KACL,SAAS;KACT,WAAU;eAET,EAAc,GAAG,yBAAyB,aAAa;KACjD,CAAA,EAEV,KACC,kBAAC,UAAD;KACE,MAAK;KACL,SAAS;KACT,WAAU;eAET,EAAc,GAAG,2BAA2B,eAAe;KACrD,CAAA,CAEP;;GAEJ"}
@@ -6,7 +6,8 @@ import { useDragDrop as te } from "../hooks/useDragDrop.js";
6
6
  import { FileCard as ne } from "./FileCard.js";
7
7
  import { FileListItem as re } from "./FileListItem.js";
8
8
  import { FolderCard as ie } from "./FolderCard.js";
9
- import { ContextMenu as r, createFileMenuItems as ae, createFolderMenuItems as i } from "./ContextMenu.js";
9
+ import { ContextMenu as r } from "./ContextMenu.js";
10
+ import { createFileMenuItems as ae, createFolderMenuItems as i } from "./contextMenuItems.js";
10
11
  import { useState as a } from "react";
11
12
  import { Grid3x3 as oe, Loader2 as se, Star as ce } from "lucide-react";
12
13
  import { Fragment as le, jsx as o, jsxs as s } from "react/jsx-runtime";
@@ -137,6 +138,7 @@ var c = ({ files: c, folders: l, loading: de = !1, error: u = null, preserveSort
137
138
  children: u.message || n(A, "files.browser.unexpectedError", "An unexpected error occurred")
138
139
  }),
139
140
  /* @__PURE__ */ o("button", {
141
+ type: "button",
140
142
  onClick: () => window.location.reload(),
141
143
  className: "rounded-lg bg-action-primary-bg px-6 py-2.5 text-sm font-medium text-text-inverse transition-colors hover:bg-action-primary-bg-hover",
142
144
  children: n(A, "files.browser.retry", "Retry")
@@ -258,6 +260,7 @@ var c = ({ files: c, folders: l, loading: de = !1, error: u = null, preserveSort
258
260
  className: "flex w-32 flex-shrink-0 items-center gap-1 opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100",
259
261
  children: [
260
262
  Z(t) && C && /* @__PURE__ */ o("button", {
263
+ type: "button",
261
264
  onClick: (e) => {
262
265
  e.stopPropagation(), C(t);
263
266
  },
@@ -278,6 +281,7 @@ var c = ({ files: c, folders: l, loading: de = !1, error: u = null, preserveSort
278
281
  })
279
282
  }),
280
283
  X(t) && E && /* @__PURE__ */ o("button", {
284
+ type: "button",
281
285
  onClick: (e) => {
282
286
  e.stopPropagation(), E(t);
283
287
  },
@@ -298,6 +302,7 @@ var c = ({ files: c, folders: l, loading: de = !1, error: u = null, preserveSort
298
302
  })
299
303
  }),
300
304
  Q(t) && w && /* @__PURE__ */ o("button", {
305
+ type: "button",
301
306
  onClick: (e) => {
302
307
  e.stopPropagation(), w(t);
303
308
  },