@tutti-os/workspace-file-reference 0.0.38 → 0.0.40

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/ui/index.js CHANGED
@@ -3,13 +3,13 @@ import {
3
3
  createReferenceSourcePickerController,
4
4
  normalizeDirectoryPath,
5
5
  useWorkspaceFileReferencePickerView
6
- } from "../chunk-SXYVXNMS.js";
6
+ } from "../chunk-7MGLDKT7.js";
7
7
  import {
8
8
  REFERENCE_FILTER_CATEGORIES,
9
9
  WORKSPACE_ROOT_GROUP_NODE_ID,
10
10
  nodeRefKey,
11
11
  selectedReferenceToWorkspaceFileReference
12
- } from "../chunk-BD7XDAYN.js";
12
+ } from "../chunk-Z2HHO3KB.js";
13
13
 
14
14
  // src/ui/internal/reference/WorkspaceFileReferencePicker.tsx
15
15
  import {
@@ -739,16 +739,29 @@ import { AddLinedIcon as AddLinedIcon2 } from "@tutti-os/ui-system/icons";
739
739
  import {
740
740
  WorkspaceFilePreviewSurface
741
741
  } from "@tutti-os/workspace-file-preview/react";
742
+ import {
743
+ WorkspaceFileManagerContextMenu,
744
+ resolveRevealInFolderLabel
745
+ } from "@tutti-os/workspace-file-manager";
742
746
 
743
747
  // src/react/internal/reference/useReferenceSourcePickerView.ts
744
748
  import { useCallback, useEffect as useEffect2, useMemo, useRef, useState as useState3 } from "react";
745
749
  import { useSnapshot } from "valtio";
746
750
  import {
747
- sortWorkspaceFileEntriesForArrangeMode
751
+ resolveWorkspaceFileOpenWithCacheKey,
752
+ sortWorkspaceFileEntriesForArrangeMode,
753
+ WorkspaceFileOpenWithApplicationsCache
748
754
  } from "@tutti-os/workspace-file-manager/services";
749
755
  import {
750
756
  createWorkspaceFilePreviewLoadedState
751
757
  } from "@tutti-os/workspace-file-preview";
758
+ function referenceNodeToOpenWithCacheEntry(node) {
759
+ return {
760
+ kind: node.kind === "folder" ? "directory" : "file",
761
+ name: node.displayName,
762
+ path: node.displayName
763
+ };
764
+ }
752
765
  function useReferenceSourcePickerView({
753
766
  aggregator,
754
767
  workspaceId,
@@ -770,6 +783,9 @@ function useReferenceSourcePickerView({
770
783
  const [breadcrumbBySource, setBreadcrumbBySource] = useState3({});
771
784
  const [focusedNode, setFocusedNode] = useState3(null);
772
785
  const [arrangeMode, setArrangeMode] = useState3("none");
786
+ const openWithApplicationsCache = useRef(
787
+ new WorkspaceFileOpenWithApplicationsCache()
788
+ );
773
789
  const sortNodes = useCallback(
774
790
  (nodes) => {
775
791
  if (arrangeMode === "none") {
@@ -1071,6 +1087,21 @@ function useReferenceSourcePickerView({
1071
1087
  [isSelectable, snapshot.selection]
1072
1088
  );
1073
1089
  const [isConfirming, setIsConfirming] = useState3(false);
1090
+ const [isOpeningReference, setIsOpeningReference] = useState3(false);
1091
+ const runReferenceAction = useCallback(
1092
+ async (action) => {
1093
+ if (isOpeningReference) {
1094
+ return;
1095
+ }
1096
+ setIsOpeningReference(true);
1097
+ try {
1098
+ await action();
1099
+ } finally {
1100
+ setIsOpeningReference(false);
1101
+ }
1102
+ },
1103
+ [isOpeningReference]
1104
+ );
1074
1105
  const confirm = useCallback(async () => {
1075
1106
  if (isConfirming) {
1076
1107
  return;
@@ -1305,6 +1336,30 @@ function useReferenceSourcePickerView({
1305
1336
  loadMore: () => isQuery ? controller.loadMoreSearch() : controller.loadMore(currentNode),
1306
1337
  isSelectable,
1307
1338
  isSelected,
1339
+ isOpeningReference,
1340
+ getCachedOpenWithApplications: (node) => openWithApplicationsCache.current.get(
1341
+ resolveWorkspaceFileOpenWithCacheKey(
1342
+ referenceNodeToOpenWithCacheEntry(node)
1343
+ )
1344
+ ),
1345
+ listOpenWithApplications: (node) => openWithApplicationsCache.current.resolve(
1346
+ resolveWorkspaceFileOpenWithCacheKey(
1347
+ referenceNodeToOpenWithCacheEntry(node)
1348
+ ),
1349
+ () => aggregator.listOpenWithApplications(scope, node)
1350
+ ),
1351
+ openNode: (node) => runReferenceAction(() => aggregator.open(scope, node)),
1352
+ openWithApplication: (node, applicationPath) => runReferenceAction(
1353
+ () => aggregator.openWithApplication(scope, node, applicationPath)
1354
+ ),
1355
+ openWithOtherApplication: (node, applicationPickerPrompt) => runReferenceAction(
1356
+ () => aggregator.openWithOtherApplication(
1357
+ scope,
1358
+ node,
1359
+ applicationPickerPrompt
1360
+ )
1361
+ ),
1362
+ revealNode: (node) => runReferenceAction(() => aggregator.reveal(scope, node)),
1308
1363
  confirm,
1309
1364
  isConfirming
1310
1365
  };
@@ -1415,12 +1470,15 @@ function autoFitPanelWidth(groupEl, contentEl, panel, trailingPx) {
1415
1470
  function ReferenceSourcePicker({
1416
1471
  aggregator,
1417
1472
  copy,
1473
+ fileManagerCopy,
1474
+ hostOs = "darwin",
1418
1475
  initialTarget,
1419
1476
  isNodeSelectable,
1420
1477
  onClose,
1421
1478
  onConfirm,
1422
1479
  onConfirmBundles,
1423
1480
  open,
1481
+ resolveOpenWithApplicationIcon,
1424
1482
  workspaceId
1425
1483
  }) {
1426
1484
  const titleId = useId2();
@@ -1451,10 +1509,88 @@ function ReferenceSourcePicker({
1451
1509
  value: view.searchQuery
1452
1510
  });
1453
1511
  const layoutRef = useRef2(null);
1512
+ const menuBoundaryRef = useRef2(null);
1513
+ const contextMenuRef = useRef2(null);
1454
1514
  const sidebarContentRef = useRef2(null);
1455
1515
  const middleContentRef = useRef2(null);
1456
1516
  const sidebarPanelRef = useRef2(null);
1457
1517
  const middlePanelRef = useRef2(null);
1518
+ const [contextMenu, setContextMenu] = useState4(null);
1519
+ const [openWithApplications, setOpenWithApplications] = useState4([]);
1520
+ const [openWithLoading, setOpenWithLoading] = useState4(false);
1521
+ useEffect3(() => {
1522
+ if (!contextMenu || !fileManagerCopy) {
1523
+ setOpenWithApplications([]);
1524
+ setOpenWithLoading(false);
1525
+ return;
1526
+ }
1527
+ let cancelled = false;
1528
+ const cachedApplications = view.getCachedOpenWithApplications(
1529
+ contextMenu.node
1530
+ );
1531
+ if (cachedApplications) {
1532
+ setOpenWithApplications(cachedApplications);
1533
+ setOpenWithLoading(false);
1534
+ return;
1535
+ }
1536
+ setOpenWithApplications([]);
1537
+ setOpenWithLoading(true);
1538
+ void view.listOpenWithApplications(contextMenu.node).then((applications) => {
1539
+ if (cancelled) {
1540
+ return;
1541
+ }
1542
+ setOpenWithApplications(applications);
1543
+ setOpenWithLoading(false);
1544
+ }).catch(() => {
1545
+ if (cancelled) {
1546
+ return;
1547
+ }
1548
+ setOpenWithApplications([]);
1549
+ setOpenWithLoading(false);
1550
+ });
1551
+ return () => {
1552
+ cancelled = true;
1553
+ };
1554
+ }, [contextMenu?.node, fileManagerCopy]);
1555
+ useEffect3(() => {
1556
+ if (!contextMenu) {
1557
+ return;
1558
+ }
1559
+ function handlePointerDown(event) {
1560
+ const target = event.target;
1561
+ if (target instanceof Node && contextMenuRef.current?.contains(target)) {
1562
+ return;
1563
+ }
1564
+ if (target instanceof Element && target.closest("[data-workspace-file-manager-submenu]")) {
1565
+ return;
1566
+ }
1567
+ setContextMenu(null);
1568
+ }
1569
+ function handleKeyDown(event) {
1570
+ if (event.key === "Escape") {
1571
+ setContextMenu(null);
1572
+ }
1573
+ }
1574
+ window.addEventListener("pointerdown", handlePointerDown);
1575
+ window.addEventListener("keydown", handleKeyDown);
1576
+ return () => {
1577
+ window.removeEventListener("pointerdown", handlePointerDown);
1578
+ window.removeEventListener("keydown", handleKeyDown);
1579
+ };
1580
+ }, [contextMenu]);
1581
+ const openReferenceContextMenu = (event, node) => {
1582
+ if (!fileManagerCopy || node.kind !== "file") {
1583
+ return;
1584
+ }
1585
+ event.preventDefault();
1586
+ event.stopPropagation();
1587
+ view.setFocusedNode(node);
1588
+ setContextMenu({
1589
+ node,
1590
+ x: event.clientX,
1591
+ y: event.clientY
1592
+ });
1593
+ };
1458
1594
  if (!open) {
1459
1595
  return null;
1460
1596
  }
@@ -1546,107 +1682,196 @@ function ReferenceSourcePicker({
1546
1682
  panelRef: (handle) => {
1547
1683
  middlePanelRef.current = handle;
1548
1684
  },
1549
- children: /* @__PURE__ */ jsxs4("div", { className: "flex h-full min-h-0 flex-col", children: [
1550
- /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2 border-b border-[var(--line-1)] p-3", children: [
1551
- /* @__PURE__ */ jsxs4("div", { className: "relative flex-1", children: [
1552
- /* @__PURE__ */ jsx4(SearchIcon2, { className: "pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2 text-[var(--text-tertiary)]" }),
1685
+ children: /* @__PURE__ */ jsxs4(
1686
+ "div",
1687
+ {
1688
+ ref: menuBoundaryRef,
1689
+ className: "relative flex h-full min-h-0 flex-col",
1690
+ "data-slot": "viewport-menu-boundary",
1691
+ "data-workspace-file-menu-boundary": "",
1692
+ style: {
1693
+ "--workspace-file-manager-dialog-overlay-z-index": "100710"
1694
+ },
1695
+ children: [
1696
+ /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2 border-b border-[var(--line-1)] p-3", children: [
1697
+ /* @__PURE__ */ jsxs4("div", { className: "relative flex-1", children: [
1698
+ /* @__PURE__ */ jsx4(SearchIcon2, { className: "pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2 text-[var(--text-tertiary)]" }),
1699
+ /* @__PURE__ */ jsx4(
1700
+ Input2,
1701
+ {
1702
+ className: "pl-9",
1703
+ placeholder: copy.t(
1704
+ "referencePicker.searchPlaceholder"
1705
+ ),
1706
+ value: searchInput.value,
1707
+ onBlur: searchInput.onBlur,
1708
+ onChange: searchInput.onChange,
1709
+ onCompositionEnd: searchInput.onCompositionEnd,
1710
+ onCompositionStart: searchInput.onCompositionStart
1711
+ }
1712
+ )
1713
+ ] }),
1714
+ view.capabilities?.filterable && view.filterCategories.length > 0 ? /* @__PURE__ */ jsx4(
1715
+ FilterCategoryFilter,
1716
+ {
1717
+ categories: view.filterCategories,
1718
+ copy,
1719
+ selected: activeFilterSet,
1720
+ onClear: clearFilters,
1721
+ onToggle: toggleFilter
1722
+ }
1723
+ ) : null
1724
+ ] }),
1553
1725
  /* @__PURE__ */ jsx4(
1554
- Input2,
1726
+ ScrollArea2,
1555
1727
  {
1556
- className: "pl-9",
1557
- placeholder: copy.t(
1558
- "referencePicker.searchPlaceholder"
1559
- ),
1560
- value: searchInput.value,
1561
- onBlur: searchInput.onBlur,
1562
- onChange: searchInput.onChange,
1563
- onCompositionEnd: searchInput.onCompositionEnd,
1564
- onCompositionStart: searchInput.onCompositionStart
1565
- }
1566
- )
1567
- ] }),
1568
- view.capabilities?.filterable && view.filterCategories.length > 0 ? /* @__PURE__ */ jsx4(
1569
- FilterCategoryFilter,
1570
- {
1571
- categories: view.filterCategories,
1572
- copy,
1573
- selected: activeFilterSet,
1574
- onClear: clearFilters,
1575
- onToggle: toggleFilter
1576
- }
1577
- ) : null
1578
- ] }),
1579
- /* @__PURE__ */ jsx4(
1580
- ScrollArea2,
1581
- {
1582
- className: "min-h-0 flex-1",
1583
- viewportProps: {
1584
- // 拉到底部(距底 <120px)自动加载更多 —— 查询态走增长式分页,
1585
- // 浏览态走 cursor 续页。已在加载/无更多时由 loadMore 内部 no-op。
1586
- onScroll: (event) => {
1587
- const el = event.currentTarget;
1588
- if (view.hasMore && !view.isLoading && !view.isLoadingMore && el.scrollHeight - el.scrollTop - el.clientHeight < 120) {
1589
- view.loadMore();
1590
- }
1728
+ className: "min-h-0 flex-1",
1729
+ viewportProps: {
1730
+ // 拉到底部(距底 <120px)自动加载更多 —— 查询态走增长式分页,
1731
+ // 浏览态走 cursor 续页。已在加载/无更多时由 loadMore 内部 no-op。
1732
+ onScroll: (event) => {
1733
+ const el = event.currentTarget;
1734
+ if (view.hasMore && !view.isLoading && !view.isLoadingMore && el.scrollHeight - el.scrollTop - el.clientHeight < 120) {
1735
+ view.loadMore();
1736
+ }
1737
+ }
1738
+ },
1739
+ children: /* @__PURE__ */ jsxs4(
1740
+ "div",
1741
+ {
1742
+ ref: middleContentRef,
1743
+ className: "flex flex-col gap-[2px] p-3",
1744
+ children: [
1745
+ view.isLoading ? /* @__PURE__ */ jsx4(Feedback, { children: /* @__PURE__ */ jsx4(Spinner2, { size: 16 }) }) : view.isQuery ? (
1746
+ // 查询态(关键词或筛选):扁平结果
1747
+ view.searchResults.length === 0 ? /* @__PURE__ */ jsx4(Feedback, { children: copy.t("referencePicker.emptySearch") }) : view.searchResults.map((node) => /* @__PURE__ */ jsx4(
1748
+ SearchResultRow,
1749
+ {
1750
+ focused: isFocused(view.focusedNode, node),
1751
+ node,
1752
+ selected: view.isSelected(node),
1753
+ onFocus: view.setFocusedNode,
1754
+ onContextMenu: openReferenceContextMenu,
1755
+ onOpen: view.openNode,
1756
+ selectable: view.isSelectable(node),
1757
+ onSingleSelect: view.toggleSingleSelectionAndExpand,
1758
+ onToggle: view.toggleSelection
1759
+ },
1760
+ nodeRefKey(node.ref)
1761
+ ))
1762
+ ) : view.currentEntries.length === 0 ? /* @__PURE__ */ jsx4(Feedback, { children: copy.t(
1763
+ hasSelectedGroup ? "referencePicker.emptyDirectory" : "referencePicker.selectGroupHint"
1764
+ ) }) : (
1765
+ // 浏览:就地递归展开树(复刻 agent 引用面板文件树交互)
1766
+ view.currentEntries.map((node) => /* @__PURE__ */ jsx4(
1767
+ TreeNodeRow,
1768
+ {
1769
+ copy,
1770
+ depth: 0,
1771
+ node,
1772
+ onContextMenu: openReferenceContextMenu,
1773
+ view
1774
+ },
1775
+ nodeRefKey(node.ref)
1776
+ ))
1777
+ ),
1778
+ view.hasMore && (view.isQuery || hasSelectedGroup) ? /* @__PURE__ */ jsxs4(
1779
+ Button3,
1780
+ {
1781
+ className: "mt-1 w-full",
1782
+ disabled: view.isLoadingMore,
1783
+ size: "sm",
1784
+ type: "button",
1785
+ variant: "ghost",
1786
+ onClick: view.loadMore,
1787
+ children: [
1788
+ view.isLoadingMore ? /* @__PURE__ */ jsx4(Spinner2, { className: "text-current", size: 14 }) : null,
1789
+ copy.t("referencePicker.loadMore")
1790
+ ]
1791
+ }
1792
+ ) : null
1793
+ ]
1794
+ }
1795
+ )
1591
1796
  }
1592
- },
1593
- children: /* @__PURE__ */ jsxs4(
1594
- "div",
1797
+ ),
1798
+ fileManagerCopy ? /* @__PURE__ */ jsx4(
1799
+ WorkspaceFileManagerContextMenu,
1595
1800
  {
1596
- ref: middleContentRef,
1597
- className: "flex flex-col gap-[2px] p-3",
1598
- children: [
1599
- view.isLoading ? /* @__PURE__ */ jsx4(Feedback, { children: /* @__PURE__ */ jsx4(Spinner2, { size: 16 }) }) : view.isQuery ? (
1600
- // 查询态(关键词或筛选):扁平结果
1601
- view.searchResults.length === 0 ? /* @__PURE__ */ jsx4(Feedback, { children: copy.t("referencePicker.emptySearch") }) : view.searchResults.map((node) => /* @__PURE__ */ jsx4(
1602
- SearchResultRow,
1603
- {
1604
- focused: isFocused(view.focusedNode, node),
1605
- node,
1606
- selected: view.isSelected(node),
1607
- onFocus: view.setFocusedNode,
1608
- selectable: view.isSelectable(node),
1609
- onSingleSelect: view.toggleSingleSelectionAndExpand,
1610
- onToggle: view.toggleSelection
1611
- },
1612
- nodeRefKey(node.ref)
1613
- ))
1614
- ) : view.currentEntries.length === 0 ? /* @__PURE__ */ jsx4(Feedback, { children: copy.t(
1615
- hasSelectedGroup ? "referencePicker.emptyDirectory" : "referencePicker.selectGroupHint"
1616
- ) }) : (
1617
- // 浏览:就地递归展开树(复刻 agent 引用面板文件树交互)
1618
- view.currentEntries.map((node) => /* @__PURE__ */ jsx4(
1619
- TreeNodeRow,
1620
- {
1621
- copy,
1622
- depth: 0,
1623
- node,
1624
- view
1625
- },
1626
- nodeRefKey(node.ref)
1627
- ))
1801
+ busy: view.isOpeningReference,
1802
+ contextMenu: contextMenu ? {
1803
+ entry: referenceNodeToWorkspaceFileEntry(
1804
+ contextMenu.node
1628
1805
  ),
1629
- view.hasMore && (view.isQuery || hasSelectedGroup) ? /* @__PURE__ */ jsxs4(
1630
- Button3,
1631
- {
1632
- className: "mt-1 w-full",
1633
- disabled: view.isLoadingMore,
1634
- size: "sm",
1635
- type: "button",
1636
- variant: "ghost",
1637
- onClick: view.loadMore,
1638
- children: [
1639
- view.isLoadingMore ? /* @__PURE__ */ jsx4(Spinner2, { className: "text-current", size: 14 }) : null,
1640
- copy.t("referencePicker.loadMore")
1641
- ]
1642
- }
1643
- ) : null
1644
- ]
1806
+ x: contextMenu.x,
1807
+ y: contextMenu.y
1808
+ } : null,
1809
+ contextMenuRef,
1810
+ copy: fileManagerCopy,
1811
+ openWithApplications,
1812
+ openWithLoading,
1813
+ positionMode: "viewport",
1814
+ revealInFolderLabel: resolveRevealInFolderLabel(
1815
+ fileManagerCopy,
1816
+ hostOs
1817
+ ),
1818
+ resolveOpenWithApplicationIcon,
1819
+ showCopyAction: false,
1820
+ showCopyPathAction: false,
1821
+ showCreateAction: false,
1822
+ showDeleteAction: false,
1823
+ showExportAction: false,
1824
+ showImportAction: false,
1825
+ showOpenInAppBrowserAction: false,
1826
+ showOpenInDefaultBrowserAction: false,
1827
+ showOpenInFileViewerAction: false,
1828
+ showOpenWithAction: true,
1829
+ showOpenWithOtherAction: true,
1830
+ showRevealInFolderAction: true,
1831
+ showRenameAction: false,
1832
+ onClose: () => setContextMenu(null),
1833
+ onCopy: noopAsync,
1834
+ onCopyPath: noopAsync,
1835
+ onCreateDirectory: noopVoid,
1836
+ onCreateFile: noopVoid,
1837
+ onDelete: noopVoid,
1838
+ onExport: noopAsync,
1839
+ onImport: noopAsync,
1840
+ onOpen: async () => {
1841
+ if (contextMenu) {
1842
+ await view.openNode(contextMenu.node);
1843
+ }
1844
+ },
1845
+ onOpenInAppBrowser: noopAsync,
1846
+ onOpenInDefaultBrowser: noopAsync,
1847
+ onOpenInFileViewer: noopAsync,
1848
+ onOpenWithApplication: async (applicationPath) => {
1849
+ if (contextMenu) {
1850
+ await view.openWithApplication(
1851
+ contextMenu.node,
1852
+ applicationPath
1853
+ );
1854
+ }
1855
+ },
1856
+ onOpenWithOtherApplication: async () => {
1857
+ if (contextMenu) {
1858
+ await view.openWithOtherApplication(
1859
+ contextMenu.node,
1860
+ fileManagerCopy.t("openWithOtherPickerPrompt")
1861
+ );
1862
+ }
1863
+ },
1864
+ onRevealInFolder: async () => {
1865
+ if (contextMenu) {
1866
+ await view.revealNode(contextMenu.node);
1867
+ }
1868
+ },
1869
+ onRename: noopVoid
1645
1870
  }
1646
- )
1647
- }
1648
- )
1649
- ] })
1871
+ ) : null
1872
+ ]
1873
+ }
1874
+ )
1650
1875
  }
1651
1876
  ),
1652
1877
  /* @__PURE__ */ jsx4(
@@ -1837,7 +2062,9 @@ function SearchResultRow({
1837
2062
  selected,
1838
2063
  selectable,
1839
2064
  onFocus,
2065
+ onContextMenu,
1840
2066
  onSingleSelect,
2067
+ onOpen,
1841
2068
  onToggle
1842
2069
  }) {
1843
2070
  const isFolder = node.kind === "folder";
@@ -1854,6 +2081,15 @@ function SearchResultRow({
1854
2081
  onFocus(node);
1855
2082
  onSingleSelect(node);
1856
2083
  },
2084
+ onContextMenu: (event) => onContextMenu(event, node),
2085
+ onDoubleClick: (event) => {
2086
+ if (node.kind !== "file") {
2087
+ return;
2088
+ }
2089
+ event.stopPropagation();
2090
+ onFocus(node);
2091
+ void onOpen(node);
2092
+ },
1857
2093
  children: [
1858
2094
  /* @__PURE__ */ jsxs4("div", { className: "flex min-w-0 items-center gap-3 text-left", children: [
1859
2095
  /* @__PURE__ */ jsx4("span", { className: "grid size-9 shrink-0 place-items-center rounded-lg bg-[var(--transparency-block)] text-[var(--text-tertiary)]", children: isFolder ? /* @__PURE__ */ jsx4(FolderFilledIcon3, { className: "size-4 text-[var(--rich-text-folder)]" }) : /* @__PURE__ */ jsx4(FileIcon3, { className: "size-4 text-[var(--text-tertiary)]" }) }),
@@ -1875,6 +2111,7 @@ function SearchResultRow({
1875
2111
  onFocus(node);
1876
2112
  onToggle(node);
1877
2113
  },
2114
+ onDoubleClick: (event) => event.stopPropagation(),
1878
2115
  children: selected ? /* @__PURE__ */ jsx4(CheckIcon2, { size: 14 }) : /* @__PURE__ */ jsx4(AddLinedIcon2, { className: "text-[var(--text-secondary)]", size: 16 })
1879
2116
  }
1880
2117
  ) : null
@@ -2254,6 +2491,7 @@ function isFocused(focused, node) {
2254
2491
  function TreeNodeRow({
2255
2492
  node,
2256
2493
  depth,
2494
+ onContextMenu,
2257
2495
  view,
2258
2496
  copy
2259
2497
  }) {
@@ -2300,6 +2538,7 @@ function TreeNodeRow({
2300
2538
  copy,
2301
2539
  depth: depth + 1,
2302
2540
  node: child,
2541
+ onContextMenu,
2303
2542
  view
2304
2543
  },
2305
2544
  nodeRefKey(child.ref)
@@ -2325,6 +2564,15 @@ function TreeNodeRow({
2325
2564
  view.setFocusedNode(node);
2326
2565
  view.toggleSingleSelectionAndExpand(node);
2327
2566
  },
2567
+ onContextMenu: (event) => onContextMenu(event, node),
2568
+ onDoubleClick: (event) => {
2569
+ if (node.kind !== "file") {
2570
+ return;
2571
+ }
2572
+ event.stopPropagation();
2573
+ view.setFocusedNode(node);
2574
+ void view.openNode(node);
2575
+ },
2328
2576
  children: [
2329
2577
  isFolder ? /* @__PURE__ */ jsx4(
2330
2578
  "button",
@@ -2371,6 +2619,7 @@ function TreeNodeRow({
2371
2619
  view.setFocusedNode(node);
2372
2620
  view.toggleSelection(node);
2373
2621
  },
2622
+ onDoubleClick: (event) => event.stopPropagation(),
2374
2623
  children: selected ? /* @__PURE__ */ jsx4(CheckIcon2, { size: 14 }) : /* @__PURE__ */ jsx4(
2375
2624
  AddLinedIcon2,
2376
2625
  {
@@ -2420,6 +2669,20 @@ function formatBytes(bytes) {
2420
2669
  }
2421
2670
  return `${value.toFixed(1)} ${units[unitIndex]}`;
2422
2671
  }
2672
+ function referenceNodeToWorkspaceFileEntry(node) {
2673
+ return {
2674
+ hasChildren: node.kind === "folder",
2675
+ kind: node.kind === "folder" ? "directory" : "file",
2676
+ mtimeMs: node.mtimeMs ?? null,
2677
+ name: node.displayName,
2678
+ path: nodeRefKey(node.ref),
2679
+ sizeBytes: node.sizeBytes ?? null
2680
+ };
2681
+ }
2682
+ function noopVoid() {
2683
+ }
2684
+ async function noopAsync() {
2685
+ }
2423
2686
  export {
2424
2687
  ReferenceSourcePicker,
2425
2688
  WorkspaceFileReferencePicker