@tutti-os/workspace-file-reference 0.0.14 → 0.0.16

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.
@@ -4,7 +4,7 @@ import {
4
4
  nodeRefKey,
5
5
  sortReferenceNodes,
6
6
  uniqueWorkspaceFileReferences
7
- } from "./chunk-7C3RZYQE.js";
7
+ } from "./chunk-JURSITRX.js";
8
8
 
9
9
  // src/react/internal/reference/WorkspaceFileReferencePickerState.ts
10
10
  var workspaceFileReferenceDefaultExpandedDepth = 4;
@@ -162,7 +162,15 @@ var defaultDirectoryPath = "/";
162
162
  var defaultSearchDebounceMs = 180;
163
163
  function createWorkspaceFileReferencePickerController(input) {
164
164
  const searchDebounceMs = input.searchDebounceMs ?? defaultSearchDebounceMs;
165
- let browseSequence = 0;
165
+ let nextBrowseSeq = 0;
166
+ const latestBrowseSeqByKey = /* @__PURE__ */ new Map();
167
+ const stampBrowse = (seqKey) => {
168
+ const sequence = ++nextBrowseSeq;
169
+ latestBrowseSeqByKey.set(seqKey, sequence);
170
+ return sequence;
171
+ };
172
+ const isBrowseStale = (seqKey, sequence) => !retained || latestBrowseSeqByKey.get(seqKey) !== sequence;
173
+ const REVEAL_SEQ_KEY = "\0reveal";
166
174
  let previewObjectUrl = null;
167
175
  let previewSequence = 0;
168
176
  let retained = false;
@@ -223,7 +231,7 @@ function createWorkspaceFileReferencePickerController(input) {
223
231
  searchAbortController = null;
224
232
  };
225
233
  const cancelCurrentBrowse = () => {
226
- browseSequence += 1;
234
+ latestBrowseSeqByKey.clear();
227
235
  };
228
236
  const cancelCurrentPreview = () => {
229
237
  previewSequence += 1;
@@ -310,7 +318,8 @@ function createWorkspaceFileReferencePickerController(input) {
310
318
  if (normalizedRoot && snapshot.directoryStateByPath[normalizedRoot]?.loaded) {
311
319
  return;
312
320
  }
313
- const sequence = ++browseSequence;
321
+ const seqKey = normalizedRoot ?? "";
322
+ const sequence = stampBrowse(seqKey);
314
323
  setSnapshot({
315
324
  browseError: null,
316
325
  isBrowseLoading: true
@@ -323,7 +332,7 @@ function createWorkspaceFileReferencePickerController(input) {
323
332
  prefetchDepth: 4,
324
333
  workspaceId: input.workspaceId
325
334
  });
326
- if (!retained || sequence !== browseSequence) {
335
+ if (isBrowseStale(seqKey, sequence)) {
327
336
  return;
328
337
  }
329
338
  setSnapshot({
@@ -338,7 +347,7 @@ function createWorkspaceFileReferencePickerController(input) {
338
347
  return;
339
348
  }
340
349
  const listing = await loadDirectoryListing(activeBrowseRootPath);
341
- if (!retained || sequence !== browseSequence || !listing) {
350
+ if (isBrowseStale(seqKey, sequence) || !listing) {
342
351
  return;
343
352
  }
344
353
  setSnapshot((current) => ({
@@ -356,7 +365,7 @@ function createWorkspaceFileReferencePickerController(input) {
356
365
  isBrowseLoading: false
357
366
  }));
358
367
  } catch (error) {
359
- if (!retained || sequence !== browseSequence) {
368
+ if (isBrowseStale(seqKey, sequence)) {
360
369
  return;
361
370
  }
362
371
  setSnapshot({
@@ -373,7 +382,7 @@ function createWorkspaceFileReferencePickerController(input) {
373
382
  if (!retained || snapshot.directoryStateByPath[folderKey]?.loaded || snapshot.directoryStateByPath[folderKey]?.loading) {
374
383
  return;
375
384
  }
376
- const sequence = ++browseSequence;
385
+ const sequence = stampBrowse(folderKey);
377
386
  setSnapshot((current) => ({
378
387
  ...current,
379
388
  directoryStateByPath: {
@@ -388,7 +397,7 @@ function createWorkspaceFileReferencePickerController(input) {
388
397
  }));
389
398
  try {
390
399
  const listing = await loadDirectoryListing(folderKey);
391
- if (!retained || sequence !== browseSequence || !listing) {
400
+ if (isBrowseStale(folderKey, sequence) || !listing) {
392
401
  return;
393
402
  }
394
403
  setSnapshot((current) => ({
@@ -404,7 +413,7 @@ function createWorkspaceFileReferencePickerController(input) {
404
413
  }
405
414
  }));
406
415
  } catch {
407
- if (!retained || sequence !== browseSequence) {
416
+ if (isBrowseStale(folderKey, sequence)) {
408
417
  return;
409
418
  }
410
419
  setSnapshot((current) => ({
@@ -438,12 +447,12 @@ function createWorkspaceFileReferencePickerController(input) {
438
447
  }
439
448
  const nextState = createReferencePreviewState(reference, target, preview);
440
449
  if (!retained || sequence !== previewSequence) {
441
- if (nextState.status === "image") {
450
+ if (nextState.status === "image" || nextState.status === "video") {
442
451
  URL.revokeObjectURL(nextState.objectUrl);
443
452
  }
444
453
  return;
445
454
  }
446
- if (nextState.status === "image") {
455
+ if (nextState.status === "image" || nextState.status === "video") {
447
456
  previewObjectUrl = nextState.objectUrl;
448
457
  }
449
458
  setSnapshot({
@@ -542,7 +551,7 @@ function createWorkspaceFileReferencePickerController(input) {
542
551
  });
543
552
  return null;
544
553
  }
545
- const sequence = ++browseSequence;
554
+ const sequence = stampBrowse(REVEAL_SEQ_KEY);
546
555
  const loadedDirectories = {};
547
556
  const expandedDirectories = {};
548
557
  const directoryState = (path) => loadedDirectories[path] ?? snapshot.directoryStateByPath[path];
@@ -573,7 +582,7 @@ function createWorkspaceFileReferencePickerController(input) {
573
582
  loading: false
574
583
  };
575
584
  }
576
- if (!retained || sequence !== browseSequence) {
585
+ if (isBrowseStale(REVEAL_SEQ_KEY, sequence)) {
577
586
  return null;
578
587
  }
579
588
  setSnapshot((current) => ({
@@ -661,6 +670,7 @@ function createReferencePreviewState(reference, target, preview) {
661
670
  bytes: preview.bytes,
662
671
  contentType: preview.contentType,
663
672
  entry: reference,
673
+ renderHtml: true,
664
674
  target: {
665
675
  ...target,
666
676
  fileKind: preview.kind
@@ -677,6 +687,17 @@ function createReferencePreviewState(reference, target, preview) {
677
687
  status: "image"
678
688
  };
679
689
  }
690
+ if (loadedState.status === "video") {
691
+ return {
692
+ objectUrl: URL.createObjectURL(
693
+ new Blob([loadedState.bytes], {
694
+ type: loadedState.contentType
695
+ })
696
+ ),
697
+ reference,
698
+ status: "video"
699
+ };
700
+ }
680
701
  if (loadedState.status === "text") {
681
702
  return {
682
703
  content: loadedState.content,
@@ -684,6 +705,13 @@ function createReferencePreviewState(reference, target, preview) {
684
705
  status: "text"
685
706
  };
686
707
  }
708
+ if (loadedState.status === "html") {
709
+ return {
710
+ content: loadedState.content,
711
+ reference,
712
+ status: "html"
713
+ };
714
+ }
687
715
  return {
688
716
  maxSizeBytes: loadedState.maxSizeBytes,
689
717
  reason: loadedState.reason,
@@ -899,6 +927,8 @@ var ROOT_CHILDREN_KEY = nodeRefKey({
899
927
  nodeId: SOURCE_ROOT_NODE_ID
900
928
  });
901
929
  var defaultSearchDebounceMs2 = 180;
930
+ var SEARCH_PAGE_SIZE = 30;
931
+ var SEARCH_MAX_LIMIT = 200;
902
932
  function emptyTabState(sourceId) {
903
933
  return {
904
934
  sourceId,
@@ -906,8 +936,13 @@ function emptyTabState(sourceId) {
906
936
  childrenByKey: {},
907
937
  mode: "browse",
908
938
  searchQuery: "",
939
+ searchFilters: [],
940
+ searchScopeNodeId: null,
909
941
  searchEntries: [],
910
942
  searchNextCursor: null,
943
+ searchLimit: 0,
944
+ searchHasMore: false,
945
+ isSearchLoadingMore: false,
911
946
  isSearchLoading: false,
912
947
  searchError: null
913
948
  };
@@ -925,8 +960,10 @@ function createReferenceSourcePickerController(input) {
925
960
  const { aggregator, scope } = input;
926
961
  const searchDebounceMs = input.searchDebounceMs ?? defaultSearchDebounceMs2;
927
962
  let retained = false;
963
+ let tabsReady = Promise.resolve();
928
964
  let tabsSequence = 0;
929
- let browseSequence = 0;
965
+ let nextBrowseSeq = 0;
966
+ const latestBrowseSeqByKey = /* @__PURE__ */ new Map();
930
967
  let searchSequence = 0;
931
968
  let searchAbortController = null;
932
969
  let searchTimer = null;
@@ -987,7 +1024,9 @@ function createReferenceSourcePickerController(input) {
987
1024
  if (options.append && !cursor) {
988
1025
  return;
989
1026
  }
990
- const sequence = ++browseSequence;
1027
+ const seqKey = `${sourceId}\0${key}`;
1028
+ const sequence = ++nextBrowseSeq;
1029
+ latestBrowseSeqByKey.set(seqKey, sequence);
991
1030
  setChildrenState(sourceId, key, { loading: true, error: null });
992
1031
  try {
993
1032
  const result = await aggregator.listChildren(
@@ -995,7 +1034,7 @@ function createReferenceSourcePickerController(input) {
995
1034
  node ? node.ref : { sourceId, nodeId: SOURCE_ROOT_NODE_ID },
996
1035
  { cursor }
997
1036
  );
998
- if (!retained || sequence !== browseSequence) {
1037
+ if (!retained || latestBrowseSeqByKey.get(seqKey) !== sequence) {
999
1038
  return;
1000
1039
  }
1001
1040
  const prior = snapshot.bySource[sourceId]?.childrenByKey[key]?.entries ?? [];
@@ -1008,7 +1047,7 @@ function createReferenceSourcePickerController(input) {
1008
1047
  error: null
1009
1048
  });
1010
1049
  } catch (error) {
1011
- if (!retained || sequence !== browseSequence) {
1050
+ if (!retained || latestBrowseSeqByKey.get(seqKey) !== sequence) {
1012
1051
  return;
1013
1052
  }
1014
1053
  setChildrenState(sourceId, key, {
@@ -1073,7 +1112,7 @@ function createReferenceSourcePickerController(input) {
1073
1112
  searchAbortController?.abort();
1074
1113
  searchAbortController = null;
1075
1114
  };
1076
- const runSearch = async (sourceId, query) => {
1115
+ const runSearch = async (sourceId, query, filters, scopeNodeId, limit, loadingMore) => {
1077
1116
  if (!retained) {
1078
1117
  return;
1079
1118
  }
@@ -1083,13 +1122,16 @@ function createReferenceSourcePickerController(input) {
1083
1122
  searchAbortController = abortController;
1084
1123
  updateTab(sourceId, (tab) => ({
1085
1124
  ...tab,
1086
- isSearchLoading: true,
1125
+ ...loadingMore ? { isSearchLoadingMore: true } : { isSearchLoading: true },
1087
1126
  searchError: null
1088
1127
  }));
1089
1128
  try {
1090
1129
  const result = await aggregator.search(scope, sourceId, {
1091
1130
  query,
1092
- signal: abortController.signal
1131
+ limit,
1132
+ signal: abortController.signal,
1133
+ ...filters.length > 0 ? { filters } : {},
1134
+ ...scopeNodeId == null ? {} : { withinNodeId: scopeNodeId }
1093
1135
  });
1094
1136
  if (!retained || sequence !== searchSequence) {
1095
1137
  return;
@@ -1097,8 +1139,12 @@ function createReferenceSourcePickerController(input) {
1097
1139
  updateTab(sourceId, (tab) => ({
1098
1140
  ...tab,
1099
1141
  isSearchLoading: false,
1142
+ isSearchLoadingMore: false,
1100
1143
  searchEntries: sortReferenceNodes(result.entries),
1101
1144
  searchNextCursor: result.nextCursor ?? null,
1145
+ searchLimit: limit,
1146
+ // 本页返回数达到请求上限、且未触全局上限 → 认为可能还有更多(增长式分页启发式)。
1147
+ searchHasMore: result.entries.length >= limit && limit < SEARCH_MAX_LIMIT,
1102
1148
  searchError: null
1103
1149
  }));
1104
1150
  } catch (error) {
@@ -1108,7 +1154,9 @@ function createReferenceSourcePickerController(input) {
1108
1154
  updateTab(sourceId, (tab) => ({
1109
1155
  ...tab,
1110
1156
  isSearchLoading: false,
1111
- searchEntries: [],
1157
+ isSearchLoadingMore: false,
1158
+ // 加载更多失败时保留已有结果,仅新查询失败才清空。
1159
+ ...loadingMore ? {} : { searchEntries: [], searchHasMore: false },
1112
1160
  searchError: normalizeError(error, "reference search failed")
1113
1161
  }));
1114
1162
  } finally {
@@ -1144,18 +1192,32 @@ function createReferenceSourcePickerController(input) {
1144
1192
  await walk(folder);
1145
1193
  return files;
1146
1194
  };
1147
- const scheduleSearch = (sourceId, query) => {
1195
+ const scheduleSearch = (sourceId, query, filters, scopeNodeId) => {
1148
1196
  clearSearchTimer();
1149
- if (!retained || !query) {
1197
+ if (!retained || !query && filters.length === 0) {
1150
1198
  return;
1151
1199
  }
1152
1200
  if (searchDebounceMs <= 0) {
1153
- void runSearch(sourceId, query);
1201
+ void runSearch(
1202
+ sourceId,
1203
+ query,
1204
+ filters,
1205
+ scopeNodeId,
1206
+ SEARCH_PAGE_SIZE,
1207
+ false
1208
+ );
1154
1209
  return;
1155
1210
  }
1156
1211
  searchTimer = setTimeout(() => {
1157
1212
  searchTimer = null;
1158
- void runSearch(sourceId, query);
1213
+ void runSearch(
1214
+ sourceId,
1215
+ query,
1216
+ filters,
1217
+ scopeNodeId,
1218
+ SEARCH_PAGE_SIZE,
1219
+ false
1220
+ );
1159
1221
  }, searchDebounceMs);
1160
1222
  };
1161
1223
  return {
@@ -1170,17 +1232,17 @@ function createReferenceSourcePickerController(input) {
1170
1232
  return;
1171
1233
  }
1172
1234
  retained = true;
1173
- void loadTabs();
1235
+ tabsReady = loadTabs();
1174
1236
  },
1175
1237
  close() {
1176
1238
  retained = false;
1177
1239
  cancelSearch();
1178
- browseSequence += 1;
1240
+ latestBrowseSeqByKey.clear();
1179
1241
  tabsSequence += 1;
1180
1242
  },
1181
1243
  reset() {
1182
1244
  cancelSearch();
1183
- browseSequence += 1;
1245
+ latestBrowseSeqByKey.clear();
1184
1246
  tabsSequence += 1;
1185
1247
  setSnapshot({
1186
1248
  isLoadingTabs: false,
@@ -1192,17 +1254,77 @@ function createReferenceSourcePickerController(input) {
1192
1254
  });
1193
1255
  },
1194
1256
  setActiveSource(sourceId) {
1195
- if (!snapshot.tabs.some((tab2) => tab2.sourceId === sourceId)) {
1257
+ if (!snapshot.tabs.some((tab) => tab.sourceId === sourceId)) {
1196
1258
  return;
1197
1259
  }
1260
+ const prevTab = snapshot.activeSourceId ? snapshot.bySource[snapshot.activeSourceId] : void 0;
1261
+ const carriedQuery = prevTab?.searchQuery ?? "";
1262
+ const carriedFilters = prevTab?.searchFilters ?? [];
1263
+ const trimmed = carriedQuery.trim();
1198
1264
  cancelSearch();
1199
1265
  setSnapshot({ activeSourceId: sourceId });
1200
- const tab = snapshot.bySource[sourceId];
1201
- if (tab?.mode === "search" && tab.searchQuery.trim()) {
1202
- scheduleSearch(sourceId, tab.searchQuery.trim());
1203
- } else {
1266
+ if (trimmed === "" && carriedFilters.length === 0) {
1267
+ updateTab(
1268
+ sourceId,
1269
+ (tab) => tab.mode === "browse" && tab.searchQuery === "" && tab.searchFilters.length === 0 ? tab : {
1270
+ ...tab,
1271
+ mode: "browse",
1272
+ searchQuery: "",
1273
+ searchFilters: [],
1274
+ searchEntries: [],
1275
+ searchHasMore: false,
1276
+ isSearchLoading: false,
1277
+ isSearchLoadingMore: false,
1278
+ searchError: null
1279
+ }
1280
+ );
1204
1281
  ensureRootLoaded(sourceId);
1282
+ return;
1205
1283
  }
1284
+ const nextScopeNodeId = snapshot.bySource[sourceId]?.searchScopeNodeId ?? null;
1285
+ updateTab(sourceId, (tab) => ({
1286
+ ...tab,
1287
+ searchQuery: carriedQuery,
1288
+ searchFilters: carriedFilters,
1289
+ searchScopeNodeId: nextScopeNodeId,
1290
+ mode: "search",
1291
+ // 沿用旧结果直到新结果就绪,避免切源瞬间闪空。
1292
+ isSearchLoading: true,
1293
+ searchError: null
1294
+ }));
1295
+ scheduleSearch(sourceId, trimmed, carriedFilters, nextScopeNodeId);
1296
+ },
1297
+ async locatePath(target) {
1298
+ await tabsReady;
1299
+ if (!retained) {
1300
+ return [];
1301
+ }
1302
+ const refs = await aggregator.locateTarget(
1303
+ scope,
1304
+ target.sourceId,
1305
+ target.params
1306
+ );
1307
+ if (!refs || refs.length === 0) {
1308
+ return [];
1309
+ }
1310
+ const path = [];
1311
+ let parent = {
1312
+ sourceId: target.sourceId,
1313
+ nodeId: SOURCE_ROOT_NODE_ID
1314
+ };
1315
+ for (const ref of refs) {
1316
+ const { entries } = await aggregator.listChildren(scope, parent);
1317
+ const targetKey = nodeRefKey(ref);
1318
+ const node = entries.find(
1319
+ (entry) => nodeRefKey(entry.ref) === targetKey
1320
+ );
1321
+ if (!node) {
1322
+ break;
1323
+ }
1324
+ path.push(node);
1325
+ parent = ref;
1326
+ }
1327
+ return path;
1206
1328
  },
1207
1329
  ensureChildren(node) {
1208
1330
  const sourceId = node ? node.ref.sourceId : snapshot.activeSourceId;
@@ -1221,6 +1343,24 @@ function createReferenceSourcePickerController(input) {
1221
1343
  }
1222
1344
  ensureRootLoaded(sourceId);
1223
1345
  },
1346
+ expandNode(node) {
1347
+ if (node.kind !== "folder") {
1348
+ return;
1349
+ }
1350
+ const sourceId = node.ref.sourceId;
1351
+ const key = nodeRefKey(node.ref);
1352
+ updateTab(
1353
+ sourceId,
1354
+ (tab) => tab.expandedKeys[key] === true ? tab : {
1355
+ ...tab,
1356
+ expandedKeys: { ...tab.expandedKeys, [key]: true }
1357
+ }
1358
+ );
1359
+ const childState = snapshot.bySource[sourceId]?.childrenByKey[key];
1360
+ if (!childState?.loaded && !childState?.loading) {
1361
+ void loadChildren(sourceId, node, { append: false });
1362
+ }
1363
+ },
1224
1364
  toggleNode(node) {
1225
1365
  if (node.kind !== "folder") {
1226
1366
  return;
@@ -1245,26 +1385,108 @@ function createReferenceSourcePickerController(input) {
1245
1385
  }
1246
1386
  void loadChildren(sourceId, node, { append: true });
1247
1387
  },
1248
- setSearchQuery(query) {
1388
+ loadMoreSourceRoot(sourceId) {
1389
+ if (!sourceId) {
1390
+ return;
1391
+ }
1392
+ void loadChildren(sourceId, null, { append: true });
1393
+ },
1394
+ setSearchQuery(query, scopeNodeId = null) {
1249
1395
  const sourceId = snapshot.activeSourceId;
1250
1396
  if (!sourceId) {
1251
1397
  return;
1252
1398
  }
1399
+ const filters = snapshot.bySource[sourceId]?.searchFilters ?? [];
1253
1400
  const trimmed = query.trim();
1254
- const nextMode = trimmed ? "search" : "browse";
1401
+ const nextMode = trimmed || filters.length > 0 ? "search" : "browse";
1255
1402
  updateTab(sourceId, (tab) => ({
1256
1403
  ...tab,
1257
1404
  searchQuery: query,
1405
+ searchScopeNodeId: scopeNodeId,
1258
1406
  mode: nextMode,
1259
- ...nextMode === "browse" ? { isSearchLoading: false, searchEntries: [], searchError: null } : {}
1407
+ // 进入搜索:立刻置 loading(搜索是 debounce 的,否则键入到取数之间会先渲染空态,
1408
+ // 造成「空态 → spinner → 结果」闪烁)。保留上次 searchEntries,细化关键词时沿用旧结果而非闪空。
1409
+ ...nextMode === "browse" ? { isSearchLoading: false, searchEntries: [], searchError: null } : { isSearchLoading: true, searchError: null }
1260
1410
  }));
1261
1411
  if (nextMode === "search") {
1262
- scheduleSearch(sourceId, trimmed);
1412
+ scheduleSearch(sourceId, trimmed, filters, scopeNodeId);
1263
1413
  } else {
1264
1414
  cancelSearch();
1265
1415
  ensureRootLoaded(sourceId);
1266
1416
  }
1267
1417
  },
1418
+ setSearchFilters(filters, scopeNodeId = null) {
1419
+ const sourceId = snapshot.activeSourceId;
1420
+ if (!sourceId) {
1421
+ return;
1422
+ }
1423
+ const tab = snapshot.bySource[sourceId];
1424
+ const trimmed = tab?.searchQuery.trim() ?? "";
1425
+ const scopeId = scopeNodeId ?? tab?.searchScopeNodeId ?? null;
1426
+ const nextMode = trimmed || filters.length > 0 ? "search" : "browse";
1427
+ updateTab(sourceId, (current) => ({
1428
+ ...current,
1429
+ searchFilters: filters,
1430
+ searchScopeNodeId: scopeId,
1431
+ mode: nextMode,
1432
+ ...nextMode === "browse" ? { isSearchLoading: false, searchEntries: [], searchError: null } : { isSearchLoading: true, searchError: null }
1433
+ }));
1434
+ if (nextMode === "search") {
1435
+ scheduleSearch(sourceId, trimmed, filters, scopeId);
1436
+ } else {
1437
+ cancelSearch();
1438
+ ensureRootLoaded(sourceId);
1439
+ }
1440
+ },
1441
+ setSearchScope(scopeNodeId) {
1442
+ const sourceId = snapshot.activeSourceId;
1443
+ if (!sourceId) {
1444
+ return;
1445
+ }
1446
+ const tab = snapshot.bySource[sourceId];
1447
+ if (!tab || tab.searchScopeNodeId === scopeNodeId) {
1448
+ return;
1449
+ }
1450
+ updateTab(sourceId, (current) => ({
1451
+ ...current,
1452
+ searchScopeNodeId: scopeNodeId
1453
+ }));
1454
+ const trimmed = tab.searchQuery.trim();
1455
+ const filters = tab.searchFilters;
1456
+ if (tab.mode === "search" && (trimmed || filters.length > 0)) {
1457
+ scheduleSearch(sourceId, trimmed, filters, scopeNodeId);
1458
+ }
1459
+ },
1460
+ loadMoreSearch() {
1461
+ const sourceId = snapshot.activeSourceId;
1462
+ if (!sourceId) {
1463
+ return;
1464
+ }
1465
+ const tab = snapshot.bySource[sourceId];
1466
+ if (!tab || tab.mode !== "search" || !tab.searchHasMore || tab.isSearchLoadingMore) {
1467
+ return;
1468
+ }
1469
+ const trimmed = tab.searchQuery.trim();
1470
+ if (!trimmed && tab.searchFilters.length === 0) {
1471
+ return;
1472
+ }
1473
+ const nextLimit = Math.min(
1474
+ (tab.searchLimit || SEARCH_PAGE_SIZE) + SEARCH_PAGE_SIZE,
1475
+ SEARCH_MAX_LIMIT
1476
+ );
1477
+ if (nextLimit <= tab.searchLimit) {
1478
+ return;
1479
+ }
1480
+ clearSearchTimer();
1481
+ void runSearch(
1482
+ sourceId,
1483
+ trimmed,
1484
+ tab.searchFilters,
1485
+ tab.searchScopeNodeId,
1486
+ nextLimit,
1487
+ true
1488
+ );
1489
+ },
1268
1490
  toggleSelection(node) {
1269
1491
  const key = nodeRefKey(node.ref);
1270
1492
  setSnapshot((current) => {
@@ -1306,6 +1528,29 @@ function createReferenceSourcePickerController(input) {
1306
1528
  }
1307
1529
  }
1308
1530
  return resolved;
1531
+ },
1532
+ async confirmGrouped() {
1533
+ const files = [];
1534
+ const bundles = [];
1535
+ const seenPaths = /* @__PURE__ */ new Set();
1536
+ const pushFile = (ref) => {
1537
+ if (seenPaths.has(ref.path)) {
1538
+ return;
1539
+ }
1540
+ seenPaths.add(ref.path);
1541
+ files.push(ref);
1542
+ };
1543
+ for (const node of snapshot.selection) {
1544
+ const source = aggregator.getLoadedSource(node.ref.sourceId);
1545
+ const navigable = node.kind === "folder" && (source?.capabilities.navigable ?? false);
1546
+ if (!navigable) {
1547
+ pushFile(aggregator.resolveSelection(node));
1548
+ continue;
1549
+ }
1550
+ const handle = source?.describeReferenceHandle?.(node) ?? null;
1551
+ bundles.push({ root: node, handle });
1552
+ }
1553
+ return { files, bundles };
1309
1554
  }
1310
1555
  };
1311
1556
  }
@@ -1328,4 +1573,4 @@ export {
1328
1573
  ROOT_CHILDREN_KEY,
1329
1574
  createReferenceSourcePickerController
1330
1575
  };
1331
- //# sourceMappingURL=chunk-CD3YNHYJ.js.map
1576
+ //# sourceMappingURL=chunk-LJZYN4MH.js.map