@teriusu/rich-editor 0.10.8 → 0.11.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 (147) hide show
  1. package/dist/components/BubbleToolbar.svelte +40 -36
  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
@@ -31,40 +31,48 @@
31
31
  import { insertTableSized } from "../utils/table";
32
32
  import type { SlashMenuItem, ToolbarFeature, PromptHandler } from "../types";
33
33
  import type { Component } from "svelte";
34
+ import { defaultTranslator, type EditorMessageKey, type EditorTranslator } from "../i18n";
34
35
 
35
36
  const SI = 14;
36
37
 
37
- /** 각 feature가 속하는 섹션 라벨 */
38
- const SECTION_MAP: Record<string, string> = {
39
- "code-block": "자주 쓰는",
40
- math: "자주 쓰는",
41
- file: "미디어",
42
- pdf: "미디어",
43
- paragraph: "기본",
44
- h1: "기본",
45
- h2: "기본",
46
- h3: "기본",
47
- mbus: "미디어",
48
- video: "미디어",
49
- card: "블록",
50
- "bullet-list": "리스트",
51
- "ordered-list": "리스트",
52
- checklist: "리스트",
53
- toggle: "리스트",
54
- blockquote: "블록",
55
- "horizontal-rule": "블록",
56
- table: "레이아웃",
57
- "columns-2": "레이아웃",
58
- "columns-3": "레이아웃",
59
- tabs: "레이아웃",
60
- link: "미디어",
61
- image: "미디어",
38
+ /** 각 feature가 속하는 섹션(메시지 키 — 라벨은 렌더 시 `t()` 로 푼다) */
39
+ const SECTION_MAP: Record<string, EditorMessageKey> = {
40
+ "code-block": "sectionFrequent",
41
+ math: "sectionFrequent",
42
+ file: "sectionMedia",
43
+ pdf: "sectionMedia",
44
+ paragraph: "sectionBasic",
45
+ h1: "sectionBasic",
46
+ h2: "sectionBasic",
47
+ h3: "sectionBasic",
48
+ mbus: "sectionMedia",
49
+ video: "sectionMedia",
50
+ card: "sectionBlock",
51
+ "bullet-list": "sectionList",
52
+ "ordered-list": "sectionList",
53
+ checklist: "sectionList",
54
+ toggle: "sectionList",
55
+ blockquote: "sectionBlock",
56
+ "horizontal-rule": "sectionBlock",
57
+ table: "sectionLayout",
58
+ "columns-2": "sectionLayout",
59
+ "columns-3": "sectionLayout",
60
+ tabs: "sectionLayout",
61
+ link: "sectionMedia",
62
+ image: "sectionMedia",
62
63
  };
63
- const SECTION_ORDER = ["자주 쓰는", "기본", "리스트", "블록", "레이아웃", "미디어"];
64
+ const SECTION_ORDER: EditorMessageKey[] = [
65
+ "sectionFrequent",
66
+ "sectionBasic",
67
+ "sectionList",
68
+ "sectionBlock",
69
+ "sectionLayout",
70
+ "sectionMedia",
71
+ ];
64
72
 
65
73
  const SLASH_MENU_ITEMS_DATA: {
66
74
  feature: ToolbarFeature;
67
- label: string;
75
+ labelKey: EditorMessageKey;
68
76
  keywords: string;
69
77
  icon: Component<{ size?: number }>;
70
78
  /** 항목 오른쪽에 작게 보여 줄 입력 규칙. 없으면 안 그린다. */
@@ -74,19 +82,21 @@
74
82
  * ⚠️ 토글 제목처럼 **같은 feature 인데 다른 자리**에 놓아야 하는 것 때문에 필요하다
75
83
  * (셋 다 `toggle` 이지만 토글은 리스트, 토글 제목은 제목 옆이 맞다).
76
84
  */
77
- section?: string;
78
- command: (editor: Editor) => void;
85
+ /** `labelKey` 의 `{…}` 자리 값 (토글 제목 1~3 처럼 같은 키를 나눠 쓸 때). */
86
+ labelParams?: Record<string, string | number>;
87
+ section?: EditorMessageKey;
88
+ command: (editor: Editor, t: EditorTranslator) => void;
79
89
  }[] = [
80
90
  {
81
91
  feature: "paragraph",
82
- label: "본문",
92
+ labelKey: "paragraph",
83
93
  keywords: "paragraph text 본문 단락",
84
94
  icon: Type,
85
95
  command: (editor) => editor.chain().focus().setParagraph().run(),
86
96
  },
87
97
  {
88
98
  feature: "h1",
89
- label: "제목 1",
99
+ labelKey: "heading1",
90
100
  keywords: "heading h1 제목",
91
101
  icon: Heading1,
92
102
  shortcut: "# ",
@@ -95,7 +105,7 @@
95
105
  },
96
106
  {
97
107
  feature: "h2",
98
- label: "제목 2",
108
+ labelKey: "heading2",
99
109
  keywords: "heading h2 제목",
100
110
  icon: Heading2,
101
111
  shortcut: "## ",
@@ -104,7 +114,7 @@
104
114
  },
105
115
  {
106
116
  feature: "h3",
107
- label: "제목 3",
117
+ labelKey: "heading3",
108
118
  keywords: "heading h3 제목",
109
119
  icon: Heading3,
110
120
  shortcut: "### ",
@@ -113,7 +123,7 @@
113
123
  },
114
124
  {
115
125
  feature: "bullet-list",
116
- label: "글머리 목록",
126
+ labelKey: "bulletList",
117
127
  keywords: "bullet list 목록 리스트",
118
128
  icon: List,
119
129
  shortcut: "- ",
@@ -121,7 +131,7 @@
121
131
  },
122
132
  {
123
133
  feature: "ordered-list",
124
- label: "번호 목록",
134
+ labelKey: "orderedList",
125
135
  keywords: "ordered number list 번호 리스트",
126
136
  icon: ListOrdered,
127
137
  shortcut: "1. ",
@@ -129,7 +139,7 @@
129
139
  },
130
140
  {
131
141
  feature: "checklist",
132
- label: "체크리스트",
142
+ labelKey: "taskList",
133
143
  keywords: "checklist task todo 체크 할일",
134
144
  icon: CheckSquare,
135
145
  shortcut: "[] ",
@@ -137,7 +147,7 @@
137
147
  },
138
148
  {
139
149
  feature: "blockquote",
140
- label: "인용문",
150
+ labelKey: "blockquote",
141
151
  keywords: "quote blockquote 인용",
142
152
  icon: Quote,
143
153
  shortcut: "\" ",
@@ -145,7 +155,7 @@
145
155
  },
146
156
  {
147
157
  feature: "horizontal-rule",
148
- label: "구분선",
158
+ labelKey: "divider",
149
159
  keywords: "divider hr horizontal rule 구분",
150
160
  icon: Minus,
151
161
  shortcut: "---",
@@ -153,7 +163,7 @@
153
163
  },
154
164
  {
155
165
  feature: "code-block",
156
- label: "코드",
166
+ labelKey: "code",
157
167
  keywords: "code 코드 블록 cpp c++ python 파이썬",
158
168
  icon: Code2,
159
169
  shortcut: "```",
@@ -162,7 +172,7 @@
162
172
  },
163
173
  {
164
174
  feature: "math",
165
- label: "수식",
175
+ labelKey: "math",
166
176
  keywords: "math latex tex 수식 공식 수학 katex 시그마 분수",
167
177
  icon: Sigma,
168
178
  shortcut: "$$",
@@ -172,7 +182,7 @@
172
182
  },
173
183
  {
174
184
  feature: "toggle",
175
- label: "토글",
185
+ labelKey: "toggle",
176
186
  keywords: "toggle details 접기 펼치기 토글",
177
187
  icon: ChevronRight,
178
188
  shortcut: "> ",
@@ -188,8 +198,9 @@
188
198
  */
189
199
  {
190
200
  feature: "toggle",
191
- label: "토글 제목 1",
192
- section: "기본",
201
+ labelKey: "toggleHeading",
202
+ labelParams: { level: 1 },
203
+ section: "sectionBasic",
193
204
  keywords: "toggle heading 접기 제목 토글제목 h1",
194
205
  icon: ToggleHeading1,
195
206
  shortcut: "# > ",
@@ -197,8 +208,9 @@
197
208
  },
198
209
  {
199
210
  feature: "toggle",
200
- label: "토글 제목 2",
201
- section: "기본",
211
+ labelKey: "toggleHeading",
212
+ labelParams: { level: 2 },
213
+ section: "sectionBasic",
202
214
  keywords: "toggle heading 접기 제목 토글제목 h2",
203
215
  icon: ToggleHeading2,
204
216
  shortcut: "## > ",
@@ -206,8 +218,9 @@
206
218
  },
207
219
  {
208
220
  feature: "toggle",
209
- label: "토글 제목 3",
210
- section: "기본",
221
+ labelKey: "toggleHeading",
222
+ labelParams: { level: 3 },
223
+ section: "sectionBasic",
211
224
  keywords: "toggle heading 접기 제목 토글제목 h3",
212
225
  icon: ToggleHeading3,
213
226
  shortcut: "### > ",
@@ -215,7 +228,7 @@
215
228
  },
216
229
  {
217
230
  feature: "table",
218
- label: "표",
231
+ labelKey: "table",
219
232
  keywords: "table 표 테이블",
220
233
  icon: TableIcon,
221
234
  command: (editor) =>
@@ -223,59 +236,59 @@
223
236
  },
224
237
  {
225
238
  feature: "columns-2",
226
- label: "2단 컬럼",
239
+ labelKey: "columns2",
227
240
  keywords: "column 컬럼 2단 분할",
228
241
  icon: Columns2,
229
242
  command: (editor) => editor.chain().focus().setColumns(2).run(),
230
243
  },
231
244
  {
232
245
  feature: "columns-3",
233
- label: "3단 컬럼",
246
+ labelKey: "columns3",
234
247
  keywords: "column 컬럼 3단 분할",
235
248
  icon: Columns3,
236
249
  command: (editor) => editor.chain().focus().setColumns(3).run(),
237
250
  },
238
251
  {
239
252
  feature: "tabs",
240
- label: "탭",
253
+ labelKey: "tabs",
241
254
  keywords: "tab tabs 탭 탭블록 전환 분할",
242
255
  icon: PanelTop,
243
256
  command: (editor) => editor.chain().focus().setTabs(3).run(),
244
257
  },
245
258
  {
246
259
  feature: "image",
247
- label: "이미지",
260
+ labelKey: "image",
248
261
  keywords: "image 이미지 사진 img",
249
262
  icon: ImageIcon,
250
- command: (editor) => {
251
- const url = window.prompt("이미지 URL을 입력하세요");
263
+ command: (editor, t) => {
264
+ const url = window.prompt(t("promptImageUrl"));
252
265
  if (url) editor.chain().focus().setImage({ src: url }).run();
253
266
  },
254
267
  },
255
268
  {
256
269
  feature: "video",
257
- label: "영상",
270
+ labelKey: "video",
258
271
  keywords: "video 영상 유튜브 youtube vimeo 동영상",
259
272
  icon: Youtube,
260
- command: (editor) => {
273
+ command: (editor, t) => {
261
274
  // 붙여넣은 주소는 `setVideoEmbed` 가 임베드용으로 바꿔 준다.
262
- const url = window.prompt("영상 URL을 입력하세요 (유튜브·Vimeo 등)");
275
+ const url = window.prompt(t("promptVideoUrl"));
263
276
  if (url) editor.chain().focus().setVideoEmbed({ src: url }).run();
264
277
  },
265
278
  },
266
279
  {
267
280
  feature: "mbus",
268
- label: "미디버스 영상",
281
+ labelKey: "mbusVideo",
269
282
  keywords: "mbus video 미디버스 영상",
270
283
  icon: Tv,
271
- command: (editor) => {
272
- const url = window.prompt("미디버스 영상 URL을 입력하세요");
284
+ command: (editor, t) => {
285
+ const url = window.prompt(t("promptMbusUrl"));
273
286
  if (url) editor.chain().focus().setMbusVideo({ src: url }).run();
274
287
  },
275
288
  },
276
289
  {
277
290
  feature: "card",
278
- label: "카드",
291
+ labelKey: "card",
279
292
  keywords: "card 카드 상자 박스 강조 배경",
280
293
  icon: SquareDashed,
281
294
  command: (editor) => {
@@ -284,11 +297,11 @@
284
297
  },
285
298
  {
286
299
  feature: "link",
287
- label: "링크",
300
+ labelKey: "link",
288
301
  keywords: "link url 링크 하이퍼",
289
302
  icon: LinkIcon,
290
- command: (editor) => {
291
- const url = window.prompt("링크 URL을 입력하세요");
303
+ command: (editor, t) => {
304
+ const url = window.prompt(t("promptLinkUrl"));
292
305
  if (url)
293
306
  editor
294
307
  .chain()
@@ -311,6 +324,7 @@
311
324
  onPromptLink,
312
325
  onPromptMbus,
313
326
  onPromptVideo,
327
+ t = defaultTranslator,
314
328
  }: {
315
329
  editor: Editor;
316
330
  features: Set<ToolbarFeature>;
@@ -330,6 +344,8 @@
330
344
  * 기본 대화상자라 화면이 멈추고 앱과 모양이 따로 논다(사용자 지적).
331
345
  */
332
346
  onPromptVideo?: PromptHandler;
347
+ /** 에디터 UI 번역 함수. 미주입 시 ko. */
348
+ t?: EditorTranslator;
333
349
  } = $props();
334
350
 
335
351
  async function runItem(item: (typeof SLASH_MENU_ITEMS_DATA)[number]) {
@@ -358,7 +374,7 @@
358
374
  if (url) editor.chain().focus().setMbusVideo({ src: url }).run();
359
375
  return;
360
376
  }
361
- item.command(editor);
377
+ item.command(editor, t);
362
378
  }
363
379
 
364
380
  let selectedIndex = $state(0);
@@ -370,7 +386,7 @@
370
386
  if (onFileUpload) {
371
387
  items.push({
372
388
  feature: "file" as ToolbarFeature,
373
- label: "파일 첨부",
389
+ labelKey: "fileAttach",
374
390
  keywords: "file attach 파일 첨부",
375
391
  icon: Paperclip,
376
392
  command: () => onFileUpload!(),
@@ -379,7 +395,7 @@
379
395
  if (onPdfUpload) {
380
396
  items.push({
381
397
  feature: "pdf" as ToolbarFeature,
382
- label: "PDF 파일",
398
+ labelKey: "pdfFile",
383
399
  keywords: "pdf 파일 문서",
384
400
  icon: FileText,
385
401
  command: () => onPdfUpload!(),
@@ -393,7 +409,7 @@
393
409
  return q
394
410
  ? allItems.filter(
395
411
  (item) =>
396
- item.label.toLowerCase().includes(q) ||
412
+ t(item.labelKey, item.labelParams).toLowerCase().includes(q) ||
397
413
  item.keywords.toLowerCase().includes(q),
398
414
  )
399
415
  : allItems;
@@ -458,7 +474,7 @@
458
474
  bind:this={menuEl}
459
475
  class="slash-menu z-50 bg-popover border border-border rounded-xl shadow-xl p-2"
460
476
  >
461
- <p class="text-xs text-muted-foreground px-2 py-1">결과 없음</p>
477
+ <p class="text-xs text-muted-foreground px-2 py-1">{t('noResult')}</p>
462
478
  </div>
463
479
  {:else}
464
480
  <div
@@ -467,10 +483,10 @@
467
483
  >
468
484
  {#each SECTION_ORDER as section}
469
485
  {@const sectionItems = filtered.filter(
470
- (it) => (it.section ?? SECTION_MAP[it.feature] ?? '기본') === section,
486
+ (it) => (it.section ?? SECTION_MAP[it.feature] ?? 'sectionBasic') === section,
471
487
  )}
472
488
  {#if sectionItems.length > 0}
473
- <p class="slash-section">{section}</p>
489
+ <p class="slash-section">{t(section)}</p>
474
490
  {#each sectionItems as item}
475
491
  {@const i = filtered.indexOf(item)}
476
492
  <button
@@ -492,7 +508,7 @@
492
508
  <span class="slash-icon">
493
509
  <item.icon size={SI} />
494
510
  </span>
495
- <span class="slash-label">{item.label}</span>
511
+ <span class="slash-label">{t(item.labelKey, item.labelParams)}</span>
496
512
  {#if item.shortcut}
497
513
  <!--
498
514
  쳐서 만드는 법을 항목 옆에 적어 둔다(사용자 요청). 메뉴를 한 번 쓰고 나면
@@ -1,6 +1,7 @@
1
1
  import type { Editor } from "@tiptap/core";
2
2
  import type { ToolbarFeature, PromptHandler } from "../types";
3
3
  import type { Component } from "svelte";
4
+ import { type EditorTranslator } from "../i18n";
4
5
  type $$ComponentProps = {
5
6
  editor: Editor;
6
7
  features: Set<ToolbarFeature>;
@@ -20,6 +21,8 @@ type $$ComponentProps = {
20
21
  * 기본 대화상자라 화면이 멈추고 앱과 모양이 따로 논다(사용자 지적).
21
22
  */
22
23
  onPromptVideo?: PromptHandler;
24
+ /** 에디터 UI 번역 함수. 미주입 시 ko. */
25
+ t?: EditorTranslator;
23
26
  };
24
27
  declare const SlashCommandMenu: Component<$$ComponentProps, {}, "">;
25
28
  type SlashCommandMenu = ReturnType<typeof SlashCommandMenu>;
@@ -1 +1 @@
1
- {"version":3,"file":"SlashCommandMenu.svelte.d.ts","sourceRoot":"","sources":["../../src/components/SlashCommandMenu.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AA8B3C,OAAO,KAAK,EAAiB,cAAc,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC7E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAEvC,KAAK,gBAAgB,GAAI;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,GAAG,CAAC,cAAc,CAAC,CAAC;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B;;;OAGG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B,CAAC;AAwcJ,QAAA,MAAM,gBAAgB,qCAAwC,CAAC;AAC/D,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC5D,eAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"SlashCommandMenu.svelte.d.ts","sourceRoot":"","sources":["../../src/components/SlashCommandMenu.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AA8B3C,OAAO,KAAK,EAAiB,cAAc,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC7E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAA4C,KAAK,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEzF,KAAK,gBAAgB,GAAI;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,GAAG,CAAC,cAAc,CAAC,CAAC;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B;;;OAGG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,8BAA8B;IAC9B,CAAC,CAAC,EAAE,gBAAgB,CAAC;CACtB,CAAC;AAsdJ,QAAA,MAAM,gBAAgB,qCAAwC,CAAC;AAC/D,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC5D,eAAe,gBAAgB,CAAC"}
@@ -19,26 +19,34 @@
19
19
  import { onMount } from "svelte";
20
20
  import { cn } from "../utils/cn";
21
21
  import { splitCellPreservingHeaders } from "../utils/splitCell";
22
+ import { defaultTranslator, type EditorMessageKey, type EditorTranslator } from "../i18n";
22
23
 
23
- const PRESET_COLORS = [
24
- { label: "없음", value: "" },
25
- { label: "밝은 회색", value: "#f1f5f9" },
26
- { label: "밝은 파랑", value: "#dbeafe" },
27
- { label: "밝은 초록", value: "#dcfce7" },
28
- { label: "밝은 노랑", value: "#fef9c3" },
29
- { label: "밝은 주황", value: "#ffedd5" },
30
- { label: "밝은 빨강", value: "#fee2e2" },
31
- { label: "밝은 보라", value: "#ede9fe" },
32
- { label: "밝은 분홍", value: "#fce7f3" },
24
+ const PRESET_COLORS: { labelKey: EditorMessageKey; value: string }[] = [
25
+ { labelKey: "bgNone", value: "" },
26
+ { labelKey: "bgGray", value: "#f1f5f9" },
27
+ { labelKey: "bgBlue", value: "#dbeafe" },
28
+ { labelKey: "bgGreen", value: "#dcfce7" },
29
+ { labelKey: "bgYellow", value: "#fef9c3" },
30
+ { labelKey: "bgOrange", value: "#ffedd5" },
31
+ { labelKey: "bgRed", value: "#fee2e2" },
32
+ { labelKey: "bgPurple", value: "#ede9fe" },
33
+ { labelKey: "bgPink", value: "#fce7f3" },
33
34
  ];
34
35
 
35
- const LINE_HEIGHTS = [
36
- { label: "좁게", value: "0.8" },
37
- { label: "보통", value: "1.0" },
38
- { label: "넓게", value: "1.4" },
36
+ const LINE_HEIGHTS: { labelKey: EditorMessageKey; value: string }[] = [
37
+ { labelKey: "spacingNarrow", value: "0.8" },
38
+ { labelKey: "spacingNormal", value: "1.0" },
39
+ { labelKey: "spacingWide", value: "1.4" },
39
40
  ];
40
41
 
41
- let { editor }: { editor: Editor } = $props();
42
+ let {
43
+ editor,
44
+ t = defaultTranslator,
45
+ }: {
46
+ editor: Editor;
47
+ /** 에디터 UI 번역 함수. 미주입 시 ko. */
48
+ t?: EditorTranslator;
49
+ } = $props();
42
50
 
43
51
  let visible = $state(false);
44
52
  let pos = $state({ top: 0, left: 0, width: 0 });
@@ -143,7 +151,7 @@
143
151
  onmousedown={(e) => e.preventDefault()}
144
152
  role="toolbar"
145
153
  tabindex="-1"
146
- aria-label="표 편집"
154
+ aria-label={t('tableEdit')}
147
155
  style="top: {pos.top}px; left: {pos.left}px; width: {pos.width}px"
148
156
  >
149
157
  <div
@@ -163,7 +171,7 @@
163
171
  >
164
172
  <ArrowUpToLine size={iconSize} />
165
173
  </button>
166
- <span class="hce-table-btn-tooltip">행 위에 추가</span>
174
+ <span class="hce-table-btn-tooltip">{t('rowAddAbove')}</span>
167
175
  </div>
168
176
 
169
177
  <div class="hce-table-btn-wrap">
@@ -179,7 +187,7 @@
179
187
  >
180
188
  <ArrowDownToLine size={iconSize} />
181
189
  </button>
182
- <span class="hce-table-btn-tooltip">행 아래에 추가</span>
190
+ <span class="hce-table-btn-tooltip">{t('rowAddBelow')}</span>
183
191
  </div>
184
192
 
185
193
  <div class="hce-table-btn-wrap">
@@ -196,7 +204,7 @@
196
204
  >
197
205
  <ArrowLeftToLine size={iconSize} />
198
206
  </button>
199
- <span class="hce-table-btn-tooltip">열 왼쪽에 추가</span>
207
+ <span class="hce-table-btn-tooltip">{t('colAddLeft')}</span>
200
208
  </div>
201
209
 
202
210
  <div class="hce-table-btn-wrap">
@@ -213,7 +221,7 @@
213
221
  >
214
222
  <ArrowRightToLine size={iconSize} />
215
223
  </button>
216
- <span class="hce-table-btn-tooltip">열 오른쪽에 추가</span>
224
+ <span class="hce-table-btn-tooltip">{t('colAddRight')}</span>
217
225
  </div>
218
226
 
219
227
  <div class="w-px h-5 bg-border mx-0.5"></div>
@@ -232,7 +240,7 @@
232
240
  >
233
241
  <PanelTop size={iconSize} />
234
242
  </button>
235
- <span class="hce-table-btn-tooltip">헤더 행 토글</span>
243
+ <span class="hce-table-btn-tooltip">{t('headerRowToggle')}</span>
236
244
  </div>
237
245
 
238
246
  <div class="hce-table-btn-wrap">
@@ -249,7 +257,7 @@
249
257
  >
250
258
  <PanelLeft size={iconSize} />
251
259
  </button>
252
- <span class="hce-table-btn-tooltip">헤더 열 토글</span>
260
+ <span class="hce-table-btn-tooltip">{t('headerColToggle')}</span>
253
261
  </div>
254
262
 
255
263
  <div class="hce-table-btn-wrap">
@@ -265,7 +273,7 @@
265
273
  >
266
274
  <Combine size={iconSize} />
267
275
  </button>
268
- <span class="hce-table-btn-tooltip">셀 병합</span>
276
+ <span class="hce-table-btn-tooltip">{t('cellMerge')}</span>
269
277
  </div>
270
278
 
271
279
  <div class="hce-table-btn-wrap">
@@ -281,7 +289,7 @@
281
289
  >
282
290
  <SplitSquareHorizontal size={iconSize} />
283
291
  </button>
284
- <span class="hce-table-btn-tooltip">셀 분할</span>
292
+ <span class="hce-table-btn-tooltip">{t('cellSplit')}</span>
285
293
  </div>
286
294
 
287
295
  <div class="w-px h-5 bg-border mx-0.5"></div>
@@ -299,7 +307,7 @@
299
307
  >
300
308
  <UnfoldVertical size={iconSize} />
301
309
  </button>
302
- <span class="hce-table-btn-tooltip">줄 간격</span>
310
+ <span class="hce-table-btn-tooltip">{t('lineSpacing')}</span>
303
311
  </div>
304
312
  {#if showLineHeight}
305
313
  <div
@@ -337,7 +345,7 @@
337
345
  showLineHeight = false;
338
346
  }}
339
347
  >
340
- {lh.label}
348
+ {t(lh.labelKey)}
341
349
  </button>
342
350
  {/each}
343
351
  </div>
@@ -387,7 +395,7 @@
387
395
  >
388
396
  <EqualApproximately size={iconSize} />
389
397
  </button>
390
- <span class="hce-table-btn-tooltip">너비 동일</span>
398
+ <span class="hce-table-btn-tooltip">{t('widthEqual')}</span>
391
399
  </div>
392
400
 
393
401
  <!-- Background color -->
@@ -403,7 +411,7 @@
403
411
  >
404
412
  <Paintbrush size={iconSize} />
405
413
  </button>
406
- <span class="hce-table-btn-tooltip">셀 배경색</span>
414
+ <span class="hce-table-btn-tooltip">{t('cellBackground')}</span>
407
415
  </div>
408
416
  {#if showColors}
409
417
  <div
@@ -413,13 +421,13 @@
413
421
  <p
414
422
  class="text-xs font-medium text-muted-foreground mb-1.5 px-1"
415
423
  >
416
- 배경색
424
+ {t('background')}
417
425
  </p>
418
426
  <div class="grid grid-cols-3 gap-1">
419
427
  {#each PRESET_COLORS as c}
420
428
  <button
421
429
  type="button"
422
- title={c.label}
430
+ title={t(c.labelKey)}
423
431
  class="w-full h-7 rounded-md border border-border transition-transform hover:scale-110"
424
432
  style="background: {c.value ||
425
433
  'transparent'}; {!c.value
@@ -456,7 +464,7 @@
456
464
  >
457
465
  <RowsIcon size={iconSize} />
458
466
  </button>
459
- <span class="hce-table-btn-tooltip">행 삭제</span>
467
+ <span class="hce-table-btn-tooltip">{t('rowDelete')}</span>
460
468
  </div>
461
469
 
462
470
  <div class="hce-table-btn-wrap">
@@ -472,7 +480,7 @@
472
480
  >
473
481
  <ColumnsIcon size={iconSize} />
474
482
  </button>
475
- <span class="hce-table-btn-tooltip">열 삭제</span>
483
+ <span class="hce-table-btn-tooltip">{t('colDelete')}</span>
476
484
  </div>
477
485
 
478
486
  <div class="hce-table-btn-wrap">
@@ -488,7 +496,7 @@
488
496
  >
489
497
  <Trash2 size={iconSize} />
490
498
  </button>
491
- <span class="hce-table-btn-tooltip">표 삭제</span>
499
+ <span class="hce-table-btn-tooltip">{t('tableDelete')}</span>
492
500
  </div>
493
501
  </div>
494
502
  </div>
@@ -1,6 +1,9 @@
1
1
  import type { Editor } from "@tiptap/core";
2
+ import { type EditorTranslator } from "../i18n";
2
3
  type $$ComponentProps = {
3
4
  editor: Editor;
5
+ /** 에디터 UI 번역 함수. 미주입 시 ko. */
6
+ t?: EditorTranslator;
4
7
  };
5
8
  declare const TableBubbleMenu: import("svelte").Component<$$ComponentProps, {}, "">;
6
9
  type TableBubbleMenu = ReturnType<typeof TableBubbleMenu>;
@@ -1 +1 @@
1
- {"version":3,"file":"TableBubbleMenu.svelte.d.ts","sourceRoot":"","sources":["../../src/components/TableBubbleMenu.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAqB1C,KAAK,gBAAgB,GAAI;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAqY7C,QAAA,MAAM,eAAe,sDAAwC,CAAC;AAC9D,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAC1D,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"TableBubbleMenu.svelte.d.ts","sourceRoot":"","sources":["../../src/components/TableBubbleMenu.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAoB3C,OAAO,EAA4C,KAAK,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEzF,KAAK,gBAAgB,GAAI;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,8BAA8B;IAC9B,CAAC,CAAC,EAAE,gBAAgB,CAAC;CACtB,CAAC;AAyYJ,QAAA,MAAM,eAAe,sDAAwC,CAAC;AAC9D,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAC1D,eAAe,eAAe,CAAC"}