커스텀 탭과 ref
탭으로 걸러 보기
콘솔 위쪽 탭은 한 번에 하나만 켜져요. 켠 탭에는 밑줄이 생겨요.
- 아무것도 안 켜면 전부 보여줘요
- 다른 탭을 누르면 바로 그 탭으로 바뀌어요
- 켜진 탭을 한 번 더 누르면 꺼지고 전부 보여줘요
Log를 켜면 왼쪽에 레벨 드롭다운(Filter ▼)이 나와요
Network를 켜면 매치 순회(▲ ▼)가 되는 네트워크 전용 화면으로 바뀌어요
검색창은 찍힌 텍스트뿐 아니라 네트워크 요청의 URL · 헤더 · 본문까지 훑어요. 검색에 걸린 네트워크 줄은
매치가 있는 섹션이 펼쳐진 채로 강조돼요. 검색어는 네트워크 전용 화면과 같이 써서, 탭을 오가도 유지돼요.
위로 올려 읽는 동안에는 새 로그를 따라 내려가지 않아요. 그동안 쌓인 개수를 N new ↓ 로 알려주고,
누르면 맨 아래로 가요.
탭 추가하기
필요한 디버깅 정보를 콘솔 탭으로 넣을 수 있어요. renderContent를 준 탭은 구분선 뒤에 놓이고,
누르면 본문을 통째로 그 콘텐츠로 바꿔요.
import LynxConsole, { type CustomTab } from 'lynx-console';
const customTabs: CustomTab[] = [
{
key: 'debug',
label: 'Debug',
renderContent: () => <text>Custom debug content</text>,
},
];
function App() {
return (
<view>
<LynxConsole customTabs={customTabs} />
</view>
);
}
콘솔 로그를 골라 탭으로 보기
filter를 준 탭은 조건에 맞는 로그만 모아 보여주는 필터 탭이 돼요. Log · Network · Perf 옆에 나란히 놓여서, 다른 탭과 같이 켜거나 단독으로 켤 수 있어요.
import LynxConsole, { type CustomTab } from 'lynx-console';
const customTabs: CustomTab[] = [
// 문자열: 찍힌 텍스트에 포함되면 매칭돼요
{ key: 'track', label: 'Track', filter: 'track' },
// 정규식: 찍힌 텍스트가 통과하면 매칭돼요
{ key: 'auth', label: 'Auth', filter: /^auth / },
// 함수: 엔트리마다 직접 판정해요
{ key: 'errors', label: 'Errors', filter: (entry) => entry.level === 'error' },
];
console.log('%ctrack%c screen_view', 'color:#db2777;font-weight:bold', '', { screen: 'home' }); // Track 탭을 켜면 보여요
문자열·정규식 필터는 실제로 찍히는 텍스트를 봐요. %c 스타일 문자열은 빼고 %s · %d 서식은 적용한 뒤예요. %c 스타일은 탭에서도 그대로 그려지니, 색 칩으로 로그 종류를 표시하기 좋아요.
매칭된 로그는 평소와 같은 모양으로 그려요. 한 줄을 직접 그리고 싶으면 renderEntry를 줘요.
renderEntry는 그 탭만 단독으로 켰을 때 쓰여요.
import { isNetworkLog } from 'lynx-console';
{
key: 'net',
label: 'Net',
filter: isNetworkLog, // 네트워크 모니터가 찍은 줄만
renderEntry: (entry) => <text>{String(entry.args[0])}</text>,
}
코드에서 콘솔 열고 닫기
LynxConsoleHandle로 패널을 직접 열고 닫아요.
import { type LynxConsoleHandle } from 'lynx-console';
import { lazy, useRef } from '@lynx-js/react';
const LynxConsole = lazy(() => import('lynx-console'));
function App() {
const consoleRef = useRef<LynxConsoleHandle>(null);
const toggleConsole = () => {
if (consoleRef.current?.isOpen()) {
consoleRef.current.close();
} else {
consoleRef.current?.open();
}
};
return (
<view>
<Suspense>
<LynxConsole ref={consoleRef} />
</Suspense>
</view>
);
}
뒤로가기 핸들러에 close()를 연결하면 백 버튼으로 콘솔을 닫아요.
버튼 위치
기본값은 { right: 16, bottom: 84 } 이고, 각 변이 따로 동작해요.
<LynxConsole initialPosition={{ top: 50, left: 16 }} />
사용자가 버튼을 한 번 드래그하면 그 위치가 initialPosition보다 우선해요.
테마와 세이프 에어리어
<LynxConsole theme="dark" safeAreaInsetBottom="34px" />
safeAreaInsetBottom 기본값은 "50px" 이에요.
가로가 넓은 화면의 사이드 패널
LynxView의 가로가 세로보다 넓으면 오른쪽에 붙는 사이드 패널로 열려요.
기준은 기기가 아니라 LynxView 예요. 열 때 root 를 재고 onWindowResize 를 따라가서, 접거나 회전하면
두 모양 사이를 오가요.
사이드 패널은 화면 맨 위까지 올라오니 콘텐츠에 safeAreaInsetTop(기본 "24px") 만큼 여백을 둬요.
호스트의 상태바 높이가 다르면 값을 넘겨요.
<LynxConsole safeAreaInsetTop="44px" />
플로팅 버튼 교체하기
1. 내 버튼으로 교체하기
renderFloatingButton을 전달하면 리로드를 포함한 기본 버튼 전체를 교체해요. 탭 이벤트에 open을 연결하면 콘솔이 열려요. isOpen으로 패널이 열려 있는지도 알 수 있어요. 모양과 위치는 직접 정해요.
import LynxConsole from 'lynx-console';
<LynxConsole
renderFloatingButton={({ open }) => (
<view
style={{ position: 'fixed', right: '16px', bottom: '84px', zIndex: 9997 }}
bindtap={open}
>
<text>Open console</text>
</view>
)}
/>
2. 리로드 버튼과 드래그 추가하기
버튼 컴포넌트 안에서 공개 훅 useFloatingButtonDrag를 사용해요. 이동할 영역에는 dragHandlers, 리로드처럼 독립적으로 눌러야 하는 버튼에는 stopDragHandlers를 펼쳐 넣어요. 터치·마우스 차이를 직접 처리할 필요가 없고, 리로드를 눌렀을 때 콘솔까지 열리는 것도 막아줘요.
import LynxConsole, { useFloatingButtonDrag } from 'lynx-console';
function MyFloatingButton({ open }: { open: () => void }) {
const { positionStyle, dragHandlers, stopDragHandlers, dragOverlayHandlers } =
useFloatingButtonDrag({
onTap: open,
});
return (
<>
{dragOverlayHandlers && (
<view
style={{
position: 'fixed', top: 0, left: 0,
width: '100vw', height: '100vh', zIndex: 9996,
}}
{...dragOverlayHandlers}
/>
)}
<view
style={{
position: 'fixed', ...positionStyle, zIndex: 9997,
display: 'flex', flexDirection: 'row', alignItems: 'center',
padding: '8px', gap: '12px', borderRadius: '16px',
backgroundColor: '#eeeeee',
}}
{...dragHandlers}
>
<text style={{ color: '#222222' }}>Console</text>
<view
{...stopDragHandlers}
bindtap={() => lynx.reload({}, () => {})}
>
<text style={{ color: '#222222' }}>↻</text>
</view>
</view>
</>
);
}
<LynxConsole
initialPosition={{ right: 30, bottom: 200 }}
renderFloatingButton={({ open }) => <MyFloatingButton open={open} />}
/>
dragOverlayHandlers가 있으면 투명 오버레이도 렌더링해요. 웹에서 마우스가 버튼 밖으로 나가도 드래그를 이어가기 위해 필요해요. 오버레이의 z-index는 페이지 콘텐츠보다 높고 버튼보다 낮게 두세요. 드래그 영역에 bindtap={open}을 따로 붙이지 않아요. 훅이 탭도 처리해요.
훅은 renderFloatingButton 콜백 안에서 직접 호출하지 말고 MyFloatingButton 안에서 호출해요. 훅이 LynxConsole.initialPosition을 자동으로 읽어서 useFloatingButtonDrag({ onTap: open })만 쓰면 돼요. 훅에 initialPosition을 직접 넘기면 그 값이 우선해요. 둘 다 생략하면 { right: 16, bottom: 84 }를 사용해요. 훅은 현재 런타임의 마지막 드래그 위치를 기억하고, 기준 변이 같으면 기본 버튼과도 공유해요.
3. 기본 버튼과 전환하기
<LynxConsole
renderFloatingButton={
enabled && (({ open }) => <MyFloatingButton open={open} />)
}
/>
enabled가 false면 기본 버튼이 나와요. prop을 생략해도 같아요. 반면 렌더 콜백에서 null을 반환하면 버튼을 숨겨요. 이때는 다른 UI에서 ref.open()으로 열 수 있어요.