# useIconColor URL: /lynx/hooks/use-icon-color Source: https://github.com/daangn/seed-design/blob/dev/docs/content/lynx/hooks/use-icon-color.mdx Lynx image 아이콘의 CSS color를 native tint-color로 동기화하는 훅입니다. 사용 가능 버전: @seed-design/lynx-react@0.1.0 ## Import ```ts import { useIconColor } from "@seed-design/lynx-react"; ``` `useIconColor`는 `@seed-design/lynx-react` 패키지에 포함되어 있습니다. 주로 SEED Lynx 컴포넌트가 monochrome icon을 슬롯에 주입할 때 사용합니다. ## Usage ### 기본 사용 ```tsx import { cloneElement, isValidElement, type ReactElement } from "react"; import { useMainThreadRef } from "@lynx-js/react"; import { useIconColor } from "@seed-design/lynx-react"; function IconSlot({ icon, variant, disabled }: { icon: ReactElement; variant: string; disabled: boolean; }) { const wrapperRef = useMainThreadRef(null); const iconColorProps = useIconColor([variant, disabled], { sourceRef: wrapperRef }); if (!isValidElement(icon)) return null; return ( {cloneElement(icon, { ...iconColorProps, style: { width: "100%", height: "100%" }, })} ); } ``` `useIconColor`가 반환하는 객체는 icon element에 그대로 주입할 수 있는 props입니다. `sourceRef`를 전달하면 wrapper의 computed `color`를 읽어 icon ``의 `tint-color`에 반영합니다. 기존처럼 `sourceRef` 없이 쓰면 icon element 자신의 computed `color`를 읽습니다. ### 상태 의존성 ```tsx const iconColorProps = useIconColor([ variant, disabled, loading, checked, pressed, tone, size, ]); ``` `deps`에는 icon의 CSS `color`에 영향을 줄 수 있는 값을 모두 포함합니다. 예를 들어 ActionButton은 `variant`, `disabled`, `loading`을 포함하고, Checkbox와 RadioGroup indicator는 `checked`, `pressed`, `tone`, `size`처럼 indicator 색상에 영향을 주는 상태를 함께 포함합니다. ## 왜 필요한가 Lynx의 monochrome icon은 내부적으로 ``를 렌더링하고, 실제 아이콘 색상은 native `tint-color` attribute로 적용됩니다. 반면 SEED recipe는 slot className에 CSS `color`를 선언합니다. ```css .seed-action-button__icon { color: var(--seed-color-palette-static-white); } ``` 웹에서는 SVG나 CSS `currentColor` 패턴으로 이 색상을 자연스럽게 사용할 수 있지만, Lynx ``의 `tint-color` 경로에서는 CSS variable 문자열을 직접 넣는 방식이 안정적으로 동작하지 않습니다. 따라서 `useIconColor`는 main thread에서 computed `color`를 읽고, resolved color를 `tint-color` attribute에 반영합니다. ## 동작 방식 `useIconColor`는 두 시점에 같은 동기화를 수행합니다. 1. `deps`가 바뀐 뒤 React effect에서 `runOnMainThread`로 동기화합니다. 2. icon의 UI 노드가 appear 될 때 `main-thread:binduiappear`에서 한 번 더 동기화합니다. 두 번째 동기화는 특히 `list` / `list-item` 내부에서 중요합니다. `VariantTable`처럼 list 기반으로 많은 preview를 렌더링하는 화면에서는 background thread의 effect가 실행되는 시점과 main thread UI 노드가 실제로 attach되어 computed style을 읽을 수 있는 시점이 어긋날 수 있습니다. `binduiappear`는 polling이나 timer retry 없이, UI 노드가 보이는 생명주기에서 같은 sync를 한 번 더 실행하기 위한 장치입니다. ## 설계 결정 `useIconColor`는 색상 의미를 JS에서 다시 해석하지 않습니다. SEED semantic token 이름이나 palette token 값을 `@seed-design/lynx-react` 안에 복제하지 않고, qvism recipe와 page/root에 주입된 CSS variable이 색상의 source of truth가 되도록 둡니다. 이 결정은 다음 이유 때문입니다. - 사용자가 `#123144`, `rgb(...)`, theme별 semantic token 등 어떤 색을 쓰더라도 CSS computed value를 기준으로 처리할 수 있어야 합니다. - React 패키지에 semantic color table을 두면 theme, token, recipe 변경과 쉽게 어긋납니다. - `tint-color`에 CSS variable 문자열을 직접 넣는 방식은 Lynx image 경로에서 충분히 안정적이지 않습니다. - `setTimeout`이나 frame retry를 늘리는 방식은 list 초기 렌더 타이밍 문제를 가릴 수는 있어도, 원인을 코드에 설명하기 어렵고 성능 리스크가 커집니다. - catalog 전용 `key` remount나 `recyclable={false}` workaround는 컴포넌트 패키지의 실제 문제를 숨길 수 있습니다. 결론적으로 `useIconColor`는 “CSS computed color를 native image tint에 반영하는 얇은 bridge”입니다. 색상 계산은 recipe와 CSS가 담당하고, hook은 그 결과를 Lynx native attribute로 전달하는 책임만 가집니다. ## API ### Parameters | Parameter | Type | Description | | ------------------- | ------------------------------- | -------------------------------------------------------------------------------- | | `deps` | `DependencyList` | icon의 CSS `color`에 영향을 주는 의존성 목록입니다. 값이 바뀌면 main thread에서 tint color를 다시 동기화합니다. | | `options.sourceRef` | `RefObject` | optional. icon 자체가 아니라 wrapper element의 computed `color`를 source로 사용할 때 전달합니다. | ### Return | Property | Type | Description | | -------------------------- | ------------------------------- | --------------------------------------------------------------------------------- | | `ref` | `RefObject` | icon ``의 main-thread ref입니다. | | `main-thread:binduiappear` | `() => void` | UI 노드가 appear 될 때 computed `color`를 `tint-color`로 다시 반영하는 main-thread handler입니다. | ## 사용 시 주의사항 - monochrome icon처럼 native ``로 색상을 입히는 icon에 사용합니다. - multicolor icon처럼 원본 이미지 색상을 유지해야 하는 경우에는 사용하지 않습니다. - `deps` 누락은 stale tint의 원인이 됩니다. slot className이 바뀌는 상태를 함께 넣어주세요. - icon element가 자체 `ref`나 `main-thread:binduiappear`를 필요로 한다면, 해당 slot에서 병합 전략을 별도로 정해야 합니다. SEED Lynx 컴포넌트의 기본 icon slot은 `useIconColor`가 main-thread ref를 소유합니다. ## 웹 버전과의 차이 | 항목 | Lynx (`useIconColor`) | Web | | ------------------ | -------------------------------------------------- | ---------------------------- | | 아이콘 렌더링 | `` + native `tint-color` | SVG / CSS `currentColor` | | 색상 source of truth | recipe CSS `color`의 computed value | CSS cascade / `currentColor` | | 동기화 방식 | main thread에서 computed color를 읽어 attribute로 mirror | 별도 bridge 불필요 | | list 초기 렌더 | `binduiappear`에서 한 번 더 sync | 해당 없음 |