Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,36 @@ with a shared version number.

## [Unreleased]

## [1.1.0] - 2026-08-08

### Added

- **`@devslab/editor-ruler-summernote`** — new package: a [Summernote](https://summernote.org)
plugin (`summernote >= 0.8`). Register with `defineRulerPlugin($)` and add
`'ruler'` to `toolbar` for the ruler-icon dropdown (Show/Hide, Vertical
Ruler, Lock/Clear Guides, cm/inch/px). Options live under the `ruler` key:
`enabled`, `visible`, `unit`, `vertical`, `verticalGutter`, `guides`,
`guideSnap`, `language`.

Summernote is direct-DOM like Froala, so this adapter reuses the same
behavior rather than approximating it: **whole-table indent and column-width
markers work here too** — the first adapter besides Froala to have them.
Commits go through Summernote's own `editor.afterCommand`, which is the
method that calls `history.recordUndo()`, so a whole drag gesture is exactly
one undo step.

- Landing page gains a Summernote demo tab (jQuery and Summernote lazy-load
from a CDN only when the tab is opened) and a Summernote integration
section; `examples/summernote` added for one-click StackBlitz.

### Changed

- Docs that counted adapters ("all three", "the four packages") are now
count-free or corrected, and the feature split is stated where it matters:
the vertical ruler and guides are on every adapter, while whole-table indent
and column markers are on the direct-DOM adapters (Froala, Summernote).
- README CDN pins bumped `@1.0` → `@1.1`.

## [1.0.1] - 2026-08-08

### Fixed
Expand Down Expand Up @@ -359,7 +389,8 @@ What it deliberately does **not** cover, so these can still improve:
records one Froala undo step per gesture. iife build exposes the
`EditorRulerFroala` global (core bundled) for CDN use.

[Unreleased]: https://github.com/devslab-kr/editor-ruler/compare/v1.0.1...HEAD
[Unreleased]: https://github.com/devslab-kr/editor-ruler/compare/v1.1.0...HEAD
[1.1.0]: https://github.com/devslab-kr/editor-ruler/compare/v1.0.1...v1.1.0
[1.0.1]: https://github.com/devslab-kr/editor-ruler/compare/v1.0.0...v1.0.1
[1.0.0]: https://github.com/devslab-kr/editor-ruler/compare/v0.16.0...v1.0.0
[0.16.0]: https://github.com/devslab-kr/editor-ruler/compare/v0.15.0...v0.16.0
Expand Down
32 changes: 27 additions & 5 deletions README.ko.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Froala·TinyMCE·CKEditor 5·Quill 등 범용 WYSIWYG 에디터에는 줄자가
| [`@devslab/editor-ruler-froala`](packages/editor-ruler-froala) | [Froala WYSIWYG 에디터](https://froala.com) 플러그인 어댑터. |
| [`@devslab/editor-ruler-tiptap`](packages/editor-ruler-tiptap) | [Tiptap](https://tiptap.dev) 확장 (v2/v3). |
| [`@devslab/editor-ruler-ckeditor5`](packages/editor-ruler-ckeditor5) | [CKEditor 5](https://ckeditor.com/ckeditor-5/) 플러그인 (`ckeditor5 >= 42`). |
| [`@devslab/editor-ruler-summernote`](packages/editor-ruler-summernote) | [Summernote](https://summernote.org) 플러그인 (`summernote >= 0.8`). |

## 빠른 시작 (코어 — 아무 contenteditable)

Expand All @@ -48,7 +49,7 @@ ruler.refresh(); // 선택/내용이 바뀔 때마다 호출
iife 빌드가 전역 `EditorRuler`를 노출합니다:

```html
<script src="https://cdn.jsdelivr.net/npm/@devslab/editor-ruler@1.0/dist/index.global.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@devslab/editor-ruler@1.1/dist/index.global.js"></script>
<script>
const ruler = EditorRuler.createRuler(mountElement, { /* 동일한 옵션 */ });
</script>
Expand All @@ -60,8 +61,8 @@ Froala 어댑터도 동일합니다 — `@devslab/editor-ruler-froala/dist/index

| URL | 의미 |
|---|---|
| `@1.0.1` | 정확한 버전 고정 — 절대 안 바뀜, 캐시 최장 |
| `@1.0` | `1.0.x` 최신 패치 — 버그픽스 자동 반영, 브레이킹 없음 (권장) |
| `@1.1.0` | 정확한 버전 고정 — 절대 안 바뀜, 캐시 최장 |
| `@1.1` | `1.1.x` 최신 패치 — 버그픽스 자동 반영, 브레이킹 없음 (권장) |
| `@latest` (또는 버전 생략) | 항상 최신 릴리스 — 메이저 포함이라 브레이킹 체인지가 예고 없이 들어올 수 있음; jsDelivr가 별칭을 최대 12시간 캐시 |

## 빠른 시작 (Froala)
Expand Down Expand Up @@ -118,14 +119,34 @@ ClassicEditor.create(element, {

모델 속성이 순수 인라인 CSS로 다운캐스트되고, 드래그가 undo 1스텝입니다. [패키지 README](packages/editor-ruler-ckeditor5) 참조.

## 빠른 시작 (Summernote)

```bash
npm install @devslab/editor-ruler-summernote summernote
```

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

defineRulerPlugin($); // 에디터 초기화 전에 1회
$('#editor').summernote({
toolbar: [['misc', ['ruler']]],
ruler: { unit: 'cm' },
});
```

Froala 어댑터와 같은 직접-DOM 방식이라 **테이블 통째 밀기와 컬럼 마커까지 동일하게** 동작합니다. 커밋이 Summernote의 `afterCommand`를 거쳐 드래그가 undo 1스텝입니다. [패키지 README](packages/editor-ruler-summernote) 참조.

`defineRulerPlugin`은 `ruler` 플러그인과 **함께** 툴바 커맨드들을 등록합니다 — 필요한 것을 `toolbarButtons`에 추가하세요:

- `rulerOptions` — **권장 단일 버튼**: 줄자 아이콘 드롭다운 하나에 보이기/숨기기 · 세로 줄자 · 가이드 잠금 · 가이드 지우기 + cm / inch / px (활성 상태 체크 표시)
- `toggleRuler` / `rulerUnit` — 핵심 기능을 버튼을 나눠 쓰고 싶을 때

Froala 옵션: `rulerVisible: false`면 가로 줄자를 숨긴 채 시작(플러그인·툴바는 살아 있어 나중에 토글로 켬), `rulerVertical: true`면 초기화 시 세로 줄자 표시, `rulerVerticalGutter: true`면 세로 줄자의 23px 자리를 처음부터 예약해(`scrollbar-gutter: stable`과 같은 발상) 토글해도 본문이 리플로우되지 않음, `rulerGuides: false`면 가이드선 비활성.

Tiptap·CKEditor 5도 같은 제어를 지원합니다: `visible: false`면 숨긴 채 시작(Tiptap은 `showRuler`/`hideRuler`/`toggleRuler` 커맨드, CKEditor 5는 플러그인의 `show()`/`toggle()`), 그리고 **세로 줄자는 세 어댑터 모두에서 동작합니다** — `vertical: true`면 초기 표시, `verticalGutter: true`면 23px 자리를 예약해 토글해도 본문이 리플로우되지 않음 (Tiptap: `showVerticalRuler`/`toggleVerticalRuler` 커맨드, CKEditor 5: `showVRuler()`/`toggleVRuler()` + 툴바 드롭다운의 세로 줄자 항목).
Tiptap·CKEditor 5·Summernote는 각자의 설정 키 아래에서 같은 제어를 받습니다: `visible: false`면 숨긴 채 시작, `vertical: true`면 초기 세로 줄자 표시, `verticalGutter: true`면 23px 자리를 예약해 토글해도 본문이 리플로우되지 않습니다. **세로 줄자와 가이드선은 전 어댑터 공통**이고, 테이블 통째 밀기와 컬럼 마커는 직접-DOM 어댑터(Froala·Summernote)에 있습니다. 토글은 Tiptap이 커맨드(`toggleRuler`·`toggleVerticalRuler`), 나머지는 플러그인 메서드(`toggle()`·`toggleVRuler()`)입니다.

## 기능

Expand Down Expand Up @@ -153,6 +174,7 @@ Tiptap·CKEditor 5도 같은 제어를 지원합니다: `visible: false`면 숨
- [Froala — StackBlitz](https://stackblitz.com/github/devslab-kr/editor-ruler/tree/main/examples/froala)
- [Tiptap — StackBlitz](https://stackblitz.com/github/devslab-kr/editor-ruler/tree/main/examples/tiptap)
- [CKEditor 5 — StackBlitz](https://stackblitz.com/github/devslab-kr/editor-ruler/tree/main/examples/ckeditor5)
- [Summernote — StackBlitz](https://stackblitz.com/github/devslab-kr/editor-ruler/tree/main/examples/summernote)

로컬:

Expand All @@ -167,7 +189,7 @@ pnpm install && pnpm build

약속에 포함되는 것:

- 패키지 진입점에서 export하는 모든 심볼, 각 어댑터가 받는 옵션·설정
- 패키지 진입점에서 export하는 모든 심볼, 각 어댑터가 받는 옵션·설정
- 테마링에 쓰는 `--edr-*` CSS 커스텀 프로퍼티
- 출력 계약 — 들여쓰기는 순수 인라인 CSS(`margin-left` / `margin-right` / `text-indent`, px)로 기록

Expand Down
32 changes: 27 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Every classic WYSIWYG editor (Froala, TinyMCE, CKEditor 5, Quill, …) ships wit
| [`@devslab/editor-ruler-froala`](packages/editor-ruler-froala) | [Froala WYSIWYG editor](https://froala.com) plugin adapter. |
| [`@devslab/editor-ruler-tiptap`](packages/editor-ruler-tiptap) | [Tiptap](https://tiptap.dev) extension (v2/v3). |
| [`@devslab/editor-ruler-ckeditor5`](packages/editor-ruler-ckeditor5) | [CKEditor 5](https://ckeditor.com/ckeditor-5/) plugin (`ckeditor5 >= 42`). |
| [`@devslab/editor-ruler-summernote`](packages/editor-ruler-summernote) | [Summernote](https://summernote.org) plugin (`summernote >= 0.8`). |

## Quick start (core, any contenteditable)

Expand All @@ -48,7 +49,7 @@ ruler.refresh(); // call whenever selection or content changes
The iife build exposes an `EditorRuler` global:

```html
<script src="https://cdn.jsdelivr.net/npm/@devslab/editor-ruler@1.0/dist/index.global.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@devslab/editor-ruler@1.1/dist/index.global.js"></script>
<script>
const ruler = EditorRuler.createRuler(mountElement, { /* same options */ });
</script>
Expand All @@ -60,8 +61,8 @@ Version pinning options:

| URL | Meaning |
|---|---|
| `@1.0.1` | Exact version — never changes, cached longest |
| `@1.0` | Latest `1.0.x` patch — bugfixes auto-applied, no breaking changes (recommended) |
| `@1.1.0` | Exact version — never changes, cached longest |
| `@1.1` | Latest `1.1.x` patch — bugfixes auto-applied, no breaking changes (recommended) |
| `@latest` (or no version) | Always the newest release — majors included, so breaking changes can land without warning; jsDelivr caches the alias for up to 12h |

## Quick start (Froala)
Expand Down Expand Up @@ -118,14 +119,34 @@ ClassicEditor.create(element, {

Model attributes down-cast to plain inline CSS; one undo step per drag. See the [package README](packages/editor-ruler-ckeditor5).

## Quick start (Summernote)

```bash
npm install @devslab/editor-ruler-summernote summernote
```

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

defineRulerPlugin($); // once, before initializing any editor
$('#editor').summernote({
toolbar: [['misc', ['ruler']]],
ruler: { unit: 'cm' },
});
```

Same direct-DOM behavior as the Froala adapter — including whole-table indent and column markers. Commits go through Summernote's `afterCommand`, so a drag is one undo step. See the [package README](packages/editor-ruler-summernote).

`defineRulerPlugin` registers the `ruler` plugin **and** toolbar commands — add what you need to `toolbarButtons`:

- `rulerOptions` — **recommended single button**: one ruler-icon dropdown holding Show/Hide, Vertical Ruler, Lock Guides, Clear Guides, plus cm / inch / px (active states checkmarked)
- `toggleRuler` / `rulerUnit` — the same core functions as separate buttons, for hosts that prefer them split

Froala options: `rulerVisible: false` starts the horizontal ruler hidden (plugin and toolbar stay alive — toggle it on later); `rulerVertical: true` shows the vertical ruler on init; `rulerVerticalGutter: true` reserves the strip's 23px column from the start (like `scrollbar-gutter: stable`) so toggling the vertical ruler never reflows the content; `rulerGuides: false` disables guide lines.

Tiptap and CKEditor 5 support the same controls: `visible: false` starts the ruler hidden (`showRuler`/`hideRuler`/`toggleRuler` commands on Tiptap, the plugin's `show()`/`toggle()` on CKEditor 5), and the **vertical ruler works on all three adapters** — `vertical: true` shows it on init, `verticalGutter: true` reserves its 23px column so toggling never reflows the content (Tiptap: `showVerticalRuler`/`toggleVerticalRuler` commands; CKEditor 5: `showVRuler()`/`toggleVRuler()` plus a Vertical Ruler entry in the toolbar dropdown).
Tiptap, CKEditor 5, and Summernote take the same controls under their own config key: `visible: false` starts the ruler hidden, `vertical: true` shows the vertical ruler on init, and `verticalGutter: true` reserves its 23px column so toggling never reflows the content. **Every adapter has the vertical ruler and guides**; whole-table indent and column markers are on the direct-DOM adapters (Froala, Summernote). Toggling is via commands on Tiptap (`toggleRuler`, `toggleVerticalRuler`) and plugin methods elsewhere (`toggle()`, `toggleVRuler()`).

## Features

Expand Down Expand Up @@ -153,6 +174,7 @@ One-click sandboxes:
- [Froala on StackBlitz](https://stackblitz.com/github/devslab-kr/editor-ruler/tree/main/examples/froala)
- [Tiptap on StackBlitz](https://stackblitz.com/github/devslab-kr/editor-ruler/tree/main/examples/tiptap)
- [CKEditor 5 on StackBlitz](https://stackblitz.com/github/devslab-kr/editor-ruler/tree/main/examples/ckeditor5)
- [Summernote on StackBlitz](https://stackblitz.com/github/devslab-kr/editor-ruler/tree/main/examples/summernote)

Locally:

Expand All @@ -167,7 +189,7 @@ Stable since **1.0.0**. Breaking changes to the documented API require a major r

Covered by that promise:

- Every symbol exported from the four packages' entry points, and the options / config each adapter accepts
- Every symbol exported from the packages' entry points, and the options / config each adapter accepts
- The `--edr-*` CSS custom properties used for theming
- The output contract — indentation is written as plain inline CSS (`margin-left` / `margin-right` / `text-indent`, in px)

Expand Down
8 changes: 8 additions & 0 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,13 @@ Then wire the normalization from §3 (cells → table, img → parent block) and
call `ruler.refresh()` on selection change, content change, and window resize.
Copy an existing adapter's test file as your template.

The Summernote adapter is the worked example of exactly this: it is direct-DOM
like Froala, so it reuses the same table/image normalization and column-marker
math, and only the four host-specific calls differ — `$.summernote.plugins` for
registration, `context.layoutInfo.editable` for the DOM, `editor.getLastRange`
for the selection, and `editor.afterCommand` for the undo boundary (that method
is what calls `history.recordUndo()`).

## 7. Landmines we already stepped on (so you don't)

1. **jsdom has no layout** — `clientWidth` is 0, which collapses clamp ranges.
Expand Down Expand Up @@ -372,6 +379,7 @@ packages/editor-ruler/src/
packages/editor-ruler-froala/src/index.ts direct-DOM adapter + toolbar dropdown
packages/editor-ruler-tiptap/src/index.ts model adapter (node attribute + transactions)
packages/editor-ruler-ckeditor5/src/index.ts model adapter (schema + up/downcast)
packages/editor-ruler-summernote/src/index.ts direct-DOM adapter (jQuery plugin + toolbar dropdown)
examples/ one-click StackBlitz projects
site/ landing page with per-editor demo tabs
```
Expand Down
2 changes: 1 addition & 1 deletion examples/ckeditor5/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"preview": "vite preview"
},
"dependencies": {
"@devslab/editor-ruler-ckeditor5": "^1.0.1",
"@devslab/editor-ruler-ckeditor5": "^1.1.0",
"ckeditor5": "^48.4.0"
},
"devDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion examples/froala/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"preview": "vite preview"
},
"dependencies": {
"@devslab/editor-ruler-froala": "^1.0.1",
"@devslab/editor-ruler-froala": "^1.1.0",
"froala-editor": "^4.5.2"
},
"devDependencies": {
Expand Down
18 changes: 18 additions & 0 deletions examples/summernote/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>editor-ruler — Summernote example</title>
<style>
body { margin: 0; padding: 32px 16px; background: #f6f7f9; font-family: system-ui, sans-serif; display: flex; justify-content: center; }
.sheet { width: min(760px, 100%); }
</style>
</head>
<body>
<div class="sheet">
<div id="editor"></div>
</div>
<script type="module" src="/main.js"></script>
</body>
</html>
36 changes: 36 additions & 0 deletions examples/summernote/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import $ from 'jquery';
import 'summernote/dist/summernote-lite.css';
import 'summernote/dist/summernote-lite.js';
import { defineRulerPlugin } from '@devslab/editor-ruler-summernote';

// Summernote attaches itself to the jQuery instance it finds, so hand it ours.
window.jQuery = window.$ = $;

defineRulerPlugin($);

$('#editor').summernote({
height: 300,
toolbar: [
['style', ['bold', 'italic', 'underline']],
['para', ['ul', 'ol']],
['table', ['table']],
['misc', ['ruler']],
],
ruler: {
unit: 'cm',
verticalGutter: true, // reserve the vertical ruler's column up front
},
callbacks: {
onInit() {
$('#editor').summernote(
'code',
'<h3>editor-ruler + Summernote</h3>' +
'<p style="margin-left: 60px;">왼쪽 여백 60px 문단 — 핸들을 끌어 보세요.</p>' +
'<p>테이블 셀에 커서를 두면 줄자에 컬럼 마커가 뜨고, 여백 핸들은 테이블 전체를 밀어냅니다.</p>' +
'<table style="width: 100%;"><tbody><tr><td>제품</td><td>수량</td><td>가격</td></tr>' +
'<tr><td>editor-ruler</td><td>1</td><td>무료</td></tr></tbody></table>' +
'<p>툴바의 줄자 드롭다운으로 세로 줄자·가이드 잠금/지우기·단위 전환이 됩니다.</p>',
);
},
},
});
22 changes: 22 additions & 0 deletions examples/summernote/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "editor-ruler-example-summernote",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"@devslab/editor-ruler-summernote": "^1.1.0",
"jquery": "^3.7.1",
"summernote": "^0.9.1"
},
"devDependencies": {
"vite": "^5.4.0"
},
"stackblitz": {
"startCommand": "npm run dev"
}
}
2 changes: 1 addition & 1 deletion examples/tiptap/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"preview": "vite preview"
},
"dependencies": {
"@devslab/editor-ruler-tiptap": "^1.0.1",
"@devslab/editor-ruler-tiptap": "^1.1.0",
"@tiptap/core": "^3.6.5",
"@tiptap/extension-image": "^3.6.5",
"@tiptap/starter-kit": "^3.6.5"
Expand Down
2 changes: 1 addition & 1 deletion examples/vanilla/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"preview": "vite preview"
},
"dependencies": {
"@devslab/editor-ruler": "^1.0.1"
"@devslab/editor-ruler": "^1.1.0"
},
"devDependencies": {
"vite": "^5.4.0"
Expand Down
2 changes: 1 addition & 1 deletion packages/editor-ruler-ckeditor5/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@devslab/editor-ruler-ckeditor5",
"version": "1.0.1",
"version": "1.1.0",
"description": "CKEditor 5 plugin for @devslab/editor-ruler — a Word-like horizontal ruler with margins, first-line indent, and guide lines.",
"license": "Apache-2.0",
"author": "devslab",
Expand Down
2 changes: 1 addition & 1 deletion packages/editor-ruler-froala/README.ko.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ new FroalaEditor('#editor', {
CDN 사용 — iife 빌드는 코어를 포함한 단일 파일로 전역 `EditorRulerFroala`를 노출합니다:

```html
<script src="https://cdn.jsdelivr.net/npm/@devslab/editor-ruler-froala@1.0/dist/index.global.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@devslab/editor-ruler-froala@1.1/dist/index.global.js"></script>
<script>
EditorRulerFroala.defineRulerPlugin(FroalaEditor);
</script>
Expand Down
2 changes: 1 addition & 1 deletion packages/editor-ruler-froala/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ If you configure `pluginsEnabled` explicitly, add `'ruler'` to the list.
CDN usage — the iife build bundles the core into one file and exposes `EditorRulerFroala`:

```html
<script src="https://cdn.jsdelivr.net/npm/@devslab/editor-ruler-froala@1.0/dist/index.global.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@devslab/editor-ruler-froala@1.1/dist/index.global.js"></script>
<script>
EditorRulerFroala.defineRulerPlugin(FroalaEditor);
</script>
Expand Down
2 changes: 1 addition & 1 deletion packages/editor-ruler-froala/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@devslab/editor-ruler-froala",
"version": "1.0.1",
"version": "1.1.0",
"description": "Froala WYSIWYG editor adapter for @devslab/editor-ruler — a Word-like horizontal ruler plugin.",
"license": "Apache-2.0",
"author": "devslab",
Expand Down
Loading
Loading