@lvce-editor/extension-detail-view 3.35.0 → 3.37.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.
@@ -411,9 +411,103 @@ const IpcChildWithModuleWorkerAndMessagePort$1 = {
411
411
  listen: listen$6,
412
412
  wrap: wrap$e
413
413
  };
414
+ const addListener = (emitter, type, callback) => {
415
+ if ('addEventListener' in emitter) {
416
+ emitter.addEventListener(type, callback);
417
+ } else {
418
+ emitter.on(type, callback);
419
+ }
420
+ };
421
+ const removeListener = (emitter, type, callback) => {
422
+ if ('removeEventListener' in emitter) {
423
+ emitter.removeEventListener(type, callback);
424
+ } else {
425
+ emitter.off(type, callback);
426
+ }
427
+ };
428
+ const getFirstEvent = (eventEmitter, eventMap) => {
429
+ const {
430
+ resolve,
431
+ promise
432
+ } = Promise.withResolvers();
433
+ const listenerMap = Object.create(null);
434
+ const cleanup = value => {
435
+ for (const event of Object.keys(eventMap)) {
436
+ removeListener(eventEmitter, event, listenerMap[event]);
437
+ }
438
+ resolve(value);
439
+ };
440
+ for (const [event, type] of Object.entries(eventMap)) {
441
+ const listener = event => {
442
+ cleanup({
443
+ type,
444
+ event
445
+ });
446
+ };
447
+ addListener(eventEmitter, event, listener);
448
+ listenerMap[event] = listener;
449
+ }
450
+ return promise;
451
+ };
452
+ const Message$1 = 3;
453
+ const create$5$1 = async ({
454
+ messagePort,
455
+ isMessagePortOpen
456
+ }) => {
457
+ if (!isMessagePort(messagePort)) {
458
+ throw new IpcError('port must be of type MessagePort');
459
+ }
460
+ if (isMessagePortOpen) {
461
+ return messagePort;
462
+ }
463
+ const eventPromise = getFirstEvent(messagePort, {
464
+ message: Message$1
465
+ });
466
+ messagePort.start();
467
+ const {
468
+ type,
469
+ event
470
+ } = await eventPromise;
471
+ if (type !== Message$1) {
472
+ throw new IpcError('Failed to wait for ipc message');
473
+ }
474
+ if (event.data !== readyMessage) {
475
+ throw new IpcError('unexpected first message');
476
+ }
477
+ return messagePort;
478
+ };
479
+ const signal$1 = messagePort => {
480
+ messagePort.start();
481
+ };
482
+ class IpcParentWithMessagePort extends Ipc {
483
+ getData = getData$2;
484
+ send(message) {
485
+ this._rawIpc.postMessage(message);
486
+ }
487
+ sendAndTransfer(message) {
488
+ const transfer = getTransferrables(message);
489
+ this._rawIpc.postMessage(message, transfer);
490
+ }
491
+ dispose() {
492
+ this._rawIpc.close();
493
+ }
494
+ onMessage(callback) {
495
+ this._rawIpc.addEventListener('message', callback);
496
+ }
497
+ onClose(callback) {}
498
+ }
499
+ const wrap$5 = messagePort => {
500
+ return new IpcParentWithMessagePort(messagePort);
501
+ };
502
+ const IpcParentWithMessagePort$1 = {
503
+ __proto__: null,
504
+ create: create$5$1,
505
+ signal: signal$1,
506
+ wrap: wrap$5
507
+ };
414
508
 
415
509
  const Two = '2.0';
416
- const create$4 = (method, params) => {
510
+ const create$4$1 = (method, params) => {
417
511
  return {
418
512
  jsonrpc: Two,
419
513
  method,
@@ -421,7 +515,7 @@ const create$4 = (method, params) => {
421
515
  };
422
516
  };
423
517
  const callbacks = Object.create(null);
424
- const set$2 = (id, fn) => {
518
+ const set$4 = (id, fn) => {
425
519
  callbacks[id] = fn;
426
520
  };
427
521
  const get$2 = id => {
@@ -440,7 +534,7 @@ const registerPromise = () => {
440
534
  resolve,
441
535
  promise
442
536
  } = Promise.withResolvers();
443
- set$2(id, resolve);
537
+ set$4(id, resolve);
444
538
  return {
445
539
  id,
446
540
  promise
@@ -667,7 +761,7 @@ const getErrorResponse = (id, error, preparePrettyError, logError) => {
667
761
  const errorProperty = getErrorProperty(error, prettyError);
668
762
  return create$1$1(id, errorProperty);
669
763
  };
670
- const create$5 = (message, result) => {
764
+ const create$6 = (message, result) => {
671
765
  return {
672
766
  jsonrpc: Two,
673
767
  id: message.id,
@@ -676,7 +770,7 @@ const create$5 = (message, result) => {
676
770
  };
677
771
  const getSuccessResponse = (message, result) => {
678
772
  const resultProperty = result ?? null;
679
- return create$5(message, resultProperty);
773
+ return create$6(message, resultProperty);
680
774
  };
681
775
  const getErrorResponseSimple = (id, error) => {
682
776
  return {
@@ -781,7 +875,7 @@ const invokeHelper = async (ipc, method, params, useSendAndTransfer) => {
781
875
  return unwrapJsonRpcResult(responseMessage);
782
876
  };
783
877
  const send = (transport, method, ...params) => {
784
- const message = create$4(method, params);
878
+ const message = create$4$1(method, params);
785
879
  transport.send(message);
786
880
  };
787
881
  const invoke = (ipc, method, ...params) => {
@@ -858,7 +952,41 @@ const listen$1 = async (module, options) => {
858
952
  const ipc = module.wrap(rawIpc);
859
953
  return ipc;
860
954
  };
955
+ const create$5 = async ({
956
+ commandMap,
957
+ messagePort
958
+ }) => {
959
+ // TODO create a commandMap per rpc instance
960
+ register(commandMap);
961
+ const rawIpc = await IpcParentWithMessagePort$1.create({
962
+ messagePort,
963
+ isMessagePortOpen: true
964
+ });
965
+ const ipc = IpcParentWithMessagePort$1.wrap(rawIpc);
966
+ handleIpc(ipc);
967
+ const rpc = createRpc(ipc);
968
+ messagePort.start();
969
+ return rpc;
970
+ };
861
971
  const create$3 = async ({
972
+ commandMap,
973
+ send
974
+ }) => {
975
+ const {
976
+ port1,
977
+ port2
978
+ } = new MessageChannel();
979
+ await send(port1);
980
+ return create$5({
981
+ commandMap,
982
+ messagePort: port2
983
+ });
984
+ };
985
+ const TransferMessagePortRpcParent = {
986
+ __proto__: null,
987
+ create: create$3
988
+ };
989
+ const create$4 = async ({
862
990
  commandMap
863
991
  }) => {
864
992
  // TODO create a commandMap per rpc instance
@@ -870,7 +998,7 @@ const create$3 = async ({
870
998
  };
871
999
  const WebWorkerRpcClient = {
872
1000
  __proto__: null,
873
- create: create$3
1001
+ create: create$4
874
1002
  };
875
1003
 
876
1004
  const create$2 = () => {
@@ -935,9 +1063,13 @@ const terminate = () => {
935
1063
  globalThis.close();
936
1064
  };
937
1065
 
1066
+ const copyImage = state => {
1067
+ return state;
1068
+ };
1069
+
938
1070
  const {
939
1071
  get: get$1,
940
- set: set$1,
1072
+ set: set$2,
941
1073
  dispose: dispose$1,
942
1074
  wrapCommand
943
1075
  } = create$2();
@@ -982,26 +1114,35 @@ const create$1 = (uid, uri, x, y, width, height, platform, assetDir) => {
982
1114
  themesMarkdownDom: [],
983
1115
  uri,
984
1116
  webViews: [],
985
- width
1117
+ width,
1118
+ scrollSource: 0
986
1119
  };
987
- set$1(uid, state, state);
1120
+ set$2(uid, state, state);
988
1121
  };
989
1122
 
990
1123
  const RenderFocus = 2;
991
1124
  const RenderItems = 3;
1125
+ const RenderScrollTop = 4;
992
1126
 
993
- const diffType$1 = RenderFocus;
1127
+ const diffType$2 = RenderFocus;
1128
+ const isEqual$2 = (oldState, newState) => {
1129
+ return oldState === newState;
1130
+ };
1131
+
1132
+ const diffType$1 = RenderItems;
994
1133
  const isEqual$1 = (oldState, newState) => {
995
1134
  return oldState === newState;
996
1135
  };
997
1136
 
998
- const diffType = RenderItems;
1137
+ const User = 1;
1138
+
1139
+ const diffType = RenderScrollTop;
999
1140
  const isEqual = (oldState, newState) => {
1000
- return oldState === newState;
1141
+ return newState.scrollSource === User || oldState.readmeScrollTop === newState.readmeScrollTop;
1001
1142
  };
1002
1143
 
1003
- const modules = [isEqual, isEqual$1];
1004
- const numbers = [diffType, diffType$1];
1144
+ const modules = [isEqual$1, isEqual$2, isEqual];
1145
+ const numbers = [diffType$1, diffType$2, diffType];
1005
1146
 
1006
1147
  const diff2 = uid => {
1007
1148
  const {
@@ -1022,7 +1163,7 @@ const dispose = uid => {
1022
1163
  dispose$1(uid);
1023
1164
  };
1024
1165
 
1025
- const commandIds = ['getMenuEntries', 'handleClickCategory', 'handleClickDisable', 'handleClickScrollToTop', 'handleClickSettings', 'handleClickSetColorTheme', 'handleClickSize', 'handleClickUninstall', 'handleFeaturesClick', 'handleIconError', 'handleTabsClick', 'handleWheel', 'renderEventListeners', 'resize', 'saveState', 'selectTab', 'terminate'];
1166
+ const commandIds = ['copyImage', 'getMenuEntries', 'handleClickCategory', 'handleClickDisable', 'handleClickScrollToTop', 'handleClickSettings', 'handleClickSetColorTheme', 'handleClickSize', 'handleClickUninstall', 'handleFeaturesClick', 'handleIconError', 'handleTabsClick', 'handleWheel', 'renderEventListeners', 'resize', 'saveState', 'selectTab', 'terminate'];
1026
1167
 
1027
1168
  const getCommandIds = () => {
1028
1169
  return commandIds;
@@ -1062,14 +1203,13 @@ const OpenInNewTab = 'Open in New Tab';
1062
1203
  const ProgrammingLanguages$1 = 'Programming Languages';
1063
1204
  const SaveImageAs = 'Save Image as';
1064
1205
  const Schema = 'Schema';
1065
- const ScrollToTop = 'Scroll to top';
1206
+ const ScrollToTop$1 = 'Scroll to top';
1066
1207
  const Selector = 'Selector';
1067
1208
  const Settings$1 = 'Settings';
1068
1209
  const SetColorTheme$1 = 'Set Color Theme';
1069
1210
  const Theme$1 = 'Theme';
1070
1211
  const Uninstall$1 = 'Uninstall';
1071
1212
  const WebViews$1 = 'WebViews';
1072
- const NotImplemented = 'Not Implemented';
1073
1213
 
1074
1214
  const installation = () => {
1075
1215
  return i18nString(Installation);
@@ -1152,14 +1292,11 @@ const contentSecurityPolicy = () => {
1152
1292
  const elements = () => {
1153
1293
  return i18nString(Elements);
1154
1294
  };
1155
- const notImplemented = () => {
1156
- return i18nString(NotImplemented);
1157
- };
1158
1295
  const uninstall = () => {
1159
1296
  return i18nString(Uninstall$1);
1160
1297
  };
1161
1298
  const scrollToTop = () => {
1162
- return i18nString(ScrollToTop);
1299
+ return i18nString(ScrollToTop$1);
1163
1300
  };
1164
1301
 
1165
1302
  const None = 0;
@@ -1291,6 +1428,154 @@ const getFeatureDetailsSettings = extension => {
1291
1428
  };
1292
1429
  };
1293
1430
 
1431
+ const Panel = 'panel';
1432
+ const Tab$1 = 'tab';
1433
+ const TabList = 'tablist';
1434
+ const AriaRoles = {
1435
+ __proto__: null,
1436
+ Panel,
1437
+ Tab: Tab$1,
1438
+ TabList};
1439
+ const mergeClassNames = (...classNames) => {
1440
+ return classNames.filter(Boolean).join(' ');
1441
+ };
1442
+ const Button$1 = 1;
1443
+ const Div = 4;
1444
+ const H1 = 5;
1445
+ const Span = 8;
1446
+ const Table$1 = 9;
1447
+ const TBody = 10;
1448
+ const Td = 11;
1449
+ const Text = 12;
1450
+ const Th = 13;
1451
+ const THead = 14;
1452
+ const Tr = 15;
1453
+ const Img = 17;
1454
+ const H2 = 22;
1455
+ const Dd = 43;
1456
+ const Dl = 44;
1457
+ const Pre = 51;
1458
+ const A = 53;
1459
+ const Code$1 = 65;
1460
+ const Dt = 67;
1461
+ const VirtualDomElements = {
1462
+ __proto__: null,
1463
+ A,
1464
+ Button: Button$1,
1465
+ Code: Code$1,
1466
+ Dd,
1467
+ Div,
1468
+ Dl,
1469
+ Dt,
1470
+ H1,
1471
+ H2,
1472
+ Img,
1473
+ Pre,
1474
+ Span,
1475
+ TBody,
1476
+ THead,
1477
+ Table: Table$1,
1478
+ Td,
1479
+ Th,
1480
+ Tr};
1481
+ const text = data => {
1482
+ return {
1483
+ type: Text,
1484
+ text: data,
1485
+ childCount: 0
1486
+ };
1487
+ };
1488
+
1489
+ const AdditionalDetails = 'AdditionalDetails';
1490
+ const AdditionalDetailsEntry = 'AdditionalDetailsEntry';
1491
+ const AdditionalDetailsTitle = 'AdditionalDetailsTitle';
1492
+ const Aside = 'Aside';
1493
+ const Button = 'Button';
1494
+ const ButtonPrimary = 'ButtonPrimary';
1495
+ const Categories = 'Categories';
1496
+ const Category = 'Category';
1497
+ const Changelog$1 = 'Changelog';
1498
+ const Code = 'Code';
1499
+ const DefaultMarkdown = 'DefaultMarkdown';
1500
+ const DefinitionListItem = 'DefinitionListItem';
1501
+ const DefinitionListItemHeading = 'DefinitionListItemHeading';
1502
+ const DefinitionListItemValue = 'DefinitionListItemValue';
1503
+ const ExtensionDetail = 'ExtensionDetail';
1504
+ const ExtensionDetailDescription = 'ExtensionDetailDescription';
1505
+ const ExtensionDetailHeader = 'ExtensionDetailHeader';
1506
+ const ExtensionDetailHeaderActions = 'ExtensionDetailHeaderActions';
1507
+ const ExtensionDetailHeaderDetails = 'ExtensionDetailHeaderDetails';
1508
+ const ExtensionDetailIcon = 'ExtensionDetailIcon';
1509
+ const ExtensionDetailName = 'ExtensionDetailName';
1510
+ const ExtensionDetailNameBadge = 'ExtensionDetailNameBadge';
1511
+ const ExtensionDetailPanel = 'ExtensionDetailPanel';
1512
+ const ExtensionDetailTab = 'ExtensionDetailTab';
1513
+ const ExtensionDetailTabs = 'ExtensionDetailTabs';
1514
+ const ExtensionDetailTabSelected = 'ExtensionDetailTabSelected';
1515
+ const Feature = 'Feature';
1516
+ const FeatureContent = 'FeatureContent';
1517
+ const Features$1 = 'Features';
1518
+ const FeaturesList = 'FeaturesList';
1519
+ const FeatureWebView = 'FeatureWebView';
1520
+ const Large$1 = 'Large';
1521
+ const Link = 'Link';
1522
+ const MoreInfo = 'MoreInfo';
1523
+ const MoreInfoEntry = 'MoreInfoEntry';
1524
+ const MoreInfoEntryKey = 'MoreInfoEntryKey';
1525
+ const MoreInfoEntryOdd = 'MoreInfoEntryOdd';
1526
+ const MoreInfoEntryValue = 'MoreInfoEntryValue';
1527
+ const Normal$1 = 'Normal';
1528
+ const Resource = 'Resource';
1529
+ const Resources = 'Resources';
1530
+ const Sash = 'Sash';
1531
+ const SashVertical = 'SashVertical';
1532
+ const ScrollToTopButton = 'ScrollToTopButton';
1533
+ const SettingsButton = 'SettingsButton';
1534
+ const SettingsIcon = 'SettingsIcon';
1535
+ const Small$1 = 'Small';
1536
+ const Table = 'Table';
1537
+ const TableCell = 'TableCell';
1538
+ const TableHeading = 'TableHeading';
1539
+ const Viewlet = 'Viewlet';
1540
+
1541
+ const HandleClickCategory = 'handleClickCategory';
1542
+ const HandleClickDisable = 'handleClickDisable';
1543
+ const HandleClickScrollToTop = 'handleClickScrollToTop';
1544
+ const HandleClickSetColorTheme = 'handleClickSetColorTheme';
1545
+ const HandleClickSettings = 'handleClickSettings';
1546
+ const HandleClickSize = 'handleClickSize';
1547
+ const HandleClickUninstall = 'handleClickUninstall';
1548
+ const HandleFeaturesClick = 'handleFeaturesClick';
1549
+ const HandleIconError = 'handleIconError';
1550
+ const HandleReadmeContextMenu = 'handleReadmeContextMenu';
1551
+ const HandleReadmeWheel = 'handleReadmeWheel';
1552
+ const HandleTabsClick = 'handleTabsClick';
1553
+
1554
+ const Changelog = 'Changelog';
1555
+ const Commands = 'Commands';
1556
+ const Details = 'Details';
1557
+ const Disable = 'Disable';
1558
+ const Features = 'Features';
1559
+ const JsonValidation = 'JsonValidation';
1560
+ const ProgrammingLanguages = 'ProgrammingLanguages';
1561
+ const SetColorTheme = 'SetColorTheme';
1562
+ const Settings = 'Settings';
1563
+ const Theme = 'Theme';
1564
+ const Uninstall = 'Uninstall';
1565
+ const WebViews = 'WebViews';
1566
+ const ScrollToTop = 'scrolltotop';
1567
+
1568
+ const getScrollToTopVirtualDom = scrollToTopButtonEnabled => {
1569
+ return [{
1570
+ type: VirtualDomElements.Button,
1571
+ className: ScrollToTopButton,
1572
+ childCount: 0,
1573
+ onClick: HandleClickScrollToTop,
1574
+ ariaLabel: scrollToTop(),
1575
+ name: ScrollToTop
1576
+ }];
1577
+ };
1578
+
1294
1579
  const rpcs = Object.create(null);
1295
1580
  const set$g = (id, rpc) => {
1296
1581
  rpcs[id] = rpc;
@@ -1325,13 +1610,37 @@ const create = rpcId => {
1325
1610
  };
1326
1611
  };
1327
1612
  const RendererWorker$1 = 1;
1613
+ const MarkdownWorker$1 = 300;
1614
+ const {
1615
+ invoke: invoke$5,
1616
+ set: set$5} = create(MarkdownWorker$1);
1617
+ const getVirtualDom$1 = async html => {
1618
+ // @ts-ignore
1619
+ return invoke$5('Markdown.getVirtualDom', html);
1620
+ };
1621
+ const render$1 = async (markdown, options) => {
1622
+ // @ts-ignore
1623
+ return invoke$5('Markdown.render', markdown, options);
1624
+ };
1625
+ const MarkdownWorker = {
1626
+ __proto__: null,
1627
+ getVirtualDom: getVirtualDom$1,
1628
+ render: render$1,
1629
+ set: set$5
1630
+ };
1328
1631
  const {
1329
1632
  invoke: invoke$3,
1633
+ invokeAndTransfer: invokeAndTransfer$3,
1330
1634
  set: set$3} = create(RendererWorker$1);
1331
1635
  const setColorTheme$2 = async id => {
1332
1636
  // @ts-ignore
1333
1637
  return invoke$3(/* ColorTheme.setColorTheme */'ColorTheme.setColorTheme', /* colorThemeId */id);
1334
1638
  };
1639
+ const sendMessagePortToMarkdownWorker$2 = async (port, rpcId) => {
1640
+ const command = 'Markdown.handleMessagePort';
1641
+ // @ts-ignore
1642
+ await invokeAndTransfer$3('SendMessagePortToExtensionHostWorker.sendMessagePortToMarkdownWorker', port, command, rpcId);
1643
+ };
1335
1644
  const readFile$2 = async uri => {
1336
1645
  return invoke$3('FileSystem.readFile', uri);
1337
1646
  };
@@ -1346,14 +1655,6 @@ const getExtension$3 = async id => {
1346
1655
  // @ts-ignore
1347
1656
  return invoke$3('ExtensionManagement.getExtension', id);
1348
1657
  };
1349
- const getMarkdownDom$1 = async html => {
1350
- // @ts-ignore
1351
- return invoke$3('Markdown.getVirtualDom', html);
1352
- };
1353
- const renderMarkdown$2 = async (markdown, options) => {
1354
- // @ts-ignore
1355
- return invoke$3('Markdown.renderMarkdown', markdown, options);
1356
- };
1357
1658
  const openNativeFolder$1 = async uri => {
1358
1659
  // @ts-ignore
1359
1660
  await invoke$3('OpenNativeFolder.openNativeFolder', uri);
@@ -1363,28 +1664,28 @@ const RendererWorker = {
1363
1664
  getAllExtensions: getAllExtensions$2,
1364
1665
  getExtension: getExtension$3,
1365
1666
  getFolderSize: getFolderSize$2,
1366
- getMarkdownDom: getMarkdownDom$1,
1367
1667
  openNativeFolder: openNativeFolder$1,
1368
1668
  readFile: readFile$2,
1369
- renderMarkdown: renderMarkdown$2,
1669
+ sendMessagePortToMarkdownWorker: sendMessagePortToMarkdownWorker$2,
1370
1670
  set: set$3,
1371
1671
  setColorTheme: setColorTheme$2};
1372
1672
 
1373
1673
  const {
1374
- getAllExtensions: getAllExtensions$1,
1375
- getExtension: getExtension$2,
1376
- getFolderSize: getFolderSize$1,
1377
- getMarkdownDom,
1378
- openNativeFolder,
1379
- readFile: readFile$1,
1380
- renderMarkdown: renderMarkdown$1,
1381
- set,
1382
- setColorTheme: setColorTheme$1} = RendererWorker;
1674
+ set: set$1,
1675
+ getVirtualDom,
1676
+ render
1677
+ } = MarkdownWorker;
1383
1678
 
1384
- const getMarkdownVirtualDom = async html => {
1679
+ const getMarkdownVirtualDom = async (html, options) => {
1385
1680
  string(html);
1386
- const dom = await getMarkdownDom(html);
1387
- return dom;
1681
+ const dom = await getVirtualDom(html);
1682
+ const newDom = [...dom];
1683
+ if (options?.scrollToTopEnabled) {
1684
+ newDom[0].childCount++;
1685
+ const extraDom = getScrollToTopVirtualDom();
1686
+ newDom.splice(1, 0, ...extraDom);
1687
+ }
1688
+ return newDom;
1388
1689
  };
1389
1690
 
1390
1691
  const getThemeItemMarkdown = (heading, items) => {
@@ -1421,7 +1722,7 @@ const getThemeMarkdown = (themes, iconThemes, productIconThemes) => {
1421
1722
  };
1422
1723
 
1423
1724
  const renderMarkdown = async (markdown, options = {}) => {
1424
- const html = await renderMarkdown$1(markdown, options);
1725
+ const html = await render(markdown, options);
1425
1726
  return html;
1426
1727
  };
1427
1728
 
@@ -1469,19 +1770,6 @@ const getFeatureDetailsWebView = extension => {
1469
1770
  };
1470
1771
  };
1471
1772
 
1472
- const Changelog$1 = 'Changelog';
1473
- const Commands = 'Commands';
1474
- const Details = 'Details';
1475
- const Disable = 'Disable';
1476
- const Features$1 = 'Features';
1477
- const JsonValidation = 'JsonValidation';
1478
- const ProgrammingLanguages = 'ProgrammingLanguages';
1479
- const SetColorTheme = 'SetColorTheme';
1480
- const Settings = 'Settings';
1481
- const Theme = 'Theme';
1482
- const Uninstall = 'Uninstall';
1483
- const WebViews = 'WebViews';
1484
-
1485
1773
  const getFeatureDetailsHandler = featureName => {
1486
1774
  switch (featureName) {
1487
1775
  case Commands:
@@ -1537,12 +1825,29 @@ const handleClickFeatures = async (state, name) => {
1537
1825
  };
1538
1826
 
1539
1827
  const handleClickScrollToTop = state => {
1828
+ const {
1829
+ readmeScrollTop
1830
+ } = state;
1831
+ if (readmeScrollTop === 0) {
1832
+ return state;
1833
+ }
1540
1834
  return {
1541
1835
  ...state,
1542
1836
  readmeScrollTop: 0
1543
1837
  };
1544
1838
  };
1545
1839
 
1840
+ const {
1841
+ getAllExtensions: getAllExtensions$1,
1842
+ getExtension: getExtension$2,
1843
+ getFolderSize: getFolderSize$1,
1844
+ openNativeFolder,
1845
+ readFile: readFile$1,
1846
+ set,
1847
+ setColorTheme: setColorTheme$1,
1848
+ sendMessagePortToMarkdownWorker: sendMessagePortToMarkdownWorker$1
1849
+ } = RendererWorker;
1850
+
1546
1851
  const setColorTheme = id => {
1547
1852
  return setColorTheme$1(id);
1548
1853
  };
@@ -1616,13 +1921,13 @@ const isEnoentError = error => {
1616
1921
  return error && error.code === ENOENT;
1617
1922
  };
1618
1923
 
1619
- const join = (pathSeparator, ...parts) => {
1620
- return parts.join(pathSeparator);
1924
+ const join = (...parts) => {
1925
+ return parts.join('/');
1621
1926
  };
1622
1927
 
1623
1928
  const loadChangelogContent = async path => {
1624
1929
  try {
1625
- const changelogUrl = join('/', path, 'CHANGELOG.md');
1930
+ const changelogUrl = join(path, 'CHANGELOG.md');
1626
1931
  const changelogContent = await readFile(changelogUrl);
1627
1932
  return changelogContent;
1628
1933
  } catch (error) {
@@ -1648,7 +1953,7 @@ const selectTabChangelog = async state => {
1648
1953
  const changelogDom = await getMarkdownVirtualDom(changelogMarkdownHtml);
1649
1954
  return {
1650
1955
  ...state,
1651
- selectedTab: Changelog$1,
1956
+ selectedTab: Changelog,
1652
1957
  changelogVirtualDom: changelogDom
1653
1958
  };
1654
1959
  };
@@ -1659,7 +1964,7 @@ const selectTabDefault = async state => {
1659
1964
 
1660
1965
  const loadReadmeContent = async path => {
1661
1966
  try {
1662
- const readmeUrl = join('/', path, 'README.md');
1967
+ const readmeUrl = join(path, 'README.md');
1663
1968
  const readmeContent = await readFile(readmeUrl);
1664
1969
  return readmeContent;
1665
1970
  } catch (error) {
@@ -1701,18 +2006,18 @@ const selectTabFeatures = async state => {
1701
2006
  const partialNewState = await fn(extension, baseUrl);
1702
2007
  return {
1703
2008
  ...state,
1704
- selectedTab: Features$1,
2009
+ selectedTab: Features,
1705
2010
  ...partialNewState
1706
2011
  };
1707
2012
  };
1708
2013
 
1709
- const getSelectTabHandler = selectedTab => {
1710
- switch (selectedTab) {
2014
+ const getSelectTabHandler = name => {
2015
+ switch (name) {
1711
2016
  case Details:
1712
2017
  return selectTabDetails;
1713
- case Features$1:
2018
+ case Features:
1714
2019
  return selectTabFeatures;
1715
- case Changelog$1:
2020
+ case Changelog:
1716
2021
  return selectTabChangelog;
1717
2022
  default:
1718
2023
  return selectTabDefault;
@@ -1732,13 +2037,35 @@ const handleWheel = (state, deltaX, deltaY) => {
1732
2037
  const newScrollTop = Math.max(0, state.readmeScrollTop + deltaY);
1733
2038
  return {
1734
2039
  ...state,
1735
- readmeScrollTop: newScrollTop
2040
+ readmeScrollTop: newScrollTop,
2041
+ scrollSource: User
1736
2042
  };
1737
2043
  };
1738
2044
 
2045
+ const sendMessagePortToMarkdownWorker = async port => {
2046
+ await sendMessagePortToMarkdownWorker$1(port, 0);
2047
+ };
2048
+
2049
+ const createMarkdownWorkerRpc = async () => {
2050
+ try {
2051
+ const rpc = await TransferMessagePortRpcParent.create({
2052
+ commandMap: {},
2053
+ send: sendMessagePortToMarkdownWorker
2054
+ });
2055
+ return rpc;
2056
+ } catch (error) {
2057
+ throw new VError(error, `Failed to create markdown worker rpc`);
2058
+ }
2059
+ };
2060
+
2061
+ const initializeMarkdownWorker = async () => {
2062
+ const rpc = await createMarkdownWorkerRpc();
2063
+ set$1(rpc);
2064
+ };
2065
+
1739
2066
  const initialize = async () => {
2067
+ await initializeMarkdownWorker();
1740
2068
  // TODO create connection to file system worker
1741
- // TODO create direct connection to markdown worker
1742
2069
  };
1743
2070
 
1744
2071
  const isLanguageBasicsExtension = extension => {
@@ -2033,18 +2360,18 @@ const getSecondEntries = () => {
2033
2360
  }];
2034
2361
  };
2035
2362
 
2036
- const Small$1 = 1;
2037
- const Normal$1 = 2;
2038
- const Large$1 = 3;
2363
+ const Small = 1;
2364
+ const Normal = 2;
2365
+ const Large = 3;
2039
2366
 
2040
2367
  const getViewletSize = width => {
2041
2368
  if (width < 180) {
2042
- return Small$1;
2369
+ return Small;
2043
2370
  }
2044
2371
  if (width < 768) {
2045
- return Normal$1;
2372
+ return Normal;
2046
2373
  }
2047
- return Large$1;
2374
+ return Large;
2048
2375
  };
2049
2376
 
2050
2377
  const hasColorThemes = extension => {
@@ -2090,7 +2417,9 @@ const loadContent = async (state, platform, savedState) => {
2090
2417
  const readmeHtml = await renderMarkdown(readmeContent, {
2091
2418
  baseUrl
2092
2419
  });
2093
- const detailsVirtualDom = await getMarkdownVirtualDom(readmeHtml);
2420
+ const detailsVirtualDom = await getMarkdownVirtualDom(readmeHtml, {
2421
+ scrollToTopEnabled: true
2422
+ });
2094
2423
  const iconSrc = getIcon(extension, platform, assetDir);
2095
2424
  const description = getDescription(extension);
2096
2425
  const name = getName(extension);
@@ -2133,7 +2462,8 @@ const loadContent = async (state, platform, savedState) => {
2133
2462
  sizeOnDisk: size,
2134
2463
  sizeValue,
2135
2464
  extensionId,
2136
- extensionVersion
2465
+ extensionVersion,
2466
+ scrollToTopButtonEnabled: true
2137
2467
  };
2138
2468
  };
2139
2469
 
@@ -2141,108 +2471,6 @@ const loadContent2 = async (state, savedState) => {
2141
2471
  return loadContent(state, state.platform, savedState);
2142
2472
  };
2143
2473
 
2144
- const mergeClassNames = (...classNames) => {
2145
- return classNames.filter(Boolean).join(' ');
2146
- };
2147
- const Button$1 = 1;
2148
- const Div = 4;
2149
- const H1 = 5;
2150
- const Span = 8;
2151
- const Table$1 = 9;
2152
- const TBody = 10;
2153
- const Td = 11;
2154
- const Text = 12;
2155
- const Th = 13;
2156
- const THead = 14;
2157
- const Tr = 15;
2158
- const Img = 17;
2159
- const H2 = 22;
2160
- const Dd = 43;
2161
- const Dl = 44;
2162
- const Pre = 51;
2163
- const A = 53;
2164
- const Code$1 = 65;
2165
- const Dt = 67;
2166
- const VirtualDomElements = {
2167
- __proto__: null,
2168
- A,
2169
- Button: Button$1,
2170
- Code: Code$1,
2171
- Dd,
2172
- Div,
2173
- Dl,
2174
- Dt,
2175
- H1,
2176
- H2,
2177
- Img,
2178
- Pre,
2179
- Span,
2180
- TBody,
2181
- THead,
2182
- Table: Table$1,
2183
- Td,
2184
- Th,
2185
- Tr};
2186
- const text = data => {
2187
- return {
2188
- type: Text,
2189
- text: data,
2190
- childCount: 0
2191
- };
2192
- };
2193
-
2194
- const AdditionalDetails = 'AdditionalDetails';
2195
- const AdditionalDetailsEntry = 'AdditionalDetailsEntry';
2196
- const AdditionalDetailsTitle = 'AdditionalDetailsTitle';
2197
- const Aside = 'Aside';
2198
- const Button = 'Button';
2199
- const ButtonPrimary = 'ButtonPrimary';
2200
- const Categories = 'Categories';
2201
- const Category = 'Category';
2202
- const Changelog = 'Changelog';
2203
- const Code = 'Code';
2204
- const DefaultMarkdown = 'DefaultMarkdown';
2205
- const DefinitionListItem = 'DefinitionListItem';
2206
- const DefinitionListItemHeading = 'DefinitionListItemHeading';
2207
- const DefinitionListItemValue = 'DefinitionListItemValue';
2208
- const ExtensionDetail = 'ExtensionDetail';
2209
- const ExtensionDetailDescription = 'ExtensionDetailDescription';
2210
- const ExtensionDetailHeader = 'ExtensionDetailHeader';
2211
- const ExtensionDetailHeaderActions = 'ExtensionDetailHeaderActions';
2212
- const ExtensionDetailHeaderDetails = 'ExtensionDetailHeaderDetails';
2213
- const ExtensionDetailIcon = 'ExtensionDetailIcon';
2214
- const ExtensionDetailName = 'ExtensionDetailName';
2215
- const ExtensionDetailNameBadge = 'ExtensionDetailNameBadge';
2216
- const ExtensionDetailPanel = 'ExtensionDetailPanel';
2217
- const ExtensionDetailTab = 'ExtensionDetailTab';
2218
- const ExtensionDetailTabs = 'ExtensionDetailTabs';
2219
- const ExtensionDetailTabSelected = 'ExtensionDetailTabSelected';
2220
- const Feature = 'Feature';
2221
- const FeatureContent = 'FeatureContent';
2222
- const Features = 'Features';
2223
- const FeaturesList = 'FeaturesList';
2224
- const FeatureWebView = 'FeatureWebView';
2225
- const Large = 'Large';
2226
- const Link = 'Link';
2227
- const MoreInfo = 'MoreInfo';
2228
- const MoreInfoEntry = 'MoreInfoEntry';
2229
- const MoreInfoEntryKey = 'MoreInfoEntryKey';
2230
- const MoreInfoEntryOdd = 'MoreInfoEntryOdd';
2231
- const MoreInfoEntryValue = 'MoreInfoEntryValue';
2232
- const Normal = 'Normal';
2233
- const Resource = 'Resource';
2234
- const Resources = 'Resources';
2235
- const Sash = 'Sash';
2236
- const SashVertical = 'SashVertical';
2237
- const ScrollToTopButton = 'ScrollToTopButton';
2238
- const SettingsButton = 'SettingsButton';
2239
- const SettingsIcon = 'SettingsIcon';
2240
- const Small = 'Small';
2241
- const Table = 'Table';
2242
- const TableCell = 'TableCell';
2243
- const TableHeading = 'TableHeading';
2244
- const Viewlet = 'Viewlet';
2245
-
2246
2474
  const getBadge = (builtin, badgeEnabled) => {
2247
2475
  if (builtin && badgeEnabled) {
2248
2476
  return 'builtin';
@@ -2250,19 +2478,6 @@ const getBadge = (builtin, badgeEnabled) => {
2250
2478
  return '';
2251
2479
  };
2252
2480
 
2253
- const HandleClickCategory = 'handleClickCategory';
2254
- const HandleClickDisable = 'handleClickDisable';
2255
- const HandleClickScrollToTop = 'handleClickScrollToTop';
2256
- const HandleClickSetColorTheme = 'handleClickSetColorTheme';
2257
- const HandleClickSettings = 'handleClickSettings';
2258
- const HandleClickSize = 'handleClickSize';
2259
- const HandleClickUninstall = 'handleClickUninstall';
2260
- const HandleFeaturesClick = 'handleFeaturesClick';
2261
- const HandleIconError = 'handleIconError';
2262
- const HandleReadmeContextMenu = 'handleReadmeContextMenu';
2263
- const HandleReadmeWheel = 'handleReadmeWheel';
2264
- const HandleTabsClick = 'handleTabsClick';
2265
-
2266
2481
  const getExtensionDetailButtons = (hasColorTheme, isBuiltin) => {
2267
2482
  const allActions = [{
2268
2483
  label: setColorTheme$3(),
@@ -2283,20 +2498,16 @@ const getExtensionDetailButtons = (hasColorTheme, isBuiltin) => {
2283
2498
  return allActions;
2284
2499
  };
2285
2500
 
2286
- const getChangelogVirtualDom = () => {
2287
- const notImplemented$1 = notImplemented();
2501
+ const getChangelogVirtualDom = changelogDom => {
2502
+ // const notImplemented = ExtensionDetailStrings.notImplemented()
2288
2503
  // TODO set tabpanel role
2289
2504
  return [{
2290
2505
  type: VirtualDomElements.Div,
2291
- className: Changelog,
2506
+ className: Changelog$1,
2292
2507
  childCount: 1
2293
- }, text(notImplemented$1)];
2508
+ }, ...changelogDom];
2294
2509
  };
2295
2510
 
2296
- const TabList = 'tablist';
2297
- const Tab = 'tab';
2298
- const Panel = 'panel';
2299
-
2300
2511
  const getAdditionalDetailsEntryVirtualDom = (heading, items, renderer) => {
2301
2512
  return [{
2302
2513
  type: VirtualDomElements.Div,
@@ -2476,28 +2687,16 @@ const getMarketplaceEntries = () => {
2476
2687
  }];
2477
2688
  };
2478
2689
 
2479
- const getScrollToTopVirtualDom = scrollToTopButtonEnabled => {
2480
- if (!scrollToTopButtonEnabled) {
2481
- return [];
2482
- }
2483
- return [{
2484
- type: VirtualDomElements.Button,
2485
- className: ScrollToTopButton,
2486
- childCount: 0,
2487
- onClick: HandleClickScrollToTop,
2488
- ariaLabel: scrollToTop(),
2489
- name: 'scrolltotop'
2490
- }];
2491
- };
2690
+ // import * as GetScrollToTopVirtualDom from '../GetScrollToTopVirtualDom/GetScrollToTopVirtualDom.ts'
2492
2691
 
2493
2692
  const getChildCount = (additionalDetails, scrollToTopEnabled) => {
2494
2693
  let count = 1;
2495
2694
  if (additionalDetails) {
2496
2695
  count++;
2497
2696
  }
2498
- if (scrollToTopEnabled) {
2499
- count++;
2500
- }
2697
+ // if (scrollToTopEnabled) {
2698
+ // count++
2699
+ // }
2501
2700
  return count;
2502
2701
  };
2503
2702
  const getDetailsVirtualDom = (sanitizedReadmeHtml, displaySize, extensionId, extensionVersion, width, extensionUri, scrollToTopButtonEnabled, categories$1, resources$1, showAdditionalDetailsBreakpoint // new parameter, no default
@@ -2509,13 +2708,15 @@ const getDetailsVirtualDom = (sanitizedReadmeHtml, displaySize, extensionId, ext
2509
2708
  const thirdHeading = categories();
2510
2709
  const fourthHeading = resources();
2511
2710
  const showAdditionalDetails = width > showAdditionalDetailsBreakpoint;
2512
- const childCount = getChildCount(showAdditionalDetails, scrollToTopButtonEnabled);
2711
+ const childCount = getChildCount(showAdditionalDetails);
2513
2712
  const dom = [{
2514
2713
  type: VirtualDomElements.Div,
2515
2714
  className: ExtensionDetailPanel,
2516
2715
  childCount: childCount,
2517
- role: Panel
2518
- }, ...getScrollToTopVirtualDom(scrollToTopButtonEnabled), ...sanitizedReadmeHtml, ...getAdditionalDetailsVirtualDom(showAdditionalDetails, firstHeading, entries, secondHeading, secondEntries, thirdHeading, categories$1, fourthHeading, resources$1)];
2716
+ role: AriaRoles.Panel
2717
+ },
2718
+ // ...GetScrollToTopVirtualDom.getScrollToTopVirtualDom(scrollToTopButtonEnabled),
2719
+ ...sanitizedReadmeHtml, ...getAdditionalDetailsVirtualDom(showAdditionalDetails, firstHeading, entries, secondHeading, secondEntries, thirdHeading, categories$1, fourthHeading, resources$1)];
2519
2720
  return dom;
2520
2721
  };
2521
2722
 
@@ -2802,13 +3003,13 @@ const getFeaturesVirtualDom = (features, themesDom, selectedFeature, commands, j
2802
3003
  const none$1 = none();
2803
3004
  return [{
2804
3005
  type: VirtualDomElements.Div,
2805
- className: Features,
3006
+ className: Features$1,
2806
3007
  childCount: 3
2807
3008
  }, text(none$1)];
2808
3009
  }
2809
3010
  return [{
2810
3011
  type: VirtualDomElements.Div,
2811
- className: Features,
3012
+ className: Features$1,
2812
3013
  childCount: 3
2813
3014
  }, ...getFeatureListVirtualDom(features), {
2814
3015
  type: VirtualDomElements.Div,
@@ -2817,14 +3018,14 @@ const getFeaturesVirtualDom = (features, themesDom, selectedFeature, commands, j
2817
3018
  }, ...getFeatureContentVirtualDom(themesDom, selectedFeature, commands, jsonValidation, settings, webViews)];
2818
3019
  };
2819
3020
 
2820
- const getExtensionDetailContentVirtualDom = (sanitizedReadmeHtml, themesDom, selectedTab, features, displaySize, extensionId, extensionVersion, selectedFeature, width, scrollToTopButtonEnabled, categories, resources, breakpoint, commands, jsonValidation, settings, webViews, extensionUri) => {
3021
+ const getExtensionDetailContentVirtualDom = (sanitizedReadmeHtml, themesDom, selectedTab, features, displaySize, extensionId, extensionVersion, selectedFeature, width, scrollToTopButtonEnabled, categories, resources, breakpoint, commands, jsonValidation, settings, webViews, extensionUri, changelogDom) => {
2821
3022
  switch (selectedTab) {
2822
3023
  case Details:
2823
3024
  return getDetailsVirtualDom(sanitizedReadmeHtml, displaySize, extensionId, extensionVersion, width, extensionUri, scrollToTopButtonEnabled, categories, resources, breakpoint);
2824
- case Features$1:
3025
+ case Features:
2825
3026
  return getFeaturesVirtualDom(features, themesDom, selectedFeature, commands, jsonValidation, settings, webViews);
2826
- case Changelog$1:
2827
- return getChangelogVirtualDom();
3027
+ case Changelog:
3028
+ return getChangelogVirtualDom(changelogDom);
2828
3029
  default:
2829
3030
  return [];
2830
3031
  }
@@ -2929,12 +3130,12 @@ const getTabs = selectedTab => {
2929
3130
  selected: selectedTab === Details
2930
3131
  }, {
2931
3132
  label: features(),
2932
- name: Features$1,
2933
- selected: selectedTab === Features$1
3133
+ name: Features,
3134
+ selected: selectedTab === Features
2934
3135
  }, {
2935
3136
  label: changelog(),
2936
- name: Changelog$1,
2937
- selected: selectedTab === Changelog$1
3137
+ name: Changelog,
3138
+ selected: selectedTab === Changelog
2938
3139
  }];
2939
3140
  return tabs;
2940
3141
  };
@@ -2951,7 +3152,7 @@ const getTabVirtualDom = tab => {
2951
3152
  const ariaSelected = selected;
2952
3153
  return [{
2953
3154
  type: VirtualDomElements.Button,
2954
- role: Tab,
3155
+ role: AriaRoles.Tab,
2955
3156
  name,
2956
3157
  className,
2957
3158
  childCount: 1,
@@ -2965,7 +3166,7 @@ const getTabsVirtualDom = tabs => {
2965
3166
  type: VirtualDomElements.Div,
2966
3167
  className: ExtensionDetailTabs,
2967
3168
  childCount: tabs.length,
2968
- role: TabList,
3169
+ role: AriaRoles.TabList,
2969
3170
  onClick: HandleTabsClick,
2970
3171
  tabIndex: 0
2971
3172
  }, ...tabs.flatMap(getTabVirtualDom)];
@@ -2973,12 +3174,12 @@ const getTabsVirtualDom = tabs => {
2973
3174
 
2974
3175
  const getClassNames = size => {
2975
3176
  switch (size) {
2976
- case Small$1:
2977
- return Small;
2978
- case Normal$1:
2979
- return Normal;
2980
- case Large$1:
2981
- return Large;
3177
+ case Small:
3178
+ return Small$1;
3179
+ case Normal:
3180
+ return Normal$1;
3181
+ case Large:
3182
+ return Large$1;
2982
3183
  default:
2983
3184
  return '';
2984
3185
  }
@@ -3014,7 +3215,8 @@ const getExtensionDetailVirtualDom = (newState, selectedTab) => {
3014
3215
  jsonValidation,
3015
3216
  settings,
3016
3217
  webViews,
3017
- extension
3218
+ extension,
3219
+ changelogVirtualDom
3018
3220
  } = newState;
3019
3221
  const extensionUri = extension.uri || extension.path || '';
3020
3222
  const width = newState?.width || 500;
@@ -3026,7 +3228,7 @@ const getExtensionDetailVirtualDom = (newState, selectedTab) => {
3026
3228
  type: VirtualDomElements.Div,
3027
3229
  className: mergeClassNames(Viewlet, ExtensionDetail, sizeClass),
3028
3230
  childCount: 3
3029
- }, ...getExtensionDetailHeaderVirtualDom(name, iconSrc, description, badge, buttonDefs, settingsButtonEnabled), ...getTabsVirtualDom(tabs), ...getExtensionDetailContentVirtualDom(detailsVirtualDom, themesMarkdownDom, selectedTab, features, displaySize, extensionId, extensionVersion, selectedFeature, width, scrollToTopButtonEnabled, categories, resources, showAdditionalDetailsBreakpoint, commands, jsonValidation, settings, webViews, extensionUri)];
3231
+ }, ...getExtensionDetailHeaderVirtualDom(name, iconSrc, description, badge, buttonDefs, settingsButtonEnabled), ...getTabsVirtualDom(tabs), ...getExtensionDetailContentVirtualDom(detailsVirtualDom, themesMarkdownDom, selectedTab, features, displaySize, extensionId, extensionVersion, selectedFeature, width, scrollToTopButtonEnabled, categories, resources, showAdditionalDetailsBreakpoint, commands, jsonValidation, settings, webViews, extensionUri, changelogVirtualDom)];
3030
3232
  return dom;
3031
3233
  };
3032
3234
 
@@ -3039,12 +3241,18 @@ const renderFocus = (oldState, newState) => {
3039
3241
  return ['Viewlet.focusElementByName', ''];
3040
3242
  };
3041
3243
 
3244
+ const renderScrollTop = (oldState, newState) => {
3245
+ return ['Viewlet.setScrollTop', '', newState.readmeScrollTop];
3246
+ };
3247
+
3042
3248
  const getRenderer = diffType => {
3043
3249
  switch (diffType) {
3044
3250
  case RenderItems:
3045
3251
  return renderDom;
3046
3252
  case RenderFocus:
3047
3253
  return renderFocus;
3254
+ case RenderScrollTop:
3255
+ return renderScrollTop;
3048
3256
  default:
3049
3257
  throw new Error('unknown renderer');
3050
3258
  }
@@ -3064,7 +3272,7 @@ const render2 = (uid, diffResult) => {
3064
3272
  oldState,
3065
3273
  newState
3066
3274
  } = get$1(uid);
3067
- set$1(uid, oldState, newState);
3275
+ set$2(uid, oldState, newState);
3068
3276
  const commands = applyRender(oldState, newState, diffResult);
3069
3277
  return commands;
3070
3278
  };
@@ -3131,6 +3339,7 @@ const saveState = uid => {
3131
3339
  };
3132
3340
 
3133
3341
  const commandMap = {
3342
+ 'ExtensionDetail.copyImage': wrapCommand(copyImage),
3134
3343
  'ExtensionDetail.create': create$1,
3135
3344
  'ExtensionDetail.diff2': diff2,
3136
3345
  'ExtensionDetail.dispose': dispose,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/extension-detail-view",
3
- "version": "3.35.0",
3
+ "version": "3.37.0",
4
4
  "description": "Extension Detail View Worker",
5
5
  "license": "MIT",
6
6
  "author": "Lvce Editor",