@teriusu/rich-editor 0.10.2 → 0.10.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -88,6 +88,69 @@
88
88
  };
89
89
  },
90
90
  });
91
+
92
+ /**
93
+ * 편집 크롬(툴바 2 · 메뉴 2 · 모달 3)은 **`editable` 일 때만 그려지는데**
94
+ * 정적 import 면 읽기 전용 페이지도 통째로 받는다.
95
+ *
96
+ * 실측(정올 prod 빌드, `apps/jungol/.svelte-kit/output/client`): 이 일곱만 쓰는
97
+ * lucide 아이콘 53 개가 **270KB raw / 75KB gzip** 짜리 청크 하나로 앉아 있고,
98
+ * rich-editor 가 끌고 오는 그래프 전체는 2.06MB raw / 599KB gzip 이다. 그리고
99
+ * 그 그래프를 끌고 오는 라우트가 **176 개 중 91 개** — 문제 지문·글·댓글처럼
100
+ * 툴바가 평생 뜨지 않는 화면이 대부분이다.
101
+ *
102
+ * 그래서 **필요해질 때 한 번만** 받아 모든 인스턴스가 나눠 쓴다.
103
+ *
104
+ * ⚠️ **인스턴스마다 `import()` 를 걸지 않는다.** 모듈 자체는 캐시되니 손해가 없어
105
+ * 보이지만 `.then()` 이 인스턴스 수만큼 생긴다. 그 콜백들이 제각각 풀리면 툴바가
106
+ * 한 번에 서지 못하고 줄줄이 늘어선다 — 한 화면에 에디터가 20~27 개 서는 곳
107
+ * (정올 기출 퀴즈)에서 눈에 띈다. 소비 앱 래퍼(`ui/tiptap/TipTap.svelte`)가 같은
108
+ * 이유로 이미 모듈 스코프 공유 import 를 쓰고 있고, 그 주석에 실측이 남아 있다.
109
+ *
110
+ * ⚠️ 배럴(`index.ts`)에서 이 일곱을 **re-export 하면 안 된다.** 여기서 지연시켜도
111
+ * 배럴이 정적으로 참조하면 그래프에 그대로 남아 이 지연이 아무 효과가 없다.
112
+ * 필요하면 `@teriusu/rich-editor/toolbars` 서브패스로 가져간다.
113
+ */
114
+ /*
115
+ * ⚠️ 타입은 `typeof import(...)` 로 **원본 컴포넌트에서 그대로 가져온다.**
116
+ * `Component<any>` 로 뭉개면 마크업의 콜백 인자(`onConfirm={(url) => …}`)가
117
+ * `implicit any` 로 떨어져 타입 검사에서 걸린다. 타입 위치의 `import()` 는
118
+ * 컴파일 뒤 사라지므로 **번들에는 영향이 없다** — 지연 로드는 그대로다.
119
+ */
120
+ type EditorChrome = {
121
+ FixedToolbar: typeof import("./FixedToolbar.svelte").default;
122
+ BubbleToolbar: typeof import("./BubbleToolbar.svelte").default;
123
+ TableBubbleMenu: typeof import("./TableBubbleMenu.svelte").default;
124
+ SlashCommandMenu: typeof import("./SlashCommandMenu.svelte").default;
125
+ MediaPickerModal: typeof import("./MediaPickerModal.svelte").default;
126
+ InputModal: typeof import("./InputModal.svelte").default;
127
+ MathModal: typeof import("./MathModal.svelte").default;
128
+ };
129
+ let sharedChrome = $state<EditorChrome | null>(null);
130
+ let chromePending = false;
131
+ function loadEditorChrome() {
132
+ if (sharedChrome || chromePending) return;
133
+ chromePending = true;
134
+ Promise.all([
135
+ import("./FixedToolbar.svelte"),
136
+ import("./BubbleToolbar.svelte"),
137
+ import("./TableBubbleMenu.svelte"),
138
+ import("./SlashCommandMenu.svelte"),
139
+ import("./MediaPickerModal.svelte"),
140
+ import("./InputModal.svelte"),
141
+ import("./MathModal.svelte"),
142
+ ]).then(([fixed, bubble, table, slash, media, input, math]) => {
143
+ sharedChrome = {
144
+ FixedToolbar: fixed.default,
145
+ BubbleToolbar: bubble.default,
146
+ TableBubbleMenu: table.default,
147
+ SlashCommandMenu: slash.default,
148
+ MediaPickerModal: media.default,
149
+ InputModal: input.default,
150
+ MathModal: math.default,
151
+ };
152
+ });
153
+ }
91
154
  </script>
92
155
 
93
156
  <script lang="ts">
@@ -131,13 +194,6 @@
131
194
  import { VideoEmbed } from "../extensions/VideoEmbed";
132
195
  import { CardBlock } from "../extensions/CardBlock";
133
196
  import { MathInline, MathDisplay, type MathPrompt } from "../extensions/Math";
134
- import FixedToolbar from "./FixedToolbar.svelte";
135
- import BubbleToolbar from "./BubbleToolbar.svelte";
136
- import SlashCommandMenu from "./SlashCommandMenu.svelte";
137
- import TableBubbleMenu from "./TableBubbleMenu.svelte";
138
- import MathModal from "./MathModal.svelte";
139
- import MediaPickerModal from "./MediaPickerModal.svelte";
140
- import InputModal from "./InputModal.svelte";
141
197
  import type { UploadHandler, PromptHandler, ToolbarMode, ToolbarFeature } from "../types";
142
198
  import { resolveFeatures } from "../types";
143
199
  import type { FileResolver } from "../extensions/FileAttachment";
@@ -189,6 +245,25 @@
189
245
  let editorElement: HTMLDivElement | undefined = $state();
190
246
  let editor: Editor | undefined = $state();
191
247
 
248
+ /*
249
+ * 편집 크롬을 **필요해질 때** 받아 온다(사유·실측은 모듈 블록의 `loadEditorChrome` 주석).
250
+ * `$effect` 라 SSR 에서는 돌지 않는다 — 크롬은 어차피 `editor` 가 선 뒤에만 그려지고
251
+ * `editor` 는 `onMount` 에서 만들어지므로 서버에서는 그릴 일이 없다.
252
+ *
253
+ * 아래 일곱은 **원래 이름 그대로** 두어 마크업이 그대로 읽히게 한다. 도착 전에는
254
+ * `undefined` 이고, 마크업이 `sharedChrome` 유무로 이미 갈라져 있어 그때는 그리지 않는다.
255
+ */
256
+ $effect(() => {
257
+ if (editable) loadEditorChrome();
258
+ });
259
+ const FixedToolbar = $derived(sharedChrome?.FixedToolbar);
260
+ const BubbleToolbar = $derived(sharedChrome?.BubbleToolbar);
261
+ const TableBubbleMenu = $derived(sharedChrome?.TableBubbleMenu);
262
+ const SlashCommandMenu = $derived(sharedChrome?.SlashCommandMenu);
263
+ const MediaPickerModal = $derived(sharedChrome?.MediaPickerModal);
264
+ const InputModal = $derived(sharedChrome?.InputModal);
265
+ const MathModal = $derived(sharedChrome?.MathModal);
266
+
192
267
  /*
193
268
  * 글자수는 `editor.storage` 에서 읽는데 그건 `$state` 가 아니라, 그냥 부르면 첫 값에
194
269
  * 굳어 **타이핑해도 숫자가 안 바뀐다**(사용자 지적). 트랜잭션마다 카운터를 올리고
@@ -803,7 +878,7 @@
803
878
  ondragover={(e) => e.preventDefault()}
804
879
  ondrop={(e) => { if (!onUploadFile) e.preventDefault(); }}
805
880
  >
806
- {#if editor && editable && features.has('fixed-toolbar')}
881
+ {#if editor && editable && FixedToolbar && features.has('fixed-toolbar')}
807
882
  <FixedToolbar
808
883
  {editor}
809
884
  {features}
@@ -825,11 +900,11 @@
825
900
  <div class="hce-editor-body" bind:this={editorElement}></div>
826
901
 
827
902
  {#if editor && editable}
828
- {#if features.has('bubble-toolbar')}
903
+ {#if BubbleToolbar && features.has('bubble-toolbar')}
829
904
  <BubbleToolbar {editor} {features} {onPromptLink} />
830
905
  {/if}
831
906
 
832
- {#if features.has('table-menu')}
907
+ {#if TableBubbleMenu && features.has('table-menu')}
833
908
  <TableBubbleMenu {editor} />
834
909
  {/if}
835
910
 
@@ -843,7 +918,7 @@
843
918
  </div>
844
919
  {/if}
845
920
 
846
- {#if features.has('slash-menu') && slashMenuOpen}
921
+ {#if SlashCommandMenu && features.has('slash-menu') && slashMenuOpen}
847
922
  <div
848
923
  style="top: {slashMenuPos.top}px; left: {slashMenuPos.left}px"
849
924
  class="fixed z-50"
@@ -876,7 +951,7 @@
876
951
  이미지·파일 고르기. 둘이 **같은 모달**을 쓰고 문구만 다르다
877
952
  (`MediaPickerModal` 주석 참고).
878
953
  -->
879
- {#if mediaPicker === 'image'}
954
+ {#if MediaPickerModal && mediaPicker === 'image'}
880
955
  <MediaPickerModal
881
956
  title="이미지 추가"
882
957
  accept="image/*"
@@ -889,7 +964,7 @@
889
964
  onCancel={() => (mediaPicker = null)}
890
965
  />
891
966
  {/if}
892
- {#if mediaPicker === 'file'}
967
+ {#if MediaPickerModal && mediaPicker === 'file'}
893
968
  <MediaPickerModal
894
969
  title="파일 추가"
895
970
  uploadLabel="파일을 선택하세요"
@@ -902,7 +977,7 @@
902
977
  {/if}
903
978
 
904
979
  <!-- 업로드를 못 하는 호스트용 폴백(URL 만 받는다). 위 `pickImage` 참고. -->
905
- {#if imageUrlPrompt}
980
+ {#if InputModal && imageUrlPrompt}
906
981
  <InputModal
907
982
  title="이미지 URL 입력"
908
983
  placeholder="https://example.com/image.png"
@@ -914,7 +989,7 @@
914
989
  />
915
990
  {/if}
916
991
 
917
- {#if mathPrompt}
992
+ {#if MathModal && mathPrompt}
918
993
  <MathModal
919
994
  latex={mathPrompt.latex}
920
995
  displayMode={mathPrompt.displayMode}
@@ -1 +1 @@
1
- {"version":3,"file":"TipTapEditor.svelte.d.ts","sourceRoot":"","sources":["../../src/components/TipTapEditor.svelte.ts"],"names":[],"mappings":"AA8FA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AA2BtC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAYjD,OAAO,EAA2B,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAQ9E,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE1F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAEhE,KAAK,gBAAgB,GAAI;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,aAAa,CAAC,EAAE,YAAY,CAAC;IAC7B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,uDAAuD;IACvD,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,wCAAwC;IACxC,sBAAsB,CAAC,EAAE,aAAa,CAAC;IACvC,mDAAmD;IACnD,YAAY,CAAC,EAAE,UAAU,CAAC;IAC1B,4BAA4B;IAC5B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,YAAY,EAAE,CAAC;IAC5B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAC;CAC7B,CAAC;AA8vBJ,QAAA,MAAM,YAAY,sDAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"TipTapEditor.svelte.d.ts","sourceRoot":"","sources":["../../src/components/TipTapEditor.svelte.ts"],"names":[],"mappings":"AA6JA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AA2BtC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAYjD,OAAO,EAA2B,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE1F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAEhE,KAAK,gBAAgB,GAAI;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,aAAa,CAAC,EAAE,YAAY,CAAC;IAC7B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,uDAAuD;IACvD,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,wCAAwC;IACxC,sBAAsB,CAAC,EAAE,aAAa,CAAC;IACvC,mDAAmD;IACnD,YAAY,CAAC,EAAE,UAAU,CAAC;IAC1B,4BAA4B;IAC5B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,YAAY,EAAE,CAAC;IAC5B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAC;CAC7B,CAAC;AA0wBJ,QAAA,MAAM,YAAY,sDAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"FileAttachment.d.ts","sourceRoot":"","sources":["../../src/extensions/FileAttachment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAmB,MAAM,cAAc,CAAC;AAErD,MAAM,MAAM,iBAAiB,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAC9E,MAAM,MAAM,YAAY,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAE1E,MAAM,WAAW,qBAAqB;IACpC,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;IAC9B,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,OAAO,QAAQ,cAAc,CAAC;IAC5B,UAAU,QAAQ,CAAC,UAAU;QAC3B,cAAc,EAAE;YACd,iBAAiB,EAAE,CAAC,KAAK,EAAE;gBACzB,GAAG,CAAC,EAAE,MAAM,CAAC;gBACb,MAAM,CAAC,EAAE,MAAM,CAAC;gBAChB,IAAI,EAAE,MAAM,CAAC;gBACb,IAAI,CAAC,EAAE,MAAM,CAAC;aACf,KAAK,UAAU,CAAC;SAClB,CAAC;KACH;CACF;AAkFD,eAAO,MAAM,cAAc,kCA4NzB,CAAC"}
1
+ {"version":3,"file":"FileAttachment.d.ts","sourceRoot":"","sources":["../../src/extensions/FileAttachment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAmB,MAAM,cAAc,CAAC;AAErD,MAAM,MAAM,iBAAiB,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAC9E,MAAM,MAAM,YAAY,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAE1E,MAAM,WAAW,qBAAqB;IACpC,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;IAC9B,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,OAAO,QAAQ,cAAc,CAAC;IAC5B,UAAU,QAAQ,CAAC,UAAU;QAC3B,cAAc,EAAE;YACd,iBAAiB,EAAE,CAAC,KAAK,EAAE;gBACzB,GAAG,CAAC,EAAE,MAAM,CAAC;gBACb,MAAM,CAAC,EAAE,MAAM,CAAC;gBAChB,IAAI,EAAE,MAAM,CAAC;gBACb,IAAI,CAAC,EAAE,MAAM,CAAC;aACf,KAAK,UAAU,CAAC;SAClB,CAAC;KACH;CACF;AAkFD,eAAO,MAAM,cAAc,kCAyNzB,CAAC"}
@@ -183,35 +183,27 @@ export const FileAttachment = Node.create({
183
183
  nameEl.download = resolvedName;
184
184
  }
185
185
  updateHref();
186
- let downloadInProgress = false;
187
186
  function handleClick(e) {
188
- e.preventDefault();
187
+ // 상위(ProseMirror 노드 선택 등) 간섭만 막는다. 기본 동작을 죽일지는 분기별로 정한다.
189
188
  e.stopPropagation();
190
- if (downloadInProgress)
191
- return;
192
- const proxyUrl = getProxyUrl();
193
- const targetUrl = proxyUrl || resolvedSrc;
194
- if (!targetUrl)
189
+ const targetUrl = getProxyUrl() || resolvedSrc;
190
+ if (!targetUrl) {
191
+ e.preventDefault();
195
192
  return;
193
+ }
196
194
  if (isInlineable(resolvedName)) {
195
+ // 새 탭으로 "보여주는" 분기는 <a download>의 기본 동작(저장)과 정반대이므로
196
+ // 여기서만 기본 동작을 가로챈다.
197
+ e.preventDefault();
197
198
  window.open(targetUrl, "_blank");
199
+ return;
198
200
  }
199
- else {
200
- downloadInProgress = true;
201
- fetch(targetUrl)
202
- .then((res) => res.blob())
203
- .then((blob) => {
204
- const url = URL.createObjectURL(blob);
205
- const a = document.createElement("a");
206
- a.href = url;
207
- a.download = resolvedName;
208
- a.click();
209
- URL.revokeObjectURL(url);
210
- })
211
- .finally(() => {
212
- downloadInProgress = false;
213
- });
214
- }
201
+ // 다운로드 분기는 preventDefault 하지 않고 <a href download> 네이티브 동작에 맡긴다.
202
+ // 예전 방식(fetch → res.blob())은 파일 전체를 탭 메모리에 버퍼링한 뒤에야 저장을
203
+ // 시작해서, 381MB 첨부에서 클릭 후 수 분간 아무 반응이 없었다 — 진행률도 없고
204
+ // 브라우저 다운로드 목록에도 안 떴다. 네이티브 다운로드는 클릭 즉시 다운로드
205
+ // 관리자로 넘어가 디스크로 스트리밍되므로 대기도, 탭 메모리 점유도 없다.
206
+ // href/download는 updateHref()가 같은 우선순위(proxy → resolvedSrc)로 이미 세팅한다.
215
207
  }
216
208
  nameEl.addEventListener("click", handleClick);
217
209
  nameEl.addEventListener("mousedown", (e) => e.stopPropagation());
package/dist/index.d.ts CHANGED
@@ -1,10 +1,4 @@
1
1
  export { default as TipTapEditor } from "./components/TipTapEditor.svelte";
2
- export { default as FixedToolbar } from "./components/FixedToolbar.svelte";
3
- export { default as BubbleToolbar } from "./components/BubbleToolbar.svelte";
4
- export { default as SlashCommandMenu } from "./components/SlashCommandMenu.svelte";
5
- export { default as InputModal } from "./components/InputModal.svelte";
6
- export { default as MathModal } from "./components/MathModal.svelte";
7
- export { default as TableBubbleMenu } from "./components/TableBubbleMenu.svelte";
8
2
  export { PdfBlock } from "./extensions/PdfBlock";
9
3
  export { Indent } from "./extensions/Indent";
10
4
  export { FixedDetails } from "./extensions/FixedDetails";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAC3E,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAC3E,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAC7E,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AACnF,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,qCAAqC,CAAC;AAGjF,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AACnF,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClF,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,YAAY,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AACrF,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC5D,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGjE,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACzF,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC;AAahC,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAG5D,YAAY,EACV,iBAAiB,EACjB,aAAa,EACb,WAAW,EACX,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,qBAAqB,EACrB,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAW3E,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AACnF,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClF,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,YAAY,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AACrF,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC5D,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGjE,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACzF,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC;AAahC,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAG5D,YAAY,EACV,iBAAiB,EACjB,aAAa,EACb,WAAW,EACX,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,qBAAqB,EACrB,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC"}
package/dist/index.js CHANGED
@@ -1,11 +1,13 @@
1
1
  // 컴포넌트
2
2
  export { default as TipTapEditor } from "./components/TipTapEditor.svelte";
3
- export { default as FixedToolbar } from "./components/FixedToolbar.svelte";
4
- export { default as BubbleToolbar } from "./components/BubbleToolbar.svelte";
5
- export { default as SlashCommandMenu } from "./components/SlashCommandMenu.svelte";
6
- export { default as InputModal } from "./components/InputModal.svelte";
7
- export { default as MathModal } from "./components/MathModal.svelte";
8
- export { default as TableBubbleMenu } from "./components/TableBubbleMenu.svelte";
3
+ /*
4
+ * ⚠️ **툴바·메뉴·모달 여섯은 여기서 re-export 하지 않는다** → `@teriusu/rich-editor/toolbars`.
5
+ * `TipTapEditor` 가 그것들을 `editable` 일 때만 동적으로 받도록 해 놨는데(그쪽
6
+ * `loadEditorChrome` 주석), 배럴이 정적으로 참조하면 **지연이 통째로 무효가 된다** —
7
+ * 배럴을 가져오는 순간 다시 그래프에 들어오기 때문이다. 실측으로 그 여섯만 쓰는
8
+ * lucide 아이콘 53 개가 75KB(gzip) 짜리 청크 하나였고, 툴바가 평생 뜨지 않는
9
+ * 읽기 전용 라우트가 정올 176 개 중 91 개다.
10
+ */
9
11
  // 익스텐션
10
12
  export { PdfBlock } from "./extensions/PdfBlock";
11
13
  export { Indent } from "./extensions/Indent";
@@ -0,0 +1,18 @@
1
+ /**
2
+ * 편집 크롬(툴바·메뉴·모달) 진입점.
3
+ *
4
+ * **배럴(`index.ts`)이 아니라 여기에 있는 이유**: `TipTapEditor` 는 이 일곱을
5
+ * `editable` 일 때만 동적으로 받는다(그쪽 `loadEditorChrome` 주석에 실측이 있다).
6
+ * 배럴이 같은 것을 정적으로 re-export 하면 **그 지연이 무효가 된다** — 배럴을
7
+ * 한 번이라도 가져오는 순간 그래프에 다시 들어오기 때문이다. 그래서 갈라 둔다.
8
+ *
9
+ * 직접 쓸 일은 드물다. `TipTapEditor` 를 쓰면 알아서 실린다.
10
+ * 툴바만 따로 배치하는 호스트만 `@teriusu/rich-editor/toolbars` 로 가져간다.
11
+ */
12
+ export { default as FixedToolbar } from "./components/FixedToolbar.svelte";
13
+ export { default as BubbleToolbar } from "./components/BubbleToolbar.svelte";
14
+ export { default as SlashCommandMenu } from "./components/SlashCommandMenu.svelte";
15
+ export { default as TableBubbleMenu } from "./components/TableBubbleMenu.svelte";
16
+ export { default as InputModal } from "./components/InputModal.svelte";
17
+ export { default as MathModal } from "./components/MathModal.svelte";
18
+ //# sourceMappingURL=toolbars.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolbars.d.ts","sourceRoot":"","sources":["../src/toolbars.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAC3E,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAC7E,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AACnF,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,+BAA+B,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * 편집 크롬(툴바·메뉴·모달) 진입점.
3
+ *
4
+ * **배럴(`index.ts`)이 아니라 여기에 있는 이유**: `TipTapEditor` 는 이 일곱을
5
+ * `editable` 일 때만 동적으로 받는다(그쪽 `loadEditorChrome` 주석에 실측이 있다).
6
+ * 배럴이 같은 것을 정적으로 re-export 하면 **그 지연이 무효가 된다** — 배럴을
7
+ * 한 번이라도 가져오는 순간 그래프에 다시 들어오기 때문이다. 그래서 갈라 둔다.
8
+ *
9
+ * 직접 쓸 일은 드물다. `TipTapEditor` 를 쓰면 알아서 실린다.
10
+ * 툴바만 따로 배치하는 호스트만 `@teriusu/rich-editor/toolbars` 로 가져간다.
11
+ */
12
+ export { default as FixedToolbar } from "./components/FixedToolbar.svelte";
13
+ export { default as BubbleToolbar } from "./components/BubbleToolbar.svelte";
14
+ export { default as SlashCommandMenu } from "./components/SlashCommandMenu.svelte";
15
+ export { default as TableBubbleMenu } from "./components/TableBubbleMenu.svelte";
16
+ export { default as InputModal } from "./components/InputModal.svelte";
17
+ export { default as MathModal } from "./components/MathModal.svelte";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teriusu/rich-editor",
3
- "version": "0.10.2",
3
+ "version": "0.10.4",
4
4
  "description": "TipTap 기반 Notion-style 리치 텍스트 에디터 (Svelte)",
5
5
  "type": "module",
6
6
  "svelte": "./dist/index.js",
@@ -11,6 +11,11 @@
11
11
  "svelte": "./dist/index.js",
12
12
  "default": "./dist/index.js"
13
13
  },
14
+ "./toolbars": {
15
+ "types": "./dist/toolbars.d.ts",
16
+ "svelte": "./dist/toolbars.js",
17
+ "default": "./dist/toolbars.js"
18
+ },
14
19
  "./lowlight": {
15
20
  "types": "./dist/utils/lowlight.d.ts",
16
21
  "default": "./dist/utils/lowlight.js"