@lvce-editor/explorer-view 6.11.0 → 6.14.0

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.
@@ -189,7 +189,7 @@ class AssertionError extends Error {
189
189
  const Object$1 = 1;
190
190
  const Number$1 = 2;
191
191
  const Array$1 = 3;
192
- const String = 4;
192
+ const String$1 = 4;
193
193
  const Boolean$1 = 5;
194
194
  const Function = 6;
195
195
  const Null = 7;
@@ -201,7 +201,7 @@ const getType = value => {
201
201
  case 'function':
202
202
  return Function;
203
203
  case 'string':
204
- return String;
204
+ return String$1;
205
205
  case 'object':
206
206
  if (value === null) {
207
207
  return Null;
@@ -236,7 +236,7 @@ const array = value => {
236
236
  };
237
237
  const string = value => {
238
238
  const type = getType(value);
239
- if (type !== String) {
239
+ if (type !== String$1) {
240
240
  throw new AssertionError('expected value to be of type string');
241
241
  }
242
242
  };
@@ -1436,8 +1436,8 @@ const applyFileOperations = async operations => {
1436
1436
  }
1437
1437
  return '';
1438
1438
  } catch (error) {
1439
- console.error(new VError(error, `Failed to apply file operations`));
1440
- return `${error}`;
1439
+ console.error(new VError(error, 'Failed to apply file operations'));
1440
+ return String(error);
1441
1441
  }
1442
1442
  };
1443
1443
 
@@ -1667,11 +1667,31 @@ const getChildDirentsRaw = async uri => {
1667
1667
  };
1668
1668
 
1669
1669
  const RE_CHARACTERS = /^[a-zA-Z.-]+$/;
1670
+ const RE_LEADING_DIGITS = /^\d+/;
1671
+ const compareLeadingDigits = (a, b) => {
1672
+ const normalizedA = a.replace(/^0+/, '') || '0';
1673
+ const normalizedB = b.replace(/^0+/, '') || '0';
1674
+ if (normalizedA.length !== normalizedB.length) {
1675
+ return normalizedA.length - normalizedB.length;
1676
+ }
1677
+ if (normalizedA !== normalizedB) {
1678
+ return normalizedA < normalizedB ? -1 : 1;
1679
+ }
1680
+ return a.length - b.length;
1681
+ };
1682
+ const compareLeadingNumbers = (a, b) => {
1683
+ const leadingDigitsA = a.match(RE_LEADING_DIGITS)?.[0];
1684
+ const leadingDigitsB = b.match(RE_LEADING_DIGITS)?.[0];
1685
+ if (leadingDigitsA && leadingDigitsB) {
1686
+ return compareLeadingDigits(leadingDigitsA, leadingDigitsB);
1687
+ }
1688
+ return 0;
1689
+ };
1670
1690
  const compareStringNumeric = (a, b) => {
1671
1691
  if (RE_CHARACTERS.test(a) && RE_CHARACTERS.test(b)) {
1672
1692
  return a < b ? -1 : 1;
1673
1693
  }
1674
- return a.localeCompare(b, 'en', {
1694
+ return compareLeadingNumbers(a, b) || a.localeCompare(b, 'en', {
1675
1695
  numeric: true
1676
1696
  });
1677
1697
  };
@@ -1739,14 +1759,11 @@ const getChildDirents = async (pathSeparator, parentDirentPath, parentDirentDept
1739
1759
  return displayDirents;
1740
1760
  };
1741
1761
 
1742
- const isTopLevel = dirent => {
1743
- return dirent.depth === 1;
1744
- };
1745
-
1746
1762
  const orderDirents = dirents => {
1747
1763
  if (dirents.length === 0) {
1748
1764
  return dirents;
1749
1765
  }
1766
+ const minDepth = Math.min(...dirents.map(dirent => dirent.depth));
1750
1767
  const withDeepChildren = (parent, processed) => {
1751
1768
  if (processed.has(parent.path)) {
1752
1769
  return [];
@@ -1760,7 +1777,7 @@ const orderDirents = dirents => {
1760
1777
  }
1761
1778
  return [parent, ...children];
1762
1779
  };
1763
- const topLevelDirents = dirents.filter(isTopLevel);
1780
+ const topLevelDirents = dirents.filter(dirent => dirent.depth === minDepth);
1764
1781
  const processed = new Set();
1765
1782
  const ordered = topLevelDirents.flatMap(dirent => withDeepChildren(dirent, processed));
1766
1783
  return ordered;
@@ -1981,7 +1998,7 @@ const validateFileName2 = (name, siblingFileNames = []) => {
1981
1998
  }
1982
1999
 
1983
2000
  // Disallow reserved directory names
1984
- if (name === '.' || name === '..' || name === '...') {
2001
+ if (['.', '..', '...'].includes(name)) {
1985
2002
  return theNameIsNotValid();
1986
2003
  }
1987
2004
 
@@ -2060,14 +2077,23 @@ const computeExplorerRenamedDirentUpdate = (root, parentPath, oldUri, children,
2060
2077
  const relativeOldPath = oldUri.slice(rootLength);
2061
2078
  const relativeNewUri = newUri.slice(rootLength);
2062
2079
  const update = Object.create(null);
2063
- update[relativeDirname] = children;
2064
2080
  const oldItems = tree[relativeOldPath] || [];
2081
+ update[relativeDirname] = children.map(child => {
2082
+ if (oldItems.length > 0 && child.path === newUri && child.type === Directory) {
2083
+ return {
2084
+ ...child,
2085
+ type: DirectoryExpanded
2086
+ };
2087
+ }
2088
+ return child;
2089
+ });
2065
2090
  update[relativeNewUri] = oldItems;
2066
2091
  for (const [key, value] of Object.entries(tree)) {
2067
- if (key.startsWith(`${relativeOldPath}/`)) {
2068
- const newKey = `${relativeNewUri}` + key.slice(relativeOldPath.length);
2069
- update[newKey] = value;
2092
+ if (!key.startsWith(`${relativeOldPath}/`)) {
2093
+ continue;
2070
2094
  }
2095
+ const newKey = relativeNewUri + key.slice(relativeOldPath.length);
2096
+ update[newKey] = value;
2071
2097
  }
2072
2098
  return update;
2073
2099
  };
@@ -2244,6 +2270,10 @@ const cancelTypeAhead = state => {
2244
2270
  };
2245
2271
  };
2246
2272
 
2273
+ const isTopLevel = dirent => {
2274
+ return dirent.depth === 1;
2275
+ };
2276
+
2247
2277
  const toCollapsedDirent = dirent => {
2248
2278
  if (dirent.type === DirectoryExpanded) {
2249
2279
  return {
@@ -2384,7 +2414,7 @@ const getPaths = items => {
2384
2414
  };
2385
2415
 
2386
2416
  const getSimpleIconRequestType = direntType => {
2387
- if (direntType === Directory || direntType === DirectoryExpanded || direntType === EditingDirectoryExpanded || direntType === EditingFolder) {
2417
+ if ([Directory, DirectoryExpanded, EditingDirectoryExpanded, EditingFolder].includes(direntType)) {
2388
2418
  return 2;
2389
2419
  }
2390
2420
  return 1;
@@ -2625,12 +2655,12 @@ const getChildrenWithCount = (nodes, startIndex, childCount) => {
2625
2655
  };
2626
2656
 
2627
2657
  const compareNodes = (oldNode, newNode) => {
2628
- const patches = [];
2629
2658
  // Check if node type changed - return null to signal incompatible nodes
2630
2659
  // (caller should handle this with a Replace operation)
2631
2660
  if (oldNode.type !== newNode.type) {
2632
2661
  return null;
2633
2662
  }
2663
+ const patches = [];
2634
2664
  // Handle reference nodes - special handling for uid changes
2635
2665
  if (oldNode.type === Reference) {
2636
2666
  if (oldNode.uid !== newNode.uid) {
@@ -2666,7 +2696,7 @@ const compareNodes = (oldNode, newNode) => {
2666
2696
  }
2667
2697
  // Check for removed attributes
2668
2698
  for (const key of oldKeys) {
2669
- if (!(key in newNode)) {
2699
+ if (!Object.hasOwn(newNode, key)) {
2670
2700
  patches.push({
2671
2701
  type: RemoveAttribute,
2672
2702
  key
@@ -2684,11 +2714,78 @@ const treeToArray = node => {
2684
2714
  return result;
2685
2715
  };
2686
2716
 
2717
+ const navigateToChild = (patches, currentChildIndex, index) => {
2718
+ if (currentChildIndex === -1) {
2719
+ patches.push({
2720
+ type: NavigateChild,
2721
+ index
2722
+ });
2723
+ return index;
2724
+ }
2725
+ if (currentChildIndex !== index) {
2726
+ patches.push({
2727
+ type: NavigateSibling,
2728
+ index
2729
+ });
2730
+ }
2731
+ return index;
2732
+ };
2733
+ const navigateToParent = (patches, currentChildIndex) => {
2734
+ if (currentChildIndex >= 0) {
2735
+ patches.push({
2736
+ type: NavigateParent
2737
+ });
2738
+ }
2739
+ return -1;
2740
+ };
2741
+ const addTree = (newNode, patches) => {
2742
+ patches.push({
2743
+ type: Add,
2744
+ nodes: treeToArray(newNode)
2745
+ });
2746
+ };
2747
+ const replaceTree = (newNode, patches) => {
2748
+ patches.push({
2749
+ type: Replace,
2750
+ nodes: treeToArray(newNode)
2751
+ });
2752
+ };
2753
+ const diffExistingChild = (oldNode, newNode, patches, currentChildIndex, index) => {
2754
+ const nodePatches = compareNodes(oldNode.node, newNode.node);
2755
+ if (nodePatches === null) {
2756
+ const nextChildIndex = navigateToChild(patches, currentChildIndex, index);
2757
+ replaceTree(newNode, patches);
2758
+ return nextChildIndex;
2759
+ }
2760
+ const hasChildrenToCompare = oldNode.children.length > 0 || newNode.children.length > 0;
2761
+ if (nodePatches.length === 0 && !hasChildrenToCompare) {
2762
+ return currentChildIndex;
2763
+ }
2764
+ const nextChildIndex = navigateToChild(patches, currentChildIndex, index);
2765
+ if (nodePatches.length > 0) {
2766
+ patches.push(...nodePatches);
2767
+ }
2768
+ if (hasChildrenToCompare) {
2769
+ diffChildren(oldNode.children, newNode.children, patches);
2770
+ }
2771
+ return nextChildIndex;
2772
+ };
2773
+ const diffRootNode = (oldNode, newNode, patches) => {
2774
+ const nodePatches = compareNodes(oldNode.node, newNode.node);
2775
+ if (nodePatches === null) {
2776
+ replaceTree(newNode, patches);
2777
+ return;
2778
+ }
2779
+ if (nodePatches.length > 0) {
2780
+ patches.push(...nodePatches);
2781
+ }
2782
+ if (oldNode.children.length > 0 || newNode.children.length > 0) {
2783
+ diffChildren(oldNode.children, newNode.children, patches);
2784
+ }
2785
+ };
2687
2786
  const diffChildren = (oldChildren, newChildren, patches) => {
2688
2787
  const maxLength = Math.max(oldChildren.length, newChildren.length);
2689
- // Track where we are: -1 means at parent, >= 0 means at child index
2690
2788
  let currentChildIndex = -1;
2691
- // Collect indices of children to remove (we'll add these patches at the end in reverse order)
2692
2789
  const indicesToRemove = [];
2693
2790
  for (let i = 0; i < maxLength; i++) {
2694
2791
  const oldNode = oldChildren[i];
@@ -2697,88 +2794,17 @@ const diffChildren = (oldChildren, newChildren, patches) => {
2697
2794
  continue;
2698
2795
  }
2699
2796
  if (!oldNode) {
2700
- // Add new node - we should be at the parent
2701
- if (currentChildIndex >= 0) {
2702
- // Navigate back to parent
2703
- patches.push({
2704
- type: NavigateParent
2705
- });
2706
- currentChildIndex = -1;
2707
- }
2708
- // Flatten the entire subtree so renderInternal can handle it
2709
- const flatNodes = treeToArray(newNode);
2710
- patches.push({
2711
- type: Add,
2712
- nodes: flatNodes
2713
- });
2714
- } else if (newNode) {
2715
- // Compare nodes to see if we need any patches
2716
- const nodePatches = compareNodes(oldNode.node, newNode.node);
2717
- // If nodePatches is null, the node types are incompatible - need to replace
2718
- if (nodePatches === null) {
2719
- // Navigate to this child
2720
- if (currentChildIndex === -1) {
2721
- patches.push({
2722
- type: NavigateChild,
2723
- index: i
2724
- });
2725
- currentChildIndex = i;
2726
- } else if (currentChildIndex !== i) {
2727
- patches.push({
2728
- type: NavigateSibling,
2729
- index: i
2730
- });
2731
- currentChildIndex = i;
2732
- }
2733
- // Replace the entire subtree
2734
- const flatNodes = treeToArray(newNode);
2735
- patches.push({
2736
- type: Replace,
2737
- nodes: flatNodes
2738
- });
2739
- // After replace, we're at the new element (same position)
2740
- continue;
2741
- }
2742
- // Check if we need to recurse into children
2743
- const hasChildrenToCompare = oldNode.children.length > 0 || newNode.children.length > 0;
2744
- // Only navigate to this element if we need to do something
2745
- if (nodePatches.length > 0 || hasChildrenToCompare) {
2746
- // Navigate to this child if not already there
2747
- if (currentChildIndex === -1) {
2748
- patches.push({
2749
- type: NavigateChild,
2750
- index: i
2751
- });
2752
- currentChildIndex = i;
2753
- } else if (currentChildIndex !== i) {
2754
- patches.push({
2755
- type: NavigateSibling,
2756
- index: i
2757
- });
2758
- currentChildIndex = i;
2759
- }
2760
- // Apply node patches (these apply to the current element, not children)
2761
- if (nodePatches.length > 0) {
2762
- patches.push(...nodePatches);
2763
- }
2764
- // Compare children recursively
2765
- if (hasChildrenToCompare) {
2766
- diffChildren(oldNode.children, newNode.children, patches);
2767
- }
2768
- }
2769
- } else {
2770
- // Remove old node - collect the index for later removal
2797
+ currentChildIndex = navigateToParent(patches, currentChildIndex);
2798
+ addTree(newNode, patches);
2799
+ continue;
2800
+ }
2801
+ if (!newNode) {
2771
2802
  indicesToRemove.push(i);
2803
+ continue;
2772
2804
  }
2805
+ currentChildIndex = diffExistingChild(oldNode, newNode, patches, currentChildIndex, i);
2773
2806
  }
2774
- // Navigate back to parent if we ended at a child
2775
- if (currentChildIndex >= 0) {
2776
- patches.push({
2777
- type: NavigateParent
2778
- });
2779
- }
2780
- // Add remove patches in reverse order (highest index first)
2781
- // This ensures indices remain valid as we remove
2807
+ navigateToParent(patches, currentChildIndex);
2782
2808
  for (let j = indicesToRemove.length - 1; j >= 0; j--) {
2783
2809
  patches.push({
2784
2810
  type: RemoveChild,
@@ -2787,33 +2813,11 @@ const diffChildren = (oldChildren, newChildren, patches) => {
2787
2813
  }
2788
2814
  };
2789
2815
  const diffTrees = (oldTree, newTree, patches, path) => {
2790
- // At the root level (path.length === 0), we're already AT the element
2791
- // So we compare the root node directly, then compare its children
2792
2816
  if (path.length === 0 && oldTree.length === 1 && newTree.length === 1) {
2793
- const oldNode = oldTree[0];
2794
- const newNode = newTree[0];
2795
- // Compare root nodes
2796
- const nodePatches = compareNodes(oldNode.node, newNode.node);
2797
- // If nodePatches is null, the root node types are incompatible - need to replace
2798
- if (nodePatches === null) {
2799
- const flatNodes = treeToArray(newNode);
2800
- patches.push({
2801
- type: Replace,
2802
- nodes: flatNodes
2803
- });
2804
- return;
2805
- }
2806
- if (nodePatches.length > 0) {
2807
- patches.push(...nodePatches);
2808
- }
2809
- // Compare children
2810
- if (oldNode.children.length > 0 || newNode.children.length > 0) {
2811
- diffChildren(oldNode.children, newNode.children, patches);
2812
- }
2813
- } else {
2814
- // Non-root level or multiple root elements - use the regular comparison
2815
- diffChildren(oldTree, newTree, patches);
2817
+ diffRootNode(oldTree[0], newTree[0], patches);
2818
+ return;
2816
2819
  }
2820
+ diffChildren(oldTree, newTree, patches);
2817
2821
  };
2818
2822
 
2819
2823
  const removeTrailingNavigationPatches = patches => {
@@ -2892,6 +2896,12 @@ const getVisibleExplorerItems = (items, minLineY, maxLineY, focusedIndex, editin
2892
2896
  for (let i = minLineY; i < Math.min(maxLineY, items.length); i++) {
2893
2897
  const item = items[i];
2894
2898
  let chevron = getChevronType(item.type, useChevrons);
2899
+ const isEditing = i === editingIndex;
2900
+ let icon = icons[iconIndex++];
2901
+ if (isEditing) {
2902
+ icon = editingIcon;
2903
+ chevron = getEditingChevron(item.type);
2904
+ }
2895
2905
  const isFocused = i === focusedIndex;
2896
2906
  const id = isFocused ? 'TreeItemActive' : undefined;
2897
2907
  const isSelected = item.selected;
@@ -2903,12 +2913,6 @@ const getVisibleExplorerItems = (items, minLineY, maxLineY, focusedIndex, editin
2903
2913
  const className = getTreeItemClassName(isSelected, isFocused, isDropping, useChevrons, indent, decoration);
2904
2914
  const expanded = getExpandedType(item.type);
2905
2915
  const ariaExpanded = ariaExpandedValues[expanded];
2906
- const isEditing = i === editingIndex;
2907
- let icon = icons[iconIndex++];
2908
- if (isEditing) {
2909
- icon = editingIcon;
2910
- chevron = getEditingChevron(item.type);
2911
- }
2912
2916
  visible.push({
2913
2917
  ...item,
2914
2918
  ariaExpanded,
@@ -2937,6 +2941,9 @@ const {
2937
2941
  set,
2938
2942
  wrapGetter
2939
2943
  } = create$a();
2944
+ const hasSameVisibleExplorerItemInputs = (oldState, newState) => {
2945
+ return oldState.items === newState.items && oldState.minLineY === newState.minLineY && oldState.height === newState.height && oldState.itemHeight === newState.itemHeight && oldState.focusedIndex === newState.focusedIndex && oldState.editingIndex === newState.editingIndex && oldState.editingIcon === newState.editingIcon && oldState.cutItems === newState.cutItems && oldState.editingErrorMessage === newState.editingErrorMessage && oldState.dropTargets === newState.dropTargets && oldState.fileIconCache === newState.fileIconCache && oldState.decorations === newState.decorations && oldState.useChevrons === newState.useChevrons && oldState.sourceControlIgnoredUris === newState.sourceControlIgnoredUris;
2946
+ };
2940
2947
  const wrapListItemCommand = fn => {
2941
2948
  const wrappedCommand = async (id, ...args) => {
2942
2949
  const {
@@ -2964,10 +2971,10 @@ const wrapListItemCommand = fn => {
2964
2971
  } = updatedState;
2965
2972
  const intermediate = get(id);
2966
2973
  set(id, intermediate.oldState, updatedState);
2967
- const maxLineY = getExplorerMaxLineY(minLineY, height, itemHeight, items.length);
2968
- if (items === intermediate.newState.items && minLineY === intermediate.newState.minLineY && height === intermediate.newState.height && itemHeight === intermediate.newState.itemHeight && editingIcon === intermediate.newState.editingIcon && cutItems === intermediate.newState.cutItems && editingErrorMessage === intermediate.newState.editingErrorMessage && dropTargets === intermediate.newState.dropTargets && fileIconCache === intermediate.newState.fileIconCache && decorations === intermediate.newState.decorations) {
2974
+ if (hasSameVisibleExplorerItemInputs(intermediate.newState, updatedState)) {
2969
2975
  return;
2970
2976
  }
2977
+ const maxLineY = getExplorerMaxLineY(minLineY, height, itemHeight, items.length);
2971
2978
  const visible = items.slice(minLineY, maxLineY);
2972
2979
  const {
2973
2980
  icons,
@@ -3139,25 +3146,26 @@ const expandAll = async state => {
3139
3146
  } = dirent;
3140
3147
  const newDirents = [...items];
3141
3148
  // TODO fetch child dirents in parallel
3142
- for (const dirent of newDirents) {
3143
- if (dirent.depth === depth && dirent.type === Directory) {
3144
- // TODO expand
3145
- // TODO avoid mutating state here
3146
- // @ts-ignore
3147
- dirent.type = DirectoryExpanding;
3148
- // TODO handle error
3149
- // TODO race condition
3150
- const childDirents = await getChildDirents(pathSeparator, dirent.path, dirent.depth);
3151
- const newIndex = newDirents.indexOf(dirent);
3152
- if (newIndex === -1) {
3153
- continue;
3154
- }
3155
- newDirents.splice(newIndex + 1, 0, ...childDirents);
3156
- // TODO avoid mutating state here
3157
- // @ts-ignore
3158
- dirent.type = DirectoryExpanded;
3159
- // await expand(state, dirent.index)
3149
+ for (const dirent of items) {
3150
+ if (dirent.depth !== depth || dirent.type !== Directory) {
3151
+ continue;
3160
3152
  }
3153
+ // TODO expand
3154
+ // TODO avoid mutating state here
3155
+ // @ts-ignore
3156
+ dirent.type = DirectoryExpanding;
3157
+ // TODO handle error
3158
+ // TODO race condition
3159
+ const childDirents = await getChildDirents(pathSeparator, dirent.path, dirent.depth);
3160
+ const newIndex = newDirents.indexOf(dirent);
3161
+ if (newIndex === -1) {
3162
+ continue;
3163
+ }
3164
+ newDirents.splice(newIndex + 1, 0, ...childDirents);
3165
+ // TODO avoid mutating state here
3166
+ // @ts-ignore
3167
+ dirent.type = DirectoryExpanded;
3168
+ // await expand(state, dirent.index)
3161
3169
  }
3162
3170
  return {
3163
3171
  ...state,
@@ -3316,11 +3324,7 @@ const lastIndex = array => {
3316
3324
  return array.length - 1;
3317
3325
  };
3318
3326
  const fromAsync = async asyncIterable => {
3319
- const children = [];
3320
- for await (const value of asyncIterable) {
3321
- children.push(value);
3322
- }
3323
- return children;
3327
+ return Array.fromAsync(asyncIterable);
3324
3328
  };
3325
3329
 
3326
3330
  const focusLast = state => {
@@ -3845,7 +3849,7 @@ const OpenFolder = 'OpenFolder';
3845
3849
  const Refresh$1 = 'Refresh';
3846
3850
 
3847
3851
  const isFolder = direntType => {
3848
- return direntType === Directory || direntType === DirectoryExpanded || direntType === SymLinkFolder;
3852
+ return [Directory, DirectoryExpanded, SymLinkFolder].includes(direntType);
3849
3853
  };
3850
3854
  const getFittingIndex = (dirents, startIndex) => {
3851
3855
  for (let i = startIndex; i >= 0; i--) {
@@ -4320,12 +4324,19 @@ const handleContextMenuAtIndex = async (state, index, x, y) => {
4320
4324
  number(x);
4321
4325
  number(y);
4322
4326
  const {
4327
+ items,
4323
4328
  uid
4324
4329
  } = state;
4330
+ const contextMenuItem = items[index];
4331
+ const newItems = contextMenuItem && !contextMenuItem.selected ? items.map(item => ({
4332
+ ...item,
4333
+ selected: false
4334
+ })) : items;
4325
4335
  const newState = {
4326
4336
  ...state,
4327
4337
  focused: false,
4328
- focusedIndex: index
4338
+ focusedIndex: index,
4339
+ items: newItems
4329
4340
  };
4330
4341
  set(uid, state, newState);
4331
4342
  await show2(uid, Explorer, x, y, {
@@ -4386,6 +4397,7 @@ const handleCopy = async state => {
4386
4397
  await writeNativeFiles('copy', files);
4387
4398
  return {
4388
4399
  ...state,
4400
+ cutItems: [],
4389
4401
  pasteShouldMove: false
4390
4402
  };
4391
4403
  };
@@ -4874,11 +4886,7 @@ const getDroppedName = item => {
4874
4886
  return item.name;
4875
4887
  };
4876
4888
  const getFileSystemHandlesNormalized = fileSystemHandles => {
4877
- const normalized = [];
4878
- for (const item of fileSystemHandles) {
4879
- normalized.push(getFileSystemHandle(item));
4880
- }
4881
- return normalized;
4889
+ return Array.from(fileSystemHandles, getFileSystemHandle);
4882
4890
  };
4883
4891
  const uploadFileSystemHandles = async (root, pathSeparator, fileSystemHandles) => {
4884
4892
  if (fileSystemHandles.length === 0) {
@@ -5258,7 +5266,7 @@ const isAscii = key => {
5258
5266
  return RE_ASCII.test(key);
5259
5267
  };
5260
5268
 
5261
- let timeout;
5269
+ const typeAheadTimeout = {};
5262
5270
  const handleKeyDown = (state, key) => {
5263
5271
  const {
5264
5272
  focusedIndex,
@@ -5275,10 +5283,10 @@ const handleKeyDown = (state, key) => {
5275
5283
  const newFocusWord = focusWord + key.toLowerCase();
5276
5284
  const itemNames = items.map(item => item.name);
5277
5285
  const matchingIndex = filterByFocusWord(itemNames, focusedIndex, newFocusWord);
5278
- if (timeout) {
5279
- clearTimeout(timeout);
5286
+ if (typeAheadTimeout.value) {
5287
+ clearTimeout(typeAheadTimeout.value);
5280
5288
  }
5281
- timeout = setTimeout(async () => {
5289
+ typeAheadTimeout.value = setTimeout(async () => {
5282
5290
  await invoke$2('Explorer.cancelTypeAhead');
5283
5291
  }, focusWordTimeout);
5284
5292
  if (matchingIndex === -1) {
@@ -5601,13 +5609,14 @@ const handleUpload = async (state, dirents) => {
5601
5609
  // TODO switch
5602
5610
  // TODO symlink might not be possible to be copied
5603
5611
  // TODO create folder if type is 2
5604
- if (dirent.type === /* File */1) {
5605
- // TODO reading text might be inefficient for binary files
5606
- // but not sure how else to send them via jsonrpc
5607
- const content = await dirent.file.text();
5608
- const absolutePath = [root, dirent.file.name].join(pathSeparator);
5609
- await writeFile(absolutePath, content);
5612
+ if (dirent.type !== /* File */1) {
5613
+ continue;
5610
5614
  }
5615
+ // TODO reading text might be inefficient for binary files
5616
+ // but not sure how else to send them via jsonrpc
5617
+ const content = await dirent.file.text();
5618
+ const absolutePath = [root, dirent.file.name].join(pathSeparator);
5619
+ await writeFile(absolutePath, content);
5611
5620
  }
5612
5621
  };
5613
5622
 
@@ -5667,7 +5676,7 @@ const getContainingFolder = (root, dirents, focusedIndex, pathSeparator) => {
5667
5676
  const dirent = dirents[focusedIndex];
5668
5677
  const direntPath = dirent.path;
5669
5678
  const direntParentPath = direntPath.slice(0, -(dirent.name.length + 1));
5670
- const path = `${direntParentPath}`;
5679
+ const path = direntParentPath;
5671
5680
  return path;
5672
5681
  };
5673
5682
 
@@ -5690,7 +5699,7 @@ const confirmDelete = async paths => {
5690
5699
  // TODO use i18n string
5691
5700
  const message = paths.length === 1 ? `Are you sure you want to delete "${paths[0]}"?` : `Are you sure you want to delete ${paths.length} items?`;
5692
5701
  const result = await confirm(message);
5693
- return result === true;
5702
+ return result;
5694
5703
  };
5695
5704
 
5696
5705
  const showErrorAlert = async errorMessage => {
@@ -5893,7 +5902,7 @@ const getDragLabel = urls => {
5893
5902
  if (urls.length === 1) {
5894
5903
  return getBaseName('/', urls[0]);
5895
5904
  }
5896
- return `${urls.length}`;
5905
+ return String(urls.length);
5897
5906
  };
5898
5907
 
5899
5908
  const toUri = path => {
@@ -6633,7 +6642,17 @@ const revealItemHidden = async (state, uri) => {
6633
6642
  const pathPartsChildrenFlat = pathPartsChildren.flat();
6634
6643
  const orderedPathParts = orderDirents(pathPartsChildrenFlat);
6635
6644
  const mergedDirents = mergeVisibleWithHiddenItems(items, orderedPathParts);
6636
- const index = getIndex(mergedDirents, uri);
6645
+ const expandedPaths = new Set(pathPartsToReveal.map(pathPart => pathPart.path));
6646
+ const newDirents = mergedDirents.map(item => {
6647
+ if (expandedPaths.has(item.path) && item.type === Directory) {
6648
+ return {
6649
+ ...item,
6650
+ type: DirectoryExpanded
6651
+ };
6652
+ }
6653
+ return item;
6654
+ });
6655
+ const index = getIndex(newDirents, uri);
6637
6656
  if (index === -1) {
6638
6657
  throw new Error(`File not found in explorer ${uri}`);
6639
6658
  }
@@ -6645,7 +6664,7 @@ const revealItemHidden = async (state, uri) => {
6645
6664
  ...state,
6646
6665
  focused: true,
6647
6666
  focusedIndex: index,
6648
- items: mergedDirents,
6667
+ items: newDirents,
6649
6668
  maxLineY: newMaxLineY,
6650
6669
  minLineY: newMinLineY
6651
6670
  };
@@ -6709,6 +6728,8 @@ const saveState = state => {
6709
6728
  };
6710
6729
  };
6711
6730
 
6731
+ // TODO select all should only select all items in the current folder
6732
+ // and when calling it next item, expand selection to its parent folder
6712
6733
  const selectAll = state => {
6713
6734
  const {
6714
6735
  items
@@ -6810,7 +6831,7 @@ const getEditingIcon = async (editingType, value, direntType) => {
6810
6831
  name: value
6811
6832
  });
6812
6833
  }
6813
- if (direntType === Directory || direntType === EditingFolder || direntType === EditingDirectoryExpanded) {
6834
+ if (direntType !== undefined && [Directory, EditingFolder, EditingDirectoryExpanded].includes(direntType)) {
6814
6835
  return invoke$2('IconTheme.getFolderIcon', {
6815
6836
  name: value
6816
6837
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/explorer-view",
3
- "version": "6.11.0",
3
+ "version": "6.14.0",
4
4
  "description": "Explorer Worker",
5
5
  "repository": {
6
6
  "type": "git",