Appearance
Base Utilities
@jennifersoft/apm-components의 base 모듈 중 개별 문서가 없는 보조 컴포넌트 모음입니다. 이 문서는 @jennifersoft/apm-components@1.4.1 기준으로 정리했습니다.
같은 모듈의 다른 컴포넌트는 아래 문서를 참고하세요.
TooltipBalloon
말풍선 형태의 툴팁 컨테이너입니다. 위치 계산은 하지 않고 모양과 방향만 담당합니다.
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
position | TooltipPosition | 'center-right' | 꼬리 방향 |
cursorNone | boolean | false | 커서 앵커(삼각형) 숨김 |
backgroundColor | string | 'rgba(0, 0, 0, 0.75)' | 배경색 |
width | number | undefined | 고정 폭. 미지정 시 콘텐츠 폭 |
typescript
type TooltipPosition =
| 'top-left' | 'top-center' | 'top-right'
| 'bottom-left' | 'bottom-center' | 'bottom-right'
| 'center-right' | 'center-left';vue
<script setup lang="ts">
import { TooltipBalloon } from '@jennifersoft/apm-components';
</script>
<template>
<TooltipBalloon position="top-center" :width="200">
응답시간이 임계치를 초과했습니다.
</TooltipBalloon>
</template>PopoverBalloon과 달리 기본 배경이 반투명 검정입니다. 밝은 배경 툴팁이 필요하면 backgroundColor에 테마 토큰을 넘기세요.
BoldTextByIndex
문자열에서 지정한 인덱스의 글자만 굵게 표시합니다. 검색어 매칭 하이라이트에 사용합니다.
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
content | string | — (필수) | 원문 |
indices | number[] | [] | 굵게 표시할 문자 인덱스 |
tooltipWhenEllipsis | boolean | false | 말줄임 발생 시에만 툴팁 표시 |
인덱스는 문자 단위입니다. 부분 문자열이 아니라 흩어진 글자를 강조할 수 있어 퍼지 검색(fuzzy match) 결과 표시에 적합합니다.
vue
<script setup lang="ts">
import { BoldTextByIndex } from '@jennifersoft/apm-components';
// "OrderService" 에서 O, r, d, S 를 강조
</script>
<template>
<BoldTextByIndex
content="OrderService"
:indices="[0, 1, 2, 5]"
tooltip-when-ellipsis
/>
</template>tooltipWhenEllipsis는 useElementBounding으로 폭 변화를 관찰해 scrollWidth > clientWidth일 때만 툴팁을 노출합니다. 잘리지 않은 텍스트에는 툴팁이 뜨지 않습니다.
NOTE
content는 정규식 이스케이프 후 문자 단위로 분해되어 <span>으로 감싸집니다. HTML을 넘겨 마크업을 주입할 수는 없습니다.
아래 데모는 검색어 글자를 순서대로 훑어 매칭 위치를 만드는 퍼지 매칭입니다. ose처럼 떨어진 글자를 입력해도 각 위치가 강조됩니다.
HorizontalOverflowFade
가로로 넘치는 콘텐츠의 양끝을 페이드 처리해 스크롤 가능함을 알립니다.
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
ariaLabel | string | undefined | 스크롤 영역 접근성 이름 |
fadeWidth | number | 61 | 좌우 페이드 너비 |
fadeColor | string | 'var(--gray-50)' | 페이드가 수렴하는 색 |
hideScrollbar | boolean | false | 스크롤바를 감추고 페이드로만 안내 |
wheelHorizontal | boolean | false | 세로 휠을 가로 이동으로 변환 |
vue
<script setup lang="ts">
import { HorizontalOverflowFade } from '@jennifersoft/apm-components';
</script>
<template>
<HorizontalOverflowFade
aria-label="추천 질문"
:fade-width="40"
fade-color="var(--surface-50)"
hide-scrollbar
wheel-horizontal
>
<button v-for="q in questions" :key="q.id">{{ q.text }}</button>
</HorizontalOverflowFade>
</template>IMPORTANT
fadeColor는 컨텐츠 표면색과 반드시 맞춰야 합니다. 기본값 var(--gray-50)과 실제 배경이 다르면 양끝에 색 띠가 보입니다.
wheelHorizontal은 트랙패드가 없는 일반 마우스 사용자를 위한 옵션입니다.
CloudBackground
흐릿한 원들이 천천히 떠다니는 장식 배경입니다. AI 채팅 빈 화면 등에 사용합니다.
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
blobs | readonly CloudBackgroundBlob[] | — (필수) | 그릴 원 목록 |
blur | number | 70 | 원을 뭉개는 정도 |
opacity | number | 0.25 | 전체 불투명도 |
typescript
interface CloudBackgroundBlob {
/** 원의 **중심** 세로 위치 (CSS 길이) */
top: string;
/** 원의 **중심** 가로 위치 (CSS 길이) */
left: string;
/** 가로 지름. 백분율은 컨테이너 너비 기준 */
size: string;
/** 세로 지름. 생략하면 size와 같아 정원 */
height?: string;
/** 디자인 토큰 변수를 그대로 전달 */
color: string;
/** 떠다니는 궤도. 생략 시 나열 순서대로 1·2·3 순환 */
drift?: 1 | 2 | 3;
/** 음수를 주면 애니메이션 중간부터 시작해 원끼리 어긋난다 */
delaySeconds?: number;
durationSeconds?: number;
}vue
<script setup lang="ts">
import { CloudBackground } from '@jennifersoft/apm-components';
const blobs = [
{ top: '20%', left: '30%', size: '40%', color: 'var(--blue-300)' },
{ top: '60%', left: '70%', size: '35%', color: 'var(--purple-300)', delaySeconds: -4 },
{ top: '40%', left: '55%', size: '30%', color: 'var(--cyan-300)', delaySeconds: -8 },
];
</script>
<template>
<div style="position: relative">
<CloudBackground :blobs="blobs" :blur="90" :opacity="0.2" />
<div style="position: relative">실제 콘텐츠</div>
</div>
</template>top / left가 원의 모서리가 아니라 중심임에 주의하세요. 컨테이너가 좁을수록 blur를 줄여야 원 형태가 남습니다.
PlainTextViewer
로그·상태 원문 같은 대용량 플레인 텍스트를 보여주는 뷰어입니다.
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
text | string | — (필수) | 실제 원문 |
ariaLabel | string | — (필수) | 스크롤 영역·코드 블록 공용 접근성 이름 |
contentTestId | string | — (필수) | 호출부의 기존 E2E 식별자 보존용 |
viewportTestId | string | — (필수) | 세로 스크롤 영역 식별자 |
fontSize | number | 14 | PLAIN_TEXT_VIEWER_FONT_SIZE_PX |
lineHeight | number | 20 | PLAIN_TEXT_VIEWER_LINE_HEIGHT_PX |
backgroundColor | string | 'var(--surface-50)' | 뷰포트와 가로 페이드가 공유 |
emptyText | string | undefined | 없으면 빈 영역 유지 |
disableScrollAnchoring | boolean | false | 호출부가 직접 위치를 보정할 때 |
virtualized | boolean | true | 화면 주변 줄만 렌더 |
typescript
emit('scroll', event: Event)vue
<script setup lang="ts">
import { PlainTextViewer } from '@jennifersoft/apm-components';
</script>
<template>
<PlainTextViewer
:text="logText"
aria-label="애플리케이션 로그"
content-test-id="log-content"
viewport-test-id="log-viewport"
empty-text="표시할 로그가 없습니다."
@scroll="onScroll"
/>
</template>disableScrollAnchoring
로그 앞쪽에 내용을 prepend할 때, 브라우저의 스크롤 앵커링과 호출부의 위치 보정이 충돌해 화면이 튈 수 있습니다. 호출부가 직접 스크롤 위치를 잡는다면 이 옵션을 켜세요.
virtualized
기본값 true로 화면 주변 줄만 렌더합니다. 전체 텍스트를 DOM에 올려야 하는 경우(예: 브라우저 찾기 기능으로 전체 검색)에만 false로 두세요.
주의사항
CloudBackground는 장식 요소입니다. 콘텐츠를position: relative로 위에 올려야 가려지지 않습니다.HorizontalOverflowFade의fadeColor불일치는 가장 흔한 시각 버그입니다.PlainTextViewer의contentTestId/viewportTestId는 필수입니다. 기존 E2E 셀렉터를 유지하기 위한 설계입니다.