@teriusu/rich-editor 0.8.3 → 0.8.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/BubbleToolbar.svelte +53 -29
- package/dist/components/BubbleToolbar.svelte.d.ts.map +1 -1
- package/dist/components/FixedToolbar.svelte +155 -55
- package/dist/components/FixedToolbar.svelte.d.ts +9 -0
- package/dist/components/FixedToolbar.svelte.d.ts.map +1 -1
- package/dist/components/TipTapEditor.svelte +47 -5
- package/dist/components/TipTapEditor.svelte.d.ts +3 -0
- package/dist/components/TipTapEditor.svelte.d.ts.map +1 -1
- package/dist/styles/editor.css +1 -1
- package/dist/types.d.ts +8 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +10 -3
- package/package.json +1 -1
|
@@ -36,6 +36,30 @@
|
|
|
36
36
|
onPromptLink?: PromptHandler;
|
|
37
37
|
} = $props();
|
|
38
38
|
|
|
39
|
+
/*
|
|
40
|
+
* ⚠️ **툴바가 스스로 다시 그려지게 하는 장치.**
|
|
41
|
+
*
|
|
42
|
+
* `editor` 는 TipTap 이 만든 평범한 객체라 `$state` 가 아니다. 그래서 선택이 바뀌거나
|
|
43
|
+
* 서식이 켜져도 Svelte 는 아무것도 모르고, `editor.isActive('bold')` 를 다시 읽지 않는다
|
|
44
|
+
* — 버튼이 영영 비활성 모양으로 남는다(실측: `isActive` 는 true 인데 클래스는 그대로).
|
|
45
|
+
*
|
|
46
|
+
* 예전엔 `onTransaction` 에서 `editor = editor` 로 밀어 줬는데 그건 **Svelte 4 관용구**다.
|
|
47
|
+
* rune 에서는 같은 참조를 다시 대입해도 아무 일도 일어나지 않는다.
|
|
48
|
+
*
|
|
49
|
+
* 대신 트랜잭션마다 카운터를 올리고, 활성 여부를 읽는 자리에서 그 카운터를 함께 읽는다
|
|
50
|
+
* (쉼표 연산자). 그러면 Svelte 가 "이 표현식은 tick 에 의존한다"고 알아채 다시 계산한다.
|
|
51
|
+
*/
|
|
52
|
+
let tick = $state(0);
|
|
53
|
+
$effect(() => {
|
|
54
|
+
const bump = () => tick++;
|
|
55
|
+
editor.on("transaction", bump);
|
|
56
|
+
return () => {
|
|
57
|
+
editor.off("transaction", bump);
|
|
58
|
+
};
|
|
59
|
+
});
|
|
60
|
+
const isActive = (...args: Parameters<Editor["isActive"]>) =>
|
|
61
|
+
(tick, editor.isActive(...args));
|
|
62
|
+
|
|
39
63
|
const has = (f: ToolbarFeature) => features.has(f);
|
|
40
64
|
|
|
41
65
|
let showBlockMenu = $state(false);
|
|
@@ -58,23 +82,23 @@
|
|
|
58
82
|
];
|
|
59
83
|
|
|
60
84
|
function getCurrentBlockLabel(): string {
|
|
61
|
-
if (
|
|
62
|
-
if (
|
|
63
|
-
if (
|
|
64
|
-
if (
|
|
65
|
-
if (
|
|
66
|
-
if (
|
|
67
|
-
if (
|
|
85
|
+
if (isActive("heading", { level: 1 })) return "제목 1";
|
|
86
|
+
if (isActive("heading", { level: 2 })) return "제목 2";
|
|
87
|
+
if (isActive("heading", { level: 3 })) return "제목 3";
|
|
88
|
+
if (isActive("bulletList")) return "글머리 목록";
|
|
89
|
+
if (isActive("orderedList")) return "번호 목록";
|
|
90
|
+
if (isActive("taskList")) return "체크리스트";
|
|
91
|
+
if (isActive("blockquote")) return "인용문";
|
|
68
92
|
return "본문";
|
|
69
93
|
}
|
|
70
94
|
|
|
71
95
|
function isParagraphActive(): boolean {
|
|
72
96
|
return (
|
|
73
|
-
!
|
|
74
|
-
!
|
|
75
|
-
!
|
|
76
|
-
!
|
|
77
|
-
!
|
|
97
|
+
!isActive("heading") &&
|
|
98
|
+
!isActive("bulletList") &&
|
|
99
|
+
!isActive("orderedList") &&
|
|
100
|
+
!isActive("taskList") &&
|
|
101
|
+
!isActive("blockquote")
|
|
78
102
|
);
|
|
79
103
|
}
|
|
80
104
|
|
|
@@ -181,7 +205,7 @@
|
|
|
181
205
|
class={cn(
|
|
182
206
|
"w-full flex items-center gap-2 px-3 py-1.5 text-xs transition-colors",
|
|
183
207
|
isParagraphActive()
|
|
184
|
-
? "
|
|
208
|
+
? "hce-active"
|
|
185
209
|
: "text-white/70 hover:text-white hover:bg-white/10",
|
|
186
210
|
)}
|
|
187
211
|
onclick={() => {
|
|
@@ -198,8 +222,8 @@
|
|
|
198
222
|
type="button"
|
|
199
223
|
class={cn(
|
|
200
224
|
"w-full flex items-center gap-2 px-3 py-1.5 text-xs transition-colors",
|
|
201
|
-
|
|
202
|
-
? "
|
|
225
|
+
isActive("heading", { level })
|
|
226
|
+
? "hce-active"
|
|
203
227
|
: "text-white/70 hover:text-white hover:bg-white/10",
|
|
204
228
|
)}
|
|
205
229
|
onclick={() => {
|
|
@@ -220,8 +244,8 @@
|
|
|
220
244
|
type="button"
|
|
221
245
|
class={cn(
|
|
222
246
|
"w-full flex items-center gap-2 px-3 py-1.5 text-xs transition-colors",
|
|
223
|
-
|
|
224
|
-
? "
|
|
247
|
+
isActive("bulletList")
|
|
248
|
+
? "hce-active"
|
|
225
249
|
: "text-white/70 hover:text-white hover:bg-white/10",
|
|
226
250
|
)}
|
|
227
251
|
onclick={() => {
|
|
@@ -237,8 +261,8 @@
|
|
|
237
261
|
type="button"
|
|
238
262
|
class={cn(
|
|
239
263
|
"w-full flex items-center gap-2 px-3 py-1.5 text-xs transition-colors",
|
|
240
|
-
|
|
241
|
-
? "
|
|
264
|
+
isActive("orderedList")
|
|
265
|
+
? "hce-active"
|
|
242
266
|
: "text-white/70 hover:text-white hover:bg-white/10",
|
|
243
267
|
)}
|
|
244
268
|
onclick={() => {
|
|
@@ -254,8 +278,8 @@
|
|
|
254
278
|
type="button"
|
|
255
279
|
class={cn(
|
|
256
280
|
"w-full flex items-center gap-2 px-3 py-1.5 text-xs transition-colors",
|
|
257
|
-
|
|
258
|
-
? "
|
|
281
|
+
isActive("taskList")
|
|
282
|
+
? "hce-active"
|
|
259
283
|
: "text-white/70 hover:text-white hover:bg-white/10",
|
|
260
284
|
)}
|
|
261
285
|
onclick={() => {
|
|
@@ -271,8 +295,8 @@
|
|
|
271
295
|
type="button"
|
|
272
296
|
class={cn(
|
|
273
297
|
"w-full flex items-center gap-2 px-3 py-1.5 text-xs transition-colors",
|
|
274
|
-
|
|
275
|
-
? "
|
|
298
|
+
isActive("blockquote")
|
|
299
|
+
? "hce-active"
|
|
276
300
|
: "text-white/70 hover:text-white hover:bg-white/10",
|
|
277
301
|
)}
|
|
278
302
|
onclick={() => {
|
|
@@ -299,7 +323,7 @@
|
|
|
299
323
|
aria-label="굵게"
|
|
300
324
|
class={cn(
|
|
301
325
|
"p-1.5 rounded-full transition-colors",
|
|
302
|
-
|
|
326
|
+
isActive("bold")
|
|
303
327
|
? "bg-white/20 text-white"
|
|
304
328
|
: "text-white/70 hover:text-white hover:bg-white/10",
|
|
305
329
|
)}
|
|
@@ -315,7 +339,7 @@
|
|
|
315
339
|
aria-label="기울임"
|
|
316
340
|
class={cn(
|
|
317
341
|
"p-1.5 rounded-full transition-colors",
|
|
318
|
-
|
|
342
|
+
isActive("italic")
|
|
319
343
|
? "bg-white/20 text-white"
|
|
320
344
|
: "text-white/70 hover:text-white hover:bg-white/10",
|
|
321
345
|
)}
|
|
@@ -331,7 +355,7 @@
|
|
|
331
355
|
aria-label="밑줄"
|
|
332
356
|
class={cn(
|
|
333
357
|
"p-1.5 rounded-full transition-colors",
|
|
334
|
-
|
|
358
|
+
isActive("underline")
|
|
335
359
|
? "bg-white/20 text-white"
|
|
336
360
|
: "text-white/70 hover:text-white hover:bg-white/10",
|
|
337
361
|
)}
|
|
@@ -347,7 +371,7 @@
|
|
|
347
371
|
aria-label="취소선"
|
|
348
372
|
class={cn(
|
|
349
373
|
"p-1.5 rounded-full transition-colors",
|
|
350
|
-
|
|
374
|
+
isActive("strike")
|
|
351
375
|
? "bg-white/20 text-white"
|
|
352
376
|
: "text-white/70 hover:text-white hover:bg-white/10",
|
|
353
377
|
)}
|
|
@@ -368,7 +392,7 @@
|
|
|
368
392
|
aria-label="하이라이트"
|
|
369
393
|
class={cn(
|
|
370
394
|
"p-1.5 rounded-full transition-colors",
|
|
371
|
-
|
|
395
|
+
isActive("highlight")
|
|
372
396
|
? "bg-white/20 text-white"
|
|
373
397
|
: "text-white/70 hover:text-white hover:bg-white/10",
|
|
374
398
|
)}
|
|
@@ -449,7 +473,7 @@
|
|
|
449
473
|
aria-label="링크"
|
|
450
474
|
class={cn(
|
|
451
475
|
"p-1.5 rounded-full transition-colors",
|
|
452
|
-
|
|
476
|
+
isActive("link")
|
|
453
477
|
? "bg-white/20 text-white"
|
|
454
478
|
: "text-white/70 hover:text-white hover:bg-white/10",
|
|
455
479
|
)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BubbleToolbar.svelte.d.ts","sourceRoot":"","sources":["../../src/components/BubbleToolbar.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAuB3C,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,YAAY,CAAC,EAAE,aAAa,CAAC;CAC9B,CAAC;
|
|
1
|
+
{"version":3,"file":"BubbleToolbar.svelte.d.ts","sourceRoot":"","sources":["../../src/components/BubbleToolbar.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAuB3C,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,YAAY,CAAC,EAAE,aAAa,CAAC;CAC9B,CAAC;AAoXJ,QAAA,MAAM,aAAa,sDAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Editor } from "@tiptap/core";
|
|
3
|
+
import type { Snippet } from "svelte";
|
|
3
4
|
import {
|
|
4
5
|
Bold,
|
|
5
6
|
Italic,
|
|
@@ -46,6 +47,7 @@
|
|
|
46
47
|
onPromptLink,
|
|
47
48
|
onPromptImage,
|
|
48
49
|
onPromptMbus,
|
|
50
|
+
toolbarEnd,
|
|
49
51
|
}: {
|
|
50
52
|
editor: Editor;
|
|
51
53
|
features: Set<ToolbarFeature>;
|
|
@@ -54,8 +56,51 @@
|
|
|
54
56
|
onPromptLink?: PromptHandler;
|
|
55
57
|
onPromptImage?: PromptHandler;
|
|
56
58
|
onPromptMbus?: PromptHandler;
|
|
59
|
+
/**
|
|
60
|
+
* 툴바 **오른쪽 끝**에 호스트가 끼워 넣는 조각(예: HTML ↔ 에디터 토글).
|
|
61
|
+
*
|
|
62
|
+
* 이게 없으면 호스트는 툴바 위에 `position: absolute` 로 띄우는 수밖에 없는데,
|
|
63
|
+
* 그러면 툴바 버튼들과 세로 정렬이 맞지 않고(사용자 지적) 좁은 폭에서는 겹친다.
|
|
64
|
+
* 여기에 넣으면 툴바의 flex 행에 그대로 얹혀 정렬이 저절로 맞는다.
|
|
65
|
+
*/
|
|
66
|
+
toolbarEnd?: Snippet;
|
|
57
67
|
} = $props();
|
|
58
68
|
|
|
69
|
+
/*
|
|
70
|
+
* ⚠️ **툴바가 스스로 다시 그려지게 하는 장치.**
|
|
71
|
+
*
|
|
72
|
+
* `editor` 는 TipTap 이 만든 평범한 객체라 `$state` 가 아니다. 그래서 선택이 바뀌거나
|
|
73
|
+
* 서식이 켜져도 Svelte 는 아무것도 모르고, `editor.isActive('bold')` 를 다시 읽지 않는다
|
|
74
|
+
* — 버튼이 영영 비활성 모양으로 남는다(실측: `isActive` 는 true 인데 클래스는 그대로).
|
|
75
|
+
*
|
|
76
|
+
* 예전엔 `onTransaction` 에서 `editor = editor` 로 밀어 줬는데 그건 **Svelte 4 관용구**다.
|
|
77
|
+
* rune 에서는 같은 참조를 다시 대입해도 아무 일도 일어나지 않는다.
|
|
78
|
+
*
|
|
79
|
+
* 대신 트랜잭션마다 카운터를 올리고, 활성 여부를 읽는 자리에서 그 카운터를 함께 읽는다
|
|
80
|
+
* (쉼표 연산자). 그러면 Svelte 가 "이 표현식은 tick 에 의존한다"고 알아채 다시 계산한다.
|
|
81
|
+
*/
|
|
82
|
+
let tick = $state(0);
|
|
83
|
+
$effect(() => {
|
|
84
|
+
const bump = () => tick++;
|
|
85
|
+
editor.on("transaction", bump);
|
|
86
|
+
return () => {
|
|
87
|
+
editor.off("transaction", bump);
|
|
88
|
+
};
|
|
89
|
+
});
|
|
90
|
+
const isActive = (...args: Parameters<Editor["isActive"]>) =>
|
|
91
|
+
(tick, editor.isActive(...args));
|
|
92
|
+
/**
|
|
93
|
+
* ⚠️ `isActive` 만 고쳐서는 부족했다. **되돌리기 가능 여부**와 **지금 글자색**도
|
|
94
|
+
* 매 트랜잭션마다 다시 읽어야 하는데, 그냥 `editor.can()` / `editor.getAttributes()` 를
|
|
95
|
+
* 부르면 Svelte 가 의존성을 못 봐서 처음 값에 굳는다 —
|
|
96
|
+
* 되돌리기가 영영 비활성으로 남고(사용자 지적), 글자색 버튼은 한 번 켜지면 색을 꺼도
|
|
97
|
+
* 계속 켜진 채였다.
|
|
98
|
+
*/
|
|
99
|
+
const canDo = (fn: (c: ReturnType<Editor["can"]>) => boolean) =>
|
|
100
|
+
(tick, fn(editor.can()));
|
|
101
|
+
const attrOf = (name: string, key: string) =>
|
|
102
|
+
(tick, editor.getAttributes(name)[key] as string | undefined);
|
|
103
|
+
|
|
59
104
|
const has = (f: ToolbarFeature) => features.has(f);
|
|
60
105
|
|
|
61
106
|
const iconSize = 16;
|
|
@@ -68,18 +113,40 @@
|
|
|
68
113
|
let insertMenuEl: HTMLDivElement | undefined = $state();
|
|
69
114
|
let colorMenuEl: HTMLDivElement | undefined = $state();
|
|
70
115
|
|
|
71
|
-
|
|
116
|
+
/*
|
|
117
|
+
* ⚠️ **`검정(#000000)` 은 뺐다.** `기본`(×, 색 지정 해제)과 눈으로 구별이 안 되는데
|
|
118
|
+
* (본문 기본색이 거의 검정이다) 두 가지가 다 있으면 헷갈린다 — 사용자가 짚은 부분이다.
|
|
119
|
+
*
|
|
120
|
+
* 남기는 쪽은 **`기본`** 이다. `검정` 만 남기면 본문 기본색으로 **되돌릴 방법이 없어지고**,
|
|
121
|
+
* 저장된 HTML 에 `#000000` 이 눌러앉는다. 그 글은 다크 모드에서 검정 글자가 되어
|
|
122
|
+
* 안 보인다(코드패스가 `sanitizeBodyColors` 로 이 자국을 걷어내고 있는 이유다).
|
|
123
|
+
*
|
|
124
|
+
* `브랜드` 는 앱마다 다르므로 값을 고정하지 않고 `--primary` 를 읽는다 —
|
|
125
|
+
* 정올과 코드패스가 각자 자기 색을 얻는다. 저장은 계산된 실제 색으로 한다
|
|
126
|
+
* (`var(--primary)` 를 그대로 저장하면 앱 밖에서 렌더할 때 색이 사라진다).
|
|
127
|
+
*
|
|
128
|
+
* ⚠️ **아홉 개로 맞춰 둔다.** 팔레트가 `grid-cols-3` 라 여덟 개면 마지막 줄에 빈 칸이
|
|
129
|
+
* 남아 덜 만든 것처럼 보인다(사용자 지적). `기본` + 색 여덟이 3×3 을 정확히 채운다.
|
|
130
|
+
* 색은 색상환을 고르게 훑도록 골랐다 — 빨강·주황·노랑·초록·파랑에 브랜드(남보라)와
|
|
131
|
+
* 그 사이를 메우는 분홍, 그리고 무채색 회색. 여기서 더 늘리려면 12개(3×4)로 가야 한다.
|
|
132
|
+
*/
|
|
133
|
+
const TEXT_COLORS: { label: string; value: string; cssVar?: string }[] = [
|
|
72
134
|
{ label: "기본", value: "" },
|
|
73
|
-
{ label: "
|
|
135
|
+
{ label: "브랜드", value: "", cssVar: "--primary" },
|
|
74
136
|
{ label: "회색", value: "#6b7280" },
|
|
75
137
|
{ label: "빨강", value: "#dc2626" },
|
|
76
138
|
{ label: "주황", value: "#ea580c" },
|
|
77
139
|
{ label: "노랑", value: "#ca8a04" },
|
|
78
140
|
{ label: "초록", value: "#16a34a" },
|
|
79
141
|
{ label: "파랑", value: "#2563eb" },
|
|
80
|
-
{ label: "
|
|
142
|
+
{ label: "분홍", value: "#db2777" }
|
|
81
143
|
];
|
|
82
144
|
|
|
145
|
+
/** `--primary` 같은 CSS 변수를 그 자리에서 실제 색 문자열로 바꾼다. */
|
|
146
|
+
function resolveCssVar(el: HTMLElement, name: string): string {
|
|
147
|
+
return getComputedStyle(el).getPropertyValue(name).trim();
|
|
148
|
+
}
|
|
149
|
+
|
|
83
150
|
$effect(() => {
|
|
84
151
|
if (!blockMenuOpen && !insertMenuOpen && !colorMenuOpen) return;
|
|
85
152
|
function handleClick(e: MouseEvent) {
|
|
@@ -108,7 +175,7 @@
|
|
|
108
175
|
async function addLink() {
|
|
109
176
|
insertMenuOpen = false;
|
|
110
177
|
if (onPromptLink) {
|
|
111
|
-
const previous =
|
|
178
|
+
const previous = isActive("link")
|
|
112
179
|
? (editor.getAttributes("link").href as string) || ""
|
|
113
180
|
: "";
|
|
114
181
|
const url = await onPromptLink(previous);
|
|
@@ -151,14 +218,14 @@
|
|
|
151
218
|
}
|
|
152
219
|
|
|
153
220
|
const currentBlockLabel = $derived.by(() => {
|
|
154
|
-
if (
|
|
155
|
-
if (
|
|
156
|
-
if (
|
|
157
|
-
if (
|
|
158
|
-
if (
|
|
159
|
-
if (
|
|
160
|
-
if (
|
|
161
|
-
if (
|
|
221
|
+
if (isActive("heading", { level: 1 })) return "제목 1";
|
|
222
|
+
if (isActive("heading", { level: 2 })) return "제목 2";
|
|
223
|
+
if (isActive("heading", { level: 3 })) return "제목 3";
|
|
224
|
+
if (isActive("bulletList")) return "글머리 목록";
|
|
225
|
+
if (isActive("orderedList")) return "번호 목록";
|
|
226
|
+
if (isActive("taskList")) return "체크리스트";
|
|
227
|
+
if (isActive("blockquote")) return "인용문";
|
|
228
|
+
if (isActive("details")) return "토글";
|
|
162
229
|
return "본문";
|
|
163
230
|
});
|
|
164
231
|
|
|
@@ -208,12 +275,12 @@
|
|
|
208
275
|
<button
|
|
209
276
|
type="button"
|
|
210
277
|
onclick={() => editor.chain().focus().undo().run()}
|
|
211
|
-
disabled={!
|
|
278
|
+
disabled={!canDo((c) => c.undo())}
|
|
212
279
|
data-tooltip="실행 취소"
|
|
213
280
|
aria-label="실행 취소"
|
|
214
281
|
class={cn(
|
|
215
282
|
"p-1.5 rounded-md transition-colors text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
216
|
-
!
|
|
283
|
+
!canDo((c) => c.undo()) && "opacity-30 pointer-events-none",
|
|
217
284
|
)}
|
|
218
285
|
>
|
|
219
286
|
<Undo size={iconSize} />
|
|
@@ -223,12 +290,12 @@
|
|
|
223
290
|
<button
|
|
224
291
|
type="button"
|
|
225
292
|
onclick={() => editor.chain().focus().redo().run()}
|
|
226
|
-
disabled={!
|
|
293
|
+
disabled={!canDo((c) => c.redo())}
|
|
227
294
|
data-tooltip="다시 실행"
|
|
228
295
|
aria-label="다시 실행"
|
|
229
296
|
class={cn(
|
|
230
297
|
"p-1.5 rounded-md transition-colors text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
231
|
-
!
|
|
298
|
+
!canDo((c) => c.redo()) && "opacity-30 pointer-events-none",
|
|
232
299
|
)}
|
|
233
300
|
>
|
|
234
301
|
<Redo size={iconSize} />
|
|
@@ -263,14 +330,14 @@
|
|
|
263
330
|
type="button"
|
|
264
331
|
class={cn(
|
|
265
332
|
"w-full text-left px-2.5 py-1.5 text-xs transition-colors flex items-center gap-2 hover:bg-muted",
|
|
266
|
-
!
|
|
267
|
-
!
|
|
268
|
-
!
|
|
269
|
-
!
|
|
270
|
-
!
|
|
271
|
-
!
|
|
272
|
-
!
|
|
273
|
-
"
|
|
333
|
+
!isActive("heading") &&
|
|
334
|
+
!isActive("bulletList") &&
|
|
335
|
+
!isActive("orderedList") &&
|
|
336
|
+
!isActive("taskList") &&
|
|
337
|
+
!isActive("blockquote") &&
|
|
338
|
+
!isActive("codeBlock") &&
|
|
339
|
+
!isActive("details") &&
|
|
340
|
+
"hce-active",
|
|
274
341
|
)}
|
|
275
342
|
onclick={() =>
|
|
276
343
|
runBlock(() => editor.chain().focus().setParagraph().run())}
|
|
@@ -282,7 +349,7 @@
|
|
|
282
349
|
type="button"
|
|
283
350
|
class={cn(
|
|
284
351
|
"w-full text-left px-2.5 py-1.5 text-xs transition-colors flex items-center gap-2 hover:bg-muted",
|
|
285
|
-
|
|
352
|
+
isActive("heading", { level: 1 }) && "hce-active",
|
|
286
353
|
)}
|
|
287
354
|
onclick={() =>
|
|
288
355
|
runBlock(() =>
|
|
@@ -297,7 +364,7 @@
|
|
|
297
364
|
type="button"
|
|
298
365
|
class={cn(
|
|
299
366
|
"w-full text-left px-2.5 py-1.5 text-xs transition-colors flex items-center gap-2 hover:bg-muted",
|
|
300
|
-
|
|
367
|
+
isActive("heading", { level: 2 }) && "hce-active",
|
|
301
368
|
)}
|
|
302
369
|
onclick={() =>
|
|
303
370
|
runBlock(() =>
|
|
@@ -312,7 +379,7 @@
|
|
|
312
379
|
type="button"
|
|
313
380
|
class={cn(
|
|
314
381
|
"w-full text-left px-2.5 py-1.5 text-xs transition-colors flex items-center gap-2 hover:bg-muted",
|
|
315
|
-
|
|
382
|
+
isActive("heading", { level: 3 }) && "hce-active",
|
|
316
383
|
)}
|
|
317
384
|
onclick={() =>
|
|
318
385
|
runBlock(() =>
|
|
@@ -330,7 +397,7 @@
|
|
|
330
397
|
type="button"
|
|
331
398
|
class={cn(
|
|
332
399
|
"w-full text-left px-2.5 py-1.5 text-xs transition-colors flex items-center gap-2 hover:bg-muted",
|
|
333
|
-
|
|
400
|
+
isActive("bulletList") && "hce-active",
|
|
334
401
|
)}
|
|
335
402
|
onclick={() =>
|
|
336
403
|
runBlock(() => editor.chain().focus().toggleBulletList().run())}
|
|
@@ -343,7 +410,7 @@
|
|
|
343
410
|
type="button"
|
|
344
411
|
class={cn(
|
|
345
412
|
"w-full text-left px-2.5 py-1.5 text-xs transition-colors flex items-center gap-2 hover:bg-muted",
|
|
346
|
-
|
|
413
|
+
isActive("orderedList") && "hce-active",
|
|
347
414
|
)}
|
|
348
415
|
onclick={() =>
|
|
349
416
|
runBlock(() => editor.chain().focus().toggleOrderedList().run())}
|
|
@@ -356,7 +423,7 @@
|
|
|
356
423
|
type="button"
|
|
357
424
|
class={cn(
|
|
358
425
|
"w-full text-left px-2.5 py-1.5 text-xs transition-colors flex items-center gap-2 hover:bg-muted",
|
|
359
|
-
|
|
426
|
+
isActive("taskList") && "hce-active",
|
|
360
427
|
)}
|
|
361
428
|
onclick={() =>
|
|
362
429
|
runBlock(() => editor.chain().focus().toggleTaskList().run())}
|
|
@@ -372,7 +439,7 @@
|
|
|
372
439
|
type="button"
|
|
373
440
|
class={cn(
|
|
374
441
|
"w-full text-left px-2.5 py-1.5 text-xs transition-colors flex items-center gap-2 hover:bg-muted",
|
|
375
|
-
|
|
442
|
+
isActive("blockquote") && "hce-active",
|
|
376
443
|
)}
|
|
377
444
|
onclick={() =>
|
|
378
445
|
runBlock(() => editor.chain().focus().toggleBlockquote().run())}
|
|
@@ -385,7 +452,7 @@
|
|
|
385
452
|
type="button"
|
|
386
453
|
class={cn(
|
|
387
454
|
"w-full text-left px-2.5 py-1.5 text-xs transition-colors flex items-center gap-2 hover:bg-muted",
|
|
388
|
-
|
|
455
|
+
isActive("details") && "hce-active",
|
|
389
456
|
)}
|
|
390
457
|
onclick={() =>
|
|
391
458
|
runBlock(() => editor.chain().focus().setDetails().run())}
|
|
@@ -410,8 +477,8 @@
|
|
|
410
477
|
aria-label="굵게"
|
|
411
478
|
class={cn(
|
|
412
479
|
"p-1.5 rounded-md transition-colors",
|
|
413
|
-
|
|
414
|
-
? "
|
|
480
|
+
isActive("bold")
|
|
481
|
+
? "hce-active"
|
|
415
482
|
: "text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
416
483
|
)}
|
|
417
484
|
>
|
|
@@ -426,8 +493,8 @@
|
|
|
426
493
|
aria-label="기울임"
|
|
427
494
|
class={cn(
|
|
428
495
|
"p-1.5 rounded-md transition-colors",
|
|
429
|
-
|
|
430
|
-
? "
|
|
496
|
+
isActive("italic")
|
|
497
|
+
? "hce-active"
|
|
431
498
|
: "text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
432
499
|
)}
|
|
433
500
|
>
|
|
@@ -442,8 +509,8 @@
|
|
|
442
509
|
aria-label="밑줄"
|
|
443
510
|
class={cn(
|
|
444
511
|
"p-1.5 rounded-md transition-colors",
|
|
445
|
-
|
|
446
|
-
? "
|
|
512
|
+
isActive("underline")
|
|
513
|
+
? "hce-active"
|
|
447
514
|
: "text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
448
515
|
)}
|
|
449
516
|
>
|
|
@@ -458,8 +525,8 @@
|
|
|
458
525
|
aria-label="취소선"
|
|
459
526
|
class={cn(
|
|
460
527
|
"p-1.5 rounded-md transition-colors",
|
|
461
|
-
|
|
462
|
-
? "
|
|
528
|
+
isActive("strike")
|
|
529
|
+
? "hce-active"
|
|
463
530
|
: "text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
464
531
|
)}
|
|
465
532
|
>
|
|
@@ -475,8 +542,8 @@
|
|
|
475
542
|
aria-label="글자색"
|
|
476
543
|
class={cn(
|
|
477
544
|
"flex items-center gap-0.5 p-1.5 rounded-md transition-colors",
|
|
478
|
-
|
|
479
|
-
? "
|
|
545
|
+
attrOf('textStyle', 'color')
|
|
546
|
+
? "hce-active"
|
|
480
547
|
: "text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
481
548
|
)}
|
|
482
549
|
>
|
|
@@ -497,17 +564,20 @@
|
|
|
497
564
|
type="button"
|
|
498
565
|
title={c.label}
|
|
499
566
|
class="h-8 rounded-md border border-border transition-transform hover:scale-105 flex items-center justify-center text-xs font-bold bg-background"
|
|
500
|
-
style="color: {c.value || '#6b7280'}"
|
|
501
|
-
onclick={() => {
|
|
502
|
-
|
|
503
|
-
|
|
567
|
+
style="color: {c.cssVar ? `var(${c.cssVar})` : c.value || '#6b7280'}"
|
|
568
|
+
onclick={(e) => {
|
|
569
|
+
const color = c.cssVar
|
|
570
|
+
? resolveCssVar(e.currentTarget as HTMLElement, c.cssVar)
|
|
571
|
+
: c.value;
|
|
572
|
+
if (color) {
|
|
573
|
+
editor.chain().focus().setColor(color).run();
|
|
504
574
|
} else {
|
|
505
575
|
editor.chain().focus().unsetColor().run();
|
|
506
576
|
}
|
|
507
577
|
colorMenuOpen = false;
|
|
508
578
|
}}
|
|
509
579
|
>
|
|
510
|
-
{c.value ? "A" : "×"}
|
|
580
|
+
{c.cssVar || c.value ? "A" : "×"}
|
|
511
581
|
</button>
|
|
512
582
|
{/each}
|
|
513
583
|
</div>
|
|
@@ -518,7 +588,7 @@
|
|
|
518
588
|
<input
|
|
519
589
|
type="color"
|
|
520
590
|
class="h-6 w-10 cursor-pointer rounded border border-border bg-transparent p-0"
|
|
521
|
-
value={(
|
|
591
|
+
value={attrOf('textStyle', 'color') || '#000000'}
|
|
522
592
|
onclick={(e) => e.stopPropagation()}
|
|
523
593
|
oninput={(e) => {
|
|
524
594
|
const v = (e.target as HTMLInputElement).value;
|
|
@@ -544,8 +614,8 @@
|
|
|
544
614
|
aria-label="왼쪽 정렬"
|
|
545
615
|
class={cn(
|
|
546
616
|
"p-1.5 rounded-md transition-colors",
|
|
547
|
-
|
|
548
|
-
? "
|
|
617
|
+
isActive({ textAlign: 'left' })
|
|
618
|
+
? "hce-active"
|
|
549
619
|
: "text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
550
620
|
)}
|
|
551
621
|
>
|
|
@@ -560,8 +630,8 @@
|
|
|
560
630
|
aria-label="가운데 정렬"
|
|
561
631
|
class={cn(
|
|
562
632
|
"p-1.5 rounded-md transition-colors",
|
|
563
|
-
|
|
564
|
-
? "
|
|
633
|
+
isActive({ textAlign: 'center' })
|
|
634
|
+
? "hce-active"
|
|
565
635
|
: "text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
566
636
|
)}
|
|
567
637
|
>
|
|
@@ -576,8 +646,8 @@
|
|
|
576
646
|
aria-label="오른쪽 정렬"
|
|
577
647
|
class={cn(
|
|
578
648
|
"p-1.5 rounded-md transition-colors",
|
|
579
|
-
|
|
580
|
-
? "
|
|
649
|
+
isActive({ textAlign: 'right' })
|
|
650
|
+
? "hce-active"
|
|
581
651
|
: "text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
582
652
|
)}
|
|
583
653
|
>
|
|
@@ -738,7 +808,7 @@
|
|
|
738
808
|
<InputModal
|
|
739
809
|
title="링크 URL 입력"
|
|
740
810
|
placeholder="https://example.com"
|
|
741
|
-
defaultValue={
|
|
811
|
+
defaultValue={isActive("link") ? editor.getAttributes("link").href || "" : ""}
|
|
742
812
|
onConfirm={(url) => {
|
|
743
813
|
editor
|
|
744
814
|
.chain()
|
|
@@ -773,6 +843,10 @@
|
|
|
773
843
|
onCancel={() => (modalState = null)}
|
|
774
844
|
/>
|
|
775
845
|
{/if}
|
|
846
|
+
|
|
847
|
+
{#if toolbarEnd}
|
|
848
|
+
<div class="hce-toolbar-end">{@render toolbarEnd()}</div>
|
|
849
|
+
{/if}
|
|
776
850
|
</div>
|
|
777
851
|
|
|
778
852
|
<style>
|
|
@@ -788,6 +862,32 @@
|
|
|
788
862
|
cursor: default;
|
|
789
863
|
}
|
|
790
864
|
|
|
865
|
+
/*
|
|
866
|
+
* ── 활성 표시 ──────────────────────────────────────────────────────────
|
|
867
|
+
* ⚠️ **이 규칙은 반드시 위 리셋보다 구체적이어야 한다.** 바로 위
|
|
868
|
+
* `.hce-toolbar :global(button)` 이 `background: transparent; color: inherit` 을 걸어
|
|
869
|
+
* (0,2,1), 유틸리티 클래스 하나짜리(0,1,0)로는 절대 못 이긴다. 그래서 켜진 버튼이
|
|
870
|
+
* **아무 표시도 안 났다** — 오래된 버그다(사용자 지적).
|
|
871
|
+
*
|
|
872
|
+
* 색은 `color-mix` 로 만든다. 호스트 앱이 `--primary` 를 hex 로 주기 때문에 Tailwind 의
|
|
873
|
+
* `bg-primary/10` 같은 투명도 변형은 아예 생성되지 않는다(`.claude/rules/rich-editor.md`).
|
|
874
|
+
*/
|
|
875
|
+
.hce-toolbar :global(button.hce-active) {
|
|
876
|
+
background-color: color-mix(in srgb, var(--primary, #3382f2) 12%, transparent);
|
|
877
|
+
color: var(--primary, #3382f2);
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
.hce-toolbar :global(button.hce-active:hover) {
|
|
881
|
+
background-color: color-mix(in srgb, var(--primary, #3382f2) 18%, transparent);
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
/* 오른쪽 끝으로 밀어 붙인다 — 툴바가 flex 라 auto 마진이면 충분하다. */
|
|
885
|
+
.hce-toolbar-end {
|
|
886
|
+
margin-left: auto;
|
|
887
|
+
display: flex;
|
|
888
|
+
align-items: center;
|
|
889
|
+
}
|
|
890
|
+
|
|
791
891
|
.hce-toolbar-group {
|
|
792
892
|
display: flex;
|
|
793
893
|
align-items: center;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Editor } from "@tiptap/core";
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
2
3
|
import type { ToolbarFeature, PromptHandler } from "../types";
|
|
3
4
|
type $$ComponentProps = {
|
|
4
5
|
editor: Editor;
|
|
@@ -8,6 +9,14 @@ type $$ComponentProps = {
|
|
|
8
9
|
onPromptLink?: PromptHandler;
|
|
9
10
|
onPromptImage?: PromptHandler;
|
|
10
11
|
onPromptMbus?: PromptHandler;
|
|
12
|
+
/**
|
|
13
|
+
* 툴바 **오른쪽 끝**에 호스트가 끼워 넣는 조각(예: HTML ↔ 에디터 토글).
|
|
14
|
+
*
|
|
15
|
+
* 이게 없으면 호스트는 툴바 위에 `position: absolute` 로 띄우는 수밖에 없는데,
|
|
16
|
+
* 그러면 툴바 버튼들과 세로 정렬이 맞지 않고(사용자 지적) 좁은 폭에서는 겹친다.
|
|
17
|
+
* 여기에 넣으면 툴바의 flex 행에 그대로 얹혀 정렬이 저절로 맞는다.
|
|
18
|
+
*/
|
|
19
|
+
toolbarEnd?: Snippet;
|
|
11
20
|
};
|
|
12
21
|
declare const FixedToolbar: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
13
22
|
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;
|
|
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;AAqCtC,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,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AA6lBJ,QAAA,MAAM,YAAY,sDAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
2
3
|
import { onMount, onDestroy } from "svelte";
|
|
3
4
|
import { Editor } from "@tiptap/core";
|
|
4
5
|
import StarterKit from "@tiptap/starter-kit";
|
|
@@ -37,6 +38,7 @@
|
|
|
37
38
|
import { FileAttachment } from "../extensions/FileAttachment";
|
|
38
39
|
import { MbusVideo } from "../extensions/MbusVideo";
|
|
39
40
|
import { CardBlock } from "../extensions/CardBlock";
|
|
41
|
+
import { MathInline, MathDisplay } from "../extensions/Math";
|
|
40
42
|
import FixedToolbar from "./FixedToolbar.svelte";
|
|
41
43
|
import BubbleToolbar from "./BubbleToolbar.svelte";
|
|
42
44
|
import SlashCommandMenu from "./SlashCommandMenu.svelte";
|
|
@@ -118,6 +120,7 @@
|
|
|
118
120
|
onPromptImage,
|
|
119
121
|
onPromptMbus,
|
|
120
122
|
onPromptCardBackground,
|
|
123
|
+
toolbarEnd,
|
|
121
124
|
extensions: extraExtensions = [],
|
|
122
125
|
editable = true,
|
|
123
126
|
toolbar = 'full',
|
|
@@ -134,6 +137,8 @@
|
|
|
134
137
|
onPromptMbus?: PromptHandler;
|
|
135
138
|
/** 카드 배경 고르기. 미제공 시 window.prompt 폴백 */
|
|
136
139
|
onPromptCardBackground?: PromptHandler;
|
|
140
|
+
/** 고정 툴바 오른쪽 끝에 끼워 넣을 조각 */
|
|
141
|
+
toolbarEnd?: Snippet;
|
|
137
142
|
extensions?: AnyExtension[];
|
|
138
143
|
editable?: boolean;
|
|
139
144
|
toolbar?: ToolbarMode;
|
|
@@ -144,6 +149,18 @@
|
|
|
144
149
|
|
|
145
150
|
let editorElement: HTMLDivElement | undefined = $state();
|
|
146
151
|
let editor: Editor | undefined = $state();
|
|
152
|
+
|
|
153
|
+
/*
|
|
154
|
+
* 글자수는 `editor.storage` 에서 읽는데 그건 `$state` 가 아니라, 그냥 부르면 첫 값에
|
|
155
|
+
* 굳어 **타이핑해도 숫자가 안 바뀐다**(사용자 지적). 트랜잭션마다 카운터를 올리고
|
|
156
|
+
* 그 카운터를 함께 읽어 Svelte 에 의존성을 알린다 — 툴바 활성 표시와 같은 방식이다.
|
|
157
|
+
*/
|
|
158
|
+
let editorTick = $state(0);
|
|
159
|
+
const counts = $derived.by(() => {
|
|
160
|
+
editorTick;
|
|
161
|
+
const cc = editor?.storage?.characterCount;
|
|
162
|
+
return { chars: cc?.characters?.() ?? 0, words: cc?.words?.() ?? 0 };
|
|
163
|
+
});
|
|
147
164
|
let uploading = $state(false);
|
|
148
165
|
let pdfInputEl: HTMLInputElement | undefined = $state();
|
|
149
166
|
let fileInputEl: HTMLInputElement | undefined = $state();
|
|
@@ -385,6 +402,21 @@
|
|
|
385
402
|
}),
|
|
386
403
|
MbusVideo,
|
|
387
404
|
CardBlock.configure({ promptBackground: onPromptCardBackground ?? null }),
|
|
405
|
+
/*
|
|
406
|
+
* ⚠️ **수학은 여기서 등록한다.** 예전엔 `MathInline`/`MathDisplay` 를 내보내기만 하고
|
|
407
|
+
* 등록은 호스트에 맡겼는데, 그러면 앱마다 기억해서 `extensions` 로 넘겨야 한다 —
|
|
408
|
+
* 정올이 실제로 빠뜨려서 `\le` 같은 수식이 문제 본문에 **원문 그대로** 떴다.
|
|
409
|
+
* 두 앱 다 필요한 것이면 패키지가 갖고 있는 게 맞다.
|
|
410
|
+
*
|
|
411
|
+
* 호스트가 이미 넘겼으면 비켜선다(같은 이름 확장을 두 번 등록하면 TipTap 이 죽는다).
|
|
412
|
+
* `codeBlock` 이 쓰는 방식과 같다.
|
|
413
|
+
*/
|
|
414
|
+
...(extraExtensions.some((ext) => (ext as any).name === "math_inline")
|
|
415
|
+
? []
|
|
416
|
+
: [MathInline]),
|
|
417
|
+
...(extraExtensions.some((ext) => (ext as any).name === "math_display")
|
|
418
|
+
? []
|
|
419
|
+
: [MathDisplay]),
|
|
388
420
|
Columns,
|
|
389
421
|
Column,
|
|
390
422
|
CodeBlockTopEscape,
|
|
@@ -486,9 +518,14 @@
|
|
|
486
518
|
scrollThreshold: 100,
|
|
487
519
|
scrollMargin: 100,
|
|
488
520
|
},
|
|
521
|
+
/*
|
|
522
|
+
* ⚠️ 예전엔 여기서 `editor = editor` 로 Svelte 를 밀었다. 그건 Svelte 4 관용구고
|
|
523
|
+
* rune 에서는 **같은 참조 재대입이라 아무 일도 일어나지 않는다** — 툴바 활성 표시가
|
|
524
|
+
* 영영 갱신되지 않았다. 툴바는 이제 `transaction` 을 직접 구독하고, 이 컴포넌트가
|
|
525
|
+
* 그리는 글자수는 아래 카운터로 다시 읽는다.
|
|
526
|
+
*/
|
|
489
527
|
onTransaction: () => {
|
|
490
|
-
|
|
491
|
-
editor = editor;
|
|
528
|
+
editorTick++;
|
|
492
529
|
},
|
|
493
530
|
});
|
|
494
531
|
|
|
@@ -568,12 +605,18 @@
|
|
|
568
605
|
{onPromptLink}
|
|
569
606
|
{onPromptImage}
|
|
570
607
|
{onPromptMbus}
|
|
608
|
+
{toolbarEnd}
|
|
571
609
|
onPdfClick={() => pdfInputEl?.click()}
|
|
572
610
|
onFileClick={onUploadFile ? () => fileInputEl?.click() : undefined}
|
|
573
611
|
/>
|
|
574
612
|
{/if}
|
|
575
613
|
|
|
576
|
-
|
|
614
|
+
<!--
|
|
615
|
+
본문이 들어가는 자리. **이름을 준다** — 호스트가 상자 높이를 정해 놓고 이 안을
|
|
616
|
+
채우게 하려면 이 요소를 지목할 수 있어야 한다. 이름이 없으면 남는 높이가 아무에게도
|
|
617
|
+
배분되지 않아 글자수 표시가 상자 중간에 떠 버린다.
|
|
618
|
+
-->
|
|
619
|
+
<div class="hce-editor-body" bind:this={editorElement}></div>
|
|
577
620
|
|
|
578
621
|
{#if editor && editable}
|
|
579
622
|
{#if features.has('bubble-toolbar')}
|
|
@@ -621,8 +664,7 @@
|
|
|
621
664
|
<div
|
|
622
665
|
class="flex justify-end px-4 py-2 text-xs text-muted-foreground border-t border-border"
|
|
623
666
|
>
|
|
624
|
-
{
|
|
625
|
-
{editor.storage.characterCount.words()} 단어
|
|
667
|
+
{counts.chars} 자 · {counts.words} 단어
|
|
626
668
|
</div>
|
|
627
669
|
{/if}
|
|
628
670
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
1
2
|
import { type AnyExtension } from "@tiptap/core";
|
|
2
3
|
import type { UploadHandler, PromptHandler, ToolbarMode, ToolbarFeature } from "../types";
|
|
3
4
|
import type { FileResolver } from "../extensions/FileAttachment";
|
|
@@ -13,6 +14,8 @@ type $$ComponentProps = {
|
|
|
13
14
|
onPromptMbus?: PromptHandler;
|
|
14
15
|
/** 카드 배경 고르기. 미제공 시 window.prompt 폴백 */
|
|
15
16
|
onPromptCardBackground?: PromptHandler;
|
|
17
|
+
/** 고정 툴바 오른쪽 끝에 끼워 넣을 조각 */
|
|
18
|
+
toolbarEnd?: Snippet;
|
|
16
19
|
extensions?: AnyExtension[];
|
|
17
20
|
editable?: boolean;
|
|
18
21
|
toolbar?: ToolbarMode;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TipTapEditor.svelte.d.ts","sourceRoot":"","sources":["../../src/components/TipTapEditor.svelte.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TipTapEditor.svelte.d.ts","sourceRoot":"","sources":["../../src/components/TipTapEditor.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AA6BtC,OAAO,EAAa,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAe5D,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,wCAAwC;IACxC,sBAAsB,CAAC,EAAE,aAAa,CAAC;IACvC,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;AA8nBJ,QAAA,MAAM,YAAY,sDAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
|
package/dist/styles/editor.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.pointer-events-none{pointer-events:none}.visible{visibility:visible}.collapse{visibility:collapse}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.bottom-0{bottom:0}.bottom-full{bottom:100%}.left-0{left:0}.left-1\/2{left:50%}.top-full{top:100%}.z-30{z-index:30}.z-50{z-index:50}.mx-0\.5{margin-left:.125rem;margin-right:.125rem}.mx-auto{margin-left:auto;margin-right:auto}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-4{margin-top:1rem;margin-bottom:1rem}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.block{display:block}.inline{display:inline}.flex{display:flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-px{height:1px}.w-10{width:2.5rem}.w-4{width:1rem}.w-\[360px\]{width:360px}.w-fit{width:-moz-fit-content;width:fit-content}.w-full{width:100%}.w-px{width:1px}.min-w-\[96px\]{min-width:96px}.max-w-\[90vw\]{max-width:90vw}.flex-shrink{flex-shrink:1}.-translate-x-1\/2{--tw-translate-x:-50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.columns-2{-moz-columns:2;column-count:2}.columns-3{-moz-columns:3;column-count:3}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-4{gap:1rem}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rounded{border-radius:var(--radius-md,4px)}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:var(--radius-xl,8px)}.rounded-md{border-radius:var(--radius-md,6px)}.rounded-xl{border-radius:var(--radius-2xl,12px)}.rounded-t-xl{border-top-left-radius:var(--radius-2xl,12px);border-top-right-radius:var(--radius-2xl,12px)}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-t{border-top-width:1px}.border-border{border-color:var(--border)}.border-white\/10{border-color:hsla(0,0%,100%,.1)}.border-white\/20{border-color:hsla(0,0%,100%,.2)}.bg-background{background-color:var(--background)}.bg-black\/40{background-color:rgba(0,0,0,.4)}.bg-border{background-color:var(--border)}.bg-foreground{background-color:var(--foreground)}.bg-muted{background-color:var(--muted)}.bg-popover{background-color:var(--popover)}.bg-primary{background-color:var(--primary)}.bg-transparent{background-color:transparent}.bg-white\/20{background-color:hsla(0,0%,100%,.2)}.p-0{padding:0}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-2{padding:.5rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-8{padding:2rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-3\.5{padding-left:.875rem;padding-right:.875rem}.px-4{padding-left:1rem;padding-right:1rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-bottom:.5rem}.pt-2,.py-2{padding-top:.5rem}.text-left{text-align:left}.text-center{text-align:center}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.text-foreground{color:var(--foreground)}.text-muted-foreground{color:var(--muted-foreground)}.text-primary{color:var(--primary)}.text-primary-foreground{color:var(--primary-foreground)}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.text-white\/60{color:hsla(0,0%,100%,.6)}.text-white\/70{color:hsla(0,0%,100%,.7)}.text-white\/80{color:hsla(0,0%,100%,.8)}.underline{text-decoration-line:underline}.opacity-30{opacity:.3}.shadow-lg{--tw-shadow:var(--shadow-dropdown,0 10px 15px -3px rgba(0,0,0,.1));--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color)}.shadow-lg,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow:var(--shadow-dropdown,0 1px 2px 0 rgba(0,0,0,.05));--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.shadow-xl{--tw-shadow:var(--shadow-popup,0 20px 25px -5px rgba(0,0,0,.1));--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-shadow{transition-property:box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.hce-editor-wrapper{overflow:visible!important}.hce-color-divider{border-top:1px solid hsla(0,0%,100%,.15)}.bubble-toolbar-container button,.hce-editor-wrapper button,.slash-menu button{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;border:0;cursor:pointer;box-sizing:border-box}.bubble-toolbar-container button:disabled,.hce-editor-wrapper button:disabled,.slash-menu button:disabled{cursor:default}.tiptap{font-size:1.0625rem;line-height:1.8;color:var(--foreground);padding:1.5rem}.tiptap>*+*{margin-top:.25em}.tiptap p{margin:.5em 0!important;line-height:1.5}.tiptap p:first-child{margin-top:0!important}.tiptap p:last-child{margin-bottom:0!important}.tiptap p:empty,.tiptap p:has(>br:only-child){min-height:1.5em}.tiptap h1,.tiptap h2,.tiptap h3,.tiptap li,.tiptap p{white-space:pre-wrap}.tiptap h1{font-size:2rem;font-weight:700;margin:1.5em 0 .5em;line-height:1.25}.tiptap h2{font-size:1.5rem;font-weight:600;margin:1.2em 0 .4em;line-height:1.3}.tiptap h3{font-size:1.25rem;font-weight:600;margin:1em 0 .3em;line-height:1.35}.tiptap ul{list-style:disc}.tiptap ol,.tiptap ul{padding-left:1.5em;margin:.5em 0}.tiptap ol{list-style:decimal}.tiptap ul ul{list-style:circle}.tiptap ul ul ul{list-style:square}.tiptap ol ol{list-style:lower-alpha}.tiptap ol ol ol{list-style:lower-roman}.tiptap li{margin:.4em 0;line-height:1.7}.tiptap li>p{margin:0!important;line-height:inherit!important}.tiptap ul[data-type=taskList]{list-style:none;padding-left:0}.tiptap ul[data-type=taskList] li{display:flex;align-items:baseline;gap:.5rem;margin:.3em 0;line-height:1.7;list-style:none;list-style-type:none}.tiptap ul[data-type=taskList] li>label{flex-shrink:0;display:flex;align-items:center;height:1.5em}.tiptap ul[data-type=taskList] li>label input[type=checkbox]{-moz-appearance:none;appearance:none;-webkit-appearance:none;width:1.1em;height:1.1em;margin:0;padding:0;cursor:pointer;background-color:var(--background,#fff);border:1.5px solid var(--border);border-radius:4px;transition:background-color .12s ease,border-color .12s ease,box-shadow .12s ease;display:inline-block;vertical-align:middle;flex-shrink:0}.tiptap ul[data-type=taskList] li>label input[type=checkbox]:hover{border-color:var(--muted-foreground)}.tiptap ul[data-type=taskList] li>label input[type=checkbox]:focus-visible{outline:none;box-shadow:0 0 0 2px var(--background,#fff),0 0 0 4px var(--primary)}.tiptap ul[data-type=taskList] li>label input[type=checkbox]:checked{background-color:var(--primary);border-color:var(--primary);background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2.5' viewBox='0 0 16 16'%3E%3Cpath d='m3.5 8.5 3 3 6-6.5'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.tiptap ul[data-type=taskList] li>div{flex:1}.tiptap ul[data-type=taskList] li[data-checked=true]>div{text-decoration:line-through;opacity:.6}.tiptap blockquote{border-left:3px solid var(--border);padding:.5rem 1rem;margin:.75em 0;color:var(--muted-foreground);font-style:italic}.tiptap hr{border:none;border-top:2px solid color-mix(in srgb,var(--foreground) 38%,transparent);margin:1.5em 0}.tiptap code{background:var(--muted);border-radius:4px;padding:.15em .35em;font-size:.9em}.tiptap pre{background:#282c34;color:#abb2bf;border-radius:8px;padding:1em;margin:.75em 0;overflow-x:auto;font-family:JetBrains Mono,Fira Code,Consolas,monospace;font-size:1em;line-height:1.6}.tiptap pre code{background:none;padding:0;border-radius:0;color:#abb2bf;font-size:inherit}.tiptap pre code .hljs-keyword,.tiptap pre code .hljs-operator{color:#c678dd}.tiptap pre code .hljs-addition,.tiptap pre code .hljs-doctag,.tiptap pre code .hljs-regexp,.tiptap pre code .hljs-string{color:#98c379}.tiptap pre code .hljs-attr,.tiptap pre code .hljs-number,.tiptap pre code .hljs-selector-class,.tiptap pre code .hljs-template-variable,.tiptap pre code .hljs-type,.tiptap pre code .hljs-variable{color:#d19a66}.tiptap pre code .hljs-function,.tiptap pre code .hljs-section,.tiptap pre code .hljs-title,.tiptap pre code .hljs-title.class_{color:#61aeee}.tiptap pre code .hljs-params,.tiptap pre code .hljs-punctuation{color:#abb2bf}.tiptap pre code .hljs-comment,.tiptap pre code .hljs-quote{color:#5c6370;font-style:italic}.tiptap pre code .hljs-built_in,.tiptap pre code .hljs-formula{color:#e6c07b}.tiptap pre code .hljs-meta,.tiptap pre code .hljs-meta .hljs-keyword{color:#61aeee}.tiptap pre code .hljs-meta .hljs-string{color:#98c379}.tiptap pre code .hljs-attribute,.tiptap pre code .hljs-deletion,.tiptap pre code .hljs-name,.tiptap pre code .hljs-property,.tiptap pre code .hljs-selector-tag,.tiptap pre code .hljs-subst,.tiptap pre code .hljs-tag{color:#e06c75}.tiptap pre code .hljs-literal{color:#56b6c2}.tiptap pre code .hljs-selector-attr,.tiptap pre code .hljs-selector-id,.tiptap pre code .hljs-selector-pseudo{color:#61aeee}.tiptap pre code .hljs-link{color:#61aeee;text-decoration:underline}.tiptap pre code .hljs-bullet,.tiptap pre code .hljs-symbol{color:#61aeee}.tiptap pre code .hljs-emphasis{font-style:italic}.tiptap pre code .hljs-strong{font-weight:700}.tiptap img{max-width:100%;height:auto;margin:.75em 0;cursor:pointer;transition:box-shadow .15s}.tiptap [data-type=pdfBlock].ProseMirror-selectednode>div,.tiptap img{border-radius:8px}.tiptap a{color:var(--primary);text-decoration:underline;text-underline-offset:2px}.tiptap a:hover{opacity:.8}.tiptap mark{background-color:#fef08a;border-radius:2px;padding:.05em .1em}.tiptap [data-type=details]{border:none;border-radius:6px;padding:0;margin:.5em 0;background:transparent;display:grid;grid-template-columns:26px 1fr;align-items:start;transition:background .12s}.tiptap [data-type=details]:hover{background:var(--muted)}.tiptap [data-type=details]>button{background:none;border:none;cursor:pointer;padding:0;width:18px;height:18px;display:inline-flex;align-items:center;justify-content:center;color:var(--muted-foreground);border-radius:4px;transition:transform .2s,color .15s;flex-shrink:0;margin-top:13px;margin-left:4px}.tiptap [data-type=details]>button:after{content:"";display:block;width:0;height:0;border-left:5px solid;border-top:4px solid transparent;border-bottom:4px solid transparent;margin-left:2px}.tiptap [data-type=details]:hover>button{color:var(--foreground)}.tiptap [data-type=details].is-open>button{transform:rotate(90deg)}.tiptap [data-type=details]>div{flex:1;min-width:0}.tiptap [data-type=details] summary{font-weight:600;cursor:pointer;padding:10px 8px 10px 0;display:block;border-bottom:1px solid transparent;transition:border-color .15s}.tiptap [data-type=details].is-open>div>summary{border-bottom-color:var(--border,#e5e7eb)}.tiptap [data-type=detailsContent]{padding:8px 8px 8px 0;border-left:none}.tiptap [data-type=detailsContent][hidden]{display:none}.tiptap details{border:none;border-radius:6px;padding:0;margin:.5em 0;background:transparent;transition:background .12s}.tiptap details:hover{background:var(--muted)}.tiptap details summary{font-weight:600;cursor:pointer;padding:10px 8px 10px 26px;-webkit-user-select:none;-moz-user-select:none;user-select:none;border-bottom:1px solid transparent;position:relative;list-style:none;transition:border-color .15s}.tiptap details[open]>summary{border-bottom-color:var(--border,#e5e7eb)}.tiptap details summary::-webkit-details-marker{display:none}.tiptap details summary::marker{content:""}.tiptap details summary:before{content:"";position:absolute;left:8px;top:50%;width:0;height:0;border-left:5px solid var(--muted-foreground);border-top:4px solid transparent;border-bottom:4px solid transparent;transform:translateY(-50%);transition:transform .2s,border-left-color .15s}.tiptap details:hover summary:before{border-left-color:var(--foreground)}.tiptap details[open]>summary:before{transform:translateY(-50%) rotate(90deg)}.tiptap details[open]>:not(summary){margin-top:8px;padding-left:26px;padding-right:8px}.tiptap table{border-collapse:collapse;margin:1em 0;table-layout:fixed;border:2px solid var(--border);max-width:100%}.tiptap .tableWrapper{overflow-x:auto;max-width:100%}.tiptap td,.tiptap th{border:1px solid var(--border);padding:.6em .8em;min-width:60px;vertical-align:middle;position:relative;box-sizing:border-box;overflow:hidden;word-break:break-word;line-height:1.5}.tiptap th{background:var(--muted);font-weight:600;text-align:left}.tiptap td{background:var(--background)}.tiptap .selectedCell:after{content:"";position:absolute;inset:0;background:var(--primary);opacity:.12;pointer-events:none;z-index:1}.tiptap .column-resize-handle{position:absolute;right:-3px;top:0;bottom:0;width:6px;background:var(--primary);opacity:0;cursor:col-resize;z-index:20;border-radius:2px;transition:opacity .15s}.tiptap table:hover .column-resize-handle{opacity:.4}.tiptap .column-resize-handle:hover{opacity:1}.tiptap.resize-cursor{cursor:col-resize}.tableWrapper{overflow-x:auto;overflow-y:hidden;margin:1em 0;max-width:100%;padding-right:4px}.tiptap table .grip-column,.tiptap table .grip-row,.tiptap table .grip-table{display:none!important}.tiptap .is-empty:before{content:attr(data-placeholder);float:left;color:var(--muted-foreground);opacity:.5;pointer-events:none;height:0}.tiptap h1.is-empty:before{font-size:2rem;font-weight:700}.tiptap h2.is-empty:before{font-size:1.5rem;font-weight:600}.tiptap h3.is-empty:before{font-size:1.25rem;font-weight:600}.ProseMirror-gapcursor{display:none;pointer-events:none;position:relative}.ProseMirror-gapcursor:after{content:"";display:block;position:absolute;top:-2px;width:20px;border-top:1px solid var(--foreground);animation:ProseMirror-cursor-blink 1.1s steps(2,start) infinite}@keyframes ProseMirror-cursor-blink{to{visibility:hidden}}.ProseMirror-focused .ProseMirror-gapcursor{display:block}.ProseMirror-dropcursor{border-top:2px solid var(--primary);margin:-1px 0}.tiptap ::-moz-selection{background-color:color-mix(in srgb,var(--primary) 15%,transparent)}.tiptap ::selection{background-color:color-mix(in srgb,var(--primary) 15%,transparent)}.ProseMirror-noderangeselection ::-moz-selection{background:transparent}.ProseMirror-noderangeselection ::selection{background:transparent}.ProseMirror-noderangeselection *{caret-color:transparent}.ProseMirror-selectednode,.ProseMirror-selectednoderange{position:relative}.ProseMirror-selectednode:not(img):not([data-type=pdfBlock]):before,.ProseMirror-selectednoderange:not([data-type=pdfBlock]):before{content:"";position:absolute;inset:-.25rem;background-color:color-mix(in srgb,var(--primary) 10%,transparent);border:2px solid color-mix(in srgb,var(--primary) 30%,transparent);border-radius:.5rem;pointer-events:none;z-index:-1}.bubble-toolbar-container{z-index:50}.hce-floating-plus{display:flex;align-items:center;justify-content:center;width:24px;height:24px;border-radius:6px;border:1px solid var(--border);background:var(--background);color:var(--muted-foreground);cursor:pointer;transition:all .15s}.hce-floating-plus:hover{color:var(--foreground);border-color:var(--foreground);background:var(--muted)}.hce-drag-handle{display:flex;align-items:center;gap:2px}.hce-drag-handle__plus{display:flex;align-items:center;justify-content:center;padding:4px;border-radius:4px;border:none;background:transparent;color:var(--muted-foreground);opacity:.5;cursor:pointer;transition:opacity .15s,background-color .15s}.hce-drag-handle__plus:hover{opacity:1;background:var(--muted)}.hce-drag-handle__grip{display:flex;align-items:center;justify-content:center;padding:2px;border-radius:4px;color:var(--muted-foreground);opacity:.5;cursor:grab;transition:opacity .15s,background-color .15s}.hce-drag-handle__grip:hover{opacity:1;background:var(--muted)}.hce-drag-handle__grip:active{cursor:grabbing}.tiptap div[data-type=columns]{display:grid;gap:16px;margin:1em 0}.tiptap div[data-type=columns][data-columns="2"]{grid-template-columns:1fr 1fr}.tiptap div[data-type=columns][data-columns="3"]{grid-template-columns:1fr 1fr 1fr}.tiptap div[data-type=column]{min-width:0;padding:4px 6px;border:1px dashed var(--border);border-radius:8px}.tiptap[contenteditable=true] div[data-type=column]:focus-within{border-color:var(--primary);border-style:solid}.tiptap div[data-type=columns].ProseMirror-selectednode{outline:2px solid color-mix(in srgb,var(--primary) 30%,transparent);border-radius:8px}@media (max-width:640px){.tiptap div[data-type=columns]{grid-template-columns:1fr!important}}.hce-editor-wrapper button[data-tooltip]{position:relative}.hce-editor-wrapper button[data-tooltip]:hover:after{content:attr(data-tooltip);position:absolute;top:100%;left:50%;transform:translateX(-50%);margin-top:6px;padding:4px 8px;font-size:11px;line-height:1.2;white-space:nowrap;color:#fff;background:#1e293b;border-radius:6px;pointer-events:none;z-index:60}.hce-table-btn-wrap{position:relative;display:inline-flex}.hce-table-btn-tooltip{position:absolute;bottom:100%;left:50%;transform:translateX(-50%);margin-bottom:6px;padding:4px 8px;font-size:11px;line-height:1.2;white-space:nowrap;color:#fff;background:#1e293b;border-radius:6px;pointer-events:none;opacity:0;transition:opacity .15s;z-index:60}.hce-table-btn-wrap:hover .hce-table-btn-tooltip{opacity:1}.hce-card-frame,.tiptap [data-type=card]{position:relative}.hce-card-frame{box-sizing:border-box;width:100%;margin:12px 0;padding:26px 30px;display:flex;flex-direction:column;justify-content:center;gap:12px;overflow:hidden;border:1px solid hsla(0,0%,100%,.52);border-radius:8px;box-shadow:inset 0 0 0 1px hsla(0,0%,100%,.28),0 8px 24px rgba(15,23,42,.08);overflow-wrap:anywhere;isolation:isolate}.hce-card-frame:before{content:"";position:absolute;inset:0;z-index:0;background:linear-gradient(90deg,hsla(0,0%,100%,.14),hsla(0,0%,100%,.04) 48%,rgba(15,23,42,.08));pointer-events:none}.hce-card-content{position:relative;z-index:1;box-sizing:border-box;width:100%;max-height:100%;min-height:0;padding:18px 20px;display:flex;flex-direction:column;gap:10px;overflow:hidden;border:1px solid hsla(0,0%,100%,.56);border-radius:8px;background:hsla(0,0%,100%,.82);color:#111827;box-shadow:0 14px 42px rgba(15,23,42,.12),inset 0 1px 0 hsla(0,0%,100%,.52);backdrop-filter:blur(18px) saturate(1.16);-webkit-backdrop-filter:blur(18px) saturate(1.16)}@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){.hce-card-content{background:hsla(0,0%,100%,.9)}}.hce-card-header{flex:0 0 auto}.hce-card-title{margin:0;font-size:1.65rem;font-weight:700;line-height:1.18;color:#111827}.hce-card-title[hidden]{display:none}.hce-card-title-input{box-sizing:border-box;width:100%;padding:8px 12px;border:1px solid rgba(17,24,39,.12);border-radius:6px;background:hsla(0,0%,100%,.7);color:#111827;font:inherit;font-size:1.15rem;font-weight:700;outline:none}.hce-card-title-input:focus{border-color:var(--primary,#3382f2)}.hce-card-body{flex:1 1 auto;min-height:0;overflow:auto;font-size:1rem;line-height:1.55;color:#111827}.hce-card-body>p:first-child{margin-top:0}.hce-card-body>p:last-child{margin-bottom:0}.hce-card-bg-button{position:absolute;top:8px;right:8px;z-index:3;padding:4px 10px;border:1px solid rgba(17,24,39,.12);border-radius:6px;background:hsla(0,0%,100%,.86);color:#111827;font-size:.8125rem;line-height:1.4;cursor:pointer}.hce-card-bg-button:hover{background:#fff}@media (max-width:640px){.hce-card-frame{padding:18px}.hce-card-content{padding:14px 16px}.hce-card-title{font-size:1.35rem}}.hover\:scale-105:hover{--tw-scale-x:1.05;--tw-scale-y:1.05}.hover\:scale-105:hover,.hover\:scale-110:hover{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:scale-110:hover{--tw-scale-x:1.1;--tw-scale-y:1.1}.hover\:bg-muted:hover{background-color:var(--muted)}.hover\:bg-white\/10:hover{background-color:hsla(0,0%,100%,.1)}.hover\:text-destructive:hover{color:var(--destructive)}.hover\:text-foreground:hover{color:var(--foreground)}.hover\:text-red-300:hover{--tw-text-opacity:1;color:rgb(252 165 165/var(--tw-text-opacity,1))}.hover\:text-white:hover{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-90:hover{opacity:.9}.focus\:border-primary:focus{border-color:var(--primary)}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.disabled\:opacity-30:disabled{opacity:.3}
|
|
1
|
+
.pointer-events-none{pointer-events:none}.visible{visibility:visible}.collapse{visibility:collapse}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.bottom-0{bottom:0}.bottom-full{bottom:100%}.left-0{left:0}.left-1\/2{left:50%}.top-full{top:100%}.z-30{z-index:30}.z-50{z-index:50}.mx-0\.5{margin-left:.125rem;margin-right:.125rem}.mx-auto{margin-left:auto;margin-right:auto}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-4{margin-top:1rem;margin-bottom:1rem}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.block{display:block}.inline{display:inline}.flex{display:flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-px{height:1px}.w-10{width:2.5rem}.w-4{width:1rem}.w-\[360px\]{width:360px}.w-fit{width:-moz-fit-content;width:fit-content}.w-full{width:100%}.w-px{width:1px}.min-w-\[96px\]{min-width:96px}.max-w-\[90vw\]{max-width:90vw}.flex-shrink{flex-shrink:1}.-translate-x-1\/2{--tw-translate-x:-50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.columns-2{-moz-columns:2;column-count:2}.columns-3{-moz-columns:3;column-count:3}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-4{gap:1rem}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rounded{border-radius:var(--radius-md,4px)}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:var(--radius-xl,8px)}.rounded-md{border-radius:var(--radius-md,6px)}.rounded-xl{border-radius:var(--radius-2xl,12px)}.rounded-t-xl{border-top-left-radius:var(--radius-2xl,12px);border-top-right-radius:var(--radius-2xl,12px)}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-t{border-top-width:1px}.border-border{border-color:var(--border)}.border-white\/10{border-color:hsla(0,0%,100%,.1)}.border-white\/20{border-color:hsla(0,0%,100%,.2)}.bg-background{background-color:var(--background)}.bg-black\/40{background-color:rgba(0,0,0,.4)}.bg-border{background-color:var(--border)}.bg-foreground{background-color:var(--foreground)}.bg-muted{background-color:var(--muted)}.bg-popover{background-color:var(--popover)}.bg-primary{background-color:var(--primary)}.bg-transparent{background-color:transparent}.bg-white\/20{background-color:hsla(0,0%,100%,.2)}.p-0{padding:0}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-2{padding:.5rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-8{padding:2rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-3\.5{padding-left:.875rem;padding-right:.875rem}.px-4{padding-left:1rem;padding-right:1rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-bottom:.5rem}.pt-2,.py-2{padding-top:.5rem}.text-left{text-align:left}.text-center{text-align:center}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.text-foreground{color:var(--foreground)}.text-muted-foreground{color:var(--muted-foreground)}.text-primary{color:var(--primary)}.text-primary-foreground{color:var(--primary-foreground)}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.text-white\/60{color:hsla(0,0%,100%,.6)}.text-white\/70{color:hsla(0,0%,100%,.7)}.text-white\/80{color:hsla(0,0%,100%,.8)}.underline{text-decoration-line:underline}.opacity-30{opacity:.3}.shadow-lg{--tw-shadow:var(--shadow-dropdown,0 10px 15px -3px rgba(0,0,0,.1));--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color)}.shadow-lg,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow:var(--shadow-dropdown,0 1px 2px 0 rgba(0,0,0,.05));--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.shadow-xl{--tw-shadow:var(--shadow-popup,0 20px 25px -5px rgba(0,0,0,.1));--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-shadow{transition-property:box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.hce-editor-wrapper{overflow:visible!important}.hce-color-divider{border-top:1px solid hsla(0,0%,100%,.15)}.bubble-toolbar-container button,.hce-editor-wrapper button,.slash-menu button{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;border:0;cursor:pointer;box-sizing:border-box}.bubble-toolbar-container button:disabled,.hce-editor-wrapper button:disabled,.slash-menu button:disabled{cursor:default}.tiptap{font-size:1.0625rem;line-height:1.8;color:var(--foreground);padding:1.5rem}.tiptap>*+*{margin-top:.25em}.tiptap p{margin:.5em 0!important;line-height:1.5}.tiptap p:first-child{margin-top:0!important}.tiptap p:last-child{margin-bottom:0!important}.tiptap p:empty,.tiptap p:has(>br:only-child){min-height:1.5em}.tiptap h1,.tiptap h2,.tiptap h3,.tiptap li,.tiptap p{white-space:pre-wrap}.tiptap h1{font-size:2rem;font-weight:700;margin:1.5em 0 .5em;line-height:1.25}.tiptap h2{font-size:1.5rem;font-weight:600;margin:1.2em 0 .4em;line-height:1.3}.tiptap h3{font-size:1.25rem;font-weight:600;margin:1em 0 .3em;line-height:1.35}.tiptap ul{list-style:disc}.tiptap ol,.tiptap ul{padding-left:1.5em;margin:.5em 0}.tiptap ol{list-style:decimal}.tiptap ul ul{list-style:circle}.tiptap ul ul ul{list-style:square}.tiptap ol ol{list-style:lower-alpha}.tiptap ol ol ol{list-style:lower-roman}.tiptap li{margin:.4em 0;line-height:1.7}.tiptap li>p{margin:0!important;line-height:inherit!important}.tiptap ul[data-type=taskList]{list-style:none;padding-left:0}.tiptap ul[data-type=taskList] li{display:flex;align-items:baseline;gap:.5rem;margin:.3em 0;line-height:1.7;list-style:none;list-style-type:none}.tiptap ul[data-type=taskList] li>label{flex-shrink:0;display:flex;align-items:center;height:1.5em}.tiptap ul[data-type=taskList] li>label input[type=checkbox]{-moz-appearance:none;appearance:none;-webkit-appearance:none;width:1.1em;height:1.1em;margin:0;padding:0;cursor:pointer;background-color:var(--background,#fff);border:1.5px solid var(--border);border-radius:4px;transition:background-color .12s ease,border-color .12s ease,box-shadow .12s ease;display:inline-block;vertical-align:middle;flex-shrink:0}.tiptap ul[data-type=taskList] li>label input[type=checkbox]:hover{border-color:var(--muted-foreground)}.tiptap ul[data-type=taskList] li>label input[type=checkbox]:focus-visible{outline:none;box-shadow:0 0 0 2px var(--background,#fff),0 0 0 4px var(--primary)}.tiptap ul[data-type=taskList] li>label input[type=checkbox]:checked{background-color:var(--primary);border-color:var(--primary);background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2.5' viewBox='0 0 16 16'%3E%3Cpath d='m3.5 8.5 3 3 6-6.5'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.tiptap ul[data-type=taskList] li>div{flex:1}.tiptap ul[data-type=taskList] li[data-checked=true]>div{text-decoration:line-through;opacity:.6}.tiptap blockquote{border-left:3px solid var(--border);padding:.5rem 1rem;margin:.75em 0;color:var(--muted-foreground);font-style:italic}.tiptap hr{border:none;border-top:2px solid color-mix(in srgb,var(--foreground) 38%,transparent);margin:1.5em 0}.tiptap code{background:var(--muted);border-radius:4px;padding:.15em .35em;font-size:.9em}.tiptap pre{background:#282c34;color:#abb2bf;border-radius:8px;padding:1em;margin:.75em 0;overflow-x:auto;font-family:JetBrains Mono,Fira Code,Consolas,monospace;font-size:1em;line-height:1.6}.tiptap pre code{background:none;padding:0;border-radius:0;color:#abb2bf;font-size:inherit}.tiptap pre code .hljs-keyword,.tiptap pre code .hljs-operator{color:#c678dd}.tiptap pre code .hljs-addition,.tiptap pre code .hljs-doctag,.tiptap pre code .hljs-regexp,.tiptap pre code .hljs-string{color:#98c379}.tiptap pre code .hljs-attr,.tiptap pre code .hljs-number,.tiptap pre code .hljs-selector-class,.tiptap pre code .hljs-template-variable,.tiptap pre code .hljs-type,.tiptap pre code .hljs-variable{color:#d19a66}.tiptap pre code .hljs-function,.tiptap pre code .hljs-section,.tiptap pre code .hljs-title,.tiptap pre code .hljs-title.class_{color:#61aeee}.tiptap pre code .hljs-params,.tiptap pre code .hljs-punctuation{color:#abb2bf}.tiptap pre code .hljs-comment,.tiptap pre code .hljs-quote{color:#5c6370;font-style:italic}.tiptap pre code .hljs-built_in,.tiptap pre code .hljs-formula{color:#e6c07b}.tiptap pre code .hljs-meta,.tiptap pre code .hljs-meta .hljs-keyword{color:#61aeee}.tiptap pre code .hljs-meta .hljs-string{color:#98c379}.tiptap pre code .hljs-attribute,.tiptap pre code .hljs-deletion,.tiptap pre code .hljs-name,.tiptap pre code .hljs-property,.tiptap pre code .hljs-selector-tag,.tiptap pre code .hljs-subst,.tiptap pre code .hljs-tag{color:#e06c75}.tiptap pre code .hljs-literal{color:#56b6c2}.tiptap pre code .hljs-selector-attr,.tiptap pre code .hljs-selector-id,.tiptap pre code .hljs-selector-pseudo{color:#61aeee}.tiptap pre code .hljs-link{color:#61aeee;text-decoration:underline}.tiptap pre code .hljs-bullet,.tiptap pre code .hljs-symbol{color:#61aeee}.tiptap pre code .hljs-emphasis{font-style:italic}.tiptap pre code .hljs-strong{font-weight:700}.tiptap img{max-width:100%;height:auto;margin:.75em 0;cursor:pointer;transition:box-shadow .15s}.tiptap [data-type=pdfBlock].ProseMirror-selectednode>div,.tiptap img{border-radius:8px}.tiptap a{color:var(--primary);text-decoration:underline;text-underline-offset:2px}.tiptap a:hover{opacity:.8}.tiptap mark{background-color:#fef08a;border-radius:2px;padding:.05em .1em}.tiptap [data-type=details]{border:none;border-radius:6px;padding:0;margin:.5em 0;background:transparent;display:grid;grid-template-columns:26px 1fr;align-items:start;transition:background .12s}.tiptap [data-type=details]:hover{background:var(--muted)}.tiptap [data-type=details]>button{background:none;border:none;cursor:pointer;padding:0;width:18px;height:18px;display:inline-flex;align-items:center;justify-content:center;color:var(--muted-foreground);border-radius:4px;transition:transform .2s,color .15s;flex-shrink:0;margin-top:13px;margin-left:4px}.tiptap [data-type=details]>button:after{content:"";display:block;width:0;height:0;border-left:5px solid;border-top:4px solid transparent;border-bottom:4px solid transparent;margin-left:2px}.tiptap [data-type=details]:hover>button{color:var(--foreground)}.tiptap [data-type=details].is-open>button{transform:rotate(90deg)}.tiptap [data-type=details]>div{flex:1;min-width:0}.tiptap [data-type=details] summary{font-weight:600;cursor:pointer;padding:10px 8px 10px 0;display:block;border-bottom:1px solid transparent;transition:border-color .15s}.tiptap [data-type=details].is-open>div>summary{border-bottom-color:var(--border,#e5e7eb)}.tiptap [data-type=detailsContent]{padding:8px 8px 8px 0;border-left:none}.tiptap [data-type=detailsContent][hidden]{display:none}.tiptap details{border:none;border-radius:6px;padding:0;margin:.5em 0;background:transparent;transition:background .12s}.tiptap details:hover{background:var(--muted)}.tiptap details summary{font-weight:600;cursor:pointer;padding:10px 8px 10px 26px;-webkit-user-select:none;-moz-user-select:none;user-select:none;border-bottom:1px solid transparent;position:relative;list-style:none;transition:border-color .15s}.tiptap details[open]>summary{border-bottom-color:var(--border,#e5e7eb)}.tiptap details summary::-webkit-details-marker{display:none}.tiptap details summary::marker{content:""}.tiptap details summary:before{content:"";position:absolute;left:8px;top:50%;width:0;height:0;border-left:5px solid var(--muted-foreground);border-top:4px solid transparent;border-bottom:4px solid transparent;transform:translateY(-50%);transition:transform .2s,border-left-color .15s}.tiptap details:hover summary:before{border-left-color:var(--foreground)}.tiptap details[open]>summary:before{transform:translateY(-50%) rotate(90deg)}.tiptap details[open]>:not(summary){margin-top:8px;padding-left:26px;padding-right:8px}.tiptap table{border-collapse:collapse;margin:1em 0;table-layout:fixed;border:2px solid var(--border);max-width:100%}.tiptap .tableWrapper{overflow-x:auto;max-width:100%}.tiptap td,.tiptap th{border:1px solid var(--border);padding:.6em .8em;min-width:60px;vertical-align:middle;position:relative;box-sizing:border-box;overflow:hidden;word-break:break-word;line-height:1.5}.tiptap th{background:var(--muted);font-weight:600;text-align:left}.tiptap td{background:var(--background)}.tiptap .selectedCell:after{content:"";position:absolute;inset:0;background:var(--primary);opacity:.12;pointer-events:none;z-index:1}.tiptap .column-resize-handle{position:absolute;right:-3px;top:0;bottom:0;width:6px;background:var(--primary);opacity:0;cursor:col-resize;z-index:20;border-radius:2px;transition:opacity .15s}.tiptap table:hover .column-resize-handle{opacity:.4}.tiptap .column-resize-handle:hover{opacity:1}.tiptap.resize-cursor{cursor:col-resize}.tableWrapper{overflow-x:auto;overflow-y:hidden;margin:1em 0;max-width:100%;padding-right:4px}.tiptap table .grip-column,.tiptap table .grip-row,.tiptap table .grip-table{display:none!important}.tiptap .is-empty:before{content:attr(data-placeholder);float:left;color:var(--muted-foreground);opacity:.5;pointer-events:none;height:0}.tiptap h1.is-empty:before{font-size:2rem;font-weight:700}.tiptap h2.is-empty:before{font-size:1.5rem;font-weight:600}.tiptap h3.is-empty:before{font-size:1.25rem;font-weight:600}.ProseMirror-gapcursor{display:none;pointer-events:none;position:relative}.ProseMirror-gapcursor:after{content:"";display:block;position:absolute;top:-2px;width:20px;border-top:1px solid var(--foreground);animation:ProseMirror-cursor-blink 1.1s steps(2,start) infinite}@keyframes ProseMirror-cursor-blink{to{visibility:hidden}}.ProseMirror-focused .ProseMirror-gapcursor{display:block}.ProseMirror-dropcursor{border-top:2px solid var(--primary);margin:-1px 0}.tiptap ::-moz-selection{background-color:color-mix(in srgb,var(--primary) 15%,transparent)}.tiptap ::selection{background-color:color-mix(in srgb,var(--primary) 15%,transparent)}.ProseMirror-noderangeselection ::-moz-selection{background:transparent}.ProseMirror-noderangeselection ::selection{background:transparent}.ProseMirror-noderangeselection *{caret-color:transparent}.ProseMirror-selectednode,.ProseMirror-selectednoderange{position:relative}.ProseMirror-selectednode:not(img):not([data-type=pdfBlock]):before,.ProseMirror-selectednoderange:not([data-type=pdfBlock]):before{content:"";position:absolute;inset:-.25rem;background-color:color-mix(in srgb,var(--primary) 10%,transparent);border:2px solid color-mix(in srgb,var(--primary) 30%,transparent);border-radius:.5rem;pointer-events:none;z-index:-1}.bubble-toolbar-container{z-index:50}.hce-floating-plus{display:flex;align-items:center;justify-content:center;width:24px;height:24px;border-radius:6px;border:1px solid var(--border);background:var(--background);color:var(--muted-foreground);cursor:pointer;transition:all .15s}.hce-floating-plus:hover{color:var(--foreground);border-color:var(--foreground);background:var(--muted)}.hce-drag-handle{display:flex;align-items:center;gap:2px}.hce-drag-handle__plus{display:flex;align-items:center;justify-content:center;padding:4px;border-radius:4px;border:none;background:transparent;color:var(--muted-foreground);opacity:.5;cursor:pointer;transition:opacity .15s,background-color .15s}.hce-drag-handle__plus:hover{opacity:1;background:var(--muted)}.hce-drag-handle__grip{display:flex;align-items:center;justify-content:center;padding:2px;border-radius:4px;color:var(--muted-foreground);opacity:.5;cursor:grab;transition:opacity .15s,background-color .15s}.hce-drag-handle__grip:hover{opacity:1;background:var(--muted)}.hce-drag-handle__grip:active{cursor:grabbing}.tiptap div[data-type=columns]{display:grid;gap:16px;margin:1em 0}.tiptap div[data-type=columns][data-columns="2"]{grid-template-columns:1fr 1fr}.tiptap div[data-type=columns][data-columns="3"]{grid-template-columns:1fr 1fr 1fr}.tiptap div[data-type=column]{min-width:0;padding:4px 6px;border:1px dashed var(--border);border-radius:8px}.tiptap[contenteditable=true] div[data-type=column]:focus-within{border-color:var(--primary);border-style:solid}.tiptap div[data-type=columns].ProseMirror-selectednode{outline:2px solid color-mix(in srgb,var(--primary) 30%,transparent);border-radius:8px}@media (max-width:640px){.tiptap div[data-type=columns]{grid-template-columns:1fr!important}}.hce-editor-wrapper button[data-tooltip]{position:relative}.hce-editor-wrapper button[data-tooltip]:hover:after{content:attr(data-tooltip);position:absolute;top:100%;left:50%;transform:translateX(-50%);margin-top:6px;padding:4px 8px;font-size:11px;line-height:1.2;white-space:nowrap;color:#fff;background:#1e293b;border-radius:6px;pointer-events:none;z-index:60}.hce-table-btn-wrap{position:relative;display:inline-flex}.hce-table-btn-tooltip{position:absolute;bottom:100%;left:50%;transform:translateX(-50%);margin-bottom:6px;padding:4px 8px;font-size:11px;line-height:1.2;white-space:nowrap;color:#fff;background:#1e293b;border-radius:6px;pointer-events:none;opacity:0;transition:opacity .15s;z-index:60}.hce-table-btn-wrap:hover .hce-table-btn-tooltip{opacity:1}.hce-card-frame,.tiptap [data-type=card]{position:relative}.hce-card-frame{box-sizing:border-box;width:100%;margin:12px 0;padding:26px 30px;display:flex;flex-direction:column;justify-content:center;gap:12px;overflow:hidden;border:1px solid hsla(0,0%,100%,.52);border-radius:8px;box-shadow:inset 0 0 0 1px hsla(0,0%,100%,.28),0 8px 24px rgba(15,23,42,.08);overflow-wrap:anywhere;isolation:isolate}.hce-card-frame:before{content:"";position:absolute;inset:0;z-index:0;background:linear-gradient(90deg,hsla(0,0%,100%,.14),hsla(0,0%,100%,.04) 48%,rgba(15,23,42,.08));pointer-events:none}.hce-card-content{position:relative;z-index:1;box-sizing:border-box;width:100%;max-height:100%;min-height:0;padding:18px 20px;display:flex;flex-direction:column;gap:10px;overflow:hidden;border:1px solid hsla(0,0%,100%,.56);border-radius:8px;background:hsla(0,0%,100%,.82);color:#111827;box-shadow:0 14px 42px rgba(15,23,42,.12),inset 0 1px 0 hsla(0,0%,100%,.52);backdrop-filter:blur(18px) saturate(1.16);-webkit-backdrop-filter:blur(18px) saturate(1.16)}@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){.hce-card-content{background:hsla(0,0%,100%,.9)}}.hce-card-header{flex:0 0 auto}.hce-card-title{margin:0;font-size:1.65rem;font-weight:700;line-height:1.18;color:#111827}.hce-card-title[hidden]{display:none}.hce-card-title-input{box-sizing:border-box;width:100%;padding:8px 12px;border:1px solid rgba(17,24,39,.12);border-radius:6px;background:hsla(0,0%,100%,.7);color:#111827;font:inherit;font-size:1.15rem;font-weight:700;outline:none}.hce-card-title-input:focus{border-color:var(--primary,#3382f2)}.hce-card-body{flex:1 1 auto;min-height:0;overflow:auto;font-size:1rem;line-height:1.55;color:#111827}.hce-card-body>p:first-child{margin-top:0}.hce-card-body>p:last-child{margin-bottom:0}.hce-card-bg-button{position:absolute;top:8px;right:8px;z-index:3;padding:4px 10px;border:1px solid rgba(17,24,39,.12);border-radius:6px;background:hsla(0,0%,100%,.86);color:#111827;font-size:.8125rem;line-height:1.4;cursor:pointer}.hce-card-bg-button:hover{background:#fff}@media (max-width:640px){.hce-card-frame{padding:18px}.hce-card-content{padding:14px 16px}.hce-card-title{font-size:1.35rem}}.hce-active{background-color:color-mix(in srgb,var(--primary) 12%,transparent);color:var(--primary)}.hce-active:hover{background-color:color-mix(in srgb,var(--primary) 18%,transparent)}.hover\:scale-105:hover{--tw-scale-x:1.05;--tw-scale-y:1.05}.hover\:scale-105:hover,.hover\:scale-110:hover{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:scale-110:hover{--tw-scale-x:1.1;--tw-scale-y:1.1}.hover\:bg-muted:hover{background-color:var(--muted)}.hover\:bg-white\/10:hover{background-color:hsla(0,0%,100%,.1)}.hover\:text-destructive:hover{color:var(--destructive)}.hover\:text-foreground:hover{color:var(--foreground)}.hover\:text-red-300:hover{--tw-text-opacity:1;color:rgb(252 165 165/var(--tw-text-opacity,1))}.hover\:text-white:hover{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-90:hover{opacity:.9}.focus\:border-primary:focus{border-color:var(--primary)}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.disabled\:opacity-30:disabled{opacity:.3}
|
package/dist/types.d.ts
CHANGED
|
@@ -13,7 +13,14 @@ export type PromptHandler = (defaultValue: string) => Promise<string | null>;
|
|
|
13
13
|
export type ToolbarMode = 'minimal' | 'standard' | 'full';
|
|
14
14
|
/** 개별 툴바 기능 ID */
|
|
15
15
|
export type ToolbarFeature = 'bold' | 'italic' | 'underline' | 'strike' | 'highlight' | 'superscript' | 'subscript' | 'code' | 'text-color' | 'align-left' | 'align-center' | 'align-right' | 'paragraph' | 'h1' | 'h2' | 'h3' | 'bullet-list' | 'ordered-list' | 'checklist' | 'blockquote' | 'horizontal-rule' | 'toggle' | 'link' | 'image' | 'pdf' | 'file' | 'mbus' | 'card' | 'columns-2' | 'columns-3' | 'table' | 'code-block' | 'undo' | 'redo' | 'fixed-toolbar' | 'bubble-toolbar' | 'slash-menu' | 'table-menu' | 'character-count' | 'upload-overlay';
|
|
16
|
-
/**
|
|
16
|
+
/**
|
|
17
|
+
* 모드별 기본 feature 프리셋.
|
|
18
|
+
*
|
|
19
|
+
* ⚠️ `'card'` 는 **일부러 빠져 있다.** 실제로 안 쓰여서 삽입 메뉴와 슬래시 메뉴에서
|
|
20
|
+
* 내렸다(사용자 요청). 다만 **확장 자체는 계속 등록된다** — 빼면 이미 카드가 들어간
|
|
21
|
+
* 문서가 열릴 때 노드를 못 알아보고 내용이 날아간다. 넣는 길만 닫은 것이라,
|
|
22
|
+
* 쓰고 싶은 호스트는 `features` 에 `'card'` 를 직접 넣으면 그대로 살아난다.
|
|
23
|
+
*/
|
|
17
24
|
export declare const TOOLBAR_PRESETS: Record<ToolbarMode, ToolbarFeature[]>;
|
|
18
25
|
/** features 배열 → Set 변환. features가 있으면 그걸 쓰고 없으면 toolbar 모드 프리셋 */
|
|
19
26
|
export declare function resolveFeatures(toolbar: ToolbarMode, features?: ToolbarFeature[]): Set<ToolbarFeature>;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAEhE,+BAA+B;AAC/B,MAAM,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAE5D;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;AAE7E,YAAY;AACZ,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;AAE1D,kBAAkB;AAClB,MAAM,MAAM,cAAc,GAEvB,MAAM,GAAG,QAAQ,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,GACxD,aAAa,GAAG,WAAW,GAAG,MAAM,GAAG,YAAY,GAEnD,YAAY,GAAG,cAAc,GAAG,aAAa,GAE7C,WAAW,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAEhC,aAAa,GAAG,cAAc,GAAG,WAAW,GAC5C,YAAY,GAAG,iBAAiB,GAAG,QAAQ,GAE3C,MAAM,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAEnD,WAAW,GAAG,WAAW,GAAG,OAAO,GAAG,YAAY,GAElD,MAAM,GAAG,MAAM,GAEf,eAAe,GAAG,gBAAgB,GAAG,YAAY,GACjD,YAAY,GAAG,iBAAiB,GAAG,gBAAgB,CAAC;AAEvD
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAEhE,+BAA+B;AAC/B,MAAM,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAE5D;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;AAE7E,YAAY;AACZ,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;AAE1D,kBAAkB;AAClB,MAAM,MAAM,cAAc,GAEvB,MAAM,GAAG,QAAQ,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,GACxD,aAAa,GAAG,WAAW,GAAG,MAAM,GAAG,YAAY,GAEnD,YAAY,GAAG,cAAc,GAAG,aAAa,GAE7C,WAAW,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAEhC,aAAa,GAAG,cAAc,GAAG,WAAW,GAC5C,YAAY,GAAG,iBAAiB,GAAG,QAAQ,GAE3C,MAAM,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAEnD,WAAW,GAAG,WAAW,GAAG,OAAO,GAAG,YAAY,GAElD,MAAM,GAAG,MAAM,GAEf,eAAe,GAAG,gBAAgB,GAAG,YAAY,GACjD,YAAY,GAAG,iBAAiB,GAAG,gBAAgB,CAAC;AAEvD;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,WAAW,EAAE,cAAc,EAAE,CAgCjE,CAAC;AAEF,mEAAmE;AACnE,wBAAgB,eAAe,CAC9B,OAAO,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,cAAc,EAAE,GACzB,GAAG,CAAC,cAAc,CAAC,CAErB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uCAAuC;IACvC,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,uCAAuC;IACvC,aAAa,CAAC,EAAE,YAAY,CAAC;IAC7B,yFAAyF;IACzF,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,2CAA2C;IAC3C,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,0DAA0D;IAC1D,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,oDAAoD;IACpD,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,IAAI,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,SAAS,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC"}
|
package/dist/types.js
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* 모드별 기본 feature 프리셋.
|
|
3
|
+
*
|
|
4
|
+
* ⚠️ `'card'` 는 **일부러 빠져 있다.** 실제로 안 쓰여서 삽입 메뉴와 슬래시 메뉴에서
|
|
5
|
+
* 내렸다(사용자 요청). 다만 **확장 자체는 계속 등록된다** — 빼면 이미 카드가 들어간
|
|
6
|
+
* 문서가 열릴 때 노드를 못 알아보고 내용이 날아간다. 넣는 길만 닫은 것이라,
|
|
7
|
+
* 쓰고 싶은 호스트는 `features` 에 `'card'` 를 직접 넣으면 그대로 살아난다.
|
|
8
|
+
*/
|
|
2
9
|
export const TOOLBAR_PRESETS = {
|
|
3
10
|
full: [
|
|
4
11
|
'bold', 'italic', 'underline', 'strike', 'highlight',
|
|
@@ -7,7 +14,7 @@ export const TOOLBAR_PRESETS = {
|
|
|
7
14
|
'paragraph', 'h1', 'h2', 'h3',
|
|
8
15
|
'bullet-list', 'ordered-list', 'checklist',
|
|
9
16
|
'blockquote', 'horizontal-rule', 'toggle',
|
|
10
|
-
'link', 'image', 'pdf', 'file', 'mbus',
|
|
17
|
+
'link', 'image', 'pdf', 'file', 'mbus',
|
|
11
18
|
'columns-2', 'columns-3', 'table', 'code-block',
|
|
12
19
|
'undo', 'redo',
|
|
13
20
|
'fixed-toolbar', 'slash-menu',
|
|
@@ -19,7 +26,7 @@ export const TOOLBAR_PRESETS = {
|
|
|
19
26
|
'paragraph', 'h1', 'h2', 'h3',
|
|
20
27
|
'bullet-list', 'ordered-list', 'checklist',
|
|
21
28
|
'blockquote', 'horizontal-rule', 'toggle',
|
|
22
|
-
'link', 'image', 'pdf', 'file', 'mbus',
|
|
29
|
+
'link', 'image', 'pdf', 'file', 'mbus',
|
|
23
30
|
'columns-2', 'columns-3', 'table', 'code-block',
|
|
24
31
|
'fixed-toolbar', 'slash-menu', 'table-menu'
|
|
25
32
|
],
|