@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.
Files changed (272) hide show
  1. package/dist/api/base-classes.d.ts +7 -0
  2. package/dist/api/base-classes.d.ts.map +1 -0
  3. package/dist/api/constants.d.ts +2 -0
  4. package/dist/api/constants.d.ts.map +1 -0
  5. package/dist/api/index.d.ts +6 -0
  6. package/dist/api/index.d.ts.map +1 -0
  7. package/dist/api/index.js +80 -0
  8. package/dist/api/index.js.map +1 -0
  9. package/dist/api/services.d.ts +27 -0
  10. package/dist/api/services.d.ts.map +1 -0
  11. package/dist/api/types.d.ts +11 -0
  12. package/dist/api/types.d.ts.map +1 -0
  13. package/dist/commands/files.d.ts +2 -0
  14. package/dist/commands/files.d.ts.map +1 -0
  15. package/dist/commands/global.d.ts +1 -0
  16. package/dist/commands/global.d.ts.map +1 -0
  17. package/dist/commands/index.d.ts +1 -0
  18. package/dist/commands/index.d.ts.map +1 -0
  19. package/dist/commands/version-info.d.ts +2 -0
  20. package/dist/commands/version-info.d.ts.map +1 -0
  21. package/dist/components/index.d.ts +1 -0
  22. package/dist/components/index.d.ts.map +1 -0
  23. package/dist/components/k-app-selector.d.ts +17 -0
  24. package/dist/components/k-app-selector.d.ts.map +1 -0
  25. package/dist/components/k-app-switcher.d.ts +13 -0
  26. package/dist/components/k-app-switcher.d.ts.map +1 -0
  27. package/dist/components/k-command.d.ts +31 -0
  28. package/dist/components/k-command.d.ts.map +1 -0
  29. package/dist/components/k-extensions.d.ts +32 -0
  30. package/dist/components/k-extensions.d.ts.map +1 -0
  31. package/dist/components/k-fastviews.d.ts +34 -0
  32. package/dist/components/k-fastviews.d.ts.map +1 -0
  33. package/dist/components/k-filebrowser.d.ts +40 -0
  34. package/dist/components/k-filebrowser.d.ts.map +1 -0
  35. package/dist/components/k-language-selector.d.ts +12 -0
  36. package/dist/components/k-language-selector.d.ts.map +1 -0
  37. package/dist/components/k-log-terminal.d.ts +36 -0
  38. package/dist/components/k-log-terminal.d.ts.map +1 -0
  39. package/dist/components/k-part-name.d.ts +12 -0
  40. package/dist/components/k-part-name.d.ts.map +1 -0
  41. package/dist/components/k-tasks.d.ts +13 -0
  42. package/dist/components/k-tasks.d.ts.map +1 -0
  43. package/dist/components/k-workspace-name.d.ts +14 -0
  44. package/dist/components/k-workspace-name.d.ts.map +1 -0
  45. package/dist/contributions/default-ui-contributions.d.ts +2 -0
  46. package/dist/contributions/default-ui-contributions.d.ts.map +1 -0
  47. package/dist/contributions/index.d.ts +1 -0
  48. package/dist/contributions/index.d.ts.map +1 -0
  49. package/dist/contributions/marketplace-catalog-contributions.d.ts +2 -0
  50. package/dist/contributions/marketplace-catalog-contributions.d.ts.map +1 -0
  51. package/dist/core/app-host-config.d.ts +7 -0
  52. package/dist/core/app-host-config.d.ts.map +1 -0
  53. package/dist/core/apploader.d.ts +214 -0
  54. package/dist/core/apploader.d.ts.map +1 -0
  55. package/dist/core/appstate.d.ts +12 -0
  56. package/dist/core/appstate.d.ts.map +1 -0
  57. package/dist/core/commandregistry.d.ts +79 -0
  58. package/dist/core/commandregistry.d.ts.map +1 -0
  59. package/dist/core/config.d.ts +15 -0
  60. package/dist/core/config.d.ts.map +1 -0
  61. package/dist/core/constants.d.ts +21 -0
  62. package/dist/core/constants.d.ts.map +1 -0
  63. package/dist/core/contributionregistry.d.ts +49 -0
  64. package/dist/core/contributionregistry.d.ts.map +1 -0
  65. package/dist/core/di.d.ts +18 -0
  66. package/dist/core/di.d.ts.map +1 -0
  67. package/dist/core/dialogservice.d.ts +33 -0
  68. package/dist/core/dialogservice.d.ts.map +1 -0
  69. package/dist/core/editorregistry.d.ts +73 -0
  70. package/dist/core/editorregistry.d.ts.map +1 -0
  71. package/dist/core/esmsh-service.d.ts +40 -0
  72. package/dist/core/esmsh-service.d.ts.map +1 -0
  73. package/dist/core/events.d.ts +7 -0
  74. package/dist/core/events.d.ts.map +1 -0
  75. package/dist/core/events.js +63 -0
  76. package/dist/core/events.js.map +1 -0
  77. package/dist/core/extensionregistry.d.ts +98 -0
  78. package/dist/core/extensionregistry.d.ts.map +1 -0
  79. package/dist/core/filesys.d.ts +139 -0
  80. package/dist/core/filesys.d.ts.map +1 -0
  81. package/dist/core/i18n.d.ts +50 -0
  82. package/dist/core/i18n.d.ts.map +1 -0
  83. package/dist/core/index.d.ts +1 -0
  84. package/dist/core/index.d.ts.map +1 -0
  85. package/dist/core/k-utils.d.ts +2 -0
  86. package/dist/core/k-utils.d.ts.map +1 -0
  87. package/dist/core/keybindings.d.ts +67 -0
  88. package/dist/core/keybindings.d.ts.map +1 -0
  89. package/dist/core/logger.d.ts +44 -0
  90. package/dist/core/logger.d.ts.map +1 -0
  91. package/dist/core/marketplaceregistry.d.ts +25 -0
  92. package/dist/core/marketplaceregistry.d.ts.map +1 -0
  93. package/dist/core/packageinfoservice.d.ts +16 -0
  94. package/dist/core/packageinfoservice.d.ts.map +1 -0
  95. package/dist/core/persistenceservice.d.ts +6 -0
  96. package/dist/core/persistenceservice.d.ts.map +1 -0
  97. package/dist/core/settingsservice.d.ts +19 -0
  98. package/dist/core/settingsservice.d.ts.map +1 -0
  99. package/dist/core/signals.d.ts +3 -0
  100. package/dist/core/signals.d.ts.map +1 -0
  101. package/dist/core/taskservice.d.ts +20 -0
  102. package/dist/core/taskservice.d.ts.map +1 -0
  103. package/dist/core/toast.d.ts +4 -0
  104. package/dist/core/toast.d.ts.map +1 -0
  105. package/dist/core/tree-utils.d.ts +16 -0
  106. package/dist/core/tree-utils.d.ts.map +1 -0
  107. package/dist/dialogs/confirm-dialog.d.ts +14 -0
  108. package/dist/dialogs/confirm-dialog.d.ts.map +1 -0
  109. package/dist/dialogs/index.d.ts +5 -0
  110. package/dist/dialogs/index.d.ts.map +1 -0
  111. package/dist/dialogs/info-dialog.d.ts +13 -0
  112. package/dist/dialogs/info-dialog.d.ts.map +1 -0
  113. package/dist/dialogs/navigable-info-dialog.d.ts +33 -0
  114. package/dist/dialogs/navigable-info-dialog.d.ts.map +1 -0
  115. package/dist/dialogs/prompt-dialog.d.ts +21 -0
  116. package/dist/dialogs/prompt-dialog.d.ts.map +1 -0
  117. package/dist/externals/lit.d.ts +20 -0
  118. package/dist/externals/lit.d.ts.map +1 -0
  119. package/dist/externals/lit.js +15 -0
  120. package/dist/externals/lit.js.map +1 -0
  121. package/dist/externals/third-party.d.ts +7 -0
  122. package/dist/externals/third-party.d.ts.map +1 -0
  123. package/dist/externals/third-party.js +2 -0
  124. package/dist/externals/third-party.js.map +1 -0
  125. package/dist/externals/webawesome.d.ts +1 -0
  126. package/dist/externals/webawesome.d.ts.map +1 -0
  127. package/dist/externals/webawesome.js +52 -0
  128. package/dist/externals/webawesome.js.map +1 -0
  129. package/dist/i18n/extensions.json.d.ts +42 -0
  130. package/dist/i18n/fastviews.json.d.ts +13 -0
  131. package/dist/i18n/filebrowser.json.d.ts +35 -0
  132. package/dist/i18n/index.d.ts +2 -0
  133. package/dist/i18n/index.d.ts.map +1 -0
  134. package/dist/i18n/logterminal.json.d.ts +45 -0
  135. package/dist/i18n/partname.json.d.ts +15 -0
  136. package/dist/i18n/tasks.json.d.ts +15 -0
  137. package/dist/i18n/workspace.json.d.ts +15 -0
  138. package/dist/index.d.ts +2 -0
  139. package/dist/index.d.ts.map +1 -0
  140. package/dist/index.js +80 -0
  141. package/dist/index.js.map +1 -0
  142. package/dist/k-icon-BZC7dQV0.js +492 -0
  143. package/dist/k-icon-BZC7dQV0.js.map +1 -0
  144. package/dist/k-nocontent-Bh_yToGh.js +48 -0
  145. package/dist/k-nocontent-Bh_yToGh.js.map +1 -0
  146. package/dist/k-resizable-grid-Ch3iWZaL.js +3157 -0
  147. package/dist/k-resizable-grid-Ch3iWZaL.js.map +1 -0
  148. package/dist/k-standard-layout-CQ1VZoxa.js +5011 -0
  149. package/dist/k-standard-layout-CQ1VZoxa.js.map +1 -0
  150. package/dist/layouts/k-standard-layout.d.ts +16 -0
  151. package/dist/layouts/k-standard-layout.d.ts.map +1 -0
  152. package/dist/parts/index.d.ts +1 -0
  153. package/dist/parts/index.d.ts.map +1 -0
  154. package/dist/parts/index.js +53 -0
  155. package/dist/parts/index.js.map +1 -0
  156. package/dist/parts/k-app.d.ts +11 -0
  157. package/dist/parts/k-app.d.ts.map +1 -0
  158. package/dist/parts/k-container.d.ts +4 -0
  159. package/dist/parts/k-container.d.ts.map +1 -0
  160. package/dist/parts/k-contextmenu.d.ts +38 -0
  161. package/dist/parts/k-contextmenu.d.ts.map +1 -0
  162. package/dist/parts/k-dialog-content.d.ts +9 -0
  163. package/dist/parts/k-dialog-content.d.ts.map +1 -0
  164. package/dist/parts/k-element.d.ts +36 -0
  165. package/dist/parts/k-element.d.ts.map +1 -0
  166. package/dist/parts/k-part.d.ts +96 -0
  167. package/dist/parts/k-part.d.ts.map +1 -0
  168. package/dist/parts/k-resizable-grid.d.ts +31 -0
  169. package/dist/parts/k-resizable-grid.d.ts.map +1 -0
  170. package/dist/parts/k-tabs.d.ts +74 -0
  171. package/dist/parts/k-tabs.d.ts.map +1 -0
  172. package/dist/parts/k-toolbar.d.ts +21 -0
  173. package/dist/parts/k-toolbar.d.ts.map +1 -0
  174. package/dist/widgets/index.d.ts +1 -0
  175. package/dist/widgets/index.d.ts.map +1 -0
  176. package/dist/widgets/index.js +3 -0
  177. package/dist/widgets/index.js.map +1 -0
  178. package/dist/widgets/k-icon.d.ts +10 -0
  179. package/dist/widgets/k-icon.d.ts.map +1 -0
  180. package/dist/widgets/k-nocontent.d.ts +13 -0
  181. package/dist/widgets/k-nocontent.d.ts.map +1 -0
  182. package/dist/widgets/k-widget.d.ts +25 -0
  183. package/dist/widgets/k-widget.d.ts.map +1 -0
  184. package/package.json +81 -0
  185. package/src/api/base-classes.ts +10 -0
  186. package/src/api/constants.ts +3 -0
  187. package/src/api/index.ts +31 -0
  188. package/src/api/services.ts +52 -0
  189. package/src/api/types.ts +46 -0
  190. package/src/commands/files.ts +829 -0
  191. package/src/commands/global.ts +225 -0
  192. package/src/commands/index.ts +4 -0
  193. package/src/commands/version-info.ts +214 -0
  194. package/src/components/index.ts +10 -0
  195. package/src/components/k-app-selector.ts +233 -0
  196. package/src/components/k-app-switcher.ts +126 -0
  197. package/src/components/k-command.ts +236 -0
  198. package/src/components/k-extensions.ts +615 -0
  199. package/src/components/k-fastviews.ts +314 -0
  200. package/src/components/k-filebrowser.ts +442 -0
  201. package/src/components/k-language-selector.ts +166 -0
  202. package/src/components/k-log-terminal.ts +337 -0
  203. package/src/components/k-part-name.ts +54 -0
  204. package/src/components/k-tasks.ts +267 -0
  205. package/src/components/k-workspace-name.ts +56 -0
  206. package/src/contributions/default-ui-contributions.ts +51 -0
  207. package/src/contributions/index.ts +3 -0
  208. package/src/contributions/marketplace-catalog-contributions.ts +6 -0
  209. package/src/core/app-host-config.ts +23 -0
  210. package/src/core/apploader.ts +630 -0
  211. package/src/core/appstate.ts +15 -0
  212. package/src/core/commandregistry.ts +210 -0
  213. package/src/core/config.ts +29 -0
  214. package/src/core/constants.ts +27 -0
  215. package/src/core/contributionregistry.ts +77 -0
  216. package/src/core/di.ts +54 -0
  217. package/src/core/dialogservice.ts +266 -0
  218. package/src/core/editorregistry.ts +303 -0
  219. package/src/core/esmsh-service.ts +404 -0
  220. package/src/core/events.ts +68 -0
  221. package/src/core/extensionregistry.ts +399 -0
  222. package/src/core/filesys.ts +618 -0
  223. package/src/core/i18n.ts +221 -0
  224. package/src/core/index.ts +51 -0
  225. package/src/core/k-utils.ts +11 -0
  226. package/src/core/keybindings.ts +274 -0
  227. package/src/core/logger.ts +187 -0
  228. package/src/core/marketplaceregistry.ts +197 -0
  229. package/src/core/packageinfoservice.ts +56 -0
  230. package/src/core/persistenceservice.ts +15 -0
  231. package/src/core/settingsservice.ts +70 -0
  232. package/src/core/signals.ts +18 -0
  233. package/src/core/taskservice.ts +72 -0
  234. package/src/core/toast.ts +11 -0
  235. package/src/core/tree-utils.ts +24 -0
  236. package/src/dialogs/confirm-dialog.ts +72 -0
  237. package/src/dialogs/index.ts +4 -0
  238. package/src/dialogs/info-dialog.ts +67 -0
  239. package/src/dialogs/navigable-info-dialog.ts +256 -0
  240. package/src/dialogs/prompt-dialog.ts +123 -0
  241. package/src/externals/lit.ts +26 -0
  242. package/src/externals/third-party.ts +9 -0
  243. package/src/externals/webawesome.ts +54 -0
  244. package/src/i18n/extensions.json +39 -0
  245. package/src/i18n/fastviews.json +10 -0
  246. package/src/i18n/filebrowser.json +33 -0
  247. package/src/i18n/index.ts +25 -0
  248. package/src/i18n/logterminal.json +42 -0
  249. package/src/i18n/partname.json +12 -0
  250. package/src/i18n/tasks.json +12 -0
  251. package/src/i18n/workspace.json +12 -0
  252. package/src/icons/icons.txt +3 -0
  253. package/src/icons/js.svg +6 -0
  254. package/src/icons/jupyter.svg +18 -0
  255. package/src/icons/python.svg +15 -0
  256. package/src/index.ts +3 -0
  257. package/src/layouts/k-standard-layout.ts +174 -0
  258. package/src/parts/index.ts +6 -0
  259. package/src/parts/k-app.ts +29 -0
  260. package/src/parts/k-container.ts +4 -0
  261. package/src/parts/k-contextmenu.ts +245 -0
  262. package/src/parts/k-dialog-content.ts +31 -0
  263. package/src/parts/k-element.ts +100 -0
  264. package/src/parts/k-part.ts +158 -0
  265. package/src/parts/k-resizable-grid.ts +366 -0
  266. package/src/parts/k-tabs.ts +574 -0
  267. package/src/parts/k-toolbar.ts +158 -0
  268. package/src/vite-env.d.ts +2 -0
  269. package/src/widgets/index.ts +2 -0
  270. package/src/widgets/k-icon.ts +39 -0
  271. package/src/widgets/k-nocontent.ts +40 -0
  272. 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
+ }