fix(webui): position sidebar highlight on mount
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
import {
|
||||
type HTMLAttributes,
|
||||
type RefObject,
|
||||
useLayoutEffect,
|
||||
useRef,
|
||||
} from "react";
|
||||
|
||||
interface SidebarSelectionHighlightProps {
|
||||
containerRef: RefObject<HTMLElement>;
|
||||
interface SidebarSelectionHighlightProps extends HTMLAttributes<HTMLDivElement> {
|
||||
targetRef: RefObject<HTMLElement>;
|
||||
activeId: string | null;
|
||||
scope: string;
|
||||
@@ -18,11 +18,13 @@ export const SIDEBAR_SELECTION_ACTION_ITEM_CLASS =
|
||||
"relative z-[1] transition-[width,padding,color] [transition-duration:300ms,300ms,150ms] ease-out motion-reduce:transition-none";
|
||||
|
||||
export function SidebarSelectionHighlight({
|
||||
containerRef,
|
||||
targetRef,
|
||||
activeId,
|
||||
scope,
|
||||
children,
|
||||
...containerProps
|
||||
}: SidebarSelectionHighlightProps) {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const highlightRef = useRef<HTMLDivElement>(null);
|
||||
const positionedRef = useRef(false);
|
||||
|
||||
@@ -30,11 +32,19 @@ export function SidebarSelectionHighlight({
|
||||
const highlight = highlightRef.current;
|
||||
const container = containerRef.current;
|
||||
const target = targetRef.current;
|
||||
if (!highlight) return;
|
||||
if (!activeId || !container || !target) {
|
||||
highlight.style.opacity = "0";
|
||||
positionedRef.current = false;
|
||||
return;
|
||||
}
|
||||
|
||||
let restoreTransitionFrame: number | null = null;
|
||||
|
||||
const position = () => {
|
||||
if (!highlight) return;
|
||||
if (!activeId || !container || !target) {
|
||||
const containerRect = container.getBoundingClientRect();
|
||||
const targetRect = target.getBoundingClientRect();
|
||||
if (targetRect.width === 0 || targetRect.height === 0) {
|
||||
highlight.style.opacity = "0";
|
||||
positionedRef.current = false;
|
||||
return;
|
||||
@@ -43,8 +53,6 @@ export function SidebarSelectionHighlight({
|
||||
const firstPosition = !positionedRef.current;
|
||||
if (firstPosition) highlight.style.transitionProperty = "none";
|
||||
|
||||
const containerRect = container.getBoundingClientRect();
|
||||
const targetRect = target.getBoundingClientRect();
|
||||
highlight.style.width = `${targetRect.width}px`;
|
||||
highlight.style.height = `${targetRect.height}px`;
|
||||
highlight.style.transform = `translate3d(${targetRect.left - containerRect.left}px, ${
|
||||
@@ -64,8 +72,8 @@ export function SidebarSelectionHighlight({
|
||||
position();
|
||||
const resizeObserver =
|
||||
typeof ResizeObserver === "undefined" ? null : new ResizeObserver(position);
|
||||
if (container) resizeObserver?.observe(container);
|
||||
if (target) resizeObserver?.observe(target);
|
||||
resizeObserver?.observe(container);
|
||||
resizeObserver?.observe(target);
|
||||
window.addEventListener("resize", position);
|
||||
|
||||
return () => {
|
||||
@@ -79,12 +87,15 @@ export function SidebarSelectionHighlight({
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={highlightRef}
|
||||
data-testid={`${scope}-selection-highlight`}
|
||||
data-active-id={activeId ?? undefined}
|
||||
aria-hidden="true"
|
||||
className="pointer-events-none absolute left-0 top-0 z-0 !mt-0 rounded-xl bg-sidebar-foreground/[0.055] opacity-0 transition-[transform,width,height] duration-300 ease-out will-change-transform motion-reduce:transition-none dark:bg-white/[0.07]"
|
||||
/>
|
||||
<div {...containerProps} ref={containerRef}>
|
||||
{children}
|
||||
<div
|
||||
ref={highlightRef}
|
||||
data-testid={`${scope}-selection-highlight`}
|
||||
data-active-id={activeId ?? undefined}
|
||||
aria-hidden="true"
|
||||
className="pointer-events-none absolute left-0 top-0 z-0 !mt-0 rounded-xl bg-sidebar-foreground/[0.055] opacity-0 transition-[transform,width,height] duration-300 ease-out will-change-transform motion-reduce:transition-none dark:bg-white/[0.07]"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user