@lvce-editor/explorer-view 2.33.0 → 2.34.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.
@@ -1378,6 +1378,12 @@ const join = (pathSeparator, ...parts) => {
1378
1378
  const getBaseName = (pathSeparator, path) => {
1379
1379
  return path.slice(path.lastIndexOf(pathSeparator) + 1);
1380
1380
  };
1381
+ const join2 = (path, childPath) => {
1382
+ if (path.endsWith('/')) {
1383
+ return `${path}${childPath}`;
1384
+ }
1385
+ return `${path}/${childPath}`;
1386
+ };
1381
1387
 
1382
1388
  const acceptRename = async state => {
1383
1389
  const {
@@ -2033,6 +2039,16 @@ const expandRecursively = async state => {
2033
2039
  };
2034
2040
  };
2035
2041
 
2042
+ const focus = state => {
2043
+ if (state.focus) {
2044
+ return state;
2045
+ }
2046
+ return {
2047
+ ...state,
2048
+ focus: List
2049
+ };
2050
+ };
2051
+
2036
2052
  const focusIndex = (state, index) => {
2037
2053
  const {
2038
2054
  minLineY,
@@ -2154,7 +2170,7 @@ const focusPrevious = state => {
2154
2170
  }
2155
2171
  };
2156
2172
 
2157
- const commandIds = ['acceptEdit', 'cancelEdit', 'collapseAll', 'copyPath', 'copyRelativePath', 'dispose', 'expandAll', 'expandRecursively', 'focus', 'focusFirst', 'focusIndex', 'focusLast', 'focusNext', 'focusNone', 'focusPrevious', 'getFocusedDirent', 'getMenuEntries2', 'getMouseActions', 'handleArrowLeft', 'handleArrowLeft', 'handleArrowRight', 'handleArrowRight', 'handleBlur', 'handleClick', 'handleClickAt', 'handleClickCurrent', 'handleClickCurrentButKeepFocus', 'handleClickOpenFolder', 'handleContextMenu', 'handleContextMenuKeyboard', 'handleCopy', 'handleDragLeave', 'handleDragOver', 'handleDrop', 'handleFocus', 'handleIconThemeChange', 'handleInputBlur', 'handleInputClick', 'handleLanguagesChanged', 'handleMouseEnter', 'handleMouseLeave', 'handlePaste', 'handlePointerDown', 'handleUpload', 'handleWheel', 'handleWorkspaceChange', 'hotReload', 'newFile', 'newFolder', 'openContainingFolder', 'refresh', 'removeDirent', 'rename', 'renameDirent', 'renderEventListeners', 'revealItem', 'revealItem', 'scrollDown', 'scrollUp', 'selectAll', 'selectDown', 'selectUp', 'setDeltaY', 'setSelectedIndices', 'cancelTypeAhead', 'updateEditingValue', 'handleKeyDown', 'updateIcons'];
2173
+ const commandIds = ['acceptEdit', 'cancelEdit', 'collapseAll', 'copyPath', 'copyRelativePath', 'dispose', 'expandAll', 'expandRecursively', 'focus', 'focusFirst', 'focusIndex', 'focusLast', 'focusNext', 'focusNone', 'handleInputKeyDown', 'focusPrevious', 'getFocusedDirent', 'getMenuEntries2', 'getMouseActions', 'handleArrowLeft', 'handleArrowLeft', 'handleArrowRight', 'handleArrowRight', 'handleBlur', 'handleClick', 'handleClickAt', 'handleClickCurrent', 'handleClickCurrentButKeepFocus', 'handleClickOpenFolder', 'handleContextMenu', 'handleContextMenuKeyboard', 'handleCopy', 'handleDragLeave', 'handleDragOver', 'handleDrop', 'handleFocus', 'handleIconThemeChange', 'handleInputBlur', 'handleInputClick', 'handleLanguagesChanged', 'handleMouseEnter', 'handleMouseLeave', 'handlePaste', 'handlePointerDown', 'handleUpload', 'handleWheel', 'handleWorkspaceChange', 'hotReload', 'newFile', 'newFolder', 'openContainingFolder', 'refresh', 'removeDirent', 'rename', 'renameDirent', 'renderEventListeners', 'revealItem', 'revealItem', 'scrollDown', 'scrollUp', 'selectAll', 'selectDown', 'selectUp', 'setDeltaY', 'setSelectedIndices', 'cancelTypeAhead', 'updateEditingValue', 'handleKeyDown', 'updateIcons'];
2158
2174
 
2159
2175
  const getCommandIds = () => {
2160
2176
  return commandIds;
@@ -2461,7 +2477,7 @@ const handleClickDirectoryExpanded = async (state, dirent, index, keepFocus) =>
2461
2477
  const newMaxLineY = Math.min(maxLineY, newTotal);
2462
2478
  const newMinLineY = newMaxLineY - visibleItems;
2463
2479
  const deltaY = newMinLineY * itemHeight;
2464
- const parts = newDirents.slice(minLineY, maxLineY);
2480
+ const parts = newDirents.slice(newMinLineY, newMaxLineY);
2465
2481
  const {
2466
2482
  icons,
2467
2483
  newFileIconCache
@@ -2993,36 +3009,63 @@ const getExpandedDirents = items => {
2993
3009
  return items.filter(isExpanded);
2994
3010
  };
2995
3011
 
2996
- const refreshChildDirent = async (folder, dirent, pathSeparator, expandedFolders) => {
2997
- const path = folder.path.endsWith(pathSeparator) ? `${folder.path}${dirent.name}` : `${folder.path}${pathSeparator}${dirent.name}`;
2998
- const isExpandedFolder = expandedFolders.includes(path);
2999
- const type = dirent.type === 'directory' ? isExpandedFolder ? DirectoryExpanded : Directory : File;
3000
- const item = {
3001
- name: dirent.name,
3002
- type,
3003
- path,
3004
- depth: folder.depth + 1,
3005
- selected: false
3006
- };
3007
- if (isExpandedFolder) {
3008
- const nestedItems = await refreshChildDirents(item, pathSeparator, expandedFolders);
3009
- return [item, ...nestedItems];
3012
+ const getPathDirentsMap = async allPaths => {
3013
+ const pathToDirents = Object.create(null);
3014
+ await Promise.all(allPaths.map(async path => {
3015
+ const dirents = await readDirWithFileTypes(path);
3016
+ pathToDirents[path] = dirents;
3017
+ }));
3018
+ return pathToDirents;
3019
+ };
3020
+
3021
+ const restoreDirentType = (rawDirentType, path, expandedPaths) => {
3022
+ if (rawDirentType === Directory && expandedPaths.includes(path)) {
3023
+ return DirectoryExpanded;
3010
3024
  }
3011
- return [item];
3025
+ return rawDirentType;
3012
3026
  };
3013
- const refreshChildDirents = async (folder, pathSeparator, expandedFolders) => {
3014
- const childDirents = await readDirWithFileTypes(folder.path);
3015
- const childItems = await Promise.all(childDirents.map(async dirent => {
3016
- return refreshChildDirent(folder, dirent, pathSeparator, expandedFolders);
3017
- }));
3018
- return childItems.flat();
3027
+
3028
+ const getProtoMapInternal = (root, pathToDirents, expandedPaths, depth) => {
3029
+ if (!(root in pathToDirents)) {
3030
+ return [];
3031
+ }
3032
+ const items = pathToDirents[root] || [];
3033
+ const protoMap = [];
3034
+ for (let i = 0; i < items.length; i++) {
3035
+ const item = items[i];
3036
+ const path = join2(root, item.name);
3037
+ const displayDirent = {
3038
+ name: item.name,
3039
+ posInSet: i + 1,
3040
+ setSize: items.length,
3041
+ depth,
3042
+ type: restoreDirentType(item.type, path, expandedPaths),
3043
+ path,
3044
+ icon: '',
3045
+ selected: false
3046
+ };
3047
+ const children = getProtoMapInternal(path, pathToDirents, expandedPaths, depth + 1);
3048
+ protoMap.push(displayDirent, ...children);
3049
+ }
3050
+ return protoMap;
3051
+ };
3052
+
3053
+ const getProtoMap = (root, pathToDirents, expandedPaths) => {
3054
+ return getProtoMapInternal(root, pathToDirents, expandedPaths, 1);
3055
+ };
3056
+
3057
+ const sortPathDirentsMap = map => {
3058
+ const sortedMap = Object.create(null);
3059
+ for (const [key, value] of Object.entries(map)) {
3060
+ const sorted = sortExplorerItems(value);
3061
+ sortedMap[key] = sorted;
3062
+ }
3063
+ return sortedMap;
3019
3064
  };
3020
3065
 
3021
- // TODO add lots of tests for this
3022
3066
  const refresh = async state => {
3023
3067
  const {
3024
3068
  root,
3025
- pathSeparator,
3026
3069
  minLineY,
3027
3070
  height,
3028
3071
  itemHeight,
@@ -3030,64 +3073,25 @@ const refresh = async state => {
3030
3073
  items,
3031
3074
  focusedIndex
3032
3075
  } = state;
3033
-
3034
- // Get all expanded folders
3035
3076
  const expandedDirents = getExpandedDirents(items);
3036
- const expandedFolders = getPaths(expandedDirents);
3037
-
3038
- // Get top level dirents
3039
- const topLevelDirents = await readDirWithFileTypes(root);
3040
- const newDirents = topLevelDirents.map(dirent => ({
3041
- name: dirent.name,
3042
- type: dirent.type === 'directory' ? Directory : File,
3043
- path: root.endsWith(pathSeparator) ? `${root}${dirent.name}` : `${root}${pathSeparator}${dirent.name}`,
3044
- depth: 0,
3045
- selected: false
3046
- }));
3047
-
3048
- // Process expanded folders in parallel
3049
- const expandedFolderResults = await Promise.all(expandedFolders.map(async folderPath => {
3050
- const folderIndex = newDirents.findIndex(item => item.path === folderPath);
3051
- if (folderIndex !== -1) {
3052
- const folder = newDirents[folderIndex];
3053
- if (folder.type === Directory) {
3054
- const childItems = await refreshChildDirents(folder, pathSeparator, expandedFolders);
3055
- // @ts-ignore
3056
- folder.type = DirectoryExpanded;
3057
- return {
3058
- folderIndex,
3059
- childItems
3060
- };
3061
- }
3062
- }
3063
- return null;
3064
- }));
3065
-
3066
- // Insert child items in the correct order
3067
- let offset = 0;
3068
- for (const result of expandedFolderResults) {
3069
- if (result) {
3070
- const {
3071
- folderIndex,
3072
- childItems
3073
- } = result;
3074
- newDirents.splice(folderIndex + 1 + offset, 0, ...childItems);
3075
- offset += childItems.length;
3076
- }
3077
- }
3078
- const maxLineY = getExplorerMaxLineY(minLineY, height, itemHeight, newDirents.length);
3079
- const visible = newDirents.slice(minLineY, maxLineY);
3077
+ const expandedPaths = getPaths(expandedDirents);
3078
+ const allPaths = [root, ...expandedPaths];
3079
+ const pathToDirents = await getPathDirentsMap(allPaths);
3080
+ const sortedPathDirents = sortPathDirentsMap(pathToDirents);
3081
+ const newItems = getProtoMap(root, sortedPathDirents, expandedPaths);
3082
+ const maxLineY = getExplorerMaxLineY(minLineY, height, itemHeight, newItems.length);
3083
+ const visible = newItems.slice(minLineY, maxLineY);
3080
3084
  const {
3081
3085
  icons,
3082
3086
  newFileIconCache
3083
3087
  } = await getFileIcons(visible, fileIconCache);
3084
3088
  let newFocusedIndex = focusedIndex;
3085
- if (focusedIndex >= newDirents.length) {
3086
- newFocusedIndex = newDirents.length - 1;
3089
+ if (focusedIndex >= newItems.length) {
3090
+ newFocusedIndex = newItems.length - 1;
3087
3091
  }
3088
3092
  return {
3089
3093
  ...state,
3090
- items: newDirents,
3094
+ items: newItems,
3091
3095
  fileIconCache: newFileIconCache,
3092
3096
  icons,
3093
3097
  maxLineY,
@@ -3155,18 +3159,18 @@ const getFileOperations = (root, uploadTree) => {
3155
3159
  const operations = [];
3156
3160
  const processTree = (tree, currentPath) => {
3157
3161
  for (const [path, value] of Object.entries(tree)) {
3158
- const fullPath = currentPath ? `${currentPath}/${path}` : path;
3162
+ const fullPath = currentPath ? join2(currentPath, path) : path;
3159
3163
  if (typeof value === 'object') {
3160
3164
  operations.push({
3161
3165
  type: 'createFolder',
3162
- path: `${root}/${fullPath}`,
3166
+ path: join2(root, fullPath),
3163
3167
  text: ''
3164
3168
  });
3165
3169
  processTree(value, fullPath);
3166
3170
  } else if (typeof value === 'string') {
3167
3171
  operations.push({
3168
3172
  type: 'createFile',
3169
- path: `${root}/${fullPath}`,
3173
+ path: join2(root, fullPath),
3170
3174
  text: value
3171
3175
  });
3172
3176
  }
@@ -3232,7 +3236,7 @@ const getFileOperationsElectron = async (root, paths, fileHandles) => {
3232
3236
  const path = paths[i];
3233
3237
  operations.push({
3234
3238
  type: 'copy',
3235
- path: `${root}/${name}`,
3239
+ path: join2(root, name),
3236
3240
  text: '',
3237
3241
  from: path
3238
3242
  });
@@ -3440,6 +3444,10 @@ const handleInputClick = state => {
3440
3444
  return state;
3441
3445
  };
3442
3446
 
3447
+ const handleInputKeyDown = (state, key) => {
3448
+ return state;
3449
+ };
3450
+
3443
3451
  const filterByFocusWord = (items, focusedIndex, focusWord) => {
3444
3452
  if (items.length === 0) {
3445
3453
  return -1;
@@ -3888,7 +3896,7 @@ const getNewChildDirentsForNewDirent = async (items, depth, parentPath, direntTy
3888
3896
  existingChildren = childDirents.map((dirent, index) => ({
3889
3897
  name: dirent.name,
3890
3898
  type: dirent.type,
3891
- path: `${parentPath}/${dirent.name}`,
3899
+ path: join2(parentPath, dirent.name),
3892
3900
  depth,
3893
3901
  selected: false,
3894
3902
  posInSet: index + 1,
@@ -4684,11 +4692,18 @@ const renderEventListeners = () => {
4684
4692
  return [{
4685
4693
  name: HandleInputBlur,
4686
4694
  params: ['handleInputBlur']
4687
- }, {
4688
- name: HandleListKeyDown,
4689
- params: ['handleKeyDown', 'event.key'],
4690
- preventDefault: true
4691
- }, {
4695
+ },
4696
+ // {
4697
+ // name: DomEventListenersFunctions.HandleInputKeyDown,
4698
+ // params: ['handleInputKeyDown'],
4699
+ // stopPropagation: true, // TODO find a way to do this without stopPropagation
4700
+ // },
4701
+ // {
4702
+ // name: DomEventListenersFunctions.HandleListKeyDown,
4703
+ // params: ['handleKeyDown', 'event.key'],
4704
+ // preventDefault: true,
4705
+ // },
4706
+ {
4692
4707
  name: HandleListFocus,
4693
4708
  params: ['handleFocus', 'event.isTrusted', 'event.target.className']
4694
4709
  }, {
@@ -5088,14 +5103,14 @@ const updateEditingValue = async (state, value, inputSource = User) => {
5088
5103
 
5089
5104
  const commandMap = {
5090
5105
  'Explorer.acceptEdit': wrapCommand(acceptEdit),
5091
- 'Explorer.handleKeyDown': wrapCommand(handleKeyDown),
5092
- 'Explorer.cancelTypeAhead': wrapCommand(cancelTypeAhead),
5093
5106
  'Explorer.cancelEdit': wrapCommand(cancelEdit),
5107
+ 'Explorer.cancelTypeAhead': wrapCommand(cancelTypeAhead),
5094
5108
  'Explorer.collapseAll': wrapCommand(collapseAll),
5095
5109
  'Explorer.copyPath': wrapCommand(copyPath),
5096
5110
  'Explorer.copyRelativePath': wrapCommand(copyRelativePath),
5097
5111
  'Explorer.expandAll': wrapCommand(expandAll),
5098
5112
  'Explorer.expandRecursively': wrapCommand(expandRecursively),
5113
+ 'Explorer.focus': wrapCommand(focus),
5099
5114
  'Explorer.focusFirst': wrapCommand(focusFirst),
5100
5115
  'Explorer.focusIndex': wrapCommand(focusIndex),
5101
5116
  'Explorer.focusLast': wrapCommand(focusLast),
@@ -5123,6 +5138,8 @@ const commandMap = {
5123
5138
  'Explorer.handleIconThemeChange': wrapCommand(handleIconThemeChange),
5124
5139
  'Explorer.handleInputBlur': wrapCommand(handleInputBlur),
5125
5140
  'Explorer.handleInputClick': wrapCommand(handleInputClick),
5141
+ 'Explorer.handleInputKeyDown': wrapCommand(handleInputKeyDown),
5142
+ 'Explorer.handleKeyDown': wrapCommand(handleKeyDown),
5126
5143
  'Explorer.handlePaste': wrapCommand(handlePaste),
5127
5144
  'Explorer.handlePointerDown': wrapCommand(handlePointerDown),
5128
5145
  'Explorer.handleUpload': wrapCommand(handleUpload),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/explorer-view",
3
- "version": "2.33.0",
3
+ "version": "2.34.0",
4
4
  "description": "Explorer Worker",
5
5
  "repository": {
6
6
  "type": "git",