@tutti-os/workspace-file-manager 0.0.210 → 0.0.212
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-TNFCNCZV.js → chunk-KCYTFKPY.js} +82 -26
- package/dist/chunk-KCYTFKPY.js.map +1 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.js +104 -60
- package/dist/index.js.map +1 -1
- package/dist/services/index.js +1 -1
- package/package.json +4 -4
- package/dist/chunk-TNFCNCZV.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
splitWorkspaceFileName,
|
|
22
22
|
workspaceFileSearchEntryToEntry,
|
|
23
23
|
writeWorkspaceFileManagerArrangeMode
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-KCYTFKPY.js";
|
|
25
25
|
import {
|
|
26
26
|
createWorkspaceFileManagerI18nRuntime,
|
|
27
27
|
resolveRevealInFolderLabel,
|
|
@@ -59,6 +59,7 @@ import {
|
|
|
59
59
|
useRef,
|
|
60
60
|
useState
|
|
61
61
|
} from "react";
|
|
62
|
+
import { createPortal } from "react-dom";
|
|
62
63
|
|
|
63
64
|
// src/ui/contextMenuPlacement.ts
|
|
64
65
|
var CONTEXT_MENU_ITEM_HEIGHT_PX = 32;
|
|
@@ -155,52 +156,60 @@ function WorkspaceFileManagerContextMenu({
|
|
|
155
156
|
if (!contextMenu) {
|
|
156
157
|
return;
|
|
157
158
|
}
|
|
158
|
-
setPosition(
|
|
159
|
+
setPosition(
|
|
160
|
+
(current) => current.x === contextMenu.x && current.y === contextMenu.y ? current : { x: contextMenu.x, y: contextMenu.y }
|
|
161
|
+
);
|
|
159
162
|
}, [contextMenu?.x, contextMenu?.y]);
|
|
160
163
|
useLayoutEffect(() => {
|
|
161
164
|
if (!contextMenu) {
|
|
162
165
|
return;
|
|
163
166
|
}
|
|
164
|
-
const
|
|
165
|
-
if (!
|
|
167
|
+
const menu2 = contextMenuRef.current;
|
|
168
|
+
if (!menu2) {
|
|
166
169
|
return;
|
|
167
170
|
}
|
|
168
|
-
const menuRect =
|
|
169
|
-
const boundary = positionMode === "local" ?
|
|
171
|
+
const menuRect = menu2.getBoundingClientRect();
|
|
172
|
+
const boundary = positionMode === "local" ? menu2.closest(
|
|
170
173
|
"[data-workspace-file-menu-boundary], [data-workspace-file-manager]"
|
|
171
174
|
) : null;
|
|
172
175
|
if (positionMode === "local" && !boundary) {
|
|
173
176
|
return;
|
|
174
177
|
}
|
|
175
178
|
const boundaryRect = boundary?.getBoundingClientRect();
|
|
179
|
+
const next = clampContextMenuPosition({
|
|
180
|
+
boundaryHeight: boundaryRect?.height ?? window.innerHeight,
|
|
181
|
+
boundaryWidth: boundaryRect?.width ?? window.innerWidth,
|
|
182
|
+
menuHeight: menuRect.height,
|
|
183
|
+
menuWidth: menuRect.width,
|
|
184
|
+
x: contextMenu.x,
|
|
185
|
+
y: contextMenu.y
|
|
186
|
+
});
|
|
176
187
|
setPosition(
|
|
177
|
-
|
|
178
|
-
boundaryHeight: boundaryRect?.height ?? window.innerHeight,
|
|
179
|
-
boundaryWidth: boundaryRect?.width ?? window.innerWidth,
|
|
180
|
-
menuHeight: menuRect.height,
|
|
181
|
-
menuWidth: menuRect.width,
|
|
182
|
-
x: contextMenu.x,
|
|
183
|
-
y: contextMenu.y
|
|
184
|
-
})
|
|
188
|
+
(current) => current.x === next.x && current.y === next.y ? current : next
|
|
185
189
|
);
|
|
186
|
-
}, [contextMenu, contextMenuRef, items, positionMode]);
|
|
190
|
+
}, [contextMenu?.x, contextMenu?.y, contextMenuRef, items, positionMode]);
|
|
187
191
|
if (!contextMenu || items.length === 0) {
|
|
188
192
|
return null;
|
|
189
193
|
}
|
|
190
|
-
|
|
194
|
+
const menu = /* @__PURE__ */ jsx(
|
|
191
195
|
MenuSurface,
|
|
192
196
|
{
|
|
193
197
|
ref: contextMenuRef,
|
|
194
198
|
"data-workspace-file-manager-context-menu": "",
|
|
195
199
|
className: cn(
|
|
196
|
-
|
|
200
|
+
// `is-open` keeps host CSS that keys off the class (not only data-state)
|
|
201
|
+
// from leaving the surface at opacity:0.
|
|
202
|
+
"is-open w-[220px] overflow-visible p-1",
|
|
197
203
|
positionMode === "viewport" ? "fixed" : "absolute"
|
|
198
204
|
),
|
|
199
205
|
role: "menu",
|
|
200
206
|
style: {
|
|
201
207
|
left: `${position.x}px`,
|
|
202
208
|
top: `${position.y}px`,
|
|
203
|
-
|
|
209
|
+
// Prefer the host CSS var when present; fall back to a stable stacking
|
|
210
|
+
// value so an unset var cannot invalidate the entire z-index declaration.
|
|
211
|
+
// Viewport menus need to clear typical workbench chrome (≈ z-10..50).
|
|
212
|
+
zIndex: positionMode === "viewport" ? "var(--workspace-file-manager-dialog-overlay-z-index, 10050)" : "var(--workspace-file-manager-dialog-overlay-z-index, 20)"
|
|
204
213
|
},
|
|
205
214
|
onContextMenu: (event) => {
|
|
206
215
|
event.preventDefault();
|
|
@@ -208,6 +217,10 @@ function WorkspaceFileManagerContextMenu({
|
|
|
208
217
|
children: items.map((item) => /* @__PURE__ */ jsx(ContextMenuItemRenderer, { item, onClose }, item.id))
|
|
209
218
|
}
|
|
210
219
|
);
|
|
220
|
+
if (positionMode === "viewport" && typeof document !== "undefined") {
|
|
221
|
+
return createPortal(menu, document.body);
|
|
222
|
+
}
|
|
223
|
+
return menu;
|
|
211
224
|
}
|
|
212
225
|
function ContextMenuItemRenderer({
|
|
213
226
|
item,
|
|
@@ -791,9 +804,12 @@ function WorkspaceFileManagerContextMenuContainer({
|
|
|
791
804
|
const contextMenuRef = useRef2(null);
|
|
792
805
|
const { view } = useWorkspaceFileManagerContextMenuView(session);
|
|
793
806
|
const [items, setItems] = useState2([]);
|
|
807
|
+
const contextMenuX = view.contextMenu?.x;
|
|
808
|
+
const contextMenuY = view.contextMenu?.y;
|
|
809
|
+
const contextMenuEntryPath = view.contextMenu?.entry?.path ?? null;
|
|
794
810
|
useLayoutEffect2(() => {
|
|
795
|
-
if (
|
|
796
|
-
setItems([]);
|
|
811
|
+
if (contextMenuX === void 0 || contextMenuY === void 0) {
|
|
812
|
+
setItems((current) => current.length === 0 ? current : []);
|
|
797
813
|
return;
|
|
798
814
|
}
|
|
799
815
|
const request = buildContextMenuRequest({
|
|
@@ -802,23 +818,29 @@ function WorkspaceFileManagerContextMenuContainer({
|
|
|
802
818
|
});
|
|
803
819
|
const resolved = resolveContextMenu(request);
|
|
804
820
|
if (!isPromiseLike(resolved)) {
|
|
805
|
-
setItems(
|
|
821
|
+
setItems(
|
|
822
|
+
(current) => areContextMenuItemsEquivalent(current, resolved) ? current : resolved
|
|
823
|
+
);
|
|
806
824
|
return;
|
|
807
825
|
}
|
|
808
826
|
let cancelled = false;
|
|
809
|
-
setItems([]);
|
|
827
|
+
setItems((current) => current.length === 0 ? current : []);
|
|
810
828
|
void resolved.then((nextItems) => {
|
|
811
829
|
if (!cancelled) {
|
|
812
|
-
setItems(
|
|
830
|
+
setItems(
|
|
831
|
+
(current) => areContextMenuItemsEquivalent(current, nextItems) ? current : nextItems
|
|
832
|
+
);
|
|
813
833
|
}
|
|
814
834
|
});
|
|
815
835
|
return () => {
|
|
816
836
|
cancelled = true;
|
|
817
837
|
};
|
|
818
838
|
}, [
|
|
839
|
+
contextMenuEntryPath,
|
|
840
|
+
contextMenuX,
|
|
841
|
+
contextMenuY,
|
|
819
842
|
resolveContextMenu,
|
|
820
843
|
session,
|
|
821
|
-
view.contextMenu,
|
|
822
844
|
view.currentDirectoryPath,
|
|
823
845
|
view.isBusy,
|
|
824
846
|
view.isLoading,
|
|
@@ -838,6 +860,7 @@ function WorkspaceFileManagerContextMenuContainer({
|
|
|
838
860
|
contextMenu: { x: view.contextMenu.x, y: view.contextMenu.y },
|
|
839
861
|
contextMenuRef,
|
|
840
862
|
items,
|
|
863
|
+
positionMode: "viewport",
|
|
841
864
|
onClose: () => {
|
|
842
865
|
session.closeContextMenu();
|
|
843
866
|
}
|
|
@@ -866,6 +889,35 @@ function buildContextMenuRequest(input) {
|
|
|
866
889
|
function isPromiseLike(value) {
|
|
867
890
|
return typeof value === "object" && value !== null && "then" in value && typeof value.then === "function";
|
|
868
891
|
}
|
|
892
|
+
function areContextMenuItemsEquivalent(left, right) {
|
|
893
|
+
if (left === right) {
|
|
894
|
+
return true;
|
|
895
|
+
}
|
|
896
|
+
if (left.length !== right.length) {
|
|
897
|
+
return false;
|
|
898
|
+
}
|
|
899
|
+
for (let index = 0; index < left.length; index += 1) {
|
|
900
|
+
const leftItem = left[index];
|
|
901
|
+
const rightItem = right[index];
|
|
902
|
+
if (!leftItem || !rightItem || leftItem.id !== rightItem.id) {
|
|
903
|
+
return false;
|
|
904
|
+
}
|
|
905
|
+
if (leftItem.type !== rightItem.type) {
|
|
906
|
+
return false;
|
|
907
|
+
}
|
|
908
|
+
if (leftItem.type === "item" && rightItem.type === "item") {
|
|
909
|
+
if (leftItem.label !== rightItem.label || leftItem.disabled !== rightItem.disabled || leftItem.danger !== rightItem.danger) {
|
|
910
|
+
return false;
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
if (leftItem.type === "submenu" && rightItem.type === "submenu") {
|
|
914
|
+
if (leftItem.label !== rightItem.label || leftItem.disabled !== rightItem.disabled || leftItem.loading !== rightItem.loading) {
|
|
915
|
+
return false;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
return true;
|
|
920
|
+
}
|
|
869
921
|
function useCloseContextMenuOnOutsideInteraction(input) {
|
|
870
922
|
const { contextMenuRef, isOpen, session } = input;
|
|
871
923
|
useEffect2(() => {
|
|
@@ -3839,6 +3891,7 @@ function WorkspaceFileManager({
|
|
|
3839
3891
|
resolveEntryIconUrl,
|
|
3840
3892
|
renderExternalLocationContent,
|
|
3841
3893
|
session,
|
|
3894
|
+
showLocationSidebar = true,
|
|
3842
3895
|
showPreviewPanel = true,
|
|
3843
3896
|
surface = "card"
|
|
3844
3897
|
}) {
|
|
@@ -3859,9 +3912,7 @@ function WorkspaceFileManager({
|
|
|
3859
3912
|
);
|
|
3860
3913
|
return location?.kind === "external" ? location : null;
|
|
3861
3914
|
}, [rootView.locationSections, rootView.selectedLocationId]);
|
|
3862
|
-
const hasLocationSidebar = rootView.locationSections.some(
|
|
3863
|
-
(section) => section.locations.length > 0
|
|
3864
|
-
);
|
|
3915
|
+
const hasLocationSidebar = showLocationSidebar && rootView.locationSections.some((section) => section.locations.length > 0);
|
|
3865
3916
|
const sidebarContentMinWidth = showPreviewPanel ? workspaceFileManagerContentMinWidth : workspaceFileManagerContentWithoutPreviewMinWidth;
|
|
3866
3917
|
const sidebarMaxWidth = containerWidth > 0 ? resolveWorkspaceFileManagerSidebarMaxWidth(
|
|
3867
3918
|
containerWidth,
|
|
@@ -4059,20 +4110,16 @@ function WorkspaceFileManager({
|
|
|
4059
4110
|
function openContextMenu(event, entry) {
|
|
4060
4111
|
event.preventDefault();
|
|
4061
4112
|
event.stopPropagation();
|
|
4062
|
-
const rootBounds = rootRef.current?.getBoundingClientRect();
|
|
4063
|
-
if (!rootBounds) {
|
|
4064
|
-
return;
|
|
4065
|
-
}
|
|
4066
4113
|
const menuWidth = 220;
|
|
4067
4114
|
const menuHeight = 280;
|
|
4068
4115
|
const x = clampContextMenuCoordinate(
|
|
4069
|
-
event.clientX
|
|
4070
|
-
|
|
4116
|
+
event.clientX,
|
|
4117
|
+
window.innerWidth,
|
|
4071
4118
|
menuWidth
|
|
4072
4119
|
);
|
|
4073
4120
|
const y = clampContextMenuCoordinate(
|
|
4074
|
-
event.clientY
|
|
4075
|
-
|
|
4121
|
+
event.clientY,
|
|
4122
|
+
window.innerHeight,
|
|
4076
4123
|
menuHeight
|
|
4077
4124
|
);
|
|
4078
4125
|
session.openContextMenu({
|
|
@@ -4092,8 +4139,14 @@ function WorkspaceFileManager({
|
|
|
4092
4139
|
"data-slot": "viewport-menu-boundary",
|
|
4093
4140
|
"data-workspace-file-manager": "",
|
|
4094
4141
|
ref: rootRef,
|
|
4142
|
+
style: {
|
|
4143
|
+
// Owned by the root so context menus (siblings of the panels pane)
|
|
4144
|
+
// can resolve overlay stacking instead of falling back to invalid
|
|
4145
|
+
// `calc(var(--undefined) - 1)`.
|
|
4146
|
+
"--workspace-file-manager-dialog-overlay-z-index": "20"
|
|
4147
|
+
},
|
|
4095
4148
|
children: [
|
|
4096
|
-
/* @__PURE__ */ jsx9(
|
|
4149
|
+
hasLocationSidebar ? /* @__PURE__ */ jsx9(
|
|
4097
4150
|
WorkspaceFileManagerSidebar,
|
|
4098
4151
|
{
|
|
4099
4152
|
disabled: rootView.isBusy || panelsState.isLoading,
|
|
@@ -4107,7 +4160,7 @@ function WorkspaceFileManager({
|
|
|
4107
4160
|
void session.selectLocation(location.id);
|
|
4108
4161
|
}
|
|
4109
4162
|
}
|
|
4110
|
-
),
|
|
4163
|
+
) : null,
|
|
4111
4164
|
hasLocationSidebar ? /* @__PURE__ */ jsx9(
|
|
4112
4165
|
"div",
|
|
4113
4166
|
{
|
|
@@ -4139,31 +4192,22 @@ function WorkspaceFileManager({
|
|
|
4139
4192
|
session
|
|
4140
4193
|
}
|
|
4141
4194
|
),
|
|
4142
|
-
/* @__PURE__ */ jsx9(
|
|
4143
|
-
|
|
4195
|
+
/* @__PURE__ */ jsx9("div", { className: "@max-[600px]/workspace-file-manager:flex-col @max-[600px]/workspace-file-manager:gap-3 flex min-h-0 min-w-0 flex-1 overflow-hidden", children: /* @__PURE__ */ jsx9(
|
|
4196
|
+
WorkspaceFileManagerPanelsContainer,
|
|
4144
4197
|
{
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
layoutMode,
|
|
4157
|
-
onDirectoryExpanded,
|
|
4158
|
-
onEntryDragStart,
|
|
4159
|
-
onOpenContextMenu: openContextMenu,
|
|
4160
|
-
resolveEntryIconUrl,
|
|
4161
|
-
session,
|
|
4162
|
-
showPreviewPanel
|
|
4163
|
-
}
|
|
4164
|
-
)
|
|
4198
|
+
dateLocale,
|
|
4199
|
+
entryDragMode,
|
|
4200
|
+
arrangeMode,
|
|
4201
|
+
i18n,
|
|
4202
|
+
layoutMode,
|
|
4203
|
+
onDirectoryExpanded,
|
|
4204
|
+
onEntryDragStart,
|
|
4205
|
+
onOpenContextMenu: openContextMenu,
|
|
4206
|
+
resolveEntryIconUrl,
|
|
4207
|
+
session,
|
|
4208
|
+
showPreviewPanel
|
|
4165
4209
|
}
|
|
4166
|
-
)
|
|
4210
|
+
) })
|
|
4167
4211
|
] }) }),
|
|
4168
4212
|
!selectedExternalLocation ? /* @__PURE__ */ jsxs8(Fragment3, { children: [
|
|
4169
4213
|
/* @__PURE__ */ jsx9(WorkspaceFileManagerDialogsContainer, { i18n, session }),
|