@lvce-editor/main-area-worker 9.50.1 → 9.52.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.
@@ -1680,8 +1680,11 @@ const VirtualDomElements = {
1680
1680
  const Button$1 = 'event.button';
1681
1681
  const ClientX = 'event.clientX';
1682
1682
  const ClientY = 'event.clientY';
1683
+ const DeltaMode = 'event.deltaMode';
1684
+ const DeltaY = 'event.deltaY';
1683
1685
  const DropId = 'event.dropId';
1684
1686
  const EventTargetClassName = 'event.target.className';
1687
+ const Key = 'event.key';
1685
1688
  const TargetName = 'event.target.name';
1686
1689
 
1687
1690
  const Tab = 13;
@@ -2401,27 +2404,32 @@ const promptSave = async title => {
2401
2404
  });
2402
2405
  return shouldDiscard ? 'discard' : 'cancel';
2403
2406
  };
2407
+ const canCloseTab = async tab => {
2408
+ if (tab.editorUid === -1 || !tab.isDirty) {
2409
+ return true;
2410
+ }
2411
+ const savePromptResult = await promptSave(tab.title);
2412
+ if (savePromptResult === 'cancel') {
2413
+ return false;
2414
+ }
2415
+ if (savePromptResult === 'save') {
2416
+ const editorState = await saveEditor(tab.editorUid);
2417
+ if (editorState?.modified !== false) {
2418
+ return false;
2419
+ }
2420
+ if (tab.uri) {
2421
+ await handleModifiedStatusChange$1(tab.uri, false);
2422
+ }
2423
+ }
2424
+ return savePromptResult === 'save' || savePromptResult === 'discard';
2425
+ };
2404
2426
  const closeTabAndSave = async (state, groupId, tabId) => {
2405
2427
  const tab = findTabInState(state, groupId, tabId);
2406
2428
  if (!tab) {
2407
2429
  return state;
2408
2430
  }
2409
- if (tab.editorUid !== -1 && tab.isDirty) {
2410
- const savePromptResult = await promptSave(tab.title);
2411
- if (savePromptResult === 'cancel') {
2412
- return state;
2413
- }
2414
- if (savePromptResult === 'save') {
2415
- const editorState = await saveEditor(tab.editorUid);
2416
- if (editorState?.modified !== false) {
2417
- return state;
2418
- }
2419
- if (tab.uri) {
2420
- await handleModifiedStatusChange$1(tab.uri, false);
2421
- }
2422
- } else if (savePromptResult !== 'discard') {
2423
- return state;
2424
- }
2431
+ if (!(await canCloseTab(tab))) {
2432
+ return state;
2425
2433
  }
2426
2434
  return closeTabWithViewlet(state, groupId, tabId);
2427
2435
  };
@@ -2485,6 +2493,16 @@ const closeAll$1 = async state => {
2485
2493
  return withEmptyGroups(addClosedTabs(state, entries));
2486
2494
  };
2487
2495
 
2496
+ const closeAllAndSave = async state => {
2497
+ const tabs = state.layout.groups.flatMap(group => group.tabs);
2498
+ for (const tab of tabs) {
2499
+ if (!(await canCloseTab(tab))) {
2500
+ return state;
2501
+ }
2502
+ }
2503
+ return closeAll$1(state);
2504
+ };
2505
+
2488
2506
  const redistributeSizesWithRemainder = groups => {
2489
2507
  const baseSize = Math.floor(100 / groups.length);
2490
2508
  const remainder = 100 % groups.length;
@@ -2825,6 +2843,10 @@ const create$1 = (uid, uri, x, y, width, height, platform, assetDir, tabHeight =
2825
2843
  set$1(uid, state, state);
2826
2844
  };
2827
2845
 
2846
+ const isEqual$3 = (oldState, newState) => {
2847
+ return oldState.layout === newState.layout && oldState.width === newState.width;
2848
+ };
2849
+
2828
2850
  const isEqual$2 = (oldState, newState) => {
2829
2851
  return false;
2830
2852
  };
@@ -2842,12 +2864,13 @@ const RenderCss = 10;
2842
2864
  const RenderIncremental = 11;
2843
2865
  const RenderPendingViewletUpdate = 12;
2844
2866
  const RenderDragData = 13;
2867
+ const RenderActiveTabVisibility = 14;
2845
2868
 
2846
2869
  const isPendingViewletUpdateEqual = (oldState, newState) => {
2847
2870
  return newState.pendingViewletUpdate === undefined;
2848
2871
  };
2849
- const modules = [isEqual, isEqual$2, isPendingViewletUpdateEqual, isEqual$1];
2850
- const numbers = [RenderIncremental, RenderCss, RenderPendingViewletUpdate, RenderDragData];
2872
+ const modules = [isEqual, isEqual$2, isPendingViewletUpdateEqual, isEqual$1, isEqual$3];
2873
+ const numbers = [RenderIncremental, RenderCss, RenderPendingViewletUpdate, RenderDragData, RenderActiveTabVisibility];
2851
2874
 
2852
2875
  const diff = (oldState, newState) => {
2853
2876
  const diffResult = [];
@@ -3203,19 +3226,140 @@ const findTabById = (state, tabId) => {
3203
3226
  return undefined;
3204
3227
  };
3205
3228
 
3206
- const getSelectedTabBounds = state => {
3229
+ const getSegmentSize = segment => {
3230
+ return segment.groups.reduce((total, group) => total + group.size, 0);
3231
+ };
3232
+ const getGroupSegment = (segments, groupId) => {
3233
+ return segments.find(segment => segment.groups.some(group => group.id === groupId));
3234
+ };
3235
+ const getGroupSegments = (groups, parentDirection) => {
3236
+ const segments = [];
3237
+ let index = 0;
3238
+ while (index < groups.length) {
3239
+ const group = groups[index];
3240
+ if (group.direction !== parentDirection) {
3241
+ const startIndex = index;
3242
+ const nestedGroups = [group];
3243
+ const {
3244
+ segmentId
3245
+ } = group;
3246
+ index++;
3247
+ while (index < groups.length && groups[index].direction === group.direction && groups[index].segmentId === segmentId) {
3248
+ nestedGroups.push(groups[index]);
3249
+ index++;
3250
+ }
3251
+ segments.push({
3252
+ direction: nestedGroups.length === 1 ? undefined : group.direction,
3253
+ groups: nestedGroups,
3254
+ startIndex
3255
+ });
3256
+ continue;
3257
+ }
3258
+ segments.push({
3259
+ direction: undefined,
3260
+ groups: [group],
3261
+ startIndex: index
3262
+ });
3263
+ index++;
3264
+ }
3265
+ return segments;
3266
+ };
3267
+
3268
+ const getChildBounds = (bounds, direction, offset, size) => {
3269
+ if (direction === Horizontal) {
3270
+ return {
3271
+ height: bounds.height,
3272
+ width: bounds.width * size,
3273
+ x: bounds.x + bounds.width * offset,
3274
+ y: bounds.y
3275
+ };
3276
+ }
3277
+ return {
3278
+ height: bounds.height * size,
3279
+ width: bounds.width,
3280
+ x: bounds.x,
3281
+ y: bounds.y + bounds.height * offset
3282
+ };
3283
+ };
3284
+ const getEditorGroupBoundsFromRoot = (layout, rootBounds) => {
3207
3285
  const {
3286
+ direction,
3287
+ groups
3288
+ } = layout;
3289
+ const segments = getGroupSegments(groups, direction);
3290
+ const result = [];
3291
+ let segmentOffset = 0;
3292
+ for (const segment of segments) {
3293
+ const segmentSize = getSegmentSize(segment);
3294
+ const segmentBounds = getChildBounds(rootBounds, direction, segmentOffset / 100, segmentSize / 100);
3295
+ segmentOffset += segmentSize;
3296
+ if (segment.direction === undefined) {
3297
+ result.push({
3298
+ ...segmentBounds,
3299
+ group: segment.groups[0]
3300
+ });
3301
+ continue;
3302
+ }
3303
+ let groupOffset = 0;
3304
+ for (const group of segment.groups) {
3305
+ const groupBounds = getChildBounds(segmentBounds, segment.direction, groupOffset / segmentSize, group.size / segmentSize);
3306
+ groupOffset += group.size;
3307
+ result.push({
3308
+ ...groupBounds,
3309
+ group
3310
+ });
3311
+ }
3312
+ }
3313
+ return result;
3314
+ };
3315
+ const getEditorGroupBounds = (layout, width, height) => {
3316
+ return getEditorGroupBoundsFromRoot(layout, {
3208
3317
  height,
3318
+ width,
3319
+ x: 0,
3320
+ y: 0
3321
+ });
3322
+ };
3323
+ const getEditorGroupContentBounds = (layout, bounds, tabHeight) => {
3324
+ return getEditorGroupBoundsFromRoot(layout, bounds).map(({
3325
+ group,
3326
+ ...groupBounds
3327
+ }) => ({
3328
+ ...groupBounds,
3329
+ groupId: group.id,
3330
+ height: groupBounds.height - tabHeight,
3331
+ y: groupBounds.y + tabHeight
3332
+ }));
3333
+ };
3334
+
3335
+ const getSelectedTabBounds = (state, groupId = state.layout.activeGroupId) => {
3336
+ const {
3337
+ height,
3338
+ layout,
3209
3339
  tabHeight,
3210
3340
  width,
3211
3341
  x,
3212
3342
  y
3213
3343
  } = state;
3214
- return {
3215
- height: height - tabHeight,
3344
+ const bounds = getEditorGroupContentBounds(layout, {
3345
+ height,
3216
3346
  width,
3217
3347
  x,
3218
- y: y + tabHeight
3348
+ y
3349
+ }, tabHeight).find(item => item.groupId === groupId);
3350
+ if (!bounds) {
3351
+ return {
3352
+ height: height - tabHeight,
3353
+ width,
3354
+ x,
3355
+ y: y + tabHeight
3356
+ };
3357
+ }
3358
+ return {
3359
+ height: bounds.height,
3360
+ width: bounds.width,
3361
+ x: bounds.x,
3362
+ y: bounds.y
3219
3363
  };
3220
3364
  };
3221
3365
 
@@ -3301,7 +3445,7 @@ const maybeCreateViewletForSelectedTab = async (state, newState, groupIndex, ind
3301
3445
  if (!viewletModuleId) {
3302
3446
  return undefined;
3303
3447
  }
3304
- const bounds = getSelectedTabBounds(newState);
3448
+ const bounds = getSelectedTabBounds(newState, newState.layout.groups[groupIndex].id);
3305
3449
  let stateWithViewlet = createViewletForTab(newState, tabId);
3306
3450
  set$1(uid, state, stateWithViewlet);
3307
3451
  if (switchCommands.length > 0) {
@@ -4131,12 +4275,8 @@ const openInputWithContext = async (context, options) => {
4131
4275
  await context.updateState(() => unsupportedState);
4132
4276
  return;
4133
4277
  }
4134
- const bounds = {
4135
- height: stateAfterModuleId.height - stateAfterModuleId.tabHeight,
4136
- width: stateAfterModuleId.width,
4137
- x: stateAfterModuleId.x,
4138
- y: stateAfterModuleId.y + stateAfterModuleId.tabHeight
4139
- };
4278
+ const tabLocation = findTabById(stateAfterModuleId, tabId);
4279
+ const bounds = getSelectedTabBounds(stateAfterModuleId, tabLocation?.groupId);
4140
4280
  const stateWithViewlet = createViewletForTab(stateAfterModuleId, tabId, viewletModuleId, bounds);
4141
4281
  let intermediateState = stateWithViewlet;
4142
4282
  const {
@@ -4468,42 +4608,6 @@ const retryOpen = async state => {
4468
4608
  return openUri(state, tab.uri);
4469
4609
  };
4470
4610
 
4471
- const getSegmentSize = segment => {
4472
- return segment.groups.reduce((total, group) => total + group.size, 0);
4473
- };
4474
- const getGroupSegments = (groups, parentDirection) => {
4475
- const segments = [];
4476
- let index = 0;
4477
- while (index < groups.length) {
4478
- const group = groups[index];
4479
- if (group.direction !== parentDirection) {
4480
- const startIndex = index;
4481
- const nestedGroups = [group];
4482
- const {
4483
- segmentId
4484
- } = group;
4485
- index++;
4486
- while (index < groups.length && groups[index].direction === group.direction && groups[index].segmentId === segmentId) {
4487
- nestedGroups.push(groups[index]);
4488
- index++;
4489
- }
4490
- segments.push({
4491
- direction: nestedGroups.length === 1 ? undefined : group.direction,
4492
- groups: nestedGroups,
4493
- startIndex
4494
- });
4495
- continue;
4496
- }
4497
- segments.push({
4498
- direction: undefined,
4499
- groups: [group],
4500
- startIndex: index
4501
- });
4502
- index++;
4503
- }
4504
- return segments;
4505
- };
4506
-
4507
4611
  const rebalanceGroupSizes = groups => {
4508
4612
  const groupCount = groups.length;
4509
4613
  if (groupCount === 0) {
@@ -4822,60 +4926,6 @@ const handleDragLeave = state => {
4822
4926
  };
4823
4927
  };
4824
4928
 
4825
- const getChildBounds = (bounds, direction, offset, size) => {
4826
- if (direction === Horizontal) {
4827
- return {
4828
- height: bounds.height,
4829
- width: bounds.width * size,
4830
- x: bounds.x + bounds.width * offset,
4831
- y: bounds.y
4832
- };
4833
- }
4834
- return {
4835
- height: bounds.height * size,
4836
- width: bounds.width,
4837
- x: bounds.x,
4838
- y: bounds.y + bounds.height * offset
4839
- };
4840
- };
4841
- const getEditorGroupBounds = (layout, width, height) => {
4842
- const {
4843
- direction,
4844
- groups
4845
- } = layout;
4846
- const segments = getGroupSegments(groups, direction);
4847
- const rootBounds = {
4848
- height,
4849
- width,
4850
- x: 0,
4851
- y: 0
4852
- };
4853
- const result = [];
4854
- let segmentOffset = 0;
4855
- for (const segment of segments) {
4856
- const segmentSize = getSegmentSize(segment);
4857
- const segmentBounds = getChildBounds(rootBounds, direction, segmentOffset / 100, segmentSize / 100);
4858
- segmentOffset += segmentSize;
4859
- if (segment.direction === undefined) {
4860
- result.push({
4861
- ...segmentBounds,
4862
- group: segment.groups[0]
4863
- });
4864
- continue;
4865
- }
4866
- let groupOffset = 0;
4867
- for (const group of segment.groups) {
4868
- const groupBounds = getChildBounds(segmentBounds, segment.direction, groupOffset / segmentSize, group.size / segmentSize);
4869
- groupOffset += group.size;
4870
- result.push({
4871
- ...groupBounds,
4872
- group
4873
- });
4874
- }
4875
- }
4876
- return result;
4877
- };
4878
-
4879
4929
  const None = 0;
4880
4930
  const Up = 1;
4881
4931
  const Down = 2;
@@ -5361,14 +5411,7 @@ const newFile = async state => {
5361
5411
  uri: 'untitled:///1'
5362
5412
  };
5363
5413
  const stateWithNewTab = openTab(newState, targetGroupId, newTab);
5364
-
5365
- // Calculate bounds: use main area bounds minus tab height
5366
- const bounds = {
5367
- height: stateWithNewTab.height - stateWithNewTab.tabHeight,
5368
- width: stateWithNewTab.width,
5369
- x: stateWithNewTab.x,
5370
- y: stateWithNewTab.y + stateWithNewTab.tabHeight
5371
- };
5414
+ const bounds = getSelectedTabBounds(stateWithNewTab, targetGroupId);
5372
5415
  const viewletModuleId = EditorText;
5373
5416
  const stateWithViewlet = createViewletForTab(stateWithNewTab, tabId);
5374
5417
  let intermediateState = stateWithViewlet;
@@ -5408,7 +5451,7 @@ const handleHeaderDoubleClick = async (state, className, groupIndexRaw) => {
5408
5451
  return newFile(state);
5409
5452
  };
5410
5453
 
5411
- const getAllTabs = layout => {
5454
+ const getAllTabs$1 = layout => {
5412
5455
  const {
5413
5456
  groups
5414
5457
  } = layout;
@@ -5428,7 +5471,7 @@ const loadFileIcons = async state => {
5428
5471
  groups
5429
5472
  } = layout;
5430
5473
  try {
5431
- const allTabs = getAllTabs(layout);
5474
+ const allTabs = getAllTabs$1(layout);
5432
5475
  const {
5433
5476
  newFileIconCache
5434
5477
  } = await getFileIconsForTabs(allTabs, fileIconCache);
@@ -5535,13 +5578,6 @@ const resizeChild = async (editorUid, dimensions) => {
5535
5578
  }
5536
5579
  };
5537
5580
  const handleResize = async (state, dimensions) => {
5538
- const {
5539
- height,
5540
- width,
5541
- x,
5542
- y
5543
- } = dimensions;
5544
-
5545
5581
  // Resize all editor children to their new bounds
5546
5582
  const {
5547
5583
  layout,
@@ -5550,20 +5586,24 @@ const handleResize = async (state, dimensions) => {
5550
5586
  const {
5551
5587
  groups
5552
5588
  } = layout;
5553
- const contentHeight = height - tabHeight;
5589
+ const groupBounds = getEditorGroupContentBounds(layout, dimensions, tabHeight);
5554
5590
  const resizePromises = [];
5555
- const tabs = groups.flatMap(group => group.tabs);
5556
- for (const tab of tabs) {
5557
- if (tab.editorUid === -1) {
5591
+ for (const group of groups) {
5592
+ const bounds = groupBounds.find(item => item.groupId === group.id);
5593
+ if (!bounds) {
5558
5594
  continue;
5559
5595
  }
5560
- const resizePromise = resizeChild(tab.editorUid, {
5561
- height: contentHeight,
5562
- width,
5563
- x,
5564
- y: y + tabHeight
5565
- });
5566
- resizePromises.push(resizePromise);
5596
+ const dimensions = {
5597
+ height: bounds.height,
5598
+ width: bounds.width,
5599
+ x: bounds.x,
5600
+ y: bounds.y
5601
+ };
5602
+ for (const tab of group.tabs) {
5603
+ if (tab.editorUid !== -1) {
5604
+ resizePromises.push(resizeChild(tab.editorUid, dimensions));
5605
+ }
5606
+ }
5567
5607
  }
5568
5608
  const resizeCommands = await Promise.all(resizePromises);
5569
5609
  return resizeCommands.flat();
@@ -5768,6 +5808,7 @@ const handleSashPointerDown = async (state, sashId, clientX, clientY) => {
5768
5808
  layout
5769
5809
  } = state;
5770
5810
  const {
5811
+ direction,
5771
5812
  groups
5772
5813
  } = layout;
5773
5814
  const beforeGroup = groups.find(group => group.id === parsed.beforeGroupId);
@@ -5778,13 +5819,20 @@ const handleSashPointerDown = async (state, sashId, clientX, clientY) => {
5778
5819
  if (!Number.isFinite(clientX) || !Number.isFinite(clientY)) {
5779
5820
  return state;
5780
5821
  }
5822
+ const segments = getGroupSegments(groups, direction);
5823
+ const beforeSegment = getGroupSegment(segments, parsed.beforeGroupId);
5824
+ const afterSegment = getGroupSegment(segments, parsed.afterGroupId);
5825
+ if (!beforeSegment || !afterSegment) {
5826
+ return state;
5827
+ }
5828
+ const isNestedSash = beforeSegment === afterSegment;
5781
5829
  return {
5782
5830
  ...state,
5783
5831
  sashDrag: {
5784
5832
  afterGroupId: parsed.afterGroupId,
5785
- afterSize: afterGroup.size,
5833
+ afterSize: isNestedSash ? afterGroup.size : getSegmentSize(afterSegment),
5786
5834
  beforeGroupId: parsed.beforeGroupId,
5787
- beforeSize: beforeGroup.size,
5835
+ beforeSize: isNestedSash ? beforeGroup.size : getSegmentSize(beforeSegment),
5788
5836
  sashId,
5789
5837
  startClientX: clientX,
5790
5838
  startClientY: clientY
@@ -5792,6 +5840,14 @@ const handleSashPointerDown = async (state, sashId, clientX, clientY) => {
5792
5840
  };
5793
5841
  };
5794
5842
 
5843
+ const resizeGroupInSegment = (segment, groupId, segmentSize) => {
5844
+ const group = segment.groups.find(group => group.id === groupId);
5845
+ if (!group) {
5846
+ return undefined;
5847
+ }
5848
+ const previousSegmentSize = getSegmentSize(segment);
5849
+ return round(group.size / previousSegmentSize * segmentSize);
5850
+ };
5795
5851
  const handleSashPointerMove = async (state, clientX, clientY) => {
5796
5852
  const {
5797
5853
  height,
@@ -5811,6 +5867,13 @@ const handleSashPointerMove = async (state, clientX, clientY) => {
5811
5867
  direction,
5812
5868
  groups
5813
5869
  } = layout;
5870
+ const segments = getGroupSegments(groups, direction);
5871
+ const beforeSegment = getGroupSegment(segments, sashDrag.beforeGroupId);
5872
+ const afterSegment = getGroupSegment(segments, sashDrag.afterGroupId);
5873
+ if (!beforeSegment || !afterSegment) {
5874
+ return state;
5875
+ }
5876
+ const isNestedSash = beforeSegment === afterSegment;
5814
5877
  const axisSize = direction === Horizontal ? width : height;
5815
5878
  if (!axisSize) {
5816
5879
  return state;
@@ -5828,6 +5891,23 @@ const handleSashPointerMove = async (state, clientX, clientY) => {
5828
5891
  const beforeSize = clamp(sashDrag.beforeSize + deltaPercent, minGroupSize, totalResizableSize - minGroupSize);
5829
5892
  const afterSize = totalResizableSize - beforeSize;
5830
5893
  const newGroups = groups.map(group => {
5894
+ if (!isNestedSash) {
5895
+ const resizedBeforeGroupSize = resizeGroupInSegment(beforeSegment, group.id, beforeSize);
5896
+ if (resizedBeforeGroupSize !== undefined) {
5897
+ return {
5898
+ ...group,
5899
+ size: resizedBeforeGroupSize
5900
+ };
5901
+ }
5902
+ const resizedAfterGroupSize = resizeGroupInSegment(afterSegment, group.id, afterSize);
5903
+ if (resizedAfterGroupSize !== undefined) {
5904
+ return {
5905
+ ...group,
5906
+ size: resizedAfterGroupSize
5907
+ };
5908
+ }
5909
+ return group;
5910
+ }
5831
5911
  if (group.id === sashDrag.beforeGroupId) {
5832
5912
  return {
5833
5913
  ...group,
@@ -5885,6 +5965,77 @@ const handleTabContextMenu = async (state, button, x, y, groupIndexRaw = '', tab
5885
5965
  return state;
5886
5966
  };
5887
5967
 
5968
+ const getFocusIndex = (key, index, tabCount) => {
5969
+ switch (key) {
5970
+ case 'ArrowLeft':
5971
+ return (index + tabCount - 1) % tabCount;
5972
+ case 'ArrowRight':
5973
+ return (index + 1) % tabCount;
5974
+ case 'End':
5975
+ return tabCount - 1;
5976
+ case 'Home':
5977
+ return 0;
5978
+ default:
5979
+ return -1;
5980
+ }
5981
+ };
5982
+ const focusTab = async (state, groupIndex, index) => {
5983
+ const selector = `.${MainTab}[data-group-index="${groupIndex}"][data-index="${index}"]`;
5984
+ if (isConnected()) {
5985
+ await invoke('Viewlet.focusSelector', state.uid, selector);
5986
+ } else {
5987
+ await invoke$1('Viewlet.focusSelector', state.uid, selector);
5988
+ }
5989
+ };
5990
+ const handleTabKeyDown = async (state, groupIndexRaw, indexRaw, key) => {
5991
+ if (!groupIndexRaw || !indexRaw) {
5992
+ return state;
5993
+ }
5994
+ const groupIndex = Number.parseInt(groupIndexRaw);
5995
+ const index = Number.parseInt(indexRaw);
5996
+ const group = state.layout.groups[groupIndex];
5997
+ if (!group || index < 0 || index >= group.tabs.length) {
5998
+ return state;
5999
+ }
6000
+ if ([' ', 'Enter', 'Space'].includes(key)) {
6001
+ return selectTab(state, groupIndex, index);
6002
+ }
6003
+ const focusIndex = getFocusIndex(key, index, group.tabs.length);
6004
+ if (focusIndex === -1) {
6005
+ return state;
6006
+ }
6007
+ await focusTab(state, groupIndex, focusIndex);
6008
+ return state;
6009
+ };
6010
+
6011
+ const getPixelDelta = (state, deltaMode, deltaY) => {
6012
+ switch (deltaMode) {
6013
+ case 1:
6014
+ return deltaY * 16;
6015
+ case 2:
6016
+ return deltaY * state.width;
6017
+ default:
6018
+ return deltaY;
6019
+ }
6020
+ };
6021
+ const handleTabsWheel = async (state, groupIndexRaw, deltaMode, deltaY) => {
6022
+ if (!groupIndexRaw || deltaY === 0) {
6023
+ return state;
6024
+ }
6025
+ const groupIndex = Number.parseInt(groupIndexRaw);
6026
+ if (!state.layout.groups[groupIndex]) {
6027
+ return state;
6028
+ }
6029
+ const selector = `.${MainTabs}[data-group-index="${groupIndex}"]`;
6030
+ const pixelDelta = getPixelDelta(state, deltaMode, deltaY);
6031
+ if (isConnected()) {
6032
+ await invoke('Viewlet.scrollSelectorBy', state.uid, selector, pixelDelta);
6033
+ } else {
6034
+ await invoke$1('Viewlet.scrollSelectorBy', state.uid, selector, pixelDelta);
6035
+ }
6036
+ return state;
6037
+ };
6038
+
5888
6039
  const handleUriChange = async (state, oldUri, newUri) => {
5889
6040
  const {
5890
6041
  homeDirUri,
@@ -6056,7 +6207,10 @@ const tryRestoreLayout = savedState => {
6056
6207
  return normalizedLayout;
6057
6208
  };
6058
6209
 
6059
- const createViewlets = async (layout, viewletModuleIds, bounds) => {
6210
+ const createViewlets = async (state, viewletModuleIds) => {
6211
+ const {
6212
+ layout
6213
+ } = state;
6060
6214
  const {
6061
6215
  groups
6062
6216
  } = layout;
@@ -6067,7 +6221,8 @@ const createViewlets = async (layout, viewletModuleIds, bounds) => {
6067
6221
  if (activeTab && viewletModuleIds[activeTab.id]) {
6068
6222
  const editorUid = activeTab.editorUid === -1 ? create$2() : activeTab.editorUid;
6069
6223
  editorUids[activeTab.id] = editorUid;
6070
- const title = await createViewlet(viewletModuleIds[activeTab.id], editorUid, activeTab.id, bounds, activeTab.uri);
6224
+ const bounds = getSelectedTabBounds(state, group.id);
6225
+ const title = await createViewlet(viewletModuleIds[activeTab.id], editorUid, activeTab.id, bounds, activeTab.uri || '');
6071
6226
  if (title) {
6072
6227
  titles[activeTab.id] = title;
6073
6228
  }
@@ -6141,19 +6296,10 @@ const updateTabs = (state, editorUids) => {
6141
6296
  };
6142
6297
 
6143
6298
  const restoreAndCreateEditors = async (state, restoredLayout) => {
6144
- const {
6145
- tabHeight
6146
- } = state;
6147
6299
  let newState = {
6148
6300
  ...state,
6149
6301
  layout: restoredLayout
6150
6302
  };
6151
- const bounds = {
6152
- height: newState.height - tabHeight,
6153
- width: newState.width,
6154
- x: newState.x,
6155
- y: newState.y + tabHeight
6156
- };
6157
6303
 
6158
6304
  // Get viewlet module IDs for all active tabs
6159
6305
  const viewletModuleIds = await getViewletModuleIds(newState.layout);
@@ -6162,7 +6308,7 @@ const restoreAndCreateEditors = async (state, restoredLayout) => {
6162
6308
  const {
6163
6309
  editorUids,
6164
6310
  titles
6165
- } = await createViewlets(newState.layout, viewletModuleIds, bounds);
6311
+ } = await createViewlets(newState, viewletModuleIds);
6166
6312
 
6167
6313
  // Update tabs with editor UIDs
6168
6314
  newState = updateTabs(newState, editorUids);
@@ -6172,6 +6318,7 @@ const restoreAndCreateEditors = async (state, restoredLayout) => {
6172
6318
  const activeTab = group.tabs.find(tab => tab.id === group.activeTabId);
6173
6319
  if (activeTab && viewletModuleIds[activeTab.id]) {
6174
6320
  const editorUid = editorUids[activeTab.id];
6321
+ getSelectedTabBounds(newState, group.id);
6175
6322
  newState = createViewletForTab(newState, activeTab.id);
6176
6323
  newState = handleViewletReady(newState, editorUid, titles[activeTab.id]);
6177
6324
  }
@@ -6298,6 +6445,30 @@ const hasActiveTextEditor = state => {
6298
6445
  return activeTab?.tab.editorInput?.type === 'editor';
6299
6446
  };
6300
6447
 
6448
+ const getTabs = group => {
6449
+ return group.tabs;
6450
+ };
6451
+ const getAllTabs = state => {
6452
+ const {
6453
+ layout
6454
+ } = state;
6455
+ const {
6456
+ groups
6457
+ } = layout;
6458
+ return groups.flatMap(getTabs);
6459
+ };
6460
+
6461
+ const isDirty = tab => {
6462
+ return tab.isDirty;
6463
+ };
6464
+ const getDirtyTabs = state => {
6465
+ return getAllTabs(state).filter(isDirty);
6466
+ };
6467
+
6468
+ const hasDirtyTabs = state => {
6469
+ return getDirtyTabs(state).length > 0;
6470
+ };
6471
+
6301
6472
  const initialize$1 = async () => {
6302
6473
  // Kept as a compatibility command for existing renderer startup code.
6303
6474
  };
@@ -6695,6 +6866,24 @@ const refresh = state => {
6695
6866
  };
6696
6867
  };
6697
6868
 
6869
+ const renderActiveTabVisibility = (oldState, newState) => {
6870
+ const {
6871
+ activeGroupId,
6872
+ groups
6873
+ } = newState.layout;
6874
+ const groupIndex = groups.findIndex(group => group.id === activeGroupId);
6875
+ if (groupIndex === -1) {
6876
+ return [];
6877
+ }
6878
+ const group = groups[groupIndex];
6879
+ const tabIndex = group.tabs.findIndex(tab => tab.id === group.activeTabId);
6880
+ if (tabIndex === -1) {
6881
+ return [];
6882
+ }
6883
+ const selector = `.${MainTab}[data-group-index="${groupIndex}"][data-index="${tabIndex}"]`;
6884
+ return ['Viewlet.scrollSelectorIntoView', newState.uid, selector];
6885
+ };
6886
+
6698
6887
  const getDragOverlayCss = dragOverlay => {
6699
6888
  if (!dragOverlay) {
6700
6889
  return [];
@@ -7168,6 +7357,8 @@ const HandleDrop = 25;
7168
7357
  const HandleDragStart = 26;
7169
7358
  const HandleDragEnd = 27;
7170
7359
  const HandleTabMouseUp = 28;
7360
+ const HandleTabKeyDown = 29;
7361
+ const HandleTabsWheel = 30;
7171
7362
 
7172
7363
  const dragOverlayVirtualDom = {
7173
7364
  childCount: 0,
@@ -7396,9 +7587,11 @@ const renderTab = (tab, isActive, tabIndex, groupIndex) => {
7396
7587
  onDblClick: HandleDoubleClick,
7397
7588
  onDragEnd: HandleDragEnd,
7398
7589
  onDragStart: HandleDragStart,
7590
+ onKeyDown: HandleTabKeyDown,
7399
7591
  onMouseDown: HandleClickTab,
7400
7592
  onMouseUp: HandleTabMouseUp,
7401
7593
  role: Tab$1,
7594
+ tabIndex: isActive ? 0 : -1,
7402
7595
  title: tab.uriTitle || tab.uri || tab.title,
7403
7596
  type: Div
7404
7597
  }, ...renderTabIcon(tab), tabTitleNode, text(tab.title), ...closeButtonNodes];
@@ -7408,6 +7601,8 @@ const getTabsVirtualDom = (group, groupIndex, tabsChildCount) => {
7408
7601
  return [{
7409
7602
  childCount: tabsChildCount,
7410
7603
  className: MainTabs,
7604
+ 'data-groupIndex': groupIndex,
7605
+ onWheel: HandleTabsWheel,
7411
7606
  role: TabList,
7412
7607
  type: Div
7413
7608
  }, ...group.tabs.flatMap((tab, tabIndex) => renderTab(tab, tab.id === group.activeTabId, tabIndex, groupIndex))];
@@ -7768,6 +7963,8 @@ const renderPendingViewletUpdate = (oldState, newState) => {
7768
7963
 
7769
7964
  const getRenderer = diffType => {
7770
7965
  switch (diffType) {
7966
+ case RenderActiveTabVisibility:
7967
+ return renderActiveTabVisibility;
7771
7968
  case RenderCss:
7772
7969
  return renderCss;
7773
7970
  case RenderDragData:
@@ -7820,10 +8017,17 @@ const renderEventListeners = () => {
7820
8017
  params: ['handleClick', TargetName]
7821
8018
  }, {
7822
8019
  name: HandleClickClose,
7823
- params: ['handleClickCloseTab', 'event.target.dataset.groupIndex', 'event.target.dataset.index']
8020
+ params: ['handleClickCloseTab', 'event.currentTarget.dataset.groupIndex', 'event.currentTarget.dataset.index'],
8021
+ stopPropagation: true
7824
8022
  }, {
7825
8023
  name: HandleClickTab,
7826
- params: ['handleClickTab', 'event.target.dataset.groupIndex', 'event.target.dataset.index', Button$1]
8024
+ params: ['handleClickTab', 'event.currentTarget.dataset.groupIndex', 'event.currentTarget.dataset.index', Button$1]
8025
+ }, {
8026
+ name: HandleTabKeyDown,
8027
+ params: ['handleTabKeyDown', 'event.currentTarget.dataset.groupIndex', 'event.currentTarget.dataset.index', Key]
8028
+ }, {
8029
+ name: HandleTabsWheel,
8030
+ params: ['handleTabsWheel', 'event.currentTarget.dataset.groupIndex', DeltaMode, DeltaY]
7827
8031
  }, {
7828
8032
  name: HandleDoubleClick,
7829
8033
  params: ['handleDoubleClick', 'event.target.dataset.groupIndex', 'event.target.dataset.index']
@@ -7963,12 +8167,7 @@ const reopenEditorWith = async (context, preferredEditorId) => {
7963
8167
  errorMessage: undefined,
7964
8168
  loadingState: undefined
7965
8169
  });
7966
- const bounds = {
7967
- height: resetState.height - resetState.tabHeight,
7968
- width: resetState.width,
7969
- x: resetState.x,
7970
- y: resetState.y + resetState.tabHeight
7971
- };
8170
+ const bounds = getSelectedTabBounds(resetState, latestTab.groupId);
7972
8171
  const stateWithViewlet = createViewletForTab(resetState, initialTab.id);
7973
8172
  await context.updateState(() => stateWithViewlet);
7974
8173
  const tabWithViewlet = findTabById(stateWithViewlet, initialTab.id);
@@ -8358,6 +8557,7 @@ const commandMap = {
8358
8557
  'Main.closeActiveEditor': wrapSerialCommand(closeActiveEditor),
8359
8558
  'Main.closeAll': wrapSerialCommand(closeAll$1),
8360
8559
  'Main.closeAllEditors': wrapSerialCommand(closeAll$1),
8560
+ 'Main.closeAllEditorsAndSave': wrapSerialCommand(closeAllAndSave),
8361
8561
  'Main.closeFocusedTab': wrapSerialCommand(closeFocusedTab),
8362
8562
  'Main.closeOthers': wrapSerialCommand(closeOtherTabs),
8363
8563
  'Main.closeSaved': wrapSerialCommand(closeSaved$1),
@@ -8373,6 +8573,7 @@ const commandMap = {
8373
8573
  'Main.handleModifiedStatusChange': wrapAsyncCommand(handleModifiedStatusChangeWithContext),
8374
8574
  'Main.handleTabContextMenu': wrapSerialCommand(handleTabContextMenu),
8375
8575
  'Main.hasActiveTextEditor': wrapGetter(hasActiveTextEditor),
8576
+ 'Main.hasDirtyTabs': wrapGetter(hasDirtyTabs),
8376
8577
  'Main.openInput': wrapSerialAsyncCommand(openInputWithContext),
8377
8578
  'Main.openUri': wrapSerialAsyncCommand(openUriWithContext),
8378
8579
  'Main.openUris': wrapSerialAsyncCommand(openUrisWithContext),
@@ -8383,6 +8584,7 @@ const commandMap = {
8383
8584
  'MainArea.closeActiveEditor': wrapSerialCommand(closeActiveEditor),
8384
8585
  'MainArea.closeAll': wrapSerialCommand(closeAll$1),
8385
8586
  'MainArea.closeAllEditors': wrapSerialCommand(closeAll$1),
8587
+ 'MainArea.closeAllEditorsAndSave': wrapSerialCommand(closeAllAndSave),
8386
8588
  'MainArea.closeEditorGroup': wrapSerialCommand(closeEditorGroup$1),
8387
8589
  'MainArea.closeFocusedTab': wrapSerialCommand(closeFocusedTab),
8388
8590
  'MainArea.closeOthers': wrapSerialCommand(closeOtherTabs),
@@ -8428,12 +8630,15 @@ const commandMap = {
8428
8630
  'MainArea.handleSashPointerMove': wrapSerialCommand(handleSashPointerMove),
8429
8631
  'MainArea.handleSashPointerUp': wrapSerialCommand(handleSashPointerUp),
8430
8632
  'MainArea.handleTabContextMenu': wrapSerialCommand(handleTabContextMenu),
8633
+ 'MainArea.handleTabKeyDown': wrapSerialCommand(handleTabKeyDown),
8431
8634
  'MainArea.handleTabMouseUp': wrapSerialCommand(resetPointerDown),
8635
+ 'MainArea.handleTabsWheel': wrapSerialCommand(handleTabsWheel),
8432
8636
  'MainArea.handleTestWorkerMessagePort': handleTestWorkerMessagePort,
8433
8637
  'MainArea.handleUriChange': wrapSerialCommand(handleUriChange),
8434
8638
  'MainArea.handleWorkspaceChange': wrapSerialCommand(handleWorkspaceChange),
8435
8639
  'MainArea.handleWorkspaceRefresh': wrapAsyncCommand(handleWorkspaceRefreshWithContext),
8436
8640
  'MainArea.hasActiveTextEditor': wrapGetter(hasActiveTextEditor),
8641
+ 'MainArea.hasDirtyTabs': wrapGetter(hasDirtyTabs),
8437
8642
  'MainArea.initialize': initialize$1,
8438
8643
  'MainArea.loadContent': loadContentTracked,
8439
8644
  'MainArea.moveIntoNewWindow': wrapSerialCommand(moveIntoNewWindow),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/main-area-worker",
3
- "version": "9.50.1",
3
+ "version": "9.52.0",
4
4
  "description": "Main Area Worker",
5
5
  "repository": {
6
6
  "type": "git",