@kispace-io/core 0.7.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/api/base-classes.d.ts +7 -0
- package/dist/api/base-classes.d.ts.map +1 -0
- package/dist/api/constants.d.ts +2 -0
- package/dist/api/constants.d.ts.map +1 -0
- package/dist/api/index.d.ts +6 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +80 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/services.d.ts +27 -0
- package/dist/api/services.d.ts.map +1 -0
- package/dist/api/types.d.ts +11 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/commands/files.d.ts +2 -0
- package/dist/commands/files.d.ts.map +1 -0
- package/dist/commands/global.d.ts +1 -0
- package/dist/commands/global.d.ts.map +1 -0
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/version-info.d.ts +2 -0
- package/dist/commands/version-info.d.ts.map +1 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/k-app-selector.d.ts +17 -0
- package/dist/components/k-app-selector.d.ts.map +1 -0
- package/dist/components/k-app-switcher.d.ts +13 -0
- package/dist/components/k-app-switcher.d.ts.map +1 -0
- package/dist/components/k-command.d.ts +31 -0
- package/dist/components/k-command.d.ts.map +1 -0
- package/dist/components/k-extensions.d.ts +32 -0
- package/dist/components/k-extensions.d.ts.map +1 -0
- package/dist/components/k-fastviews.d.ts +34 -0
- package/dist/components/k-fastviews.d.ts.map +1 -0
- package/dist/components/k-filebrowser.d.ts +40 -0
- package/dist/components/k-filebrowser.d.ts.map +1 -0
- package/dist/components/k-language-selector.d.ts +12 -0
- package/dist/components/k-language-selector.d.ts.map +1 -0
- package/dist/components/k-log-terminal.d.ts +36 -0
- package/dist/components/k-log-terminal.d.ts.map +1 -0
- package/dist/components/k-part-name.d.ts +12 -0
- package/dist/components/k-part-name.d.ts.map +1 -0
- package/dist/components/k-tasks.d.ts +13 -0
- package/dist/components/k-tasks.d.ts.map +1 -0
- package/dist/components/k-workspace-name.d.ts +14 -0
- package/dist/components/k-workspace-name.d.ts.map +1 -0
- package/dist/contributions/default-ui-contributions.d.ts +2 -0
- package/dist/contributions/default-ui-contributions.d.ts.map +1 -0
- package/dist/contributions/index.d.ts +1 -0
- package/dist/contributions/index.d.ts.map +1 -0
- package/dist/contributions/marketplace-catalog-contributions.d.ts +2 -0
- package/dist/contributions/marketplace-catalog-contributions.d.ts.map +1 -0
- package/dist/core/app-host-config.d.ts +7 -0
- package/dist/core/app-host-config.d.ts.map +1 -0
- package/dist/core/apploader.d.ts +214 -0
- package/dist/core/apploader.d.ts.map +1 -0
- package/dist/core/appstate.d.ts +12 -0
- package/dist/core/appstate.d.ts.map +1 -0
- package/dist/core/commandregistry.d.ts +79 -0
- package/dist/core/commandregistry.d.ts.map +1 -0
- package/dist/core/config.d.ts +15 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/constants.d.ts +21 -0
- package/dist/core/constants.d.ts.map +1 -0
- package/dist/core/contributionregistry.d.ts +49 -0
- package/dist/core/contributionregistry.d.ts.map +1 -0
- package/dist/core/di.d.ts +18 -0
- package/dist/core/di.d.ts.map +1 -0
- package/dist/core/dialogservice.d.ts +33 -0
- package/dist/core/dialogservice.d.ts.map +1 -0
- package/dist/core/editorregistry.d.ts +73 -0
- package/dist/core/editorregistry.d.ts.map +1 -0
- package/dist/core/esmsh-service.d.ts +40 -0
- package/dist/core/esmsh-service.d.ts.map +1 -0
- package/dist/core/events.d.ts +7 -0
- package/dist/core/events.d.ts.map +1 -0
- package/dist/core/events.js +63 -0
- package/dist/core/events.js.map +1 -0
- package/dist/core/extensionregistry.d.ts +98 -0
- package/dist/core/extensionregistry.d.ts.map +1 -0
- package/dist/core/filesys.d.ts +139 -0
- package/dist/core/filesys.d.ts.map +1 -0
- package/dist/core/i18n.d.ts +50 -0
- package/dist/core/i18n.d.ts.map +1 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/k-utils.d.ts +2 -0
- package/dist/core/k-utils.d.ts.map +1 -0
- package/dist/core/keybindings.d.ts +67 -0
- package/dist/core/keybindings.d.ts.map +1 -0
- package/dist/core/logger.d.ts +44 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/marketplaceregistry.d.ts +25 -0
- package/dist/core/marketplaceregistry.d.ts.map +1 -0
- package/dist/core/packageinfoservice.d.ts +16 -0
- package/dist/core/packageinfoservice.d.ts.map +1 -0
- package/dist/core/persistenceservice.d.ts +6 -0
- package/dist/core/persistenceservice.d.ts.map +1 -0
- package/dist/core/settingsservice.d.ts +19 -0
- package/dist/core/settingsservice.d.ts.map +1 -0
- package/dist/core/signals.d.ts +3 -0
- package/dist/core/signals.d.ts.map +1 -0
- package/dist/core/taskservice.d.ts +20 -0
- package/dist/core/taskservice.d.ts.map +1 -0
- package/dist/core/toast.d.ts +4 -0
- package/dist/core/toast.d.ts.map +1 -0
- package/dist/core/tree-utils.d.ts +16 -0
- package/dist/core/tree-utils.d.ts.map +1 -0
- package/dist/dialogs/confirm-dialog.d.ts +14 -0
- package/dist/dialogs/confirm-dialog.d.ts.map +1 -0
- package/dist/dialogs/index.d.ts +5 -0
- package/dist/dialogs/index.d.ts.map +1 -0
- package/dist/dialogs/info-dialog.d.ts +13 -0
- package/dist/dialogs/info-dialog.d.ts.map +1 -0
- package/dist/dialogs/navigable-info-dialog.d.ts +33 -0
- package/dist/dialogs/navigable-info-dialog.d.ts.map +1 -0
- package/dist/dialogs/prompt-dialog.d.ts +21 -0
- package/dist/dialogs/prompt-dialog.d.ts.map +1 -0
- package/dist/externals/lit.d.ts +20 -0
- package/dist/externals/lit.d.ts.map +1 -0
- package/dist/externals/lit.js +15 -0
- package/dist/externals/lit.js.map +1 -0
- package/dist/externals/third-party.d.ts +7 -0
- package/dist/externals/third-party.d.ts.map +1 -0
- package/dist/externals/third-party.js +2 -0
- package/dist/externals/third-party.js.map +1 -0
- package/dist/externals/webawesome.d.ts +1 -0
- package/dist/externals/webawesome.d.ts.map +1 -0
- package/dist/externals/webawesome.js +52 -0
- package/dist/externals/webawesome.js.map +1 -0
- package/dist/i18n/extensions.json.d.ts +42 -0
- package/dist/i18n/fastviews.json.d.ts +13 -0
- package/dist/i18n/filebrowser.json.d.ts +35 -0
- package/dist/i18n/index.d.ts +2 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/logterminal.json.d.ts +45 -0
- package/dist/i18n/partname.json.d.ts +15 -0
- package/dist/i18n/tasks.json.d.ts +15 -0
- package/dist/i18n/workspace.json.d.ts +15 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +80 -0
- package/dist/index.js.map +1 -0
- package/dist/k-icon-BZC7dQV0.js +492 -0
- package/dist/k-icon-BZC7dQV0.js.map +1 -0
- package/dist/k-nocontent-Bh_yToGh.js +48 -0
- package/dist/k-nocontent-Bh_yToGh.js.map +1 -0
- package/dist/k-resizable-grid-Ch3iWZaL.js +3157 -0
- package/dist/k-resizable-grid-Ch3iWZaL.js.map +1 -0
- package/dist/k-standard-layout-CQ1VZoxa.js +5011 -0
- package/dist/k-standard-layout-CQ1VZoxa.js.map +1 -0
- package/dist/layouts/k-standard-layout.d.ts +16 -0
- package/dist/layouts/k-standard-layout.d.ts.map +1 -0
- package/dist/parts/index.d.ts +1 -0
- package/dist/parts/index.d.ts.map +1 -0
- package/dist/parts/index.js +53 -0
- package/dist/parts/index.js.map +1 -0
- package/dist/parts/k-app.d.ts +11 -0
- package/dist/parts/k-app.d.ts.map +1 -0
- package/dist/parts/k-container.d.ts +4 -0
- package/dist/parts/k-container.d.ts.map +1 -0
- package/dist/parts/k-contextmenu.d.ts +38 -0
- package/dist/parts/k-contextmenu.d.ts.map +1 -0
- package/dist/parts/k-dialog-content.d.ts +9 -0
- package/dist/parts/k-dialog-content.d.ts.map +1 -0
- package/dist/parts/k-element.d.ts +36 -0
- package/dist/parts/k-element.d.ts.map +1 -0
- package/dist/parts/k-part.d.ts +96 -0
- package/dist/parts/k-part.d.ts.map +1 -0
- package/dist/parts/k-resizable-grid.d.ts +31 -0
- package/dist/parts/k-resizable-grid.d.ts.map +1 -0
- package/dist/parts/k-tabs.d.ts +74 -0
- package/dist/parts/k-tabs.d.ts.map +1 -0
- package/dist/parts/k-toolbar.d.ts +21 -0
- package/dist/parts/k-toolbar.d.ts.map +1 -0
- package/dist/widgets/index.d.ts +1 -0
- package/dist/widgets/index.d.ts.map +1 -0
- package/dist/widgets/index.js +3 -0
- package/dist/widgets/index.js.map +1 -0
- package/dist/widgets/k-icon.d.ts +10 -0
- package/dist/widgets/k-icon.d.ts.map +1 -0
- package/dist/widgets/k-nocontent.d.ts +13 -0
- package/dist/widgets/k-nocontent.d.ts.map +1 -0
- package/dist/widgets/k-widget.d.ts +25 -0
- package/dist/widgets/k-widget.d.ts.map +1 -0
- package/package.json +81 -0
- package/src/api/base-classes.ts +10 -0
- package/src/api/constants.ts +3 -0
- package/src/api/index.ts +31 -0
- package/src/api/services.ts +52 -0
- package/src/api/types.ts +46 -0
- package/src/commands/files.ts +829 -0
- package/src/commands/global.ts +225 -0
- package/src/commands/index.ts +4 -0
- package/src/commands/version-info.ts +214 -0
- package/src/components/index.ts +10 -0
- package/src/components/k-app-selector.ts +233 -0
- package/src/components/k-app-switcher.ts +126 -0
- package/src/components/k-command.ts +236 -0
- package/src/components/k-extensions.ts +615 -0
- package/src/components/k-fastviews.ts +314 -0
- package/src/components/k-filebrowser.ts +442 -0
- package/src/components/k-language-selector.ts +166 -0
- package/src/components/k-log-terminal.ts +337 -0
- package/src/components/k-part-name.ts +54 -0
- package/src/components/k-tasks.ts +267 -0
- package/src/components/k-workspace-name.ts +56 -0
- package/src/contributions/default-ui-contributions.ts +51 -0
- package/src/contributions/index.ts +3 -0
- package/src/contributions/marketplace-catalog-contributions.ts +6 -0
- package/src/core/app-host-config.ts +23 -0
- package/src/core/apploader.ts +630 -0
- package/src/core/appstate.ts +15 -0
- package/src/core/commandregistry.ts +210 -0
- package/src/core/config.ts +29 -0
- package/src/core/constants.ts +27 -0
- package/src/core/contributionregistry.ts +77 -0
- package/src/core/di.ts +54 -0
- package/src/core/dialogservice.ts +266 -0
- package/src/core/editorregistry.ts +303 -0
- package/src/core/esmsh-service.ts +404 -0
- package/src/core/events.ts +68 -0
- package/src/core/extensionregistry.ts +399 -0
- package/src/core/filesys.ts +618 -0
- package/src/core/i18n.ts +221 -0
- package/src/core/index.ts +51 -0
- package/src/core/k-utils.ts +11 -0
- package/src/core/keybindings.ts +274 -0
- package/src/core/logger.ts +187 -0
- package/src/core/marketplaceregistry.ts +197 -0
- package/src/core/packageinfoservice.ts +56 -0
- package/src/core/persistenceservice.ts +15 -0
- package/src/core/settingsservice.ts +70 -0
- package/src/core/signals.ts +18 -0
- package/src/core/taskservice.ts +72 -0
- package/src/core/toast.ts +11 -0
- package/src/core/tree-utils.ts +24 -0
- package/src/dialogs/confirm-dialog.ts +72 -0
- package/src/dialogs/index.ts +4 -0
- package/src/dialogs/info-dialog.ts +67 -0
- package/src/dialogs/navigable-info-dialog.ts +256 -0
- package/src/dialogs/prompt-dialog.ts +123 -0
- package/src/externals/lit.ts +26 -0
- package/src/externals/third-party.ts +9 -0
- package/src/externals/webawesome.ts +54 -0
- package/src/i18n/extensions.json +39 -0
- package/src/i18n/fastviews.json +10 -0
- package/src/i18n/filebrowser.json +33 -0
- package/src/i18n/index.ts +25 -0
- package/src/i18n/logterminal.json +42 -0
- package/src/i18n/partname.json +12 -0
- package/src/i18n/tasks.json +12 -0
- package/src/i18n/workspace.json +12 -0
- package/src/icons/icons.txt +3 -0
- package/src/icons/js.svg +6 -0
- package/src/icons/jupyter.svg +18 -0
- package/src/icons/python.svg +15 -0
- package/src/index.ts +3 -0
- package/src/layouts/k-standard-layout.ts +174 -0
- package/src/parts/index.ts +6 -0
- package/src/parts/k-app.ts +29 -0
- package/src/parts/k-container.ts +4 -0
- package/src/parts/k-contextmenu.ts +245 -0
- package/src/parts/k-dialog-content.ts +31 -0
- package/src/parts/k-element.ts +100 -0
- package/src/parts/k-part.ts +158 -0
- package/src/parts/k-resizable-grid.ts +366 -0
- package/src/parts/k-tabs.ts +574 -0
- package/src/parts/k-toolbar.ts +158 -0
- package/src/vite-env.d.ts +2 -0
- package/src/widgets/index.ts +2 -0
- package/src/widgets/k-icon.ts +39 -0
- package/src/widgets/k-nocontent.ts +40 -0
- package/src/widgets/k-widget.ts +90 -0
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import {css, html, nothing} from 'lit'
|
|
2
|
+
import {customElement, property, state} from 'lit/decorators.js'
|
|
3
|
+
import {KElement} from "./k-element";
|
|
4
|
+
import {
|
|
5
|
+
CommandContribution,
|
|
6
|
+
Contribution,
|
|
7
|
+
ContributionChangeEvent,
|
|
8
|
+
contributionRegistry,
|
|
9
|
+
HTMLContribution,
|
|
10
|
+
TOPIC_CONTRIBUTEIONS_CHANGED
|
|
11
|
+
} from "../core/contributionregistry";
|
|
12
|
+
import {Signal} from '@lit-labs/signals';
|
|
13
|
+
import {unsafeHTML} from "lit/directives/unsafe-html.js";
|
|
14
|
+
import {subscribe} from "../core/events";
|
|
15
|
+
import {createRef, ref} from "lit/directives/ref.js";
|
|
16
|
+
|
|
17
|
+
@customElement('k-contextmenu')
|
|
18
|
+
export class KContextMenu extends KElement {
|
|
19
|
+
@property({type: Boolean, attribute: 'is-editor'})
|
|
20
|
+
private isEditor: boolean = false;
|
|
21
|
+
|
|
22
|
+
@property({attribute: false})
|
|
23
|
+
public partContextMenuRenderer?: () => any = undefined;
|
|
24
|
+
|
|
25
|
+
@state()
|
|
26
|
+
private contributions: Contribution[] = [];
|
|
27
|
+
|
|
28
|
+
@state()
|
|
29
|
+
private isOpen: boolean = false;
|
|
30
|
+
|
|
31
|
+
@state()
|
|
32
|
+
private position: { x: number, y: number } = { x: 0, y: 0 };
|
|
33
|
+
|
|
34
|
+
private anchorRef = createRef<HTMLElement>();
|
|
35
|
+
private dropdownRef = createRef<HTMLElement>();
|
|
36
|
+
|
|
37
|
+
protected doBeforeUI() {
|
|
38
|
+
const id = this.getAttribute("id");
|
|
39
|
+
if (id) {
|
|
40
|
+
this.loadContributions(id);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
subscribe(TOPIC_CONTRIBUTEIONS_CHANGED, (event: ContributionChangeEvent) => {
|
|
44
|
+
if (!id) return;
|
|
45
|
+
|
|
46
|
+
const shouldReload = this.matchesTarget(id, event.target);
|
|
47
|
+
if (shouldReload) {
|
|
48
|
+
this.loadContributions(id);
|
|
49
|
+
this.requestUpdate();
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
private matchesTarget(id: string, target: string): boolean {
|
|
56
|
+
if (target === id) return true;
|
|
57
|
+
|
|
58
|
+
if (!id.includes(':')) return false;
|
|
59
|
+
|
|
60
|
+
const [prefix] = id.split(':');
|
|
61
|
+
if (target === `${prefix}:*`) return true;
|
|
62
|
+
|
|
63
|
+
const targetParts = target.split(':');
|
|
64
|
+
if (targetParts.length === 2) {
|
|
65
|
+
const categoryToken = targetParts[1];
|
|
66
|
+
if (categoryToken === 'system.editors' || categoryToken === '.system.editors') {
|
|
67
|
+
return this.isEditor && id.startsWith(`${prefix}:`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
private loadContributions(id: string) {
|
|
75
|
+
const specific = contributionRegistry.getContributions(id);
|
|
76
|
+
|
|
77
|
+
if (!id.includes(':')) {
|
|
78
|
+
this.contributions = specific;
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const [prefix] = id.split(':');
|
|
83
|
+
const wildcardId = `${prefix}:*`;
|
|
84
|
+
const wildcard = contributionRegistry.getContributions(wildcardId);
|
|
85
|
+
|
|
86
|
+
const categoryMatches: Contribution[] = [];
|
|
87
|
+
|
|
88
|
+
if (this.isEditor) {
|
|
89
|
+
const allCategories = ['system.editors', '.system.editors'];
|
|
90
|
+
for (const category of allCategories) {
|
|
91
|
+
const categoryId = `${prefix}:${category}`;
|
|
92
|
+
const matches = contributionRegistry.getContributions(categoryId);
|
|
93
|
+
categoryMatches.push(...matches);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
this.contributions = [...wildcard, ...categoryMatches, ...specific];
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Gets the element at the given point, traversing shadow DOM boundaries recursively.
|
|
102
|
+
* This is necessary because elementFromPoint() doesn't penetrate shadow roots.
|
|
103
|
+
*/
|
|
104
|
+
private getElementFromPoint(x: number, y: number): Element | null {
|
|
105
|
+
let element: Element | null = document.elementFromPoint(x, y);
|
|
106
|
+
if (!element) return null;
|
|
107
|
+
|
|
108
|
+
// Recursively traverse shadow DOM boundaries
|
|
109
|
+
while (element) {
|
|
110
|
+
const shadowRoot = (element as any).shadowRoot as ShadowRoot | undefined;
|
|
111
|
+
if (shadowRoot) {
|
|
112
|
+
const shadowElement: Element | null = shadowRoot.elementFromPoint(x, y);
|
|
113
|
+
if (shadowElement && shadowElement !== element) {
|
|
114
|
+
element = shadowElement;
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return element;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Triggers a click on the element under the cursor to update selection before showing context menu.
|
|
126
|
+
*/
|
|
127
|
+
private triggerClickUnderCursor(mouseEvent: MouseEvent): void {
|
|
128
|
+
const elementUnderCursor = this.getElementFromPoint(mouseEvent.clientX, mouseEvent.clientY);
|
|
129
|
+
if (elementUnderCursor) {
|
|
130
|
+
const clickEvent = new MouseEvent('click', {
|
|
131
|
+
bubbles: true,
|
|
132
|
+
cancelable: true,
|
|
133
|
+
view: window,
|
|
134
|
+
clientX: mouseEvent.clientX,
|
|
135
|
+
clientY: mouseEvent.clientY,
|
|
136
|
+
screenX: mouseEvent.screenX,
|
|
137
|
+
screenY: mouseEvent.screenY,
|
|
138
|
+
button: 0,
|
|
139
|
+
buttons: 0,
|
|
140
|
+
detail: 1,
|
|
141
|
+
which: 1
|
|
142
|
+
});
|
|
143
|
+
elementUnderCursor.dispatchEvent(clickEvent);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
public show(position: { x: number, y: number }, mouseEvent?: MouseEvent) {
|
|
148
|
+
// Trigger click before showing context menu to update selection
|
|
149
|
+
if (mouseEvent) {
|
|
150
|
+
this.triggerClickUnderCursor(mouseEvent);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
this.position = position;
|
|
154
|
+
this.isOpen = true;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
private onClose() {
|
|
158
|
+
this.isOpen = false;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
private handleCommandClick(commandId: string, params?: Record<string, any>) {
|
|
162
|
+
return async () => {
|
|
163
|
+
this.executeCommand(commandId, params || {});
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
private renderContribution(contribution: Contribution) {
|
|
168
|
+
if ("command" in contribution) {
|
|
169
|
+
const commandContribution = contribution as CommandContribution;
|
|
170
|
+
return html`
|
|
171
|
+
<wa-dropdown-item
|
|
172
|
+
@click=${this.handleCommandClick(commandContribution.command, commandContribution.params)}
|
|
173
|
+
?disabled="${(commandContribution.disabled as Signal.Computed<boolean>)?.get()}">
|
|
174
|
+
${commandContribution.icon ? html`<wa-icon slot="icon" name=${commandContribution.icon}></wa-icon>` : ''}
|
|
175
|
+
${commandContribution.label}
|
|
176
|
+
</wa-dropdown-item>
|
|
177
|
+
`;
|
|
178
|
+
} else if ("html" in contribution) {
|
|
179
|
+
const contents = (contribution as HTMLContribution).html;
|
|
180
|
+
if (contents instanceof Function) {
|
|
181
|
+
return contents();
|
|
182
|
+
}
|
|
183
|
+
return unsafeHTML(contents);
|
|
184
|
+
}
|
|
185
|
+
return nothing;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
render() {
|
|
189
|
+
if (!this.isOpen) return nothing;
|
|
190
|
+
|
|
191
|
+
const partContent = this.partContextMenuRenderer ? this.partContextMenuRenderer() : nothing;
|
|
192
|
+
|
|
193
|
+
return html`
|
|
194
|
+
<wa-dropdown
|
|
195
|
+
${ref(this.dropdownRef)}
|
|
196
|
+
?open=${this.isOpen}
|
|
197
|
+
@wa-after-hide=${this.onClose}
|
|
198
|
+
placement="bottom-start"
|
|
199
|
+
distance="0">
|
|
200
|
+
|
|
201
|
+
<div
|
|
202
|
+
slot="trigger"
|
|
203
|
+
${ref(this.anchorRef)}
|
|
204
|
+
style="position: fixed;
|
|
205
|
+
left: ${this.position.x}px;
|
|
206
|
+
top: ${this.position.y}px;
|
|
207
|
+
width: 1px;
|
|
208
|
+
height: 1px;
|
|
209
|
+
pointer-events: none;">
|
|
210
|
+
</div>
|
|
211
|
+
|
|
212
|
+
${partContent}
|
|
213
|
+
${this.contributions.map(c => this.renderContribution(c))}
|
|
214
|
+
</wa-dropdown>
|
|
215
|
+
`;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
static styles = css`
|
|
219
|
+
:host {
|
|
220
|
+
position: fixed;
|
|
221
|
+
top: 0;
|
|
222
|
+
left: 0;
|
|
223
|
+
width: 0;
|
|
224
|
+
height: 0;
|
|
225
|
+
pointer-events: none;
|
|
226
|
+
z-index: 10000;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
wa-dropdown {
|
|
230
|
+
pointer-events: auto;
|
|
231
|
+
min-width: 200px;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
wa-dropdown::part(panel) {
|
|
235
|
+
min-width: 200px;
|
|
236
|
+
}
|
|
237
|
+
`;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
declare global {
|
|
241
|
+
interface HTMLElementTagNameMap {
|
|
242
|
+
'k-contextmenu': KContextMenu
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { html, TemplateResult, css } from "lit";
|
|
2
|
+
import { unsafeHTML } from "lit/directives/unsafe-html.js";
|
|
3
|
+
import { marked } from "marked";
|
|
4
|
+
import { KElement } from "./k-element";
|
|
5
|
+
|
|
6
|
+
export abstract class KDialogContent extends KElement {
|
|
7
|
+
static styles = [
|
|
8
|
+
css`
|
|
9
|
+
.dialog-message {
|
|
10
|
+
margin-bottom: 0.5rem;
|
|
11
|
+
color: var(--wa-color-text-normal);
|
|
12
|
+
}
|
|
13
|
+
`
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
dispose(): void | Promise<void> {
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
getResult(): any {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
protected renderMessage(message: string, markdown: boolean = false): TemplateResult {
|
|
24
|
+
if (markdown) {
|
|
25
|
+
const htmlContent = marked.parse(message, { async: false }) as string;
|
|
26
|
+
return html`<div class="dialog-message" style="white-space: normal;">${unsafeHTML(htmlContent)}</div>`;
|
|
27
|
+
}
|
|
28
|
+
return html`<div class="dialog-message" style="white-space: pre-line;">${message}</div>`;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import {KWidget} from "../widgets/k-widget";
|
|
2
|
+
import {appSettings} from "../core/settingsservice";
|
|
3
|
+
|
|
4
|
+
export abstract class KElement extends KWidget {
|
|
5
|
+
/**
|
|
6
|
+
* Unique settings key for this element, used for persisting dialog settings.
|
|
7
|
+
* Automatically initialized on first access via getDialogSetting() or setDialogSetting().
|
|
8
|
+
*/
|
|
9
|
+
private settingsKey: string | null = null;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Builds a unique DOM tree path for this element.
|
|
13
|
+
* Uses id attribute if available, otherwise builds a path based on tag names and indices.
|
|
14
|
+
* Useful for generating unique settings keys.
|
|
15
|
+
*
|
|
16
|
+
* @returns A string representing the DOM path, or null if path cannot be determined
|
|
17
|
+
*/
|
|
18
|
+
private buildDOMTreePath(): string | null {
|
|
19
|
+
const pathParts: string[] = [];
|
|
20
|
+
let current: HTMLElement | null = this;
|
|
21
|
+
|
|
22
|
+
while (current && current !== document.body && current !== document.documentElement) {
|
|
23
|
+
const id = current.getAttribute("id");
|
|
24
|
+
if (id) {
|
|
25
|
+
pathParts.unshift(`#${id}`);
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const tagName = current.tagName.toLowerCase();
|
|
30
|
+
const parent: HTMLElement | null = current.parentElement;
|
|
31
|
+
|
|
32
|
+
if (!parent) {
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const siblings = Array.from(parent.children).filter(
|
|
37
|
+
(child: Element) => child.tagName.toLowerCase() === tagName
|
|
38
|
+
) as HTMLElement[];
|
|
39
|
+
const index = siblings.indexOf(current);
|
|
40
|
+
|
|
41
|
+
if (index >= 0) {
|
|
42
|
+
pathParts.unshift(`${tagName}:${index}`);
|
|
43
|
+
} else {
|
|
44
|
+
pathParts.unshift(tagName);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
current = parent;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return pathParts.length > 0 ? pathParts.join(" > ") : null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Initializes the settings key for this element using the element's tag name.
|
|
55
|
+
* Called automatically on first access via getDialogSetting() or setDialogSetting().
|
|
56
|
+
*/
|
|
57
|
+
private initializeSettingsKey(): void {
|
|
58
|
+
if (!this.settingsKey) {
|
|
59
|
+
const prefix = this.tagName.toLowerCase();
|
|
60
|
+
const id = this.getAttribute("id");
|
|
61
|
+
if (id) {
|
|
62
|
+
this.settingsKey = `${prefix}:${id}`;
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const path = this.buildDOMTreePath();
|
|
67
|
+
if (path) {
|
|
68
|
+
this.settingsKey = `${prefix}:${path}`;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Gets a dialog setting value for this element.
|
|
75
|
+
* Automatically initializes the settings key on first access if not already set.
|
|
76
|
+
*
|
|
77
|
+
* @returns The persisted setting value, or undefined if not found
|
|
78
|
+
*/
|
|
79
|
+
protected async getDialogSetting(): Promise<any> {
|
|
80
|
+
this.initializeSettingsKey();
|
|
81
|
+
if (!this.settingsKey) {
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
return await appSettings.getDialogSetting(this.settingsKey);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Saves a dialog setting value for this element.
|
|
89
|
+
* Automatically initializes the settings key on first access if not already set.
|
|
90
|
+
*
|
|
91
|
+
* @param value - The value to persist
|
|
92
|
+
*/
|
|
93
|
+
protected async setDialogSetting(value: any): Promise<void> {
|
|
94
|
+
this.initializeSettingsKey();
|
|
95
|
+
if (!this.settingsKey) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
await appSettings.setDialogSetting(this.settingsKey, value);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import {KContainer} from "./k-container";
|
|
2
|
+
import {property} from "lit/decorators.js";
|
|
3
|
+
import {PropertyValues, TemplateResult, nothing} from "lit";
|
|
4
|
+
import {partDirtySignal, activePartSignal} from "../core/appstate";
|
|
5
|
+
import {CommandStack} from "../core/commandregistry";
|
|
6
|
+
import {TabContribution} from "../core/contributionregistry";
|
|
7
|
+
|
|
8
|
+
export abstract class KPart extends KContainer {
|
|
9
|
+
@property()
|
|
10
|
+
private dirty: boolean = false
|
|
11
|
+
|
|
12
|
+
public tabContribution?: TabContribution;
|
|
13
|
+
|
|
14
|
+
public isEditor: boolean = false;
|
|
15
|
+
|
|
16
|
+
protected commandStack?: CommandStack;
|
|
17
|
+
|
|
18
|
+
public getCommandStack(): CommandStack | undefined {
|
|
19
|
+
return this.commandStack;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Override this method to provide toolbar content for this part.
|
|
24
|
+
* This is a lightweight alternative to registering toolbar contributions
|
|
25
|
+
* for actions that are scoped to this part instance.
|
|
26
|
+
*
|
|
27
|
+
* IMPORTANT: Event handlers MUST use arrow functions to preserve the component's 'this' context.
|
|
28
|
+
* The toolbar template is rendered in a different component (k-toolbar), so direct method
|
|
29
|
+
* references lose their binding.
|
|
30
|
+
*
|
|
31
|
+
* ✅ Correct:
|
|
32
|
+
* @click=${() => this.myMethod()}
|
|
33
|
+
* @click=${(e) => this.handleClick(e)}
|
|
34
|
+
*
|
|
35
|
+
* ❌ Wrong (this will be bound to the toolbar, not your component):
|
|
36
|
+
* @click=${this.myMethod}
|
|
37
|
+
*
|
|
38
|
+
* Example:
|
|
39
|
+
* ```typescript
|
|
40
|
+
* protected renderToolbar() {
|
|
41
|
+
* return html`
|
|
42
|
+
* <wa-button @click=${() => this.save()} title="Save">
|
|
43
|
+
* <wa-icon name="save"></wa-icon>
|
|
44
|
+
* </wa-button>
|
|
45
|
+
* `;
|
|
46
|
+
* }
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* @returns TemplateResult with toolbar items, or nothing if no toolbar needed
|
|
50
|
+
*/
|
|
51
|
+
protected renderToolbar(): TemplateResult | typeof nothing {
|
|
52
|
+
return nothing;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Call this method to update the toolbar when the component's state changes.
|
|
57
|
+
* This triggers a re-render of the toolbar with the latest content from renderToolbar().
|
|
58
|
+
*/
|
|
59
|
+
protected updateToolbar(): void {
|
|
60
|
+
this.dispatchEvent(new CustomEvent('part-toolbar-changed', {
|
|
61
|
+
bubbles: true,
|
|
62
|
+
composed: true
|
|
63
|
+
}));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Override this method to provide context menu content for this part.
|
|
68
|
+
* This is a lightweight alternative to registering context menu contributions
|
|
69
|
+
* for actions that are scoped to this part instance.
|
|
70
|
+
*
|
|
71
|
+
* IMPORTANT: Event handlers MUST use arrow functions to preserve the component's 'this' context.
|
|
72
|
+
* The context menu is rendered in a different component (k-contextmenu), so direct method
|
|
73
|
+
* references lose their binding.
|
|
74
|
+
*
|
|
75
|
+
* ✅ Correct:
|
|
76
|
+
* @click=${() => this.myMethod()}
|
|
77
|
+
* @click=${(e) => this.handleClick(e)}
|
|
78
|
+
*
|
|
79
|
+
* ❌ Wrong (this will be bound to the context menu, not your component):
|
|
80
|
+
* @click=${this.myMethod}
|
|
81
|
+
*
|
|
82
|
+
* Example:
|
|
83
|
+
* ```typescript
|
|
84
|
+
* protected renderContextMenu() {
|
|
85
|
+
* return html`
|
|
86
|
+
* <wa-dropdown-item @click=${() => this.open()}>
|
|
87
|
+
* <wa-icon name="folder-open"></wa-icon>
|
|
88
|
+
* Open
|
|
89
|
+
* </wa-dropdown-item>
|
|
90
|
+
* <wa-divider></wa-divider>
|
|
91
|
+
* <wa-dropdown-item @click=${() => this.delete()}>
|
|
92
|
+
* <wa-icon name="trash"></wa-icon>
|
|
93
|
+
* Delete
|
|
94
|
+
* </wa-dropdown-item>
|
|
95
|
+
* `;
|
|
96
|
+
* }
|
|
97
|
+
* ```
|
|
98
|
+
*
|
|
99
|
+
* @returns TemplateResult with context menu items, or nothing if no context menu needed
|
|
100
|
+
*/
|
|
101
|
+
protected renderContextMenu(): TemplateResult | typeof nothing {
|
|
102
|
+
return nothing;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Call this method to update the context menu when the component's state changes.
|
|
107
|
+
* This triggers a re-render of the context menu with the latest content from renderContextMenu().
|
|
108
|
+
*/
|
|
109
|
+
protected updateContextMenu(): void {
|
|
110
|
+
this.dispatchEvent(new CustomEvent('part-contextmenu-changed', {
|
|
111
|
+
bubbles: true,
|
|
112
|
+
composed: true
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
protected updated(_changedProperties: PropertyValues) {
|
|
117
|
+
super.updated(_changedProperties);
|
|
118
|
+
|
|
119
|
+
if (_changedProperties.has("dirty")) {
|
|
120
|
+
const dirty = _changedProperties.get("dirty")
|
|
121
|
+
if (dirty !== undefined) {
|
|
122
|
+
this.dispatchEvent(new CustomEvent("dirty", {detail: this.dirty, bubbles: true}))
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
protected doClose() {
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
disconnectedCallback() {
|
|
131
|
+
super.disconnectedCallback();
|
|
132
|
+
// Don't automatically close when disconnected - the element might just be moving
|
|
133
|
+
// Call close() explicitly when actually closing the part
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
public close() {
|
|
137
|
+
this.doClose()
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
connectedCallback() {
|
|
141
|
+
super.connectedCallback();
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
save() {
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
public isDirty() {
|
|
148
|
+
return this.dirty
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
public markDirty(dirty: boolean) {
|
|
152
|
+
this.dirty = dirty
|
|
153
|
+
partDirtySignal.set(null as unknown as KPart)
|
|
154
|
+
partDirtySignal.set(this)
|
|
155
|
+
activePartSignal.set(null as unknown as KPart)
|
|
156
|
+
activePartSignal.set(this)
|
|
157
|
+
}
|
|
158
|
+
}
|