@moda-editor/core 0.1.3 → 0.2.0

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.
Files changed (252) hide show
  1. package/dist/collab.d.ts +61 -0
  2. package/dist/collab.d.ts.map +1 -0
  3. package/dist/collab.js +67 -0
  4. package/dist/collab.js.map +1 -0
  5. package/dist/commands.d.ts +11 -0
  6. package/dist/commands.d.ts.map +1 -1
  7. package/dist/commands.js +48 -4
  8. package/dist/commands.js.map +1 -1
  9. package/dist/conformance/editor-base.d.ts +7 -0
  10. package/dist/conformance/editor-base.d.ts.map +1 -0
  11. package/dist/conformance/editor-base.js +304 -0
  12. package/dist/conformance/editor-base.js.map +1 -0
  13. package/dist/conformance/editor-codeblock.d.ts +8 -0
  14. package/dist/conformance/editor-codeblock.d.ts.map +1 -0
  15. package/dist/conformance/editor-codeblock.js +402 -0
  16. package/dist/conformance/editor-codeblock.js.map +1 -0
  17. package/dist/conformance/editor-ime.d.ts +7 -0
  18. package/dist/conformance/editor-ime.d.ts.map +1 -0
  19. package/dist/conformance/editor-ime.js +166 -0
  20. package/dist/conformance/editor-ime.js.map +1 -0
  21. package/dist/conformance/editor-input.d.ts +8 -0
  22. package/dist/conformance/editor-input.d.ts.map +1 -0
  23. package/dist/conformance/editor-input.js +676 -0
  24. package/dist/conformance/editor-input.js.map +1 -0
  25. package/dist/conformance/editor-nodeview.d.ts +7 -0
  26. package/dist/conformance/editor-nodeview.d.ts.map +1 -0
  27. package/dist/conformance/editor-nodeview.js +169 -0
  28. package/dist/conformance/editor-nodeview.js.map +1 -0
  29. package/dist/conformance/editor-overlay.d.ts +8 -0
  30. package/dist/conformance/editor-overlay.d.ts.map +1 -0
  31. package/dist/conformance/editor-overlay.js +345 -0
  32. package/dist/conformance/editor-overlay.js.map +1 -0
  33. package/dist/conformance/fixtures.d.ts +4 -0
  34. package/dist/conformance/fixtures.d.ts.map +1 -0
  35. package/dist/conformance/fixtures.js +15 -0
  36. package/dist/conformance/fixtures.js.map +1 -0
  37. package/dist/conformance/index.d.ts +14 -0
  38. package/dist/conformance/index.d.ts.map +1 -0
  39. package/dist/conformance/index.js +28 -0
  40. package/dist/conformance/index.js.map +1 -0
  41. package/dist/conformance/types.d.ts +51 -0
  42. package/dist/conformance/types.d.ts.map +1 -0
  43. package/dist/conformance/types.js +2 -0
  44. package/dist/conformance/types.js.map +1 -0
  45. package/dist/conformance/widget.d.ts +3 -0
  46. package/dist/conformance/widget.d.ts.map +1 -0
  47. package/dist/conformance/widget.js +49 -0
  48. package/dist/conformance/widget.js.map +1 -0
  49. package/dist/conformance.d.ts +1 -58
  50. package/dist/conformance.d.ts.map +1 -1
  51. package/dist/conformance.js +3 -1748
  52. package/dist/conformance.js.map +1 -1
  53. package/dist/editor/editor.d.ts.map +1 -1
  54. package/dist/editor/editor.js +18 -1
  55. package/dist/editor/editor.js.map +1 -1
  56. package/dist/editor/extension.d.ts +47 -3
  57. package/dist/editor/extension.d.ts.map +1 -1
  58. package/dist/features/ace.d.ts +4 -0
  59. package/dist/features/ace.d.ts.map +1 -1
  60. package/dist/features/ace.js +59 -20
  61. package/dist/features/ace.js.map +1 -1
  62. package/dist/features/block-dnd.d.ts +7 -0
  63. package/dist/features/block-dnd.d.ts.map +1 -0
  64. package/dist/features/block-dnd.js +207 -0
  65. package/dist/features/block-dnd.js.map +1 -0
  66. package/dist/features/code-block.d.ts +9 -84
  67. package/dist/features/code-block.d.ts.map +1 -1
  68. package/dist/features/code-block.js +84 -1034
  69. package/dist/features/code-block.js.map +1 -1
  70. package/dist/features/code-context.d.ts +81 -0
  71. package/dist/features/code-context.d.ts.map +1 -0
  72. package/dist/features/code-context.js +322 -0
  73. package/dist/features/code-context.js.map +1 -0
  74. package/dist/features/code-edit.d.ts +50 -0
  75. package/dist/features/code-edit.d.ts.map +1 -0
  76. package/dist/features/code-edit.js +412 -0
  77. package/dist/features/code-edit.js.map +1 -0
  78. package/dist/features/code-format.d.ts +21 -0
  79. package/dist/features/code-format.d.ts.map +1 -0
  80. package/dist/features/code-format.js +410 -0
  81. package/dist/features/code-format.js.map +1 -0
  82. package/dist/features/doc.d.ts +16 -0
  83. package/dist/features/doc.d.ts.map +1 -1
  84. package/dist/features/doc.js +154 -2
  85. package/dist/features/doc.js.map +1 -1
  86. package/dist/features/heading.d.ts.map +1 -1
  87. package/dist/features/heading.js.map +1 -1
  88. package/dist/features/image.d.ts +3 -1
  89. package/dist/features/image.d.ts.map +1 -1
  90. package/dist/features/image.js +27 -9
  91. package/dist/features/image.js.map +1 -1
  92. package/dist/features/index.d.ts +7 -0
  93. package/dist/features/index.d.ts.map +1 -1
  94. package/dist/features/index.js +16 -0
  95. package/dist/features/index.js.map +1 -1
  96. package/dist/features/inline-style.d.ts.map +1 -1
  97. package/dist/features/inline-style.js +4 -1
  98. package/dist/features/inline-style.js.map +1 -1
  99. package/dist/features/link.d.ts.map +1 -1
  100. package/dist/features/link.js +1 -1
  101. package/dist/features/link.js.map +1 -1
  102. package/dist/features/markdown.d.ts +15 -0
  103. package/dist/features/markdown.d.ts.map +1 -0
  104. package/dist/features/markdown.js +80 -0
  105. package/dist/features/markdown.js.map +1 -0
  106. package/dist/features/marks.d.ts.map +1 -1
  107. package/dist/features/marks.js +49 -4
  108. package/dist/features/marks.js.map +1 -1
  109. package/dist/features/mention.d.ts +30 -0
  110. package/dist/features/mention.d.ts.map +1 -0
  111. package/dist/features/mention.js +89 -0
  112. package/dist/features/mention.js.map +1 -0
  113. package/dist/features/script.d.ts.map +1 -1
  114. package/dist/features/script.js.map +1 -1
  115. package/dist/features/search.d.ts +76 -0
  116. package/dist/features/search.d.ts.map +1 -0
  117. package/dist/features/search.js +281 -0
  118. package/dist/features/search.js.map +1 -0
  119. package/dist/features/shared.d.ts +69 -0
  120. package/dist/features/shared.d.ts.map +1 -0
  121. package/dist/features/shared.js +272 -0
  122. package/dist/features/shared.js.map +1 -0
  123. package/dist/features/table.d.ts.map +1 -1
  124. package/dist/features/table.js +17 -3
  125. package/dist/features/table.js.map +1 -1
  126. package/dist/features/testkit.d.ts.map +1 -1
  127. package/dist/features/testkit.js +1 -1
  128. package/dist/features/testkit.js.map +1 -1
  129. package/dist/history.d.ts.map +1 -1
  130. package/dist/history.js +65 -20
  131. package/dist/history.js.map +1 -1
  132. package/dist/index.d.ts +21 -7
  133. package/dist/index.d.ts.map +1 -1
  134. package/dist/index.js +18 -6
  135. package/dist/index.js.map +1 -1
  136. package/dist/model/schema.d.ts.map +1 -1
  137. package/dist/model/schema.js +2 -1
  138. package/dist/model/schema.js.map +1 -1
  139. package/dist/parse/html.d.ts.map +1 -1
  140. package/dist/parse/html.js +38 -6
  141. package/dist/parse/html.js.map +1 -1
  142. package/dist/parse/sanitize.d.ts.map +1 -1
  143. package/dist/parse/sanitize.js +4 -1
  144. package/dist/parse/sanitize.js.map +1 -1
  145. package/dist/presets/highlight.d.ts.map +1 -1
  146. package/dist/presets/highlight.js +1 -4
  147. package/dist/presets/highlight.js.map +1 -1
  148. package/dist/presets/markdown-parse.d.ts +13 -0
  149. package/dist/presets/markdown-parse.d.ts.map +1 -0
  150. package/dist/presets/markdown-parse.js +398 -0
  151. package/dist/presets/markdown-parse.js.map +1 -0
  152. package/dist/presets/markdown.d.ts +46 -0
  153. package/dist/presets/markdown.d.ts.map +1 -0
  154. package/dist/presets/markdown.js +196 -0
  155. package/dist/presets/markdown.js.map +1 -0
  156. package/dist/state/apply.d.ts.map +1 -1
  157. package/dist/state/apply.js +25 -13
  158. package/dist/state/apply.js.map +1 -1
  159. package/dist/state/delete-ops.d.ts +34 -0
  160. package/dist/state/delete-ops.d.ts.map +1 -0
  161. package/dist/state/delete-ops.js +204 -0
  162. package/dist/state/delete-ops.js.map +1 -0
  163. package/dist/state/input-rules.d.ts +30 -0
  164. package/dist/state/input-rules.d.ts.map +1 -0
  165. package/dist/state/input-rules.js +70 -0
  166. package/dist/state/input-rules.js.map +1 -0
  167. package/dist/state/insert-ops.d.ts +54 -0
  168. package/dist/state/insert-ops.d.ts.map +1 -0
  169. package/dist/state/insert-ops.js +186 -0
  170. package/dist/state/insert-ops.js.map +1 -0
  171. package/dist/state/list-ops.d.ts +46 -0
  172. package/dist/state/list-ops.d.ts.map +1 -0
  173. package/dist/state/list-ops.js +231 -0
  174. package/dist/state/list-ops.js.map +1 -0
  175. package/dist/state/navigate.d.ts.map +1 -1
  176. package/dist/state/navigate.js +3 -1
  177. package/dist/state/navigate.js.map +1 -1
  178. package/dist/state/resolve-insert.d.ts +55 -0
  179. package/dist/state/resolve-insert.d.ts.map +1 -0
  180. package/dist/state/resolve-insert.js +118 -0
  181. package/dist/state/resolve-insert.js.map +1 -0
  182. package/dist/state/slice-ops.d.ts +46 -0
  183. package/dist/state/slice-ops.d.ts.map +1 -0
  184. package/dist/state/slice-ops.js +150 -0
  185. package/dist/state/slice-ops.js.map +1 -0
  186. package/dist/state/state.d.ts +6 -1
  187. package/dist/state/state.d.ts.map +1 -1
  188. package/dist/state/state.js +10 -0
  189. package/dist/state/state.js.map +1 -1
  190. package/dist/state/transaction.d.ts +43 -49
  191. package/dist/state/transaction.d.ts.map +1 -1
  192. package/dist/state/transaction.js +62 -858
  193. package/dist/state/transaction.js.map +1 -1
  194. package/dist/styles.css +401 -213
  195. package/dist/theme.d.ts +29 -0
  196. package/dist/theme.d.ts.map +1 -0
  197. package/dist/theme.js +347 -0
  198. package/dist/theme.js.map +1 -0
  199. package/dist/view/adapter.d.ts +84 -0
  200. package/dist/view/adapter.d.ts.map +1 -0
  201. package/dist/view/adapter.js +76 -0
  202. package/dist/view/adapter.js.map +1 -0
  203. package/dist/view/caret.d.ts +25 -0
  204. package/dist/view/caret.d.ts.map +1 -0
  205. package/dist/view/caret.js +43 -0
  206. package/dist/view/caret.js.map +1 -0
  207. package/dist/view/decoration.d.ts +9 -0
  208. package/dist/view/decoration.d.ts.map +1 -0
  209. package/dist/view/decoration.js +214 -0
  210. package/dist/view/decoration.js.map +1 -0
  211. package/dist/view/dirty-keys.d.ts +18 -0
  212. package/dist/view/dirty-keys.d.ts.map +1 -0
  213. package/dist/view/dirty-keys.js +31 -0
  214. package/dist/view/dirty-keys.js.map +1 -0
  215. package/dist/view/dom.d.ts.map +1 -1
  216. package/dist/view/dom.js +7 -5
  217. package/dist/view/dom.js.map +1 -1
  218. package/dist/view/hook-ctx.d.ts +32 -0
  219. package/dist/view/hook-ctx.d.ts.map +1 -0
  220. package/dist/view/hook-ctx.js +64 -0
  221. package/dist/view/hook-ctx.js.map +1 -0
  222. package/dist/view/ime.d.ts +72 -0
  223. package/dist/view/ime.d.ts.map +1 -0
  224. package/dist/view/ime.js +185 -0
  225. package/dist/view/ime.js.map +1 -0
  226. package/dist/view/input.d.ts +12 -12
  227. package/dist/view/input.d.ts.map +1 -1
  228. package/dist/view/input.js +156 -535
  229. package/dist/view/input.js.map +1 -1
  230. package/dist/view/keys.d.ts +25 -0
  231. package/dist/view/keys.d.ts.map +1 -0
  232. package/dist/view/keys.js +106 -0
  233. package/dist/view/keys.js.map +1 -0
  234. package/dist/view/line-nav.d.ts +13 -0
  235. package/dist/view/line-nav.d.ts.map +1 -0
  236. package/dist/view/line-nav.js +114 -0
  237. package/dist/view/line-nav.js.map +1 -0
  238. package/dist/view/mount.d.ts.map +1 -1
  239. package/dist/view/mount.js +43 -39
  240. package/dist/view/mount.js.map +1 -1
  241. package/dist/view/node-selection.d.ts +33 -0
  242. package/dist/view/node-selection.d.ts.map +1 -0
  243. package/dist/view/node-selection.js +107 -0
  244. package/dist/view/node-selection.js.map +1 -0
  245. package/dist/view/render.d.ts +4 -1
  246. package/dist/view/render.d.ts.map +1 -1
  247. package/dist/view/render.js +22 -3
  248. package/dist/view/render.js.map +1 -1
  249. package/dist/view/serialize.d.ts.map +1 -1
  250. package/dist/view/serialize.js +14 -5
  251. package/dist/view/serialize.js.map +1 -1
  252. package/package.json +1 -1
@@ -0,0 +1,89 @@
1
+ import { createText } from "../model/node.js";
2
+ import { normalizedRange, pointEq } from "../state/selection.js";
3
+ import { defineFeature } from "./feature.js";
4
+ /**
5
+ * 멘션 — 인라인 atom 노드(@이름 칩)의 레퍼런스 구현.
6
+ *
7
+ * 스키마가 `inline: true` + `atom: true`를 지원하는지 검증하는
8
+ * 기능이기도 하다 — image는 "블록" atom이라 인라인 atom은
9
+ * 이 모듈이 첫 용례다. DOM 계약:
10
+ *
11
+ * <span class="me-mention" data-me-path="i,j"
12
+ * contenteditable="false" data-label="이름"></span>
13
+ *
14
+ * - 라벨은 DOM 텍스트가 아니라 CSS `::after { content: attr(data-label) }`로
15
+ * 그린다 — 텍스트 노드가 없어서 텍스트 누적 오프셋 매핑(dom.ts)이
16
+ * 그대로 유지된다.
17
+ * - atom이라 삭제·드래그는 노드 통째로 — domToPoint가 ce=false
18
+ * 홀더를 부모 경계로 환원한다.
19
+ * - parseDOM은 span.me-mention을 다시 노드로 읽는다 — 붙여넣기 왕복.
20
+ *
21
+ * starterFeatures에는 넣지 않는다 — 제품에서 자기 데이터(id 정책,
22
+ * 라벨 렌더)에 맞게 어트리뷰트를 정하는 영역이라 à-la-carte다:
23
+ * extensions: [...starterFeatures(), mentionFeature]
24
+ */
25
+ /**
26
+ * 멘션 삽입 — 캐럿 위치에 atom 칩을 넣고 뒤에 공백 하나를 둔다
27
+ * (캐럿이 atom 경계에 붙어 다음 타이핑이 어색해지는 것을 막는
28
+ * Tiptap insertContent 관례). 범위 선택이면 먼저 지운다.
29
+ */
30
+ export const insertMention = ({ state, tr, dispatch }, label, id) => {
31
+ const name = typeof label === "string" && label
32
+ ? label
33
+ : (globalThis.prompt?.("멘션 이름") ?? null);
34
+ if (!name)
35
+ return false;
36
+ const sel = state.selection;
37
+ if (sel.type !== "text")
38
+ return false;
39
+ const range = normalizedRange(sel);
40
+ const node = {
41
+ type: "mention",
42
+ attrs: { id: typeof id === "string" ? id : name, label: name },
43
+ };
44
+ if (!pointEq(range.anchor, range.focus))
45
+ tr.delete(range);
46
+ // [mention, " "]를 한 조각으로 — insertSlice가 텍스트 분할/컨테이너
47
+ // 경계 해석/캐럿 위치를 알아서 처리한다. insertText로 뒤 공백을
48
+ // 따로 넣으면 리프 끝 삽입 시 공백이 멘션 앞 텍스트에 붙는다
49
+ tr.insertSlice(range.anchor, [node, createText(" ")]);
50
+ dispatch();
51
+ return true;
52
+ };
53
+ export const mentionFeature = defineFeature({
54
+ name: "mention",
55
+ description: "멘션 — @이름 인라인 atom 칩 (insertMention), ce=false + ::after 라벨",
56
+ nodes: {
57
+ mention: {
58
+ inline: true,
59
+ atom: true,
60
+ group: "inline",
61
+ attrs: {
62
+ id: { default: "" },
63
+ label: { default: "" },
64
+ },
65
+ toDOM: (n) => ({
66
+ tag: "span",
67
+ attrs: {
68
+ class: "me-mention",
69
+ "data-id": String(n.attrs?.["id"] ?? ""),
70
+ "data-label": String(n.attrs?.["label"] ?? ""),
71
+ contenteditable: "false",
72
+ },
73
+ }),
74
+ parseDOM: [
75
+ {
76
+ tag: "span.me-mention",
77
+ getAttrs: (el) => ({
78
+ id: el.getAttribute("data-id") ?? "",
79
+ label: el.getAttribute("data-label") ?? "",
80
+ }),
81
+ },
82
+ ],
83
+ },
84
+ },
85
+ commands: {
86
+ insertMention,
87
+ },
88
+ });
89
+ //# sourceMappingURL=mention.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mention.js","sourceRoot":"","sources":["../../src/features/mention.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAY,CACpC,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,EAAE,EACvB,KAAM,EACN,EAAG,EACH,EAAE;IACF,MAAM,IAAI,GACR,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK;QAChC,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC;IAC7C,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IACxB,MAAM,GAAG,GAAG,KAAK,CAAC,SAAS,CAAC;IAC5B,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,KAAK,CAAC;IACtC,MAAM,KAAK,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IACnC,MAAM,IAAI,GAAe;QACvB,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE;KAC/D,CAAC;IACF,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC;QAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC1D,oDAAoD;IACpD,2CAA2C;IAC3C,qCAAqC;IACrC,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACtD,QAAQ,EAAE,CAAC;IACX,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,aAAa,CAAC;IAC1C,IAAI,EAAE,SAAS;IACf,WAAW,EACT,4DAA4D;IAC9D,KAAK,EAAE;QACL,OAAO,EAAE;YACP,MAAM,EAAE,IAAI;YACZ,IAAI,EAAE,IAAI;YACV,KAAK,EAAE,QAAQ;YACf,KAAK,EAAE;gBACL,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;gBACnB,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;aACvB;YACD,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACb,GAAG,EAAE,MAAM;gBACX,KAAK,EAAE;oBACL,KAAK,EAAE,YAAY;oBACnB,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;oBACxC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;oBAC9C,eAAe,EAAE,OAAO;iBACzB;aACF,CAAC;YACF,QAAQ,EAAE;gBACR;oBACE,GAAG,EAAE,iBAAiB;oBACtB,QAAQ,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;wBACjB,EAAE,EAAE,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,IAAI,EAAE;wBACpC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,YAAY,CAAC,IAAI,EAAE;qBAC3C,CAAC;iBACH;aACF;SACF;KACF;IACD,QAAQ,EAAE;QACR,aAAa;KACd;CACF,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"script.d.ts","sourceRoot":"","sources":["../../src/features/script.ts"],"names":[],"mappings":"AAqCA,eAAO,MAAM,aAAa,gCAqBxB,CAAC"}
1
+ {"version":3,"file":"script.d.ts","sourceRoot":"","sources":["../../src/features/script.ts"],"names":[],"mappings":"AAmCA,eAAO,MAAM,aAAa,gCAqBxB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"script.js","sourceRoot":"","sources":["../../src/features/script.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C;;;GAGG;AAEH,2CAA2C;AAC3C,SAAS,eAAe,CAAC,QAAgB,EAAE,KAAa;IACtD,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;QACjC,MAAM,GAAG,GAAG,KAAK,CAAC,SAAS,CAAC;QAC5B,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM;YAAE,OAAO,KAAK,CAAC;QACtC,MAAM,KAAK,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;YACvC,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,MAAM,CAC1C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CACxB,CAAC;YACF,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;YACjD,EAAE,CAAC,cAAc,CACf,GAAG;gBACD,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC;gBACxC,CAAC,CAAC,CAAC,GAAG,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CACjC,CAAC;QACJ,CAAC;aAAM,IAAI,YAAY,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,EAAE,QAAQ,CAAC,EAAE,CAAC;YACpD,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QACjC,CAAC;aAAM,CAAC;YACN,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;YAC5B,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;QACxC,CAAC;QACD,QAAQ,EAAE,CAAC;QACX,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,aAAa,CAAC;IACzC,IAAI,EAAE,QAAQ;IACd,WAAW,EAAE,6CAA6C;IAC1D,KAAK,EAAE;QACL,SAAS,EAAE;YACT,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;YAC7B,QAAQ,EAAE,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;SAC3B;QACD,WAAW,EAAE;YACX,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;YAC7B,QAAQ,EAAE,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;SAC3B;KACF;IACD,QAAQ,EAAE;QACR,eAAe,EAAE,eAAe,CAAC,WAAW,EAAE,aAAa,CAAC;QAC5D,iBAAiB,EAAE,eAAe,CAAC,aAAa,EAAE,WAAW,CAAC;KAC/D;IACD,MAAM,EAAE;QACN,OAAO,EAAE,eAAe,CAAC,aAAa,EAAE,WAAW,CAAC;QACpD,OAAO,EAAE,eAAe,CAAC,WAAW,EAAE,aAAa,CAAC;KACrD;CACF,CAAC,CAAC"}
1
+ {"version":3,"file":"script.js","sourceRoot":"","sources":["../../src/features/script.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C;;;GAGG;AAEH,2CAA2C;AAC3C,SAAS,eAAe,CAAC,QAAgB,EAAE,KAAa;IACtD,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;QACjC,MAAM,GAAG,GAAG,KAAK,CAAC,SAAS,CAAC;QAC5B,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM;YAAE,OAAO,KAAK,CAAC;QACtC,MAAM,KAAK,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;YACvC,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC;YACtE,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;YACjD,EAAE,CAAC,cAAc,CACf,GAAG;gBACD,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC;gBACxC,CAAC,CAAC,CAAC,GAAG,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CACjC,CAAC;QACJ,CAAC;aAAM,IAAI,YAAY,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,EAAE,QAAQ,CAAC,EAAE,CAAC;YACpD,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QACjC,CAAC;aAAM,CAAC;YACN,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;YAC5B,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;QACxC,CAAC;QACD,QAAQ,EAAE,CAAC;QACX,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,aAAa,CAAC;IACzC,IAAI,EAAE,QAAQ;IACd,WAAW,EAAE,6CAA6C;IAC1D,KAAK,EAAE;QACL,SAAS,EAAE;YACT,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;YAC7B,QAAQ,EAAE,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;SAC3B;QACD,WAAW,EAAE;YACX,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;YAC7B,QAAQ,EAAE,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;SAC3B;KACF;IACD,QAAQ,EAAE;QACR,eAAe,EAAE,eAAe,CAAC,WAAW,EAAE,aAAa,CAAC;QAC5D,iBAAiB,EAAE,eAAe,CAAC,aAAa,EAAE,WAAW,CAAC;KAC/D;IACD,MAAM,EAAE;QACN,OAAO,EAAE,eAAe,CAAC,aAAa,EAAE,WAAW,CAAC;QACpD,OAAO,EAAE,eAAe,CAAC,WAAW,EAAE,aAAa,CAAC;KACrD;CACF,CAAC,CAAC"}
@@ -0,0 +1,76 @@
1
+ import type { Command } from "../editor/extension.js";
2
+ import type { EditorNode } from "../model/node.js";
3
+ import type { Point } from "../state/selection.js";
4
+ /**
5
+ * 검색/치환 — 문서 내 텍스트를 찾아 매치를 수집하고, 이동·치환하는
6
+ * 기능 모듈. Tiptap은 외부 검색 확장을 쓰지만, 순수 JSON doc이라
7
+ * 코어 플러그인 하나로 매치 수집이 끝난다.
8
+ *
9
+ * 구조:
10
+ * - Plugin("search")이 pluginState에 {query, matches, active}를 유지.
11
+ * doc이 바뀌거나 쿼리가 바뀌면 apply 단계에서 매치를 재계산한다 —
12
+ * 셀렉션만 바뀌는 tr은 재계산을 건너뛰어 타이핑 외 입력이 공짜다.
13
+ * - 커맨드는 tr.meta["search"]로 쿼리/active를 채널에 싣는다 —
14
+ * history.group과 같은 메타 채널 관례.
15
+ * - 하이라이트는 CSS Custom Highlight API(::highlight(me-find)) —
16
+ * 괄호 매칭(me-bracket)과 같은 계약이라 DOM/매핑을 전혀 건드리지
17
+ * 않는다. 미지원 환경(jsdom/구형)은 조용히 스킵.
18
+ *
19
+ * 한계: 매치는 텍스트 노드 경계를 넘지 않는다 — 마크로 쪼개진
20
+ * "검색|어" 같은 경우는 매치되지 않는다 (Notion 1세대 검색과 같은 제약).
21
+ */
22
+ /** 한 매치 — 텍스트 리프 포인트 쌍 (anchor ≤ focus) */
23
+ export interface SearchMatch {
24
+ anchor: Point;
25
+ focus: Point;
26
+ }
27
+ /** pluginState["search"]에 유지되는 상태 */
28
+ export interface SearchState {
29
+ /** 현재 검색어 — 빈 문자열이면 검색 비활성 */
30
+ readonly query: string;
31
+ /** 대소문자 구분 여부 */
32
+ readonly caseSensitive: boolean;
33
+ /** 문서 순서대로 정렬된 매치 목록 */
34
+ readonly matches: readonly SearchMatch[];
35
+ /** 현재 선택된 매치 인덱스 — 없으면 -1 */
36
+ readonly active: number;
37
+ }
38
+ /** 플러그인 키 — tr.meta와 pluginState 양쪽의 채널 이름 */
39
+ export declare const SEARCH_KEY = "search";
40
+ /** state.pluginState에서 검색 상태를 읽는다 — 없으면 비활성 상태 */
41
+ export declare function searchStateOf(state: {
42
+ pluginState: Readonly<Record<string, unknown>>;
43
+ }): SearchState;
44
+ /**
45
+ * doc 안에서 query가 나타나는 모든 위치를 문서 순서대로 돌려준다.
46
+ * 텍스트 노드 단위로만 찾는다 — 노드를 넘는 매치는 잡지 않는다.
47
+ */
48
+ export declare function collectMatches(doc: EditorNode, query: string, caseSensitive?: boolean): SearchMatch[];
49
+ /**
50
+ * 검색어 설정 — 쿼리를 등록하고 매치를 수집해 하이라이트한다.
51
+ * 셀렉션은 움직이지 않는다 — 입력창에 타이핑하는 동안 캐럿이
52
+ * 튀지 않도록 매치로의 이동은 findNext/findPrev의 몫이다.
53
+ * active에는 캐럿 이후 첫 매치 인덱스를 두어 n/total 카운터와
54
+ * 첫 내비게이션의 도착점으로 쓴다. 빈 문자열은 검색 해제와 같다.
55
+ * UI(검색 입력창)가 호출하는 진입점.
56
+ */
57
+ export declare const setSearch: Command;
58
+ export declare const findNext: Command;
59
+ export declare const findPrev: Command;
60
+ /**
61
+ * 현재 매치 하나를 replacement로 치환 — active가 유효하면 그 매치,
62
+ * 아니면 첫 매치. 치환 후 같은 인덱스를 유지하면 자연스럽게
63
+ * "다음 매치"가 active가 된다 (삭제로 앞 매치가 지워지지 않는 한).
64
+ * 일반 편집 트랜잭션이라 undo 단위가 된다.
65
+ */
66
+ export declare const replaceNext: Command;
67
+ /**
68
+ * 모든 매치를 replacement로 일괄 치환 — 뒤쪽 매치부터 처리해 앞쪽
69
+ * 매치의 좌표가 밀리지 않게 한다 (스텝 좌표는 누적 적용 기준).
70
+ * 한 트랜잭션 = 한 undo 단위다.
71
+ */
72
+ export declare const replaceAll: Command;
73
+ /** 검색 해제 — 쿼리·매치·하이라이트를 전부 지운다 */
74
+ export declare const clearSearch: Command;
75
+ export declare const searchFeature: import("./feature.js").Feature;
76
+ //# sourceMappingURL=search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/features/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAU,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAOnD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAKnD;;;;;;;;;;;;;;;;;GAiBG;AAEH,2CAA2C;AAC3C,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,KAAK,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;CACd;AAED,qCAAqC;AACrC,MAAM,WAAW,WAAW;IAC1B,8BAA8B;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,iBAAiB;IACjB,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,wBAAwB;IACxB,QAAQ,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,CAAC;IACzC,6BAA6B;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,8CAA8C;AAC9C,eAAO,MAAM,UAAU,WAAW,CAAC;AASnC,kDAAkD;AAClD,wBAAgB,aAAa,CAAC,KAAK,EAAE;IACnC,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAChD,GAAG,WAAW,CAEd;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,UAAU,EACf,KAAK,EAAE,MAAM,EACb,aAAa,UAAQ,GACpB,WAAW,EAAE,CAsBf;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,SAAS,EAAE,OAwBvB,CAAC;AA6CF,eAAO,MAAM,QAAQ,EAAE,OAAqB,CAAC;AAC7C,eAAO,MAAM,QAAQ,EAAE,OAAsB,CAAC;AAE9C;;;;;GAKG;AACH,eAAO,MAAM,WAAW,EAAE,OAiBzB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,UAAU,EAAE,OAoBxB,CAAC;AAEF,kCAAkC;AAClC,eAAO,MAAM,WAAW,EAAE,OAIzB,CAAC;AAqFF,eAAO,MAAM,aAAa,gCAmBxB,CAAC"}
@@ -0,0 +1,281 @@
1
+ import { normalizedRange, pointCmp, pointEq, textSelection, } from "../state/selection.js";
2
+ import { pointToDOM } from "../view/dom.js";
3
+ import { defineFeature } from "./feature.js";
4
+ /** 플러그인 키 — tr.meta와 pluginState 양쪽의 채널 이름 */
5
+ export const SEARCH_KEY = "search";
6
+ const EMPTY = {
7
+ query: "",
8
+ caseSensitive: false,
9
+ matches: [],
10
+ active: -1,
11
+ };
12
+ /** state.pluginState에서 검색 상태를 읽는다 — 없으면 비활성 상태 */
13
+ export function searchStateOf(state) {
14
+ return state.pluginState[SEARCH_KEY] ?? EMPTY;
15
+ }
16
+ /**
17
+ * doc 안에서 query가 나타나는 모든 위치를 문서 순서대로 돌려준다.
18
+ * 텍스트 노드 단위로만 찾는다 — 노드를 넘는 매치는 잡지 않는다.
19
+ */
20
+ export function collectMatches(doc, query, caseSensitive = false) {
21
+ if (!query)
22
+ return [];
23
+ const needle = caseSensitive ? query : query.toLowerCase();
24
+ const out = [];
25
+ const walk = (node, path) => {
26
+ if (node.type === "text") {
27
+ const raw = node.text ?? "";
28
+ const hay = caseSensitive ? raw : raw.toLowerCase();
29
+ let i = hay.indexOf(needle);
30
+ while (i !== -1) {
31
+ out.push({
32
+ anchor: { path, offset: i },
33
+ focus: { path, offset: i + needle.length },
34
+ });
35
+ i = hay.indexOf(needle, i + needle.length);
36
+ }
37
+ return;
38
+ }
39
+ (node.content ?? []).forEach((c, i) => walk(c, [...path, i]));
40
+ };
41
+ (doc.content ?? []).forEach((c, i) => walk(c, [i]));
42
+ return out;
43
+ }
44
+ /**
45
+ * 검색어 설정 — 쿼리를 등록하고 매치를 수집해 하이라이트한다.
46
+ * 셀렉션은 움직이지 않는다 — 입력창에 타이핑하는 동안 캐럿이
47
+ * 튀지 않도록 매치로의 이동은 findNext/findPrev의 몫이다.
48
+ * active에는 캐럿 이후 첫 매치 인덱스를 두어 n/total 카운터와
49
+ * 첫 내비게이션의 도착점으로 쓴다. 빈 문자열은 검색 해제와 같다.
50
+ * UI(검색 입력창)가 호출하는 진입점.
51
+ */
52
+ export const setSearch = ({ state, tr, dispatch }, query, caseSensitive) => {
53
+ if (typeof query !== "string")
54
+ return false;
55
+ const cs = caseSensitive === true;
56
+ const meta = { query, caseSensitive: cs };
57
+ if (!query) {
58
+ meta["active"] = -1;
59
+ }
60
+ else {
61
+ const matches = collectMatches(state.doc, query, cs);
62
+ const sel = state.selection;
63
+ const caret = sel.type === "text" ? normalizedRange(sel).focus : null;
64
+ // 캐럿 위치 이후의 첫 매치 — 문서 순환(GDocs/VS Code 관례)
65
+ let idx = caret
66
+ ? matches.findIndex((m) => pointCmp(m.focus, caret) > 0)
67
+ : 0;
68
+ if (idx === -1)
69
+ idx = matches.length ? 0 : -1;
70
+ meta["active"] = idx;
71
+ }
72
+ tr.setMeta(SEARCH_KEY, meta);
73
+ dispatch();
74
+ return true;
75
+ };
76
+ /**
77
+ * 다음/이전 매치로 이동 — 셀렉션이 이미 active 매치 위에 있으면
78
+ * 순환하고, 아직 아무 매치로도 가지 않은 상태면 캐럿 기준
79
+ * 이후(또는 이전) 매치로 간다. 이동할 때만 매치를 선택한다.
80
+ */
81
+ const findStep = (dir) => ({ state, tr, dispatch }) => {
82
+ const st = searchStateOf(state);
83
+ const n = st.matches.length;
84
+ if (!st.query || !n)
85
+ return false;
86
+ const sel = state.selection;
87
+ const cur = st.active >= 0 ? st.matches[st.active] : undefined;
88
+ const onActive = !!cur &&
89
+ sel.type === "text" &&
90
+ pointEq(sel.anchor, cur.anchor) &&
91
+ pointEq(sel.focus, cur.focus);
92
+ let next;
93
+ if (onActive) {
94
+ next = (st.active + dir + n) % n;
95
+ }
96
+ else {
97
+ const caret = sel.type === "text" ? normalizedRange(sel).focus : null;
98
+ const i = caret
99
+ ? st.matches.findIndex((m) => pointCmp(m.focus, caret) > 0)
100
+ : -1;
101
+ next =
102
+ dir === 1
103
+ ? i === -1
104
+ ? 0
105
+ : i
106
+ : i === -1
107
+ ? n - 1
108
+ : (i - 1 + n) % n;
109
+ }
110
+ const m = st.matches[next];
111
+ tr.setSelection(textSelection(m.anchor, m.focus));
112
+ tr.setMeta(SEARCH_KEY, { active: next });
113
+ dispatch();
114
+ return true;
115
+ };
116
+ export const findNext = findStep(1);
117
+ export const findPrev = findStep(-1);
118
+ /**
119
+ * 현재 매치 하나를 replacement로 치환 — active가 유효하면 그 매치,
120
+ * 아니면 첫 매치. 치환 후 같은 인덱스를 유지하면 자연스럽게
121
+ * "다음 매치"가 active가 된다 (삭제로 앞 매치가 지워지지 않는 한).
122
+ * 일반 편집 트랜잭션이라 undo 단위가 된다.
123
+ */
124
+ export const replaceNext = ({ state, tr, dispatch }, rep) => {
125
+ const st = searchStateOf(state);
126
+ if (!st.query || !st.matches.length)
127
+ return false;
128
+ const text = typeof rep === "string" ? rep : "";
129
+ const i = st.active >= 0 && st.active < st.matches.length ? st.active : 0;
130
+ const m = st.matches[i];
131
+ tr.delete({ anchor: m.anchor, focus: m.focus });
132
+ if (text)
133
+ tr.insertText(text, m.anchor);
134
+ tr.setSelection(textSelection({
135
+ path: m.anchor.path,
136
+ offset: m.anchor.offset + text.length,
137
+ }));
138
+ tr.setMeta(SEARCH_KEY, { active: i });
139
+ dispatch();
140
+ return true;
141
+ };
142
+ /**
143
+ * 모든 매치를 replacement로 일괄 치환 — 뒤쪽 매치부터 처리해 앞쪽
144
+ * 매치의 좌표가 밀리지 않게 한다 (스텝 좌표는 누적 적용 기준).
145
+ * 한 트랜잭션 = 한 undo 단위다.
146
+ */
147
+ export const replaceAll = ({ state, tr, dispatch }, rep) => {
148
+ const st = searchStateOf(state);
149
+ if (!st.query || !st.matches.length)
150
+ return false;
151
+ const text = typeof rep === "string" ? rep : "";
152
+ const ordered = [...st.matches].sort((a, b) => pointCmp(a.anchor, b.anchor));
153
+ for (let i = ordered.length - 1; i >= 0; i--) {
154
+ const m = ordered[i];
155
+ tr.delete({ anchor: m.anchor, focus: m.focus });
156
+ if (text)
157
+ tr.insertText(text, m.anchor);
158
+ }
159
+ const first = ordered[0];
160
+ tr.setSelection(textSelection({
161
+ path: first.anchor.path,
162
+ offset: first.anchor.offset + text.length,
163
+ }));
164
+ tr.setMeta(SEARCH_KEY, { active: -1 });
165
+ dispatch();
166
+ return true;
167
+ };
168
+ /** 검색 해제 — 쿼리·매치·하이라이트를 전부 지운다 */
169
+ export const clearSearch = ({ tr, dispatch }) => {
170
+ tr.setMeta(SEARCH_KEY, { query: "", active: -1 });
171
+ dispatch();
172
+ return true;
173
+ };
174
+ /**
175
+ * 검색 플러그인 — pluginState의 매치 목록을 doc과 동기화한다.
176
+ * doc이 바뀌거나 쿼리가 바뀐 tr에서만 재수집한다 — 셀렉션/active만
177
+ * 바뀌는 tr(커서 이동, findNext)은 matches를 그대로 재사용한다.
178
+ */
179
+ const searchPlugin = {
180
+ key: SEARCH_KEY,
181
+ init: () => EMPTY,
182
+ apply(tr, prev, prevState, state) {
183
+ const cur = prev;
184
+ const meta = tr.meta[SEARCH_KEY];
185
+ let query = cur.query;
186
+ let caseSensitive = cur.caseSensitive;
187
+ let active = cur.active;
188
+ if (meta) {
189
+ if (typeof meta["query"] === "string")
190
+ query = meta["query"];
191
+ if (typeof meta["caseSensitive"] === "boolean") {
192
+ caseSensitive = meta["caseSensitive"];
193
+ }
194
+ if (typeof meta["active"] === "number")
195
+ active = meta["active"];
196
+ }
197
+ // 검색 해제 — 빈 상태로 접는다
198
+ if (!query) {
199
+ return cur.query === "" && cur.active === -1 ? cur : { ...EMPTY };
200
+ }
201
+ const stale = state.doc !== prevState.doc ||
202
+ query !== cur.query ||
203
+ caseSensitive !== cur.caseSensitive;
204
+ // 셀렉션/active만의 변경 — 매치 재계산 없이 인덱스만 반영
205
+ if (!stale) {
206
+ return active === cur.active ? cur : { ...cur, active };
207
+ }
208
+ const matches = collectMatches(state.doc, query, caseSensitive);
209
+ if (!matches.length) {
210
+ return { query, caseSensitive, matches, active: -1 };
211
+ }
212
+ if (active < 0)
213
+ active = 0;
214
+ return {
215
+ query,
216
+ caseSensitive,
217
+ matches,
218
+ active: Math.min(active, matches.length - 1),
219
+ };
220
+ },
221
+ };
222
+ /**
223
+ * CSS Custom Highlight 등록 — me-bracket(code-block)과 같은
224
+ * DOM-비접촉 계약. 지원하지 않는 환경에서는 조용히 스킵한다.
225
+ */
226
+ function paintSearchHighlights(el, st) {
227
+ const win = el.ownerDocument.defaultView;
228
+ const reg = win
229
+ ?.CSS?.highlights;
230
+ const H = win?.Highlight;
231
+ if (!reg || !H)
232
+ return;
233
+ const all = [];
234
+ const act = [];
235
+ if (st.query) {
236
+ st.matches.forEach((m, i) => {
237
+ const a = pointToDOM(el, m.anchor);
238
+ const f = pointToDOM(el, m.focus);
239
+ if (!a || !f)
240
+ return;
241
+ const r = el.ownerDocument.createRange();
242
+ r.setStart(a.node, a.offset);
243
+ r.setEnd(f.node, f.offset);
244
+ (i === st.active ? act : all).push(r);
245
+ });
246
+ }
247
+ if (all.length)
248
+ reg.set("me-find", new H(...all));
249
+ else
250
+ reg.delete("me-find");
251
+ if (act.length)
252
+ reg.set("me-find-active", new H(...act));
253
+ else
254
+ reg.delete("me-find-active");
255
+ // 찾기 바에 포커스가 있는 동안엔 DOM 셀렉션이 갱신되지 않으므로
256
+ // active 매치를 스크롤로 따라간다 (Chrome 찾기 관례) — nearest라
257
+ // 이미 보이면 아무 동작도 하지 않는다
258
+ const c = act[0]?.startContainer;
259
+ const target = c && (c.nodeType === 1 ? c : c.parentElement);
260
+ target?.scrollIntoView({ block: "nearest", inline: "nearest" });
261
+ }
262
+ export const searchFeature = defineFeature({
263
+ name: "search",
264
+ description: "검색/치환 — setSearch/findNext/replaceNext/replaceAll 커맨드 + ::highlight(me-find) 매치 표시",
265
+ commands: {
266
+ setSearch,
267
+ findNext,
268
+ findPrev,
269
+ replaceNext,
270
+ replaceAll,
271
+ clearSearch,
272
+ },
273
+ plugins: [searchPlugin],
274
+ input: {
275
+ /** 매치 하이라이트 — doc 변경 없이 Range만 등록한다 */
276
+ paintOverlay(el, state) {
277
+ paintSearchHighlights(el, searchStateOf(state));
278
+ },
279
+ },
280
+ });
281
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/features/search.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ import type { Command, InputRule } from "../editor/extension.js";
2
+ import type { EditorNode } from "../model/node.js";
3
+ import type { Range } from "../state/selection.js";
4
+ import type { EditorState } from "../state/state.js";
5
+ import type { Transaction } from "../state/transaction.js";
6
+ /**
7
+ * 기능 모듈 공용 헬퍼 — 두 개 이상의 feature가 쓰는 캐럿 해석·
8
+ * 마크 유틸·입력 규칙 팩토리를 모은다. 기능 전용 헬퍼는 각
9
+ * feature 파일에 둔다.
10
+ */
11
+ /** 범위 안 텍스트가 전부 markType을 가지면 true */
12
+ export declare function rangeHasMark(doc: EditorNode, range: Range, markType: string): boolean;
13
+ /** 마크 토글 커맨드 — collapsed면 storedMarks, 범위면 add/remove */
14
+ export declare function toggleMark(markType: string): Command;
15
+ /**
16
+ * 캐럿/선택에 markType이 활성인가.
17
+ * collapsed면 storedMarks(토글 직후) → 커서 위치 텍스트 마크 순으로 보고,
18
+ * 범위 선택이면 범위 전체가 마크를 가질 때만 true다.
19
+ */
20
+ export declare function isMarkActive(state: EditorState, markType: string): boolean;
21
+ /** 캐럿이 속한 텍스트블록이 type인가 — 중첩(li>p 등) 안에서도 동작 */
22
+ export declare function isBlockActive(state: EditorState, type: string): boolean;
23
+ /**
24
+ * 캐럿이 type 노드 안에 있는가 — 텍스트블록 자신(코드블록)이거나
25
+ * 조상 컨테이너(리스트·인용구·콜아웃)면 true. 툴바 active 판정용.
26
+ */
27
+ export declare function isInNode(state: EditorState, type: string): boolean;
28
+ /**
29
+ * 셀렉션 포인트를 품은 텍스트블록 경로 — 트랜잭션이 만드는 컨테이너
30
+ * 포인트(빈 블록 안 {path:블록,offset:0} 등)도 안쪽 텍스트블록으로
31
+ * 내려간다. 커맨드들의 공용 캐럿 해석.
32
+ */
33
+ export declare function caretBlockPath(state: EditorState): readonly number[] | null;
34
+ /** 캐럿을 품은 리스트 아이템 컨텍스트 — 없으면 null */
35
+ export declare function itemContext(state: EditorState): {
36
+ itemPath: readonly number[];
37
+ listPath: readonly number[];
38
+ } | null;
39
+ /** 캐럿을 품은 텍스트블록을 type으로 교체 — 중첩 안에서도 동작 */
40
+ export declare function setBlockType(type: string, attrs?: Record<string, unknown>): Command;
41
+ /** 인라인 자식들의 텍스트를 순서대로 합친다 (hardBreak 등은 무시) */
42
+ export declare function blockText(node: EditorNode): string;
43
+ export declare function samePath(a: readonly number[], b: readonly number[]): boolean;
44
+ /**
45
+ * 마크 입력 규칙 — `**x**`, `*x*`, `` `x` ``, `~~x~~` 형태.
46
+ * fence 위치는 매치 끝(= 캐럿)에서 문자열 길이로 역산한다 — 패턴이
47
+ * 앞쪽 컨텍스트((?:^|[^*]) 등)를 포함해도 안전하다. fence 전체가
48
+ * 같은 텍스트 노드에 있을 때만 변환 — 경계를 걸치면 스킵.
49
+ */
50
+ export declare function markRule(pattern: RegExp, markType: string, open: string, close?: string): InputRule;
51
+ /**
52
+ * 블록 입력 규칙 — 블록 시작 패턴(`# `, `## `…)이면 블록을 교체한다.
53
+ * fn은 매치와 현재 블록을 받아 교체할 노드 조각(Partial)을 돌려준다 —
54
+ * null이면 규칙 폴스루.
55
+ */
56
+ export declare function blockRule(pattern: RegExp, fn: (m: RegExpMatchArray, block: EditorNode) => Partial<EditorNode> | null): InputRule;
57
+ /** 정렬 attr → DOMSpec — left 기본값은 style을 내지 않는다 */
58
+ export declare function alignDOM(tag: string, n: EditorNode): {
59
+ tag: string;
60
+ attrs?: Record<string, string>;
61
+ };
62
+ /**
63
+ * 래핑 입력 규칙 헬퍼 — `- `, `> `처럼 매치된 블록을 wrapper 안에
64
+ * 넣는다. make()의 content는 블록이 들어갈 빈 슬롯 경로를 표현한다
65
+ * (리스트는 li 껍데기, 인용구는 빈 content). 접두 텍스트는 래핑 후
66
+ * 한 단계 깊어진 위치에서 지운다.
67
+ */
68
+ export declare function wrapBlock(tr: Transaction, range: Range, doc: EditorNode, make: () => EditorNode | null): boolean;
69
+ //# sourceMappingURL=shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/features/shared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAQnD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D;;;;GAIG;AAEH,sCAAsC;AACtC,wBAAgB,YAAY,CAC1B,GAAG,EAAE,UAAU,EACf,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,MAAM,GACf,OAAO,CAWT;AAED,yDAAyD;AACzD,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAmBpD;AAID;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAa1E;AAED,gDAAgD;AAChD,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAGvE;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAQlE;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,WAAW,GACjB,SAAS,MAAM,EAAE,GAAG,IAAI,CAuB1B;AAED,qCAAqC;AACrC,wBAAgB,WAAW,CACzB,KAAK,EAAE,WAAW,GACjB;IAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAAG,IAAI,CAQrE;AAED,2CAA2C;AAC3C,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CA2BT;AAED,+CAA+C;AAC/C,wBAAgB,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAElD;AAED,wBAAgB,QAAQ,CACtB,CAAC,EAAE,SAAS,MAAM,EAAE,EACpB,CAAC,EAAE,SAAS,MAAM,EAAE,GACnB,OAAO,CAET;AAID;;;;;GAKG;AACH,wBAAgB,QAAQ,CACtB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,KAAK,SAAO,GACX,SAAS,CAmCX;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CACvB,OAAO,EAAE,MAAM,EACf,EAAE,EAAE,CAAC,CAAC,EAAE,gBAAgB,EAAE,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC,UAAU,CAAC,GAAG,IAAI,GACzE,SAAS,CAiBX;AAED,kDAAkD;AAClD,wBAAgB,QAAQ,CACtB,GAAG,EAAE,MAAM,EACX,CAAC,EAAE,UAAU,GACZ;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAGjD;AAoBD;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,EAAE,EAAE,WAAW,EACf,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,UAAU,EACf,IAAI,EAAE,MAAM,UAAU,GAAG,IAAI,GAC5B,OAAO,CAkBT"}