@teriusu/rich-editor 0.9.6 → 0.9.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/components/BubbleToolbar.svelte +102 -49
  2. package/dist/components/BubbleToolbar.svelte.d.ts.map +1 -1
  3. package/dist/components/FixedToolbar.svelte +136 -214
  4. package/dist/components/FixedToolbar.svelte.d.ts +9 -1
  5. package/dist/components/FixedToolbar.svelte.d.ts.map +1 -1
  6. package/dist/components/InputModal.svelte +1 -1
  7. package/dist/components/MathModal.svelte +111 -1
  8. package/dist/components/MathModal.svelte.d.ts.map +1 -1
  9. package/dist/components/MediaPickerModal.svelte +206 -0
  10. package/dist/components/MediaPickerModal.svelte.d.ts +18 -0
  11. package/dist/components/MediaPickerModal.svelte.d.ts.map +1 -0
  12. package/dist/components/SlashCommandMenu.svelte +114 -13
  13. package/dist/components/SlashCommandMenu.svelte.d.ts +10 -1
  14. package/dist/components/SlashCommandMenu.svelte.d.ts.map +1 -1
  15. package/dist/components/TableBubbleMenu.svelte +71 -48
  16. package/dist/components/TableBubbleMenu.svelte.d.ts.map +1 -1
  17. package/dist/components/TipTapEditor.svelte +163 -24
  18. package/dist/components/TipTapEditor.svelte.d.ts +2 -0
  19. package/dist/components/TipTapEditor.svelte.d.ts.map +1 -1
  20. package/dist/extensions/NotionInputRules.d.ts +59 -0
  21. package/dist/extensions/NotionInputRules.d.ts.map +1 -0
  22. package/dist/extensions/NotionInputRules.js +141 -0
  23. package/dist/extensions/NotionInputRules.test.d.ts +2 -0
  24. package/dist/extensions/NotionInputRules.test.d.ts.map +1 -0
  25. package/dist/extensions/NotionInputRules.test.js +117 -0
  26. package/dist/extensions/VideoEmbed.d.ts +36 -0
  27. package/dist/extensions/VideoEmbed.d.ts.map +1 -0
  28. package/dist/extensions/VideoEmbed.js +246 -0
  29. package/dist/extensions/VideoEmbed.test.d.ts +2 -0
  30. package/dist/extensions/VideoEmbed.test.d.ts.map +1 -0
  31. package/dist/extensions/VideoEmbed.test.js +57 -0
  32. package/dist/index.d.ts +1 -0
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +13 -0
  35. package/dist/styles/editor.css +1 -1
  36. package/dist/types.d.ts +14 -2
  37. package/dist/types.d.ts.map +1 -1
  38. package/dist/types.js +20 -6
  39. package/dist/utils/lowlight.d.ts +17 -0
  40. package/dist/utils/lowlight.d.ts.map +1 -0
  41. package/dist/utils/lowlight.js +106 -0
  42. package/dist/utils/lowlight.test.d.ts +2 -0
  43. package/dist/utils/lowlight.test.d.ts.map +1 -0
  44. package/dist/utils/lowlight.test.js +56 -0
  45. package/dist/utils/sanitize.d.ts.map +1 -1
  46. package/dist/utils/sanitize.js +14 -0
  47. package/dist/utils/splitCell.d.ts +20 -0
  48. package/dist/utils/splitCell.d.ts.map +1 -0
  49. package/dist/utils/splitCell.js +74 -0
  50. package/dist/utils/table.d.ts +22 -0
  51. package/dist/utils/table.d.ts.map +1 -0
  52. package/dist/utils/table.js +68 -0
  53. package/package.json +6 -1
@@ -0,0 +1,57 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { toEmbedUrl } from "./VideoEmbed";
3
+ /*
4
+ * 이 변환이 이 확장의 전부다. 틀리면 유튜브가 `X-Frame-Options` 로 거부해 **빈 칸**만
5
+ * 남고, 화면에는 아무 단서도 안 나온다. 그래서 사람들이 실제로 붙여넣는 꼴을 모아 둔다.
6
+ */
7
+ describe("toEmbedUrl", () => {
8
+ it("watch?v= 주소를 임베드 주소로 바꾼다", () => {
9
+ expect(toEmbedUrl("https://www.youtube.com/watch?v=dQw4w9WgXcQ")).toBe("https://www.youtube.com/embed/dQw4w9WgXcQ");
10
+ });
11
+ it("youtu.be 단축 주소도 받는다", () => {
12
+ expect(toEmbedUrl("https://youtu.be/dQw4w9WgXcQ")).toBe("https://www.youtube.com/embed/dQw4w9WgXcQ");
13
+ });
14
+ it("shorts·live 도 같은 임베드 주소가 된다", () => {
15
+ expect(toEmbedUrl("https://www.youtube.com/shorts/abc12345678")).toBe("https://www.youtube.com/embed/abc12345678");
16
+ expect(toEmbedUrl("https://www.youtube.com/live/abc12345678")).toBe("https://www.youtube.com/embed/abc12345678");
17
+ });
18
+ it("모바일·뮤직·nocookie 호스트도 알아본다", () => {
19
+ expect(toEmbedUrl("https://m.youtube.com/watch?v=abc12345678")).toBe("https://www.youtube.com/embed/abc12345678");
20
+ expect(toEmbedUrl("https://music.youtube.com/watch?v=abc12345678")).toBe("https://www.youtube.com/embed/abc12345678");
21
+ });
22
+ it("타임스탬프를 start 초로 옮긴다", () => {
23
+ expect(toEmbedUrl("https://youtu.be/abc12345678?t=90")).toBe("https://www.youtube.com/embed/abc12345678?start=90");
24
+ // `1m30s` 꼴도 같은 90초여야 한다
25
+ expect(toEmbedUrl("https://www.youtube.com/watch?v=abc12345678&t=1m30s")).toBe("https://www.youtube.com/embed/abc12345678?start=90");
26
+ expect(toEmbedUrl("https://youtu.be/abc12345678?t=1h2m3s")).toBe("https://www.youtube.com/embed/abc12345678?start=3723");
27
+ });
28
+ it("재생목록은 유지한다", () => {
29
+ expect(toEmbedUrl("https://www.youtube.com/watch?v=abc12345678&list=PL123")).toBe("https://www.youtube.com/embed/abc12345678?list=PL123");
30
+ });
31
+ it("이미 임베드 주소면 그대로 둔다", () => {
32
+ expect(toEmbedUrl("https://www.youtube.com/embed/abc12345678")).toBe("https://www.youtube.com/embed/abc12345678");
33
+ });
34
+ it("Vimeo 를 플레이어 주소로 바꾼다", () => {
35
+ expect(toEmbedUrl("https://vimeo.com/123456789")).toBe("https://player.vimeo.com/video/123456789");
36
+ expect(toEmbedUrl("https://vimeo.com/channels/staffpicks/123456789")).toBe("https://player.vimeo.com/video/123456789");
37
+ // 이미 플레이어 주소면 손대지 않는다
38
+ expect(toEmbedUrl("https://player.vimeo.com/video/123456789")).toBe("https://player.vimeo.com/video/123456789");
39
+ });
40
+ /*
41
+ * ⚠️ **모르는 주소는 손대지 않는다.** mbus 처럼 그 자체가 플레이어인 주소나 사내
42
+ * 플레이어를 쓰는 경우를 막지 않기 위해서다.
43
+ */
44
+ it("아는 서비스가 아니면 그대로 돌려준다", () => {
45
+ const mbus = "https://play.mbus.tv/v1/hls/abc?label=x&start=&volume=50";
46
+ expect(toEmbedUrl(mbus)).toBe(mbus);
47
+ });
48
+ it("주소로 파싱되지 않는 입력도 떨어뜨리지 않는다", () => {
49
+ expect(toEmbedUrl("그냥 글자")).toBe("그냥 글자");
50
+ expect(toEmbedUrl(" ")).toBe("");
51
+ });
52
+ it("id 를 못 뽑으면 원본을 지킨다", () => {
53
+ // `v` 가 없는 watch 주소 — 임의로 잘라내면 엉뚱한 곳을 가리키게 된다
54
+ const weird = "https://www.youtube.com/watch?foo=bar";
55
+ expect(toEmbedUrl(weird)).toBe(weird);
56
+ });
57
+ });
package/dist/index.d.ts CHANGED
@@ -23,6 +23,7 @@ export { configurePdfJs, getPdfJs } from "./utils/pdf";
23
23
  export { attachResize } from "./utils/resize";
24
24
  export type { AttachResizeOptions, ResizeAxis } from "./utils/resize";
25
25
  export { cn } from "./utils/cn";
26
+ export { lowlight, CODE_LANGUAGES } from "./utils/lowlight";
26
27
  export type { TipTapEditorProps, UploadHandler, ToolbarMode, ToolbarFeature, FixedToolbarProps, BlockHandleProps, SlashCommandMenuProps, PdfViewerProps, SlashMenuItem, } from "./types";
27
28
  export { TOOLBAR_PRESETS, resolveFeatures } from "./types";
28
29
  //# sourceMappingURL=index.d.ts.map
@@ -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,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,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,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;AAGhC,YAAY,EACV,iBAAiB,EACjB,aAAa,EACb,WAAW,EACX,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,qBAAqB,EACrB,cAAc,EACd,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;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,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,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,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,cAAc,EACd,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC"}
package/dist/index.js CHANGED
@@ -22,4 +22,17 @@ export { sanitizeHtml, stripHtmlToExcerpt, transformLegacyHtml } from "./utils/s
22
22
  export { configurePdfJs, getPdfJs } from "./utils/pdf";
23
23
  export { attachResize } from "./utils/resize";
24
24
  export { cn } from "./utils/cn";
25
+ /*
26
+ * 코드 하이라이터. **소비 앱도 이걸 가져다 쓴다** — 앱이 따로 `createLowlight(all)` 을
27
+ * 부르면 언어 목록이 두 벌이 되고(번들에도 두 벌), 어느 쪽을 고쳐야 하는지 흐려진다.
28
+ * 자동 감지 후보를 좁히고 싶으면 이 인스턴스를 감싸면 된다(정올 `code/index.ts` 가 그렇게 한다).
29
+ *
30
+ * ⚠️ **앱에서는 이 배럴 말고 `@teriusu/rich-editor/lowlight` 를 쓸 것.**
31
+ * 여기(`index.ts`)를 타면 하이라이터 하나 때문에 **에디터 전체가 함께 로드**된다.
32
+ * 실제로 정올이 이 경로로 가져갔다가 SSR 이 통째로 500 이 났다 — 앱 트리의
33
+ * `@tiptap/extension-list`(3.30) 와 `@tiptap/core`(3.22) 버전이 갈려 있어서
34
+ * `getPreviousBlockSibling` 미존재로 터졌다(문제 페이지 전부 오류 화면).
35
+ * 서브패스로 가져오면 `utils/lowlight.js` 만 로드돼 그 지뢰를 밟지 않는다.
36
+ */
37
+ export { lowlight, CODE_LANGUAGES } from "./utils/lowlight";
25
38
  export { TOOLBAR_PRESETS, resolveFeatures } from "./types";
@@ -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-2{margin-top:.5rem;margin-bottom:.5rem}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.ml-auto{margin-left:auto}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.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}.min-h-\[52px\]{min-height:52px}.w-10{width:2.5rem}.w-4{width:1rem}.w-\[360px\]{width:360px}.w-\[440px\]{width:440px}.w-fit{width:-moz-fit-content;width:fit-content}.w-full{width:100%}.w-px{width:1px}.min-w-0{min-width:0}.min-w-\[96px\]{min-width:96px}.max-w-\[90vw\]{max-width:90vw}.flex-1{flex:1 1 0%}.flex-shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.-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))}.\!transform{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))!important}.transform{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}.select-text{-webkit-user-select:text;-moz-user-select:text;user-select:text}.resize-y{resize:vertical}.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-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.break-all{word-break:break-all}.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-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-0\.5{padding-top:.125rem;padding-bottom:.125rem}.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}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-\[11px\]{font-size:11px}.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)}.leading-none{line-height:1}.text-destructive{color:var(--destructive)}.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}.blur{--tw-blur:blur(8px)}.blur,.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,.hce-table-bubble{z-index:var(--hce-menu-z,100)}.hce-menu-surface{background-color:var(--hce-menu-surface,#333)}.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}.tiptap math-inline,math-inline.math-node{display:inline-block;vertical-align:baseline}.tiptap math-display,math-display.math-node{display:block;margin:.9em 0;text-align:center}.math-node,.tiptap .math-node{font-size:.95em}.tiptap math-inline.math-node .katex,math-inline.math-node .katex{font-size:1.0285em}.tiptap[contenteditable=true] .math-node{cursor:pointer;border-radius:4px;transition:background-color .12s}.tiptap[contenteditable=true] .math-node:hover{background-color:color-mix(in srgb,var(--primary) 10%,transparent)}.tiptap .math-node.ProseMirror-selectednode{background-color:color-mix(in srgb,var(--primary) 18%,transparent);outline:1px solid color-mix(in srgb,var(--primary) 45%,transparent)}.tiptap .math-node.empty-math .math-placeholder{font-size:.85em;padding:0 .35em;color:var(--muted-foreground);border:1px dashed var(--border);border-radius:4px}.math-node .math-error,.tiptap .math-error{color:#dc2626;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.9em}.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\:border-ring:hover{border-color:var(--ring)}.hover\:bg-background:hover{background-color:var(--background)}.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\:border-ring:focus{border-color:var(--ring)}.focus\:text-foreground:focus{color:var(--foreground)}.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-2{margin-top:.5rem;margin-bottom:.5rem}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.ml-auto{margin-left:auto}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.block{display:block}.inline{display:inline}.flex{display:flex}.\!table{display:table!important}.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-px{height:1px}.min-h-\[52px\]{min-height:52px}.w-10{width:2.5rem}.w-4{width:1rem}.w-\[360px\]{width:360px}.w-\[420px\]{width:420px}.w-\[440px\]{width:440px}.w-fit{width:-moz-fit-content;width:fit-content}.w-full{width:100%}.w-px{width:1px}.min-w-0{min-width:0}.min-w-\[96px\]{min-width:96px}.max-w-\[90vw\]{max-width:90vw}.flex-1{flex:1 1 0%}.flex-shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.-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))}.\!transform{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))!important}.transform{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}.select-text{-webkit-user-select:text;-moz-user-select:text;user-select:text}.resize-y{resize:vertical}.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-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.break-all{word-break:break-all}.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)}.bg-background{background-color:var(--background)}.bg-black\/40{background-color:rgba(0,0,0,.4)}.bg-border{background-color:var(--border)}.bg-muted{background-color:var(--muted)}.bg-popover{background-color:var(--popover)}.bg-primary{background-color:var(--primary)}.bg-transparent{background-color:transparent}.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-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.pt-2{padding-top:.5rem}.pt-3{padding-top:.75rem}.text-left{text-align:left}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-\[11px\]{font-size:11px}.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)}.leading-none{line-height:1}.text-destructive{color:var(--destructive)}.text-foreground{color:var(--foreground)}.text-muted-foreground{color:var(--muted-foreground)}.text-primary{color:var(--primary)}.text-primary-foreground{color:var(--primary-foreground)}.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}.blur{--tw-blur:blur(8px)}.blur,.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 var(--border)}.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}.bubble-toolbar-container .hce-btn-primary,.hce-editor-wrapper .hce-btn-primary,.slash-menu .hce-btn-primary{background-color:var(--primary);color:var(--primary-foreground,#fff)}.tiptap{font-size:1.0625rem;line-height:1.8;color:var(--foreground);padding:1.5rem}.tiptap>*+*{margin-top:.25em}.tiptap [data-type=column]>:first-child,.tiptap [data-type=detailsContent]>:first-child,.tiptap blockquote>:first-child,.tiptap li>:first-child,.tiptap td>:first-child,.tiptap th>:first-child,.tiptap>:first-child{margin-top:0}.tiptap [data-type=column]>:last-child,.tiptap [data-type=detailsContent]>:last-child,.tiptap blockquote>:last-child,.tiptap li>:last-child,.tiptap td>:last-child,.tiptap th>:last-child,.tiptap>:last-child{margin-bottom:0}.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:30px 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:22px;height:22px;display:inline-flex;align-items:center;justify-content:center;color:var(--muted-foreground);border-radius:4px;transition:transform .2s,color .15s,background-color .15s;flex-shrink:0;margin-top:14px;margin-left:4px}.tiptap [data-type=details]>button:hover{background:color-mix(in srgb,var(--foreground) 8%,transparent)}.tiptap [data-type=details]>button:after{content:"";display:block;width:0;height:0;border-left:7px solid;border-top:5.5px solid transparent;border-bottom:5.5px 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=details] summary[data-level="1"],.tiptap details summary[data-level="1"]{font-size:2rem;font-weight:700;line-height:1.25}.tiptap [data-type=details] summary[data-level="2"],.tiptap details summary[data-level="2"]{font-size:1.5rem;font-weight:600;line-height:1.3}.tiptap [data-type=details] summary[data-level="3"],.tiptap details summary[data-level="3"]{font-size:1.25rem;font-weight:600;line-height:1.35}.tiptap [data-type=details]:has(>div>summary[data-level="1"])>button{margin-top:19px}.tiptap [data-type=details]:has(>div>summary[data-level="2"])>button{margin-top:15px}.tiptap [data-type=details]:has(>div>summary[data-level="3"])>button{margin-top:13px}.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:7px solid var(--muted-foreground);border-top:5.5px solid transparent;border-bottom:5.5px 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:-1px;bottom:-1px;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}.hce-table-bubble{z-index:var(--hce-menu-z,100)}.bubble-toolbar-container{position:absolute;top:0;left:0;width:-moz-max-content;width:max-content;z-index:calc(var(--hce-menu-z, 100) + 1)}.hce-toolbar:has(.absolute)~.bubble-toolbar-container,.hce-toolbar:has(.absolute)~.hce-table-bubble{display:none}.hce-menu-surface{background-color:var(--hce-menu-surface,#333)}.hce-floating-panel{background-color:color-mix(in srgb,var(--foreground) 8%,var(--popover,var(--background,#fff)));border:1px solid color-mix(in srgb,var(--foreground) 18%,var(--border));box-shadow:0 8px 24px color-mix(in srgb,var(--foreground) 16%,transparent),0 2px 6px color-mix(in srgb,var(--foreground) 10%,transparent)}.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-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-table-btn-wrap.hce-tooltip-off:hover .hce-table-btn-tooltip{opacity:0}.tiptap math-inline,math-inline.math-node{display:inline-block;vertical-align:baseline}.tiptap math-display,math-display.math-node{display:block;margin:.9em 0;text-align:center}.math-node,.tiptap .math-node{font-size:.95em}.tiptap math-inline.math-node .katex,math-inline.math-node .katex{font-size:1.0285em}.tiptap[contenteditable=true] .math-node{cursor:pointer;border-radius:4px;transition:background-color .12s}.tiptap[contenteditable=true] .math-node:hover{background-color:color-mix(in srgb,var(--primary) 10%,transparent)}.tiptap .math-node.ProseMirror-selectednode{background-color:color-mix(in srgb,var(--primary) 18%,transparent);outline:1px solid color-mix(in srgb,var(--primary) 45%,transparent)}.tiptap .math-node.empty-math .math-placeholder{font-size:.85em;padding:0 .35em;color:var(--muted-foreground);border:1px dashed var(--border);border-radius:4px}.math-node .math-error,.tiptap .math-error{color:#dc2626;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.9em}.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\:border-ring:hover{border-color:var(--ring)}.hover\:bg-background:hover{background-color:var(--background)}.hover\:bg-muted:hover{background-color:var(--muted)}.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\:underline:hover{text-decoration-line:underline}.hover\:opacity-90:hover{opacity:.9}.focus\:border-primary:focus{border-color:var(--primary)}.focus\:border-ring:focus{border-color:var(--ring)}.focus\:text-foreground:focus{color:var(--foreground)}.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,7 @@ export type PromptHandler = (defaultValue: string) => Promise<string | null>;
13
13
  /** 툴바 모드 */
14
14
  export type ToolbarMode = 'minimal' | 'standard' | 'full';
15
15
  /** 개별 툴바 기능 ID */
16
- 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' | 'math' | 'undo' | 'redo' | 'fixed-toolbar' | 'bubble-toolbar' | 'slash-menu' | 'table-menu' | 'character-count' | 'upload-overlay';
16
+ 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' | 'video' | 'card' | 'columns-2' | 'columns-3' | 'table' | 'code-block' | 'math' | 'undo' | 'redo' | 'fixed-toolbar' | 'bubble-toolbar' | 'slash-menu' | 'table-menu' | 'character-count' | 'upload-overlay';
17
17
  /**
18
18
  * 모드별 기본 feature 프리셋.
19
19
  *
@@ -25,6 +25,12 @@ export type ToolbarFeature = 'bold' | 'italic' | 'underline' | 'strike' | 'highl
25
25
  * ⚠️ `'math'` 는 **세 프리셋 모두**에 있다. 온라인저지라 댓글에도 `$O(n \log n)$` 이
26
26
  * 예사로 나오고, 무엇보다 `$…$` 입력 규칙과 붙여넣기 변환은 feature 와 무관하게 항상
27
27
  * 걸려 있어서(확장 자체가 그렇다) 여기서만 빼면 "쳐서 만들면 되는데 메뉴엔 없는" 상태가 된다.
28
+ *
29
+ * ⚠️ `'bubble-toolbar'` 도 이제 **세 프리셋 모두**에 있다. 예전엔 `minimal` 에만 있어서,
30
+ * 고정 툴바를 쓰는 곳(정올·코드패스의 기본인 `full`)에서는 **글자를 끌어 골라도 아무것도
31
+ * 안 떴다**(사용자 요청으로 켬). 고정 툴바와 겹쳐 보이지만 하는 일이 다르다 —
32
+ * 고정 툴바는 늘 같은 자리에 있고, 버블은 **고른 글자 바로 위**에 와서 손이 덜 움직인다.
33
+ * 버블은 선택이 비어 있으면 뜨지 않으므로(`shouldShow`) 평소에는 방해하지 않는다.
28
34
  */
29
35
  export declare const TOOLBAR_PRESETS: Record<ToolbarMode, ToolbarFeature[]>;
30
36
  /** features 배열 → Set 변환. features가 있으면 그걸 쓰고 없으면 toolbar 모드 프리셋 */
@@ -39,7 +45,13 @@ export interface TipTapEditorProps {
39
45
  onResolveFile?: FileResolver;
40
46
  /** 링크 URL 프롬프트. 미제공 시 내장 InputModal (FixedToolbar) / window.prompt (BubbleToolbar) 폴백 */
41
47
  onPromptLink?: PromptHandler;
42
- /** 이미지 URL 프롬프트. 미제공 시 내장 InputModal 폴백 */
48
+ /**
49
+ * 이미지 URL 프롬프트.
50
+ *
51
+ * ⚠️ **`onUploadFile` 을 함께 주면 이건 쓰이지 않는다.** 올릴 수 있는 호스트에게는
52
+ * 업로드/링크 탭이 있는 내장 모달을 띄우기 때문이다(URL 만 받으면 내 컴퓨터의 그림을
53
+ * 넣을 방법이 없다). 업로드를 못 하는 호스트에서만 폴백으로 쓰인다.
54
+ */
43
55
  onPromptImage?: PromptHandler;
44
56
  /** LaTeX 수식 프롬프트. 미제공 시 내장 MathModal(미리보기 포함) 폴백 */
45
57
  onPromptMath?: MathPrompt;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js CHANGED
@@ -9,19 +9,33 @@
9
9
  * ⚠️ `'math'` 는 **세 프리셋 모두**에 있다. 온라인저지라 댓글에도 `$O(n \log n)$` 이
10
10
  * 예사로 나오고, 무엇보다 `$…$` 입력 규칙과 붙여넣기 변환은 feature 와 무관하게 항상
11
11
  * 걸려 있어서(확장 자체가 그렇다) 여기서만 빼면 "쳐서 만들면 되는데 메뉴엔 없는" 상태가 된다.
12
+ *
13
+ * ⚠️ `'bubble-toolbar'` 도 이제 **세 프리셋 모두**에 있다. 예전엔 `minimal` 에만 있어서,
14
+ * 고정 툴바를 쓰는 곳(정올·코드패스의 기본인 `full`)에서는 **글자를 끌어 골라도 아무것도
15
+ * 안 떴다**(사용자 요청으로 켬). 고정 툴바와 겹쳐 보이지만 하는 일이 다르다 —
16
+ * 고정 툴바는 늘 같은 자리에 있고, 버블은 **고른 글자 바로 위**에 와서 손이 덜 움직인다.
17
+ * 버블은 선택이 비어 있으면 뜨지 않으므로(`shouldShow`) 평소에는 방해하지 않는다.
12
18
  */
13
19
  export const TOOLBAR_PRESETS = {
14
20
  full: [
21
+ /*
22
+ * ⚠️ `'superscript'`·`'subscript'` 는 **일부러 뺐다**(`'card'` 와 같은 방식).
23
+ * 여기는 수식(KaTeX)이 있어서 `x^2`·`a_i` 같은 표기를 수식이 거의 다 커버한다 —
24
+ * 굳이 같은 일을 하는 버튼을 인라인 그룹에 하나 더 두면 줄만 길어진다(사용자 결정).
25
+ * **확장은 계속 등록된다** — 빼면 이미 `<sup>`·`<sub>` 가 든 옛 문서를 열 때
26
+ * 그 표기가 통째로 날아간다. 넣는 길만 닫은 것이라, 쓰려는 호스트는 `features` 에
27
+ * 직접 넣으면 된다.
28
+ */
15
29
  'bold', 'italic', 'underline', 'strike', 'highlight',
16
- 'superscript', 'subscript', 'code', 'text-color',
30
+ 'code', 'text-color',
17
31
  'align-left', 'align-center', 'align-right',
18
32
  'paragraph', 'h1', 'h2', 'h3',
19
33
  'bullet-list', 'ordered-list', 'checklist',
20
34
  'blockquote', 'horizontal-rule', 'toggle',
21
- 'link', 'image', 'pdf', 'file', 'mbus',
35
+ 'link', 'image', 'pdf', 'file', 'mbus', 'video',
22
36
  'columns-2', 'columns-3', 'table', 'code-block', 'math',
23
37
  'undo', 'redo',
24
- 'fixed-toolbar', 'slash-menu',
38
+ 'fixed-toolbar', 'bubble-toolbar', 'slash-menu',
25
39
  'table-menu', 'character-count', 'upload-overlay'
26
40
  ],
27
41
  standard: [
@@ -30,16 +44,16 @@ export const TOOLBAR_PRESETS = {
30
44
  'paragraph', 'h1', 'h2', 'h3',
31
45
  'bullet-list', 'ordered-list', 'checklist',
32
46
  'blockquote', 'horizontal-rule', 'toggle',
33
- 'link', 'image', 'pdf', 'file', 'mbus',
47
+ 'link', 'image', 'pdf', 'file', 'mbus', 'video',
34
48
  'columns-2', 'columns-3', 'table', 'code-block', 'math',
35
- 'fixed-toolbar', 'slash-menu', 'table-menu'
49
+ 'fixed-toolbar', 'bubble-toolbar', 'slash-menu', 'table-menu'
36
50
  ],
37
51
  minimal: [
38
52
  'bold', 'italic', 'underline', 'strike', 'code', 'text-color',
39
53
  'paragraph', 'h2', 'h3',
40
54
  'bullet-list', 'ordered-list', 'checklist',
41
55
  'blockquote', 'code-block', 'math',
42
- 'link', 'image', 'file', 'pdf',
56
+ 'link', 'image', 'file', 'pdf', 'video',
43
57
  'bubble-toolbar', 'slash-menu'
44
58
  ]
45
59
  };
@@ -0,0 +1,17 @@
1
+ /** 등록하는 언어 이름. 테스트가 이 목록으로 실제 등록분을 검사한다. */
2
+ export declare const CODE_LANGUAGES: readonly ["cpp", "java", "python", "javascript", "typescript", "kotlin", "go", "csharp", "rust", "sql", "pgsql", "graphql", "xml", "css", "json", "yaml", "bash", "shell", "makefile", "ini", "diff"];
3
+ export declare const lowlight: {
4
+ highlight: (language: string, value: string, options?: Readonly<import("lowlight").Options> | null | undefined) => import("hast").Root;
5
+ highlightAuto: (value: string, options?: Readonly<import("lowlight").AutoOptions> | null | undefined) => import("hast").Root;
6
+ listLanguages: () => Array<string>;
7
+ register: {
8
+ (grammars: Readonly<Record<string, import("highlight.js").LanguageFn>>): undefined;
9
+ (name: string, grammar: import("highlight.js").LanguageFn): undefined;
10
+ };
11
+ registerAlias: {
12
+ (aliases: Readonly<Record<string, ReadonlyArray<string> | string>>): undefined;
13
+ (language: string, alias: ReadonlyArray<string> | string): undefined;
14
+ };
15
+ registered: (aliasOrName: string) => boolean;
16
+ };
17
+ //# sourceMappingURL=lowlight.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lowlight.d.ts","sourceRoot":"","sources":["../../src/utils/lowlight.ts"],"names":[],"mappings":"AAuDA,4CAA4C;AAC5C,eAAO,MAAM,cAAc,uMA0BjB,CAAC;AAEX,eAAO,MAAM,QAAQ;wDA3EL,CAAA;0CAGM,CAAC;;;;;;;;;;;CAwEiB,CAAC"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * 코드블록 문법 하이라이터. **앱 전체에 한 벌**이다.
3
+ *
4
+ * ── ⚠️ `common`(37종)·`all`(192종)을 쓰지 않는다 ──────────────────────────────
5
+ * lowlight 의 묶음 export 는 언어를 통째로 끌고 들어오고 **트리셰이킹이 되지 않는다**
6
+ * (전부 참조되기 때문). 정올 빌드 산출물을 실측하면 하이라이터 문법이 **한 청크에
7
+ * 402KB(gzip) / 1.2MB(raw)** 로 앉아 있었다 — 코드블록이 있는 문서를 열 때마다 받는다.
8
+ * 여기서 실제로 쓰이는 건 채점 언어 몇 개뿐이다.
9
+ *
10
+ * 그래서 **필요한 것만 명시 등록**한다.
11
+ *
12
+ * 목록 근거 — **직접 고르거나 붙여넣을 만한 것**까지 넉넉히 잡았다. 언어 선택 UI 는
13
+ * `cpp·java·python` 셋뿐이지만, 저장된 문서에는 `language-sql` 처럼 다른 값이 들어 있을
14
+ * 수 있고 그때 색이 빠지면 눈에 띈다.
15
+ *
16
+ * · 채점·알고리즘 (9) cpp·java·python 과 그 밖의 흔한 언어
17
+ * · DB·질의 (3) hljs 에 있는 DB 계열은 이 셋이 전부다(`plsql`·`mongodb` 는 없다)
18
+ * · 웹·데이터 (4) `xml` 이 HTML 을 겸한다
19
+ * · 셸·설정 (5) 코드 예시에 딸려 오는 명령·설정 파일
20
+ *
21
+ * 스물하나를 다 넣어도 **40KB 대(gzip)** 다 — 묶음 export 는 398KB 였다. 크기 여유가
22
+ * 크므로 "혹시 쓸까" 싶은 것은 빼기보다 넣는 쪽이 낫다.
23
+ *
24
+ * ⚠️ **`c` 는 일부러 없다.** C++ 문법이 C 를 사실상 포함해 색이 거의 같은데, 자동 감지
25
+ * 후보에 넣으면 relevance 를 과하게 먹어 **Python 코드까지 `c` 로 판정**했다(실측).
26
+ * `language-c` 로 지정된 블록은 자동 감지로 떨어져 `cpp` 로 칠해진다 — 눈으로는 같다.
27
+ *
28
+ * ⚠️ **여기 없는 언어는 색이 빠진다** — 깨지지는 않고 평범한 글자로 나온다.
29
+ * 늘려야 할 언어가 생기면 이 목록에 추가한다. `common`/`all` 로 되돌리지 말 것.
30
+ * ⚠️ `js`·`ts`·`c++` 같은 짧은 이름은 문법 정의가 자기 `aliases` 로 갖고 있어 따로
31
+ * 등록하지 않아도 인식된다.
32
+ */
33
+ import { createLowlight } from "lowlight";
34
+ import cpp from "highlight.js/lib/languages/cpp";
35
+ import java from "highlight.js/lib/languages/java";
36
+ import python from "highlight.js/lib/languages/python";
37
+ import javascript from "highlight.js/lib/languages/javascript";
38
+ import typescript from "highlight.js/lib/languages/typescript";
39
+ import kotlin from "highlight.js/lib/languages/kotlin";
40
+ import go from "highlight.js/lib/languages/go";
41
+ import csharp from "highlight.js/lib/languages/csharp";
42
+ import rust from "highlight.js/lib/languages/rust";
43
+ import sql from "highlight.js/lib/languages/sql";
44
+ import pgsql from "highlight.js/lib/languages/pgsql";
45
+ import graphql from "highlight.js/lib/languages/graphql";
46
+ import xml from "highlight.js/lib/languages/xml";
47
+ import css from "highlight.js/lib/languages/css";
48
+ import json from "highlight.js/lib/languages/json";
49
+ import yaml from "highlight.js/lib/languages/yaml";
50
+ import bash from "highlight.js/lib/languages/bash";
51
+ import shell from "highlight.js/lib/languages/shell";
52
+ import makefile from "highlight.js/lib/languages/makefile";
53
+ import ini from "highlight.js/lib/languages/ini";
54
+ import diff from "highlight.js/lib/languages/diff";
55
+ /** 등록하는 언어 이름. 테스트가 이 목록으로 실제 등록분을 검사한다. */
56
+ export const CODE_LANGUAGES = [
57
+ // 채점·알고리즘
58
+ "cpp",
59
+ "java",
60
+ "python",
61
+ "javascript",
62
+ "typescript",
63
+ "kotlin",
64
+ "go",
65
+ "csharp",
66
+ "rust",
67
+ // DB·질의
68
+ "sql",
69
+ "pgsql",
70
+ "graphql",
71
+ // 웹·데이터 (`xml` 이 HTML 을 겸한다)
72
+ "xml",
73
+ "css",
74
+ "json",
75
+ "yaml",
76
+ // 셸·설정
77
+ "bash",
78
+ "shell",
79
+ "makefile",
80
+ "ini",
81
+ "diff",
82
+ ];
83
+ export const lowlight = createLowlight();
84
+ lowlight.register({
85
+ cpp,
86
+ java,
87
+ python,
88
+ javascript,
89
+ typescript,
90
+ kotlin,
91
+ go,
92
+ csharp,
93
+ rust,
94
+ sql,
95
+ pgsql,
96
+ graphql,
97
+ xml,
98
+ css,
99
+ json,
100
+ yaml,
101
+ bash,
102
+ shell,
103
+ makefile,
104
+ ini,
105
+ diff,
106
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=lowlight.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lowlight.test.d.ts","sourceRoot":"","sources":["../../src/utils/lowlight.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,56 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { lowlight, CODE_LANGUAGES } from "./lowlight";
3
+ /*
4
+ * 이 목록은 **번들 크기와 직결된다.** `common`(37종)·`all`(192종)로 되돌리면 하이라이터
5
+ * 문법만 402KB(gzip) 가 된다(정올 빌드 실측). 그래서 "몇 개가 실려 있는지"를 못박아,
6
+ * 나중에 무심코 묶음 export 로 되돌아가는 걸 테스트가 잡게 한다.
7
+ */
8
+ describe("코드 하이라이터 언어 목록", () => {
9
+ it("선언한 목록만 등록한다", () => {
10
+ expect(lowlight.listLanguages().sort()).toEqual([...CODE_LANGUAGES].sort());
11
+ });
12
+ it("묶음 export 로 되돌아가지 않았다 (common 37 · all 192)", () => {
13
+ expect(lowlight.listLanguages().length).toBe(CODE_LANGUAGES.length);
14
+ expect(lowlight.listLanguages().length).toBeLessThan(37);
15
+ });
16
+ /* 붙여넣기로 들어오는 대표 언어들 — 빠지면 색이 조용히 사라진다. */
17
+ it("DB 계열(sql·pgsql·graphql)이 들어 있다", () => {
18
+ for (const lang of ["sql", "pgsql", "graphql"]) {
19
+ expect(lowlight.registered(lang)).toBe(true);
20
+ }
21
+ });
22
+ it("웹·셸 계열(xml/html·css·json·bash)이 들어 있다", () => {
23
+ for (const lang of ["xml", "css", "json", "bash"]) {
24
+ expect(lowlight.registered(lang)).toBe(true);
25
+ }
26
+ // `xml` 이 HTML 을 겸한다
27
+ expect(lowlight.registered("html")).toBe(true);
28
+ });
29
+ it("채점 언어(cpp·java·python)는 반드시 들어 있다", () => {
30
+ for (const lang of ["cpp", "java", "python"]) {
31
+ expect(lowlight.registered(lang)).toBe(true);
32
+ }
33
+ });
34
+ /*
35
+ * ⚠️ `c` 는 일부러 없다 — C++ 문법이 C 를 사실상 포함하고, 자동 감지 후보에 넣으면
36
+ * relevance 를 과하게 먹어 Python 코드까지 `c` 로 판정했다(실측).
37
+ */
38
+ it("c 는 등록하지 않는다 (cpp 가 대신한다)", () => {
39
+ expect(lowlight.registered("c")).toBe(false);
40
+ expect(lowlight.registered("cpp")).toBe(true);
41
+ });
42
+ /*
43
+ * 짧은 이름은 문법 정의가 자기 `aliases` 로 갖고 있다. 따로 등록하지 않아도 되는지를
44
+ * 확인해 둔다 — 안 되면 저장된 `language-js` 코드블록이 색을 잃는다.
45
+ */
46
+ it("별칭(js·ts·c++)도 그대로 인식한다", () => {
47
+ expect(lowlight.registered("js")).toBe(true);
48
+ expect(lowlight.registered("ts")).toBe(true);
49
+ expect(lowlight.registered("c++")).toBe(true);
50
+ });
51
+ it("등록하지 않은 언어는 색이 없다(깨지지는 않는다)", () => {
52
+ expect(lowlight.registered("ruby")).toBe(false);
53
+ // 색을 못 입혀도 예외를 던지지 않고 평범한 텍스트로 남는지
54
+ expect(() => lowlight.highlightAuto("puts 'hi'")).not.toThrow();
55
+ });
56
+ });
@@ -1 +1 @@
1
- {"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../../src/utils/sanitize.ts"],"names":[],"mappings":"AAgDA,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAcjD;AA0BD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA8ExD;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,SAAM,GAAG,MAAM,CAWrE"}
1
+ {"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../../src/utils/sanitize.ts"],"names":[],"mappings":"AA8DA,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAcjD;AA0BD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA8ExD;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,SAAM,GAAG,MAAM,CAWrE"}
@@ -5,6 +5,14 @@ const ALLOWED_TAGS = new Set([
5
5
  "blockquote", "pre", "code", "img", "figure", "figcaption",
6
6
  "table", "colgroup", "col", "thead", "tbody", "tr", "th", "td",
7
7
  "span", "div", "hr", "sub", "sup",
8
+ /*
9
+ * ⚠️ **토글(접기)이 여기 빠져 있었다.** 저장본에서 토글은 네이티브
10
+ * `<details><summary>제목</summary><div>본문</div></details>` 로 내려가는데, 두 태그가
11
+ * 허용 목록에 없어서 살균을 거치면 **토글이 통째로 지워졌다.** 정올은 문항 목록에서
12
+ * 저장 HTML 을 `{@html}` 로 먼저 그리면서 이 함수를 태우므로(그쪽 `TipTap.svelte` 주석),
13
+ * 토글이 든 문항은 정적 렌더에서 내용이 사라졌다가 에디터가 서면 되돌아오는 상태였다.
14
+ */
15
+ "details", "summary",
8
16
  "tiptap-midibus",
9
17
  "math-inline", "math-display",
10
18
  ]);
@@ -31,11 +39,17 @@ const ALLOWED_ATTRS = {
31
39
  "data-file-size",
32
40
  "data-mbus-src",
33
41
  "data-mbus-width",
42
+ // 유튜브·Vimeo 등 바깥 영상(`VideoEmbed`). mbus 와 **다른 이름**을 쓴다.
43
+ "data-video-src",
44
+ "data-video-width",
34
45
  "data-card-title",
35
46
  "data-card-background",
36
47
  "data-card-height",
37
48
  "style",
38
49
  ]),
50
+ // 토글은 열린 채 저장될 수 있고(`persist`), 제목 단계는 `data-level` 로 들어간다.
51
+ details: new Set(["open", "data-type"]),
52
+ summary: new Set(["data-level"]),
39
53
  pre: new Set(["class"]),
40
54
  code: new Set(["class"]),
41
55
  "tiptap-midibus": new Set(["id", "start", "uuid", "width", "height"]),
@@ -0,0 +1,20 @@
1
+ import type { Editor } from "@tiptap/core";
2
+ /**
3
+ * 셀 분할 — **헤더 표시를 원래 자리로 되돌린다**.
4
+ *
5
+ * ⚠️ 기본 `splitCell()` 은 나눈 조각을 **원래 셀 타입 그대로** 만든다. 그런데 헤더 셀과
6
+ * 일반 셀을 병합하면 결과가 `tableHeader` 가 되므로, 그걸 다시 나누면 **원래 일반 셀이던
7
+ * 자리까지 전부 헤더로 남는다.** 그 상태는 `헤더 행/열 토글` 로도 못 고친다 — 그건 행·열
8
+ * 전체를 뒤집는 것이라 표 한가운데 남은 헤더 셀에는 닿지 않는다(사용자 지적: "헤더표시가
9
+ * 남아서 없앨수가 없어").
10
+ *
11
+ * 그래서 나눌 때 **자리에 맞는 타입**을 직접 정해 준다:
12
+ * · 표에 헤더 행이 있으면 → 첫 행 조각은 헤더
13
+ * · 표에 헤더 열이 있으면 → 첫 열 조각은 헤더
14
+ * · 그 밖은 전부 일반 셀
15
+ *
16
+ * ⚠️ "헤더 행이 있는가" 는 **병합에 끼지 않은 셀**로 판정한다. 병합 결과 셀은 그 자체가
17
+ * 헤더 타입일 수 있어서, 그걸 근거로 삼으면 "헤더가 있다" 고 잘못 읽는다.
18
+ */
19
+ export declare function splitCellPreservingHeaders(editor: Editor): boolean;
20
+ //# sourceMappingURL=splitCell.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"splitCell.d.ts","sourceRoot":"","sources":["../../src/utils/splitCell.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAI3C;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CA2DlE"}