@lvce-editor/main-area-worker 9.74.1 → 9.74.2

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.
@@ -2880,7 +2880,7 @@ const create$1 = (uid, uri, x, y, width, height, platform, assetDir, tabHeight =
2880
2880
  };
2881
2881
 
2882
2882
  const isEqual$3 = (oldState, newState) => {
2883
- return oldState.layout === newState.layout && oldState.width === newState.width;
2883
+ return oldState.layout === newState.layout && oldState.width === newState.width && oldState.activeTabVisibilityVersion === newState.activeTabVisibilityVersion;
2884
2884
  };
2885
2885
 
2886
2886
  const isEqual$2 = (oldState, newState) => {
@@ -4445,6 +4445,12 @@ const tabIconNode = {
4445
4445
  role: None$2,
4446
4446
  type: Div
4447
4447
  };
4448
+ const emptyTabIconNode = {
4449
+ childCount: 0,
4450
+ className: TabIcon,
4451
+ role: None$2,
4452
+ type: Div
4453
+ };
4448
4454
  const tabTitleNode = {
4449
4455
  childCount: 1,
4450
4456
  className: TabTitle,
@@ -4480,7 +4486,7 @@ const renderTabIcon = tab => {
4480
4486
  return renderMaskIcon(MaskIconDebugAlt2);
4481
4487
  }
4482
4488
  if (!tab.icon) {
4483
- return [];
4489
+ return [emptyTabIconNode];
4484
4490
  }
4485
4491
  return [{
4486
4492
  childCount: 0,
@@ -4514,7 +4520,7 @@ const renderTab = (tab, isActive, tabIndex, groupIndex, dropIndicatorPosition) =
4514
4520
  }
4515
4521
  return [{
4516
4522
  'aria-selected': isActive,
4517
- childCount: 2 + (tabIconNodes.length > 0 ? 1 : 0),
4523
+ childCount: 3,
4518
4524
  className,
4519
4525
  'data-groupIndex': groupIndex,
4520
4526
  'data-index': tabIndex,
@@ -5436,68 +5442,6 @@ const isDirectoryEditorInput = async (editorInput, applicationId) => {
5436
5442
  }
5437
5443
  };
5438
5444
 
5439
- const switchTab = (state, groupId, tabId) => {
5440
- const {
5441
- layout
5442
- } = state;
5443
- const {
5444
- groups
5445
- } = layout;
5446
- const updatedGroups = groups.map(group => {
5447
- if (group.id === groupId) {
5448
- const tabExists = group.tabs.some(tab => tab.id === tabId);
5449
- if (tabExists) {
5450
- return {
5451
- ...group,
5452
- activeTabId: tabId
5453
- };
5454
- }
5455
- }
5456
- return group;
5457
- });
5458
- return {
5459
- ...state,
5460
- layout: {
5461
- ...layout,
5462
- groups: updatedGroups
5463
- }
5464
- };
5465
- };
5466
-
5467
- const getIconsCached = (dirents, fileIconCache) => {
5468
- return dirents.map(dirent => fileIconCache[dirent]);
5469
- };
5470
-
5471
- const getBasename = uri => {
5472
- const lastSlashIndex = uri.lastIndexOf('/');
5473
- if (lastSlashIndex === -1) {
5474
- return uri;
5475
- }
5476
- return uri.slice(lastSlashIndex + 1);
5477
- };
5478
- const getMissingTabs = (tabs, fileIconCache) => {
5479
- const missingTabs = [];
5480
- for (const tab of tabs) {
5481
- if (tab.uri && !getFileIcon(tab.uri) && !(tab.uri in fileIconCache)) {
5482
- missingTabs.push(tab);
5483
- }
5484
- }
5485
- return missingTabs;
5486
- };
5487
- const tabToIconRequest = tab => {
5488
- const uri = tab.uri || '';
5489
- return {
5490
- name: getBasename(uri),
5491
- path: uri,
5492
- type: File
5493
- };
5494
- };
5495
- const getMissingIconRequestsForTabs = (tabs, fileIconCache) => {
5496
- const missingRequests = getMissingTabs(tabs, fileIconCache);
5497
- const iconRequests = missingRequests.map(tabToIconRequest);
5498
- return iconRequests;
5499
- };
5500
-
5501
5445
  const getSimpleIconRequestType = direntType => {
5502
5446
  if (direntType === Directory || direntType === DirectoryExpanded) {
5503
5447
  return 2;
@@ -5521,75 +5465,58 @@ const requestFileIcons = async requests => {
5521
5465
  return icons;
5522
5466
  };
5523
5467
 
5524
- const updateIconCache = (iconCache, missingRequests, newIcons) => {
5525
- if (missingRequests.length === 0) {
5526
- return iconCache;
5468
+ const prepareTabIcon = async (context, uri) => {
5469
+ const state = context.getState();
5470
+ let icon = getFileIcon(uri) || state.fileIconCache[uri] || '';
5471
+ if (!icon && uri && !(uri in state.fileIconCache)) {
5472
+ try {
5473
+ const icons = await requestFileIcons([{
5474
+ name: uri.slice(uri.lastIndexOf('/') + 1),
5475
+ path: uri,
5476
+ type: File
5477
+ }]);
5478
+ icon = icons[0] || '';
5479
+ } catch {
5480
+ // Icon failures must not prevent opening the file. The reserved slot keeps its title stable.
5481
+ }
5527
5482
  }
5528
- const newFileIconCache = {
5529
- ...iconCache
5530
- };
5531
- for (let i = 0; i < missingRequests.length; i++) {
5532
- const request = missingRequests[i];
5533
- const icon = newIcons[i];
5534
- newFileIconCache[request.path] = icon;
5483
+ const latestState = context.getState();
5484
+ if (latestState.iconThemeVersion !== state.iconThemeVersion) {
5485
+ return prepareTabIcon(context, uri);
5535
5486
  }
5536
- return newFileIconCache;
5537
- };
5538
-
5539
- const getUri = tab => {
5540
- return tab.uri || '';
5541
- };
5542
- const getFileIconsForTabs = async (tabs, fileIconCache) => {
5543
- const missingRequests = getMissingIconRequestsForTabs(tabs, fileIconCache);
5544
- const newIcons = await requestFileIcons(missingRequests);
5545
- const newFileIconCache = updateIconCache(fileIconCache, missingRequests, newIcons);
5546
- const tabUris = tabs.map(getUri);
5547
- const icons = getIconsCached(tabUris, newFileIconCache);
5548
5487
  return {
5549
- icons,
5550
- newFileIconCache
5488
+ icon,
5489
+ state: latestState
5551
5490
  };
5552
5491
  };
5553
5492
 
5554
- const updateIcon = (state, tabId, icon) => {
5493
+ const switchTab = (state, groupId, tabId) => {
5494
+ const {
5495
+ layout
5496
+ } = state;
5497
+ const {
5498
+ groups
5499
+ } = layout;
5500
+ const updatedGroups = groups.map(group => {
5501
+ if (group.id === groupId) {
5502
+ const tabExists = group.tabs.some(tab => tab.id === tabId);
5503
+ if (tabExists) {
5504
+ return {
5505
+ ...group,
5506
+ activeTabId: tabId
5507
+ };
5508
+ }
5509
+ }
5510
+ return group;
5511
+ });
5555
5512
  return {
5556
5513
  ...state,
5557
5514
  layout: {
5558
- ...state.layout,
5559
- groups: state.layout.groups.map(group => ({
5560
- ...group,
5561
- tabs: group.tabs.map(tab => tab.id === tabId ? {
5562
- ...tab,
5563
- icon
5564
- } : tab)
5565
- }))
5515
+ ...layout,
5516
+ groups: updatedGroups
5566
5517
  }
5567
5518
  };
5568
5519
  };
5569
- const updateTabIcon = async (context, readyState, tabId) => {
5570
- const newTab = findTabById(readyState, tabId);
5571
- if (!newTab || !newTab.tab.uri) {
5572
- return undefined;
5573
- }
5574
- const builtInIcon = getFileIcon(newTab.tab.uri);
5575
- if (builtInIcon) {
5576
- return context.updateState(state => updateIcon(state, tabId, builtInIcon));
5577
- }
5578
- try {
5579
- const {
5580
- newFileIconCache
5581
- } = await getFileIconsForTabs([newTab.tab], readyState.fileIconCache);
5582
- const stateBeforeIconUpdate = context.getState();
5583
- const icon = newFileIconCache[newTab.tab.uri] || '';
5584
- const stateWithIcon = updateIcon({
5585
- ...stateBeforeIconUpdate,
5586
- fileIconCache: newFileIconCache
5587
- }, tabId, icon);
5588
- return context.updateState(() => stateWithIcon);
5589
- } catch {
5590
- return undefined;
5591
- }
5592
- };
5593
5520
 
5594
5521
  const renderMainAreaPending = async (uid, applicationId) => {
5595
5522
  try {
@@ -5671,19 +5598,70 @@ const handleOpenError = async (context, tabId, editorInput, uri, error) => {
5671
5598
  });
5672
5599
  await context.updateState(() => errorState);
5673
5600
  };
5601
+ const findReusableTab = (state, options, uri) => {
5602
+ return options.reuseExisting === false ? undefined : findTabByUri(state, uri);
5603
+ };
5604
+ const getStateWithIcon = (state, tabId, uri, icon) => {
5605
+ const stateWithIcon = updateTab(state, tabId, {
5606
+ icon
5607
+ });
5608
+ return {
5609
+ ...stateWithIcon,
5610
+ fileIconCache: icon && !getFileIcon(uri) ? {
5611
+ ...stateWithIcon.fileIconCache,
5612
+ [uri]: icon
5613
+ } : stateWithIcon.fileIconCache
5614
+ };
5615
+ };
5616
+ const disposePreviewEditor = async editorUid => {
5617
+ if (editorUid !== -1) {
5618
+ await disposeEditors([editorUid]);
5619
+ }
5620
+ };
5621
+ const isSupersededPreview = (state, initialState, requestId, preview) => {
5622
+ return preview && (state.openRequestId !== requestId || getActiveTabId(state) !== getActiveTabId(initialState));
5623
+ };
5674
5624
  const openInputWithContext = async (context, options) => {
5675
- const state = context.getState();
5676
- object(state);
5625
+ object(context.getState());
5677
5626
  object(options);
5627
+ const requestId = getNextRequestId();
5628
+ await context.updateState(state => ({
5629
+ ...state,
5630
+ openRequestId: requestId
5631
+ }));
5632
+ const state = context.getState();
5678
5633
  const {
5679
5634
  editorInput
5680
5635
  } = options;
5681
5636
  const preview = options.preview ?? false;
5682
5637
  const uri = getEditorInputUri(editorInput);
5683
5638
  const title = getEditorInputTitle(editorInput);
5684
- const currentState = state;
5685
- const existingTab = options.reuseExisting === false ? undefined : findTabByUri(currentState, uri);
5686
- const shouldRetry = shouldRetryExistingTab(existingTab, editorInput, options.forceOpen === true);
5639
+ let currentState = state;
5640
+ let existingTab = findReusableTab(currentState, options, uri);
5641
+ let shouldRetry = shouldRetryExistingTab(existingTab, editorInput, options.forceOpen === true);
5642
+ let icon = '';
5643
+ let {
5644
+ iconThemeVersion
5645
+ } = state;
5646
+ if (!existingTab || shouldRetry) {
5647
+ const {
5648
+ icon: resolvedIcon,
5649
+ state: {
5650
+ iconThemeVersion: resolvedIconThemeVersion
5651
+ }
5652
+ } = await prepareTabIcon(context, uri);
5653
+ icon = resolvedIcon;
5654
+ iconThemeVersion = resolvedIconThemeVersion;
5655
+ currentState = context.getState();
5656
+ existingTab = findReusableTab(currentState, options, uri);
5657
+ shouldRetry = shouldRetryExistingTab(existingTab, editorInput, options.forceOpen === true);
5658
+ }
5659
+ if (isSupersededPreview(currentState, state, requestId, preview)) {
5660
+ return;
5661
+ }
5662
+ if (currentState.iconThemeVersion !== iconThemeVersion) {
5663
+ return openInputWithContext(context, options);
5664
+ }
5687
5665
  if (existingTab && !shouldRetry) {
5688
5666
  const switchedState = getExistingTabState(currentState, existingTab, preview);
5689
5667
  await context.updateState(() => switchedState);
@@ -5697,10 +5675,8 @@ const openInputWithContext = async (context, options) => {
5697
5675
  stateWithTab,
5698
5676
  tabId
5699
5677
  } = getStateWithTab(currentState, editorInput, existingTab, shouldRetry, uri, preview, title);
5700
- await context.updateState(() => stateWithTab);
5701
- if (replacedEditorUid !== -1) {
5702
- await disposeEditors([replacedEditorUid]);
5703
- }
5678
+ await context.updateState(() => getStateWithIcon(stateWithTab, tabId, uri, icon));
5679
+ await disposePreviewEditor(replacedEditorUid);
5704
5680
  if (await isDirectoryEditorInput(editorInput, state.applicationId)) {
5705
5681
  const latestState = context.getState();
5706
5682
  const errorState = updateTab(latestState, tabId, {
@@ -5773,10 +5749,12 @@ const openInputWithContext = async (context, options) => {
5773
5749
  readyState = handleViewletReady(context.getState(), editorUid, renderedTitle);
5774
5750
  await context.updateState(() => readyState);
5775
5751
  }
5776
- const stateWithIcon = await updateTabIcon(context, readyState, tabId);
5777
- if (stateWithIcon) {
5778
- return;
5779
- }
5752
+ // Earlier visibility commands can run before the final editor DOM is committed.
5753
+ // Request a final scroll without changing the tab DOM or fetching its icon again.
5754
+ await context.updateState(state => ({
5755
+ ...state,
5756
+ activeTabVisibilityVersion: (state.activeTabVisibilityVersion ?? 0) + 1
5757
+ }));
5780
5758
  } catch (error) {
5781
5759
  await handleOpenError(context, tabId, editorInput, uri, error);
5782
5760
  }
@@ -7185,6 +7163,70 @@ const handleHeaderDoubleClick = async (state, className, groupIndexRaw) => {
7185
7163
  return newFile(state);
7186
7164
  };
7187
7165
 
7166
+ const getIconsCached = (dirents, fileIconCache) => {
7167
+ return dirents.map(dirent => fileIconCache[dirent]);
7168
+ };
7169
+
7170
+ const getBasename = uri => {
7171
+ const lastSlashIndex = uri.lastIndexOf('/');
7172
+ if (lastSlashIndex === -1) {
7173
+ return uri;
7174
+ }
7175
+ return uri.slice(lastSlashIndex + 1);
7176
+ };
7177
+ const getMissingTabs = (tabs, fileIconCache) => {
7178
+ const missingTabs = [];
7179
+ for (const tab of tabs) {
7180
+ if (tab.uri && !getFileIcon(tab.uri) && !(tab.uri in fileIconCache)) {
7181
+ missingTabs.push(tab);
7182
+ }
7183
+ }
7184
+ return missingTabs;
7185
+ };
7186
+ const tabToIconRequest = tab => {
7187
+ const uri = tab.uri || '';
7188
+ return {
7189
+ name: getBasename(uri),
7190
+ path: uri,
7191
+ type: File
7192
+ };
7193
+ };
7194
+ const getMissingIconRequestsForTabs = (tabs, fileIconCache) => {
7195
+ const missingRequests = getMissingTabs(tabs, fileIconCache);
7196
+ const iconRequests = missingRequests.map(tabToIconRequest);
7197
+ return iconRequests;
7198
+ };
7199
+
7200
+ const updateIconCache = (iconCache, missingRequests, newIcons) => {
7201
+ if (missingRequests.length === 0) {
7202
+ return iconCache;
7203
+ }
7204
+ const newFileIconCache = {
7205
+ ...iconCache
7206
+ };
7207
+ for (let i = 0; i < missingRequests.length; i++) {
7208
+ const request = missingRequests[i];
7209
+ const icon = newIcons[i];
7210
+ newFileIconCache[request.path] = icon;
7211
+ }
7212
+ return newFileIconCache;
7213
+ };
7214
+
7215
+ const getUri = tab => {
7216
+ return tab.uri || '';
7217
+ };
7218
+ const getFileIconsForTabs = async (tabs, fileIconCache) => {
7219
+ const missingRequests = getMissingIconRequestsForTabs(tabs, fileIconCache);
7220
+ const newIcons = await requestFileIcons(missingRequests);
7221
+ const newFileIconCache = updateIconCache(fileIconCache, missingRequests, newIcons);
7222
+ const tabUris = tabs.map(getUri);
7223
+ const icons = getIconsCached(tabUris, newFileIconCache);
7224
+ return {
7225
+ icons,
7226
+ newFileIconCache
7227
+ };
7228
+ };
7229
+
7188
7230
  const getAllTabs$1 = layout => {
7189
7231
  const {
7190
7232
  groups
@@ -7259,6 +7301,7 @@ const handleIconThemeChange = async state => {
7259
7301
  return {
7260
7302
  ...state,
7261
7303
  fileIconCache,
7304
+ iconThemeVersion: (state.iconThemeVersion ?? 0) + 1,
7262
7305
  layout: updatedLayout
7263
7306
  };
7264
7307
  };
@@ -8866,11 +8909,14 @@ const applyRender = (oldState, newState, diffResult) => {
8866
8909
  return commands;
8867
8910
  };
8868
8911
 
8869
- const render2 = (uid, diffResult) => {
8912
+ const render2 = (uid, _diffResult) => {
8870
8913
  const {
8871
8914
  newState,
8872
8915
  oldState
8873
8916
  } = get$1(uid);
8917
+ // State can change between the caller's diff2 RPC and this render2 RPC.
8918
+ // Diff and render the same snapshot before marking it as rendered.
8919
+ const diffResult = diff(oldState, newState);
8874
8920
  set$1(uid, newState, newState);
8875
8921
  const commands = applyRender(oldState, newState, diffResult);
8876
8922
  if (!isConnected()) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/main-area-worker",
3
- "version": "9.74.1",
3
+ "version": "9.74.2",
4
4
  "description": "Main Area Worker",
5
5
  "repository": {
6
6
  "type": "git",