@moda-editor/core 0.1.1
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/LICENSE +21 -0
- package/README.md +16 -0
- package/dist/commands.d.ts +78 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +299 -0
- package/dist/commands.js.map +1 -0
- package/dist/conformance.d.ts +59 -0
- package/dist/conformance.d.ts.map +1 -0
- package/dist/conformance.js +1609 -0
- package/dist/conformance.js.map +1 -0
- package/dist/core.d.ts +37 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +117 -0
- package/dist/core.js.map +1 -0
- package/dist/editor/editor.d.ts +104 -0
- package/dist/editor/editor.d.ts.map +1 -0
- package/dist/editor/editor.js +204 -0
- package/dist/editor/editor.js.map +1 -0
- package/dist/editor/extension.d.ts +170 -0
- package/dist/editor/extension.d.ts.map +1 -0
- package/dist/editor/extension.js +2 -0
- package/dist/editor/extension.js.map +1 -0
- package/dist/features/ace.d.ts +9 -0
- package/dist/features/ace.d.ts.map +1 -0
- package/dist/features/ace.js +144 -0
- package/dist/features/ace.js.map +1 -0
- package/dist/features/alignment.d.ts +9 -0
- package/dist/features/alignment.d.ts.map +1 -0
- package/dist/features/alignment.js +28 -0
- package/dist/features/alignment.js.map +1 -0
- package/dist/features/blockquote.d.ts +9 -0
- package/dist/features/blockquote.d.ts.map +1 -0
- package/dist/features/blockquote.js +65 -0
- package/dist/features/blockquote.js.map +1 -0
- package/dist/features/code-block.d.ts +77 -0
- package/dist/features/code-block.d.ts.map +1 -0
- package/dist/features/code-block.js +986 -0
- package/dist/features/code-block.js.map +1 -0
- package/dist/features/doc.d.ts +15 -0
- package/dist/features/doc.d.ts.map +1 -0
- package/dist/features/doc.js +79 -0
- package/dist/features/doc.js.map +1 -0
- package/dist/features/feature.d.ts +26 -0
- package/dist/features/feature.d.ts.map +1 -0
- package/dist/features/feature.js +8 -0
- package/dist/features/feature.js.map +1 -0
- package/dist/features/hard-break.d.ts +9 -0
- package/dist/features/hard-break.d.ts.map +1 -0
- package/dist/features/hard-break.js +48 -0
- package/dist/features/hard-break.js.map +1 -0
- package/dist/features/heading.d.ts +3 -0
- package/dist/features/heading.d.ts.map +1 -0
- package/dist/features/heading.js +31 -0
- package/dist/features/heading.js.map +1 -0
- package/dist/features/horizontal-rule.d.ts +9 -0
- package/dist/features/horizontal-rule.d.ts.map +1 -0
- package/dist/features/horizontal-rule.js +64 -0
- package/dist/features/horizontal-rule.js.map +1 -0
- package/dist/features/image.d.ts +12 -0
- package/dist/features/image.d.ts.map +1 -0
- package/dist/features/image.js +116 -0
- package/dist/features/image.js.map +1 -0
- package/dist/features/index.d.ts +31 -0
- package/dist/features/index.d.ts.map +1 -0
- package/dist/features/index.js +65 -0
- package/dist/features/index.js.map +1 -0
- package/dist/features/inline-style.d.ts +12 -0
- package/dist/features/inline-style.d.ts.map +1 -0
- package/dist/features/inline-style.js +126 -0
- package/dist/features/inline-style.js.map +1 -0
- package/dist/features/link.d.ts +29 -0
- package/dist/features/link.d.ts.map +1 -0
- package/dist/features/link.js +198 -0
- package/dist/features/link.js.map +1 -0
- package/dist/features/lists.d.ts +14 -0
- package/dist/features/lists.d.ts.map +1 -0
- package/dist/features/lists.js +178 -0
- package/dist/features/lists.js.map +1 -0
- package/dist/features/marks.d.ts +6 -0
- package/dist/features/marks.d.ts.map +1 -0
- package/dist/features/marks.js +68 -0
- package/dist/features/marks.js.map +1 -0
- package/dist/features/script.d.ts +2 -0
- package/dist/features/script.d.ts.map +1 -0
- package/dist/features/script.js +55 -0
- package/dist/features/script.js.map +1 -0
- package/dist/features/table.d.ts +20 -0
- package/dist/features/table.d.ts.map +1 -0
- package/dist/features/table.js +195 -0
- package/dist/features/table.js.map +1 -0
- package/dist/features/task-list.d.ts +10 -0
- package/dist/features/task-list.d.ts.map +1 -0
- package/dist/features/task-list.js +68 -0
- package/dist/features/task-list.js.map +1 -0
- package/dist/features/testkit.d.ts +32 -0
- package/dist/features/testkit.d.ts.map +1 -0
- package/dist/features/testkit.js +92 -0
- package/dist/features/testkit.js.map +1 -0
- package/dist/history.d.ts +40 -0
- package/dist/history.d.ts.map +1 -0
- package/dist/history.js +192 -0
- package/dist/history.js.map +1 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/model/node.d.ts +47 -0
- package/dist/model/node.d.ts.map +1 -0
- package/dist/model/node.js +30 -0
- package/dist/model/node.js.map +1 -0
- package/dist/model/schema.d.ts +105 -0
- package/dist/model/schema.d.ts.map +1 -0
- package/dist/model/schema.js +46 -0
- package/dist/model/schema.js.map +1 -0
- package/dist/model/traverse.d.ts +36 -0
- package/dist/model/traverse.d.ts.map +1 -0
- package/dist/model/traverse.js +123 -0
- package/dist/model/traverse.js.map +1 -0
- package/dist/mount.d.ts +24 -0
- package/dist/mount.d.ts.map +1 -0
- package/dist/mount.js +45 -0
- package/dist/mount.js.map +1 -0
- package/dist/parse/html.d.ts +8 -0
- package/dist/parse/html.d.ts.map +1 -0
- package/dist/parse/html.js +247 -0
- package/dist/parse/html.js.map +1 -0
- package/dist/parse/sanitize.d.ts +20 -0
- package/dist/parse/sanitize.d.ts.map +1 -0
- package/dist/parse/sanitize.js +116 -0
- package/dist/parse/sanitize.js.map +1 -0
- package/dist/presets/highlight.d.ts +23 -0
- package/dist/presets/highlight.d.ts.map +1 -0
- package/dist/presets/highlight.js +170 -0
- package/dist/presets/highlight.js.map +1 -0
- package/dist/presets/starter.d.ts +14 -0
- package/dist/presets/starter.d.ts.map +1 -0
- package/dist/presets/starter.js +18 -0
- package/dist/presets/starter.js.map +1 -0
- package/dist/state/apply.d.ts +64 -0
- package/dist/state/apply.d.ts.map +1 -0
- package/dist/state/apply.js +528 -0
- package/dist/state/apply.js.map +1 -0
- package/dist/state/navigate.d.ts +5 -0
- package/dist/state/navigate.d.ts.map +1 -0
- package/dist/state/navigate.js +81 -0
- package/dist/state/navigate.js.map +1 -0
- package/dist/state/selection.d.ts +44 -0
- package/dist/state/selection.d.ts.map +1 -0
- package/dist/state/selection.js +63 -0
- package/dist/state/selection.js.map +1 -0
- package/dist/state/state.d.ts +39 -0
- package/dist/state/state.d.ts.map +1 -0
- package/dist/state/state.js +123 -0
- package/dist/state/state.js.map +1 -0
- package/dist/state/transaction.d.ts +234 -0
- package/dist/state/transaction.d.ts.map +1 -0
- package/dist/state/transaction.js +988 -0
- package/dist/state/transaction.js.map +1 -0
- package/dist/styles.css +948 -0
- package/dist/types.d.ts +44 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/view/dom.d.ts +26 -0
- package/dist/view/dom.d.ts.map +1 -0
- package/dist/view/dom.js +249 -0
- package/dist/view/dom.js.map +1 -0
- package/dist/view/input.d.ts +45 -0
- package/dist/view/input.d.ts.map +1 -0
- package/dist/view/input.js +901 -0
- package/dist/view/input.js.map +1 -0
- package/dist/view/mount.d.ts +26 -0
- package/dist/view/mount.d.ts.map +1 -0
- package/dist/view/mount.js +119 -0
- package/dist/view/mount.js.map +1 -0
- package/dist/view/render.d.ts +64 -0
- package/dist/view/render.d.ts.map +1 -0
- package/dist/view/render.js +203 -0
- package/dist/view/render.js.map +1 -0
- package/dist/view/serialize.d.ts +4 -0
- package/dist/view/serialize.d.ts.map +1 -0
- package/dist/view/serialize.js +37 -0
- package/dist/view/serialize.js.map +1 -0
- package/package.json +44 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Extension } from "./editor/extension.js";
|
|
2
|
+
import type { DocNode } from "./model/node.js";
|
|
3
|
+
import type { Selection } from "./state/selection.js";
|
|
4
|
+
import type { Step } from "./state/transaction.js";
|
|
5
|
+
export declare const HISTORY_KEY = "history";
|
|
6
|
+
export interface HistoryEntry {
|
|
7
|
+
/** 되돌리기용 — 원 스텝의 역스텝(역순 평탄화) */
|
|
8
|
+
inverse: Step[];
|
|
9
|
+
/** 재실행용 원 스텝 */
|
|
10
|
+
steps: Step[];
|
|
11
|
+
selBefore: Selection;
|
|
12
|
+
selAfter: Selection;
|
|
13
|
+
/** 같은 그룹의 연속 편집은 한 엔트리로 뭉친다 (tr.meta["history.group"]) */
|
|
14
|
+
group: string | null;
|
|
15
|
+
/** 마지막 편집 시각(ms) — 그룹 병합 시간 창 판정용 */
|
|
16
|
+
time: number;
|
|
17
|
+
}
|
|
18
|
+
export interface HistoryState {
|
|
19
|
+
done: HistoryEntry[];
|
|
20
|
+
undone: HistoryEntry[];
|
|
21
|
+
}
|
|
22
|
+
export declare function historyOf(state: {
|
|
23
|
+
pluginState: Readonly<Record<string, unknown>>;
|
|
24
|
+
}): HistoryState;
|
|
25
|
+
export declare function canUndo(state: {
|
|
26
|
+
pluginState: Readonly<Record<string, unknown>>;
|
|
27
|
+
}): boolean;
|
|
28
|
+
export declare function canRedo(state: {
|
|
29
|
+
pluginState: Readonly<Record<string, unknown>>;
|
|
30
|
+
}): boolean;
|
|
31
|
+
/** 단일 스텝의 역변환 — doc은 스텝 적용 "전" 문서 */
|
|
32
|
+
export declare function invertStep(step: Step, doc: DocNode): Step[];
|
|
33
|
+
/** 스텝 시퀀스의 역변환 — 각 스텝을 순차 적용해가며 계산 후 역순 */
|
|
34
|
+
export declare function invertSteps(steps: readonly Step[], docBefore: DocNode): Step[];
|
|
35
|
+
/**
|
|
36
|
+
* undo/redo 확장 — starterExtensions에 포함된다.
|
|
37
|
+
* commands.undo()/redo() + Mod-z / Mod-Shift-z / Mod-y 키맵.
|
|
38
|
+
*/
|
|
39
|
+
export declare function historyExtension(): Extension;
|
|
40
|
+
//# sourceMappingURL=history.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../src/history.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,SAAS,EAAU,MAAM,uBAAuB,CAAC;AACxE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAG/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAuBnD,eAAO,MAAM,WAAW,YAAY,CAAC;AAErC,MAAM,WAAW,YAAY;IAC3B,gCAAgC;IAChC,OAAO,EAAE,IAAI,EAAE,CAAC;IAChB,gBAAgB;IAChB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,SAAS,EAAE,SAAS,CAAC;IACrB,QAAQ,EAAE,SAAS,CAAC;IACpB,0DAA0D;IAC1D,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,YAAY,EAAE,CAAC;IACrB,MAAM,EAAE,YAAY,EAAE,CAAC;CACxB;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE;IAC/B,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAChD,GAAG,YAAY,CAOf;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE;IAC7B,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAChD,GAAG,OAAO,CAEV;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE;IAC7B,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAChD,GAAG,OAAO,CAEV;AAED,qCAAqC;AACrC,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,GAAG,IAAI,EAAE,CAmD3D;AAED,2CAA2C;AAC3C,wBAAgB,WAAW,CACzB,KAAK,EAAE,SAAS,IAAI,EAAE,EACtB,SAAS,EAAE,OAAO,GACjB,IAAI,EAAE,CAQR;AA4ED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,SAAS,CAY5C"}
|
package/dist/history.js
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { nodeAt } from "./model/traverse.js";
|
|
2
|
+
import { applyStep, computeSplitOps } from "./state/apply.js";
|
|
3
|
+
/**
|
|
4
|
+
* 히스토리 — Step의 순수 JSON 설계가 실현되는 곳.
|
|
5
|
+
*
|
|
6
|
+
* 모든 Step은 (step, docBefore) → 역스텝으로 역변환된다:
|
|
7
|
+
* insert ↔ remove (스텝이 이미 노드를 들고 있다)
|
|
8
|
+
* setAttr → prev 값으로 되돌리기
|
|
9
|
+
* split → join 경계 / join → seam split
|
|
10
|
+
* addMark ↔ removeMark
|
|
11
|
+
*
|
|
12
|
+
* Lexical의 update 클로저는 역변환 불가라 별도 변경 추적이 필요하고,
|
|
13
|
+
* PM은 Step 클래스에 인스턴스 메서드로 invert를 둔다 — 우리는 순수
|
|
14
|
+
* 함수라 직렬화된 트랜잭션 로그만으로도 undo를 재구성할 수 있다.
|
|
15
|
+
*
|
|
16
|
+
* 알려진 한계:
|
|
17
|
+
* - removeMark 역변환은 마크 attrs를 복원하지 못한다 (type만 복원)
|
|
18
|
+
* - join은 병합 시 next 노드 attrs를 버리므로 되돌려도 attrs는 prev 것
|
|
19
|
+
*/
|
|
20
|
+
const DEPTH = 100;
|
|
21
|
+
/** 같은 그룹 연속 편집을 한 엔트리로 뭉치는 시간 창 — PM newGroupDelay */
|
|
22
|
+
const GROUP_DELAY = 500;
|
|
23
|
+
export const HISTORY_KEY = "history";
|
|
24
|
+
export function historyOf(state) {
|
|
25
|
+
return (state.pluginState[HISTORY_KEY] ?? {
|
|
26
|
+
done: [],
|
|
27
|
+
undone: [],
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
export function canUndo(state) {
|
|
31
|
+
return historyOf(state).done.length > 0;
|
|
32
|
+
}
|
|
33
|
+
export function canRedo(state) {
|
|
34
|
+
return historyOf(state).undone.length > 0;
|
|
35
|
+
}
|
|
36
|
+
/** 단일 스텝의 역변환 — doc은 스텝 적용 "전" 문서 */
|
|
37
|
+
export function invertStep(step, doc) {
|
|
38
|
+
switch (step.op) {
|
|
39
|
+
case "insert":
|
|
40
|
+
return [{ op: "remove", at: step.at, node: step.node }];
|
|
41
|
+
case "remove":
|
|
42
|
+
return [{ op: "insert", at: step.at, node: step.node }];
|
|
43
|
+
case "setAttr":
|
|
44
|
+
return [
|
|
45
|
+
{
|
|
46
|
+
op: "setAttr",
|
|
47
|
+
path: step.path,
|
|
48
|
+
key: step.key,
|
|
49
|
+
value: step.prev,
|
|
50
|
+
prev: nodeAt(doc, step.path)?.attrs?.[step.key],
|
|
51
|
+
},
|
|
52
|
+
];
|
|
53
|
+
case "addMark":
|
|
54
|
+
return [{ op: "removeMark", range: step.range, markType: step.mark.type }];
|
|
55
|
+
case "removeMark":
|
|
56
|
+
return [
|
|
57
|
+
{ op: "addMark", range: step.range, mark: { type: step.markType } },
|
|
58
|
+
];
|
|
59
|
+
case "split": {
|
|
60
|
+
// 적용된 op의 역순으로 join — 바깥 split부터 되감는다
|
|
61
|
+
const ops = computeSplitOps(doc, step);
|
|
62
|
+
const joins = [];
|
|
63
|
+
for (const op of [...ops].reverse()) {
|
|
64
|
+
const parent = op.path.slice(0, -1);
|
|
65
|
+
const i = op.path[op.path.length - 1];
|
|
66
|
+
joins.push({ op: "join", at: { path: parent, offset: i + 1 } });
|
|
67
|
+
}
|
|
68
|
+
return joins;
|
|
69
|
+
}
|
|
70
|
+
case "join": {
|
|
71
|
+
// seam에서 재분할 — prev 노드 크기가 split index다
|
|
72
|
+
const prev = nodeAt(doc, [...step.at.path, step.at.offset - 1]);
|
|
73
|
+
if (!prev)
|
|
74
|
+
return [];
|
|
75
|
+
const seam = prev.type === "text"
|
|
76
|
+
? (prev.text?.length ?? 0)
|
|
77
|
+
: (prev.content?.length ?? 0);
|
|
78
|
+
return [
|
|
79
|
+
{
|
|
80
|
+
op: "split",
|
|
81
|
+
at: { path: [...step.at.path, step.at.offset - 1], offset: seam },
|
|
82
|
+
// text면 depth 0(텍스트만), 블록이면 depth 1(노드 자체 분할)
|
|
83
|
+
depth: prev.type === "text" ? 0 : 1,
|
|
84
|
+
},
|
|
85
|
+
];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/** 스텝 시퀀스의 역변환 — 각 스텝을 순차 적용해가며 계산 후 역순 */
|
|
90
|
+
export function invertSteps(steps, docBefore) {
|
|
91
|
+
let d = docBefore;
|
|
92
|
+
const invs = [];
|
|
93
|
+
for (const s of steps) {
|
|
94
|
+
invs.push(invertStep(s, d));
|
|
95
|
+
d = applyStep(d, s);
|
|
96
|
+
}
|
|
97
|
+
return invs.reverse().flat();
|
|
98
|
+
}
|
|
99
|
+
const undo = ({ state, tr, dispatch }) => {
|
|
100
|
+
const h = historyOf(state);
|
|
101
|
+
const entry = h.done[h.done.length - 1];
|
|
102
|
+
if (!entry)
|
|
103
|
+
return false;
|
|
104
|
+
for (const s of entry.inverse)
|
|
105
|
+
tr.addStep(s);
|
|
106
|
+
tr.setSelection(entry.selBefore).setMeta("history", "undo");
|
|
107
|
+
dispatch();
|
|
108
|
+
return true;
|
|
109
|
+
};
|
|
110
|
+
const redo = ({ state, tr, dispatch }) => {
|
|
111
|
+
const h = historyOf(state);
|
|
112
|
+
const entry = h.undone[h.undone.length - 1];
|
|
113
|
+
if (!entry)
|
|
114
|
+
return false;
|
|
115
|
+
for (const s of entry.steps)
|
|
116
|
+
tr.addStep(s);
|
|
117
|
+
tr.setSelection(entry.selAfter).setMeta("history", "redo");
|
|
118
|
+
dispatch();
|
|
119
|
+
return true;
|
|
120
|
+
};
|
|
121
|
+
const historyPlugin = {
|
|
122
|
+
key: HISTORY_KEY,
|
|
123
|
+
init: () => ({ done: [], undone: [] }),
|
|
124
|
+
apply(tr, prev, prevState, state) {
|
|
125
|
+
const h = prev;
|
|
126
|
+
const kind = tr.meta["history"];
|
|
127
|
+
if (kind === "undo") {
|
|
128
|
+
const top = h.done[h.done.length - 1];
|
|
129
|
+
return top
|
|
130
|
+
? { done: h.done.slice(0, -1), undone: [...h.undone, top] }
|
|
131
|
+
: h;
|
|
132
|
+
}
|
|
133
|
+
if (kind === "redo") {
|
|
134
|
+
const top = h.undone[h.undone.length - 1];
|
|
135
|
+
return top
|
|
136
|
+
? { done: [...h.done, top], undone: h.undone.slice(0, -1) }
|
|
137
|
+
: h;
|
|
138
|
+
}
|
|
139
|
+
if (!tr.docChanged)
|
|
140
|
+
return h;
|
|
141
|
+
const now = Date.now();
|
|
142
|
+
const entry = {
|
|
143
|
+
steps: [...tr.steps],
|
|
144
|
+
inverse: invertSteps(tr.steps, prevState.doc),
|
|
145
|
+
selBefore: prevState.selection,
|
|
146
|
+
selAfter: state.selection,
|
|
147
|
+
group: tr.meta["history.group"] ?? null,
|
|
148
|
+
time: now,
|
|
149
|
+
};
|
|
150
|
+
const done = [...h.done];
|
|
151
|
+
const last = done[done.length - 1];
|
|
152
|
+
// 같은 그룹이어도 시간 창을 넘으면 별도 엔트리 — 안 그러면 한
|
|
153
|
+
// 세션의 모든 타이핑이 하나로 뭉쳐 undo가 문서 전체를 날린다
|
|
154
|
+
if (entry.group &&
|
|
155
|
+
last?.group === entry.group &&
|
|
156
|
+
now - last.time <= GROUP_DELAY) {
|
|
157
|
+
// 같은 그룹 연속 편집 — 한 엔트리로 병합 (역스텝은 새것이 먼저)
|
|
158
|
+
done[done.length - 1] = {
|
|
159
|
+
steps: [...last.steps, ...entry.steps],
|
|
160
|
+
inverse: [...entry.inverse, ...last.inverse],
|
|
161
|
+
selBefore: last.selBefore,
|
|
162
|
+
selAfter: entry.selAfter,
|
|
163
|
+
group: last.group,
|
|
164
|
+
time: now,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
done.push(entry);
|
|
169
|
+
if (done.length > DEPTH)
|
|
170
|
+
done.shift();
|
|
171
|
+
}
|
|
172
|
+
return { done, undone: [] };
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
/**
|
|
176
|
+
* undo/redo 확장 — starterExtensions에 포함된다.
|
|
177
|
+
* commands.undo()/redo() + Mod-z / Mod-Shift-z / Mod-y 키맵.
|
|
178
|
+
*/
|
|
179
|
+
export function historyExtension() {
|
|
180
|
+
return {
|
|
181
|
+
name: "history",
|
|
182
|
+
priority: 50, // 사용자 확장보다 낮게 — 커맨드 override 가능
|
|
183
|
+
commands: { undo, redo },
|
|
184
|
+
keymap: {
|
|
185
|
+
"Mod-z": undo,
|
|
186
|
+
"Mod-Shift-z": redo,
|
|
187
|
+
"Mod-y": redo,
|
|
188
|
+
},
|
|
189
|
+
plugins: [historyPlugin],
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history.js","sourceRoot":"","sources":["../src/history.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export { WidgetCore } from "./core.js";
|
|
2
|
+
export type { Widget } from "./core.js";
|
|
3
|
+
export { mountWidget } from "./mount.js";
|
|
4
|
+
export type { MountedWidget, MountWidgetOptions } from "./mount.js";
|
|
5
|
+
export type { WidgetCoreOptions, WidgetEventHandlers, WidgetEventMap, WidgetEventType, WidgetSnapshot, RowData, } from "./types.js";
|
|
6
|
+
export type { Attrs, DocNode, EditorNode, Mark } from "./model/node.js";
|
|
7
|
+
export { createDoc, createText, isLeaf, isTextNode } from "./model/node.js";
|
|
8
|
+
export type { AttrSpec, DOMSpec, MarkSpec, NodeSpec, ParseRule, Schema, SchemaSpec, } from "./model/schema.js";
|
|
9
|
+
export { createSchema } from "./model/schema.js";
|
|
10
|
+
export { firstTextPath, lastTextPath, nodeAt } from "./model/traverse.js";
|
|
11
|
+
export { applyStep, leafPoint, mapPoint, marksEq } from "./state/apply.js";
|
|
12
|
+
export type { NodeSelection, Point, Range, Selection, TextSelection, } from "./state/selection.js";
|
|
13
|
+
export { isCollapsed, nodeSelection, normalizedRange, point, pointCmp, pointEq, selectionEq, textSelection, } from "./state/selection.js";
|
|
14
|
+
export type { AddMarkStep, InsertStep, JoinStep, RemoveMarkStep, RemoveStep, SetAttrStep, SplitStep, Step, Transaction, } from "./state/transaction.js";
|
|
15
|
+
export type { CreateStateOptions, EditorState, EditorStateConfig, } from "./state/state.js";
|
|
16
|
+
export { createState } from "./state/state.js";
|
|
17
|
+
export type { BlockTextCtx, Command, CommandContext, Extension, FileDropCtx, InputHooks, InputRule, Keymap, PasteData, Plugin, RangeCtx, } from "./editor/extension.js";
|
|
18
|
+
export type { Editor, EditorEventHandlers, EditorEventMap, EditorEventType, EditorOptions, } from "./editor/editor.js";
|
|
19
|
+
export { createEditor } from "./editor/editor.js";
|
|
20
|
+
export type { NodeViewProps, RenderNode } from "./view/render.js";
|
|
21
|
+
export { nodeViewEditable, nodeViewFor, renderChildren, } from "./view/render.js";
|
|
22
|
+
export { bindEditorInput, DirtyKeyMap } from "./view/input.js";
|
|
23
|
+
export type { EditorInputBinding } from "./view/input.js";
|
|
24
|
+
export { applyDomSelection, domSelection, domToPoint, pointToDOM, } from "./view/dom.js";
|
|
25
|
+
export { mountEditor } from "./view/mount.js";
|
|
26
|
+
export type { MountedEditor, MountEditorOptions } from "./view/mount.js";
|
|
27
|
+
export { serializeToHTML } from "./view/serialize.js";
|
|
28
|
+
export { parseHTML } from "./parse/html.js";
|
|
29
|
+
export { sanitizeHTML } from "./parse/sanitize.js";
|
|
30
|
+
export { pointAfter, pointBefore } from "./state/navigate.js";
|
|
31
|
+
export { historyExtension, historyOf, invertStep, invertSteps } from "./history.js";
|
|
32
|
+
export type { HistoryEntry, HistoryState } from "./history.js";
|
|
33
|
+
export type { Feature } from "./features/index.js";
|
|
34
|
+
export { aceFeature, alignmentFeature, blockquoteFeature, codeBlockFeature, defineFeature, docFeature, hardBreakFeature, headingFeature, horizontalRuleFeature, imageFeature, inlineStyleFeature, linkFeature, listsFeature, marksFeature, scriptFeature, starterFeatures, tableFeature, taskListFeature, } from "./features/index.js";
|
|
35
|
+
export { alignDOM, blockRule, blockText, blockTextOffset, blockTextPoint, caretBlockPath, isBlockActive, isInNode, isMarkActive, itemContext, markRule, rangeHasMark, samePath, setBlockType, toggleMark, wrapBlock, } from "./commands.js";
|
|
36
|
+
export { addTableColumn, addTableRow, canRedo, canUndo, clearFormat, codeBracketAt, codeCaret, codeTextAt, dedentCode, deleteTable, duplicateCodeLines, exitBlock, exitCodeArrow, indentCode, insertHardBreak, insertHorizontalRule, insertImage, insertTable, liftListItem, liftOnItemBackspace, linkHrefAt, linkRangeAt, moveCodeLines, nextCell, prevCell, setAlign, setCodeLanguage, setLink, setMarkAttr, sinkListItem, splitBlock, starterExtensions, toggleCodeBlock, toggleCodeComment, toggleList, toggleQuote, toggleTaskItem, unsetLink, } from "./presets/starter.js";
|
|
37
|
+
export { highlightCode } from "./presets/highlight.js";
|
|
38
|
+
export type { CodeHighlighter, CodeToken } from "./presets/highlight.js";
|
|
39
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// ── 템플릿 예시 (골든 패스 레퍼런스) — 에디터 뷰로 교체 예정 ──
|
|
2
|
+
export { WidgetCore } from "./core.js";
|
|
3
|
+
export { mountWidget } from "./mount.js";
|
|
4
|
+
export { createDoc, createText, isLeaf, isTextNode } from "./model/node.js";
|
|
5
|
+
export { createSchema } from "./model/schema.js";
|
|
6
|
+
// ── 상태 계층: 셀렉션/트랜잭션/에디터 상태 ───────────────────
|
|
7
|
+
export { firstTextPath, lastTextPath, nodeAt } from "./model/traverse.js";
|
|
8
|
+
export { applyStep, leafPoint, mapPoint, marksEq } from "./state/apply.js";
|
|
9
|
+
export { isCollapsed, nodeSelection, normalizedRange, point, pointCmp, pointEq, selectionEq, textSelection, } from "./state/selection.js";
|
|
10
|
+
export { createState } from "./state/state.js";
|
|
11
|
+
export { createEditor } from "./editor/editor.js";
|
|
12
|
+
export { nodeViewEditable, nodeViewFor, renderChildren, } from "./view/render.js";
|
|
13
|
+
export { bindEditorInput, DirtyKeyMap } from "./view/input.js";
|
|
14
|
+
export { applyDomSelection, domSelection, domToPoint, pointToDOM, } from "./view/dom.js";
|
|
15
|
+
export { mountEditor } from "./view/mount.js";
|
|
16
|
+
export { serializeToHTML } from "./view/serialize.js";
|
|
17
|
+
// ── 파싱/새니타이즈 ─────────────────────────────────────────
|
|
18
|
+
export { parseHTML } from "./parse/html.js";
|
|
19
|
+
export { sanitizeHTML } from "./parse/sanitize.js";
|
|
20
|
+
export { pointAfter, pointBefore } from "./state/navigate.js";
|
|
21
|
+
// ── 히스토리 ────────────────────────────────────────────────
|
|
22
|
+
export { historyExtension, historyOf, invertStep, invertSteps } from "./history.js";
|
|
23
|
+
export { aceFeature, alignmentFeature, blockquoteFeature, codeBlockFeature, defineFeature, docFeature, hardBreakFeature, headingFeature, horizontalRuleFeature, imageFeature, inlineStyleFeature, linkFeature, listsFeature, marksFeature, scriptFeature, starterFeatures, tableFeature, taskListFeature, } from "./features/index.js";
|
|
24
|
+
// ── 기능 제작 툴킷 — 커맨드·캐럿 해석·입력 규칙 팩토리 ─────────
|
|
25
|
+
export { alignDOM, blockRule, blockText, blockTextOffset, blockTextPoint, caretBlockPath, isBlockActive, isInNode, isMarkActive, itemContext, markRule, rangeHasMark, samePath, setBlockType, toggleMark, wrapBlock, } from "./commands.js";
|
|
26
|
+
// ── 프리셋 ──────────────────────────────────────────────────
|
|
27
|
+
export { addTableColumn, addTableRow, canRedo, canUndo, clearFormat, codeBracketAt, codeCaret, codeTextAt, dedentCode, deleteTable, duplicateCodeLines, exitBlock, exitCodeArrow, indentCode, insertHardBreak, insertHorizontalRule, insertImage, insertTable, liftListItem, liftOnItemBackspace, linkHrefAt, linkRangeAt, moveCodeLines, nextCell, prevCell, setAlign, setCodeLanguage, setLink, setMarkAttr, sinkListItem, splitBlock, starterExtensions, toggleCodeBlock, toggleCodeComment, toggleList, toggleQuote, toggleTaskItem, unsetLink, } from "./presets/starter.js";
|
|
28
|
+
export { highlightCode } from "./presets/highlight.js";
|
|
29
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAazC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAU5E,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,gDAAgD;AAChD,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAQ3E,OAAO,EACL,WAAW,EACX,aAAa,EACb,eAAe,EACf,KAAK,EACL,QAAQ,EACR,OAAO,EACP,WAAW,EACX,aAAa,GACd,MAAM,sBAAsB,CAAC;AAiB9B,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAuB/C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAIlD,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,cAAc,GACf,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE/D,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,UAAU,EACV,UAAU,GACX,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE9C,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD,wDAAwD;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAE9D,2DAA2D;AAC3D,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAOpF,OAAO,EACL,UAAU,EACV,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,UAAU,EACV,gBAAgB,EAChB,cAAc,EACd,qBAAqB,EACrB,YAAY,EACZ,kBAAkB,EAClB,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,eAAe,EACf,YAAY,EACZ,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAE7B,8CAA8C;AAC9C,OAAO,EACL,QAAQ,EACR,SAAS,EACT,SAAS,EACT,eAAe,EACf,cAAc,EACd,cAAc,EACd,aAAa,EACb,QAAQ,EACR,YAAY,EACZ,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,SAAS,GACV,MAAM,eAAe,CAAC;AAEvB,4DAA4D;AAC5D,OAAO,EACL,cAAc,EACd,WAAW,EACX,OAAO,EACP,OAAO,EACP,WAAW,EACX,aAAa,EACb,SAAS,EACT,UAAU,EACV,UAAU,EACV,WAAW,EACX,kBAAkB,EAClB,SAAS,EACT,aAAa,EACb,UAAU,EACV,eAAe,EACf,oBAAoB,EACpB,WAAW,EACX,WAAW,EACX,YAAY,EACZ,mBAAmB,EACnB,UAAU,EACV,WAAW,EACX,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,eAAe,EACf,OAAO,EACP,WAAW,EACX,YAAY,EACZ,UAAU,EACV,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,UAAU,EACV,WAAW,EACX,cAAc,EACd,SAAS,GACV,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 문서 데이터 모델 — 순수 JSON AST.
|
|
3
|
+
*
|
|
4
|
+
* 설계 근거 (vs Lexical / ProseMirror):
|
|
5
|
+
* - Lexical: 노드가 클래스 인스턴스다. 직렬화·협업 시 instance↔JSON 변환
|
|
6
|
+
* 계층과 커스텀 노드별 importJSON/exportJSON 구현이 필요하다.
|
|
7
|
+
* - ProseMirror: 불변이지만 Node/Fragment 클래스다 — toJSON/fromJSON
|
|
8
|
+
* 왕복이 필요하고 스키마에 결합되어 있다.
|
|
9
|
+
* - moda-editor: 문서가 곧 JSON이다. JSON.stringify(doc)이 곧 저장
|
|
10
|
+
* 포맷이고, 불변 구조 공유로 업데이트 시 루트→변경 노드 경로만 복사한다
|
|
11
|
+
* (키 입력 한 번 = O(depth) 할당). CRDT(Yjs) 바인딩도 클래스 역직렬화
|
|
12
|
+
* 없이 "데이터 → 데이터" 매핑으로 끝난다.
|
|
13
|
+
*/
|
|
14
|
+
/** 노드/마크 속성 — JSON 직렬화 가능한 값만 허용한다 (규약) */
|
|
15
|
+
export type Attrs = Record<string, unknown>;
|
|
16
|
+
/** 텍스트에 붙는 인라인 스타일 (bold, link, comment …) */
|
|
17
|
+
export interface Mark {
|
|
18
|
+
readonly type: string;
|
|
19
|
+
readonly attrs?: Attrs;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 문서 트리의 노드. 모든 노드가 같은 형태라 재귀 순회·직렬화가 단순하다.
|
|
23
|
+
* - `text`는 type === "text" 인 리프 노드만 가진다
|
|
24
|
+
* - `content`는 자식 배열 — 없거나 빈 배열이면 리프
|
|
25
|
+
* - `marks`는 텍스트/인라인 노드에만 의미가 있다
|
|
26
|
+
*/
|
|
27
|
+
export interface EditorNode {
|
|
28
|
+
readonly type: string;
|
|
29
|
+
readonly attrs?: Attrs;
|
|
30
|
+
readonly content?: readonly EditorNode[];
|
|
31
|
+
readonly marks?: readonly Mark[];
|
|
32
|
+
readonly text?: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 문서 루트 — 블록 자식을 가진다. type은 스키마의 topNodeType과 일치하며
|
|
36
|
+
* 기본값은 "doc" (SchemaSpec.topNode로 변경 가능 — "document" 등).
|
|
37
|
+
*/
|
|
38
|
+
export interface DocNode extends EditorNode {
|
|
39
|
+
readonly content: readonly EditorNode[];
|
|
40
|
+
}
|
|
41
|
+
export declare function isTextNode(node: EditorNode): boolean;
|
|
42
|
+
export declare function isLeaf(node: EditorNode): boolean;
|
|
43
|
+
/** 자식 수 — 없으면 0 */
|
|
44
|
+
export declare function childCount(node: EditorNode): number;
|
|
45
|
+
export declare function createDoc(content?: readonly EditorNode[]): DocNode;
|
|
46
|
+
export declare function createText(text: string, marks?: readonly Mark[]): EditorNode;
|
|
47
|
+
//# sourceMappingURL=node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../src/model/node.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,2CAA2C;AAC3C,MAAM,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE5C,8CAA8C;AAC9C,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;CACxB;AAED;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;IACvB,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IACzC,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,IAAI,EAAE,CAAC;IACjC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;GAGG;AACH,MAAM,WAAW,OAAQ,SAAQ,UAAU;IACzC,QAAQ,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,CAAC;CACzC;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAEpD;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAEhD;AAED,mBAAmB;AACnB,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAEnD;AAED,wBAAgB,SAAS,CAAC,OAAO,GAAE,SAAS,UAAU,EAAO,GAAG,OAAO,CAEtE;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,SAAS,IAAI,EAAE,GAAG,UAAU,CAE5E"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 문서 데이터 모델 — 순수 JSON AST.
|
|
3
|
+
*
|
|
4
|
+
* 설계 근거 (vs Lexical / ProseMirror):
|
|
5
|
+
* - Lexical: 노드가 클래스 인스턴스다. 직렬화·협업 시 instance↔JSON 변환
|
|
6
|
+
* 계층과 커스텀 노드별 importJSON/exportJSON 구현이 필요하다.
|
|
7
|
+
* - ProseMirror: 불변이지만 Node/Fragment 클래스다 — toJSON/fromJSON
|
|
8
|
+
* 왕복이 필요하고 스키마에 결합되어 있다.
|
|
9
|
+
* - moda-editor: 문서가 곧 JSON이다. JSON.stringify(doc)이 곧 저장
|
|
10
|
+
* 포맷이고, 불변 구조 공유로 업데이트 시 루트→변경 노드 경로만 복사한다
|
|
11
|
+
* (키 입력 한 번 = O(depth) 할당). CRDT(Yjs) 바인딩도 클래스 역직렬화
|
|
12
|
+
* 없이 "데이터 → 데이터" 매핑으로 끝난다.
|
|
13
|
+
*/
|
|
14
|
+
export function isTextNode(node) {
|
|
15
|
+
return node.type === "text";
|
|
16
|
+
}
|
|
17
|
+
export function isLeaf(node) {
|
|
18
|
+
return node.content == null || node.content.length === 0;
|
|
19
|
+
}
|
|
20
|
+
/** 자식 수 — 없으면 0 */
|
|
21
|
+
export function childCount(node) {
|
|
22
|
+
return node.content?.length ?? 0;
|
|
23
|
+
}
|
|
24
|
+
export function createDoc(content = []) {
|
|
25
|
+
return { type: "doc", content };
|
|
26
|
+
}
|
|
27
|
+
export function createText(text, marks) {
|
|
28
|
+
return marks?.length ? { type: "text", text, marks } : { type: "text", text };
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node.js","sourceRoot":"","sources":["../../src/model/node.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAiCH,MAAM,UAAU,UAAU,CAAC,IAAgB;IACzC,OAAO,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,IAAgB;IACrC,OAAO,IAAI,CAAC,OAAO,IAAI,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC;AAC3D,CAAC;AAED,mBAAmB;AACnB,MAAM,UAAU,UAAU,CAAC,IAAgB;IACzC,OAAO,IAAI,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,UAAiC,EAAE;IAC3D,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,KAAuB;IAC9D,OAAO,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AAChF,CAAC"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { Attrs, EditorNode, Mark } from "./node.js";
|
|
2
|
+
/**
|
|
3
|
+
* 스키마 — 노드/마크 타입 레지스트리.
|
|
4
|
+
*
|
|
5
|
+
* Tiptap은 스키마를 Extension 내부에 숨겨 최종 스키마를 추론하기 어렵게
|
|
6
|
+
* 한다. moda-editor는 스키마를 독립 값으로 만들어 (1) 문서 검증,
|
|
7
|
+
* (2) DOM 렌더 명세(toDOM), (3) 붙여넣기 파싱 규칙(parseDOM)을 한
|
|
8
|
+
* 레지스트리에서 가져온다 — sanitizer가 스키마 밖 태그를 버리는 근거가
|
|
9
|
+
* 이 레지스트리다.
|
|
10
|
+
*/
|
|
11
|
+
/** 렌더 명세 — 프레임워크 비의존. 어댑터가 자기 vNode로 번역한다 */
|
|
12
|
+
export interface DOMSpec {
|
|
13
|
+
/** 태그명 — "p", "strong", "img" … */
|
|
14
|
+
tag: string;
|
|
15
|
+
attrs?: Record<string, string>;
|
|
16
|
+
}
|
|
17
|
+
export interface AttrSpec {
|
|
18
|
+
/** attrs에 키가 없을 때의 기본값 */
|
|
19
|
+
default?: unknown;
|
|
20
|
+
}
|
|
21
|
+
/** HTML → 노드 역방향 규칙 — 붙여넣기/파서가 사용한다 */
|
|
22
|
+
export interface ParseRule {
|
|
23
|
+
/** CSS 선택자 — "p", "span[data-mention]", "h1" … */
|
|
24
|
+
tag?: string;
|
|
25
|
+
/** 인라인 스타일 매칭 — "font-weight=bold" 형태 */
|
|
26
|
+
style?: string;
|
|
27
|
+
/** 낮을수록 먼저 시도 (기본 50) */
|
|
28
|
+
priority?: number;
|
|
29
|
+
/** attrs 추출 — false 반환 시 이 규칙은 매칭 실패로 처리 */
|
|
30
|
+
getAttrs?: (el: Element) => Attrs | false | undefined;
|
|
31
|
+
}
|
|
32
|
+
export interface NodeSpec {
|
|
33
|
+
/** 허용 자식 표현 — PM 스타일 "block+", "inline*", "paragraph block*" */
|
|
34
|
+
content?: string;
|
|
35
|
+
/** 이 노드가 속하는 그룹 — "block" | "inline" | 커스텀, 공백 구분 복수 */
|
|
36
|
+
group?: string;
|
|
37
|
+
/** 인라인 노드 여부 (mention, hardBreak 등) */
|
|
38
|
+
inline?: boolean;
|
|
39
|
+
/** 내부가 리프 — 커서 진입 불가, 통째로 선택 (image, hr) */
|
|
40
|
+
atom?: boolean;
|
|
41
|
+
selectable?: boolean;
|
|
42
|
+
draggable?: boolean;
|
|
43
|
+
/** 코드 블록 — Enter가 개행이고 입력 규칙/마크 변환이 비활성 */
|
|
44
|
+
code?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* 구문 하이라이트 — 뷰 레벨 데코레이션 (Tiptap lowlight 관례).
|
|
47
|
+
* doc을 오염시키지 않고 렌더 시 텍스트 자식을 `me-tok-<kind>`
|
|
48
|
+
* 스팬으로 쪼갠다. 생략하면 플레인 텍스트. lowlight 같은 외부
|
|
49
|
+
* 엔진은 토큰 형태만 맞춰 주입하면 된다.
|
|
50
|
+
*/
|
|
51
|
+
codeHighlighter?: (code: string, language: string | null) => readonly {
|
|
52
|
+
text: string;
|
|
53
|
+
kind?: string;
|
|
54
|
+
}[];
|
|
55
|
+
/** 리스트 아이템 컨테이너 — Enter가 아이템 분할, 빈 아이템 Enter와
|
|
56
|
+
* 아이템 시작 Backspace는 lift(탈출)가 된다 */
|
|
57
|
+
listItem?: boolean;
|
|
58
|
+
/** 체크박스 아이템 — 마커 영역 클릭이 attrs.checked를 토글한다
|
|
59
|
+
* (taskItem). 마커는 CSS ::before이므로 DOM↔doc 매핑을 깨지 않는다 */
|
|
60
|
+
checkbox?: boolean;
|
|
61
|
+
/** 블록 끝 Enter가 만드는 블록 타입 — 생략하면 같은 타입 유지.
|
|
62
|
+
* heading은 "paragraph"를 지정해 끝 Enter가 본문을 만든다 */
|
|
63
|
+
splitExit?: string;
|
|
64
|
+
/** 허용 마크 — ""면 불가, 생략 시 전부 허용 */
|
|
65
|
+
marks?: string;
|
|
66
|
+
attrs?: Record<string, AttrSpec>;
|
|
67
|
+
toDOM?: (node: EditorNode) => DOMSpec;
|
|
68
|
+
parseDOM?: readonly ParseRule[];
|
|
69
|
+
}
|
|
70
|
+
export interface MarkSpec {
|
|
71
|
+
attrs?: Record<string, AttrSpec>;
|
|
72
|
+
/** 공존 불가 마크 목록 — "em italic" 공백 구분 */
|
|
73
|
+
excludes?: string;
|
|
74
|
+
/** false면 경계에서 타이핑이 마크 밖으로 나간다 (link 관례) */
|
|
75
|
+
inclusive?: boolean;
|
|
76
|
+
toDOM?: (mark: Mark) => DOMSpec;
|
|
77
|
+
parseDOM?: readonly ParseRule[];
|
|
78
|
+
}
|
|
79
|
+
export interface SchemaSpec {
|
|
80
|
+
nodes: Record<string, NodeSpec>;
|
|
81
|
+
marks?: Record<string, MarkSpec>;
|
|
82
|
+
/** 루트 노드 타입 — 기본 "doc" */
|
|
83
|
+
topNode?: string;
|
|
84
|
+
}
|
|
85
|
+
export interface Schema {
|
|
86
|
+
readonly spec: SchemaSpec;
|
|
87
|
+
readonly topNodeType: string;
|
|
88
|
+
nodeSpec(type: string): NodeSpec | undefined;
|
|
89
|
+
markSpec(type: string): MarkSpec | undefined;
|
|
90
|
+
/** 인라인 컨텍스트에 놓이는 타입인가 (명시 inline이거나 group이 inline) */
|
|
91
|
+
isInline(type: string): boolean;
|
|
92
|
+
isAtom(type: string): boolean;
|
|
93
|
+
/** 노드가 속한 그룹 집합 */
|
|
94
|
+
groups(type: string): readonly string[];
|
|
95
|
+
/** attrs 기본값이 적용된 노드를 만든다 — 알 수 없는 타입이면 throw */
|
|
96
|
+
node(type: string, init?: Partial<EditorNode>): EditorNode;
|
|
97
|
+
/** 마크 attrs 기본값 적용 */
|
|
98
|
+
mark(type: string, attrs?: Attrs): Mark;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* 스키마 조립 — extensions에서 모은 spec으로 만든다.
|
|
102
|
+
* 레지스트리 + 기본값 팩토리일 뿐, 유효성 검증은 상태 계층(state)이 한다.
|
|
103
|
+
*/
|
|
104
|
+
export declare function createSchema(spec: SchemaSpec): Schema;
|
|
105
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/model/schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 스키마 조립 — extensions에서 모은 spec으로 만든다.
|
|
3
|
+
* 레지스트리 + 기본값 팩토리일 뿐, 유효성 검증은 상태 계층(state)이 한다.
|
|
4
|
+
*/
|
|
5
|
+
export function createSchema(spec) {
|
|
6
|
+
const nodes = spec.nodes;
|
|
7
|
+
const marks = spec.marks ?? {};
|
|
8
|
+
const topNodeType = spec.topNode ?? "doc";
|
|
9
|
+
function withDefaults(specAttrs, given) {
|
|
10
|
+
if (!specAttrs)
|
|
11
|
+
return given;
|
|
12
|
+
const out = {};
|
|
13
|
+
for (const [key, a] of Object.entries(specAttrs)) {
|
|
14
|
+
if (a.default !== undefined)
|
|
15
|
+
out[key] = a.default;
|
|
16
|
+
}
|
|
17
|
+
return Object.assign(out, given);
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
spec,
|
|
21
|
+
topNodeType,
|
|
22
|
+
nodeSpec: (type) => nodes[type],
|
|
23
|
+
markSpec: (type) => marks[type],
|
|
24
|
+
isInline(type) {
|
|
25
|
+
const s = nodes[type];
|
|
26
|
+
return !!s && (s.inline === true || (s.group ?? "").split(" ").includes("inline"));
|
|
27
|
+
},
|
|
28
|
+
isAtom: (type) => nodes[type]?.atom === true,
|
|
29
|
+
groups: (type) => (nodes[type]?.group ?? "").split(" ").filter(Boolean),
|
|
30
|
+
node(type, init = {}) {
|
|
31
|
+
const s = nodes[type];
|
|
32
|
+
if (!s)
|
|
33
|
+
throw new Error(`알 수 없는 노드 타입: ${type}`);
|
|
34
|
+
const attrs = withDefaults(s.attrs, init.attrs);
|
|
35
|
+
return { type, ...init, ...(attrs && { attrs }) };
|
|
36
|
+
},
|
|
37
|
+
mark(type, attrs) {
|
|
38
|
+
const s = marks[type];
|
|
39
|
+
if (!s)
|
|
40
|
+
throw new Error(`알 수 없는 마크 타입: ${type}`);
|
|
41
|
+
const merged = withDefaults(s.attrs, attrs);
|
|
42
|
+
return merged ? { type, attrs: merged } : { type };
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/model/schema.ts"],"names":[],"mappings":"AA4GA;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,IAAgB;IAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;IACzB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;IAC/B,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC;IAE1C,SAAS,YAAY,CACnB,SAA+C,EAC/C,KAAwB;QAExB,IAAI,CAAC,SAAS;YAAE,OAAO,KAAK,CAAC;QAC7B,MAAM,GAAG,GAAU,EAAE,CAAC;QACtB,KAAK,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;YACjD,IAAI,CAAC,CAAC,OAAO,KAAK,SAAS;gBAAE,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC;QACpD,CAAC;QACD,OAAO,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACnC,CAAC;IAED,OAAO;QACL,IAAI;QACJ,WAAW;QACX,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;QAC/B,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;QAC/B,QAAQ,CAAC,IAAI;YACX,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;YACtB,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;QACrF,CAAC;QACD,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,KAAK,IAAI;QAC5C,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;QACvE,IAAI,CAAC,IAAI,EAAE,IAAI,GAAG,EAAE;YAClB,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;YACtB,IAAI,CAAC,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC;YACjD,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;YAChD,OAAO,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,GAAG,CAAC,KAAK,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QACpD,CAAC;QACD,IAAI,CAAC,IAAI,EAAE,KAAK;YACd,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;YACtB,IAAI,CAAC,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC;YACjD,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;YAC5C,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QACrD,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { EditorNode } from "./node.js";
|
|
2
|
+
/**
|
|
3
|
+
* 문서 순회 + 불변 업데이트 유틸.
|
|
4
|
+
*
|
|
5
|
+
* updateNodeAt은 "루트→대상 경로만 새 객체"라는 구조 공유의 핵심이다 —
|
|
6
|
+
* fn이 같은 참조를 반환하면 상위도 전부 참조 유지되므로, 변경 없는 트리는
|
|
7
|
+
* 비용 0으로 재사용된다 (대용량 문서에서의 성능 근거).
|
|
8
|
+
*/
|
|
9
|
+
/** path → 노드. 경로가 유효하지 않으면 undefined */
|
|
10
|
+
export declare function nodeAt(doc: EditorNode, path: readonly number[]): EditorNode | undefined;
|
|
11
|
+
/** path의 부모 노드 — []이면 doc 자신 */
|
|
12
|
+
export declare function parentAt(doc: EditorNode, path: readonly number[]): EditorNode | undefined;
|
|
13
|
+
/** path가 가리키는 텍스트 노드 — 아니면 undefined */
|
|
14
|
+
export declare function textNodeAt(doc: EditorNode, path: readonly number[]): EditorNode | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* path 위치 노드를 fn(node)으로 교체. fn이 같은 참조를 반환하면
|
|
17
|
+
* 상위 노드도 모두 같은 참조가 유지된다 — "변경 없음"이 참조로 감지된다.
|
|
18
|
+
*/
|
|
19
|
+
export declare function updateNodeAt(node: EditorNode, path: readonly number[], fn: (node: EditorNode) => EditorNode): EditorNode;
|
|
20
|
+
/** path의 부모 아래 index 위치에 자식 삽입 */
|
|
21
|
+
export declare function insertChildAt(doc: EditorNode, path: readonly number[], index: number, child: EditorNode): EditorNode;
|
|
22
|
+
/** path의 부모 아래 index 자식 제거 */
|
|
23
|
+
export declare function removeChildAt(doc: EditorNode, path: readonly number[], index: number): EditorNode;
|
|
24
|
+
/** path의 부모 아래 [from, to) 자식들을 nodes로 교체 */
|
|
25
|
+
export declare function spliceChildren(doc: EditorNode, path: readonly number[], from: number, to: number, nodes: readonly EditorNode[]): EditorNode;
|
|
26
|
+
/**
|
|
27
|
+
* 모든 텍스트 노드에 fn을 적용 — fn은 노드 배열을 반환해 노드를
|
|
28
|
+
* 0..N개로 치환할 수 있다(마크 분할 등). 단일 패스라 트리 위치가
|
|
29
|
+
* 중간에 흔들리지 않는다.
|
|
30
|
+
*/
|
|
31
|
+
export declare function expandTextNodes(node: EditorNode, path: readonly number[], fn: (node: EditorNode, path: readonly number[]) => readonly EditorNode[]): readonly EditorNode[];
|
|
32
|
+
/** 문서의 마지막 텍스트 노드 경로 — 없으면 null */
|
|
33
|
+
export declare function lastTextPath(doc: EditorNode): readonly number[] | null;
|
|
34
|
+
/** 문서의 첫 텍스트 노드 경로 — 없으면 null */
|
|
35
|
+
export declare function firstTextPath(doc: EditorNode): readonly number[] | null;
|
|
36
|
+
//# sourceMappingURL=traverse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"traverse.d.ts","sourceRoot":"","sources":["../../src/model/traverse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE5C;;;;;;GAMG;AAEH,wCAAwC;AACxC,wBAAgB,MAAM,CACpB,GAAG,EAAE,UAAU,EACf,IAAI,EAAE,SAAS,MAAM,EAAE,GACtB,UAAU,GAAG,SAAS,CAIxB;AAED,gCAAgC;AAChC,wBAAgB,QAAQ,CACtB,GAAG,EAAE,UAAU,EACf,IAAI,EAAE,SAAS,MAAM,EAAE,GACtB,UAAU,GAAG,SAAS,CAExB;AAED,wCAAwC;AACxC,wBAAgB,UAAU,CACxB,GAAG,EAAE,UAAU,EACf,IAAI,EAAE,SAAS,MAAM,EAAE,GACtB,UAAU,GAAG,SAAS,CAGxB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,EAAE,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,UAAU,GACnC,UAAU,CAUZ;AAED,kCAAkC;AAClC,wBAAgB,aAAa,CAC3B,GAAG,EAAE,UAAU,EACf,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,UAAU,GAChB,UAAU,CAMZ;AAED,8BAA8B;AAC9B,wBAAgB,aAAa,CAC3B,GAAG,EAAE,UAAU,EACf,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,KAAK,EAAE,MAAM,GACZ,UAAU,CAOZ;AAED,4CAA4C;AAC5C,wBAAgB,cAAc,CAC5B,GAAG,EAAE,UAAU,EACf,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,SAAS,UAAU,EAAE,GAC3B,UAAU,CAMZ;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,EAAE,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,SAAS,UAAU,EAAE,GACvE,SAAS,UAAU,EAAE,CAYvB;AAED,mCAAmC;AACnC,wBAAgB,YAAY,CAAC,GAAG,EAAE,UAAU,GAAG,SAAS,MAAM,EAAE,GAAG,IAAI,CAYtE;AAED,iCAAiC;AACjC,wBAAgB,aAAa,CAAC,GAAG,EAAE,UAAU,GAAG,SAAS,MAAM,EAAE,GAAG,IAAI,CAYvE"}
|