You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Lumino can be used in situations where there are hundreds of thousands of nodes, and where stylesheets from different providers are attached at the same time. Limiting the stylesheet applicability to a specific subset of nodes is possible with two approaches:
Lumino currently does not support shadow DOM in the sense that individual widgets cannot be moved to shadow DOM and there are no methods exposed allowing to attach stylesheets to specific widgets/shadow DOM roots.
Proposed Solution
Note: If you have not worked with shadow DOM before please see the details below to understand why the solution (2) wraps the shadow root into another <div>.
DOM nodes can be moved to the shadow DOM by attaching them to a transient shadow DOM root which is attached to another DOM node. There can ever be only one shadow DOM root in each DOM element:
At widget attachment, check if node of the node of the parent widget hosts a shadow root and if it does, attaching to the shadow root instead of the parent node itself:
Separate Widget.node and Widget.attachmentNode; by default Widget.attachmentNode would be just an alias for Widget.node but when a widget is instructed to wrap itself into shadow DOM, it would point to the ShadowRoot (but wrapped into a translucent div to avoid the issue of multiple-roots)
the problem with this approach is that it requires rewritting CSS styles since the widget.node is no longer a direct descendant of its parent (lm-translucentWrapper is).
Using Proxy to create Frankenstein-kind hybrid of ShadowRoot and HTMLElement and keeping node without changes: this does not work because native code in insertBefore and friends does not accept non-native nodes (strict class checks are performed at runtime so even if the proxy quacks like a perfect node, it will be rejected).
Then we could either:
a) allow each widget to be moved into shadow DOM via a new option in constructor, or
b) provide a subclass of Widget say ShadowWidget which would put its node into shadow DOM.
Further we would need to be consider how to handle CSS stylesheets. Widgets could have a method like:
classWidget{/** * Adopt a constructed CSS stylesheet for the use in shadow DOM. * Is a no-op if the widget is not a shadow DOM root. * @returns whether the stylesheet was successfully adopted. */adoptStyleSheet(stylesheet: CSSStyleSheet): boolean{if(!this.options.shadowDOM){returnfalse;}// not needed in (b)this.node.shadowRoot.adoptedStyleSheets.push(stylesheet);returntrue;}}
I am slightly leaning towards 2a as that would allow us to enable shadow DOM downstream by changing the options without a need to duplicate class definitions. The separation of node and attachmentNode could be introduced in Lumino 2.0 whether we decide to proceed with the shadow DOM implementation or not.
Additional context
I was able to set it up in JupyterLab and created a code snipped to copy all stylesheets for adoption in widgets, thus limiting the performance benefits to containing style changes to nodes within the shadow DOM but still using all styles; this is super preliminary and I will update if I get a chance to perform a proper benchmark:
I saw very little performance benefits when moving MainAreaWidget to shadow DOM
I saw more performance benefits when moving the entire DockLayout to shadow DOM
My confidence in the results above is low. I expect that gains will differ depending on the browser.
The text was updated successfully, but these errors were encountered:
One place where shadow DOM wrappers could be very useful (performance aside) are CellOutput widgets in JupyterLab; this would allow outputs to add any CSS stylesheet they want without breaking the JupyterLab styling (on the other hand it would prevent them from modifying the theme which is probably a good thing security-wise).
Problem
Lumino can be used in situations where there are hundreds of thousands of nodes, and where stylesheets from different providers are attached at the same time. Limiting the stylesheet applicability to a specific subset of nodes is possible with two approaches:
Lumino currently does not support shadow DOM in the sense that individual widgets cannot be moved to shadow DOM and there are no methods exposed allowing to attach stylesheets to specific widgets/shadow DOM roots.
Proposed Solution
Note: If you have not worked with shadow DOM before please see the details below to understand why the solution (2) wraps the shadow root into another
<div>
.DOM nodes can be moved to the shadow DOM by attaching them to a transient shadow DOM root which is attached to another DOM node. There can ever be only one shadow DOM root in each DOM element:
This is allowed:
This is forbidden (multiple shadow roots were removed from the specification in 2015):
The solutions I considered are:
Widget.node
andWidget.attachmentNode
; by defaultWidget.attachmentNode
would be just an alias forWidget.node
but when a widget is instructed to wrap itself into shadow DOM, it would point to the ShadowRoot (but wrapped into a translucent div to avoid the issue of multiple-roots)widget.node
is no longer a direct descendant of its parent (lm-translucentWrapper
is).Proxy
to create Frankenstein-kind hybrid ofShadowRoot
andHTMLElement
and keepingnode
without changes: this does not work because native code ininsertBefore
and friends does not accept non-native nodes (strict class checks are performed at runtime so even if the proxy quacks like a perfect node, it will be rejected).Then we could either:
ShadowWidget
which would put its node into shadow DOM.Further we would need to be consider how to handle CSS stylesheets. Widgets could have a method like:
I am slightly leaning towards 2a as that would allow us to enable shadow DOM downstream by changing the options without a need to duplicate class definitions. The separation of
node
andattachmentNode
could be introduced in Lumino 2.0 whether we decide to proceed with the shadow DOM implementation or not.Additional context
I was able to set it up in JupyterLab and created a code snipped to copy all stylesheets for adoption in widgets, thus limiting the performance benefits to containing style changes to nodes within the shadow DOM but still using all styles; this is super preliminary and I will update if I get a chance to perform a proper benchmark:
MainAreaWidget
to shadow DOMDockLayout
to shadow DOMMy confidence in the results above is low. I expect that gains will differ depending on the browser.
The text was updated successfully, but these errors were encountered: