@lvce-editor/extension-host-worker 8.34.0 → 8.35.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.
- package/dist/extension-api/index.js +153 -2
- package/dist/extension-api/parts/ExtensionApiCommandMap/ExtensionApiCommandMap.js +2 -0
- package/dist/extension-api/parts/ViewRegistry/ViewRegistry.js +153 -2
- package/extension-api/dist/index.d.ts +1 -1
- package/extension-api/dist/parts/CommandMap/CommandMap.d.ts +1 -0
- package/extension-api/dist/parts/ExtensionApiCommandMap/ExtensionApiCommandMap.d.ts +1 -0
- package/extension-api/dist/parts/ExtensionApiCommandMap/ExtensionApiCommandMap.js +2 -1
- package/extension-api/dist/parts/ExtensionApiWorkerCommandMap/ExtensionApiWorkerCommandMap.d.ts +1 -0
- package/extension-api/dist/parts/View/View.d.ts +22 -0
- package/extension-api/dist/parts/ViewRegistry/ViewRegistry.d.ts +2 -1
- package/extension-api/dist/parts/ViewRegistry/ViewRegistry.js +153 -2
- package/extension-api/package.json +1 -1
- package/extension-api/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -2393,6 +2393,50 @@ var diffTree = (oldNodes, newNodes) => {
|
|
|
2393
2393
|
var views = /* @__PURE__ */ Object.create(null);
|
|
2394
2394
|
var instances = /* @__PURE__ */ Object.create(null);
|
|
2395
2395
|
var renderedDoms = /* @__PURE__ */ Object.create(null);
|
|
2396
|
+
var contexts = /* @__PURE__ */ Object.create(null);
|
|
2397
|
+
var contextViewIds = /* @__PURE__ */ Object.create(null);
|
|
2398
|
+
var assertBoolean = (value, message) => {
|
|
2399
|
+
if (value !== void 0 && typeof value !== "boolean") {
|
|
2400
|
+
throw new ExtensionApiError(message);
|
|
2401
|
+
}
|
|
2402
|
+
};
|
|
2403
|
+
var assertNumber = (value, message) => {
|
|
2404
|
+
if (typeof value !== "number") {
|
|
2405
|
+
throw new ExtensionApiError(message);
|
|
2406
|
+
}
|
|
2407
|
+
};
|
|
2408
|
+
var assertString = (value, message) => {
|
|
2409
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
2410
|
+
throw new ExtensionApiError(message);
|
|
2411
|
+
}
|
|
2412
|
+
};
|
|
2413
|
+
var assertEventListener = (viewId, listener, index) => {
|
|
2414
|
+
if (!listener || typeof listener !== "object") {
|
|
2415
|
+
throw new ExtensionApiError(`view ${viewId} event listener ${index} must be an object`);
|
|
2416
|
+
}
|
|
2417
|
+
const eventListener = listener;
|
|
2418
|
+
if (typeof eventListener.name !== "string" && typeof eventListener.name !== "number") {
|
|
2419
|
+
throw new ExtensionApiError(`view ${viewId} event listener ${index} is missing name`);
|
|
2420
|
+
}
|
|
2421
|
+
if (!Array.isArray(eventListener.params) || eventListener.params.some((param) => typeof param !== "string")) {
|
|
2422
|
+
throw new ExtensionApiError(`view ${viewId} event listener ${index} is missing params`);
|
|
2423
|
+
}
|
|
2424
|
+
assertBoolean(eventListener.capture, `view ${viewId} event listener ${index} has invalid capture`);
|
|
2425
|
+
assertBoolean(eventListener.passive, `view ${viewId} event listener ${index} has invalid passive`);
|
|
2426
|
+
assertBoolean(eventListener.preventDefault, `view ${viewId} event listener ${index} has invalid preventDefault`);
|
|
2427
|
+
assertBoolean(eventListener.stopPropagation, `view ${viewId} event listener ${index} has invalid stopPropagation`);
|
|
2428
|
+
};
|
|
2429
|
+
var assertEventListeners = (view) => {
|
|
2430
|
+
if (view.eventListeners === void 0) {
|
|
2431
|
+
return;
|
|
2432
|
+
}
|
|
2433
|
+
if (!Array.isArray(view.eventListeners)) {
|
|
2434
|
+
throw new ExtensionApiError(`view ${view.id} eventListeners must be an array`);
|
|
2435
|
+
}
|
|
2436
|
+
for (const [index, listener] of view.eventListeners.entries()) {
|
|
2437
|
+
assertEventListener(view.id, listener, index);
|
|
2438
|
+
}
|
|
2439
|
+
};
|
|
2396
2440
|
var assertView = (view) => {
|
|
2397
2441
|
if (!view) {
|
|
2398
2442
|
throw new ExtensionApiError("view is not defined");
|
|
@@ -2406,11 +2450,13 @@ var assertView = (view) => {
|
|
|
2406
2450
|
if (view.id in views) {
|
|
2407
2451
|
throw new ExtensionApiError(`view ${view.id} is already registered`);
|
|
2408
2452
|
}
|
|
2453
|
+
assertEventListeners(view);
|
|
2409
2454
|
};
|
|
2410
2455
|
var toRegisteredView = (view) => {
|
|
2411
2456
|
const displayName = view.displayName || view.name || view.title;
|
|
2412
2457
|
const registeredView = {
|
|
2413
2458
|
displayName,
|
|
2459
|
+
...view.eventListeners && { eventListeners: view.eventListeners },
|
|
2414
2460
|
icon: view.icon,
|
|
2415
2461
|
id: view.id,
|
|
2416
2462
|
name: view.name,
|
|
@@ -2462,6 +2508,34 @@ var renderDom = async (instance) => {
|
|
|
2462
2508
|
}
|
|
2463
2509
|
return dom;
|
|
2464
2510
|
};
|
|
2511
|
+
var normalizeMenuEntry = (entry, index) => {
|
|
2512
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
|
|
2513
|
+
throw new ExtensionApiError(`menu entry ${index} must be an object`);
|
|
2514
|
+
}
|
|
2515
|
+
const menuEntry = entry;
|
|
2516
|
+
assertString(menuEntry.id, `menu entry ${index} is missing id`);
|
|
2517
|
+
assertString(menuEntry.label, `menu entry ${index} is missing label`);
|
|
2518
|
+
assertString(menuEntry.command, `menu entry ${index} is missing command`);
|
|
2519
|
+
if (menuEntry.flags !== void 0 && typeof menuEntry.flags !== "number") {
|
|
2520
|
+
throw new ExtensionApiError(`menu entry ${index} has invalid flags`);
|
|
2521
|
+
}
|
|
2522
|
+
if (menuEntry.args !== void 0 && !Array.isArray(menuEntry.args)) {
|
|
2523
|
+
throw new ExtensionApiError(`menu entry ${index} has invalid args`);
|
|
2524
|
+
}
|
|
2525
|
+
return {
|
|
2526
|
+
command: menuEntry.command,
|
|
2527
|
+
flags: menuEntry.flags ?? 0,
|
|
2528
|
+
id: menuEntry.id,
|
|
2529
|
+
label: menuEntry.label,
|
|
2530
|
+
...menuEntry.args && { args: menuEntry.args }
|
|
2531
|
+
};
|
|
2532
|
+
};
|
|
2533
|
+
var normalizeMenuEntries = (entries) => {
|
|
2534
|
+
if (!Array.isArray(entries)) {
|
|
2535
|
+
throw new ExtensionApiError("view menu entries must be an array");
|
|
2536
|
+
}
|
|
2537
|
+
return entries.map(normalizeMenuEntry);
|
|
2538
|
+
};
|
|
2465
2539
|
var renderPatches = async (uid, instance) => {
|
|
2466
2540
|
const oldDom = renderedDoms[uid] || [];
|
|
2467
2541
|
const newDom = await renderDom(instance);
|
|
@@ -2472,6 +2546,54 @@ var renderPatches = async (uid, instance) => {
|
|
|
2472
2546
|
type: "setPatches"
|
|
2473
2547
|
};
|
|
2474
2548
|
};
|
|
2549
|
+
var normalizeContext = (context) => {
|
|
2550
|
+
if (!context || typeof context !== "object" || Array.isArray(context)) {
|
|
2551
|
+
return {};
|
|
2552
|
+
}
|
|
2553
|
+
const normalized = {};
|
|
2554
|
+
for (const [key, value] of Object.entries(context)) {
|
|
2555
|
+
if (typeof value === "boolean") {
|
|
2556
|
+
normalized[key] = value;
|
|
2557
|
+
}
|
|
2558
|
+
}
|
|
2559
|
+
return normalized;
|
|
2560
|
+
};
|
|
2561
|
+
var isSameContext = (oldContext, newContext) => {
|
|
2562
|
+
const oldKeys = Object.keys(oldContext);
|
|
2563
|
+
const newKeys = Object.keys(newContext);
|
|
2564
|
+
if (oldKeys.length !== newKeys.length) {
|
|
2565
|
+
return false;
|
|
2566
|
+
}
|
|
2567
|
+
for (const key of oldKeys) {
|
|
2568
|
+
if (oldContext[key] !== newContext[key]) {
|
|
2569
|
+
return false;
|
|
2570
|
+
}
|
|
2571
|
+
}
|
|
2572
|
+
return true;
|
|
2573
|
+
};
|
|
2574
|
+
var maybeNotifyContextChanged = async (uid, viewId, instance) => {
|
|
2575
|
+
if (typeof instance.getContext !== "function") {
|
|
2576
|
+
return;
|
|
2577
|
+
}
|
|
2578
|
+
const oldContext = contexts[uid] || {};
|
|
2579
|
+
const newContext = normalizeContext(instance.getContext());
|
|
2580
|
+
if (isSameContext(oldContext, newContext)) {
|
|
2581
|
+
return;
|
|
2582
|
+
}
|
|
2583
|
+
if (Object.keys(newContext).length === 0) {
|
|
2584
|
+
delete contexts[uid];
|
|
2585
|
+
} else {
|
|
2586
|
+
contexts[uid] = newContext;
|
|
2587
|
+
}
|
|
2588
|
+
await ExtensionManagementWorker_exports.invoke("Extensions.handleViewContextChange", uid, viewId, newContext);
|
|
2589
|
+
};
|
|
2590
|
+
var maybeClearContext = async (uid, viewId) => {
|
|
2591
|
+
if (!contexts[uid]) {
|
|
2592
|
+
return;
|
|
2593
|
+
}
|
|
2594
|
+
delete contexts[uid];
|
|
2595
|
+
await ExtensionManagementWorker_exports.invoke("Extensions.handleViewContextChange", uid, viewId, {});
|
|
2596
|
+
};
|
|
2475
2597
|
var createViewInstance = async (viewId, uid, context) => {
|
|
2476
2598
|
const view = views[viewId];
|
|
2477
2599
|
if (!view) {
|
|
@@ -2485,13 +2607,21 @@ var createViewInstance = async (viewId, uid, context) => {
|
|
|
2485
2607
|
requestRerender() {
|
|
2486
2608
|
return ExtensionManagementWorker_exports.invoke("Extensions.requestViewRerender", uid);
|
|
2487
2609
|
},
|
|
2610
|
+
showContextMenu(menuId, x, y) {
|
|
2611
|
+
assertString(menuId, "menuId must be a string");
|
|
2612
|
+
assertNumber(x, "x must be a number");
|
|
2613
|
+
assertNumber(y, "y must be a number");
|
|
2614
|
+
return ExtensionManagementWorker_exports.invoke("Extensions.showViewContextMenu", uid, viewId, menuId, x, y);
|
|
2615
|
+
},
|
|
2488
2616
|
uid,
|
|
2489
2617
|
viewId
|
|
2490
2618
|
});
|
|
2491
2619
|
assertVirtualDomViewInstance(viewId, instance);
|
|
2492
2620
|
instances[uid] = instance;
|
|
2621
|
+
contextViewIds[uid] = viewId;
|
|
2493
2622
|
const dom = await renderDom(instance);
|
|
2494
2623
|
renderedDoms[uid] = dom;
|
|
2624
|
+
await maybeNotifyContextChanged(uid, viewId, instance);
|
|
2495
2625
|
return {
|
|
2496
2626
|
dom,
|
|
2497
2627
|
type: "setDom"
|
|
@@ -2502,19 +2632,25 @@ var dispatchViewEvent = async (uid, event) => {
|
|
|
2502
2632
|
if (typeof instance.handleEvent === "function") {
|
|
2503
2633
|
await instance.handleEvent(event);
|
|
2504
2634
|
}
|
|
2505
|
-
|
|
2635
|
+
const result = await renderPatches(uid, instance);
|
|
2636
|
+
await maybeNotifyContextChanged(uid, contextViewIds[uid], instance);
|
|
2637
|
+
return result;
|
|
2506
2638
|
};
|
|
2507
2639
|
var renderViewInstance = async (uid) => {
|
|
2508
2640
|
const instance = getVirtualDomInstance(uid);
|
|
2509
|
-
|
|
2641
|
+
const result = await renderPatches(uid, instance);
|
|
2642
|
+
await maybeNotifyContextChanged(uid, contextViewIds[uid], instance);
|
|
2643
|
+
return result;
|
|
2510
2644
|
};
|
|
2511
2645
|
var disposeViewInstance = async (uid) => {
|
|
2512
2646
|
const instance = instances[uid];
|
|
2513
2647
|
if (instance && typeof instance.dispose === "function") {
|
|
2514
2648
|
await instance.dispose();
|
|
2515
2649
|
}
|
|
2650
|
+
await maybeClearContext(uid, contextViewIds[uid]);
|
|
2516
2651
|
delete instances[uid];
|
|
2517
2652
|
delete renderedDoms[uid];
|
|
2653
|
+
delete contextViewIds[uid];
|
|
2518
2654
|
};
|
|
2519
2655
|
var saveViewInstanceState = async (uid) => {
|
|
2520
2656
|
const instance = getVirtualDomInstance(uid);
|
|
@@ -2523,6 +2659,14 @@ var saveViewInstanceState = async (uid) => {
|
|
|
2523
2659
|
}
|
|
2524
2660
|
return instance.saveState();
|
|
2525
2661
|
};
|
|
2662
|
+
var getViewMenuEntries = async (uid, menuId) => {
|
|
2663
|
+
assertString(menuId, "menuId must be a string");
|
|
2664
|
+
const instance = getVirtualDomInstance(uid);
|
|
2665
|
+
if (typeof instance.getMenuEntries !== "function") {
|
|
2666
|
+
return [];
|
|
2667
|
+
}
|
|
2668
|
+
return normalizeMenuEntries(await instance.getMenuEntries(menuId));
|
|
2669
|
+
};
|
|
2526
2670
|
var getViewRegistrySnapshot = () => {
|
|
2527
2671
|
return {
|
|
2528
2672
|
views: Object.values(views).map(toRegisteredView)
|
|
@@ -2538,6 +2682,12 @@ var resetViewRegistry = () => {
|
|
|
2538
2682
|
for (const uid of Object.keys(renderedDoms)) {
|
|
2539
2683
|
delete renderedDoms[Number(uid)];
|
|
2540
2684
|
}
|
|
2685
|
+
for (const uid of Object.keys(contexts)) {
|
|
2686
|
+
delete contexts[Number(uid)];
|
|
2687
|
+
}
|
|
2688
|
+
for (const uid of Object.keys(contextViewIds)) {
|
|
2689
|
+
delete contextViewIds[Number(uid)];
|
|
2690
|
+
}
|
|
2541
2691
|
};
|
|
2542
2692
|
|
|
2543
2693
|
// packages/extension-api/src/parts/ExtensionApiCommandMap/ExtensionApiCommandMap.ts
|
|
@@ -2570,6 +2720,7 @@ var commandMap = {
|
|
|
2570
2720
|
"ExtensionApi.getOutputChannelRegistrySnapshot": getOutputChannelRegistrySnapshot,
|
|
2571
2721
|
"ExtensionApi.getSourceControlProviderRegistrySnapshot": getSourceControlProviderRegistrySnapshot,
|
|
2572
2722
|
"ExtensionApi.getStatusBarItems": getStatusBarItems,
|
|
2723
|
+
"ExtensionApi.getViewMenuEntries": getViewMenuEntries,
|
|
2573
2724
|
"ExtensionApi.getViewRegistrySnapshot": getViewRegistrySnapshot,
|
|
2574
2725
|
"ExtensionApi.renderViewInstance": renderViewInstance,
|
|
2575
2726
|
"ExtensionApi.saveViewInstanceState": saveViewInstanceState
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
dispatchViewEvent,
|
|
24
24
|
disposeViewInstance,
|
|
25
25
|
executeViewProvider,
|
|
26
|
+
getViewMenuEntries,
|
|
26
27
|
getViewRegistrySnapshot,
|
|
27
28
|
renderViewInstance,
|
|
28
29
|
saveViewInstanceState
|
|
@@ -56,6 +57,7 @@ const commandMap = {
|
|
|
56
57
|
"ExtensionApi.getOutputChannelRegistrySnapshot": getOutputChannelRegistrySnapshot,
|
|
57
58
|
"ExtensionApi.getSourceControlProviderRegistrySnapshot": getSourceControlProviderRegistrySnapshot,
|
|
58
59
|
"ExtensionApi.getStatusBarItems": getStatusBarItems,
|
|
60
|
+
"ExtensionApi.getViewMenuEntries": getViewMenuEntries,
|
|
59
61
|
"ExtensionApi.getViewRegistrySnapshot": getViewRegistrySnapshot,
|
|
60
62
|
"ExtensionApi.renderViewInstance": renderViewInstance,
|
|
61
63
|
"ExtensionApi.saveViewInstanceState": saveViewInstanceState
|
|
@@ -4,6 +4,50 @@ import { ExtensionApiError } from "../ExtensionApiError/ExtensionApiError.js";
|
|
|
4
4
|
const views = /* @__PURE__ */ Object.create(null);
|
|
5
5
|
const instances = /* @__PURE__ */ Object.create(null);
|
|
6
6
|
const renderedDoms = /* @__PURE__ */ Object.create(null);
|
|
7
|
+
const contexts = /* @__PURE__ */ Object.create(null);
|
|
8
|
+
const contextViewIds = /* @__PURE__ */ Object.create(null);
|
|
9
|
+
const assertBoolean = (value, message) => {
|
|
10
|
+
if (value !== void 0 && typeof value !== "boolean") {
|
|
11
|
+
throw new ExtensionApiError(message);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
const assertNumber = (value, message) => {
|
|
15
|
+
if (typeof value !== "number") {
|
|
16
|
+
throw new ExtensionApiError(message);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
const assertString = (value, message) => {
|
|
20
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
21
|
+
throw new ExtensionApiError(message);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const assertEventListener = (viewId, listener, index) => {
|
|
25
|
+
if (!listener || typeof listener !== "object") {
|
|
26
|
+
throw new ExtensionApiError(`view ${viewId} event listener ${index} must be an object`);
|
|
27
|
+
}
|
|
28
|
+
const eventListener = listener;
|
|
29
|
+
if (typeof eventListener.name !== "string" && typeof eventListener.name !== "number") {
|
|
30
|
+
throw new ExtensionApiError(`view ${viewId} event listener ${index} is missing name`);
|
|
31
|
+
}
|
|
32
|
+
if (!Array.isArray(eventListener.params) || eventListener.params.some((param) => typeof param !== "string")) {
|
|
33
|
+
throw new ExtensionApiError(`view ${viewId} event listener ${index} is missing params`);
|
|
34
|
+
}
|
|
35
|
+
assertBoolean(eventListener.capture, `view ${viewId} event listener ${index} has invalid capture`);
|
|
36
|
+
assertBoolean(eventListener.passive, `view ${viewId} event listener ${index} has invalid passive`);
|
|
37
|
+
assertBoolean(eventListener.preventDefault, `view ${viewId} event listener ${index} has invalid preventDefault`);
|
|
38
|
+
assertBoolean(eventListener.stopPropagation, `view ${viewId} event listener ${index} has invalid stopPropagation`);
|
|
39
|
+
};
|
|
40
|
+
const assertEventListeners = (view) => {
|
|
41
|
+
if (view.eventListeners === void 0) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (!Array.isArray(view.eventListeners)) {
|
|
45
|
+
throw new ExtensionApiError(`view ${view.id} eventListeners must be an array`);
|
|
46
|
+
}
|
|
47
|
+
for (const [index, listener] of view.eventListeners.entries()) {
|
|
48
|
+
assertEventListener(view.id, listener, index);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
7
51
|
const assertView = (view) => {
|
|
8
52
|
if (!view) {
|
|
9
53
|
throw new ExtensionApiError("view is not defined");
|
|
@@ -17,11 +61,13 @@ const assertView = (view) => {
|
|
|
17
61
|
if (view.id in views) {
|
|
18
62
|
throw new ExtensionApiError(`view ${view.id} is already registered`);
|
|
19
63
|
}
|
|
64
|
+
assertEventListeners(view);
|
|
20
65
|
};
|
|
21
66
|
const toRegisteredView = (view) => {
|
|
22
67
|
const displayName = view.displayName || view.name || view.title;
|
|
23
68
|
const registeredView = {
|
|
24
69
|
displayName,
|
|
70
|
+
...view.eventListeners && { eventListeners: view.eventListeners },
|
|
25
71
|
icon: view.icon,
|
|
26
72
|
id: view.id,
|
|
27
73
|
name: view.name,
|
|
@@ -73,6 +119,34 @@ const renderDom = async (instance) => {
|
|
|
73
119
|
}
|
|
74
120
|
return dom;
|
|
75
121
|
};
|
|
122
|
+
const normalizeMenuEntry = (entry, index) => {
|
|
123
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
|
|
124
|
+
throw new ExtensionApiError(`menu entry ${index} must be an object`);
|
|
125
|
+
}
|
|
126
|
+
const menuEntry = entry;
|
|
127
|
+
assertString(menuEntry.id, `menu entry ${index} is missing id`);
|
|
128
|
+
assertString(menuEntry.label, `menu entry ${index} is missing label`);
|
|
129
|
+
assertString(menuEntry.command, `menu entry ${index} is missing command`);
|
|
130
|
+
if (menuEntry.flags !== void 0 && typeof menuEntry.flags !== "number") {
|
|
131
|
+
throw new ExtensionApiError(`menu entry ${index} has invalid flags`);
|
|
132
|
+
}
|
|
133
|
+
if (menuEntry.args !== void 0 && !Array.isArray(menuEntry.args)) {
|
|
134
|
+
throw new ExtensionApiError(`menu entry ${index} has invalid args`);
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
command: menuEntry.command,
|
|
138
|
+
flags: menuEntry.flags ?? 0,
|
|
139
|
+
id: menuEntry.id,
|
|
140
|
+
label: menuEntry.label,
|
|
141
|
+
...menuEntry.args && { args: menuEntry.args }
|
|
142
|
+
};
|
|
143
|
+
};
|
|
144
|
+
const normalizeMenuEntries = (entries) => {
|
|
145
|
+
if (!Array.isArray(entries)) {
|
|
146
|
+
throw new ExtensionApiError("view menu entries must be an array");
|
|
147
|
+
}
|
|
148
|
+
return entries.map(normalizeMenuEntry);
|
|
149
|
+
};
|
|
76
150
|
const renderPatches = async (uid, instance) => {
|
|
77
151
|
const oldDom = renderedDoms[uid] || [];
|
|
78
152
|
const newDom = await renderDom(instance);
|
|
@@ -83,6 +157,54 @@ const renderPatches = async (uid, instance) => {
|
|
|
83
157
|
type: "setPatches"
|
|
84
158
|
};
|
|
85
159
|
};
|
|
160
|
+
const normalizeContext = (context) => {
|
|
161
|
+
if (!context || typeof context !== "object" || Array.isArray(context)) {
|
|
162
|
+
return {};
|
|
163
|
+
}
|
|
164
|
+
const normalized = {};
|
|
165
|
+
for (const [key, value] of Object.entries(context)) {
|
|
166
|
+
if (typeof value === "boolean") {
|
|
167
|
+
normalized[key] = value;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return normalized;
|
|
171
|
+
};
|
|
172
|
+
const isSameContext = (oldContext, newContext) => {
|
|
173
|
+
const oldKeys = Object.keys(oldContext);
|
|
174
|
+
const newKeys = Object.keys(newContext);
|
|
175
|
+
if (oldKeys.length !== newKeys.length) {
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
for (const key of oldKeys) {
|
|
179
|
+
if (oldContext[key] !== newContext[key]) {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return true;
|
|
184
|
+
};
|
|
185
|
+
const maybeNotifyContextChanged = async (uid, viewId, instance) => {
|
|
186
|
+
if (typeof instance.getContext !== "function") {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
const oldContext = contexts[uid] || {};
|
|
190
|
+
const newContext = normalizeContext(instance.getContext());
|
|
191
|
+
if (isSameContext(oldContext, newContext)) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
if (Object.keys(newContext).length === 0) {
|
|
195
|
+
delete contexts[uid];
|
|
196
|
+
} else {
|
|
197
|
+
contexts[uid] = newContext;
|
|
198
|
+
}
|
|
199
|
+
await ExtensionManagementWorker.invoke("Extensions.handleViewContextChange", uid, viewId, newContext);
|
|
200
|
+
};
|
|
201
|
+
const maybeClearContext = async (uid, viewId) => {
|
|
202
|
+
if (!contexts[uid]) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
delete contexts[uid];
|
|
206
|
+
await ExtensionManagementWorker.invoke("Extensions.handleViewContextChange", uid, viewId, {});
|
|
207
|
+
};
|
|
86
208
|
const createViewInstance = async (viewId, uid, context) => {
|
|
87
209
|
const view = views[viewId];
|
|
88
210
|
if (!view) {
|
|
@@ -96,13 +218,21 @@ const createViewInstance = async (viewId, uid, context) => {
|
|
|
96
218
|
requestRerender() {
|
|
97
219
|
return ExtensionManagementWorker.invoke("Extensions.requestViewRerender", uid);
|
|
98
220
|
},
|
|
221
|
+
showContextMenu(menuId, x, y) {
|
|
222
|
+
assertString(menuId, "menuId must be a string");
|
|
223
|
+
assertNumber(x, "x must be a number");
|
|
224
|
+
assertNumber(y, "y must be a number");
|
|
225
|
+
return ExtensionManagementWorker.invoke("Extensions.showViewContextMenu", uid, viewId, menuId, x, y);
|
|
226
|
+
},
|
|
99
227
|
uid,
|
|
100
228
|
viewId
|
|
101
229
|
});
|
|
102
230
|
assertVirtualDomViewInstance(viewId, instance);
|
|
103
231
|
instances[uid] = instance;
|
|
232
|
+
contextViewIds[uid] = viewId;
|
|
104
233
|
const dom = await renderDom(instance);
|
|
105
234
|
renderedDoms[uid] = dom;
|
|
235
|
+
await maybeNotifyContextChanged(uid, viewId, instance);
|
|
106
236
|
return {
|
|
107
237
|
dom,
|
|
108
238
|
type: "setDom"
|
|
@@ -113,19 +243,25 @@ const dispatchViewEvent = async (uid, event) => {
|
|
|
113
243
|
if (typeof instance.handleEvent === "function") {
|
|
114
244
|
await instance.handleEvent(event);
|
|
115
245
|
}
|
|
116
|
-
|
|
246
|
+
const result = await renderPatches(uid, instance);
|
|
247
|
+
await maybeNotifyContextChanged(uid, contextViewIds[uid], instance);
|
|
248
|
+
return result;
|
|
117
249
|
};
|
|
118
250
|
const renderViewInstance = async (uid) => {
|
|
119
251
|
const instance = getVirtualDomInstance(uid);
|
|
120
|
-
|
|
252
|
+
const result = await renderPatches(uid, instance);
|
|
253
|
+
await maybeNotifyContextChanged(uid, contextViewIds[uid], instance);
|
|
254
|
+
return result;
|
|
121
255
|
};
|
|
122
256
|
const disposeViewInstance = async (uid) => {
|
|
123
257
|
const instance = instances[uid];
|
|
124
258
|
if (instance && typeof instance.dispose === "function") {
|
|
125
259
|
await instance.dispose();
|
|
126
260
|
}
|
|
261
|
+
await maybeClearContext(uid, contextViewIds[uid]);
|
|
127
262
|
delete instances[uid];
|
|
128
263
|
delete renderedDoms[uid];
|
|
264
|
+
delete contextViewIds[uid];
|
|
129
265
|
};
|
|
130
266
|
const saveViewInstanceState = async (uid) => {
|
|
131
267
|
const instance = getVirtualDomInstance(uid);
|
|
@@ -134,6 +270,14 @@ const saveViewInstanceState = async (uid) => {
|
|
|
134
270
|
}
|
|
135
271
|
return instance.saveState();
|
|
136
272
|
};
|
|
273
|
+
const getViewMenuEntries = async (uid, menuId) => {
|
|
274
|
+
assertString(menuId, "menuId must be a string");
|
|
275
|
+
const instance = getVirtualDomInstance(uid);
|
|
276
|
+
if (typeof instance.getMenuEntries !== "function") {
|
|
277
|
+
return [];
|
|
278
|
+
}
|
|
279
|
+
return normalizeMenuEntries(await instance.getMenuEntries(menuId));
|
|
280
|
+
};
|
|
137
281
|
const getViewRegistrySnapshot = () => {
|
|
138
282
|
return {
|
|
139
283
|
views: Object.values(views).map(toRegisteredView)
|
|
@@ -149,12 +293,19 @@ const resetViewRegistry = () => {
|
|
|
149
293
|
for (const uid of Object.keys(renderedDoms)) {
|
|
150
294
|
delete renderedDoms[Number(uid)];
|
|
151
295
|
}
|
|
296
|
+
for (const uid of Object.keys(contexts)) {
|
|
297
|
+
delete contexts[Number(uid)];
|
|
298
|
+
}
|
|
299
|
+
for (const uid of Object.keys(contextViewIds)) {
|
|
300
|
+
delete contextViewIds[Number(uid)];
|
|
301
|
+
}
|
|
152
302
|
};
|
|
153
303
|
export {
|
|
154
304
|
createViewInstance,
|
|
155
305
|
dispatchViewEvent,
|
|
156
306
|
disposeViewInstance,
|
|
157
307
|
executeViewProvider,
|
|
308
|
+
getViewMenuEntries,
|
|
158
309
|
getViewRegistrySnapshot,
|
|
159
310
|
registerView,
|
|
160
311
|
renderViewInstance,
|
|
@@ -12,7 +12,7 @@ export { executeSourceControlAcceptInput, executeSourceControlAdd, executeSource
|
|
|
12
12
|
export { createViewInstance, dispatchViewEvent, disposeViewInstance, executeViewProvider, getViewRegistrySnapshot, renderViewInstance, registerView, resetViewRegistry, saveViewInstanceState, } from './parts/ViewRegistry/ViewRegistry.ts';
|
|
13
13
|
export { createOutputChannel, getOutputChannelRegistrySnapshot, resetOutputChannelRegistry } from './parts/OutputChannel/OutputChannel.ts';
|
|
14
14
|
export { getStatusBarItemProviderRegistrySnapshot, registerStatusBarItemProvider, resetStatusBarItemProviderRegistry, } from './parts/StatusBar/StatusBar.ts';
|
|
15
|
-
export type { RegisteredView, View, ViewContext, ViewEvent, ViewKind, ViewRegistrySnapshot, ViewRenderResult, VirtualDomViewInstance, } from './parts/View/View.ts';
|
|
15
|
+
export type { RegisteredView, View, ViewContext, ViewEvent, ViewKind, MenuEntry, ViewRegistrySnapshot, ViewRenderResult, VirtualDomViewInstance, } from './parts/View/View.ts';
|
|
16
16
|
export { handleExtensionManagementMessagePort } from './parts/HandleExtensionManagementMessagePort/HandleExtensionManagementMessagePort.ts';
|
|
17
17
|
export type { Command } from './parts/Command/Command.ts';
|
|
18
18
|
export type { CommandCallback } from './parts/CommandCallback/CommandCallback.ts';
|
|
@@ -28,6 +28,7 @@ export declare const commandMap: {
|
|
|
28
28
|
'ExtensionApi.getOutputChannelRegistrySnapshot': () => import("../OutputChannelRegistrySnapshot/OutputChannelRegistrySnapshot.ts").OutputChannelRegistrySnapshot;
|
|
29
29
|
'ExtensionApi.getSourceControlProviderRegistrySnapshot': () => import("../SourceControlProviderRegistrySnapshot/SourceControlProviderRegistrySnapshot.ts").SourceControlProviderRegistrySnapshot;
|
|
30
30
|
'ExtensionApi.getStatusBarItems': () => readonly import("../StatusBarItem/StatusBarItem.ts").StatusBarItem[];
|
|
31
|
+
'ExtensionApi.getViewMenuEntries': (uid: number, menuId: string) => Promise<readonly import("../View/View.ts").MenuEntry[]>;
|
|
31
32
|
'ExtensionApi.getViewRegistrySnapshot': () => import("../View/View.ts").ViewRegistrySnapshot;
|
|
32
33
|
'ExtensionApi.renderViewInstance': (uid: number) => Promise<import("../View/View.ts").ViewRenderResult>;
|
|
33
34
|
'ExtensionApi.saveViewInstanceState': (uid: number) => Promise<unknown>;
|
|
@@ -27,6 +27,7 @@ export declare const commandMap: {
|
|
|
27
27
|
'ExtensionApi.getOutputChannelRegistrySnapshot': () => import("../OutputChannelRegistrySnapshot/OutputChannelRegistrySnapshot.ts").OutputChannelRegistrySnapshot;
|
|
28
28
|
'ExtensionApi.getSourceControlProviderRegistrySnapshot': () => import("../SourceControlProviderRegistrySnapshot/SourceControlProviderRegistrySnapshot.ts").SourceControlProviderRegistrySnapshot;
|
|
29
29
|
'ExtensionApi.getStatusBarItems': () => readonly import("../StatusBarItem/StatusBarItem.ts").StatusBarItem[];
|
|
30
|
+
'ExtensionApi.getViewMenuEntries': (uid: number, menuId: string) => Promise<readonly import("../View/View.ts").MenuEntry[]>;
|
|
30
31
|
'ExtensionApi.getViewRegistrySnapshot': () => import("../View/View.ts").ViewRegistrySnapshot;
|
|
31
32
|
'ExtensionApi.renderViewInstance': (uid: number) => Promise<import("../View/View.ts").ViewRenderResult>;
|
|
32
33
|
'ExtensionApi.saveViewInstanceState': (uid: number) => Promise<unknown>;
|
|
@@ -6,7 +6,7 @@ import { getStatusBarItems } from "../GetStatusBarItems/GetStatusBarItems.js";
|
|
|
6
6
|
import { executeHoverProvider, getHoverProviderRegistrySnapshot } from "../Hover/Hover.js";
|
|
7
7
|
import { getOutputChannelRegistrySnapshot } from "../OutputChannel/OutputChannel.js";
|
|
8
8
|
import { executeSourceControlAcceptInput, executeSourceControlAdd, executeSourceControlDiscard, executeSourceControlGenerateCommitMessage, executeSourceControlGetChangedFiles, executeSourceControlGetFeatures, executeSourceControlGetFileBefore, executeSourceControlGetFileDecorations, executeSourceControlGetGroups, executeSourceControlIsActive, getSourceControlProviderRegistrySnapshot, } from "../SourceControl/SourceControl.js";
|
|
9
|
-
import { createViewInstance, dispatchViewEvent, disposeViewInstance, executeViewProvider, getViewRegistrySnapshot, renderViewInstance, saveViewInstanceState, } from "../ViewRegistry/ViewRegistry.js";
|
|
9
|
+
import { createViewInstance, dispatchViewEvent, disposeViewInstance, executeViewProvider, getViewMenuEntries, getViewRegistrySnapshot, renderViewInstance, saveViewInstanceState, } from "../ViewRegistry/ViewRegistry.js";
|
|
10
10
|
export const commandMap = {
|
|
11
11
|
'ExtensionApi.createViewInstance': createViewInstance,
|
|
12
12
|
'ExtensionApi.dispatchViewEvent': dispatchViewEvent,
|
|
@@ -36,6 +36,7 @@ export const commandMap = {
|
|
|
36
36
|
'ExtensionApi.getOutputChannelRegistrySnapshot': getOutputChannelRegistrySnapshot,
|
|
37
37
|
'ExtensionApi.getSourceControlProviderRegistrySnapshot': getSourceControlProviderRegistrySnapshot,
|
|
38
38
|
'ExtensionApi.getStatusBarItems': getStatusBarItems,
|
|
39
|
+
'ExtensionApi.getViewMenuEntries': getViewMenuEntries,
|
|
39
40
|
'ExtensionApi.getViewRegistrySnapshot': getViewRegistrySnapshot,
|
|
40
41
|
'ExtensionApi.renderViewInstance': renderViewInstance,
|
|
41
42
|
'ExtensionApi.saveViewInstanceState': saveViewInstanceState,
|
package/extension-api/dist/parts/ExtensionApiWorkerCommandMap/ExtensionApiWorkerCommandMap.d.ts
CHANGED
|
@@ -29,6 +29,7 @@ export declare const commandMap: {
|
|
|
29
29
|
'ExtensionApi.getOutputChannelRegistrySnapshot': () => import("../OutputChannelRegistrySnapshot/OutputChannelRegistrySnapshot.ts").OutputChannelRegistrySnapshot;
|
|
30
30
|
'ExtensionApi.getSourceControlProviderRegistrySnapshot': () => import("../SourceControlProviderRegistrySnapshot/SourceControlProviderRegistrySnapshot.ts").SourceControlProviderRegistrySnapshot;
|
|
31
31
|
'ExtensionApi.getStatusBarItems': () => readonly import("../StatusBarItem/StatusBarItem.ts").StatusBarItem[];
|
|
32
|
+
'ExtensionApi.getViewMenuEntries': (uid: number, menuId: string) => Promise<readonly import("../View/View.ts").MenuEntry[]>;
|
|
32
33
|
'ExtensionApi.getViewRegistrySnapshot': () => import("../View/View.ts").ViewRegistrySnapshot;
|
|
33
34
|
'ExtensionApi.renderViewInstance': (uid: number) => Promise<import("../View/View.ts").ViewRenderResult>;
|
|
34
35
|
'ExtensionApi.saveViewInstanceState': (uid: number) => Promise<unknown>;
|
|
@@ -2,6 +2,7 @@ import type { VirtualDomNode } from '@lvce-editor/virtual-dom-worker';
|
|
|
2
2
|
export type ViewKind = 'virtualDom';
|
|
3
3
|
export interface ViewContext {
|
|
4
4
|
readonly requestRerender: () => Promise<void>;
|
|
5
|
+
readonly showContextMenu: (menuId: string, x: number, y: number) => Promise<void>;
|
|
5
6
|
readonly state?: unknown;
|
|
6
7
|
readonly uid: number;
|
|
7
8
|
readonly viewId: string;
|
|
@@ -10,9 +11,28 @@ export interface ViewEvent {
|
|
|
10
11
|
readonly name?: string;
|
|
11
12
|
readonly type: string;
|
|
12
13
|
readonly value?: unknown;
|
|
14
|
+
readonly x?: number;
|
|
15
|
+
readonly y?: number;
|
|
16
|
+
}
|
|
17
|
+
export interface MenuEntry {
|
|
18
|
+
readonly args?: readonly unknown[];
|
|
19
|
+
readonly command: string;
|
|
20
|
+
readonly flags?: number;
|
|
21
|
+
readonly id: string;
|
|
22
|
+
readonly label: string;
|
|
23
|
+
}
|
|
24
|
+
export interface DomEventListener {
|
|
25
|
+
readonly capture?: boolean;
|
|
26
|
+
readonly name: string | number;
|
|
27
|
+
readonly params: readonly string[];
|
|
28
|
+
readonly passive?: boolean;
|
|
29
|
+
readonly preventDefault?: boolean;
|
|
30
|
+
readonly stopPropagation?: boolean;
|
|
13
31
|
}
|
|
14
32
|
export interface VirtualDomViewInstance {
|
|
15
33
|
readonly dispose?: () => unknown;
|
|
34
|
+
readonly getContext?: () => Readonly<Record<string, boolean>>;
|
|
35
|
+
readonly getMenuEntries?: (menuId: string) => readonly MenuEntry[] | Promise<readonly MenuEntry[]>;
|
|
16
36
|
readonly handleEvent?: (event: ViewEvent) => unknown;
|
|
17
37
|
readonly render: () => readonly VirtualDomNode[] | Promise<readonly VirtualDomNode[]>;
|
|
18
38
|
readonly saveState?: () => unknown;
|
|
@@ -20,6 +40,7 @@ export interface VirtualDomViewInstance {
|
|
|
20
40
|
export interface View {
|
|
21
41
|
readonly create: (context?: ViewContext) => unknown;
|
|
22
42
|
readonly displayName?: string;
|
|
43
|
+
readonly eventListeners?: readonly DomEventListener[];
|
|
23
44
|
readonly icon?: string;
|
|
24
45
|
readonly id: string;
|
|
25
46
|
readonly kind?: ViewKind;
|
|
@@ -28,6 +49,7 @@ export interface View {
|
|
|
28
49
|
}
|
|
29
50
|
export interface RegisteredView {
|
|
30
51
|
readonly displayName?: string;
|
|
52
|
+
readonly eventListeners?: readonly DomEventListener[];
|
|
31
53
|
readonly icon?: string;
|
|
32
54
|
readonly id: string;
|
|
33
55
|
readonly kind?: ViewKind;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Disposable } from '../Disposable/Disposable.ts';
|
|
2
|
-
import type { View, ViewContext, ViewEvent, ViewRegistrySnapshot, ViewRenderResult } from '../View/View.ts';
|
|
2
|
+
import type { MenuEntry, View, ViewContext, ViewEvent, ViewRegistrySnapshot, ViewRenderResult } from '../View/View.ts';
|
|
3
3
|
export declare const registerView: (view: View) => Disposable;
|
|
4
4
|
export declare const executeViewProvider: (id: string) => unknown;
|
|
5
5
|
export declare const createViewInstance: (viewId: string, uid: number, context?: ViewContext) => Promise<ViewRenderResult>;
|
|
@@ -7,5 +7,6 @@ export declare const dispatchViewEvent: (uid: number, event: ViewEvent) => Promi
|
|
|
7
7
|
export declare const renderViewInstance: (uid: number) => Promise<ViewRenderResult>;
|
|
8
8
|
export declare const disposeViewInstance: (uid: number) => Promise<void>;
|
|
9
9
|
export declare const saveViewInstanceState: (uid: number) => Promise<unknown>;
|
|
10
|
+
export declare const getViewMenuEntries: (uid: number, menuId: string) => Promise<readonly MenuEntry[]>;
|
|
10
11
|
export declare const getViewRegistrySnapshot: () => ViewRegistrySnapshot;
|
|
11
12
|
export declare const resetViewRegistry: () => void;
|