@lvce-editor/explorer-view 1.20.0 → 1.22.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.
@@ -779,12 +779,12 @@ const invokeAndTransfer = (ipc, method, ...params) => {
779
779
  return invokeHelper(ipc, method, params, true);
780
780
  };
781
781
 
782
- const commands = Object.create(null);
782
+ const commands$1 = Object.create(null);
783
783
  const register = commandMap => {
784
- Object.assign(commands, commandMap);
784
+ Object.assign(commands$1, commandMap);
785
785
  };
786
786
  const getCommand = key => {
787
- return commands[key];
787
+ return commands$1[key];
788
788
  };
789
789
  const execute = (command, ...args) => {
790
790
  const fn = getCommand(command);
@@ -1100,9 +1100,7 @@ const acceptCreate = async (state, newDirentType, createFn) => {
1100
1100
  return state;
1101
1101
  }
1102
1102
  const parentDirent = focusedIndex >= 0 ? state.items[focusedIndex] : {
1103
- depth: 0,
1104
- path: state.root
1105
- };
1103
+ depth: 0};
1106
1104
  const depth = parentDirent.depth + 1;
1107
1105
  const newDirent = {
1108
1106
  path: absolutePath,
@@ -1334,6 +1332,43 @@ const create = (id, uri, x, y, width, height, args, parentUid) => {
1334
1332
  return state;
1335
1333
  };
1336
1334
 
1335
+ const RenderItems = 4;
1336
+ const RenderEditingIndex = 5;
1337
+
1338
+ const diffType$1 = RenderEditingIndex;
1339
+ const isEqual$2 = (oldState, newState) => {
1340
+ return oldState.editingIndex === newState.editingIndex && oldState.editingType === newState.editingType;
1341
+ };
1342
+
1343
+ const DiffEditingIndex = {
1344
+ __proto__: null,
1345
+ diffType: diffType$1,
1346
+ isEqual: isEqual$2
1347
+ };
1348
+
1349
+ const diffType = RenderItems;
1350
+ const isEqual$1 = (oldState, newState) => {
1351
+ return oldState.items === newState.items && oldState.minLineY === newState.minLineY && oldState.maxLineY === newState.maxLineY && oldState.focusedIndex === newState.focusedIndex && oldState.editingIndex === newState.editingIndex && oldState.editingType === newState.editingType && oldState.editingValue === newState.editingValue && oldState.width === newState.width && oldState.focused === newState.focused;
1352
+ };
1353
+
1354
+ const DiffItems = {
1355
+ __proto__: null,
1356
+ diffType,
1357
+ isEqual: isEqual$1
1358
+ };
1359
+
1360
+ const modules = [DiffItems, DiffEditingIndex];
1361
+
1362
+ const diff = (oldState, newState) => {
1363
+ const diffResult = [];
1364
+ for (const module of modules) {
1365
+ if (!module.isEqual(oldState, newState)) {
1366
+ diffResult.push(module.diffType);
1367
+ }
1368
+ }
1369
+ return diffResult;
1370
+ };
1371
+
1337
1372
  const isSymbolicLink = dirent => {
1338
1373
  return dirent.type === Symlink;
1339
1374
  };
@@ -1853,6 +1888,11 @@ const getActions = root => {
1853
1888
  }];
1854
1889
  };
1855
1890
 
1891
+ const commands = ['acceptEdit', 'cancelEdit', 'collapseAll', 'copyPath', 'copyRelativePath', 'expandAll', 'expandRecursively', 'focus', 'focusFirst', 'focusIndex', 'focusLast', 'focusNext', 'focusNone', 'focusPrevious', 'getFocusedDirent', 'handleArrowLeft', 'handleArrowLeft', 'handleArrowRight', 'handleArrowRight', 'handleBlur', 'handleClick', 'handleClickAt', 'handleClickCurrent', 'handleClickCurrentButKeepFocus', 'handleClickOpenFolder', 'handleContextMenu', 'handleCopy', 'handleDragOver', 'handleDrop', 'handleFocus', 'handleIconThemeChange', 'handleLanguagesChanged', 'handleMouseEnter', 'handleMouseLeave', 'handlePaste', 'handlePointerDown', 'handleUpload', 'handleWheel', 'handleWorkspaceChange', 'hotReload', 'newFile', 'newFolder', 'openContainingFolder', 'refresh', 'refresh', 'relealItem', 'removeDirent', 'rename', 'renameDirent', 'revealItem', 'scrollDown', 'scrollUp', 'setDeltaY', 'updateEditingValue', 'updateIcons'];
1892
+ const getCommandIds = () => {
1893
+ return commands;
1894
+ };
1895
+
1856
1896
  const None$4 = 'none';
1857
1897
  const ToolBar = 'toolbar';
1858
1898
  const Tree = 'tree';
@@ -1892,7 +1932,7 @@ const WelcomeMessage = 'WelcomeMessage';
1892
1932
 
1893
1933
  const HandleBlur = 'handleBlur';
1894
1934
  const HandleClick = 'handleClick';
1895
- const handleClickOpenFolder$1 = 'handleClickOpenFolder';
1935
+ const HandleClickOpenFolder = 'handleClickOpenFolder';
1896
1936
  const HandleContextMenu = 'handleContextMenu';
1897
1937
  const HandleEditingInput = 'handleEditingInput';
1898
1938
  const HandleFocus = 'handleFocus';
@@ -2019,7 +2059,7 @@ const getExplorerWelcomeVirtualDom = isWide => {
2019
2059
  type: Button,
2020
2060
  className: mergeClassNames(Button$1, ButtonPrimary, isWide ? ButtonWide : ButtonNarrow),
2021
2061
  childCount: 1,
2022
- onClick: handleClickOpenFolder$1
2062
+ onClick: HandleClickOpenFolder
2023
2063
  }, text(openFolder$1())];
2024
2064
  };
2025
2065
 
@@ -2355,66 +2395,24 @@ const getVisibleExplorerItems = (items, minLineY, maxLineY, focusedIndex, editin
2355
2395
  return visible;
2356
2396
  };
2357
2397
 
2358
- const handleBlur = state => {
2359
- // TODO when blur event occurs because of context menu, focused index should stay the same
2360
- // but focus outline should be removed
2361
- const {
2362
- editingType
2363
- } = state;
2364
- if (editingType !== None$5) {
2365
- return state;
2398
+ const getParentStartIndex = (dirents, index) => {
2399
+ const dirent = dirents[index];
2400
+ let startIndex = index - 1;
2401
+ while (startIndex >= 0 && dirents[startIndex].depth >= dirent.depth) {
2402
+ startIndex--;
2366
2403
  }
2367
- return {
2368
- ...state,
2369
- focused: false
2370
- };
2404
+ return startIndex;
2371
2405
  };
2372
2406
 
2373
- const handleClickDirectory = async (state, dirent, index, keepFocus) => {
2374
- // @ts-ignore
2375
- dirent.type = DirectoryExpanding;
2376
- // TODO handle error
2377
- const dirents = await getChildDirents(state.pathSeparator, dirent);
2378
- const state2 = state;
2379
- if (!state2) {
2380
- return state;
2381
- }
2382
- // TODO use Viewlet.getState here and check if it exists
2383
- const newIndex = state2.items.indexOf(dirent);
2384
- // TODO if viewlet is disposed or root has changed, return
2385
- if (newIndex === -1) {
2407
+ const focusParentFolder = state => {
2408
+ const parentStartIndex = getParentStartIndex(state.items, state.focusedIndex);
2409
+ if (parentStartIndex === -1) {
2386
2410
  return state;
2387
2411
  }
2388
- const newDirents = [...state2.items];
2389
- newDirents.splice(newIndex + 1, 0, ...dirents);
2390
- // @ts-ignore
2391
- dirent.type = DirectoryExpanded;
2392
- // @ts-ignore
2393
- dirent.icon = getIcon();
2394
- const {
2395
- height,
2396
- itemHeight,
2397
- minLineY
2398
- } = state2;
2399
- // TODO when focused index has changed while expanding, don't update it
2400
- const maxLineY = getExplorerMaxLineY(minLineY, height, itemHeight, newDirents.length);
2401
- const parts = newDirents.slice(minLineY, maxLineY);
2402
- const {
2403
- icons,
2404
- newFileIconCache
2405
- } = await getFileIcons(parts, state.fileIconCache);
2406
- return {
2407
- ...state,
2408
- items: newDirents,
2409
- icons,
2410
- fileIconCache: newFileIconCache,
2411
- focusedIndex: newIndex,
2412
- focused: keepFocus,
2413
- maxLineY
2414
- };
2412
+ return focusIndex(state, parentStartIndex);
2415
2413
  };
2416
2414
 
2417
- const handleClickDirectoryExpanded$1 = async (state, dirent, index, keepFocus) => {
2415
+ const handleClickDirectoryExpanded = async (state, dirent, index, keepFocus) => {
2418
2416
  const {
2419
2417
  minLineY,
2420
2418
  maxLineY,
@@ -2468,15 +2466,84 @@ const handleClickDirectoryExpanded$1 = async (state, dirent, index, keepFocus) =
2468
2466
  };
2469
2467
  };
2470
2468
 
2471
- const handleClickDirectoryExpanding = async (state, dirent, index, keepFocus) => {
2469
+ const handleArrowLeft = state => {
2470
+ const {
2471
+ items,
2472
+ focusedIndex
2473
+ } = state;
2474
+ if (focusedIndex === -1) {
2475
+ return state;
2476
+ }
2477
+ const dirent = items[focusedIndex];
2478
+ switch (dirent.type) {
2479
+ case Directory:
2480
+ case File:
2481
+ case SymLinkFile:
2482
+ return focusParentFolder(state);
2483
+ case DirectoryExpanded:
2484
+ return handleClickDirectoryExpanded(state, dirent, focusedIndex, true);
2485
+ default:
2486
+ // TODO handle expanding directory and cancel file system call to read child dirents
2487
+ return state;
2488
+ }
2489
+ };
2490
+
2491
+ const handleArrowRightDirectoryExpanded = (state, dirent) => {
2492
+ const {
2493
+ items,
2494
+ focusedIndex
2495
+ } = state;
2496
+ if (focusedIndex === items.length - 1) {
2497
+ return state;
2498
+ }
2499
+ const nextDirent = items[focusedIndex + 1];
2500
+ if (nextDirent.depth === dirent.depth + 1) {
2501
+ return focusIndex(state, focusedIndex + 1);
2502
+ }
2503
+ return state;
2504
+ };
2505
+
2506
+ const handleClickDirectory = async (state, dirent, index, keepFocus) => {
2472
2507
  // @ts-ignore
2473
- dirent.type = Directory;
2508
+ dirent.type = DirectoryExpanding;
2509
+ // TODO handle error
2510
+ const dirents = await getChildDirents(state.pathSeparator, dirent);
2511
+ const state2 = state;
2512
+ if (!state2) {
2513
+ return state;
2514
+ }
2515
+ // TODO use Viewlet.getState here and check if it exists
2516
+ const newIndex = state2.items.indexOf(dirent);
2517
+ // TODO if viewlet is disposed or root has changed, return
2518
+ if (newIndex === -1) {
2519
+ return state;
2520
+ }
2521
+ const newDirents = [...state2.items];
2522
+ newDirents.splice(newIndex + 1, 0, ...dirents);
2523
+ // @ts-ignore
2524
+ dirent.type = DirectoryExpanded;
2474
2525
  // @ts-ignore
2475
2526
  dirent.icon = getIcon();
2527
+ const {
2528
+ height,
2529
+ itemHeight,
2530
+ minLineY
2531
+ } = state2;
2532
+ // TODO when focused index has changed while expanding, don't update it
2533
+ const maxLineY = getExplorerMaxLineY(minLineY, height, itemHeight, newDirents.length);
2534
+ const parts = newDirents.slice(minLineY, maxLineY);
2535
+ const {
2536
+ icons,
2537
+ newFileIconCache
2538
+ } = await getFileIcons(parts, state.fileIconCache);
2476
2539
  return {
2477
2540
  ...state,
2478
- focusedIndex: index,
2479
- focused: keepFocus
2541
+ items: newDirents,
2542
+ icons,
2543
+ fileIconCache: newFileIconCache,
2544
+ focusedIndex: newIndex,
2545
+ focused: keepFocus,
2546
+ maxLineY
2480
2547
  };
2481
2548
  };
2482
2549
 
@@ -2484,7 +2551,7 @@ const openUri = async (uri, focus) => {
2484
2551
  await invoke(/* Main.openAbsolutePath */'Main.openUri', /* absolutePath */uri, /* focus */focus);
2485
2552
  };
2486
2553
 
2487
- const handleClickFile$1 = async (state, dirent, index, keepFocus = false) => {
2554
+ const handleClickFile = async (state, dirent, index, keepFocus = false) => {
2488
2555
  await openUri(dirent.path, !keepFocus);
2489
2556
  return {
2490
2557
  ...state,
@@ -2493,17 +2560,70 @@ const handleClickFile$1 = async (state, dirent, index, keepFocus = false) => {
2493
2560
  };
2494
2561
  };
2495
2562
 
2496
- const handleClickSymLink$1 = async (state, dirent, index) => {
2563
+ const handleClickSymLink = async (state, dirent, index) => {
2497
2564
  const realPath = await getRealPath(dirent.path);
2498
2565
  const type = await stat(realPath);
2499
2566
  switch (type) {
2500
2567
  case File:
2501
- return handleClickFile$1(state, dirent, index);
2568
+ return handleClickFile(state, dirent, index);
2502
2569
  default:
2503
2570
  throw new Error(`unsupported file type ${type}`);
2504
2571
  }
2505
2572
  };
2506
2573
 
2574
+ const handleArrowRight = async state => {
2575
+ const {
2576
+ items,
2577
+ focusedIndex
2578
+ } = state;
2579
+ if (focusedIndex === -1) {
2580
+ return state;
2581
+ }
2582
+ const dirent = items[focusedIndex];
2583
+ switch (dirent.type) {
2584
+ case File:
2585
+ case SymLinkFile:
2586
+ return state;
2587
+ case Directory:
2588
+ case SymLinkFolder:
2589
+ // @ts-ignore
2590
+ return handleClickDirectory(state, dirent);
2591
+ case DirectoryExpanded:
2592
+ return handleArrowRightDirectoryExpanded(state, dirent);
2593
+ case Symlink:
2594
+ return handleClickSymLink(state, dirent, focusedIndex);
2595
+ default:
2596
+ throw new Error(`unsupported file type ${dirent.type}`);
2597
+ }
2598
+ };
2599
+
2600
+ const handleBlur = state => {
2601
+ // TODO when blur event occurs because of context menu, focused index should stay the same
2602
+ // but focus outline should be removed
2603
+ const {
2604
+ editingType
2605
+ } = state;
2606
+ if (editingType !== None$5) {
2607
+ return state;
2608
+ }
2609
+ return {
2610
+ ...state,
2611
+ focused: false
2612
+ };
2613
+ };
2614
+
2615
+ const handleClickDirectoryExpanding = async (state, dirent, index, keepFocus) => {
2616
+ // @ts-ignore
2617
+ dirent.type = Directory;
2618
+ // @ts-ignore
2619
+ dirent.icon = getIcon();
2620
+ return {
2621
+ ...state,
2622
+ focusedIndex: index,
2623
+ focused: keepFocus
2624
+ };
2625
+ };
2626
+
2507
2627
  // TODO viewlet should only have create and refresh functions
2508
2628
  // every thing else can be in a separate module <viewlet>.lazy.js
2509
2629
  // and <viewlet>.ipc.js
@@ -2525,16 +2645,16 @@ const getClickFn = direntType => {
2525
2645
  switch (direntType) {
2526
2646
  case File:
2527
2647
  case SymLinkFile:
2528
- return handleClickFile$1;
2648
+ return handleClickFile;
2529
2649
  case Directory:
2530
2650
  case SymLinkFolder:
2531
2651
  return handleClickDirectory;
2532
2652
  case DirectoryExpanding:
2533
2653
  return handleClickDirectoryExpanding;
2534
2654
  case DirectoryExpanded:
2535
- return handleClickDirectoryExpanded$1;
2655
+ return handleClickDirectoryExpanded;
2536
2656
  case Symlink:
2537
- return handleClickSymLink$1;
2657
+ return handleClickSymLink;
2538
2658
  case CharacterDevice:
2539
2659
  throw new Error('Cannot open character device files');
2540
2660
  case BlockDevice:
@@ -2546,34 +2666,6 @@ const getClickFn = direntType => {
2546
2666
  }
2547
2667
  };
2548
2668
 
2549
- const getIndexFromPosition = (state, eventX, eventY) => {
2550
- const {
2551
- y,
2552
- itemHeight,
2553
- items
2554
- } = state;
2555
- const index = Math.floor((eventY - y) / itemHeight);
2556
- if (index < 0) {
2557
- return 0;
2558
- }
2559
- if (index >= items.length) {
2560
- return -1;
2561
- }
2562
- return index;
2563
- };
2564
-
2565
- const getParentStartIndex = (dirents, index) => {
2566
- const dirent = dirents[index];
2567
- let startIndex = index - 1;
2568
- while (startIndex >= 0 && dirents[startIndex].depth >= dirent.depth) {
2569
- startIndex--;
2570
- }
2571
- return startIndex;
2572
- };
2573
-
2574
- const Keyboard = -1;
2575
- const LeftClick = 0;
2576
-
2577
2669
  // TODO viewlet should only have create and refresh functions
2578
2670
  // every thing else can be in a separate module <viewlet>.lazy.js
2579
2671
  // and <viewlet>.ipc.js
@@ -2584,81 +2676,11 @@ const LeftClick = 0;
2584
2676
  // TODO instead of root string, there should be a root dirent
2585
2677
 
2586
2678
  // TODO rename dirents to items, then can use virtual list component directly
2587
- const setDeltaY$1 = (state, deltaY) => {
2588
- const {
2589
- itemHeight,
2590
- height,
2591
- items
2592
- } = state;
2593
- if (deltaY < 0) {
2594
- deltaY = 0;
2595
- } else if (deltaY > items.length * itemHeight - height) {
2596
- deltaY = Math.max(items.length * itemHeight - height, 0);
2597
- }
2598
- if (state.deltaY === deltaY) {
2599
- return state;
2600
- }
2601
- const minLineY = Math.round(deltaY / itemHeight);
2602
- const maxLineY = minLineY + Math.round(height / itemHeight);
2603
- return {
2604
- ...state,
2605
- deltaY,
2606
- minLineY,
2607
- maxLineY
2608
- };
2609
- };
2610
- const handleWheel = (state, deltaMode, deltaY) => {
2611
- return setDeltaY$1(state, state.deltaY + deltaY);
2612
- };
2613
2679
 
2614
2680
  // TODO use posInSet and setSize properties to compute more effectively
2615
2681
 
2616
2682
  // TODO much shared logic with newFolder
2617
2683
 
2618
- const handleClickFile = async (state, dirent, index, keepFocus = false) => {
2619
- // await Command.execute(/* Main.openAbsolutePath */ 'Main.openUri', /* absolutePath */ dirent.path, /* focus */ !keepFocus)
2620
- return {
2621
- ...state,
2622
- focusedIndex: index,
2623
- focused: keepFocus
2624
- };
2625
- };
2626
- const handleClickDirectoryExpanded = (state, dirent, index, keepFocus) => {
2627
- const {
2628
- minLineY,
2629
- maxLineY,
2630
- itemHeight
2631
- } = state;
2632
- dirent.type = Directory;
2633
- dirent.icon = getIcon();
2634
- const endIndex = getParentEndIndex(state.items, index);
2635
- const removeCount = endIndex - index - 1;
2636
- // TODO race conditions and side effects are everywhere
2637
- const newDirents = [...state.items];
2638
- newDirents.splice(index + 1, removeCount);
2639
- const newTotal = newDirents.length;
2640
- if (newTotal < maxLineY) {
2641
- const visibleItems = Math.min(maxLineY - minLineY, newTotal);
2642
- const newMaxLineY = Math.min(maxLineY, newTotal);
2643
- const newMinLineY = newMaxLineY - visibleItems;
2644
- const deltaY = newMinLineY * itemHeight;
2645
- return {
2646
- ...state,
2647
- items: newDirents,
2648
- focusedIndex: index,
2649
- focused: keepFocus,
2650
- minLineY: newMinLineY,
2651
- maxLineY: newMaxLineY,
2652
- deltaY
2653
- };
2654
- }
2655
- return {
2656
- ...state,
2657
- items: newDirents,
2658
- focusedIndex: index,
2659
- focused: keepFocus
2660
- };
2661
- };
2662
2684
  const handleClick = async (state, index, keepFocus = false) => {
2663
2685
  const {
2664
2686
  items,
@@ -2676,102 +2698,44 @@ const handleClick = async (state, index, keepFocus = false) => {
2676
2698
  const clickFn = getClickFn(dirent.type);
2677
2699
  return clickFn(state, dirent, actualIndex, keepFocus);
2678
2700
  };
2679
- const handleClickAt = (state, button, x, y) => {
2680
- if (button !== LeftClick) {
2681
- return state;
2682
- }
2683
- const index = getIndexFromPosition(state, x, y);
2684
- return handleClick(state, index);
2685
- };
2686
- const handleClickCurrentButKeepFocus = state => {
2687
- return handleClick(state, state.focusedIndex - state.minLineY, /* keepFocus */true);
2688
- };
2689
2701
 
2690
2702
  // export const handleBlur=()=>{}
2691
2703
 
2692
- const handleClickSymLink = async (state, dirent, index) => {
2693
- const realPath = await getRealPath(dirent.path);
2694
- const type = await stat(realPath);
2695
- switch (type) {
2696
- case File:
2697
- return handleClickFile(state, dirent, index);
2698
- default:
2699
- throw new Error(`unsupported file type ${type}`);
2700
- }
2701
- };
2702
- const handleArrowRightDirectoryExpanded = (state, dirent) => {
2703
- const {
2704
- items,
2705
- focusedIndex
2706
- } = state;
2707
- if (focusedIndex === items.length - 1) {
2708
- return state;
2709
- }
2710
- const nextDirent = items[focusedIndex + 1];
2711
- if (nextDirent.depth === dirent.depth + 1) {
2712
- return focusIndex(state, focusedIndex + 1);
2713
- }
2714
- return state;
2715
- };
2716
- const handleArrowRight = async state => {
2704
+ // TODO what happens when mouse leave and anther mouse enter event occur?
2705
+ // should update preview instead of closing and reopening
2706
+
2707
+ // TODO maybe just insert items into explorer and refresh whole explorer
2708
+
2709
+ const getIndexFromPosition = (state, eventX, eventY) => {
2717
2710
  const {
2718
- items,
2719
- focusedIndex
2711
+ y,
2712
+ itemHeight,
2713
+ items
2720
2714
  } = state;
2721
- if (focusedIndex === -1) {
2722
- return state;
2723
- }
2724
- const dirent = items[focusedIndex];
2725
- switch (dirent.type) {
2726
- case File:
2727
- case SymLinkFile:
2728
- return state;
2729
- case Directory:
2730
- case SymLinkFolder:
2731
- // @ts-ignore
2732
- return handleClickDirectory(state, dirent);
2733
- case DirectoryExpanded:
2734
- return handleArrowRightDirectoryExpanded(state, dirent);
2735
- case Symlink:
2736
- return handleClickSymLink(state, dirent, focusedIndex);
2737
- default:
2738
- throw new Error(`unsupported file type ${dirent.type}`);
2715
+ const index = Math.floor((eventY - y) / itemHeight);
2716
+ if (index < 0) {
2717
+ return 0;
2739
2718
  }
2740
- };
2741
- const focusParentFolder = state => {
2742
- const parentStartIndex = getParentStartIndex(state.items, state.focusedIndex);
2743
- if (parentStartIndex === -1) {
2744
- return state;
2719
+ if (index >= items.length) {
2720
+ return -1;
2745
2721
  }
2746
- return focusIndex(state, parentStartIndex);
2722
+ return index;
2747
2723
  };
2748
- const handleArrowLeft = state => {
2749
- const {
2750
- items,
2751
- focusedIndex
2752
- } = state;
2753
- if (focusedIndex === -1) {
2724
+
2725
+ const Keyboard = -1;
2726
+ const LeftClick = 0;
2727
+
2728
+ const handleClickAt = (state, button, x, y) => {
2729
+ if (button !== LeftClick) {
2754
2730
  return state;
2755
2731
  }
2756
- const dirent = items[focusedIndex];
2757
- switch (dirent.type) {
2758
- case Directory:
2759
- case File:
2760
- case SymLinkFile:
2761
- return focusParentFolder(state);
2762
- case DirectoryExpanded:
2763
- // @ts-ignore
2764
- return handleClickDirectoryExpanded(state, dirent, focusedIndex);
2765
- default:
2766
- // TODO handle expanding directory and cancel file system call to read child dirents
2767
- return state;
2768
- }
2732
+ const index = getIndexFromPosition(state, x, y);
2733
+ return handleClick(state, index);
2769
2734
  };
2770
2735
 
2771
- // TODO what happens when mouse leave and anther mouse enter event occur?
2772
- // should update preview instead of closing and reopening
2773
-
2774
- // TODO maybe just insert items into explorer and refresh whole explorer
2736
+ const handleClickCurrentButKeepFocus = state => {
2737
+ return handleClick(state, state.focusedIndex - state.minLineY, /* keepFocus */true);
2738
+ };
2775
2739
 
2776
2740
  const openFolder = async () => {
2777
2741
  // TODO
@@ -3239,6 +3203,34 @@ const handleUpload = async (state, dirents) => {
3239
3203
  }
3240
3204
  };
3241
3205
 
3206
+ const setDeltaY = (state, deltaY) => {
3207
+ const {
3208
+ itemHeight,
3209
+ height,
3210
+ items
3211
+ } = state;
3212
+ if (deltaY < 0) {
3213
+ deltaY = 0;
3214
+ } else if (deltaY > items.length * itemHeight - height) {
3215
+ deltaY = Math.max(items.length * itemHeight - height, 0);
3216
+ }
3217
+ if (state.deltaY === deltaY) {
3218
+ return state;
3219
+ }
3220
+ const minLineY = Math.round(deltaY / itemHeight);
3221
+ const maxLineY = minLineY + Math.round(height / itemHeight);
3222
+ return {
3223
+ ...state,
3224
+ deltaY,
3225
+ minLineY,
3226
+ maxLineY
3227
+ };
3228
+ };
3229
+
3230
+ const handleWheel = (state, deltaMode, deltaY) => {
3231
+ return setDeltaY(state, state.deltaY + deltaY);
3232
+ };
3233
+
3242
3234
  const getWorkspacePath = () => {
3243
3235
  return invoke('Workspace.getPath');
3244
3236
  };
@@ -3471,9 +3463,7 @@ const openContainingFolder = async state => {
3471
3463
  const {
3472
3464
  focusedIndex,
3473
3465
  root,
3474
- items,
3475
- pathSeparator
3476
- } = state;
3466
+ items} = state;
3477
3467
  const path = getContaingingFolder(root, items, focusedIndex);
3478
3468
  await invoke('OpenNativeFolder.openNativeFolder', /* path */path);
3479
3469
  return state;
@@ -3557,71 +3547,54 @@ const renameDirent = state => {
3557
3547
  };
3558
3548
  };
3559
3549
 
3560
- const renderItems = {
3561
- isEqual(oldState, newState) {
3562
- return oldState.items === newState.items && oldState.minLineY === newState.minLineY && oldState.maxLineY === newState.maxLineY && oldState.focusedIndex === newState.focusedIndex && oldState.editingIndex === newState.editingIndex && oldState.editingType === newState.editingType && oldState.editingValue === newState.editingValue && oldState.width === newState.width && oldState.focused === newState.focused;
3563
- },
3564
- apply(oldState, newState) {
3565
- const visibleDirents = getVisibleExplorerItems(newState.items, newState.minLineY, newState.maxLineY, newState.focusedIndex, newState.editingIndex, newState.editingType, newState.editingValue, newState.icons, newState.useChevrons);
3566
- const isWide = newState.width > 450;
3567
- const dom = getExplorerVirtualDom(visibleDirents, newState.focusedIndex, newState.root, isWide, newState.focused);
3568
- return ['Viewlet.setDom2', dom];
3569
- }
3570
- };
3571
-
3572
- // TODO add virtual dom diffing so that focus is not lost when updating dom
3573
- // const renderFocus = {
3574
- // isEqual(oldState: any, newState: any) {
3575
- // return oldState.focusedIndex === newState.focusedIndex && oldState.focused === newState.focused && oldState.minLineY === newState.minLineY
3576
- // },
3577
- // apply(oldState: any, newState: any) {
3578
- // const oldFocusedIndex = oldState.focusedIndex - oldState.minLineY
3579
- // const newFocusedIndex = newState.focusedIndex - newState.minLineY
3580
- // return [/* method */ 'setFocusedIndex', /* oldindex */ oldFocusedIndex, /* newIndex */ newFocusedIndex, /* focused */ newState.focused]
3581
- // },
3582
- // }
3583
-
3584
- // const renderDropTargets = {
3585
- // isEqual(oldState:any, newState:any) {
3586
- // return oldState.dropTargets === newState.dropTargets
3587
- // },
3588
- // apply(oldState:any, newState:any) {
3589
- // return [/* method */ 'setDropTargets', /* oldDropTargets */ oldState.dropTargets, /* newDropTargets */ newState.dropTargets]
3590
- // },
3591
- // }
3592
-
3593
- const renderEditingIndex = {
3594
- isEqual(oldState, newState) {
3595
- return oldState.editingIndex === newState.editingIndex && oldState.editingType === newState.editingType;
3596
- },
3597
- apply(oldState, newState) {
3598
- return ['focusInput', 'ExplorerInput'];
3599
- }
3600
- };
3601
- const render = [renderItems, renderEditingIndex];
3550
+ const renderEditingIndex = (oldState, newState) => {
3551
+ return ['focusInput', 'ExplorerInput'];
3552
+ };
3553
+
3554
+ const renderItems = (oldState, newState) => {
3555
+ const visibleDirents = getVisibleExplorerItems(newState.items, newState.minLineY, newState.maxLineY, newState.focusedIndex, newState.editingIndex, newState.editingType, newState.editingValue, newState.icons, newState.useChevrons);
3556
+ const isWide = newState.width > 450;
3557
+ const dom = getExplorerVirtualDom(visibleDirents, newState.focusedIndex, newState.root, isWide, newState.focused);
3558
+ return ['Viewlet.setDom2', dom];
3559
+ };
3560
+
3561
+ const getRenderer = diffType => {
3562
+ switch (diffType) {
3563
+ case RenderEditingIndex:
3564
+ return renderEditingIndex;
3565
+ case RenderItems:
3566
+ return renderItems;
3567
+ default:
3568
+ throw new Error('unknown renderer');
3569
+ }
3570
+ };
3571
+
3572
+ const applyRender = (oldState, newState, diffResult) => {
3573
+ const commands = [];
3574
+ for (const item of diffResult) {
3575
+ const fn = getRenderer(item);
3576
+ commands.push(fn(oldState, newState));
3577
+ }
3578
+ return commands;
3579
+ };
3580
+
3581
+ const renderInternal = (oldState, newState) => {
3582
+ const diffResult = diff(oldState, newState);
3583
+ return applyRender(oldState, newState, diffResult);
3584
+ };
3602
3585
  const doRender = (uid, _) => {
3603
3586
  if (typeof uid === 'number') {
3604
3587
  const {
3605
3588
  oldState,
3606
3589
  newState
3607
3590
  } = get(uid);
3608
- const commands = [];
3609
- for (const fn of render) {
3610
- if (!fn.isEqual(oldState, newState)) {
3611
- commands.push(fn.apply(oldState, newState));
3612
- }
3613
- }
3591
+ const commands = renderInternal(oldState, newState);
3614
3592
  return commands;
3615
3593
  }
3616
3594
  // deprecated
3617
3595
  const oldState = uid;
3618
3596
  const newState = _;
3619
- const commands = [];
3620
- for (const fn of render) {
3621
- if (!fn.isEqual(oldState, newState)) {
3622
- commands.push(fn.apply(oldState, newState));
3623
- }
3624
- }
3597
+ const commands = renderInternal(oldState, newState);
3625
3598
  return commands;
3626
3599
  };
3627
3600
 
@@ -3673,6 +3646,41 @@ const renderActions = state => {
3673
3646
  return dom;
3674
3647
  };
3675
3648
 
3649
+ const renderEventListeners = () => {
3650
+ return [{
3651
+ name: HandleBlur,
3652
+ params: ['handleBlur']
3653
+ }, {
3654
+ name: HandleFocus,
3655
+ params: ['handleFocus', 'event.isTrusted', 'event.target.className']
3656
+ }, {
3657
+ name: HandleBlur,
3658
+ params: ['handleBlur']
3659
+ }, {
3660
+ name: HandleClick,
3661
+ params: ['event.button', 'event.clientX', 'event.clientY'],
3662
+ preventDefault: true
3663
+ }, {
3664
+ name: HandleClickOpenFolder,
3665
+ params: [],
3666
+ preventDefault: true
3667
+ }, {
3668
+ name: HandlePointerDown,
3669
+ params: ['event.button', 'event.clientX', 'event.clientY'],
3670
+ preventDefault: true
3671
+ }, {
3672
+ name: HandleEditingInput,
3673
+ params: ['event.target.value']
3674
+ }, {
3675
+ name: HandleContextMenu,
3676
+ params: ['event.button', 'event.clientX', 'event.clientY']
3677
+ }, {
3678
+ name: HandleWheel,
3679
+ params: ['event.deltaMode', 'event.deltaY'],
3680
+ passive: true
3681
+ }];
3682
+ };
3683
+
3676
3684
  const getSavedRoot = (savedState, workspacePath) => {
3677
3685
  return workspacePath;
3678
3686
  };
@@ -3957,30 +3965,6 @@ const saveState = uid => {
3957
3965
  };
3958
3966
  };
3959
3967
 
3960
- const setDeltaY = (state, deltaY) => {
3961
- const {
3962
- itemHeight,
3963
- height,
3964
- items
3965
- } = state;
3966
- if (deltaY < 0) {
3967
- deltaY = 0;
3968
- } else if (deltaY > items.length * itemHeight - height) {
3969
- deltaY = Math.max(items.length * itemHeight - height, 0);
3970
- }
3971
- if (state.deltaY === deltaY) {
3972
- return state;
3973
- }
3974
- const minLineY = Math.round(deltaY / itemHeight);
3975
- const maxLineY = minLineY + Math.round(height / itemHeight);
3976
- return {
3977
- ...state,
3978
- deltaY,
3979
- minLineY,
3980
- maxLineY
3981
- };
3982
- };
3983
-
3984
3968
  const terminate = () => {
3985
3969
  globalThis.close();
3986
3970
  };
@@ -4027,6 +4011,7 @@ const commandMap = {
4027
4011
  'Explorer.focusNext': wrapCommand(focusNext),
4028
4012
  'Explorer.focusPrevious': wrapCommand(focusPrevious),
4029
4013
  'Explorer.getActions': wrapCommand(getActions),
4014
+ 'Explorer.getCommandIds': getCommandIds,
4030
4015
  'Explorer.getKeyBindings': wrapCommand(getKeyBindings),
4031
4016
  'Explorer.getMenuEntries': wrapCommand(getMenuEntries),
4032
4017
  'Explorer.getVirtualDom': wrapCommand(getExplorerVirtualDom),
@@ -4065,7 +4050,9 @@ const commandMap = {
4065
4050
  'Explorer.create': create,
4066
4051
  'Explorer.render': doRender,
4067
4052
  'Explorer.renderActions': renderActions,
4068
- 'Explorer.saveState': saveState
4053
+ 'Explorer.saveState': saveState,
4054
+ 'Explorer.renderEventListeners': renderEventListeners,
4055
+ 'Explorer.diff': diff
4069
4056
  };
4070
4057
 
4071
4058
  const listen = async () => {
package/package.json CHANGED
@@ -1,8 +1,7 @@
1
1
  {
2
2
  "name": "@lvce-editor/explorer-view",
3
- "version": "1.20.0",
3
+ "version": "1.22.0",
4
4
  "description": "Explorer Worker",
5
- "keywords": [],
6
5
  "repository": {
7
6
  "type": "git",
8
7
  "url": "git+https://github.com/lvce-editor/explorer-view.git"