diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1cb1734..523612d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -61,6 +61,11 @@ jobs: - run: deno install - run: npx playwright install chromium - run: deno task vitest --run + - uses: actions/upload-artifact@v4 + if: failure() + with: + name: screenshots + path: src/higlass/__screenshots__/ TypecheckJavaScript: name: JavaScript / Typecheck diff --git a/src/higlass/widget.js b/src/higlass/widget.js index 66e72aa..6d108ec 100644 --- a/src/higlass/widget.js +++ b/src/higlass/widget.js @@ -1,4 +1,4 @@ -import * as hglib from "https://esm.sh/higlass@1.13?deps=react@17,react-dom@17,pixi.js@6"; +import * as hglib from "https://esm.sh/higlass@2.2.3?deps=react@17,react-dom@17,pixi.js@6"; import { v4 } from "https://esm.sh/@lukeed/uuid@2.0.1"; /** @import { AnyModel } from "@anywidget/types" */ @@ -6,6 +6,9 @@ import { v4 } from "https://esm.sh/@lukeed/uuid@2.0.1"; const NAME = "jupyter"; +let HIGLASS_STYLES = new CSSStyleSheet(); +HIGLASS_STYLES.replaceSync(hglib.CSS); + /** * @param {string} href * @returns {Promise} @@ -275,7 +278,10 @@ function addEventListenersTo(el) { }); // prevent wheel events from scrolling the page while allowing HiGlass zoom - el.addEventListener("wheel", (event) => event.stopPropagation(), { + el.addEventListener("wheel", (event) => { + event.preventDefault(); + event.stopPropagation(); + }, { signal: controller.signal, passive: false, }); @@ -303,28 +309,45 @@ export default { model.get("_viewconf"), ); let options = model.get("_options") ?? {}; - let api = await hglib.viewer(el, viewconf, options); + + let shadow = el.shadowRoot ?? el.attachShadow({ mode: "open" }); + shadow.innerHTML = ""; + shadow.adoptedStyleSheets = [HIGLASS_STYLES]; + let container = document.createElement("div"); + shadow.appendChild(container); + + let api = await hglib.viewer(container, viewconf, options); let unlisten = addEventListenersTo(el); model.on("msg:custom", (msg) => { msg = JSON.parse(msg); let [fn, ...args] = msg; - api[fn](...args); + /** @type {any} */ (api)[fn](...args); }); if (viewconf.views.length === 1) { - api.on("location", (/** @type {GenomicLocation} */ loc) => { - model.set("location", locationToCoordinates(loc)); - model.save_changes(); - }, viewconf.views[0].uid); + api.on( + "location", + (/** @type {GenomicLocation} */ loc) => { + model.set("location", locationToCoordinates(loc)); + model.save_changes(); + }, + viewconf.views[0].uid, + undefined, + ); } else { viewconf.views.forEach((view, idx) => { - api.on("location", (/** @type{GenomicLocation} */ loc) => { - let location = model.get("location").slice(); - location[idx] = locationToCoordinates(loc); - model.set("location", location); - model.save_changes(); - }, view.uid); + api.on( + "location", + (/** @type{GenomicLocation} */ loc) => { + let location = model.get("location").slice(); + location[idx] = locationToCoordinates(loc); + model.set("location", location); + model.save_changes(); + }, + view.uid, + undefined, + ); }); } diff --git a/src/higlass/widget.test.ts b/src/higlass/widget.test.ts index c7934a6..f3239a1 100644 --- a/src/higlass/widget.test.ts +++ b/src/higlass/widget.test.ts @@ -58,8 +58,8 @@ test("render creates a HiGlass viewer with a simple viewconf", async () => { const cleanup = await widget.render({ model, el, experimental }); - // resolved without throwing; container has content - expect(el.children.length).toBeGreaterThan(0); + // resolved without throwing; shadow root has content + expect(el.shadowRoot?.children.length).toBeGreaterThan(0); expect(typeof cleanup).toBe("function"); cleanup?.();