Add support for anchoring callouts to shadowDOM elements
Categories
(Firefox :: Sidebar, enhancement, P2)
Tracking
()
Tracking | Status | |
---|---|---|
firefox135 | --- | fixed |
People
(Reporter: fchasen, Assigned: kpatenio)
References
(Blocks 2 open bugs)
Details
(Whiteboard: [fidefe-RCSidebar])
Attachments
(1 file)
We are trying to anchor OMC messages to a tools moz-button to call out the functionality. :aminomancer request that we add a part
attribute to the buttons so they can target them using CSS like #sidebar-main > sidebar-main::part(sidebar-tool-COMMAND_ID)
.
Hoping we could a part="sidebar-tool-${action.view}
to the template in sidebar-main to enable that.
Updated•5 months ago
|
Comment 1•3 months ago
•
|
||
It looks like ::part()
will not actually work. It works in CSS and in Element.matches()
, but not in Element.querySelector()
.
Instead, I think we'll need to introduce a new system to FeatureCallout that allows traversing through the DOM in multiple steps, similar to this package. The anchor could then be written like this:
{
"selectors": [
"#sidebar-main > sidebar-main::%shadow% .tools-and-extensions[orientation='vertical']::%shadow% moz-button[view='review-checker']"
],
"panel_position": {
"anchor_attachment": "rightcenter",
"callout_attachment": "leftcenter"
}
}
This is better to some extent, since it doesn't run into the issue Katherine mentioned in the other bug. With the ::part()
selector, you can't interrogate anything else within the shadow tree or about the target, besides pseudo-classes. And I think reaching this button requires traversing two shadow trees rather than one, so we'd also need to use exportparts
if we used ::part()
. So not being able to use it might be lucky after all.
The get anchor code can parse out the individual components and manually traverse over them:
if (selector.includes("::%shadow%")) {
let parts = selector.split("::%shadow%");
for (let i = 0; i < parts.length; i++) {
selector = parts[i].trim();
if (i === parts.length - 1) {
break;
}
let el = scope.querySelector(selector);
if (!el) {
break;
}
if (el.shadowRoot) {
scope = el.shadowRoot;
}
}
}
let element = scope.querySelector(selector);
if (!element && scope.matches?.(selector)) {
element = scope;
}
Reporter | ||
Updated•2 months ago
|
Updated•2 months ago
|
Updated•2 months ago
|
Description
•