@aeriz/wysiwyg 1.0.3 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -13
- package/dist/adapters/shared.cjs +1 -1
- package/dist/adapters/shared.js +11 -11
- package/dist/aeriz-wysiwyg-adapter.js +1 -1
- package/dist/aeriz-wysiwyg-adapter.min.js +1 -1
- package/dist/aeriz-wysiwyg-jquery.js +1 -1
- package/dist/aeriz-wysiwyg-jquery.min.js +1 -1
- package/dist/aeriz-wysiwyg-wc.js +1 -1
- package/dist/aeriz-wysiwyg-wc.min.js +1 -1
- package/dist/aeriz-wysiwyg.cjs +3773 -1926
- package/dist/aeriz-wysiwyg.css +554 -38
- package/dist/aeriz-wysiwyg.esm.js +3773 -1926
- package/dist/aeriz-wysiwyg.esm.min.js +4271 -2658
- package/dist/aeriz-wysiwyg.js +3773 -1926
- package/dist/aeriz-wysiwyg.min.cjs +36 -34
- package/dist/aeriz-wysiwyg.min.css +1 -1
- package/dist/aeriz-wysiwyg.min.js +40 -38
- package/dist/server.cjs +24 -22
- package/dist/server.js +444 -312
- package/dist-types/adapters/shared.d.ts.map +1 -1
- package/dist-types/cjs/core/AerizEditor.d.cts +180 -7
- package/dist-types/cjs/core/block-meta.d.cts +66 -0
- package/dist-types/cjs/core/block-policy.d.cts +43 -0
- package/dist-types/cjs/core/blocks.d.cts +47 -4
- package/dist-types/cjs/core/history.d.cts +86 -0
- package/dist-types/cjs/core/i18n.d.cts +12 -0
- package/dist-types/cjs/core/import-html.d.cts +1 -0
- package/dist-types/cjs/core/import-markdown.d.cts +0 -4
- package/dist-types/cjs/core/input-rules.d.cts +46 -0
- package/dist-types/cjs/core/selection.d.cts +46 -0
- package/dist-types/cjs/core/table-ops.d.cts +30 -0
- package/dist-types/cjs/index.d.cts +2 -0
- package/dist-types/core/AerizEditor.d.ts +180 -7
- package/dist-types/core/AerizEditor.d.ts.map +1 -1
- package/dist-types/core/block-meta.d.ts +66 -0
- package/dist-types/core/block-meta.d.ts.map +1 -1
- package/dist-types/core/block-policy.d.ts +43 -0
- package/dist-types/core/block-policy.d.ts.map +1 -0
- package/dist-types/core/blocks.d.ts +47 -4
- package/dist-types/core/blocks.d.ts.map +1 -1
- package/dist-types/core/history.d.ts +86 -0
- package/dist-types/core/history.d.ts.map +1 -0
- package/dist-types/core/i18n.d.ts +12 -0
- package/dist-types/core/i18n.d.ts.map +1 -1
- package/dist-types/core/import-html.d.ts +1 -0
- package/dist-types/core/import-html.d.ts.map +1 -1
- package/dist-types/core/import-markdown.d.ts +0 -4
- package/dist-types/core/import-markdown.d.ts.map +1 -1
- package/dist-types/core/input-rules.d.ts +46 -0
- package/dist-types/core/input-rules.d.ts.map +1 -0
- package/dist-types/core/plain-text.d.ts.map +1 -1
- package/dist-types/core/render-string.d.ts.map +1 -1
- package/dist-types/core/selection.d.ts +46 -0
- package/dist-types/core/selection.d.ts.map +1 -0
- package/dist-types/core/snapshot.d.ts.map +1 -1
- package/dist-types/core/table-ops.d.ts +30 -0
- package/dist-types/core/table-ops.d.ts.map +1 -0
- package/dist-types/index.d.ts +2 -0
- package/dist-types/index.d.ts.map +1 -1
- package/dist-types/ui/Toolbar.d.ts.map +1 -1
- package/dist-types/ui/dialogs.d.ts.map +1 -1
- package/dist-types/ui/icons.d.ts.map +1 -1
- package/dist-types/ui/popovers.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/adapters/shared.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EACL,WAAW,EACX,WAAW,EAMZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EACV,aAAa,EACb,aAAa,EACb,WAAW,EACX,aAAa,EACd,MAAM,gBAAgB,CAAC;AAExB;;;;;;GAMG;AACH,MAAM,WAAW,gBACf,SAAQ,IAAI,CAAC,aAAa,EAAE,SAAS,GAAG,UAAU,CAAC;IACnD;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kDAAkD;IAClD,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,0CAA0C;IAC1C,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IAC7C,0CAA0C;IAC1C,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC;IACxC,2BAA2B;IAC3B,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC;CAC3C;AAED,sBAAsB;AACtB,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAAC,aAAa,EAAE,SAAS,CAAC;IACtE,iCAAiC;IACjC,MAAM,CAAC,EAAE,aAAa,EAAE,CAAC;IACzB,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC;IACxC,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC;CAC3C;AAED,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,0CAA0C;IAC1C,MAAM,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACrC,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,MAAM,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACrC,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,EAAE,
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/adapters/shared.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EACL,WAAW,EACX,WAAW,EAMZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EACV,aAAa,EACb,aAAa,EACb,WAAW,EACX,aAAa,EACd,MAAM,gBAAgB,CAAC;AAExB;;;;;;GAMG;AACH,MAAM,WAAW,gBACf,SAAQ,IAAI,CAAC,aAAa,EAAE,SAAS,GAAG,UAAU,CAAC;IACnD;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kDAAkD;IAClD,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,0CAA0C;IAC1C,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IAC7C,0CAA0C;IAC1C,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC;IACxC,2BAA2B;IAC3B,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC;CAC3C;AAED,sBAAsB;AACtB,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAAC,aAAa,EAAE,SAAS,CAAC;IACtE,iCAAiC;IACjC,MAAM,CAAC,EAAE,aAAa,EAAE,CAAC;IACzB,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC;IACxC,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC;CAC3C;AAED,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,0CAA0C;IAC1C,MAAM,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACrC,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,MAAM,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACrC,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,EAAE,CAS1D;AA4CD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,WAAW,EACjB,YAAY,EAAE,gBAAgB,GAC7B,qBAAqB,CA2HvB;AAgBD,6BAA6B;AAC7B,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,WAAW,EACjB,YAAY,EAAE,gBAAgB,GAC7B,qBAAqB,CAwCvB"}
|
|
@@ -23,7 +23,11 @@ export declare class AerizEditor {
|
|
|
23
23
|
private readonly dropIndicator;
|
|
24
24
|
private readonly handles;
|
|
25
25
|
private readonly blockLabelPill;
|
|
26
|
+
private readonly pillGlyphEl;
|
|
27
|
+
private readonly pillTextEl;
|
|
26
28
|
private readonly statusBar;
|
|
29
|
+
private readonly undoBtn;
|
|
30
|
+
private readonly redoBtn;
|
|
27
31
|
private readonly statusBlockEl;
|
|
28
32
|
private readonly statusBlocksEl;
|
|
29
33
|
private readonly statusCharsEl;
|
|
@@ -35,10 +39,33 @@ export declare class AerizEditor {
|
|
|
35
39
|
private readonly listeners;
|
|
36
40
|
private readonly handleSelectionChange;
|
|
37
41
|
private readonly handleResize;
|
|
42
|
+
/** document 에 붙는다 — destroy() 에서 반드시 떼야 인스턴스가 GC 된다. */
|
|
43
|
+
private readonly handleDocumentMouseUp;
|
|
38
44
|
private state;
|
|
39
45
|
private destroyed;
|
|
40
46
|
private syncQueued;
|
|
41
47
|
private lastSerialized;
|
|
48
|
+
/** 포인터가 올라가 있는 블록. 그 블록의 컨트롤만 드러낸다. */
|
|
49
|
+
private hoveredBlockId;
|
|
50
|
+
/** hover 판정을 프레임당 1 회로 묶기 위한 rAF 핸들. */
|
|
51
|
+
private hoverRaf;
|
|
52
|
+
/** 라벨 pill 의 등장 애니메이션을 블록이 **바뀔 때만** 다시 재생하기 위한 표식. */
|
|
53
|
+
private pillBlockId;
|
|
54
|
+
/**
|
|
55
|
+
* 편집 이력. 브라우저 기본 undo 는 우리가 직접 한 DOM 조작(블록 이동 · 표
|
|
56
|
+
* 편집 · 유형 변경) 을 모르기 때문에 자체 스택을 둔다.
|
|
57
|
+
*/
|
|
58
|
+
private history;
|
|
59
|
+
/**
|
|
60
|
+
* 이력 되돌리기가 만든 DOM 변경인지. 이 동안의 변경은 다시 기록하지 않는다
|
|
61
|
+
* (되돌리기가 스스로를 이력에 쌓으면 되돌리기를 되돌릴 수 없다).
|
|
62
|
+
*/
|
|
63
|
+
private applyingHistory;
|
|
64
|
+
/**
|
|
65
|
+
* 다음 기록의 성격. 구조를 바꾸는 조작은 타이핑과 합쳐지지 않도록
|
|
66
|
+
* 조작 직전에 이 값을 올려 둔다.
|
|
67
|
+
*/
|
|
68
|
+
private pendingChangeKind;
|
|
42
69
|
/** 사용자가 색 다이얼로그에서 직접 고른 색상의 LRU. 에디터 인스턴스 메모리에만 유지. */
|
|
43
70
|
private recentCustomColors;
|
|
44
71
|
constructor(options: EditorOptions);
|
|
@@ -96,7 +123,48 @@ export declare class AerizEditor {
|
|
|
96
123
|
* takeRecords 로 흡수한 뒤 onChange + queueSync.
|
|
97
124
|
*/
|
|
98
125
|
private flush;
|
|
126
|
+
/**
|
|
127
|
+
* 지금 본문을 이력에 기록한다.
|
|
128
|
+
*
|
|
129
|
+
* 되돌리기가 만든 변경은 기록하지 않는다 — 자기 자신을 이력에 쌓으면
|
|
130
|
+
* 되돌리기를 되돌릴 수 없다.
|
|
131
|
+
*/
|
|
132
|
+
private recordHistory;
|
|
133
|
+
/**
|
|
134
|
+
* 유형이 막 바뀐 블록을 한 번 반짝인다.
|
|
135
|
+
*
|
|
136
|
+
* 유형 변경은 결과가 화면 아래쪽(들여쓰기 · 글꼴 · 배경) 에서 조용히 일어나
|
|
137
|
+
* "눌리긴 한 건가" 싶을 때가 있다. 짧은 하이라이트 하나로 어느 블록이
|
|
138
|
+
* 바뀌었는지가 분명해진다.
|
|
139
|
+
*
|
|
140
|
+
* 표식은 `data-block-flash` 속성이다 — class 로 걸면 사용자 컨텐츠의 class 에
|
|
141
|
+
* 섞여 `getHTML()` 로 새어 나갈 수 있다. data-block-* 는 출력 단계에서
|
|
142
|
+
* 통째로 제거되는 에디터 전용 네임스페이스다.
|
|
143
|
+
*
|
|
144
|
+
* 속성을 넣고 뺄 때마다 옵저버 레코드를 흡수한다. 이걸 빠뜨리면 이 표식
|
|
145
|
+
* 하나가 "문서가 바뀌었다" 로 잡혀 이력에 항목이 하나 더 쌓이고, 되돌리기가
|
|
146
|
+
* 눈에 보이는 변화 없이 한 번 헛돈다 (실제로 그랬다).
|
|
147
|
+
*/
|
|
148
|
+
private flashBlock;
|
|
149
|
+
/**
|
|
150
|
+
* 이어지는 한 번의 변경을 **구조 변경**으로 표시한다.
|
|
151
|
+
*
|
|
152
|
+
* 블록 이동 · 유형 변경 · 표 편집처럼 사용자가 "한 번에 하나씩" 되돌리길
|
|
153
|
+
* 기대하는 조작 직전에 부른다. 이 표시가 없으면 직전 타이핑과 한 항목으로
|
|
154
|
+
* 합쳐져 Ctrl+Z 한 번에 둘 다 사라진다.
|
|
155
|
+
*/
|
|
156
|
+
private markStructuralChange;
|
|
157
|
+
/** 되돌리기. 되돌릴 것이 없으면 아무 일도 하지 않는다. */
|
|
158
|
+
undo(): void;
|
|
159
|
+
/** 다시 실행. */
|
|
160
|
+
redo(): void;
|
|
161
|
+
private applyHistoryEntry;
|
|
99
162
|
private handleToolbarAction;
|
|
163
|
+
/**
|
|
164
|
+
* 선택 영역의 인라인 서식을 지운다. 블록 유형은 건드리지 않는다 —
|
|
165
|
+
* "서식 지우기" 로 제목이 본문이 되면 되돌릴 방법을 찾기 어렵다.
|
|
166
|
+
*/
|
|
167
|
+
private clearInlineFormat;
|
|
100
168
|
/**
|
|
101
169
|
* 인라인 마크(bold/italic/underline/strike) 토글. 활성 블록의 allowedMarks
|
|
102
170
|
* 에 포함되지 않은 마크면 무시. styleWithCSS=true 모드로 deprecated 태그
|
|
@@ -201,6 +269,25 @@ export declare class AerizEditor {
|
|
|
201
269
|
*/
|
|
202
270
|
private handleTableResizeStart;
|
|
203
271
|
private handleTableResizeMove;
|
|
272
|
+
/**
|
|
273
|
+
* 체크리스트 항목의 체크 표시 토글.
|
|
274
|
+
*
|
|
275
|
+
* 체크박스는 실제 element 가 아니라 `<li>` 의 `::before` 다 — 폼 요소를
|
|
276
|
+
* contentEditable 안에 두면 캐럿이 그 안으로 들어가고 서버 sanitizer 가
|
|
277
|
+
* 지워 버린다. 그래서 클릭 좌표가 그 표시 영역 안인지 직접 따진다.
|
|
278
|
+
*
|
|
279
|
+
* `click` 이 아니라 `mousedown` 에서 처리한다 — click 까지 기다리면 그
|
|
280
|
+
* 사이에 캐럿이 항목 안으로 들어가 화면이 한 번 흔들린다.
|
|
281
|
+
*/
|
|
282
|
+
private handleTaskToggle;
|
|
283
|
+
/**
|
|
284
|
+
* 이미지 캡션(`<figcaption>`) 에 캐럿을 둔다. 없으면 만든다.
|
|
285
|
+
*
|
|
286
|
+
* 버튼은 토글이 아니다 — 다시 눌러 캡션을 지우면 사용자가 쓴 글이 말없이
|
|
287
|
+
* 사라진다. 캡션을 없애는 방법은 글자를 지우는 것이고, 빈 캡션은 캐럿이
|
|
288
|
+
* 떠난 뒤 `normalizeContent` 가 알아서 걷어낸다.
|
|
289
|
+
*/
|
|
290
|
+
private focusImageCaption;
|
|
204
291
|
/**
|
|
205
292
|
* 이미지/유튜브 좌상단 정렬 컨트롤 클릭 핸들러. data-align 에 따라 wrapper
|
|
206
293
|
* 의 marginLeft / marginRight 를 조정 — left/center/right.
|
|
@@ -303,20 +390,99 @@ export declare class AerizEditor {
|
|
|
303
390
|
* `url` 필드를 사용. 둘 다 없으면 undefined → 다이얼로그 업로드 탭 비활성.
|
|
304
391
|
*/
|
|
305
392
|
private resolveImageUploadFn;
|
|
306
|
-
/**
|
|
307
|
-
* `src` 의 이미지를 figure>img 블록으로 본문에 삽입.
|
|
308
|
-
* 활성 블록이 있으면 그 블록을 image 로 변환, 없으면 본문 끝에 추가.
|
|
309
|
-
*/
|
|
310
|
-
private insertImageBlock;
|
|
311
393
|
private queueSync;
|
|
312
394
|
private sync;
|
|
313
395
|
private handleKeyDown;
|
|
314
396
|
/**
|
|
315
|
-
*
|
|
316
|
-
*
|
|
397
|
+
* 마크다운 입력 규칙.
|
|
398
|
+
*
|
|
399
|
+
* 본문 블록 맨 앞에 `# ` / `- ` / `1. ` / `> ` / ``` 을 치면 그 자리에서
|
|
400
|
+
* 블록 유형이 바뀌고 방아쇠 문자는 사라진다. 메뉴를 열지 않고 글을 쓰던
|
|
401
|
+
* 흐름 그대로 유형을 고르는 길이다.
|
|
402
|
+
*
|
|
403
|
+
* 조건을 좁게 잡는다 — **본문 블록**에서, **캐럿이 그 텍스트 바로 뒤**에
|
|
404
|
+
* 있을 때만. 그렇지 않으면 이미 쓴 문단 중간에서 "- " 를 고치다가 블록이
|
|
405
|
+
* 통째로 바뀌는 사고가 난다.
|
|
406
|
+
*/
|
|
407
|
+
private handleInputRule;
|
|
408
|
+
/**
|
|
409
|
+
* 글머리 목록 항목에서 `[ ] ` / `[x] ` 를 알아보고 체크리스트로 바꾼다.
|
|
410
|
+
*
|
|
411
|
+
* `setBlockType` 을 쓰지 않는다 — 그 경로는 항목들을 `<br>` 로 이어 붙여
|
|
412
|
+
* 한 덩어리로 만들기 때문에, 항목이 여럿인 목록에서 줄이 뭉개진다. 목록
|
|
413
|
+
* 구조는 그대로 두고 클래스만 올린다.
|
|
414
|
+
*/
|
|
415
|
+
private applyTaskItemRule;
|
|
416
|
+
/**
|
|
417
|
+
* 블록 단축키. 처리했으면 `true`.
|
|
418
|
+
*
|
|
419
|
+
* 유형 변경은 `Ctrl/Cmd + Alt + 숫자` 다 — 구글 문서 · 노션이 같은 자리를
|
|
420
|
+
* 쓰기 때문에 손이 이미 알고 있는 배열이고, 브라우저 기본 단축키
|
|
421
|
+
* (Ctrl+숫자 = 탭 전환) 와 겹치지 않는다. 어느 유형의 블록에서든 다른
|
|
422
|
+
* 유형으로 바로 넘어간다.
|
|
423
|
+
*
|
|
424
|
+
* Ctrl+Alt+0 본문 Ctrl+Alt+1~6 제목 1~6
|
|
425
|
+
* Ctrl+Alt+7 번호 목록 Ctrl+Alt+8 글머리 목록
|
|
426
|
+
* Ctrl+Alt+9 인용구 Ctrl+Alt+C 코드 블록
|
|
427
|
+
* Ctrl+Shift+↑/↓ 블록 이동 Ctrl+Shift+D 블록 삭제
|
|
428
|
+
*
|
|
429
|
+
* 이동과 삭제는 캐럿이 어디 있든 **블록 단위**로 동작한다. 지금까지는
|
|
430
|
+
* 드래그 핸들을 잡는 것 말고는 블록을 옮길 방법이 없었다.
|
|
431
|
+
*/
|
|
432
|
+
private handleBlockShortcut;
|
|
433
|
+
/**
|
|
434
|
+
* 활성 블록을 위/아래 형제와 자리바꿈한다. 문서 끝에서는 아무 일도 하지
|
|
435
|
+
* 않는다 — 경고 없이 조용히 멈추는 편이 캐럿을 잃는 것보다 낫다.
|
|
436
|
+
*/
|
|
437
|
+
private moveActiveBlock;
|
|
438
|
+
/**
|
|
439
|
+
* 활성 블록을 지우고 캐럿을 이웃 블록으로 옮긴다.
|
|
440
|
+
*
|
|
441
|
+
* 마지막 블록을 지우면 `normalizeContent` 가 빈 본문 블록을 다시 만든다 —
|
|
442
|
+
* 본문이 블록 없는 상태로 남지 않는다.
|
|
443
|
+
*/
|
|
444
|
+
private deleteActiveBlock;
|
|
445
|
+
/**
|
|
446
|
+
* Tab 처리. 처리했으면 `true`.
|
|
447
|
+
*
|
|
448
|
+
* - 표 안: 다음(Shift 면 이전) 셀로 캐럿 이동. 마지막 셀에서 Tab 은 새 행을
|
|
449
|
+
* 만든다 — 표를 채워 넣을 때 손이 마우스로 갈 일이 없어진다.
|
|
450
|
+
* - 목록 안: `indent` / `outdent` 로 한 단계 들여쓰기. 중첩 목록을 만들
|
|
451
|
+
* 방법이 이것 말고는 없었다(마크다운으로 가져온 중첩 목록은 편집만 가능).
|
|
452
|
+
*/
|
|
453
|
+
private handleTabKey;
|
|
454
|
+
/**
|
|
455
|
+
* Backspace 처리. 처리했으면 `true`.
|
|
456
|
+
*
|
|
457
|
+
* 비어 있는 제목 · 인용구 · 코드 블록 · 목록의 맨 앞에서 Backspace 를 누르면
|
|
458
|
+
* **본문 블록으로 되돌린다.** 유형을 잘못 골랐을 때 되돌리는 가장 자연스러운
|
|
459
|
+
* 동작이고, 브라우저 기본 동작(앞 블록에 병합) 이 만들어 내는 이상한 중첩
|
|
460
|
+
* (제목 안에 목록이 들어가는 등) 도 함께 피한다.
|
|
461
|
+
*/
|
|
462
|
+
private handleBackspaceKey;
|
|
463
|
+
/**
|
|
464
|
+
* 활성 블록 뒤에 새 빈 **본문 블록**을 만들고 캐럿을 그 안에 둔다.
|
|
465
|
+
* 인용구 / 코드 블록의 Enter 탈출, 제목 끝 Enter 에 사용.
|
|
317
466
|
*/
|
|
318
467
|
private exitBlockOnEnter;
|
|
319
468
|
private syncBlockHandles;
|
|
469
|
+
/**
|
|
470
|
+
* 컨트롤(드래그 핸들 · 단락 추가) 은 **지금 다루고 있는 블록** 에만 보인다.
|
|
471
|
+
* 포인터가 놓인 블록과 캐럿이 있는 블록 두 가지가 그 대상이다.
|
|
472
|
+
*
|
|
473
|
+
* 예전에는 본문에 포인터만 올라가면 모든 블록의 핸들이 한꺼번에 흐리게
|
|
474
|
+
* 떠올랐다. 글이 길어질수록 왼쪽에 점 세 개짜리 기둥이 생겨서, 정작 어느
|
|
475
|
+
* 블록을 잡는 손잡이인지가 안 보였다.
|
|
476
|
+
*/
|
|
477
|
+
private syncHandleVisibility;
|
|
478
|
+
private readonly handleHoverMove;
|
|
479
|
+
private readonly handleHoverLeave;
|
|
480
|
+
private setHoveredBlock;
|
|
481
|
+
/**
|
|
482
|
+
* 뷰포트 y 좌표가 걸치는 블록의 id. 좌표가 블록들 사이의 여백이면 가장
|
|
483
|
+
* 가까운 블록으로 붙인다 — 문단 사이 간격에서 컨트롤이 깜빡이지 않게.
|
|
484
|
+
*/
|
|
485
|
+
private blockIdAtViewportY;
|
|
320
486
|
private repositionHandles;
|
|
321
487
|
private positionHandle;
|
|
322
488
|
private createBlockHandle;
|
|
@@ -351,6 +517,13 @@ export declare class AerizEditor {
|
|
|
351
517
|
* - 우측: 총 블록 수, 본문 글자 수(공백 제외)
|
|
352
518
|
*/
|
|
353
519
|
private syncStatusBar;
|
|
520
|
+
/**
|
|
521
|
+
* 되돌리기 / 다시 실행 버튼의 활성 상태.
|
|
522
|
+
*
|
|
523
|
+
* 누를 수 없는 버튼이 누를 수 있는 것처럼 보이면, 눌러 보고 아무 일도 안
|
|
524
|
+
* 일어나는 경험을 준다. 이력 끝에 닿았다는 사실 자체가 정보다.
|
|
525
|
+
*/
|
|
526
|
+
private syncHistoryButtons;
|
|
354
527
|
private syncBlockMarkers;
|
|
355
528
|
private applyToolbarState;
|
|
356
529
|
}
|
|
@@ -29,4 +29,70 @@ export declare const YOUTUBE_EMBED_BASE = "https://www.youtube-nocookie.com/embe
|
|
|
29
29
|
export declare const FILE_FALLBACK_NAME = "\uD30C\uC77C";
|
|
30
30
|
/** 블록의 안정 식별자를 담는 속성명. */
|
|
31
31
|
export declare const BLOCK_ID_ATTR = "data-block-id";
|
|
32
|
+
/**
|
|
33
|
+
* 눈에 보이지 않는 폭 없는 문자들 — ZWSP · ZWNJ · ZWJ · BOM.
|
|
34
|
+
*
|
|
35
|
+
* 에디터가 캐럿을 붙잡아 두려고 심는 U+200B 가 대표적이다. 글자 수를 세거나
|
|
36
|
+
* "이 블록이 비었나" 를 판단할 때 이것들을 글자로 치면 사용자가 보는 것과
|
|
37
|
+
* 다른 답이 나온다. 세 군데(글자 수 · 캐럿 판정 · 평문 추출)에서 같은 판정을
|
|
38
|
+
* 써야 해서 여기 한 번만 적는다.
|
|
39
|
+
*/
|
|
40
|
+
export declare const ZERO_WIDTH_RE: RegExp;
|
|
41
|
+
/**
|
|
42
|
+
* 스냅샷이 블록 element **자신**에서 함께 실어 나르는 속성.
|
|
43
|
+
*
|
|
44
|
+
* `html` 은 블록의 **안쪽**만 담고 `style` 은 따로 필드가 있다. 그래서 블록에
|
|
45
|
+
* 직접 걸린 나머지 속성은 아무 데도 실리지 않아 저장 한 번에 사라졌다.
|
|
46
|
+
* 잃으면 실제로 곤란한 것만 골라 담는다.
|
|
47
|
+
*
|
|
48
|
+
* - `id` : 문서 안 앵커 링크(`#section-1`) 가 끊긴다
|
|
49
|
+
* - `class`: 가져온 문서의 스타일 훅이 사라진다
|
|
50
|
+
* - `dir` : 아랍어 · 히브리어 문단의 쓰기 방향이 뒤집힌다
|
|
51
|
+
* - `lang` : 스크린 리더 발음과 하이픈 규칙이 바뀐다
|
|
52
|
+
* - `title`: 마우스를 올렸을 때 뜨는 설명
|
|
53
|
+
*
|
|
54
|
+
* **허용목록인 것이 핵심이다.** 전부 실어 나르면 `onclick` 같은 이벤트 핸들러
|
|
55
|
+
* 속성이 저장을 거쳐 되살아난다 — 저장된 글은 다른 사람에게 렌더된다.
|
|
56
|
+
*/
|
|
57
|
+
export declare const PRESERVED_BLOCK_ATTRS: ReadonlyArray<string>;
|
|
58
|
+
/**
|
|
59
|
+
* `unknown` 블록으로 되살릴 수 있는 태그.
|
|
60
|
+
*
|
|
61
|
+
* 저장된 값에서 온 태그명을 그대로 `createElement` 에 넘기면 안 된다 —
|
|
62
|
+
* `script` 를 만들어 내용을 넣고 문서에 붙이면 **실행된다** (innerHTML 경로와
|
|
63
|
+
* 달리 createElement 경로는 막히지 않는다). 내용을 담기만 하는 컨테이너
|
|
64
|
+
* 태그만 허용하고, 나머지는 `<div>` 로 떨어뜨린다.
|
|
65
|
+
*/
|
|
66
|
+
export declare const SAFE_UNKNOWN_TAGS: ReadonlySet<string>;
|
|
67
|
+
/** 저장된 태그명을 되살릴 수 있는 것으로 정규화한다. 알 수 없으면 `'div'`. */
|
|
68
|
+
export declare function safeUnknownTag(raw: string | undefined | null): string;
|
|
69
|
+
/**
|
|
70
|
+
* 클래스 이름들을 순서를 지키며 하나로 합친다 (중복 제거).
|
|
71
|
+
*
|
|
72
|
+
* 어떤 블록은 클래스가 곧 정체성이다 — `aw-task-list` 가 없으면 체크리스트가
|
|
73
|
+
* 글머리 목록으로 잡힌다. 그런데 스냅샷에 저장된 사용자 클래스도 함께 살려야
|
|
74
|
+
* 한다. 둘 중 하나를 고르면 반드시 무언가를 잃으므로 합친다.
|
|
75
|
+
*/
|
|
76
|
+
export declare function mergeClassNames(...values: ReadonlyArray<string | undefined | null>): string;
|
|
77
|
+
/** 체크리스트 `<ul>` 을 글머리 목록과 구분하는 클래스. */
|
|
78
|
+
export declare const TASK_LIST_CLASS = "aw-task-list";
|
|
79
|
+
/** 체크리스트 항목의 완료 여부를 담는 속성명. */
|
|
80
|
+
export declare const TASK_CHECKED_ATTR = "data-checked";
|
|
81
|
+
/**
|
|
82
|
+
* 링크 / 다운로드 URL 을 검사한다. 안전하면 원문 그대로, 아니면 빈 문자열.
|
|
83
|
+
*
|
|
84
|
+
* 스킴이 없는 값(상대 경로 · `#앵커` · `?쿼리`) 은 그대로 통과한다 — 문서
|
|
85
|
+
* 안에서 쓰는 정상적인 링크다.
|
|
86
|
+
*/
|
|
87
|
+
export declare function safeLinkUrl(raw: string | undefined | null): string;
|
|
88
|
+
/**
|
|
89
|
+
* 이미지 src 를 검사한다. 안전하면 원문 그대로, 아니면 빈 문자열.
|
|
90
|
+
* `data:image/...` 는 허용한다 — 이미지 다이얼로그의 임베드 탭이 만드는 값이다.
|
|
91
|
+
*/
|
|
92
|
+
export declare function safeImageUrl(raw: string | undefined | null): string;
|
|
93
|
+
/**
|
|
94
|
+
* YouTube 영상 ID 의 형태 검사. 임베드 URL 에 그대로 이어 붙이는 값이라
|
|
95
|
+
* `../` 나 따옴표가 섞이면 URL 자체가 다른 곳을 가리키게 된다.
|
|
96
|
+
*/
|
|
97
|
+
export declare function safeYouTubeId(raw: string | undefined | null): string;
|
|
32
98
|
// (소스맵은 CJS 선언 사본에서 제외됨 — scripts/finalize-types.mjs)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 블록이 무엇을 허용하는지, 그리고 화면에 어떻게 소개되는지.
|
|
3
|
+
*
|
|
4
|
+
* 툴바의 항목 표시 여부, 단축키가 먹히는지, 유형을 바꿀 때 어떤 서식을
|
|
5
|
+
* 남길지가 모두 같은 판정에서 나와야 한다. 한 곳에서만 답하게 두면
|
|
6
|
+
* "툴바에서는 안 보이는데 단축키로는 먹는" 종류의 어긋남이 생기지 않는다.
|
|
7
|
+
*
|
|
8
|
+
* 판정의 근거는 대부분 `BlockType` 에 이미 선언돼 있다 (`allowedMarks` ·
|
|
9
|
+
* `allowsColor` · `allowsFontSize` · `allowsInlineFormat`). 여기 있는 함수는
|
|
10
|
+
* 그 선언을 "활성 블록" 이라는 물음으로 바꿔 주는 얇은 층이다.
|
|
11
|
+
*/
|
|
12
|
+
import type { Block, BlockMatch, InlineMarkName } from './blocks.cjs';
|
|
13
|
+
/**
|
|
14
|
+
* 활성 블록이 특정 인라인 마크를 허용하는지.
|
|
15
|
+
*
|
|
16
|
+
* paragraph / 목록 / 체크리스트 / table — 모든 마크
|
|
17
|
+
* heading — italic 만 (제목은 이미 굵고, 밑줄·취소선은 시맨틱에 안 맞는다)
|
|
18
|
+
* blockquote — bold / underline / strike (인용구는 이미 italic 으로 렌더된다)
|
|
19
|
+
* codeBlock 및 원자 블록 — 없음
|
|
20
|
+
*/
|
|
21
|
+
export declare function isMarkAllowed(active: Block | null, mark: InlineMarkName): boolean;
|
|
22
|
+
/** 인라인 서식(글꼴 등) 적용을 허용하는지. */
|
|
23
|
+
export declare function isInlineFormatAllowed(active: Block | null): boolean;
|
|
24
|
+
/** 글자 크기 조정을 허용하는지. heading 은 level 이 크기를 정하므로 false. */
|
|
25
|
+
export declare function isFontSizeAllowed(active: Block | null): boolean;
|
|
26
|
+
/** 글자색 / 배경색 적용을 허용하는지. heading · blockquote 는 톤 보존을 위해 false. */
|
|
27
|
+
export declare function isColorAllowed(active: Block | null): boolean;
|
|
28
|
+
export declare function isAlignAllowed(active: Block | null): boolean;
|
|
29
|
+
/** 표 전용 도구(셀 배경 · 표 편집) 를 켤 조건. */
|
|
30
|
+
export declare function isTableActive(active: Block | null): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* 블록 라벨.
|
|
33
|
+
*
|
|
34
|
+
* 블록은 언제나 자기 kind 의 정식 라벨을 단다. 비어 있다고 해서 유형이 없는
|
|
35
|
+
* 것이 아니다 — Enter 로 갓 생긴 빈 블록은 **본문 블록**이고 그렇게 보여야
|
|
36
|
+
* 한다. 예전에는 이런 블록에 '?' 를 달았는데, 사용자에게 "아직 유형이 정해지지
|
|
37
|
+
* 않은 블록" 이라는 없는 상태를 만들어 보여 준 셈이었다.
|
|
38
|
+
*
|
|
39
|
+
* 어떤 BlockType 에도 매칭되지 않은 element(`unknown`) 만 태그명을 쓴다.
|
|
40
|
+
*/
|
|
41
|
+
export declare function blockLabelFor(el: HTMLElement, match: BlockMatch): string;
|
|
42
|
+
export declare function blockGlyphFor(match: BlockMatch): string;
|
|
43
|
+
// (소스맵은 CJS 선언 사본에서 제외됨 — scripts/finalize-types.mjs)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type BlockKind = 'paragraph' | 'heading' | 'bulletList' | 'orderedList' | 'blockquote' | 'codeBlock' | 'image' | 'table' | 'hr' | 'linkCard' | 'youtube' | 'file' | 'importedHtml' | 'unknown';
|
|
1
|
+
export type BlockKind = 'paragraph' | 'heading' | 'bulletList' | 'orderedList' | 'taskList' | 'blockquote' | 'codeBlock' | 'image' | 'table' | 'hr' | 'linkCard' | 'youtube' | 'file' | 'importedHtml' | 'unknown';
|
|
2
2
|
export type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
|
|
3
3
|
/** 단락 — 메타데이터 없음. */
|
|
4
4
|
export interface ParagraphAttrs {
|
|
@@ -13,6 +13,12 @@ export interface BulletListAttrs {
|
|
|
13
13
|
/** 번호 목록(ordered) — kind 자체가 ordered=true 를 의미. 추가 메타 없음. */
|
|
14
14
|
export interface OrderedListAttrs {
|
|
15
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* 체크리스트 — 항목별 완료 여부는 `<li data-checked>` 로 html 안에 담긴다.
|
|
18
|
+
* 블록 단위 메타는 없다.
|
|
19
|
+
*/
|
|
20
|
+
export interface TaskListAttrs {
|
|
21
|
+
}
|
|
16
22
|
/** 인용구 — 메타데이터 없음. */
|
|
17
23
|
export interface BlockquoteAttrs {
|
|
18
24
|
}
|
|
@@ -25,6 +31,18 @@ export interface CodeBlockAttrs {
|
|
|
25
31
|
export interface ImageAttrs {
|
|
26
32
|
src?: string;
|
|
27
33
|
alt?: string;
|
|
34
|
+
/**
|
|
35
|
+
* 그림 아래 설명(`<figcaption>`) 의 **텍스트**.
|
|
36
|
+
*
|
|
37
|
+
* `alt` 와는 다른 값이다 — `alt` 는 그림을 못 보는 사람에게 그림을 대신
|
|
38
|
+
* 설명하는 글이고, 캡션은 보는 사람에게도 함께 읽히는 본문의 일부다
|
|
39
|
+
* (출처 · 촬영 정보 · 부연). 둘을 한 필드로 합치면 어느 쪽도 제 역할을
|
|
40
|
+
* 못 한다.
|
|
41
|
+
*
|
|
42
|
+
* 서식이 들어간 캡션(링크 등) 은 `snapshot.html` 에 그대로 실린다. 이
|
|
43
|
+
* 필드는 `html` 이 비어 있을 때 골격을 조립하기 위한 평문이다.
|
|
44
|
+
*/
|
|
45
|
+
caption?: string;
|
|
28
46
|
/** wrapper(figure) 의 인라인 style — width / margin 등 outer 스타일 보존. */
|
|
29
47
|
wrapperStyle?: string;
|
|
30
48
|
}
|
|
@@ -75,6 +93,14 @@ export interface ImportedHtmlAttrs {
|
|
|
75
93
|
}
|
|
76
94
|
/** 어떤 BlockType 에도 매칭되지 않은 element. */
|
|
77
95
|
export interface UnknownAttrs {
|
|
96
|
+
/**
|
|
97
|
+
* 원래 태그명 (소문자).
|
|
98
|
+
*
|
|
99
|
+
* `unknown` 은 미래 버전의 블록이 강등되어 오는 자리다. 태그를 버리면 그
|
|
100
|
+
* 블록을 만든 버전에서 다시 열었을 때도 `<div>` 로 남아 영영 복구되지
|
|
101
|
+
* 않는다. 안전한 컨테이너 태그만 되살린다 ({@link SAFE_UNKNOWN_TAGS}).
|
|
102
|
+
*/
|
|
103
|
+
tag?: string;
|
|
78
104
|
}
|
|
79
105
|
/** BlockKind → 해당 블록의 attrs 타입 매핑. discriminated union 의 기반. */
|
|
80
106
|
export interface BlockAttrsByKind {
|
|
@@ -82,6 +108,7 @@ export interface BlockAttrsByKind {
|
|
|
82
108
|
heading: HeadingAttrs;
|
|
83
109
|
bulletList: BulletListAttrs;
|
|
84
110
|
orderedList: OrderedListAttrs;
|
|
111
|
+
taskList: TaskListAttrs;
|
|
85
112
|
blockquote: BlockquoteAttrs;
|
|
86
113
|
codeBlock: CodeBlockAttrs;
|
|
87
114
|
image: ImageAttrs;
|
|
@@ -99,7 +126,7 @@ export interface BlockAttrsByKind {
|
|
|
99
126
|
* 외부에서 직렬화된 BlockSnapshot 의 attrs 는 BlockAttrsByKind[kind] 로 더
|
|
100
127
|
* 구체적으로 타입이 잡힌다 — 아래 BlockSnapshot 의 discriminated union 참고.
|
|
101
128
|
*/
|
|
102
|
-
export interface BlockAttrs extends Partial<HeadingAttrs>, Partial<BulletListAttrs>, Partial<OrderedListAttrs>, Partial<CodeBlockAttrs>, Partial<ImageAttrs>, Partial<TableAttrs>, Partial<LinkCardAttrs>, Partial<YoutubeAttrs>, Partial<FileAttrs>, Partial<ImportedHtmlAttrs> {
|
|
129
|
+
export interface BlockAttrs extends Partial<HeadingAttrs>, Partial<BulletListAttrs>, Partial<OrderedListAttrs>, Partial<CodeBlockAttrs>, Partial<ImageAttrs>, Partial<TableAttrs>, Partial<LinkCardAttrs>, Partial<YoutubeAttrs>, Partial<FileAttrs>, Partial<ImportedHtmlAttrs>, Partial<UnknownAttrs> {
|
|
103
130
|
}
|
|
104
131
|
/**
|
|
105
132
|
* BlockType.matches() 의 반환 타입. 내부 사용은 느슨한 BlockAttrs 로 두고,
|
|
@@ -197,9 +224,18 @@ export declare function assignMissingIds(root: HTMLElement, ids: BlockIdRegistry
|
|
|
197
224
|
* "homeless" 텍스트가 생길 수 있는데, 이를 정규화하여 모든 본문 자식이
|
|
198
225
|
* 항상 유효한 블록 element 가 되도록 보장한다.
|
|
199
226
|
*/
|
|
200
|
-
export
|
|
227
|
+
export interface NormalizeOptions {
|
|
228
|
+
/**
|
|
229
|
+
* 본문이 항상 캐럿을 받을 수 있는 상태로 끝나도록 빈 본문 블록을 보장할지.
|
|
230
|
+
* 기본 `true` (편집 경로). HTML → 블록 변환처럼 **편집하지 않는** 용도라면
|
|
231
|
+
* `false` 로 꺼서 없던 빈 단락이 결과에 끼어들지 않게 한다.
|
|
232
|
+
*/
|
|
233
|
+
writableTail?: boolean;
|
|
234
|
+
}
|
|
235
|
+
export declare function normalizeContent(root: HTMLElement, options?: NormalizeOptions): void;
|
|
201
236
|
/**
|
|
202
|
-
* 사람이 읽을 수 있는
|
|
237
|
+
* 사람이 읽을 수 있는 블록 라벨. 포커스된 블록 위 태그 표시 등에 사용.
|
|
238
|
+
* 문자열은 현재 로케일(`setLocale`) 사전에서 가져온다.
|
|
203
239
|
*/
|
|
204
240
|
export declare function getBlockLabel(match: BlockMatch): string;
|
|
205
241
|
export type BlockIdResolver = (el: HTMLElement) => string;
|
|
@@ -229,6 +265,13 @@ export type BlockSnapshot = {
|
|
|
229
265
|
attrs: BlockAttrsByKind[K];
|
|
230
266
|
html: string;
|
|
231
267
|
style?: string;
|
|
268
|
+
/**
|
|
269
|
+
* 블록 element 자신의 나머지 속성 (`id` · `class` · `dir` · `lang` ·
|
|
270
|
+
* `title`). `html` 은 안쪽만, `style` 은 따로 담기 때문에 이 필드가 없으면
|
|
271
|
+
* 저장 한 번에 사라진다 — 앵커 링크가 끊기고 RTL 문단의 방향이 뒤집힌다.
|
|
272
|
+
* 허용목록은 `PRESERVED_BLOCK_ATTRS`.
|
|
273
|
+
*/
|
|
274
|
+
attributes?: Record<string, string>;
|
|
232
275
|
};
|
|
233
276
|
}[BlockKind];
|
|
234
277
|
/** 특정 BlockKind 에 한정된 BlockSnapshot 의 별칭. 외부에서 narrow 한
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 본문 편집 이력(undo / redo).
|
|
3
|
+
*
|
|
4
|
+
* ## 왜 브라우저 기본 undo 를 쓰지 않는가
|
|
5
|
+
*
|
|
6
|
+
* `document.execCommand('undo')` 는 브라우저가 **자기가 만든 변경**만 되돌린다.
|
|
7
|
+
* 이 에디터는 블록 이동 · 표 행/열 편집 · 이미지 리사이즈 · 블록 유형 변경을
|
|
8
|
+
* 전부 직접 DOM 조작으로 처리하는데, 그 조작들은 브라우저 undo 스택에 아예
|
|
9
|
+
* 올라가지 않는다. 결과적으로 Ctrl+Z 를 누르면 방금 옮긴 블록은 그대로 있고
|
|
10
|
+
* 그 전에 타이핑한 글자가 지워지는, 예측할 수 없는 동작이 된다.
|
|
11
|
+
*
|
|
12
|
+
* ## 무엇을 저장하는가
|
|
13
|
+
*
|
|
14
|
+
* 본문 HTML 전체와 캐럿 위치를 한 항목으로 저장하는 스냅샷 방식이다.
|
|
15
|
+
* 조작 단위 이력(operation log) 이 메모리는 덜 쓰지만, 되돌리기가 **정확히**
|
|
16
|
+
* 원래 화면으로 돌아간다는 보장을 얻기가 훨씬 어렵다. 스냅샷은 그 보장이
|
|
17
|
+
* 공짜다 — 문자열을 도로 넣기만 하면 된다.
|
|
18
|
+
*
|
|
19
|
+
* 캐럿은 문자 오프셋으로 저장한다. HTML 을 통째로 갈아끼우면 노드 참조는
|
|
20
|
+
* 전부 무효가 되지만, "본문 시작에서 몇 번째 글자" 는 그대로 살아남는다.
|
|
21
|
+
*
|
|
22
|
+
* ## 언제 한 항목으로 묶는가
|
|
23
|
+
*
|
|
24
|
+
* 글자 하나마다 항목을 쌓으면 되돌리기가 사실상 쓸모없어진다. 연속된 타이핑은
|
|
25
|
+
* {@link COALESCE_MS} 안에 이어지는 한 하나로 합친다. 반대로 블록 이동 ·
|
|
26
|
+
* 유형 변경처럼 **구조가 바뀌는 조작**은 합치지 않는다 — 그건 사용자가 한
|
|
27
|
+
* 번에 하나씩 되돌리길 기대하는 단위다.
|
|
28
|
+
*/
|
|
29
|
+
/** 이력 한 항목 — 그 순간의 본문 전체와 캐럿. */
|
|
30
|
+
export interface HistoryEntry {
|
|
31
|
+
html: string;
|
|
32
|
+
/** 본문 시작 기준 캐럿 시작/끝 문자 오프셋. 셀렉션이 없으면 null. */
|
|
33
|
+
selection: {
|
|
34
|
+
start: number;
|
|
35
|
+
end: number;
|
|
36
|
+
} | null;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* 이 시간 안에 이어지는 타이핑은 한 항목으로 합친다.
|
|
40
|
+
* 사람이 문장 하나를 치는 동안의 간격보다 짧게, 생각하고 다시 치기 시작하는
|
|
41
|
+
* 간격보다는 길게 잡은 값이다.
|
|
42
|
+
*/
|
|
43
|
+
export declare const COALESCE_MS = 600;
|
|
44
|
+
/** 스택에 쌓아 두는 최대 항목 수. 넘치면 가장 오래된 것부터 버린다. */
|
|
45
|
+
export declare const HISTORY_LIMIT = 200;
|
|
46
|
+
/**
|
|
47
|
+
* 이 길이를 넘게 한 번에 바뀌면 타이핑으로 보지 않는다.
|
|
48
|
+
*
|
|
49
|
+
* 붙여넣기는 `input` 이벤트로 들어와 타이핑과 구분되지 않는다. 그대로 두면
|
|
50
|
+
* "글 좀 쓰다가 붙여넣기" 가 한 항목으로 묶여, 붙여넣기를 되돌리려다 앞서
|
|
51
|
+
* 쓴 글까지 함께 사라진다. 사람이 600ms 안에 칠 수 있는 양보다 넉넉히 크게
|
|
52
|
+
* 잡아, 실제 타이핑이 여기 걸리지 않도록 한다.
|
|
53
|
+
*/
|
|
54
|
+
export declare const BULK_CHANGE_CHARS = 64;
|
|
55
|
+
/** 변경의 성격 — 합쳐도 되는 타이핑인지, 한 단위로 남아야 하는 조작인지. */
|
|
56
|
+
export type ChangeKind = 'typing' | 'structural';
|
|
57
|
+
export declare class History {
|
|
58
|
+
private readonly past;
|
|
59
|
+
private readonly future;
|
|
60
|
+
/** 지금 화면에 보이는 상태. past 의 마지막이 아니라 이 값이 현재다. */
|
|
61
|
+
private present;
|
|
62
|
+
/** 마지막으로 항목을 쌓은 시각과 성격 — 합침 판단에 쓴다. */
|
|
63
|
+
private lastPushAt;
|
|
64
|
+
private lastKind;
|
|
65
|
+
constructor(initial: HistoryEntry);
|
|
66
|
+
get canUndo(): boolean;
|
|
67
|
+
get canRedo(): boolean;
|
|
68
|
+
/**
|
|
69
|
+
* 새 상태를 기록한다.
|
|
70
|
+
*
|
|
71
|
+
* @param now 현재 시각(ms). 테스트가 시간을 직접 넣을 수 있도록 인자로 받는다.
|
|
72
|
+
*/
|
|
73
|
+
record(entry: HistoryEntry, kind: ChangeKind, now: number): void;
|
|
74
|
+
/** 되돌린다. 되돌릴 것이 없으면 null. */
|
|
75
|
+
undo(): HistoryEntry | null;
|
|
76
|
+
/** 다시 실행한다. 없으면 null. */
|
|
77
|
+
redo(): HistoryEntry | null;
|
|
78
|
+
/** 현재 상태. 외부에서 비교용으로 읽는다. */
|
|
79
|
+
current(): HistoryEntry;
|
|
80
|
+
/**
|
|
81
|
+
* 이력을 비우고 주어진 상태에서 다시 시작한다.
|
|
82
|
+
* `setHTML()` 처럼 문서를 통째로 갈아끼우는 프로그램적 변경에 쓴다.
|
|
83
|
+
*/
|
|
84
|
+
reset(entry: HistoryEntry): void;
|
|
85
|
+
}
|
|
86
|
+
// (소스맵은 CJS 선언 사본에서 제외됨 — scripts/finalize-types.mjs)
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
export type Locale = 'en' | 'ko' | 'ja' | 'zh';
|
|
11
11
|
export interface Strings {
|
|
12
12
|
toolbar: {
|
|
13
|
+
/** 툴바 컨테이너의 aria-label. */
|
|
14
|
+
ariaLabel: string;
|
|
13
15
|
undo: string;
|
|
14
16
|
redo: string;
|
|
15
17
|
blockType: string;
|
|
@@ -44,6 +46,7 @@ export interface Strings {
|
|
|
44
46
|
heading: string;
|
|
45
47
|
bulletList: string;
|
|
46
48
|
orderedList: string;
|
|
49
|
+
taskList: string;
|
|
47
50
|
blockquote: string;
|
|
48
51
|
codeBlock: string;
|
|
49
52
|
image: string;
|
|
@@ -57,6 +60,7 @@ export interface Strings {
|
|
|
57
60
|
};
|
|
58
61
|
blockMenu: {
|
|
59
62
|
body: string;
|
|
63
|
+
taskList: string;
|
|
60
64
|
h1: string;
|
|
61
65
|
h2: string;
|
|
62
66
|
h3: string;
|
|
@@ -135,6 +139,10 @@ export interface Strings {
|
|
|
135
139
|
urlPlaceholder: string;
|
|
136
140
|
uploadDropzone: string;
|
|
137
141
|
noUploadApi: string;
|
|
142
|
+
/** 캡션 버튼 tooltip. */
|
|
143
|
+
captionAdd: string;
|
|
144
|
+
/** 빈 캡션에 흐리게 뜨는 안내. */
|
|
145
|
+
captionPlaceholder: string;
|
|
138
146
|
};
|
|
139
147
|
youtube: {
|
|
140
148
|
title: string;
|
|
@@ -186,6 +194,10 @@ export interface Strings {
|
|
|
186
194
|
uploadFailed: string;
|
|
187
195
|
errEmpty: string;
|
|
188
196
|
};
|
|
197
|
+
content: {
|
|
198
|
+
/** 캐럿이 놓인 빈 본문 블록에 흐릿하게 뜨는 안내. */
|
|
199
|
+
emptyHint: string;
|
|
200
|
+
};
|
|
189
201
|
status: {
|
|
190
202
|
/** "{label} ({id8})" 의 prefix 라벨용 */
|
|
191
203
|
noActive: string;
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
*
|
|
12
12
|
* 다른 origin / iframe contentDocument 접근 제한이 발생하면 reject.
|
|
13
13
|
*/
|
|
14
|
+
export declare function isBlockLevelTag(tagName: string): boolean;
|
|
14
15
|
export interface ImportHtmlOptions {
|
|
15
16
|
/** iframe load 후 추가 idle 대기(ms). Tailwind CDN 등 런타임 스타일 주입을
|
|
16
17
|
* 기다리기 위해 기본 1000ms. */
|
|
@@ -25,10 +25,6 @@
|
|
|
25
25
|
* - 자동 링크: `<https://…>`
|
|
26
26
|
* - 줄바꿈: 줄 끝 두 칸 공백 → `<br>`
|
|
27
27
|
*/
|
|
28
|
-
/**
|
|
29
|
-
* Markdown 문자열을 본문에 삽입할 수 있는 HTMLElement 배열로 변환한다.
|
|
30
|
-
* 결과 element 들은 에디터의 네이티브 블록 유형으로 인식 가능한 표준 태그.
|
|
31
|
-
*/
|
|
32
28
|
export declare function markdownToBlocks(md: string): HTMLElement[];
|
|
33
29
|
/**
|
|
34
30
|
* Markdown 문자열을 HTML 문자열로 변환. 외부 직접 사용 가능 (테스트 등).
|