@tutti-os/workspace-file-reference 0.0.32 → 0.0.34
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-BEBHG64Q.js → chunk-SXYVXNMS.js} +24 -3
- package/dist/chunk-SXYVXNMS.js.map +1 -0
- package/dist/react/index.d.ts +3 -1
- package/dist/react/index.js +1 -1
- package/dist/ui/index.js +144 -42
- package/dist/ui/index.js.map +1 -1
- package/package.json +5 -5
- package/dist/chunk-BEBHG64Q.js.map +0 -1
package/dist/ui/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
createReferenceSourcePickerController,
|
|
4
4
|
normalizeDirectoryPath,
|
|
5
5
|
useWorkspaceFileReferencePickerView
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-SXYVXNMS.js";
|
|
7
7
|
import {
|
|
8
8
|
REFERENCE_FILTER_CATEGORIES,
|
|
9
9
|
WORKSPACE_ROOT_GROUP_NODE_ID,
|
|
@@ -935,13 +935,21 @@ function useReferenceSourcePickerView({
|
|
|
935
935
|
},
|
|
936
936
|
[controller]
|
|
937
937
|
);
|
|
938
|
+
const shouldRefreshChildrenOnEnter = useCallback(
|
|
939
|
+
(sourceId) => snapshot.tabs.find((tab) => tab.sourceId === sourceId)?.capabilities.navigable ?? false,
|
|
940
|
+
[snapshot.tabs]
|
|
941
|
+
);
|
|
938
942
|
const enterFolder = useCallback(
|
|
939
943
|
(node) => {
|
|
940
944
|
const sourceId = node.ref.sourceId;
|
|
941
945
|
if (node.kind !== "folder" || !sourceId || node.ref.nodeId === WORKSPACE_ROOT_GROUP_NODE_ID) {
|
|
942
946
|
return;
|
|
943
947
|
}
|
|
944
|
-
|
|
948
|
+
if (shouldRefreshChildrenOnEnter(sourceId)) {
|
|
949
|
+
controller.refreshChildren(node);
|
|
950
|
+
} else {
|
|
951
|
+
controller.ensureChildren(node);
|
|
952
|
+
}
|
|
945
953
|
setBreadcrumbBySource((current) => {
|
|
946
954
|
const stack = current[sourceId] ?? [];
|
|
947
955
|
const index = stack.findIndex(
|
|
@@ -952,7 +960,7 @@ function useReferenceSourcePickerView({
|
|
|
952
960
|
});
|
|
953
961
|
setFocusedNode(null);
|
|
954
962
|
},
|
|
955
|
-
[controller]
|
|
963
|
+
[controller, shouldRefreshChildrenOnEnter]
|
|
956
964
|
);
|
|
957
965
|
useEffect2(() => {
|
|
958
966
|
if (!open || !activeSourceId) {
|
|
@@ -991,10 +999,19 @@ function useReferenceSourcePickerView({
|
|
|
991
999
|
return { ...current, [activeSourceId]: stack.slice(0, index + 1) };
|
|
992
1000
|
});
|
|
993
1001
|
const target = (breadcrumbBySource[activeSourceId] ?? [])[index] ?? null;
|
|
994
|
-
|
|
1002
|
+
if (target && shouldRefreshChildrenOnEnter(target.ref.sourceId)) {
|
|
1003
|
+
controller.refreshChildren(target);
|
|
1004
|
+
} else {
|
|
1005
|
+
controller.ensureChildren(target);
|
|
1006
|
+
}
|
|
995
1007
|
setFocusedNode(null);
|
|
996
1008
|
},
|
|
997
|
-
[
|
|
1009
|
+
[
|
|
1010
|
+
activeSourceId,
|
|
1011
|
+
breadcrumbBySource,
|
|
1012
|
+
controller,
|
|
1013
|
+
shouldRefreshChildrenOnEnter
|
|
1014
|
+
]
|
|
998
1015
|
);
|
|
999
1016
|
const navigateToRoot = useCallback(
|
|
1000
1017
|
(sourceId) => {
|
|
@@ -1014,18 +1031,30 @@ function useReferenceSourcePickerView({
|
|
|
1014
1031
|
if (!sourceId) {
|
|
1015
1032
|
return;
|
|
1016
1033
|
}
|
|
1034
|
+
const nextScopeNodeId = node.ref.nodeId === WORKSPACE_ROOT_GROUP_NODE_ID ? null : node.ref.nodeId;
|
|
1017
1035
|
if (sourceId !== snapshot.activeSourceId) {
|
|
1018
|
-
controller.setActiveSource(sourceId);
|
|
1036
|
+
controller.setActiveSource(sourceId, nextScopeNodeId);
|
|
1019
1037
|
}
|
|
1020
1038
|
if (node.ref.nodeId === WORKSPACE_ROOT_GROUP_NODE_ID) {
|
|
1039
|
+
controller.setSearchScope(null);
|
|
1021
1040
|
navigateToRoot(sourceId);
|
|
1022
1041
|
return;
|
|
1023
1042
|
}
|
|
1024
|
-
|
|
1043
|
+
if (shouldRefreshChildrenOnEnter(sourceId)) {
|
|
1044
|
+
controller.refreshChildren(node);
|
|
1045
|
+
} else {
|
|
1046
|
+
controller.ensureChildren(node);
|
|
1047
|
+
}
|
|
1048
|
+
controller.setSearchScope(nextScopeNodeId);
|
|
1025
1049
|
setBreadcrumbBySource((current) => ({ ...current, [sourceId]: [node] }));
|
|
1026
1050
|
setFocusedNode(null);
|
|
1027
1051
|
},
|
|
1028
|
-
[
|
|
1052
|
+
[
|
|
1053
|
+
controller,
|
|
1054
|
+
snapshot.activeSourceId,
|
|
1055
|
+
navigateToRoot,
|
|
1056
|
+
shouldRefreshChildrenOnEnter
|
|
1057
|
+
]
|
|
1029
1058
|
);
|
|
1030
1059
|
const isSelected = useCallback(
|
|
1031
1060
|
(node) => (isNodeSelectable?.(node) ?? true) && snapshot.selection.some(
|
|
@@ -1123,6 +1152,8 @@ function useReferenceSourcePickerView({
|
|
|
1123
1152
|
setPreviewState({ node, status: "unsupported" });
|
|
1124
1153
|
return;
|
|
1125
1154
|
}
|
|
1155
|
+
const previewSizeBytes = preview.bytes.byteLength;
|
|
1156
|
+
const loadedSizeBytes = node.sizeBytes != null && node.sizeBytes > 0 ? node.sizeBytes : previewSizeBytes;
|
|
1126
1157
|
const loaded = createWorkspaceFilePreviewLoadedState({
|
|
1127
1158
|
bytes: preview.bytes,
|
|
1128
1159
|
contentType: preview.contentType,
|
|
@@ -1131,7 +1162,7 @@ function useReferenceSourcePickerView({
|
|
|
1131
1162
|
name: node.displayName,
|
|
1132
1163
|
path: node.ref.nodeId,
|
|
1133
1164
|
mtimeMs: node.mtimeMs ?? null,
|
|
1134
|
-
sizeBytes:
|
|
1165
|
+
sizeBytes: loadedSizeBytes
|
|
1135
1166
|
},
|
|
1136
1167
|
renderHtml: true,
|
|
1137
1168
|
target: {
|
|
@@ -1139,7 +1170,7 @@ function useReferenceSourcePickerView({
|
|
|
1139
1170
|
name: node.displayName,
|
|
1140
1171
|
path: node.ref.nodeId,
|
|
1141
1172
|
mtimeMs: node.mtimeMs ?? null,
|
|
1142
|
-
sizeBytes:
|
|
1173
|
+
sizeBytes: loadedSizeBytes
|
|
1143
1174
|
}
|
|
1144
1175
|
});
|
|
1145
1176
|
if (cancelled) {
|
|
@@ -1150,7 +1181,12 @@ function useReferenceSourcePickerView({
|
|
|
1150
1181
|
new Blob([loaded.bytes], { type: loaded.contentType })
|
|
1151
1182
|
);
|
|
1152
1183
|
previewObjectUrlRef.current = objectUrl;
|
|
1153
|
-
setPreviewState({
|
|
1184
|
+
setPreviewState({
|
|
1185
|
+
node,
|
|
1186
|
+
objectUrl,
|
|
1187
|
+
previewSizeBytes,
|
|
1188
|
+
status: "image"
|
|
1189
|
+
});
|
|
1154
1190
|
return;
|
|
1155
1191
|
}
|
|
1156
1192
|
if (loaded.status === "video") {
|
|
@@ -1158,19 +1194,35 @@ function useReferenceSourcePickerView({
|
|
|
1158
1194
|
new Blob([loaded.bytes], { type: loaded.contentType })
|
|
1159
1195
|
);
|
|
1160
1196
|
previewObjectUrlRef.current = objectUrl;
|
|
1161
|
-
setPreviewState({
|
|
1197
|
+
setPreviewState({
|
|
1198
|
+
node,
|
|
1199
|
+
objectUrl,
|
|
1200
|
+
previewSizeBytes,
|
|
1201
|
+
status: "video"
|
|
1202
|
+
});
|
|
1162
1203
|
return;
|
|
1163
1204
|
}
|
|
1164
1205
|
if (loaded.status === "text") {
|
|
1165
|
-
setPreviewState({
|
|
1206
|
+
setPreviewState({
|
|
1207
|
+
content: loaded.content,
|
|
1208
|
+
node,
|
|
1209
|
+
previewSizeBytes,
|
|
1210
|
+
status: "text"
|
|
1211
|
+
});
|
|
1166
1212
|
return;
|
|
1167
1213
|
}
|
|
1168
1214
|
if (loaded.status === "html") {
|
|
1169
|
-
setPreviewState({
|
|
1215
|
+
setPreviewState({
|
|
1216
|
+
content: loaded.content,
|
|
1217
|
+
node,
|
|
1218
|
+
previewSizeBytes,
|
|
1219
|
+
status: "html"
|
|
1220
|
+
});
|
|
1170
1221
|
return;
|
|
1171
1222
|
}
|
|
1172
1223
|
setPreviewState({
|
|
1173
1224
|
node,
|
|
1225
|
+
previewSizeBytes,
|
|
1174
1226
|
reason: loaded.reason,
|
|
1175
1227
|
...loaded.maxSizeBytes == null ? {} : { maxSizeBytes: loaded.maxSizeBytes },
|
|
1176
1228
|
status: "readonly"
|
|
@@ -1259,6 +1311,22 @@ function useReferenceSourcePickerView({
|
|
|
1259
1311
|
}
|
|
1260
1312
|
|
|
1261
1313
|
// src/ui/internal/reference/referenceSourcePickerPresentation.ts
|
|
1314
|
+
function formatHierarchyTitle(hierarchy) {
|
|
1315
|
+
if (hierarchy.length === 0) {
|
|
1316
|
+
return null;
|
|
1317
|
+
}
|
|
1318
|
+
return hierarchy.map((crumb) => crumb.displayName).join(" / ");
|
|
1319
|
+
}
|
|
1320
|
+
function formatReferenceNodePathText(node, hierarchy = []) {
|
|
1321
|
+
const decodedPath = decodeReferenceListFileNodeId(node.ref.nodeId);
|
|
1322
|
+
if (decodedPath) {
|
|
1323
|
+
return decodedPath;
|
|
1324
|
+
}
|
|
1325
|
+
if (node.kind === "folder" && node.ref.nodeId.startsWith("g:")) {
|
|
1326
|
+
return formatHierarchyTitle(completeHierarchy(hierarchy, node)) || node.displayName;
|
|
1327
|
+
}
|
|
1328
|
+
return node.contextLabel?.trim() || node.ref.nodeId;
|
|
1329
|
+
}
|
|
1262
1330
|
function formatReferencePreviewDateTime(ms, options = {}) {
|
|
1263
1331
|
const timeZone = options.timeZone ?? Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
1264
1332
|
const formatter = new Intl.DateTimeFormat(options.locale, {
|
|
@@ -1275,6 +1343,46 @@ function formatReferencePreviewDateTime(ms, options = {}) {
|
|
|
1275
1343
|
);
|
|
1276
1344
|
return `${parts.year}-${parts.month}-${parts.day} ${parts.hour}:${parts.minute}`;
|
|
1277
1345
|
}
|
|
1346
|
+
function resolveReferencePreviewSizeBytes(node, previewState) {
|
|
1347
|
+
const metadataSize = normalizedSizeBytes(node.sizeBytes);
|
|
1348
|
+
if (metadataSize != null && metadataSize > 0) {
|
|
1349
|
+
return metadataSize;
|
|
1350
|
+
}
|
|
1351
|
+
if (previewState.node && previewState.node.ref.sourceId === node.ref.sourceId && previewState.node.ref.nodeId === node.ref.nodeId) {
|
|
1352
|
+
const previewSize = normalizedSizeBytes(previewState.previewSizeBytes);
|
|
1353
|
+
if (previewSize != null && previewSize > 0) {
|
|
1354
|
+
return previewSize;
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
return metadataSize;
|
|
1358
|
+
}
|
|
1359
|
+
function completeHierarchy(hierarchy, node) {
|
|
1360
|
+
const last = hierarchy.at(-1);
|
|
1361
|
+
if (last && last.ref.sourceId === node.ref.sourceId && last.ref.nodeId === node.ref.nodeId) {
|
|
1362
|
+
return [...hierarchy];
|
|
1363
|
+
}
|
|
1364
|
+
return [...hierarchy, node];
|
|
1365
|
+
}
|
|
1366
|
+
function decodeReferenceListFileNodeId(nodeId) {
|
|
1367
|
+
if (!nodeId.startsWith("f:")) {
|
|
1368
|
+
return null;
|
|
1369
|
+
}
|
|
1370
|
+
try {
|
|
1371
|
+
const normalized = nodeId.slice(2).replace(/-/g, "+").replace(/_/g, "/");
|
|
1372
|
+
const padded = normalized.padEnd(
|
|
1373
|
+
normalized.length + (4 - normalized.length % 4) % 4,
|
|
1374
|
+
"="
|
|
1375
|
+
);
|
|
1376
|
+
const binary = atob(padded);
|
|
1377
|
+
const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
|
|
1378
|
+
return new TextDecoder().decode(bytes);
|
|
1379
|
+
} catch {
|
|
1380
|
+
return null;
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
function normalizedSizeBytes(sizeBytes) {
|
|
1384
|
+
return typeof sizeBytes === "number" && Number.isFinite(sizeBytes) && sizeBytes >= 0 ? sizeBytes : null;
|
|
1385
|
+
}
|
|
1278
1386
|
|
|
1279
1387
|
// src/ui/internal/reference/ReferenceSourcePicker.tsx
|
|
1280
1388
|
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
@@ -1503,7 +1611,9 @@ function ReferenceSourcePicker({
|
|
|
1503
1611
|
},
|
|
1504
1612
|
nodeRefKey(node.ref)
|
|
1505
1613
|
))
|
|
1506
|
-
) :
|
|
1614
|
+
) : view.currentEntries.length === 0 ? /* @__PURE__ */ jsx4(Feedback, { children: copy.t(
|
|
1615
|
+
hasSelectedGroup ? "referencePicker.emptyDirectory" : "referencePicker.selectGroupHint"
|
|
1616
|
+
) }) : (
|
|
1507
1617
|
// 浏览:就地递归展开树(复刻 agent 引用面板文件树交互)
|
|
1508
1618
|
view.currentEntries.map((node) => /* @__PURE__ */ jsx4(
|
|
1509
1619
|
TreeNodeRow,
|
|
@@ -1559,6 +1669,7 @@ function ReferenceSourcePicker({
|
|
|
1559
1669
|
PreviewInfoPane,
|
|
1560
1670
|
{
|
|
1561
1671
|
copy,
|
|
1672
|
+
hierarchy: view.breadcrumb,
|
|
1562
1673
|
node: view.focusedNode,
|
|
1563
1674
|
previewState: view.previewState,
|
|
1564
1675
|
sourceLabel: view.activeTabLabel
|
|
@@ -1853,10 +1964,12 @@ function FullTextTooltip({
|
|
|
1853
1964
|
}
|
|
1854
1965
|
function PreviewInfoPane({
|
|
1855
1966
|
copy,
|
|
1967
|
+
hierarchy,
|
|
1856
1968
|
node,
|
|
1857
1969
|
previewState,
|
|
1858
1970
|
sourceLabel
|
|
1859
1971
|
}) {
|
|
1972
|
+
const sizeBytes = node ? resolveReferencePreviewSizeBytes(node, previewState) : null;
|
|
1860
1973
|
return /* @__PURE__ */ jsx4("aside", { className: "flex h-full min-h-0 w-full flex-col bg-[var(--background-fronted)]", children: node ? /* @__PURE__ */ jsxs4("div", { className: "flex min-h-0 flex-1 flex-col gap-4 p-4", children: [
|
|
1861
1974
|
/* @__PURE__ */ jsx4(
|
|
1862
1975
|
WorkspaceFilePreviewSurface,
|
|
@@ -1879,7 +1992,7 @@ function PreviewInfoPane({
|
|
|
1879
1992
|
),
|
|
1880
1993
|
/* @__PURE__ */ jsxs4("div", { className: "space-y-1", children: [
|
|
1881
1994
|
/* @__PURE__ */ jsx4("p", { className: "truncate text-[15px] font-semibold", children: node.displayName }),
|
|
1882
|
-
/* @__PURE__ */ jsx4(ReferencePathText, { node })
|
|
1995
|
+
/* @__PURE__ */ jsx4(ReferencePathText, { hierarchy, node })
|
|
1883
1996
|
] }),
|
|
1884
1997
|
/* @__PURE__ */ jsxs4("dl", { className: "space-y-2 text-[13px]", children: [
|
|
1885
1998
|
/* @__PURE__ */ jsx4(InfoRow, { label: copy.t("referencePicker.previewSource"), children: /* @__PURE__ */ jsx4(
|
|
@@ -1891,12 +2004,15 @@ function PreviewInfoPane({
|
|
|
1891
2004
|
}
|
|
1892
2005
|
) }),
|
|
1893
2006
|
node.mtimeMs != null ? /* @__PURE__ */ jsx4(InfoRow, { label: copy.t("referencePicker.previewModified"), children: formatReferencePreviewDateTime(node.mtimeMs) }) : null,
|
|
1894
|
-
|
|
2007
|
+
sizeBytes != null ? /* @__PURE__ */ jsx4(InfoRow, { label: copy.t("referencePicker.previewSize"), children: formatBytes(sizeBytes) }) : null
|
|
1895
2008
|
] })
|
|
1896
2009
|
] }) : /* @__PURE__ */ jsx4(Feedback, { children: copy.t("referencePicker.emptyPreview") }) });
|
|
1897
2010
|
}
|
|
1898
|
-
function ReferencePathText({
|
|
1899
|
-
|
|
2011
|
+
function ReferencePathText({
|
|
2012
|
+
hierarchy,
|
|
2013
|
+
node
|
|
2014
|
+
}) {
|
|
2015
|
+
const pathText = getReferenceNodePathText(node, hierarchy);
|
|
1900
2016
|
const lastSlashIndex = pathText.lastIndexOf("/");
|
|
1901
2017
|
if (lastSlashIndex <= 0 || lastSlashIndex === pathText.length - 1) {
|
|
1902
2018
|
return /* @__PURE__ */ jsx4(
|
|
@@ -1920,29 +2036,8 @@ function ReferencePathText({ node }) {
|
|
|
1920
2036
|
}
|
|
1921
2037
|
);
|
|
1922
2038
|
}
|
|
1923
|
-
function getReferenceNodePathText(node) {
|
|
1924
|
-
|
|
1925
|
-
if (decodedPath) {
|
|
1926
|
-
return decodedPath;
|
|
1927
|
-
}
|
|
1928
|
-
return node.contextLabel?.trim() || node.ref.nodeId;
|
|
1929
|
-
}
|
|
1930
|
-
function decodeReferenceListFileNodeId(nodeId) {
|
|
1931
|
-
if (!nodeId.startsWith("f:")) {
|
|
1932
|
-
return null;
|
|
1933
|
-
}
|
|
1934
|
-
try {
|
|
1935
|
-
const normalized = nodeId.slice(2).replace(/-/g, "+").replace(/_/g, "/");
|
|
1936
|
-
const padded = normalized.padEnd(
|
|
1937
|
-
normalized.length + (4 - normalized.length % 4) % 4,
|
|
1938
|
-
"="
|
|
1939
|
-
);
|
|
1940
|
-
const binary = atob(padded);
|
|
1941
|
-
const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
|
|
1942
|
-
return new TextDecoder().decode(bytes);
|
|
1943
|
-
} catch {
|
|
1944
|
-
return null;
|
|
1945
|
-
}
|
|
2039
|
+
function getReferenceNodePathText(node, hierarchy) {
|
|
2040
|
+
return formatReferenceNodePathText(node, hierarchy);
|
|
1946
2041
|
}
|
|
1947
2042
|
function InfoRow({
|
|
1948
2043
|
label,
|
|
@@ -2171,7 +2266,13 @@ function TreeNodeRow({
|
|
|
2171
2266
|
const selectable = view.isSelectable(node);
|
|
2172
2267
|
const focused = isFocused(view.focusedNode, node);
|
|
2173
2268
|
const active = selected || focused && selectable;
|
|
2269
|
+
const focusedRowRef = useRef2(null);
|
|
2174
2270
|
const [shouldRenderChildContent, setShouldRenderChildContent] = useState4(expanded);
|
|
2271
|
+
useEffect3(() => {
|
|
2272
|
+
if (focused) {
|
|
2273
|
+
focusedRowRef.current?.scrollIntoView({ block: "nearest" });
|
|
2274
|
+
}
|
|
2275
|
+
}, [focused]);
|
|
2175
2276
|
useEffect3(() => {
|
|
2176
2277
|
if (expanded) {
|
|
2177
2278
|
setShouldRenderChildContent(true);
|
|
@@ -2214,6 +2315,7 @@ function TreeNodeRow({
|
|
|
2214
2315
|
/* @__PURE__ */ jsxs4(
|
|
2215
2316
|
"div",
|
|
2216
2317
|
{
|
|
2318
|
+
ref: focused ? focusedRowRef : void 0,
|
|
2217
2319
|
className: cn3(
|
|
2218
2320
|
"flex cursor-pointer items-center gap-2 rounded-[6px] py-1.5 pr-1 transition-colors",
|
|
2219
2321
|
active ? "bg-transparency-block" : "hover:bg-transparency-block"
|