frontend: move hive-menu's reachable dropdown/trigger chrome out of the caller stylesheet
Per mara's review on #2881: the dropdown box chrome (background/border/ radius/shadow/min-width/white-space) and the trigger button's base icon-button treatment are both reachable from hive-menu.css now -- the box chrome lives on hive-menu's own shadow-owned .menu-dropdown wrapper (no slotting constraint at all), and the trigger button is styled via ::slotted([slot='trigger']) since it's the top-level slotted node for that slot. Item-row styling stays in the caller's stylesheet -- ::slotted() only reaches directly-slotted elements, not their descendants, so individual dropdown items are architecturally unreachable from hive-menu's shadow tree. Verified interactively via headless Chromium/CDP: trigger opacity/hover/border-radius and the dropdown wrapper's background/border all resolve correctly, hover and click-to-open still work.
This commit is contained in:
parent
395c9a6df2
commit
8ebefeb0d5
2 changed files with 54 additions and 47 deletions
|
|
@ -298,41 +298,22 @@ hive-agent-menu {
|
|||
align-self: flex-start;
|
||||
margin-top: 0.3em;
|
||||
}
|
||||
.agent-menu-btn {
|
||||
display: block;
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--subtext0);
|
||||
font-size: 1.1em;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
padding: 0.1em 0.4em;
|
||||
border-radius: 4px;
|
||||
opacity: var(--menu-btn-opacity, 0);
|
||||
transition: opacity 120ms, background 120ms, color 120ms;
|
||||
}
|
||||
.agent-menu-btn:hover,
|
||||
.agent-menu-btn:focus-visible {
|
||||
background: color-mix(in srgb, var(--purple) 10%, transparent);
|
||||
color: var(--purple);
|
||||
outline: none;
|
||||
}
|
||||
.agent-menu-btn:focus-visible {
|
||||
outline: 1px solid var(--purple);
|
||||
}
|
||||
/* Positioning (`position`/`top`/`right`/`z-index`) is generic and lives
|
||||
on `<hive-menu>`'s own `.menu-dropdown` wrapper instead — this is just
|
||||
the item list's visual chrome. */
|
||||
/* .agent-menu-btn carries no styling of its own anymore — the trigger is
|
||||
a top-level `slot="trigger"` node inside <hive-menu>'s shadow tree, so
|
||||
its base icon-button chrome now lives in hive-menu.css's
|
||||
`::slotted([slot='trigger'])` rules instead (reachable and genuinely
|
||||
generic — any <hive-menu> trigger gets the same treatment). The class
|
||||
itself stays, just as an identification hook (aria-label/title
|
||||
already carry the real semantics). */
|
||||
/* Box chrome (background/border/radius/shadow/min-width/white-space) now
|
||||
lives on <hive-menu>'s own `.menu-dropdown` wrapper (shadow-DOM-owned
|
||||
markup, no slotting constraint) — this is just the `<ul>`'s own
|
||||
list-reset + item padding, which only the caller (owning the actual
|
||||
list markup) can set. */
|
||||
.agent-menu-dropdown {
|
||||
background: var(--bg-elev);
|
||||
border: 1px solid var(--purple-dim);
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0.3em 0;
|
||||
min-width: 10em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.agent-menu-item {
|
||||
display: block;
|
||||
|
|
|
|||
|
|
@ -4,22 +4,17 @@
|
|||
inside the shadow root — see @hive/shared/shadow-css.js's header
|
||||
comment for why a plain <style> tag and not adoptedStyleSheets.
|
||||
|
||||
`:host` carries only the one truly generic requirement: it's the
|
||||
containing block for the shadow tree's absolutely-positioned dropdown
|
||||
— a shadow host is the containing block for its own shadow tree's
|
||||
positioned descendants, exactly like any other positioned ancestor in
|
||||
the flat tree. Any *layout* role the host plays in a particular
|
||||
caller's own flex row (e.g. <hive-agent-menu>'s placement in
|
||||
`.container-row`) is caller-specific and lives in the caller's own
|
||||
stylesheet instead, not here.
|
||||
|
||||
`.menu-dropdown` is the generic positioning box wrapping the caller's
|
||||
opaque `content` node (projected in via `<slot name="content">` — see
|
||||
hive-menu.js). Only position/z-index/visibility live here; the
|
||||
button/item-row *visual* styling (colors, fonts, hover states) is
|
||||
presentational content the caller's own trigger/content nodes carry,
|
||||
so it lives in the caller's own stylesheet — `<hive-menu>` never sees
|
||||
those class names, only the opaque nodes handed to it. */
|
||||
Two kinds of rules live here, split by what they can actually reach:
|
||||
`:host`/`.menu-dropdown` style shadow-DOM-owned markup this element
|
||||
builds itself (no slotting constraint at all); `::slotted(...)` rules
|
||||
reach the caller's *top-level* trigger/content nodes (the ones with a
|
||||
`slot` attribute) since those are true light-DOM children, just
|
||||
rendered here. What can NOT live here: anything inside the content
|
||||
node (e.g. individual dropdown item rows) — `::slotted()` only
|
||||
matches directly-slotted elements, not their descendants, and no CSS
|
||||
mechanism pierces further than that. That's a hard Shadow DOM
|
||||
architecture limit, not a scope choice — item-level styling stays in
|
||||
the caller's own stylesheet regardless of how generic it looks. */
|
||||
|
||||
:host {
|
||||
position: relative;
|
||||
|
|
@ -29,4 +24,35 @@
|
|||
right: 0;
|
||||
top: calc(100% + 2px);
|
||||
z-index: 50;
|
||||
background: var(--bg-elev);
|
||||
border: 1px solid var(--purple-dim);
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
|
||||
min-width: 10em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
/* The trigger is the top-level `slot="trigger"` node — reachable, so its
|
||||
base icon-button chrome (invisible until hover/open, via
|
||||
`--menu-btn-opacity`) lives here rather than duplicated per caller. */
|
||||
::slotted([slot='trigger']) {
|
||||
display: block;
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--subtext0);
|
||||
font-size: 1.1em;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
padding: 0.1em 0.4em;
|
||||
border-radius: 4px;
|
||||
opacity: var(--menu-btn-opacity, 0);
|
||||
transition: opacity 120ms, background 120ms, color 120ms;
|
||||
}
|
||||
::slotted([slot='trigger']:hover),
|
||||
::slotted([slot='trigger']:focus-visible) {
|
||||
background: color-mix(in srgb, var(--purple) 10%, transparent);
|
||||
color: var(--purple);
|
||||
outline: none;
|
||||
}
|
||||
::slotted([slot='trigger']:focus-visible) {
|
||||
outline: 1px solid var(--purple);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue