diff --git a/crates/rustmotion-studio/src/components/color_picker/style.css b/crates/rustmotion-studio/src/components/color_picker/style.css index 2566bf1..85748dd 100644 --- a/crates/rustmotion-studio/src/components/color_picker/style.css +++ b/crates/rustmotion-studio/src/components/color_picker/style.css @@ -187,7 +187,10 @@ position: fixed; z-index: 1000; top: auto; - right: 308px; + /* Right edge approaches the LEFT edge of the clicked swatch (not the + panel edge). Constant per host context via --picker-anchor-right: + panel 300 − swatch-left-offset + 8px gap. Fallback = standard rows. */ + right: var(--picker-anchor-right, 210px); left: auto; display: block; border-radius: 0.5rem; @@ -197,6 +200,12 @@ box-shadow: inset 0 0 0 1px var(--rm-border), 0 8px 24px rgba(0, 0, 0, 0.35); + /* Lift so the popover TOP aligns with its trigger row's top: the static + position puts it below the swatch → up by swatch height (2rem = 32px) + + margin-top (4px) = 36px. A transform on the positioned element + itself is fine (only ANCESTOR transforms hijack fixed). */ + --picker-lift: -36px; + transform: translateY(var(--picker-lift)); } .dx-color-picker-popover[data-state="open"] { @@ -208,27 +217,29 @@ pointer-events: none; } +/* The fade keyframes COMPOSE with the lift (an animation's transform would + otherwise override the base one and make the box jump at animation end). */ @keyframes dx-color-picker-popover-fade-in { from { opacity: 0; - transform: translateY(-4px); + transform: translateY(calc(var(--picker-lift) - 4px)); } to { opacity: 1; - transform: translateY(0); + transform: translateY(var(--picker-lift)); } } @keyframes dx-color-picker-popover-fade-out { from { opacity: 1; - transform: translateY(0); + transform: translateY(var(--picker-lift)); } to { opacity: 0; - transform: translateY(-4px); + transform: translateY(calc(var(--picker-lift) - 4px)); } } diff --git a/crates/rustmotion-studio/src/editor/inspector.rs b/crates/rustmotion-studio/src/editor/inspector.rs index a3128c2..30bc84b 100644 --- a/crates/rustmotion-studio/src/editor/inspector.rs +++ b/crates/rustmotion-studio/src/editor/inspector.rs @@ -616,7 +616,10 @@ pub fn InspectorPanel( let fam = family(&kind); rsx! { div { - style: "width:300px; flex:none; min-height:0; background:var(--rm-surface); border-left:1px solid var(--rm-border); box-sizing:border-box; display:flex; flex-direction:column; overflow:auto;", + // --picker-anchor-right: popover right-edge offset so it hugs the + // swatch's left edge. Standard rows: 300 − (14 section padding + + // 76 label + 8 gap) + 8 gap = 210px. Object sub-rows override it. + style: "width:300px; flex:none; min-height:0; background:var(--rm-surface); border-left:1px solid var(--rm-border); box-sizing:border-box; display:flex; flex-direction:column; overflow:auto; --picker-anchor-right:210px;", // The open picker popover is `position:fixed` at its trigger's // static position: it doesn't follow the panel scroll, so close // it when the panel scrolls (standard dropdown behavior). @@ -1536,7 +1539,10 @@ fn ObjectControl( }; rsx! { - div { style: "display:flex; flex-direction:column; gap:6px; width:100%; padding-left:10px; border-left:2px solid var(--rm-border-2);", + // Sub-rows are indented (10px padding + 2px border) and re-nest a + // 76px label + 8px gap: swatch sits at 98 + 12 + 84 = 194 from the + // panel's left → --picker-anchor-right: 300 − 194 + 8 = 114px. + div { style: "display:flex; flex-direction:column; gap:6px; width:100%; padding-left:10px; border-left:2px solid var(--rm-border-2); --picker-anchor-right:114px;", for spec in specs { GenericRow { key: "{pointer}-{name}-{spec.name}",