Editor
Lexical 기반 리치 텍스트 에디터 컴포넌트
개요
Editor는 서식, 이미지, 표, 레이아웃 등 풍부한 콘텐츠 편집 기능을 제공하는 리치 텍스트 에디터입니다. Lexical 엔진을 기반으로 하며, FormItem을 통합합니다.
주요 특징
- ✅ 리치 텍스트 편집: 서식, 정렬, 들여쓰기 등
- ✅ Toolbar: 서식 선택, Insert, 정렬, 링크 등 메뉴
- ✅ 콘텐츠 삽입: 이미지, 표, 컬럼 레이아웃, HTML 블록
- ✅ HTML 입/출력:
editorHtmlState로 초기화,onHtmlChange로 변경 통보 - ✅ 명령적 API: ref(
EditorHandle)로 외부에서 텍스트 삽입·포커스 제어 - ✅ FormItem 통합: 레이블, 설명, 에러 메시지
- ✅ 접근성: 키보드 네비게이션 지원
States
Preview
0 characters
|0 words
0 characters
|0 words
0 characters
|0 words
0 characters
|0 words
사용 예시
예시 1: 기본 에디터
Preview
0 characters
|0 words
예시 2: 읽기 전용
Toolbar와 Actions가 숨겨지고 콘텐츠 수정이 제한됩니다.
Preview
0 characters
|0 words
예시 3: 에러 상태
Preview
0 characters
|0 words
예시 4: Toolbar 및 서식 기능
Toolbar에서 서식 선택(Paragraph, Heading, List 등), 글꼴/크기/굵기/기울임/밑줄, 텍스트 정렬, 들여쓰기, 링크 삽입/해제, 서식 초기화를 제공합니다.
Preview
0 characters
|0 words
예시 5: 콘텐츠 삽입
Insert 메뉴 또는 / (슬래시) 커맨드로 이미지, 표, 컨럼 레이아웃 등의 콘텐츠 블록을 삽입할 수 있습니다.
Preview
0 characters
|0 words
예시 6: Serialized State 관리
import { Editor } from "@vortex/ui-icignal"
import { useState } from "react"
function MyEditor() {
const [state, setState] = useState(undefined)
return (
<Editor
label="내용"
labelWidth={80}
editorSerializedState={state}
onSerializedChange={setState}
/>
)
}예시 7: HTML 입/출력 (editorHtmlState / onHtmlChange)
JSON 외에 HTML 문자열로도 양방향 입/출력이 가능합니다. 초기화는
editorHtmlState prop으로 마운트 시점에 1회 적용되고,
변경 통보는 onHtmlChange 콜백으로 매 업데이트마다 HTML 문자열이
전달됩니다. 이 값을 그대로 API의 contentsBody 등으로 전송할 수 있습니다.
import { Editor } from "@vortex/ui-icignal"
import { useState } from "react"
function MyEditor() {
const [html, setHtml] = useState("")
return (
<Editor
label="내용"
labelWidth={80}
editorHtmlState={item.contentsBody}
onHtmlChange={setHtml}
/>
)
}초기화 우선순위는 editorState > editorSerializedState >
editorHtmlState 입니다. 외부에서 다시 로드하려면 key 변경으로 컴포넌트를
강제 remount 해야 합니다.
예시 8: Ref Handle - 외부에서 텍스트 삽입
useRef<EditorHandle>(null)로 ref를 만들어 <Editor ref={...} />에
연결하면 외부에서 현재 커서(또는 선택 영역) 위치에 텍스트를 삽입할 수
있습니다. 내부적으로 lexical의 RangeSelection.insertText를 사용하므로
deprecated된 document.execCommand("insertText") 에 의존하지 않습니다.
SMS / LMS / MMS 등 다른 채널의 textarea 기반 치환 문자 삽입과 동일한 UX를
Lexical contenteditable 환경에서도 제공합니다. readOnly 상태에서는 호출이
무시됩니다.
import { Button, Editor, type EditorHandle } from "@vortex/ui-icignal"
import { useRef } from "react"
function MessageEditor() {
const editorRef = useRef<EditorHandle>(null)
const fields = ["회원명", "날짜", "주문번호"] as const
return (
<div className="flex flex-col gap-3">
<div className="flex flex-wrap gap-2">
{fields.map((field) => (
<Button
key={field}
size="sm"
variant="outline"
onClick={() => editorRef.current?.insertText(`$$${field}$$`)}
>
+ {field}
</Button>
))}
</div>
<Editor ref={editorRef} label="메시지 본문" labelWidth={100} />
</div>
)
}API Reference
Props
| Prop | Type | Default | Description |
|---|---|---|---|
readOnly | boolean | false | 읽기 전용 여부 |
error | string | - | 에러 메시지 |
className | string | - | FormItem 래퍼에 적용할 CSS 클래스 |
editorClassName | string | - | 내부 에디터 요소에 적용할 CSS 클래스 |
label | string | - | 필드 레이블 |
labelWidth | string | number | - | 레이블 너비 |
labelAlign | "start" | "center" | "end" | - | 레이블 가로 정렬 |
labelVerticalAlign | "start" | "center" | "end" | - | 레이블 세로 정렬 |
required | boolean | false | 필수 여부 |
orientation | "horizontal" | "vertical" | "horizontal" | 레이블-필드 배치 방향 |
description | string | - | 설명 텍스트 |
editorState | EditorState | - | Lexical EditorState (제어) |
editorSerializedState | SerializedEditorState | - | JSON 직렬화 상태 (제어) |
editorHtmlState | string | - | 마운트 시 HTML 문자열로 초기화 (1회 적용) |
초기화 우선순위: editorState > editorSerializedState > editorHtmlState
Events
| Event | Type | Description |
|---|---|---|
onChange | (editorState: EditorState) => void | EditorState 변경 핸들러 |
onSerializedChange | (state: SerializedEditorState) => void | JSON 직렬화 변경 핸들러 |
onHtmlChange | (html: string) => void | HTML 문자열 변경 핸들러 (명시 시에만 변환) |
Ref Handle (EditorHandle)
forwardRef로 받은 ref를 통해 명령적으로 에디터를 제어합니다.
| Method | Type | Description |
|---|---|---|
insertText | (text: string) => void | 현재 커서/선택 영역 위치에 텍스트 삽입. 선택 영역이 있으면 대체, 없으면 root 마지막에 append. readOnly 시 무시 |
focus | () => void | 에디터에 포커스 |
getEditor | () => LexicalEditor | null | 내부 LexicalEditor 인스턴스에 직접 접근 (고급 사용처용) |
기본 사용법
import { Editor } from "@vortex/ui-icignal"
// 기본
<Editor label="내용" />
// 읽기 전용
<Editor label="내용" readOnly />
// 에러
<Editor label="내용" error="필수 항목입니다" required />접근성
권장 사항
- ✅
label로 에디터 용도 전달 - ✅ 키보드: Tab으로 툴바 이동, 에디터 내 텍스트 편집
- ✅ 읽기 전용 시 Toolbar 자동 숨김
- ❌ label 없이 사용 지양
관련 컴포넌트
- Editor (Foundation): 기본 Editor
- Textarea: 단순 텍스트 입력
- Input: 한 줄 텍스트 입력