useActiveIndicatoruseActiveIndicator

트랙 안에서 활성 항목의 위치를 재서 인디케이터를 슬라이드할 수 있게 합니다.Measure the active item inside a track so one indicator can slide between items.

사용법Usage

tabs.tsx
import { useRef } from "react";

import { useActiveIndicator } from "@horon-ai/react";

function Tabs({ items, value }: { items: string[]; value: string }) {
  const track = useRef<HTMLDivElement>(null);
  const { rect, animate } = useActiveIndicator(track, '[aria-current="page"]');
  return (
    <div ref={track} className="relative flex gap-1">
      {items.map((item) => (
        <button key={item} aria-current={item === value ? "page" : undefined}>
          {item}
        </button>
      ))}
      <span
        aria-hidden
        className={animate ? "pointer-events-none absolute rounded-full motion-indicator" : "pointer-events-none absolute rounded-full"}
        style={{ ...rect, opacity: rect ? 1 : 0 }}
      />
    </div>
  );
}

시그니처Signature

use-active-indicator.ts
export type IndicatorRect = {
  left: number;
  top: number;
  width: number;
  height: number;
};

export function useActiveIndicator(
  track: RefObject<HTMLElement | null>,
  selector: string,
): { rect: IndicatorRect | null; animate: boolean }

매개변수Parameters

이름Name 타입Type 기본값Default 설명Description
track RefObject<HTMLElement | null> - 항목을 담은 위치 지정 트랙 요소의 ref입니다.Ref to the positioned track element that holds the items.
selector string - 트랙 안에서 활성 항목을 찾는 CSS 선택자입니다. 항목이 없으면 rect가 null이 됩니다.CSS selector for the active item, queried inside the track; a missing item yields a null rect.

반환값Returns

측정한 rect와 첫 프레임용 animate 플래그를 돌려줍니다. rect는 첫 측정 전까지 null입니다.The measured rect (or null before the first measurement) and an animate flag for the first frame.

동작과 주의Behavior notes

  • rect의 네 값은 활성 항목의 offsetLeft, offsetTop, offsetWidth, offsetHeight에서 읽습니다.The four rect values come from the active item's offsetLeft, offsetTop, offsetWidth and offsetHeight.
  • 측정은 레이아웃 이펙트에서 하므로 서버 렌더는 인디케이터를 그리지 않습니다. 첫 클라이언트 패스에서 페인트 전에 자리를 잡고, animate는 그때까지 false입니다.Measuring happens in a layout effect, so a server render draws no indicator: rect starts null, and the first client pass places the item before paint while animate stays false.
  • rect는 속성 변화와 크기 변화를 따라갑니다. 트랙과 그 자식에 ResizeObserver를, 트랙의 속성과 하위 트리, 자식 목록에 MutationObserver를 겁니다.The rect follows attribute changes and resizes: a ResizeObserver watches the track and its children, a MutationObserver watches attributes, the subtree and the child list.
  • animate는 첫 배치 다음 프레임에 true가 되어 인디케이터가 0,0에서 미끄러져 들어오지 않고 제자리에 나타납니다.animate turns true one frame after the first placement, so the indicator lands in place instead of sliding in from 0,0.