@teriusu/rich-editor 0.10.8 → 0.11.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.
Files changed (147) hide show
  1. package/dist/components/BubbleToolbar.svelte +182 -54
  2. package/dist/components/BubbleToolbar.svelte.d.ts +3 -0
  3. package/dist/components/BubbleToolbar.svelte.d.ts.map +1 -1
  4. package/dist/components/EmojiSuggestionMenu.svelte +291 -0
  5. package/dist/components/EmojiSuggestionMenu.svelte.d.ts +9 -0
  6. package/dist/components/EmojiSuggestionMenu.svelte.d.ts.map +1 -0
  7. package/dist/components/FixedToolbar.svelte +53 -47
  8. package/dist/components/FixedToolbar.svelte.d.ts +3 -0
  9. package/dist/components/FixedToolbar.svelte.d.ts.map +1 -1
  10. package/dist/components/FloatingHelper.svelte +219 -0
  11. package/dist/components/FloatingHelper.svelte.d.ts +14 -0
  12. package/dist/components/FloatingHelper.svelte.d.ts.map +1 -0
  13. package/dist/components/InputModal.svelte +7 -3
  14. package/dist/components/InputModal.svelte.d.ts +3 -0
  15. package/dist/components/InputModal.svelte.d.ts.map +1 -1
  16. package/dist/components/MathModal.svelte +33 -29
  17. package/dist/components/MathModal.svelte.d.ts +3 -0
  18. package/dist/components/MathModal.svelte.d.ts.map +1 -1
  19. package/dist/components/MediaPickerModal.svelte +7 -3
  20. package/dist/components/MediaPickerModal.svelte.d.ts +3 -0
  21. package/dist/components/MediaPickerModal.svelte.d.ts.map +1 -1
  22. package/dist/components/SlashCommandMenu.svelte +88 -72
  23. package/dist/components/SlashCommandMenu.svelte.d.ts +3 -0
  24. package/dist/components/SlashCommandMenu.svelte.d.ts.map +1 -1
  25. package/dist/components/TableBubbleMenu.svelte +41 -33
  26. package/dist/components/TableBubbleMenu.svelte.d.ts +3 -0
  27. package/dist/components/TableBubbleMenu.svelte.d.ts.map +1 -1
  28. package/dist/components/TipTapEditor.svelte +239 -127
  29. package/dist/components/TipTapEditor.svelte.d.ts +7 -0
  30. package/dist/components/TipTapEditor.svelte.d.ts.map +1 -1
  31. package/dist/extensions/CardBlock.d.ts.map +1 -1
  32. package/dist/extensions/CardBlock.js +6 -4
  33. package/dist/extensions/FileAttachment.d.ts.map +1 -1
  34. package/dist/extensions/FileAttachment.js +2 -1
  35. package/dist/extensions/FixedDetails.d.ts.map +1 -1
  36. package/dist/extensions/FixedDetails.js +5 -3
  37. package/dist/extensions/LegacyBlock.d.ts.map +1 -1
  38. package/dist/extensions/LegacyBlock.js +8 -6
  39. package/dist/extensions/Math.d.ts.map +1 -1
  40. package/dist/extensions/Math.js +5 -2
  41. package/dist/extensions/MbusVideo.d.ts.map +1 -1
  42. package/dist/extensions/MbusVideo.js +73 -9
  43. package/dist/extensions/MediaToolbar.d.ts +41 -0
  44. package/dist/extensions/MediaToolbar.d.ts.map +1 -0
  45. package/dist/extensions/MediaToolbar.js +196 -0
  46. package/dist/extensions/MediaToolbar.test.d.ts +2 -0
  47. package/dist/extensions/MediaToolbar.test.d.ts.map +1 -0
  48. package/dist/extensions/MediaToolbar.test.js +231 -0
  49. package/dist/extensions/OrderedListMarker.d.ts +2 -0
  50. package/dist/extensions/OrderedListMarker.d.ts.map +1 -0
  51. package/dist/extensions/OrderedListMarker.js +114 -0
  52. package/dist/extensions/OrderedListMarker.test.d.ts +2 -0
  53. package/dist/extensions/OrderedListMarker.test.d.ts.map +1 -0
  54. package/dist/extensions/OrderedListMarker.test.js +176 -0
  55. package/dist/extensions/PdfBlock.d.ts.map +1 -1
  56. package/dist/extensions/PdfBlock.js +25 -23
  57. package/dist/extensions/ResizableImage.d.ts.map +1 -1
  58. package/dist/extensions/ResizableImage.js +20 -1
  59. package/dist/extensions/TableKeymap.d.ts +16 -0
  60. package/dist/extensions/TableKeymap.d.ts.map +1 -0
  61. package/dist/extensions/TableKeymap.js +97 -0
  62. package/dist/extensions/TableKeymap.test.d.ts +2 -0
  63. package/dist/extensions/TableKeymap.test.d.ts.map +1 -0
  64. package/dist/extensions/TableKeymap.test.js +147 -0
  65. package/dist/extensions/TabsBlock.d.ts.map +1 -1
  66. package/dist/extensions/TabsBlock.js +12 -9
  67. package/dist/extensions/TiptapMidibus.d.ts.map +1 -1
  68. package/dist/extensions/TiptapMidibus.js +60 -6
  69. package/dist/extensions/UploadSkeleton.d.ts +61 -0
  70. package/dist/extensions/UploadSkeleton.d.ts.map +1 -0
  71. package/dist/extensions/UploadSkeleton.js +233 -0
  72. package/dist/extensions/UploadSkeleton.test.d.ts +2 -0
  73. package/dist/extensions/UploadSkeleton.test.d.ts.map +1 -0
  74. package/dist/extensions/UploadSkeleton.test.js +128 -0
  75. package/dist/extensions/VideoEmbed.d.ts +8 -0
  76. package/dist/extensions/VideoEmbed.d.ts.map +1 -1
  77. package/dist/extensions/VideoEmbed.js +226 -45
  78. package/dist/extensions/VideoEmbed.test.js +131 -2
  79. package/dist/i18n/en.d.ts +3 -0
  80. package/dist/i18n/en.d.ts.map +1 -0
  81. package/dist/i18n/en.js +191 -0
  82. package/dist/i18n/es.d.ts +3 -0
  83. package/dist/i18n/es.d.ts.map +1 -0
  84. package/dist/i18n/es.js +191 -0
  85. package/dist/i18n/index.d.ts +43 -0
  86. package/dist/i18n/index.d.ts.map +1 -0
  87. package/dist/i18n/index.js +109 -0
  88. package/dist/i18n/index.test.d.ts +2 -0
  89. package/dist/i18n/index.test.d.ts.map +1 -0
  90. package/dist/i18n/index.test.js +173 -0
  91. package/dist/i18n/ja.d.ts +3 -0
  92. package/dist/i18n/ja.d.ts.map +1 -0
  93. package/dist/i18n/ja.js +191 -0
  94. package/dist/i18n/ko.d.ts +198 -0
  95. package/dist/i18n/ko.d.ts.map +1 -0
  96. package/dist/i18n/ko.js +215 -0
  97. package/dist/i18n/zh-hans.d.ts +3 -0
  98. package/dist/i18n/zh-hans.d.ts.map +1 -0
  99. package/dist/i18n/zh-hans.js +191 -0
  100. package/dist/i18n/zh-hant.d.ts +3 -0
  101. package/dist/i18n/zh-hant.d.ts.map +1 -0
  102. package/dist/i18n/zh-hant.js +192 -0
  103. package/dist/index.d.ts +7 -1
  104. package/dist/index.d.ts.map +1 -1
  105. package/dist/index.js +13 -1
  106. package/dist/static/highlight.d.ts +13 -0
  107. package/dist/static/highlight.d.ts.map +1 -0
  108. package/dist/static/highlight.js +99 -0
  109. package/dist/static/index.d.ts +33 -0
  110. package/dist/static/index.d.ts.map +1 -0
  111. package/dist/static/index.js +367 -0
  112. package/dist/static/index.test.d.ts +2 -0
  113. package/dist/static/index.test.d.ts.map +1 -0
  114. package/dist/static/index.test.js +194 -0
  115. package/dist/static/tokenizer.d.ts +52 -0
  116. package/dist/static/tokenizer.d.ts.map +1 -0
  117. package/dist/static/tokenizer.js +289 -0
  118. package/dist/styles/editor.css +1 -1
  119. package/dist/utils/emoji-data.d.ts +15 -0
  120. package/dist/utils/emoji-suggestion.d.ts +48 -0
  121. package/dist/utils/emoji-suggestion.d.ts.map +1 -0
  122. package/dist/utils/emoji-suggestion.js +51 -0
  123. package/dist/utils/emoji-suggestion.test.d.ts +2 -0
  124. package/dist/utils/emoji-suggestion.test.d.ts.map +1 -0
  125. package/dist/utils/emoji-suggestion.test.js +117 -0
  126. package/dist/utils/floating-helper.d.ts +60 -0
  127. package/dist/utils/floating-helper.d.ts.map +1 -0
  128. package/dist/utils/floating-helper.js +63 -0
  129. package/dist/utils/floating-helper.test.d.ts +2 -0
  130. package/dist/utils/floating-helper.test.d.ts.map +1 -0
  131. package/dist/utils/floating-helper.test.js +141 -0
  132. package/dist/utils/guard-vscode-paste.d.ts +19 -0
  133. package/dist/utils/guard-vscode-paste.d.ts.map +1 -0
  134. package/dist/utils/guard-vscode-paste.js +46 -0
  135. package/dist/utils/guard-vscode-paste.test.d.ts +2 -0
  136. package/dist/utils/guard-vscode-paste.test.d.ts.map +1 -0
  137. package/dist/utils/guard-vscode-paste.test.js +86 -0
  138. package/dist/utils/media-size.d.ts +29 -0
  139. package/dist/utils/media-size.d.ts.map +1 -0
  140. package/dist/utils/media-size.js +90 -0
  141. package/dist/utils/resize.d.ts +12 -0
  142. package/dist/utils/resize.d.ts.map +1 -1
  143. package/dist/utils/resize.js +5 -5
  144. package/dist/utils/sanitize.d.ts +2 -0
  145. package/dist/utils/sanitize.d.ts.map +1 -1
  146. package/dist/utils/sanitize.js +28 -3
  147. package/package.json +8 -1
@@ -1,6 +1,7 @@
1
1
  import type { Editor } from "@tiptap/core";
2
2
  import type { Snippet } from "svelte";
3
3
  import type { ToolbarFeature, PromptHandler } from "../types";
4
+ import { type EditorTranslator } from "../i18n";
4
5
  type $$ComponentProps = {
5
6
  editor: Editor;
6
7
  features: Set<ToolbarFeature>;
@@ -25,6 +26,8 @@ type $$ComponentProps = {
25
26
  * 여기에 넣으면 툴바의 flex 행에 그대로 얹혀 정렬이 저절로 맞는다.
26
27
  */
27
28
  toolbarEnd?: Snippet;
29
+ /** 에디터 UI 번역 함수. 미주입 시 ko. */
30
+ t?: EditorTranslator;
28
31
  };
29
32
  declare const FixedToolbar: import("svelte").Component<$$ComponentProps, {}, "">;
30
33
  type FixedToolbar = ReturnType<typeof FixedToolbar>;
@@ -1 +1 @@
1
- {"version":3,"file":"FixedToolbar.svelte.d.ts","sourceRoot":"","sources":["../../src/components/FixedToolbar.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAwCtC,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE7D,KAAK,gBAAgB,GAAI;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,GAAG,CAAC,cAAc,CAAC,CAAC;IAC9B,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB;;;;;OAKG;IACH,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,0CAA0C;IAC1C,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAuiBJ,QAAA,MAAM,YAAY,sDAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"FixedToolbar.svelte.d.ts","sourceRoot":"","sources":["../../src/components/FixedToolbar.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAwCtC,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC9D,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAElE,KAAK,gBAAgB,GAAI;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,GAAG,CAAC,cAAc,CAAC,CAAC;IAC9B,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB;;;;;OAKG;IACH,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,0CAA0C;IAC1C,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,8BAA8B;IAC9B,CAAC,CAAC,EAAE,gBAAgB,CAAC;CACtB,CAAC;AAyiBJ,QAAA,MAAM,YAAY,sDAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
@@ -0,0 +1,219 @@
1
+ <script lang="ts">
2
+ import type { Editor } from "@tiptap/core";
3
+ import { Sigma, Code2 } from "lucide-svelte";
4
+ import type { ToolbarFeature } from "../types";
5
+ import {
6
+ floatingHelperVisible,
7
+ helperInsertMath,
8
+ helperInsertCodeBlock,
9
+ FLOATING_HELPER_ON_CLASS,
10
+ } from "../utils/floating-helper";
11
+ import { defaultTranslator, type EditorTranslator } from "../i18n";
12
+
13
+ /*
14
+ * 빈 줄 플로팅 헬퍼의 **화면 절반** — 판정·커맨드는 `utils/floating-helper.ts`.
15
+ *
16
+ * 포커스된 최상위 빈 문단 옆에 "/로 명령어 입력" 안내와 수식·코드 즉시 삽입 버튼을
17
+ * 띄운다(main 정올 `Floating.svelte` 의 직접 구현 이식). 에디터 컨테이너
18
+ * (`.hce-editor-wrapper`, `position:relative`) 안에 `position:absolute` 로 그린다 —
19
+ * 포털이 없고 문서 흐름의 자리도 차지하지 않는다.
20
+ *
21
+ * ⚠️ 위치 계산 셋이 main 사고 이력의 재발 방지다:
22
+ * - `.hce-floating-helper` 는 CSS 에서 **처음부터** `position:absolute; width:max-content`
23
+ * 다. 블록 폭으로 측정된 뒤에 좁히면 넘침 보정이 화면 밖(left:-437px)으로 민 전력이
24
+ * 있다(main floating-ui 시절).
25
+ * - 등장 애니메이션은 **안쪽 요소에만** 건다. 바깥(위치 담당)에 transform 을 걸면
26
+ * 위치가 애니메이션 프레임에 덮인다(main `79f64c18`→`c9840fdb`).
27
+ * - 슬래시·이모지 메뉴가 열리면 `suppressed` 로 끈다 — 그 둘은 `position:fixed`
28
+ * 뷰포트 좌표라 좌표계가 달라 서로 피해 갈 수 없다.
29
+ */
30
+ let {
31
+ editor,
32
+ features,
33
+ suppressed = false,
34
+ t = defaultTranslator,
35
+ }: {
36
+ editor: Editor;
37
+ features: Set<ToolbarFeature>;
38
+ suppressed?: boolean;
39
+ /** 에디터 UI 번역 함수. 미주입 시 ko. */
40
+ t?: EditorTranslator;
41
+ } = $props();
42
+
43
+ let visible = $state(false);
44
+ let pos = $state({ top: 0, left: 0 });
45
+ let helperEl = $state<HTMLDivElement>();
46
+ let focused = $state(false);
47
+
48
+ const showMath = $derived(features.has("math"));
49
+ const showCode = $derived(features.has("code-block"));
50
+ const hasButtons = $derived(showMath || showCode);
51
+
52
+ function updatePosition() {
53
+ const wrapper = editor.view.dom.closest(".hce-editor-wrapper") as HTMLElement | null;
54
+ if (!wrapper) return;
55
+ const { from } = editor.state.selection;
56
+ const caret = editor.view.coordsAtPos(from);
57
+ const box = wrapper.getBoundingClientRect();
58
+ let left = caret.right - box.left + 8;
59
+ let top = caret.top - box.top;
60
+ /*
61
+ * 요소가 이미 서 있으면 실측으로 보정한다 — 세로는 커서 줄에 가운데 맞춤,
62
+ * 가로는 래퍼 오른쪽을 넘으면 안으로 죈다(첫 프레임은 아래 `$effect` 가 재계산).
63
+ */
64
+ if (helperEl) {
65
+ const h = helperEl.offsetHeight;
66
+ if (h) top = caret.top - box.top + (caret.bottom - caret.top - h) / 2;
67
+ const w = helperEl.offsetWidth;
68
+ const maxLeft = wrapper.clientWidth - w - 4;
69
+ if (w && left > maxLeft) left = Math.max(4, maxLeft);
70
+ }
71
+ pos = { top, left };
72
+ }
73
+
74
+ function evaluate() {
75
+ const show = floatingHelperVisible(editor, { focused, suppressed });
76
+ if (show) updatePosition();
77
+ visible = show;
78
+ /* placeholder 겹침 방지 — 근거는 `FLOATING_HELPER_ON_CLASS` 주석. */
79
+ editor.view.dom.classList.toggle(FLOATING_HELPER_ON_CLASS, show);
80
+ }
81
+
82
+ $effect(() => {
83
+ focused = editor.view.hasFocus();
84
+ const onFocus = () => {
85
+ focused = true;
86
+ };
87
+ const onBlur = () => {
88
+ focused = false;
89
+ };
90
+ editor.on("transaction", evaluate);
91
+ editor.on("focus", onFocus);
92
+ editor.on("blur", onBlur);
93
+ return () => {
94
+ editor.off("transaction", evaluate);
95
+ editor.off("focus", onFocus);
96
+ editor.off("blur", onBlur);
97
+ editor.view.dom.classList.remove(FLOATING_HELPER_ON_CLASS);
98
+ };
99
+ });
100
+
101
+ /* 포커스·suppressed 가 바뀌면 재판정 (트랜잭션 없이 바뀌는 두 축). */
102
+ $effect(() => {
103
+ focused;
104
+ suppressed;
105
+ evaluate();
106
+ });
107
+
108
+ /* 마운트 직후 실측(폭·높이)으로 한 번 더 자리를 잡는다. */
109
+ $effect(() => {
110
+ if (visible && helperEl) updatePosition();
111
+ });
112
+
113
+ /* 래퍼 안쪽이 스크롤되는 호스트 대비 — 슬래시·이모지 메뉴와 같은 캡처 구독. */
114
+ $effect(() => {
115
+ if (!visible) return;
116
+ const onMove = () => updatePosition();
117
+ window.addEventListener("scroll", onMove, true);
118
+ window.addEventListener("resize", onMove);
119
+ return () => {
120
+ window.removeEventListener("scroll", onMove, true);
121
+ window.removeEventListener("resize", onMove);
122
+ };
123
+ });
124
+ </script>
125
+
126
+ {#if visible}
127
+ <!--
128
+ mousedown preventDefault: 버튼을 누르는 순간 에디터가 blur 되면 클릭이 닿기 전에
129
+ 헬퍼가 사라진다(버튼과 함께). 포커스를 아예 뺏기지 않는 쪽이 main 의
130
+ `setTimeout(focus)` 복원보다 깔끔하다 — 툴바들이 쓰는 표준 수법.
131
+ -->
132
+ <div
133
+ bind:this={helperEl}
134
+ class="hce-floating-helper"
135
+ style="top: {pos.top}px; left: {pos.left}px"
136
+ role="toolbar"
137
+ tabindex="-1"
138
+ aria-label={t('emptyLineTools')}
139
+ onmousedown={(e) => e.preventDefault()}
140
+ >
141
+ <div class="hce-floating-helper-inner">
142
+ <span class="hce-floating-helper-hint">{t('floatingHint')}{hasButtons ? t('floatingHintOr') : ""}</span>
143
+ {#if showMath}
144
+ <button
145
+ type="button"
146
+ class="hce-floating-plus"
147
+ title={t('math')}
148
+ aria-label={t('insertMath')}
149
+ onclick={() => helperInsertMath(editor)}
150
+ >
151
+ <Sigma size={14} />
152
+ </button>
153
+ {/if}
154
+ {#if showCode}
155
+ <button
156
+ type="button"
157
+ class="hce-floating-plus"
158
+ title={t('codeBlock')}
159
+ aria-label={t('insertCodeBlock')}
160
+ onclick={() => helperInsertCodeBlock(editor)}
161
+ >
162
+ <Code2 size={14} />
163
+ </button>
164
+ {/if}
165
+ </div>
166
+ </div>
167
+ {/if}
168
+
169
+ <style>
170
+ /*
171
+ * ⚠️ `position:absolute` + `width:max-content` 는 **여기 고정**이다 — 위치·크기가
172
+ * 런타임 계산보다 먼저 서 있어야 실측 보정(`updatePosition`)이 옳은 폭을 잰다.
173
+ * z-index 100: 정올 sticky 브레드크럼(z:93)보다 위, 모달(z-50=50 계열 Tailwind 층과는
174
+ * 별개 스택) 아래를 노린 값.
175
+ */
176
+ .hce-floating-helper {
177
+ position: absolute;
178
+ width: -moz-max-content;
179
+ width: max-content;
180
+ z-index: 100;
181
+ pointer-events: auto;
182
+ }
183
+
184
+ /* 등장 애니메이션은 안쪽에만 — 바깥 transform 은 위치 계산과 충돌한다. */
185
+ .hce-floating-helper-inner {
186
+ display: flex;
187
+ align-items: center;
188
+ gap: 6px;
189
+ animation: hce-floating-helper-in 0.18s ease-out;
190
+ }
191
+
192
+ @keyframes hce-floating-helper-in {
193
+ from {
194
+ opacity: 0;
195
+ transform: translateX(-4px);
196
+ }
197
+ to {
198
+ opacity: 1;
199
+ transform: none;
200
+ }
201
+ }
202
+
203
+ @media (prefers-reduced-motion: reduce) {
204
+ .hce-floating-helper-inner {
205
+ animation: none;
206
+ }
207
+ }
208
+
209
+ .hce-floating-helper-hint {
210
+ font-size: 0.875rem;
211
+ color: var(--muted-foreground);
212
+ opacity: 0.6;
213
+ pointer-events: none;
214
+ -webkit-user-select: none;
215
+ -moz-user-select: none;
216
+ user-select: none;
217
+ white-space: nowrap;
218
+ }
219
+ </style>
@@ -0,0 +1,14 @@
1
+ import type { Editor } from "@tiptap/core";
2
+ import type { ToolbarFeature } from "../types";
3
+ import { type EditorTranslator } from "../i18n";
4
+ type $$ComponentProps = {
5
+ editor: Editor;
6
+ features: Set<ToolbarFeature>;
7
+ suppressed?: boolean;
8
+ /** 에디터 UI 번역 함수. 미주입 시 ko. */
9
+ t?: EditorTranslator;
10
+ };
11
+ declare const FloatingHelper: import("svelte").Component<$$ComponentProps, {}, "">;
12
+ type FloatingHelper = ReturnType<typeof FloatingHelper>;
13
+ export default FloatingHelper;
14
+ //# sourceMappingURL=FloatingHelper.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FloatingHelper.svelte.d.ts","sourceRoot":"","sources":["../../src/components/FloatingHelper.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAO/C,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAElE,KAAK,gBAAgB,GAAI;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,GAAG,CAAC,cAAc,CAAC,CAAC;IAC9B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,8BAA8B;IAC9B,CAAC,CAAC,EAAE,gBAAgB,CAAC;CACtB,CAAC;AA0IJ,QAAA,MAAM,cAAc,sDAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { X } from "lucide-svelte";
3
+ import { defaultTranslator, type EditorTranslator } from "../i18n";
3
4
 
4
5
  let {
5
6
  title,
@@ -7,12 +8,15 @@
7
8
  defaultValue = "",
8
9
  onConfirm,
9
10
  onCancel,
11
+ t = defaultTranslator,
10
12
  }: {
11
13
  title: string;
12
14
  placeholder?: string;
13
15
  defaultValue?: string;
14
16
  onConfirm: (value: string) => void;
15
17
  onCancel: () => void;
18
+ /** 에디터 UI 번역 함수. 미주입 시 ko. */
19
+ t?: EditorTranslator;
16
20
  } = $props();
17
21
 
18
22
  let value = $state(defaultValue);
@@ -71,7 +75,7 @@
71
75
  type="button"
72
76
  class="p-1 rounded-md hover:bg-muted text-muted-foreground"
73
77
  onclick={onCancel}
74
- aria-label="닫기"
78
+ aria-label={t('close')}
75
79
  >
76
80
  <X size={14} />
77
81
  </button>
@@ -91,14 +95,14 @@
91
95
  class="px-3.5 py-1.5 text-sm rounded-md border border-border hover:bg-muted transition-colors"
92
96
  onclick={onCancel}
93
97
  >
94
- 취소
98
+ {t('cancel')}
95
99
  </button>
96
100
  <button
97
101
  type="button"
98
102
  class="px-3.5 py-1.5 text-sm rounded-md hce-btn-primary hover:opacity-90 transition-opacity"
99
103
  onclick={handleSubmit}
100
104
  >
101
- 확인
105
+ {t('confirm')}
102
106
  </button>
103
107
  </div>
104
108
  </div>
@@ -1,9 +1,12 @@
1
+ import { type EditorTranslator } from "../i18n";
1
2
  type $$ComponentProps = {
2
3
  title: string;
3
4
  placeholder?: string;
4
5
  defaultValue?: string;
5
6
  onConfirm: (value: string) => void;
6
7
  onCancel: () => void;
8
+ /** 에디터 UI 번역 함수. 미주입 시 ko. */
9
+ t?: EditorTranslator;
7
10
  };
8
11
  declare const InputModal: import("svelte").Component<$$ComponentProps, {}, "">;
9
12
  type InputModal = ReturnType<typeof InputModal>;
@@ -1 +1 @@
1
- {"version":3,"file":"InputModal.svelte.d.ts","sourceRoot":"","sources":["../../src/components/InputModal.svelte.ts"],"names":[],"mappings":"AAKC,KAAK,gBAAgB,GAAI;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB,CAAC;AA+EJ,QAAA,MAAM,UAAU,sDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"InputModal.svelte.d.ts","sourceRoot":"","sources":["../../src/components/InputModal.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAElE,KAAK,gBAAgB,GAAI;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,8BAA8B;IAC9B,CAAC,CAAC,EAAE,gBAAgB,CAAC;CACtB,CAAC;AAiFJ,QAAA,MAAM,UAAU,sDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
@@ -11,18 +11,22 @@
11
11
  */
12
12
  import { X } from "lucide-svelte";
13
13
  import katex from "katex";
14
+ import { defaultTranslator, type EditorMessageKey, type EditorTranslator } from "../i18n";
14
15
 
15
16
  let {
16
17
  latex = "",
17
18
  displayMode = false,
18
19
  onConfirm,
19
20
  onCancel,
21
+ t = defaultTranslator,
20
22
  }: {
21
23
  latex?: string;
22
24
  displayMode?: boolean;
23
25
  /** 빈 문자열로 확인하면 호출부가 노드를 지운다(편집 중일 때). */
24
26
  onConfirm: (value: string) => void;
25
27
  onCancel: () => void;
28
+ /** 에디터 UI 번역 함수. 미주입 시 ko. */
29
+ t?: EditorTranslator;
26
30
  } = $props();
27
31
 
28
32
  let value = $state(latex);
@@ -87,27 +91,27 @@
87
91
  *
88
92
  * `$` 는 커서를 놓을 자리다(아래 `insert` 가 그 자리에 커서를 둔다). 없으면 끝에 놓인다.
89
93
  */
90
- const SYMBOLS: { label: string; snippet: string; title: string }[] = [
91
- { label: "x²", snippet: "^{$}", title: "위첨자" },
92
- { label: "xᵢ", snippet: "_{$}", title: "아래첨자" },
93
- { label: "a/b", snippet: "\\frac{$}{}", title: "분수" },
94
- { label: "√", snippet: "\\sqrt{$}", title: "제곱근" },
95
- { label: "∑", snippet: "\\sum_{i=1}^{n} $", title: "합" },
96
- { label: "∏", snippet: "\\prod_{i=1}^{n} $", title: "곱" },
97
- { label: "log", snippet: "\\log $", title: "로그" },
98
- { label: "O(n)", snippet: "O($)", title: "빅오 표기" },
99
- { label: "≤", snippet: "\\le $", title: "작거나 같다" },
100
- { label: "≥", snippet: "\\ge $", title: "크거나 같다" },
101
- { label: "≠", snippet: "\\ne $", title: "같지 않다" },
102
- { label: "×", snippet: "\\times $", title: "곱하기" },
103
- { label: "÷", snippet: "\\div $", title: "나누기" },
104
- { label: "∈", snippet: "\\in $", title: "원소" },
105
- { label: "∞", snippet: "\\infty $", title: "무한대" },
106
- { label: "α", snippet: "\\alpha $", title: "알파" },
107
- { label: "θ", snippet: "\\theta $", title: "세타" },
108
- { label: "π", snippet: "\\pi $", title: "파이" },
109
- { label: "→", snippet: "\\to $", title: "화살표" },
110
- { label: "⋯", snippet: "\\cdots $", title: "가운데 말줄임" },
94
+ const SYMBOLS: { label: string; snippet: string; titleKey: EditorMessageKey }[] = [
95
+ { label: "x²", snippet: "^{$}", titleKey: "mathSuperscript" },
96
+ { label: "xᵢ", snippet: "_{$}", titleKey: "mathSubscript" },
97
+ { label: "a/b", snippet: "\\frac{$}{}", titleKey: "mathFraction" },
98
+ { label: "√", snippet: "\\sqrt{$}", titleKey: "mathSqrt" },
99
+ { label: "∑", snippet: "\\sum_{i=1}^{n} $", titleKey: "mathSum" },
100
+ { label: "∏", snippet: "\\prod_{i=1}^{n} $", titleKey: "mathProduct" },
101
+ { label: "log", snippet: "\\log $", titleKey: "mathLog" },
102
+ { label: "O(n)", snippet: "O($)", titleKey: "mathBigO" },
103
+ { label: "≤", snippet: "\\le $", titleKey: "mathLe" },
104
+ { label: "≥", snippet: "\\ge $", titleKey: "mathGe" },
105
+ { label: "≠", snippet: "\\ne $", titleKey: "mathNe" },
106
+ { label: "×", snippet: "\\times $", titleKey: "mathTimes" },
107
+ { label: "÷", snippet: "\\div $", titleKey: "mathDivide" },
108
+ { label: "∈", snippet: "\\in $", titleKey: "mathIn" },
109
+ { label: "∞", snippet: "\\infty $", titleKey: "mathInfinity" },
110
+ { label: "α", snippet: "\\alpha $", titleKey: "mathAlpha" },
111
+ { label: "θ", snippet: "\\theta $", titleKey: "mathTheta" },
112
+ { label: "π", snippet: "\\pi $", titleKey: "mathPi" },
113
+ { label: "→", snippet: "\\to $", titleKey: "mathArrow" },
114
+ { label: "⋯", snippet: "\\cdots $", titleKey: "mathCdots" },
111
115
  ];
112
116
 
113
117
  /**
@@ -158,13 +162,13 @@
158
162
  >
159
163
  <div class="flex items-center justify-between mb-3">
160
164
  <span class="text-sm font-semibold">
161
- {displayMode ? "수식 블록" : "인라인 수식"}
165
+ {displayMode ? t('mathBlock') : t('mathInline')}
162
166
  </span>
163
167
  <button
164
168
  type="button"
165
169
  class="p-1 rounded-md hover:bg-muted text-muted-foreground"
166
170
  onclick={onCancel}
167
- aria-label="닫기"
171
+ aria-label={t('close')}
168
172
  >
169
173
  <X size={14} />
170
174
  </button>
@@ -189,8 +193,8 @@
189
193
  <button
190
194
  type="button"
191
195
  class="hce-math-sym"
192
- title={sym.title}
193
- aria-label={sym.title}
196
+ title={t(sym.titleKey)}
197
+ aria-label={t(sym.titleKey)}
194
198
  onclick={() => insert(sym.snippet)}
195
199
  >
196
200
  {sym.label}
@@ -215,26 +219,26 @@
215
219
  <!-- eslint-disable-next-line svelte/no-at-html-tags -->
216
220
  {@html preview.html}
217
221
  {:else}
218
- <span class="text-xs text-muted-foreground">미리보기</span>
222
+ <span class="text-xs text-muted-foreground">{t('preview')}</span>
219
223
  {/if}
220
224
  </div>
221
225
 
222
226
  <div class="hce-math-actions flex items-center justify-between gap-2 mt-4">
223
- <span class="text-[11px] text-muted-foreground">⌘/Ctrl + Enter 로 확인</span>
227
+ <span class="text-[11px] text-muted-foreground">{t('mathConfirmHint')}</span>
224
228
  <div class="flex gap-2">
225
229
  <button
226
230
  type="button"
227
231
  class="px-3.5 py-1.5 text-sm rounded-md border border-border hover:bg-muted transition-colors"
228
232
  onclick={onCancel}
229
233
  >
230
- 취소
234
+ {t('cancel')}
231
235
  </button>
232
236
  <button
233
237
  type="button"
234
238
  class="px-3.5 py-1.5 text-sm rounded-md hce-btn-primary hover:opacity-90 transition-opacity"
235
239
  onclick={handleSubmit}
236
240
  >
237
- 확인
241
+ {t('confirm')}
238
242
  </button>
239
243
  </div>
240
244
  </div>
@@ -1,9 +1,12 @@
1
+ import { type EditorTranslator } from "../i18n";
1
2
  type $$ComponentProps = {
2
3
  latex?: string;
3
4
  displayMode?: boolean;
4
5
  /** 빈 문자열로 확인하면 호출부가 노드를 지운다(편집 중일 때). */
5
6
  onConfirm: (value: string) => void;
6
7
  onCancel: () => void;
8
+ /** 에디터 UI 번역 함수. 미주입 시 ko. */
9
+ t?: EditorTranslator;
7
10
  };
8
11
  declare const MathModal: import("svelte").Component<$$ComponentProps, {}, "">;
9
12
  type MathModal = ReturnType<typeof MathModal>;
@@ -1 +1 @@
1
- {"version":3,"file":"MathModal.svelte.d.ts","sourceRoot":"","sources":["../../src/components/MathModal.svelte.ts"],"names":[],"mappings":"AAgBC,KAAK,gBAAgB,GAAI;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,yCAAyC;IACzC,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB,CAAC;AAuLJ,QAAA,MAAM,SAAS,sDAAwC,CAAC;AACxD,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAC9C,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"MathModal.svelte.d.ts","sourceRoot":"","sources":["../../src/components/MathModal.svelte.ts"],"names":[],"mappings":"AAeA,OAAO,EAA4C,KAAK,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEzF,KAAK,gBAAgB,GAAI;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,yCAAyC;IACzC,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,8BAA8B;IAC9B,CAAC,CAAC,EAAE,gBAAgB,CAAC;CACtB,CAAC;AAyLJ,QAAA,MAAM,SAAS,sDAAwC,CAAC;AACxD,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAC9C,eAAe,SAAS,CAAC"}
@@ -11,6 +11,7 @@
11
11
  * 업로드 함수도, 노드를 만드는 방법도 거기 있기 때문이다.
12
12
  */
13
13
  import { X } from "lucide-svelte";
14
+ import { defaultTranslator, type EditorTranslator } from "../i18n";
14
15
 
15
16
  let {
16
17
  title,
@@ -22,6 +23,7 @@
22
23
  onUpload,
23
24
  onLink,
24
25
  onCancel,
26
+ t = defaultTranslator,
25
27
  }: {
26
28
  title: string;
27
29
  /** 파일 선택창에서 거를 확장자. 파일 첨부처럼 아무거나 받는 곳은 비운다. */
@@ -35,6 +37,8 @@
35
37
  onUpload: (file: File) => void;
36
38
  onLink: (url: string) => void;
37
39
  onCancel: () => void;
40
+ /** 에디터 UI 번역 함수. 미주입 시 ko. */
41
+ t?: EditorTranslator;
38
42
  } = $props();
39
43
 
40
44
  let tab: "upload" | "link" = $state("upload");
@@ -82,7 +86,7 @@
82
86
  type="button"
83
87
  class="p-1 rounded-md hover:bg-muted text-muted-foreground"
84
88
  onclick={onCancel}
85
- aria-label="닫기"
89
+ aria-label={t('close')}
86
90
  >
87
91
  <X size={14} />
88
92
  </button>
@@ -101,7 +105,7 @@
101
105
  class:hce-picker-tab-on={tab === "upload"}
102
106
  onclick={() => (tab = "upload")}
103
107
  >
104
- 업로드
108
+ {t('upload')}
105
109
  </button>
106
110
  <button
107
111
  type="button"
@@ -111,7 +115,7 @@
111
115
  class:hce-picker-tab-on={tab === "link"}
112
116
  onclick={() => (tab = "link")}
113
117
  >
114
- 링크
118
+ {t('link')}
115
119
  </button>
116
120
  </div>
117
121
 
@@ -1,3 +1,4 @@
1
+ import { type EditorTranslator } from "../i18n";
1
2
  type $$ComponentProps = {
2
3
  title: string;
3
4
  /** 파일 선택창에서 거를 확장자. 파일 첨부처럼 아무거나 받는 곳은 비운다. */
@@ -11,6 +12,8 @@ type $$ComponentProps = {
11
12
  onUpload: (file: File) => void;
12
13
  onLink: (url: string) => void;
13
14
  onCancel: () => void;
15
+ /** 에디터 UI 번역 함수. 미주입 시 ko. */
16
+ t?: EditorTranslator;
14
17
  };
15
18
  declare const MediaPickerModal: import("svelte").Component<$$ComponentProps, {}, "">;
16
19
  type MediaPickerModal = ReturnType<typeof MediaPickerModal>;
@@ -1 +1 @@
1
- {"version":3,"file":"MediaPickerModal.svelte.d.ts","sourceRoot":"","sources":["../../src/components/MediaPickerModal.svelte.ts"],"names":[],"mappings":"AAgBC,KAAK,gBAAgB,GAAI;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iCAAiC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,QAAQ,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC/B,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB,CAAC;AAkGJ,QAAA,MAAM,gBAAgB,sDAAwC,CAAC;AAC/D,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC5D,eAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"MediaPickerModal.svelte.d.ts","sourceRoot":"","sources":["../../src/components/MediaPickerModal.svelte.ts"],"names":[],"mappings":"AAeA,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAElE,KAAK,gBAAgB,GAAI;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iCAAiC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,QAAQ,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC/B,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,8BAA8B;IAC9B,CAAC,CAAC,EAAE,gBAAgB,CAAC;CACtB,CAAC;AAoGJ,QAAA,MAAM,gBAAgB,sDAAwC,CAAC;AAC/D,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC5D,eAAe,gBAAgB,CAAC"}