Skip to content

Commit cfe14f2

Browse files
authored
feat(tabs): Implement Shadow DOM isolation for non-editor tabs (#1260)
* feat: add editor tab isolation * fix * load stylesheet first
1 parent 5359da1 commit cfe14f2

File tree

1 file changed

+87
-5
lines changed

1 file changed

+87
-5
lines changed

src/lib/editorFile.js

Lines changed: 87 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import tile from "components/tile";
33
import confirm from "dialogs/confirm";
44
import fsOperation from "fileSystem";
55
import startDrag from "handlers/editorFileTab";
6+
import tag from "html-tag-js";
67
import mimeTypes from "mime-types";
78
import Path from "utils/Path";
89
import Url from "utils/Url";
@@ -49,6 +50,12 @@ export default class EditorFile {
4950
*/
5051
#content = null;
5152

53+
/**
54+
* Custom stylesheets for tab
55+
* @type {string|string[]}
56+
*/
57+
stylesheets;
58+
5259
/**
5360
* If editor was focused before resize
5461
*/
@@ -194,11 +201,47 @@ export default class EditorFile {
194201
if (options?.type) {
195202
this.#type = options.type;
196203
if (this.#type !== "editor") {
197-
const container = (
198-
<div className="tab-page-container">
199-
<div className="tab-page-content">{options.content}</div>
200-
</div>
201-
);
204+
const container = tag("div", {
205+
className: "tab-page-container",
206+
});
207+
208+
// shadow dom
209+
const shadow = container.attachShadow({ mode: "open" });
210+
211+
// main app styles
212+
const mainStyle = tag("link", {
213+
rel: "stylesheet",
214+
href: "./css/build/main.css",
215+
});
216+
// icon styles
217+
const iconStyle = tag("link", {
218+
rel: "stylesheet",
219+
href: "./res/icons/style.css",
220+
});
221+
// file icon styles
222+
const fileIconStyle = tag("link", {
223+
rel: "stylesheet",
224+
href: "./res/file-icons/style.css",
225+
});
226+
227+
// Add base styles to shadow DOM first
228+
shadow.appendChild(mainStyle);
229+
shadow.appendChild(iconStyle);
230+
shadow.appendChild(fileIconStyle);
231+
232+
// Handle custom stylesheets if provided
233+
if (options.stylesheets) {
234+
this.#addCustomStyles(options.stylesheets, shadow);
235+
}
236+
237+
const content = tag("div", {
238+
className: "tab-page-content",
239+
});
240+
content.appendChild(options.content);
241+
242+
// Append content container to shadow DOM
243+
shadow.appendChild(content);
244+
202245
this.#content = container;
203246
} else {
204247
this.#content = options.content;
@@ -838,6 +881,45 @@ export default class EditorFile {
838881
if (index > -1) events.splice(index, 1);
839882
}
840883

884+
/**
885+
* Add custom stylesheets to shadow DOM
886+
* @param {string|string[]} styles URLs or CSS strings
887+
* @param {ShadowRoot} shadow Shadow DOM root
888+
*/
889+
#addCustomStyles(styles, shadow) {
890+
if (typeof styles === "string") {
891+
styles = [styles];
892+
}
893+
894+
styles.forEach((style) => {
895+
if (style.startsWith("http") || style.startsWith("/")) {
896+
// External stylesheet
897+
const link = tag("link", {
898+
rel: "stylesheet",
899+
href: style,
900+
});
901+
shadow.appendChild(link);
902+
} else {
903+
// Inline CSS
904+
const styleElement = tag("style", {
905+
textContent: style,
906+
});
907+
shadow.appendChild(styleElement);
908+
}
909+
});
910+
}
911+
912+
/**
913+
* Add stylesheet to tab's shadow DOM
914+
* @param {string} style URL or CSS string
915+
*/
916+
addStyle(style) {
917+
if (this.#type === "editor" || !this.#content) return;
918+
919+
const shadow = this.#content.shadowRoot;
920+
this.#addCustomStyles(style, shadow);
921+
}
922+
841923
/**
842924
*
843925
* @param {FileAction} action

0 commit comments

Comments
 (0)