@lvce-editor/main-area-worker 6.2.0 → 6.4.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.
@@ -2071,6 +2071,11 @@ const handleClickTab = async (state, groupIndexRaw, indexRaw) => {
2071
2071
  return selectTab(state, groupIndex, index);
2072
2072
  };
2073
2073
 
2074
+ const handleDoubleClick = async state => {
2075
+ // TODO: implement handleDoubleClick
2076
+ return state;
2077
+ };
2078
+
2074
2079
  const handleResize = async (state, x, y, width, height) => {
2075
2080
  number(x);
2076
2081
  number(y);
@@ -2124,83 +2129,6 @@ const handleTabContextMenu = async (state, x, y) => {
2124
2129
  return state;
2125
2130
  };
2126
2131
 
2127
- const handleWorkspaceChange = state => {
2128
- return {
2129
- ...state,
2130
- layout: {
2131
- ...state.layout,
2132
- activeGroupId: undefined,
2133
- groups: []
2134
- }
2135
- };
2136
- };
2137
-
2138
- const id = 7201;
2139
- const sendMessagePortToExtensionHostWorker = async port => {
2140
- await sendMessagePortToExtensionHostWorker$1(port, id);
2141
- };
2142
-
2143
- const createExtensionHostRpc = async () => {
2144
- try {
2145
- const rpc = await TransferMessagePortRpcParent.create({
2146
- commandMap: {},
2147
- send: sendMessagePortToExtensionHostWorker
2148
- });
2149
- return rpc;
2150
- } catch (error) {
2151
- throw new VError(error, `Failed to create extension host rpc`);
2152
- }
2153
- };
2154
-
2155
- const initialize = async () => {
2156
- const rpc = await createExtensionHostRpc();
2157
- set$3(rpc);
2158
- };
2159
-
2160
- const isValidTab = tab => {
2161
- return tab && typeof tab.id === 'number' && typeof tab.title === 'string' && typeof tab.isDirty === 'boolean' && typeof tab.editorUid === 'number' && typeof tab.icon === 'string' && (tab.editorType === 'text' || tab.editorType === 'custom');
2162
- };
2163
-
2164
- const isValidEditorGroup = group => {
2165
- return group && typeof group.id === 'number' && Array.isArray(group.tabs) && group.tabs.every(isValidTab) && (group.activeTabId === undefined || typeof group.activeTabId === 'number') && typeof group.focused === 'boolean' && typeof group.size === 'number' && group.size > 0 && typeof group.isEmpty === 'boolean';
2166
- };
2167
-
2168
- const isValidMainAreaLayout = layout => {
2169
- if (!layout || typeof layout !== 'object') {
2170
- return false;
2171
- }
2172
- const layoutObj = layout;
2173
- if (layoutObj.activeGroupId !== undefined && typeof layoutObj.activeGroupId !== 'number') {
2174
- return false;
2175
- }
2176
- if (layoutObj.direction !== 'horizontal' && layoutObj.direction !== 'vertical') {
2177
- return false;
2178
- }
2179
- if (!Array.isArray(layoutObj.groups)) {
2180
- return false;
2181
- }
2182
- if (!layoutObj.groups.every(isValidEditorGroup)) {
2183
- return false;
2184
- }
2185
- return true;
2186
- };
2187
-
2188
- const tryRestoreLayout = savedState => {
2189
- if (savedState === undefined || savedState === null) {
2190
- return undefined;
2191
- }
2192
- if (typeof savedState !== 'object') {
2193
- return undefined;
2194
- }
2195
- const {
2196
- layout
2197
- } = savedState;
2198
- if (!isValidMainAreaLayout(layout)) {
2199
- return undefined;
2200
- }
2201
- return layout;
2202
- };
2203
-
2204
2132
  const getIconsCached = (dirents, fileIconCache) => {
2205
2133
  return dirents.map(dirent => fileIconCache[dirent]);
2206
2134
  };
@@ -2327,6 +2255,140 @@ const loadFileIcons = async state => {
2327
2255
  }
2328
2256
  };
2329
2257
 
2258
+ const getBasename = uri => {
2259
+ const lastSlashIndex = uri.lastIndexOf('/');
2260
+ if (lastSlashIndex === -1) {
2261
+ return uri;
2262
+ }
2263
+ return uri.slice(lastSlashIndex + 1);
2264
+ };
2265
+ const getLabel = uri => {
2266
+ if (uri.startsWith('settings://')) {
2267
+ return 'Settings';
2268
+ }
2269
+ if (uri.startsWith('simple-browser://')) {
2270
+ return 'Simple Browser';
2271
+ }
2272
+ return getBasename(uri);
2273
+ };
2274
+
2275
+ const handleUriChange = async (state, oldUri, newUri) => {
2276
+ const {
2277
+ layout
2278
+ } = state;
2279
+ const {
2280
+ groups
2281
+ } = layout;
2282
+ const newTitle = getLabel(newUri);
2283
+ const updatedGroups = groups.map(group => {
2284
+ return {
2285
+ ...group,
2286
+ tabs: group.tabs.map(tab => {
2287
+ if (tab.uri === oldUri) {
2288
+ return {
2289
+ ...tab,
2290
+ title: newTitle,
2291
+ uri: newUri
2292
+ };
2293
+ }
2294
+ return tab;
2295
+ })
2296
+ };
2297
+ });
2298
+ const stateWithUpdatedUri = {
2299
+ ...state,
2300
+ layout: {
2301
+ ...layout,
2302
+ groups: updatedGroups
2303
+ }
2304
+ };
2305
+
2306
+ // Load icons for the new URI
2307
+ const result = await loadFileIcons(stateWithUpdatedUri);
2308
+ return {
2309
+ ...stateWithUpdatedUri,
2310
+ fileIconCache: result.fileIconCache,
2311
+ layout: result.updatedLayout
2312
+ };
2313
+ };
2314
+
2315
+ const handleWorkspaceChange = state => {
2316
+ return {
2317
+ ...state,
2318
+ layout: {
2319
+ ...state.layout,
2320
+ activeGroupId: undefined,
2321
+ groups: []
2322
+ }
2323
+ };
2324
+ };
2325
+
2326
+ const id = 7201;
2327
+ const sendMessagePortToExtensionHostWorker = async port => {
2328
+ await sendMessagePortToExtensionHostWorker$1(port, id);
2329
+ };
2330
+
2331
+ const createExtensionHostRpc = async () => {
2332
+ try {
2333
+ const rpc = await TransferMessagePortRpcParent.create({
2334
+ commandMap: {},
2335
+ send: sendMessagePortToExtensionHostWorker
2336
+ });
2337
+ return rpc;
2338
+ } catch (error) {
2339
+ throw new VError(error, `Failed to create extension host rpc`);
2340
+ }
2341
+ };
2342
+
2343
+ const initialize = async () => {
2344
+ const rpc = await createExtensionHostRpc();
2345
+ set$3(rpc);
2346
+ };
2347
+
2348
+ const isValidTab = tab => {
2349
+ return tab && typeof tab.id === 'number' && typeof tab.title === 'string' && typeof tab.isDirty === 'boolean' && typeof tab.editorUid === 'number' && typeof tab.icon === 'string' && (tab.editorType === 'text' || tab.editorType === 'custom');
2350
+ };
2351
+
2352
+ const isValidEditorGroup = group => {
2353
+ return group && typeof group.id === 'number' && Array.isArray(group.tabs) && group.tabs.every(isValidTab) && (group.activeTabId === undefined || typeof group.activeTabId === 'number') && typeof group.focused === 'boolean' && typeof group.size === 'number' && group.size > 0 && typeof group.isEmpty === 'boolean';
2354
+ };
2355
+
2356
+ const isValidMainAreaLayout = layout => {
2357
+ if (!layout || typeof layout !== 'object') {
2358
+ return false;
2359
+ }
2360
+ const layoutObj = layout;
2361
+ if (layoutObj.activeGroupId !== undefined && typeof layoutObj.activeGroupId !== 'number') {
2362
+ return false;
2363
+ }
2364
+ if (layoutObj.direction !== 'horizontal' && layoutObj.direction !== 'vertical') {
2365
+ return false;
2366
+ }
2367
+ if (!Array.isArray(layoutObj.groups)) {
2368
+ return false;
2369
+ }
2370
+ if (!layoutObj.groups.every(isValidEditorGroup)) {
2371
+ return false;
2372
+ }
2373
+ return true;
2374
+ };
2375
+
2376
+ const tryRestoreLayout = savedState => {
2377
+ if (savedState === undefined || savedState === null) {
2378
+ return undefined;
2379
+ }
2380
+ if (typeof savedState !== 'object') {
2381
+ return undefined;
2382
+ }
2383
+ const {
2384
+ layout
2385
+ } = savedState;
2386
+ if (!isValidMainAreaLayout(layout)) {
2387
+ return undefined;
2388
+ }
2389
+ return layout;
2390
+ };
2391
+
2330
2392
  const createViewlets = async (layout, viewletModuleIds, bounds) => {
2331
2393
  const editorUids = {};
2332
2394
  for (const group of layout.groups) {
@@ -2578,23 +2640,6 @@ const getMenuEntries = async (state, props) => {
2578
2640
  }
2579
2641
  };
2580
2642
 
2581
- const getBasename = uri => {
2582
- const lastSlashIndex = uri.lastIndexOf('/');
2583
- if (lastSlashIndex === -1) {
2584
- return uri;
2585
- }
2586
- return uri.slice(lastSlashIndex + 1);
2587
- };
2588
- const getLabel = uri => {
2589
- if (uri.startsWith('settings://')) {
2590
- return 'Settings';
2591
- }
2592
- if (uri.startsWith('simple-browser://')) {
2593
- return 'Simple Browser';
2594
- }
2595
- return getBasename(uri);
2596
- };
2597
-
2598
2643
  const createEmptyGroup = (state, uri, requestId) => {
2599
2644
  const {
2600
2645
  layout
@@ -2636,6 +2681,18 @@ const createEmptyGroup = (state, uri, requestId) => {
2636
2681
  };
2637
2682
  };
2638
2683
 
2684
+ const getActiveTabId = state => {
2685
+ const {
2686
+ layout
2687
+ } = state;
2688
+ const {
2689
+ activeGroupId,
2690
+ groups
2691
+ } = layout;
2692
+ const activeGroup = groups.find(g => g.id === activeGroupId);
2693
+ return activeGroup?.activeTabId;
2694
+ };
2695
+
2639
2696
  const openTab = (state, groupId, tab) => {
2640
2697
  const newTab = 'id' in tab && tab.id !== undefined ? tab : {
2641
2698
  ...tab,
@@ -2668,6 +2725,111 @@ const openTab = (state, groupId, tab) => {
2668
2725
  };
2669
2726
  };
2670
2727
 
2728
+ const newFile = async state => {
2729
+ object(state);
2730
+ const {
2731
+ layout,
2732
+ uid
2733
+ } = state;
2734
+ const {
2735
+ activeGroupId,
2736
+ groups
2737
+ } = layout;
2738
+
2739
+ // Find the active group
2740
+ const activeGroup = activeGroupId === undefined ? groups.find(group => group.focused) : groups.find(group => group.id === activeGroupId);
2741
+
2742
+ // Prepare initial state
2743
+ let newState = state;
2744
+ let targetGroupId;
2745
+ if (activeGroup) {
2746
+ targetGroupId = activeGroup.id;
2747
+ } else {
2748
+ // No active group, create an empty one
2749
+ newState = createEmptyGroup(state, '');
2750
+ const updatedActiveGroupId = newState.layout.activeGroupId;
2751
+ if (!updatedActiveGroupId) {
2752
+ return state;
2753
+ }
2754
+ targetGroupId = updatedActiveGroupId;
2755
+
2756
+ // Remove the tab that createEmptyGroup created, we'll add our own
2757
+ newState = {
2758
+ ...newState,
2759
+ layout: {
2760
+ ...newState.layout,
2761
+ groups: newState.layout.groups.map(group => {
2762
+ if (group.id === targetGroupId) {
2763
+ return {
2764
+ ...group,
2765
+ activeTabId: undefined,
2766
+ tabs: []
2767
+ };
2768
+ }
2769
+ return group;
2770
+ })
2771
+ }
2772
+ };
2773
+ }
2774
+
2775
+ // Get previous active tab ID for viewlet switching
2776
+ getActiveTabId(newState);
2777
+
2778
+ // Create a new empty tab
2779
+ const tabId = create$1();
2780
+ const editorUid = create$1();
2781
+ const newTab = {
2782
+ editorType: 'text',
2783
+ editorUid,
2784
+ errorMessage: '',
2785
+ icon: '',
2786
+ id: tabId,
2787
+ isDirty: false,
2788
+ language: 'plaintext',
2789
+ loadingState: 'loading',
2790
+ title: 'Untitled',
2791
+ uri: 'untitled:///1'
2792
+ };
2793
+ const stateWithNewTab = openTab(newState, targetGroupId, newTab);
2794
+
2795
+ // Calculate bounds: use main area bounds minus tab height
2796
+ const bounds = {
2797
+ height: stateWithNewTab.height - stateWithNewTab.tabHeight,
2798
+ width: stateWithNewTab.width,
2799
+ x: stateWithNewTab.x,
2800
+ y: stateWithNewTab.y + stateWithNewTab.tabHeight
2801
+ };
2802
+ const stateWithViewlet = createViewletForTab(stateWithNewTab, tabId);
2803
+ let intermediateState = stateWithViewlet;
2804
+
2805
+ // Switch viewlet (detach old, attach new if ready)
2806
+ const {
2807
+ newState: switchedState
2808
+ } = switchViewlet(intermediateState);
2809
+ intermediateState = switchedState;
2810
+ set(uid, state, intermediateState);
2811
+
2812
+ // Get the tab to extract editorUid
2813
+ const tabWithViewlet = findTabById(intermediateState, tabId);
2814
+ if (!tabWithViewlet) {
2815
+ return intermediateState;
2816
+ }
2817
+ const {
2818
+ editorUid: actualEditorUid
2819
+ } = tabWithViewlet.tab;
2820
+ if (actualEditorUid === -1) {
2821
+ throw new Error(`invalid editorUid`);
2822
+ }
2823
+ await createViewlet('Editor', actualEditorUid, tabId, bounds, newTab.uri || '');
2824
+
2825
+ // After viewlet is created, get the latest state and mark it as ready
2826
+ const {
2827
+ newState: latestState
2828
+ } = get(uid);
2829
+ const readyState = handleViewletReady(latestState, actualEditorUid);
2830
+ return readyState;
2831
+ };
2832
+
2671
2833
  const ensureActiveGroup = (state, uri) => {
2672
2834
  // Find the active group (by activeGroupId or focused flag)
2673
2835
  const {
@@ -2748,18 +2910,6 @@ const focusEditorGroup = (state, groupId) => {
2748
2910
  };
2749
2911
  };
2750
2912
 
2751
- const getActiveTabId = state => {
2752
- const {
2753
- layout
2754
- } = state;
2755
- const {
2756
- activeGroupId,
2757
- groups
2758
- } = layout;
2759
- const activeGroup = groups.find(g => g.id === activeGroupId);
2760
- return activeGroup?.activeTabId;
2761
- };
2762
-
2763
2913
  const getOptionUriOptions = options => {
2764
2914
  let uri = '';
2765
2915
  if (typeof options === 'string') {
@@ -2826,13 +2976,12 @@ const openUri = async (state, options) => {
2826
2976
  return newState;
2827
2977
  }
2828
2978
 
2829
- // Calculate bounds: use main area bounds minus 35px for tab height
2830
- const TAB_HEIGHT = 35;
2979
+ // Calculate bounds: use main area bounds minus tab height
2831
2980
  const bounds = {
2832
- height: newState.height - TAB_HEIGHT,
2981
+ height: newState.height - newState.tabHeight,
2833
2982
  width: newState.width,
2834
2983
  x: newState.x,
2835
- y: newState.y + TAB_HEIGHT
2984
+ y: newState.y + newState.tabHeight
2836
2985
  };
2837
2986
  const stateWithViewlet = createViewletForTab(newState, tabId);
2838
2987
  let intermediateState1 = stateWithViewlet;
@@ -3339,8 +3488,9 @@ const renderEditorGroupActions = (group, groupIndex, splitButtonEnabled) => {
3339
3488
  const renderEditorGroupHeader = (group, groupIndex, splitButtonEnabled) => {
3340
3489
  const tabsChildCount = group.tabs.length;
3341
3490
  const actions = renderEditorGroupActions(group, groupIndex, splitButtonEnabled);
3491
+ const hasActions = actions.length > 0;
3342
3492
  return [{
3343
- childCount: actions.length > 0 ? 2 : 1,
3493
+ childCount: hasActions ? 2 : 1,
3344
3494
  className: 'EditorGroupHeader',
3345
3495
  role: 'none',
3346
3496
  type: Div
@@ -3471,6 +3621,10 @@ const getActiveTab = state => {
3471
3621
  };
3472
3622
  };
3473
3623
 
3624
+ const saveEditor = async editorUid => {
3625
+ await invoke('Editor.save', editorUid);
3626
+ };
3627
+
3474
3628
  const save = async state => {
3475
3629
  const activeTabData = getActiveTab(state);
3476
3630
  if (!activeTabData) {
@@ -3482,7 +3636,7 @@ const save = async state => {
3482
3636
  if (tab.loadingState === 'loading') {
3483
3637
  return state;
3484
3638
  }
3485
- await invoke('Editor.save', tab.editorUid);
3639
+ await saveEditor(tab.editorUid);
3486
3640
  if (!tab.isDirty) {
3487
3641
  return state;
3488
3642
  }
@@ -3495,8 +3649,26 @@ const saveState = state => {
3495
3649
  const {
3496
3650
  layout
3497
3651
  } = state;
3652
+
3653
+ // Filter out untitled editors from tabs
3654
+ const filteredGroups = layout.groups.map(group => ({
3655
+ ...group,
3656
+ tabs: group.tabs.filter(tab => !tab.uri?.startsWith('untitled://'))
3657
+ }))
3658
+ // Remove groups that become empty after filtering
3659
+ .filter(group => group.tabs.length > 0);
3660
+
3661
+ // Update activeGroupId if it points to a removed group
3662
+ const {
3663
+ activeGroupId: originalActiveGroupId
3664
+ } = layout;
3665
+ const activeGroupId = originalActiveGroupId !== undefined && !filteredGroups.some(g => g.id === originalActiveGroupId) ? undefined : originalActiveGroupId;
3498
3666
  return {
3499
- layout
3667
+ layout: {
3668
+ ...layout,
3669
+ activeGroupId,
3670
+ groups: filteredGroups
3671
+ }
3500
3672
  };
3501
3673
  };
3502
3674
 
@@ -3582,11 +3754,14 @@ const commandMap = {
3582
3754
  'MainArea.handleClickAction': wrapCommand(handleClickAction),
3583
3755
  'MainArea.handleClickCloseTab': wrapCommand(handleClickCloseTab),
3584
3756
  'MainArea.handleClickTab': wrapCommand(handleClickTab),
3757
+ 'MainArea.handleDoubleClick': wrapCommand(handleDoubleClick),
3585
3758
  'MainArea.handleResize': wrapCommand(handleResize),
3586
3759
  'MainArea.handleTabContextMenu': wrapCommand(handleTabContextMenu),
3760
+ 'MainArea.handleUriChange': wrapCommand(handleUriChange),
3587
3761
  'MainArea.handleWorkspaceChange': wrapCommand(handleWorkspaceChange),
3588
3762
  'MainArea.initialize': initialize,
3589
3763
  'MainArea.loadContent': wrapCommand(loadContent),
3764
+ 'MainArea.newFile': wrapCommand(newFile),
3590
3765
  'MainArea.openUri': wrapCommand(openUri),
3591
3766
  'MainArea.refresh': wrapCommand(refresh),
3592
3767
  'MainArea.render2': render2,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/main-area-worker",
3
- "version": "6.2.0",
3
+ "version": "6.4.0",
4
4
  "description": "Main Area Worker",
5
5
  "repository": {
6
6
  "type": "git",