@lvce-editor/main-area-worker 1.1.0 → 1.3.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.
@@ -508,7 +508,7 @@ const IpcParentWithMessagePort$1 = {
508
508
 
509
509
  const Two$1 = '2.0';
510
510
  const callbacks = Object.create(null);
511
- const get$3 = id => {
511
+ const get$2 = id => {
512
512
  return callbacks[id];
513
513
  };
514
514
  const remove$1 = id => {
@@ -657,7 +657,7 @@ const warn = (...args) => {
657
657
  console.warn(...args);
658
658
  };
659
659
  const resolve = (id, response) => {
660
- const fn = get$3(id);
660
+ const fn = get$2(id);
661
661
  if (!fn) {
662
662
  console.log(response);
663
663
  warn(`callback ${id} may already be disposed`);
@@ -1028,8 +1028,6 @@ const createMockRpc = ({
1028
1028
  return mockRpc;
1029
1029
  };
1030
1030
 
1031
- const Button$1 = 'button';
1032
-
1033
1031
  const Button = 1;
1034
1032
  const Div = 4;
1035
1033
  const Span = 8;
@@ -1047,7 +1045,7 @@ const rpcs = Object.create(null);
1047
1045
  const set$3 = (id, rpc) => {
1048
1046
  rpcs[id] = rpc;
1049
1047
  };
1050
- const get$2 = id => {
1048
+ const get$1 = id => {
1051
1049
  return rpcs[id];
1052
1050
  };
1053
1051
  const remove = id => {
@@ -1058,18 +1056,18 @@ const remove = id => {
1058
1056
  const create$2 = rpcId => {
1059
1057
  return {
1060
1058
  async dispose() {
1061
- const rpc = get$2(rpcId);
1059
+ const rpc = get$1(rpcId);
1062
1060
  await rpc.dispose();
1063
1061
  },
1064
1062
  // @ts-ignore
1065
1063
  invoke(method, ...params) {
1066
- const rpc = get$2(rpcId);
1064
+ const rpc = get$1(rpcId);
1067
1065
  // @ts-ignore
1068
1066
  return rpc.invoke(method, ...params);
1069
1067
  },
1070
1068
  // @ts-ignore
1071
1069
  invokeAndTransfer(method, ...params) {
1072
- const rpc = get$2(rpcId);
1070
+ const rpc = get$1(rpcId);
1073
1071
  // @ts-ignore
1074
1072
  return rpc.invokeAndTransfer(method, ...params);
1075
1073
  },
@@ -1092,12 +1090,10 @@ const create$2 = rpcId => {
1092
1090
  };
1093
1091
 
1094
1092
  const {
1095
- invoke: invoke$1,
1096
1093
  set: set$2
1097
1094
  } = create$2(ExtensionHostWorker);
1098
1095
 
1099
1096
  const {
1100
- invoke,
1101
1097
  invokeAndTransfer,
1102
1098
  set: set$1
1103
1099
  } = create$2(RendererWorker);
@@ -1105,12 +1101,6 @@ const sendMessagePortToExtensionHostWorker$1 = async (port, rpcId = 0) => {
1105
1101
  const command = 'HandleMessagePort.handleMessagePort2';
1106
1102
  await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToExtensionHostWorker', port, command, rpcId);
1107
1103
  };
1108
- const activateByEvent$1 = (event, assetDir, platform) => {
1109
- return invoke('ExtensionHostManagement.activateByEvent', event, assetDir, platform);
1110
- };
1111
- const getPreference = async key => {
1112
- return await invoke('Preferences.get', key);
1113
- };
1114
1104
 
1115
1105
  const toCommandId = key => {
1116
1106
  const dotIndex = key.indexOf('.');
@@ -1198,11 +1188,11 @@ const terminate = () => {
1198
1188
  };
1199
1189
 
1200
1190
  const {
1201
- get: get$1,
1202
- getCommandIds: getCommandIds$1,
1203
- registerCommands: registerCommands$1,
1191
+ get,
1192
+ getCommandIds,
1193
+ registerCommands,
1204
1194
  set,
1205
- wrapCommand: wrapCommand$1} = create$1();
1195
+ wrapCommand} = create$1();
1206
1196
 
1207
1197
  const create = (uid, uri, x, y, width, height, platform, assetDir) => {
1208
1198
  const state = {
@@ -1216,7 +1206,7 @@ const create = (uid, uri, x, y, width, height, platform, assetDir) => {
1216
1206
  };
1217
1207
 
1218
1208
  const isEqual = (oldState, newState) => {
1219
- return oldState.statusBarItemsLeft === newState.statusBarItemsLeft && oldState.statusBarItemsRight === newState.statusBarItemsRight;
1209
+ return oldState.layout === newState.layout;
1220
1210
  };
1221
1211
 
1222
1212
  const RenderItems = 4;
@@ -1239,65 +1229,15 @@ const diff2 = uid => {
1239
1229
  const {
1240
1230
  newState,
1241
1231
  oldState
1242
- } = get$1(uid);
1232
+ } = get(uid);
1243
1233
  const result = diff(oldState, newState);
1244
1234
  return result;
1245
1235
  };
1246
1236
 
1247
- const getMatchingItem = (itemsLeft, itemsRight, name) => {
1248
- for (const item of itemsLeft) {
1249
- if (item.name === name) {
1250
- return item;
1251
- }
1252
- }
1253
- for (const item of itemsRight) {
1254
- if (item.name === name) {
1255
- return item;
1256
- }
1257
- }
1258
- return undefined;
1259
- };
1260
-
1261
- const handleClickExtensionStatusBarItem = async name => {
1262
- // @ts-ignore
1263
- await invoke$1(`ExtensionHostStatusBar.executeCommand`, name);
1264
- };
1265
-
1266
- const handleClickNotification = async () => {
1267
- // TODO toggle notifications
1268
- };
1269
-
1270
- const handleClickProblems = async () => {
1271
- // @ts-ignore
1272
- await invoke('Layout.showPanel');
1273
- // @ts-ignore
1274
- await invoke('Panel.toggleView', 'Problems');
1275
- };
1276
-
1277
- const Notifications = 'Notifications';
1278
- const Problems = 'Problems';
1279
-
1280
1237
  const handleClick = async (state, name) => {
1281
1238
  if (!name) {
1282
1239
  return state;
1283
1240
  }
1284
- const {
1285
- statusBarItemsLeft,
1286
- statusBarItemsRight
1287
- } = state;
1288
- const item = getMatchingItem(statusBarItemsLeft, statusBarItemsRight, name);
1289
- if (!item) {
1290
- return state;
1291
- }
1292
- if (item.name === Notifications) {
1293
- await handleClickNotification();
1294
- } else if (item.name === Problems) {
1295
- await handleClickProblems();
1296
- } else {
1297
- await handleClickExtensionStatusBarItem(name);
1298
- }
1299
- // TODO
1300
- // sendExtensionWorker([/* statusBarItemHandleClick */ 7657, /* name */ name])
1301
1241
  return state;
1302
1242
  };
1303
1243
 
@@ -1323,199 +1263,34 @@ const initialize = async () => {
1323
1263
  set$2(rpc);
1324
1264
  };
1325
1265
 
1326
- const getIndex = (items, item) => {
1327
- for (let i = 0; i < items.length; i++) {
1328
- if (items[i].name === item.name) {
1329
- return i;
1330
- }
1331
- }
1332
- return -1;
1333
- };
1334
-
1335
- const updateArray = (items, newItem) => {
1336
- const index = getIndex(items, newItem);
1337
- const before = items.slice(0, index);
1338
- const after = items.slice(index + 1);
1339
- return [...before, newItem, ...after];
1340
- };
1341
-
1342
- const itemLeftUpdate = (state, newItem) => {
1343
- return {
1344
- ...state,
1345
- statusBarItemsLeft: updateArray([...state.statusBarItemsLeft], newItem)
1346
- };
1347
- };
1348
-
1349
- const itemRightCreate = (state, newItem) => {
1350
- const {
1351
- statusBarItemsRight
1352
- } = state;
1353
- const newStatusBarItemsRight = [...statusBarItemsRight, newItem];
1354
- return {
1355
- ...state,
1356
- statusBarItemsRight: newStatusBarItemsRight
1357
- };
1358
- };
1359
-
1360
- const itemRightUpdate = (state, newItem) => {
1361
- const {
1362
- statusBarItemsRight
1363
- } = state;
1364
- const newStatusBarItemsRight = updateArray([...statusBarItemsRight], newItem);
1365
- return {
1366
- ...state,
1367
- statusBarItemsRight: newStatusBarItemsRight
1368
- };
1369
- };
1370
-
1371
- const ProblemsErrorIcon = 'ProblemsErrorIcon';
1372
- const ProblemsWarningIcon = 'ProblemsWarningIcon';
1373
- const StatusBarItem = 'StatusBarItem';
1374
- const StatusBarItemsLeft = 'StatusBarItemsLeft';
1375
- const StatusBarItemsRight = 'StatusBarItemsRight';
1376
-
1377
- const OnStatusBarItem = 'onStatusBarItem';
1378
-
1379
- const GetStatusBarItems = 'ExtensionHost.getStatusBarItems2';
1380
-
1381
- const activateByEvent = (event, assetDir, platform) => {
1382
- // @ts-ignore
1383
- return activateByEvent$1(event, assetDir, platform);
1384
- };
1385
-
1386
- const executeProviders = async ({
1387
- assetDir,
1388
- combineResults,
1389
- event,
1390
- method,
1391
- noProviderFoundMessage = 'No provider found',
1392
- noProviderFoundResult,
1393
- params,
1394
- platform
1395
- }) => {
1396
- await activateByEvent(event, assetDir, platform);
1397
- // @ts-ignore
1398
- const result = await invoke$1(method, ...params);
1399
- return result;
1400
- };
1401
-
1402
- const combineResults = results => {
1403
- return results.flat();
1404
- };
1405
- const getStatusBarItems$1 = (assetDir, platform) => {
1406
- return executeProviders({
1407
- assetDir,
1408
- combineResults,
1409
- event: OnStatusBarItem,
1410
- method: GetStatusBarItems,
1411
- noProviderFoundMessage: 'No status bar item provider found',
1412
- noProviderFoundResult: [],
1413
- params: [],
1414
- platform
1415
- });
1416
- };
1417
-
1418
- const toStatusBarItem = uiStatusBarItem => {
1419
- const elements = [];
1420
- if (uiStatusBarItem.icon) {
1421
- elements.push({
1422
- type: 'icon',
1423
- value: uiStatusBarItem.icon
1424
- });
1425
- }
1426
- if (uiStatusBarItem.text) {
1427
- elements.push({
1428
- type: 'text',
1429
- value: uiStatusBarItem.text
1430
- });
1431
- }
1432
- if (elements.length === 0) {
1433
- elements.push({
1434
- type: 'text',
1435
- value: ''
1436
- });
1437
- }
1438
- return {
1439
- command: uiStatusBarItem.command || undefined,
1440
- elements,
1441
- name: uiStatusBarItem.name,
1442
- tooltip: uiStatusBarItem.tooltip
1443
- };
1444
- };
1445
-
1446
- const toUiStatusBarItem = extensionHostStatusBarItem => {
1447
- return {
1448
- command: extensionHostStatusBarItem.command || '',
1449
- icon: extensionHostStatusBarItem.icon || '',
1450
- name: extensionHostStatusBarItem.id || extensionHostStatusBarItem.name || '',
1451
- text: extensionHostStatusBarItem.text || '',
1452
- tooltip: extensionHostStatusBarItem.tooltip || ''
1453
- };
1454
- };
1455
-
1456
- const toUiStatusBarItems = statusBarItems => {
1457
- if (!statusBarItems) {
1458
- return [];
1459
- }
1460
- return statusBarItems.map(toUiStatusBarItem);
1461
- };
1462
-
1463
- const getStatusBarItems = async (showItems, assetDir, platform) => {
1464
- if (!showItems) {
1465
- return [];
1466
- }
1467
- await activateByEvent('onSourceControl', assetDir, platform);
1468
- const extensionStatusBarItems = await getStatusBarItems$1(assetDir, platform);
1469
- const uiStatusBarItems = toUiStatusBarItems(extensionStatusBarItems);
1470
- const extraItems = [{
1471
- command: undefined,
1472
- elements: [{
1473
- type: 'text',
1474
- value: 'Notifications'
1475
- }],
1476
- name: Notifications,
1477
- tooltip: ''
1266
+ const loadContent = async state => {
1267
+ const tabs = [{
1268
+ content: '',
1269
+ editorType: 'text',
1270
+ id: '1',
1271
+ isDirty: false,
1272
+ title: 'tab 1'
1478
1273
  }, {
1479
- command: undefined,
1480
- elements: [{
1481
- type: 'icon',
1482
- value: ProblemsErrorIcon
1483
- }, {
1484
- type: 'text',
1485
- value: '0'
1486
- }, {
1487
- type: 'icon',
1488
- value: ProblemsWarningIcon
1489
- }, {
1490
- type: 'text',
1491
- value: '0'
1492
- }],
1493
- name: Problems,
1494
- tooltip: ''
1274
+ content: '',
1275
+ editorType: 'text',
1276
+ id: '2',
1277
+ isDirty: false,
1278
+ title: 'tab 2'
1495
1279
  }];
1496
- return [...uiStatusBarItems.map(toStatusBarItem), ...extraItems];
1497
- };
1498
-
1499
- const get = async key => {
1500
- return getPreference(key);
1501
- };
1502
-
1503
- const itemsVisible = async () => {
1504
- const statusBarItemsPreference = (await get('statusBar.itemsVisible')) ?? true;
1505
- return statusBarItemsPreference;
1506
- };
1507
-
1508
- const loadContent = async state => {
1509
- const {
1510
- assetDir,
1511
- platform
1512
- } = state;
1513
- const statusBarItemsPreference = await itemsVisible();
1514
- const statusBarItems = await getStatusBarItems(statusBarItemsPreference, assetDir, platform);
1515
1280
  return {
1516
1281
  ...state,
1517
- statusBarItemsLeft: [...statusBarItems],
1518
- statusBarItemsRight: []
1282
+ layout: {
1283
+ activeGroupId: '0',
1284
+ direction: 'horizontal',
1285
+ groups: [{
1286
+ activeTabId: '',
1287
+ direction: 'horizontal',
1288
+ focused: false,
1289
+ id: '0',
1290
+ size: 300,
1291
+ tabs
1292
+ }]
1293
+ }
1519
1294
  };
1520
1295
  };
1521
1296
 
@@ -1527,77 +1302,92 @@ const text = data => {
1527
1302
  };
1528
1303
  };
1529
1304
 
1530
- const HandleClick = 11;
1531
-
1532
- const getElementVirtualDom = element => {
1533
- if (element.type === 'text') {
1534
- return [text(element.value)];
1535
- }
1536
- if (element.type === 'icon') {
1537
- return [{
1538
- childCount: 0,
1539
- className: element.value,
1540
- type: Div
1541
- }];
1542
- }
1543
- return [];
1305
+ const CSS_CLASSES = {
1306
+ CUSTOM_EDITOR: 'custom-editor',
1307
+ EDITOR_CONTAINER: 'editor-container',
1308
+ EDITOR_CONTENT: 'editor-content',
1309
+ EDITOR_GROUP: 'editor-group',
1310
+ EDITOR_GROUP_FOCUSED: 'focused',
1311
+ EDITOR_GROUPS_CONTAINER: 'editor-groups-container',
1312
+ MAIN_AREA: 'main-area',
1313
+ TAB: 'tab',
1314
+ TAB_ACTIVE: 'active',
1315
+ TAB_BAR: 'tab-bar',
1316
+ TAB_CLOSE: 'tab-close',
1317
+ TAB_TITLE: 'tab-title',
1318
+ TEXT_EDITOR: 'text-editor'
1544
1319
  };
1545
- const getStatusBarItemVirtualDom = statusBarItem => {
1546
- const {
1547
- elements,
1548
- name,
1549
- tooltip
1550
- } = statusBarItem;
1551
- const elementNodes = elements.flatMap(getElementVirtualDom);
1320
+
1321
+ const renderTab = (tab, isActive) => {
1552
1322
  return [{
1553
- childCount: elementNodes.length,
1554
- className: StatusBarItem,
1555
- name,
1556
- role: Button$1,
1557
- tabIndex: -1,
1558
- title: tooltip,
1323
+ childCount: 2,
1324
+ className: `${CSS_CLASSES.TAB} ${isActive ? CSS_CLASSES.TAB_ACTIVE : ''}`,
1325
+ type: Div
1326
+ }, {
1327
+ childCount: 1,
1328
+ className: CSS_CLASSES.TAB_TITLE,
1329
+ type: Span
1330
+ }, text(tab.isDirty ? `*${tab.title}` : tab.title), {
1331
+ childCount: 1,
1332
+ className: CSS_CLASSES.TAB_CLOSE,
1559
1333
  type: Button
1560
- }, ...elementNodes];
1334
+ }, text('×')];
1561
1335
  };
1562
-
1563
- const getStatusBarItemsVirtualDom = (items, className) => {
1564
- if (items.length === 0) {
1565
- return [];
1566
- }
1336
+ const renderTabBar = group => {
1567
1337
  return [{
1568
- childCount: items.length,
1569
- className,
1338
+ childCount: group.tabs.length,
1339
+ className: CSS_CLASSES.TAB_BAR,
1570
1340
  type: Div
1571
- }, ...items.flatMap(getStatusBarItemVirtualDom)];
1341
+ }, ...group.tabs.flatMap(tab => renderTab(tab, tab.id === group.activeTabId))];
1572
1342
  };
1573
-
1574
- const getChildCount = (leftCount, rightCount) => {
1575
- let count = 0;
1576
- if (leftCount > 0) {
1577
- count++;
1578
- }
1579
- if (rightCount > 0) {
1580
- count++;
1343
+ const renderEditor = tab => {
1344
+ if (tab.editorType === 'custom') {
1345
+ return [{
1346
+ childCount: 1,
1347
+ className: CSS_CLASSES.CUSTOM_EDITOR,
1348
+ type: Div
1349
+ }, text(`Custom Editor: ${tab.customEditorId}`)];
1581
1350
  }
1582
- return count;
1351
+ return [{
1352
+ childCount: 1,
1353
+ className: CSS_CLASSES.TEXT_EDITOR,
1354
+ type: Div
1355
+ }, {
1356
+ childCount: 1,
1357
+ className: CSS_CLASSES.EDITOR_CONTENT,
1358
+ type: Pre
1359
+ }, text(tab.content || '')];
1360
+ };
1361
+ const renderEditorGroup = group => {
1362
+ const activeTab = group.tabs.find(tab => tab.id === group.activeTabId);
1363
+ return [{
1364
+ childCount: 2,
1365
+ className: `${CSS_CLASSES.EDITOR_GROUP} ${group.focused ? CSS_CLASSES.EDITOR_GROUP_FOCUSED : ''}`,
1366
+ type: Div
1367
+ }, ...renderTabBar(group), {
1368
+ childCount: activeTab ? 1 : 1,
1369
+ className: CSS_CLASSES.EDITOR_CONTAINER,
1370
+ type: Div
1371
+ }, ...renderEditor(activeTab)];
1583
1372
  };
1584
- const getStatusBarVirtualDom = (statusBarItemsLeft, statusBarItemsRight) => {
1585
- const dom = [{
1586
- childCount: getChildCount(statusBarItemsLeft.length, statusBarItemsRight.length),
1587
- className: 'StatusBar',
1588
- onClick: HandleClick,
1373
+ const getMainAreaVirtualDom = layout => {
1374
+ return [{
1375
+ childCount: 1,
1376
+ className: CSS_CLASSES.MAIN_AREA,
1377
+ type: Div
1378
+ }, {
1379
+ childCount: layout.groups.length,
1380
+ className: CSS_CLASSES.EDITOR_GROUPS_CONTAINER,
1589
1381
  type: Div
1590
- }, ...getStatusBarItemsVirtualDom(statusBarItemsLeft, StatusBarItemsLeft), ...getStatusBarItemsVirtualDom(statusBarItemsRight, StatusBarItemsRight)];
1591
- return dom;
1382
+ }, ...layout.groups.flatMap(renderEditorGroup)];
1592
1383
  };
1593
1384
 
1594
1385
  const renderItems = (oldState, newState) => {
1595
1386
  const {
1596
- statusBarItemsLeft,
1597
- statusBarItemsRight,
1387
+ layout,
1598
1388
  uid
1599
1389
  } = newState;
1600
- const dom = getStatusBarVirtualDom(statusBarItemsLeft, statusBarItemsRight);
1390
+ const dom = getMainAreaVirtualDom(layout);
1601
1391
  return [SetDom2, uid, dom];
1602
1392
  };
1603
1393
 
@@ -1626,12 +1416,14 @@ const render2 = (uid, diffResult) => {
1626
1416
  const {
1627
1417
  newState,
1628
1418
  oldState
1629
- } = get$1(uid);
1419
+ } = get(uid);
1630
1420
  set(uid, newState, newState);
1631
1421
  const commands = applyRender(oldState, newState, diffResult);
1632
1422
  return commands;
1633
1423
  };
1634
1424
 
1425
+ const HandleClick = 11;
1426
+
1635
1427
  const renderEventListeners = () => {
1636
1428
  return [{
1637
1429
  name: HandleClick,
@@ -1648,7 +1440,7 @@ const resize = (state, dimensions) => {
1648
1440
 
1649
1441
  const saveState = uid => {
1650
1442
  number(uid);
1651
- const value = get$1(uid);
1443
+ const value = get(uid);
1652
1444
  const {
1653
1445
  newState
1654
1446
  } = value;
@@ -1663,24 +1455,21 @@ const saveState = uid => {
1663
1455
  };
1664
1456
 
1665
1457
  const commandMap = {
1666
- 'StatusBar.create': create,
1667
- 'StatusBar.diff2': diff2,
1668
- 'StatusBar.getCommandIds': getCommandIds$1,
1669
- 'StatusBar.handleClick': wrapCommand$1(handleClick),
1670
- 'StatusBar.initialize': initialize,
1671
- 'StatusBar.itemLeftUpdate': wrapCommand$1(itemLeftUpdate),
1672
- 'StatusBar.itemRightCreate': wrapCommand$1(itemRightCreate),
1673
- 'StatusBar.itemRightUpdate': wrapCommand$1(itemRightUpdate),
1674
- 'StatusBar.loadContent': wrapCommand$1(loadContent),
1675
- 'StatusBar.render2': render2,
1676
- 'StatusBar.renderEventListeners': renderEventListeners,
1677
- 'StatusBar.resize': wrapCommand$1(resize),
1678
- 'StatusBar.saveState': saveState,
1679
- 'StatusBar.terminate': terminate
1458
+ 'MainArea.create': create,
1459
+ 'MainArea.diff2': diff2,
1460
+ 'MainArea.getCommandIds': getCommandIds,
1461
+ 'MainArea.handleClick': wrapCommand(handleClick),
1462
+ 'MainArea.initialize': initialize,
1463
+ 'MainArea.loadContent': wrapCommand(loadContent),
1464
+ 'MainArea.render2': render2,
1465
+ 'MainArea.renderEventListeners': renderEventListeners,
1466
+ 'MainArea.resize': wrapCommand(resize),
1467
+ 'MainArea.saveState': saveState,
1468
+ 'MainArea.terminate': terminate
1680
1469
  };
1681
1470
 
1682
1471
  const listen = async () => {
1683
- registerCommands$1(commandMap);
1472
+ registerCommands(commandMap);
1684
1473
  const rpc = await WebWorkerRpcClient.create({
1685
1474
  commandMap: commandMap
1686
1475
  });
@@ -1691,565 +1480,10 @@ const main$2 = async () => {
1691
1480
  await listen();
1692
1481
  };
1693
1482
 
1694
- const closeEditorGroup = (state, groupId) => {
1695
- const groupIndex = state.layout.groups.findIndex(group => group.id === groupId);
1696
- if (groupIndex === -1 || state.layout.groups.length <= 1) {
1697
- return state;
1698
- }
1699
- const remainingGroups = state.layout.groups.filter(group => group.id !== groupId);
1700
- const redistributedGroups = remainingGroups.map((group, index) => ({
1701
- ...group,
1702
- size: Math.round(100 / remainingGroups.length)
1703
- }));
1704
- const newActiveGroupId = state.layout.activeGroupId === groupId ? remainingGroups[0].id : state.layout.activeGroupId;
1705
- return {
1706
- ...state,
1707
- layout: {
1708
- ...state.layout,
1709
- activeGroupId: newActiveGroupId,
1710
- groups: redistributedGroups
1711
- }
1712
- };
1713
- };
1714
-
1715
- const closeTab = (state, groupId, tabId) => {
1716
- const groups = state.layout.groups.map(group => {
1717
- if (group.id === groupId) {
1718
- const newTabs = group.tabs.filter(tab => tab.id !== tabId);
1719
- let newActiveTabId = group.activeTabId;
1720
- if (group.activeTabId === tabId) {
1721
- const tabIndex = group.tabs.findIndex(tab => tab.id === tabId);
1722
- if (newTabs.length > 0) {
1723
- newActiveTabId = newTabs[Math.min(tabIndex, newTabs.length - 1)].id;
1724
- } else {
1725
- newActiveTabId = undefined;
1726
- }
1727
- }
1728
- return {
1729
- ...group,
1730
- activeTabId: newActiveTabId,
1731
- tabs: newTabs
1732
- };
1733
- }
1734
- return group;
1735
- });
1736
- return {
1737
- ...state,
1738
- layout: {
1739
- ...state.layout,
1740
- groups
1741
- }
1742
- };
1743
- };
1744
-
1745
- const focusEditorGroup = (state, groupId) => {
1746
- const groups = state.layout.groups.map(group => ({
1747
- ...group,
1748
- focused: group.id === groupId
1749
- }));
1750
- return {
1751
- ...state,
1752
- layout: {
1753
- ...state.layout,
1754
- activeGroupId: groupId,
1755
- groups
1756
- }
1757
- };
1758
- };
1759
-
1760
- const CSS_CLASSES = {
1761
- CUSTOM_EDITOR: 'custom-editor',
1762
- EDITOR_CONTAINER: 'editor-container',
1763
- EDITOR_CONTENT: 'editor-content',
1764
- EDITOR_GROUP: 'editor-group',
1765
- EDITOR_GROUP_FOCUSED: 'focused',
1766
- EDITOR_GROUPS_CONTAINER: 'editor-groups-container',
1767
- EMPTY_EDITOR: 'empty-editor',
1768
- MAIN_AREA: 'main-area',
1769
- TAB: 'tab',
1770
- TAB_ACTIVE: 'active',
1771
- TAB_BAR: 'tab-bar',
1772
- TAB_CLOSE: 'tab-close',
1773
- TAB_TITLE: 'tab-title',
1774
- TEXT_EDITOR: 'text-editor'
1775
- };
1776
- const CSS_ATTRIBUTES = {
1777
- DATA_ACTION: 'data-action',
1778
- DATA_CUSTOM_EDITOR_ID: 'data-custom-editor-id',
1779
- DATA_DIRECTION: 'data-direction',
1780
- DATA_GROUP_ID: 'data-group-id',
1781
- DATA_LANGUAGE: 'data-language',
1782
- DATA_TAB_ID: 'data-tab-id'
1783
- };
1784
- const CSS_STYLES = {
1785
- CUSTOM_EDITOR_STYLE: 'flex: 1; overflow: auto;',
1786
- EDITOR_GROUP_BASE: 'display: flex; flex-direction: column; border-right: 1px solid var(--border-color);',
1787
- EDITOR_GROUP_FOCUSED_STYLE: 'box-shadow: 0 0 0 1px var(--focus-border-color);',
1788
- EMPTY_EDITOR_STYLE: 'flex: 1; display: flex; align-items: center; justify-content: center; color: var(--dimmed-color);',
1789
- FLEX_COLUMN: 'display: flex; flex-direction: column; height: 100%;',
1790
- FLEX_ROW: 'display: flex; flex-direction: row; height: 100%;',
1791
- TAB_ACTIVE_STYLE: 'background: var(--tab-active-background); color: var(--tab-active-color);',
1792
- TAB_BAR_BASE: 'display: flex; align-items: center; background: var(--tab-bar-background); border-bottom: 1px solid var(--border-color);',
1793
- TAB_BASE: 'padding: 4px 8px; cursor: pointer; border-right: 1px solid var(--border-color); display: flex; align-items: center; gap: 4px;',
1794
- TAB_CLOSE_STYLE: 'background: none; border: none; cursor: pointer; padding: 2px; border-radius: 2px; opacity: 0.7;',
1795
- TEXT_EDITOR_STYLE: 'flex: 1; overflow: auto; font-family: var(--editor-font-family); font-size: var(--editor-font-size);'
1796
- };
1797
- const THEMES = {
1798
- DARK: {
1799
- '--border-color': '#3e3e42',
1800
- '--dimmed-color': '#858585',
1801
- '--editor-font-family': 'Consolas, Monaco, "Courier New", monospace',
1802
- '--editor-font-size': '14px',
1803
- '--focus-border-color': '#0078d4',
1804
- '--tab-active-background': '#1e1e1e',
1805
- '--tab-active-color': '#ffffff',
1806
- '--tab-bar-background': '#252526',
1807
- '--tab-close-hover-background': '#3e3e42'
1808
- },
1809
- LIGHT: {
1810
- '--border-color': '#e1e1e1',
1811
- '--dimmed-color': '#999999',
1812
- '--editor-font-family': 'Consolas, Monaco, "Courier New", monospace',
1813
- '--editor-font-size': '14px',
1814
- '--focus-border-color': '#0078d4',
1815
- '--tab-active-background': '#ffffff',
1816
- '--tab-active-color': '#333333',
1817
- '--tab-bar-background': '#f3f3f3',
1818
- '--tab-close-hover-background': '#e1e1e1'
1819
- }
1820
- };
1821
- const getThemeStyles = (theme = 'DARK') => {
1822
- const themeVars = THEMES[theme];
1823
- return Object.entries(themeVars).map(([key, value]) => `${key}: ${value};`).join(' ');
1824
- };
1825
-
1826
- const renderTab = (tab, isActive) => {
1827
- return {
1828
- attributes: {
1829
- [CSS_ATTRIBUTES.DATA_TAB_ID]: tab.id,
1830
- style: `${CSS_STYLES.TAB_BASE} ${isActive ? CSS_STYLES.TAB_ACTIVE_STYLE : ''}`
1831
- },
1832
- childCount: 2,
1833
- children: [{
1834
- childCount: 1,
1835
- children: [tab.isDirty ? `*${tab.title}` : tab.title],
1836
- className: CSS_CLASSES.TAB_TITLE,
1837
- type: Span
1838
- }, {
1839
- attributes: {
1840
- [CSS_ATTRIBUTES.DATA_ACTION]: 'close-tab',
1841
- [CSS_ATTRIBUTES.DATA_TAB_ID]: tab.id,
1842
- style: CSS_STYLES.TAB_CLOSE_STYLE
1843
- },
1844
- childCount: 1,
1845
- children: ['×'],
1846
- className: CSS_CLASSES.TAB_CLOSE,
1847
- type: Button
1848
- }],
1849
- className: `${CSS_CLASSES.TAB} ${isActive ? CSS_CLASSES.TAB_ACTIVE : ''}`,
1850
- type: Div
1851
- };
1852
- };
1853
- const renderTabBar = group => {
1854
- return {
1855
- attributes: {
1856
- [CSS_ATTRIBUTES.DATA_GROUP_ID]: group.id,
1857
- style: CSS_STYLES.TAB_BAR_BASE
1858
- },
1859
- childCount: group.tabs.length,
1860
- children: group.tabs.map(tab => renderTab(tab, tab.id === group.activeTabId)),
1861
- className: CSS_CLASSES.TAB_BAR,
1862
- type: Div
1863
- };
1864
- };
1865
- const renderEditor = tab => {
1866
- if (tab.editorType === 'custom') {
1867
- return {
1868
- attributes: {
1869
- [CSS_ATTRIBUTES.DATA_CUSTOM_EDITOR_ID]: tab.customEditorId,
1870
- [CSS_ATTRIBUTES.DATA_TAB_ID]: tab.id,
1871
- style: CSS_STYLES.CUSTOM_EDITOR_STYLE
1872
- },
1873
- childCount: 1,
1874
- children: [`Custom Editor: ${tab.customEditorId}`],
1875
- className: CSS_CLASSES.CUSTOM_EDITOR,
1876
- type: Div
1877
- };
1878
- }
1879
- return {
1880
- attributes: {
1881
- [CSS_ATTRIBUTES.DATA_LANGUAGE]: tab.language || 'plaintext',
1882
- [CSS_ATTRIBUTES.DATA_TAB_ID]: tab.id,
1883
- style: CSS_STYLES.TEXT_EDITOR_STYLE
1884
- },
1885
- childCount: 1,
1886
- children: [{
1887
- childCount: 1,
1888
- children: [tab.content || ''],
1889
- className: CSS_CLASSES.EDITOR_CONTENT,
1890
- type: Pre
1891
- }],
1892
- className: CSS_CLASSES.TEXT_EDITOR,
1893
- type: Div
1894
- };
1895
- };
1896
- const renderEditorGroup = group => {
1897
- const activeTab = group.tabs.find(tab => tab.id === group.activeTabId);
1898
- return {
1899
- attributes: {
1900
- [CSS_ATTRIBUTES.DATA_GROUP_ID]: group.id,
1901
- style: `${CSS_STYLES.EDITOR_GROUP_BASE} flex: ${group.size}; ${group.focused ? CSS_STYLES.EDITOR_GROUP_FOCUSED_STYLE : ''}`
1902
- },
1903
- childCount: 2,
1904
- children: [renderTabBar(group), {
1905
- childCount: activeTab ? 1 : 1,
1906
- children: activeTab ? [renderEditor(activeTab)] : [{
1907
- attributes: {
1908
- style: CSS_STYLES.EMPTY_EDITOR_STYLE
1909
- },
1910
- childCount: 1,
1911
- children: ['No open tabs'],
1912
- className: CSS_CLASSES.EMPTY_EDITOR,
1913
- type: Div
1914
- }],
1915
- className: CSS_CLASSES.EDITOR_CONTAINER,
1916
- type: Div
1917
- }],
1918
- className: `${CSS_CLASSES.EDITOR_GROUP} ${group.focused ? CSS_CLASSES.EDITOR_GROUP_FOCUSED : ''}`,
1919
- type: Div
1920
- };
1921
- };
1922
- const getMainAreaVirtualDom = state => {
1923
- return [{
1924
- attributes: {
1925
- [CSS_ATTRIBUTES.DATA_DIRECTION]: state.layout.direction,
1926
- style: getThemeStyles('DARK')
1927
- },
1928
- childCount: 1,
1929
- children: [{
1930
- attributes: {
1931
- style: state.layout.direction === 'horizontal' ? CSS_STYLES.FLEX_ROW : CSS_STYLES.FLEX_COLUMN
1932
- },
1933
- childCount: state.layout.groups.length,
1934
- children: state.layout.groups.map(renderEditorGroup),
1935
- className: CSS_CLASSES.EDITOR_GROUPS_CONTAINER,
1936
- type: Div
1937
- }],
1938
- className: CSS_CLASSES.MAIN_AREA,
1939
- type: Div
1940
- }];
1941
- };
1942
-
1943
- const splitEditorGroup = (state, groupId, direction) => {
1944
- const sourceGroup = state.layout.groups.find(group => group.id === groupId);
1945
- if (!sourceGroup) {
1946
- return state;
1947
- }
1948
- const newGroupId = `group-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
1949
- const isHorizontalSplit = direction === 'left' || direction === 'right';
1950
- const newLayoutDirection = isHorizontalSplit ? 'horizontal' : 'vertical';
1951
- const updatedGroups = state.layout.groups.map(group => {
1952
- if (group.id === groupId) {
1953
- return {
1954
- ...group,
1955
- focused: false,
1956
- size: 50
1957
- };
1958
- }
1959
- return group;
1960
- });
1961
- const newGroup = {
1962
- activeTabId: undefined,
1963
- focused: true,
1964
- id: newGroupId,
1965
- size: 50,
1966
- tabs: []
1967
- };
1968
- let reorderedGroups;
1969
- if (direction === 'right' || direction === 'down') {
1970
- reorderedGroups = [...updatedGroups, newGroup];
1971
- } else {
1972
- const sourceIndex = updatedGroups.findIndex(group => group.id === groupId);
1973
- reorderedGroups = [...updatedGroups.slice(0, sourceIndex), newGroup, ...updatedGroups.slice(sourceIndex)];
1974
- }
1975
- return {
1976
- ...state,
1977
- layout: {
1978
- activeGroupId: newGroupId,
1979
- direction: newLayoutDirection,
1980
- groups: reorderedGroups
1981
- }
1982
- };
1983
- };
1984
-
1985
- const switchTab = (state, groupId, tabId) => {
1986
- const groups = state.layout.groups.map(group => {
1987
- if (group.id === groupId) {
1988
- const tabExists = group.tabs.some(tab => tab.id === tabId);
1989
- if (tabExists) {
1990
- return {
1991
- ...group,
1992
- activeTabId: tabId
1993
- };
1994
- }
1995
- }
1996
- return group;
1997
- });
1998
- return {
1999
- ...state,
2000
- layout: {
2001
- ...state.layout,
2002
- groups
2003
- }
2004
- };
2005
- };
2006
-
2007
- const handleMainAreaClick = (state, event) => {
2008
- const {
2009
- target
2010
- } = event;
2011
- if (!target.dataset) {
2012
- return state;
2013
- }
2014
- const {
2015
- dataset
2016
- } = target;
2017
-
2018
- // Handle tab click
2019
- if (dataset.tabId) {
2020
- const {
2021
- groupId
2022
- } = dataset;
2023
- if (groupId) {
2024
- return switchTab(state, groupId, dataset.tabId);
2025
- }
2026
- }
2027
-
2028
- // Handle tab close button
2029
- if (dataset.action === 'close-tab' && dataset.tabId) {
2030
- const {
2031
- groupId
2032
- } = dataset;
2033
- if (groupId) {
2034
- return closeTab(state, groupId, dataset.tabId);
2035
- }
2036
- }
2037
-
2038
- // Handle editor group focus
2039
- if (dataset.groupId && !dataset.tabId) {
2040
- return focusEditorGroup(state, dataset.groupId);
2041
- }
2042
-
2043
- // Handle split actions
2044
- if (dataset.action?.startsWith('split-')) {
2045
- const {
2046
- groupId
2047
- } = dataset;
2048
- if (groupId) {
2049
- const direction = dataset.action.replace('split-', '');
2050
- return splitEditorGroup(state, groupId, direction);
2051
- }
2052
- }
2053
- return state;
2054
- };
2055
-
2056
- const handleMainAreaKeyboard = (state, event) => {
2057
- const {
2058
- ctrlKey = false,
2059
- key,
2060
- metaKey = false,
2061
- shiftKey = false
2062
- } = event;
2063
- const isCtrl = ctrlKey || metaKey;
2064
- const activeGroup = state.layout.groups.find(group => group.focused);
2065
- if (!activeGroup) {
2066
- return state;
2067
- }
2068
-
2069
- // Tab navigation
2070
- if (key === 'Tab' && isCtrl) {
2071
- const groupIndex = state.layout.groups.findIndex(group => group.id === activeGroup.id);
2072
- const nextGroupIndex = shiftKey ? (groupIndex - 1 + state.layout.groups.length) % state.layout.groups.length : (groupIndex + 1) % state.layout.groups.length;
2073
- const nextGroup = state.layout.groups[nextGroupIndex];
2074
- return focusEditorGroup(state, nextGroup.id);
2075
- }
2076
-
2077
- // Switch between tabs within group
2078
- if (key === 'ArrowLeft' && isCtrl && !shiftKey) {
2079
- const activeTabIndex = activeGroup.tabs.findIndex(tab => tab.id === activeGroup.activeTabId);
2080
- if (activeTabIndex > 0) {
2081
- const prevTab = activeGroup.tabs[activeTabIndex - 1];
2082
- return switchTab(state, activeGroup.id, prevTab.id);
2083
- }
2084
- }
2085
- if (key === 'ArrowRight' && isCtrl && !shiftKey) {
2086
- const activeTabIndex = activeGroup.tabs.findIndex(tab => tab.id === activeGroup.activeTabId);
2087
- if (activeTabIndex < activeGroup.tabs.length - 1) {
2088
- const nextTab = activeGroup.tabs[activeTabIndex + 1];
2089
- return switchTab(state, activeGroup.id, nextTab.id);
2090
- }
2091
- }
2092
-
2093
- // Close current tab
2094
- if (key === 'w' && isCtrl && activeGroup.activeTabId) {
2095
- return closeTab(state, activeGroup.id, activeGroup.activeTabId);
2096
- }
2097
-
2098
- // Split editor
2099
- if (key === '\\' && isCtrl) {
2100
- const direction = shiftKey ? 'down' : 'right';
2101
- return splitEditorGroup(state, activeGroup.id, direction);
2102
- }
2103
- return state;
2104
- };
2105
-
2106
- const moveTabToGroup = (state, sourceGroupId, targetGroupId, tabId, targetIndex) => {
2107
- const sourceGroup = state.layout.groups.find(group => group.id === sourceGroupId);
2108
- const targetGroup = state.layout.groups.find(group => group.id === targetGroupId);
2109
- if (!sourceGroup || !targetGroup || sourceGroupId === targetGroupId) {
2110
- return state;
2111
- }
2112
- const tabToMove = sourceGroup.tabs.find(tab => tab.id === tabId);
2113
- if (!tabToMove) {
2114
- return state;
2115
- }
2116
- const updatedGroups = state.layout.groups.map(group => {
2117
- if (group.id === sourceGroupId) {
2118
- const newTabs = group.tabs.filter(tab => tab.id !== tabId);
2119
- let newActiveTabId = group.activeTabId;
2120
- if (group.activeTabId === tabId) {
2121
- if (newTabs.length > 0) {
2122
- const removedIndex = group.tabs.findIndex(tab => tab.id === tabId);
2123
- newActiveTabId = newTabs[Math.min(removedIndex, newTabs.length - 1)].id;
2124
- } else {
2125
- newActiveTabId = undefined;
2126
- }
2127
- }
2128
- return {
2129
- ...group,
2130
- activeTabId: newActiveTabId,
2131
- tabs: newTabs
2132
- };
2133
- }
2134
- if (group.id === targetGroupId) {
2135
- const insertIndex = targetIndex === undefined ? group.tabs.length : targetIndex;
2136
- const newTabs = [...group.tabs];
2137
- newTabs.splice(insertIndex, 0, tabToMove);
2138
- return {
2139
- ...group,
2140
- activeTabId: tabId,
2141
- tabs: newTabs
2142
- };
2143
- }
2144
- return group;
2145
- });
2146
- return {
2147
- ...state,
2148
- layout: {
2149
- ...state.layout,
2150
- activeGroupId: targetGroupId,
2151
- groups: updatedGroups
2152
- }
2153
- };
2154
- };
2155
-
2156
- const startTabDrag = (state, tabId, groupId) => {
2157
- return {
2158
- dragState: {
2159
- draggedTabId: tabId,
2160
- sourceGroupId: groupId
2161
- },
2162
- state
2163
- };
2164
- };
2165
- const updateTabDrag = (state, dragState, targetGroupId, targetIndex) => {
2166
- return {
2167
- ...dragState,
2168
- targetGroupId,
2169
- targetIndex
2170
- };
2171
- };
2172
- const endTabDrag = (state, dragState) => {
2173
- if (dragState.targetGroupId && dragState.targetGroupId !== dragState.sourceGroupId) {
2174
- return moveTabToGroup(state, dragState.sourceGroupId, dragState.targetGroupId, dragState.draggedTabId, dragState.targetIndex);
2175
- }
2176
- return state;
2177
- };
2178
-
2179
- const {
2180
- getCommandIds,
2181
- registerCommands,
2182
- wrapCommand} = create$1();
2183
-
2184
- const openTab = (state, groupId, tab) => {
2185
- const newTab = {
2186
- ...tab,
2187
- id: `tab-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`
2188
- };
2189
- const groups = state.layout.groups.map(group => {
2190
- if (group.id === groupId) {
2191
- return {
2192
- ...group,
2193
- activeTabId: newTab.id,
2194
- tabs: [...group.tabs, newTab]
2195
- };
2196
- }
2197
- return group;
2198
- });
2199
- return {
2200
- ...state,
2201
- layout: {
2202
- ...state.layout,
2203
- groups
2204
- }
2205
- };
2206
- };
2207
-
2208
- const restoreMainAreaState = (savedState, currentState) => {
2209
- try {
2210
- const parsed = JSON.parse(savedState);
2211
- return {
2212
- ...currentState,
2213
- layout: parsed.layout
2214
- };
2215
- } catch (error) {
2216
- console.error('Failed to restore main area state:', error);
2217
- return currentState;
2218
- }
2219
- };
2220
-
2221
- const saveMainAreaState = state => {
2222
- return JSON.stringify({
2223
- layout: state.layout,
2224
- version: '1.0.0'
2225
- });
2226
- };
2227
-
2228
- const mainAreaCommandMap = {
2229
- 'MainArea.closeEditorGroup': wrapCommand((state, groupId) => closeEditorGroup(state, groupId)),
2230
- 'MainArea.closeTab': wrapCommand((state, groupId, tabId) => closeTab(state, groupId, tabId)),
2231
- 'MainArea.create': () => {},
2232
- 'MainArea.endTabDrag': wrapCommand((state, dragState) => endTabDrag(state, dragState)),
2233
- 'MainArea.focusEditorGroup': wrapCommand((state, groupId) => focusEditorGroup(state, groupId)),
2234
- 'MainArea.getCommandIds': getCommandIds,
2235
- 'MainArea.getVirtualDom': state => getMainAreaVirtualDom(state),
2236
- 'MainArea.handleClick': wrapCommand((state, event) => handleMainAreaClick(state, event)),
2237
- 'MainArea.handleKeyboard': wrapCommand((state, event) => handleMainAreaKeyboard(state, event)),
2238
- 'MainArea.moveTabToGroup': wrapCommand((state, sourceGroupId, targetGroupId, tabId, targetIndex) => moveTabToGroup(state, sourceGroupId, targetGroupId, tabId, targetIndex)),
2239
- 'MainArea.openTab': wrapCommand((state, groupId, tab) => openTab(state, groupId, tab)),
2240
- 'MainArea.restoreState': wrapCommand((state, savedState) => restoreMainAreaState(savedState, state)),
2241
- 'MainArea.saveState': state => saveMainAreaState(state),
2242
- 'MainArea.splitEditorGroup': wrapCommand((state, groupId, direction) => splitEditorGroup(state, groupId, direction)),
2243
- 'MainArea.startTabDrag': (state, tabId, groupId) => startTabDrag(state, tabId, groupId),
2244
- 'MainArea.switchTab': wrapCommand((state, groupId, tabId) => switchTab(state, groupId, tabId)),
2245
- 'MainArea.terminate': terminate,
2246
- 'MainArea.updateTabDrag': (state, dragState, targetGroupId, targetIndex) => updateTabDrag(state, dragState, targetGroupId, targetIndex)
2247
- };
2248
-
2249
1483
  const main$1 = async () => {
2250
- registerCommands(mainAreaCommandMap);
1484
+ registerCommands(commandMap);
2251
1485
  const rpc = await WebWorkerRpcClient.create({
2252
- commandMap: mainAreaCommandMap
1486
+ commandMap: commandMap
2253
1487
  });
2254
1488
  set$1(rpc);
2255
1489
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/main-area-worker",
3
- "version": "1.1.0",
3
+ "version": "1.3.0",
4
4
  "description": "Main Area Worker",
5
5
  "repository": {
6
6
  "type": "git",