Skip to content

Commit 0bd8743

Browse files
authored
Use a simpler but more effective shadow DOM workaround (#95)
1 parent 1489fb6 commit 0bd8743

File tree

2 files changed

+26
-56
lines changed

2 files changed

+26
-56
lines changed

ipywidgets_bokeh/src/widget.ts

Lines changed: 25 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ import {UIElement} from "@bokehjs/models/ui/ui_element"
44
import {Document} from "@bokehjs/document"
55
import {MessageSentEvent} from "@bokehjs/document/events"
66
import * as p from "@bokehjs/core/properties"
7-
import {isString, isObject} from "@bokehjs/core/util/types"
7+
import {isString} from "@bokehjs/core/util/types"
88
import {assert} from "@bokehjs/core/util/assert"
9-
import {values} from "@bokehjs/core/util/object"
109

1110
import {generate_require_loader} from "./loader"
1211
import {WidgetManager, ModelBundle} from "./manager"
@@ -15,27 +14,6 @@ import {WidgetView} from "@jupyter-widgets/base"
1514

1615
const widget_managers: WeakMap<Document, WidgetManager> = new WeakMap()
1716

18-
declare type Module = {
19-
id: string
20-
loaded: boolean
21-
exports: {[key: string]: unknown}
22-
}
23-
24-
declare type UseOptions = {
25-
handler?(css: string): void
26-
}
27-
28-
declare type StyleModule = Module & {
29-
exports: {
30-
default: {
31-
use(options?: UseOptions): void
32-
unuse(): void
33-
}
34-
}
35-
}
36-
37-
declare const __webpack_module_cache__: {[key: string]: Module}
38-
3917
export class IPyWidgetView extends LayoutDOMView {
4018
container: HTMLDivElement
4119
override model: IPyWidget
@@ -47,29 +25,32 @@ export class IPyWidgetView extends LayoutDOMView {
4725
return []
4826
}
4927

50-
protected _ipy_stylesheets(): StyleSheetLike[] {
51-
const stylesheets: StyleSheetLike[] = []
28+
override connect_signals(): void {
29+
super.connect_signals()
5230

53-
function handler(raw_css: string): void {
54-
const css = raw_css.replace(/:root/g, ":host")
55-
stylesheets.push(new InlineStyleSheet(css))
56-
}
57-
58-
function is_StyleModule(module: Module): module is StyleModule {
59-
const {exports} = module
60-
return isObject(exports.default) && "use" in exports.default
61-
}
31+
const observer = new MutationObserver((mutations) => {
32+
for (const mutation of mutations) {
33+
for (const node of [...mutation.addedNodes, ...mutation.removedNodes]) {
34+
if (node instanceof HTMLStyleElement) {
35+
this._update_stylesheets()
36+
break
37+
}
38+
}
39+
}
40+
})
41+
observer.observe(document.head, {childList: true})
42+
}
6243

63-
const modules = values(__webpack_module_cache__)
64-
const css_modules = modules.filter(({id, exports}) => id.endsWith(".css") && "default" in exports)
65-
const style_modules = css_modules.filter(is_StyleModule)
44+
protected _ipy_stylesheets(): StyleSheetLike[] {
45+
const stylesheets: StyleSheetLike[] = []
6646

67-
for (const module of style_modules) {
68-
const style = module.exports.default
69-
try {
70-
style.use({handler})
71-
} catch {
72-
console.error("failed to apply a stylesheet")
47+
for (const child of document.head.children) {
48+
if (child instanceof HTMLStyleElement) {
49+
const raw_css = child.textContent
50+
if (raw_css != null) {
51+
const css = raw_css.replace(/:root/g, ":host")
52+
stylesheets.push(new InlineStyleSheet(css))
53+
}
7354
}
7455
}
7556

@@ -82,7 +63,7 @@ export class IPyWidgetView extends LayoutDOMView {
8263

8364
override render(): void {
8465
super.render()
85-
this.container = div({style: "display: contents;"})
66+
this.container = div({style: "display: contents;"}) // ipywidgets' APIs require HTMLElement, not DocumentFragment
8667
this.shadow_el.append(this.container)
8768
this._render().then(() => {
8869
this.invalidate_layout() // TODO: this may be overzealous; probably should be removed

ipywidgets_bokeh/webpack.config.js

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,8 @@
11
const path = require("path");
22
const version = require('./package.json').version;
33

4-
const style_loader = {
5-
loader: "style-loader",
6-
options: {
7-
injectType: "lazyStyleTag",
8-
insert: (element, options) => {},
9-
styleTagTransform: (css, style, options) => {
10-
options.handler(css)
11-
},
12-
},
13-
}
14-
154
const rules = [
16-
{ test: /\.css$/, use: [style_loader, "css-loader"] },
5+
{ test: /\.css$/, use: ["style-loader", "css-loader"] },
176
// required to load font-awesome
187
{ test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, use: "url-loader?limit=10000&mimetype=application/font-woff" },
198
{ test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, use: "url-loader?limit=10000&mimetype=application/font-woff" },

0 commit comments

Comments
 (0)