editor-ruler v1.1.0

DevsLab 오픈소스 · OSS 브랜드 가이드 · Registry O01

웹 에디터에는 줄자가 없었습니다.
이제 어디에나 달 수 있습니다.

Froala·TinyMCE·CKEditor 5·Quill — 어떤 범용 WYSIWYG 에디터도 Word처럼 여백과 들여쓰기를 끌어서 조절하는 줄자를 제공하지 않습니다. editor-ruler는 에디터에 종속되지 않는 코어와 얇은 어댑터로 그 공백을 채우는 오픈소스입니다.

의존성 0 TypeScript cm · in · px 가이드선 + 스냅 세로 줄자 Froala · Tiptap · CKEditor 5 Apache-2.0

📄 왜 만들었나 — Every web rich-text editor is missing a ruler (영문)

라이브 데모 — 에디터별로 보기

StackBlitz에서 열기 ↗

문단을 클릭하면 그 문단의 여백, 테이블 셀을 클릭하면 컬럼 마커 + 테이블 통째 이동, 이미지를 선택하면 소속 블록이 밀립니다. 줄자 빈 곳에서 아래로 끌면 가로 가이드, 툴바 드롭다운으로 세로 줄자·단위 전환. "Unlicensed" 표시는 Froala 트라이얼 워터마크로 이 플러그인과 무관합니다.

시작하기 — npm

npm install @devslab/editor-ruler
import { createRuler } from '@devslab/editor-ruler';

const ruler = createRuler(mountElement, {
  unit: 'cm', // 'cm' | 'in' | 'px'
  getMetrics: () => ({ contentWidth, leftMargin, rightMargin, firstLineIndent }), // px
  onChange(change, phase) {
    // px 값을 현재 문단(들)에 적용; 드래그를 놓는 순간 phase === 'commit'
  },
});

ruler.refresh();      // 선택/내용이 바뀔 때 호출
ruler.setUnit('in');  // 눈금 전환

시작하기 — CDN (빌드 도구 없이)

번들러 없이 <script> 한 줄로 씁니다. 전역 EditorRuler가 노출됩니다.

<script src="https://cdn.jsdelivr.net/npm/@devslab/editor-ruler@1.1.0/dist/index.global.js"></script>
<script>
  const ruler = EditorRuler.createRuler(document.getElementById('ruler-mount'), {
    unit: 'cm',
    getMetrics: () => ({ /* ... */ }),
    onChange(change) { /* ... */ },
  });
</script>

Froala 어댑터도 동일합니다: @devslab/editor-ruler-froala/dist/index.global.js를 로드하면 전역 EditorRulerFroala.defineRulerPlugin이 노출됩니다 (코어 포함 단일 파일).

버전 지정: @1.1.0(정확 고정) · @1.1(패치 자동 반영 — 권장) · @latest(항상 최신 — 메이저 포함이라 브레이킹 체인지 위험, jsDelivr가 별칭을 최대 12시간 캐시).

Froala 연동

npm install @devslab/editor-ruler-froala froala-editor
import FroalaEditor from 'froala-editor';
import { defineRulerPlugin } from '@devslab/editor-ruler-froala';

defineRulerPlugin(FroalaEditor); // 인스턴스 생성 전에 1회

new FroalaEditor('#editor', {
  rulerEnabled: true, // 기본 true — false면 플러그인 자체 비활성
  rulerVisible: true, // false면 숨긴 채 시작 — 툴바 토글로 켬 (기본 true)
  rulerUnit: 'cm',
  // 세로 줄자 23px 자리를 미리 예약 — 토글해도 본문 폭 불변 (기본 false):
  rulerVerticalGutter: true,
  // 줄자 옵션 통합 드롭다운 (보이기/숨기기 + 세로 줄자 + 가이드 + 단위):
  toolbarButtons: ['bold', 'italic', '|', 'rulerOptions'],
  // 따로 쓰고 싶으면 'toggleRuler', 'rulerUnit'도 각각 등록돼 있습니다
});

defineRulerPlugin은 표준 Froala 플러그인(ruler)과 함께 줄자 아이콘 드롭다운 rulerOptions를 등록합니다 — 보이기/숨기기·세로 줄자·가이드 잠금/지우기·cm/inch/px가 한 버튼에 있고 활성 상태가 체크로 표시됩니다. pluginsEnabled를 직접 지정한다면 'ruler'를 포함하세요. 드래그는 선택 문단의 margin-left/right·text-indent를 갱신하고 제스처당 undo 스텝을 1회 기록합니다.

Tiptap 연동

npm install @devslab/editor-ruler-tiptap @tiptap/core
import { Editor } from '@tiptap/core';
import StarterKit from '@tiptap/starter-kit';
import { EditorRuler } from '@devslab/editor-ruler-tiptap';

new Editor({
  element,
  extensions: [StarterKit, EditorRuler.configure({ unit: 'cm' })],
  content: '<p>Hello</p>',
});

들여쓰기는 rulerIndent 노드 속성으로 저장되어 getHTML()에 순수 인라인 CSS로 나오고, 드래그 전체가 undo 한 단계입니다. Tiptap v2·v3 지원. visible: false면 숨긴 채 시작하고 editor.commands.toggleRuler()로 켭니다. 세로 줄자는 vertical: true(+verticalGutter로 자리 예약)와 toggleVerticalRuler 커맨드로 제어합니다.

CKEditor 5 연동

npm install @devslab/editor-ruler-ckeditor5 ckeditor5
import { ClassicEditor, Essentials, Paragraph, Heading } from 'ckeditor5';
import { EditorRulerPlugin } from '@devslab/editor-ruler-ckeditor5';

ClassicEditor.create(element, {
  licenseKey: 'GPL',
  plugins: [Essentials, Paragraph, Heading, EditorRulerPlugin],
  toolbar: ['heading', '|', 'editorRuler'], // 줄자 아이콘 드롭다운
  editorRuler: {
    unit: 'cm',      // 'cm' | 'in' | 'px'
    visible: true,   // false면 숨긴 채 시작 — 드롭다운/plugin.show()로 켬
    vertical: false, // 세로 줄자 초기 표시 (verticalGutter로 자리 예약)
    guides: true,
  },
});

들여쓰기는 모델 속성으로 저장되어 getData()에 순수 인라인 CSS로 다운캐스트되고, 드래그 전체가 undo 한 단계입니다. editorRuler 툴바 드롭다운에 보이기/숨기기·세로 줄자·가이드 잠금/지우기·단위 전환이 들어 있습니다. ckeditor5 >= 42 필요.

Summernote 연동

npm install @devslab/editor-ruler-summernote summernote
import $ from 'jquery';
import 'summernote';
import { defineRulerPlugin } from '@devslab/editor-ruler-summernote';

defineRulerPlugin($); // 에디터 초기화 전에 1회

$('#editor').summernote({
  toolbar: [['misc', ['ruler']]], // 줄자 아이콘 드롭다운
  ruler: {
    unit: 'cm',            // 'cm' | 'in' | 'px'
    visible: true,         // false면 숨긴 채 시작
    vertical: false,       // 세로 줄자 초기 표시
    verticalGutter: false, // 자리 예약 — 토글해도 본문 폭 불변
    guides: true,
  },
});

toolbar'ruler'를 넣으면 줄자 아이콘 드롭다운이 생깁니다. Froala 어댑터와 같은 직접-DOM 방식이라 테이블 통째 밀기와 컬럼 마커까지 동일합니다. 커밋은 Summernote의 afterCommand를 거치고, 그 함수가 undo 스냅샷을 찍습니다. summernote >= 0.8과 jQuery peer가 필요합니다.

API 요약

createRuler(mount, options)줄자를 마운트하고 Ruler 핸들을 반환 — guides·columns·guideSnap 옵션 포함
options.getMetrics(){ contentWidth, leftMargin, rightMargin, firstLineIndent } — 전부 px
options.onChange(change, phase)드래그 중 'drag', 놓는 순간 'commit' (undo 경계)
createGuides(container, options)가이드선 컨트롤러 — list/set/clear/setLocked/setVisible
createVRuler(mount, options)세로 눈금 스트립 (가이드 생성 지원)
ruler.refresh() / setUnit(u) / destroy()메트릭 갱신 · 눈금 전환 · 정리

핸들과 컬럼 마커는 ARIA 슬라이더입니다 — / 1px, Shift 10px, Home/End. 테마는 --edr-* CSS 변수, UI 언어는 브라우저를 따릅니다(ko/en 내장).

자주 묻는 것

결과물 HTML은 어떻게 나오나요? 순수 인라인 CSS입니다 — <p style="margin-left: 75px; text-indent: 38px">. 어디로 내보내도(메일·다른 페이지·CMS) 레이아웃이 유지됩니다.

테이블·이미지는요? Word처럼 다 밀립니다 — 테이블 안에 커서를 두고 드래그하면 테이블 전체가 이동하고, 셀 안 문단은 개별 들여쓰기, 이미지는 소속 블록과 함께 움직입니다. 테이블 안에서는 줄자에 컬럼 경계 마커가 떠서 드래그로 컬럼 폭도 조절됩니다 (병합 셀 테이블 제외). 이 테이블·이미지 동작은 현재 Froala 어댑터 전용입니다 — Tiptap·CKEditor 5에서는 문단 들여쓰기·세로 줄자·가이드선까지 동일하게 동작합니다.

가이드선은 문서에 남나요? 아니요 — 순수 시각 오버레이라 내보내는 HTML에 전혀 남지 않습니다. 정렬 참고용이며, 드롭다운에서 잠그거나 한 번에 지울 수 있고, 드래그 중 핸들과 컬럼 마커가 가이드 근처에서 스냅됩니다.

탭 스톱은요? HTML에는 탭 스톱 모델이 없어 의도적으로 범위 밖입니다. 여백·들여쓰기는 CSS와 1:1이라 어디서나 안전하게 동작합니다.

다른 에디터는요? 코어가 에디터 불문이라 어댑터는 "선택 블록 읽기/스타일 쓰기/undo 연결"만 하면 됩니다 — Froala·Tiptap·CKEditor 5·Summernote 어댑터가 이미 있고, 위 탭에서 넷 다 바로 써볼 수 있습니다. 다른 에디터가 필요하면 이슈로 알려주세요.