@bavuchoko/js-editor
v0.1.1
Published
Lightweight React WYSIWYG editor built with contentEditable
Maintainers
Readme
@bavuchoko/js-editor
React용 경량 WYSIWYG 에디터입니다.contentEditable + Selection API로 구현되어 있으며 TipTap / Lexical / ProseMirror 같은 외부 에디터 엔진에 의존하지 않습니다.
Install
npm install @bavuchoko/js-editorpeer dependency:
npm install react react-domReact 18 이상을 지원합니다.
Usage
import { useRef } from 'react'
import { Editor, type EditorHandle } from '@bavuchoko/js-editor'
import '@bavuchoko/js-editor/style.css'
function App() {
const editorRef = useRef<EditorHandle>(null)
const save = () => {
// 권장: JSON으로 저장
const json = editorRef.current?.getJson()
// await api.save(json)
}
const load = (doc: unknown) => {
editorRef.current?.setJson(doc)
}
return (
<Editor
ref={editorRef}
theme={{
toolbar: { background: '#fff' },
content: { padding: 24, minHeight: 320 },
}}
/>
)
}스타일(style.css)은 반드시 함께 import 해야 합니다.
Features
| 영역 | 지원 |
|------|------|
| 인라인 | 굵게, 기울임, 밑줄, 글자색, 배경색 |
| 블록 | 본문, Heading 1–3, 인용, 코드 블록 |
| 목록 | 글머리, 번호, 체크리스트 |
| 정렬 | 왼쪽 / 가운데 / 오른쪽 |
| 테이블 | 삽입, 셀 드래그 선택, 셀 병합, Tab/Enter 이동 |
| 단축키 | Undo/Redo, 마크다운 입력 |
| 보안 | 붙여넣기·initialHTML·setHtml sanitize |
플레이스홀더 문구: 내용을 입력하세요
Keyboard shortcuts
| 단축키 | 동작 |
|--------|------|
| Ctrl+Z / Cmd+Z | Undo |
| Ctrl+Shift+Z / Cmd+Shift+Z | Redo |
| Ctrl+Y / Cmd+Y | Redo |
| Tab (테이블 셀) | 다음 셀로 이동 |
| Enter (테이블 셀) | 아래 셀로 이동 |
툴바에 Undo/Redo 버튼은 없고 단축키만 지원합니다.
Markdown shortcuts
줄 시작에서 입력 후 스페이스:
| 입력 | 결과 |
|------|------|
| # | Heading 1 |
| ## | Heading 2 |
| ### | Heading 3 |
| > | 인용 |
| - 또는 * | 글머리 목록 |
| 1. | 번호 목록 |
| ``` + 스페이스 | 코드 블록 |
인라인:
| 입력 | 결과 |
|------|------|
| **텍스트** | 굵게 |
| *텍스트* | 기울임 |
API
Editor props
| prop | 타입 | 설명 |
|------|------|------|
| initialHTML | string | 초기 HTML (sanitize 후 적용) |
| theme | EditorTheme | toolbar / content에 CSSProperties |
| className / style | | 루트 요소 |
| toolbarClassName / toolbarStyle | | 툴바 (theme.toolbar와 병합) |
| contentClassName / contentStyle | | 본문 (theme.content와 병합) |
type EditorTheme = {
toolbar?: CSSProperties
content?: CSSProperties
}ref methods (EditorHandle)
| method | 설명 |
|--------|------|
| getHtml() | 현재 본문 HTML |
| setHtml(html) | HTML 로드 (sanitize + 히스토리 리셋) |
| getJson() | 현재 본문 JSON (EditorDoc) |
| setJson(doc) | JSON 로드 (HTML 변환 + sanitize + 히스토리 리셋) |
| getText() | plain text |
| focus() | 편집 영역 포커스 |
유틸 export
import {
htmlToJson,
jsonToHtml,
domToJson,
normalizeDoc,
sanitizeHTML,
sanitizePlainText,
type EditorDoc,
type BlockNode,
type InlineNode,
type Mark,
} from '@bavuchoko/js-editor'| 함수 | 설명 |
|------|------|
| htmlToJson(html) | HTML → EditorDoc |
| jsonToHtml(doc) | EditorDoc → HTML |
| domToJson(element) | DOM 노드 → EditorDoc |
| normalizeDoc(doc) | 알 수 없는 입력을 안전한 EditorDoc으로 정규화 |
| sanitizeHTML(html) | 허용 태그/속성만 남김 |
| sanitizePlainText(text) | 텍스트만 남김 |
Document JSON
저장·전송은 HTML보다 JSON을 권장합니다.
type EditorDoc = {
type: 'doc'
content: BlockNode[]
}예시:
{
"type": "doc",
"content": [
{
"type": "heading",
"attrs": { "level": 1 },
"content": [{ "type": "text", "text": "제목" }]
},
{
"type": "paragraph",
"attrs": { "textAlign": "left" },
"content": [
{ "type": "text", "text": "안녕하세요, " },
{
"type": "text",
"text": "굵은 글씨",
"marks": [{ "type": "bold" }]
}
]
},
{
"type": "taskList",
"content": [
{
"type": "taskItem",
"attrs": { "checked": false },
"content": [{ "type": "text", "text": "할 일" }]
}
]
}
]
}지원 블록: paragraph, heading, blockquote, codeBlock, bulletList, orderedList, taskList, table
지원 마크: bold, italic, underline, code, textStyle(색), highlight(배경색)
Security
- 붙여넣기,
initialHTML,setHtml/setJson경로에서 HTML을 sanitize 합니다. - 허용되지 않은 태그·속성·이벤트 핸들러·위험한 URL은 제거됩니다.
- 서버에서도 저장 전에 검증하는 것을 권장합니다. JSON으로 저장하면 스키마 검증이 쉽습니다.
// 서버에서 받은 HTML을 넣을 때
editorRef.current?.setHtml(untrustedHtml) // 내부에서 sanitize
// 더 안전하게 JSON만 받기
editorRef.current?.setJson(docFromDb)Develop
npm install
npm run dev # 데모 앱
npm run build # 라이브러리 빌드 (publish용)
npm run build:demo # 데모 앱 빌드
npm run pack:check # 빌드 + npm pack dry-runLicense
MIT
