@teriusu/rich-editor 0.10.8 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/dist/components/BubbleToolbar.svelte +40 -36
  2. package/dist/components/BubbleToolbar.svelte.d.ts +3 -0
  3. package/dist/components/BubbleToolbar.svelte.d.ts.map +1 -1
  4. package/dist/components/EmojiSuggestionMenu.svelte +291 -0
  5. package/dist/components/EmojiSuggestionMenu.svelte.d.ts +9 -0
  6. package/dist/components/EmojiSuggestionMenu.svelte.d.ts.map +1 -0
  7. package/dist/components/FixedToolbar.svelte +53 -47
  8. package/dist/components/FixedToolbar.svelte.d.ts +3 -0
  9. package/dist/components/FixedToolbar.svelte.d.ts.map +1 -1
  10. package/dist/components/FloatingHelper.svelte +219 -0
  11. package/dist/components/FloatingHelper.svelte.d.ts +14 -0
  12. package/dist/components/FloatingHelper.svelte.d.ts.map +1 -0
  13. package/dist/components/InputModal.svelte +7 -3
  14. package/dist/components/InputModal.svelte.d.ts +3 -0
  15. package/dist/components/InputModal.svelte.d.ts.map +1 -1
  16. package/dist/components/MathModal.svelte +33 -29
  17. package/dist/components/MathModal.svelte.d.ts +3 -0
  18. package/dist/components/MathModal.svelte.d.ts.map +1 -1
  19. package/dist/components/MediaPickerModal.svelte +7 -3
  20. package/dist/components/MediaPickerModal.svelte.d.ts +3 -0
  21. package/dist/components/MediaPickerModal.svelte.d.ts.map +1 -1
  22. package/dist/components/SlashCommandMenu.svelte +88 -72
  23. package/dist/components/SlashCommandMenu.svelte.d.ts +3 -0
  24. package/dist/components/SlashCommandMenu.svelte.d.ts.map +1 -1
  25. package/dist/components/TableBubbleMenu.svelte +41 -33
  26. package/dist/components/TableBubbleMenu.svelte.d.ts +3 -0
  27. package/dist/components/TableBubbleMenu.svelte.d.ts.map +1 -1
  28. package/dist/components/TipTapEditor.svelte +239 -127
  29. package/dist/components/TipTapEditor.svelte.d.ts +7 -0
  30. package/dist/components/TipTapEditor.svelte.d.ts.map +1 -1
  31. package/dist/extensions/CardBlock.d.ts.map +1 -1
  32. package/dist/extensions/CardBlock.js +6 -4
  33. package/dist/extensions/FileAttachment.d.ts.map +1 -1
  34. package/dist/extensions/FileAttachment.js +2 -1
  35. package/dist/extensions/FixedDetails.d.ts.map +1 -1
  36. package/dist/extensions/FixedDetails.js +5 -3
  37. package/dist/extensions/LegacyBlock.d.ts.map +1 -1
  38. package/dist/extensions/LegacyBlock.js +8 -6
  39. package/dist/extensions/Math.d.ts.map +1 -1
  40. package/dist/extensions/Math.js +5 -2
  41. package/dist/extensions/MbusVideo.d.ts.map +1 -1
  42. package/dist/extensions/MbusVideo.js +73 -9
  43. package/dist/extensions/MediaToolbar.d.ts +41 -0
  44. package/dist/extensions/MediaToolbar.d.ts.map +1 -0
  45. package/dist/extensions/MediaToolbar.js +196 -0
  46. package/dist/extensions/MediaToolbar.test.d.ts +2 -0
  47. package/dist/extensions/MediaToolbar.test.d.ts.map +1 -0
  48. package/dist/extensions/MediaToolbar.test.js +231 -0
  49. package/dist/extensions/OrderedListMarker.d.ts +2 -0
  50. package/dist/extensions/OrderedListMarker.d.ts.map +1 -0
  51. package/dist/extensions/OrderedListMarker.js +114 -0
  52. package/dist/extensions/OrderedListMarker.test.d.ts +2 -0
  53. package/dist/extensions/OrderedListMarker.test.d.ts.map +1 -0
  54. package/dist/extensions/OrderedListMarker.test.js +176 -0
  55. package/dist/extensions/PdfBlock.d.ts.map +1 -1
  56. package/dist/extensions/PdfBlock.js +25 -23
  57. package/dist/extensions/ResizableImage.d.ts.map +1 -1
  58. package/dist/extensions/ResizableImage.js +20 -1
  59. package/dist/extensions/TableKeymap.d.ts +16 -0
  60. package/dist/extensions/TableKeymap.d.ts.map +1 -0
  61. package/dist/extensions/TableKeymap.js +97 -0
  62. package/dist/extensions/TableKeymap.test.d.ts +2 -0
  63. package/dist/extensions/TableKeymap.test.d.ts.map +1 -0
  64. package/dist/extensions/TableKeymap.test.js +147 -0
  65. package/dist/extensions/TabsBlock.d.ts.map +1 -1
  66. package/dist/extensions/TabsBlock.js +12 -9
  67. package/dist/extensions/TiptapMidibus.d.ts.map +1 -1
  68. package/dist/extensions/TiptapMidibus.js +60 -6
  69. package/dist/extensions/UploadSkeleton.d.ts +61 -0
  70. package/dist/extensions/UploadSkeleton.d.ts.map +1 -0
  71. package/dist/extensions/UploadSkeleton.js +233 -0
  72. package/dist/extensions/UploadSkeleton.test.d.ts +2 -0
  73. package/dist/extensions/UploadSkeleton.test.d.ts.map +1 -0
  74. package/dist/extensions/UploadSkeleton.test.js +128 -0
  75. package/dist/extensions/VideoEmbed.d.ts +8 -0
  76. package/dist/extensions/VideoEmbed.d.ts.map +1 -1
  77. package/dist/extensions/VideoEmbed.js +226 -45
  78. package/dist/extensions/VideoEmbed.test.js +131 -2
  79. package/dist/i18n/en.d.ts +3 -0
  80. package/dist/i18n/en.d.ts.map +1 -0
  81. package/dist/i18n/en.js +191 -0
  82. package/dist/i18n/es.d.ts +3 -0
  83. package/dist/i18n/es.d.ts.map +1 -0
  84. package/dist/i18n/es.js +191 -0
  85. package/dist/i18n/index.d.ts +43 -0
  86. package/dist/i18n/index.d.ts.map +1 -0
  87. package/dist/i18n/index.js +109 -0
  88. package/dist/i18n/index.test.d.ts +2 -0
  89. package/dist/i18n/index.test.d.ts.map +1 -0
  90. package/dist/i18n/index.test.js +173 -0
  91. package/dist/i18n/ja.d.ts +3 -0
  92. package/dist/i18n/ja.d.ts.map +1 -0
  93. package/dist/i18n/ja.js +191 -0
  94. package/dist/i18n/ko.d.ts +198 -0
  95. package/dist/i18n/ko.d.ts.map +1 -0
  96. package/dist/i18n/ko.js +215 -0
  97. package/dist/i18n/zh-hans.d.ts +3 -0
  98. package/dist/i18n/zh-hans.d.ts.map +1 -0
  99. package/dist/i18n/zh-hans.js +191 -0
  100. package/dist/i18n/zh-hant.d.ts +3 -0
  101. package/dist/i18n/zh-hant.d.ts.map +1 -0
  102. package/dist/i18n/zh-hant.js +192 -0
  103. package/dist/index.d.ts +7 -1
  104. package/dist/index.d.ts.map +1 -1
  105. package/dist/index.js +13 -1
  106. package/dist/static/highlight.d.ts +13 -0
  107. package/dist/static/highlight.d.ts.map +1 -0
  108. package/dist/static/highlight.js +99 -0
  109. package/dist/static/index.d.ts +33 -0
  110. package/dist/static/index.d.ts.map +1 -0
  111. package/dist/static/index.js +367 -0
  112. package/dist/static/index.test.d.ts +2 -0
  113. package/dist/static/index.test.d.ts.map +1 -0
  114. package/dist/static/index.test.js +194 -0
  115. package/dist/static/tokenizer.d.ts +52 -0
  116. package/dist/static/tokenizer.d.ts.map +1 -0
  117. package/dist/static/tokenizer.js +289 -0
  118. package/dist/styles/editor.css +1 -1
  119. package/dist/utils/emoji-data.d.ts +15 -0
  120. package/dist/utils/emoji-suggestion.d.ts +48 -0
  121. package/dist/utils/emoji-suggestion.d.ts.map +1 -0
  122. package/dist/utils/emoji-suggestion.js +51 -0
  123. package/dist/utils/emoji-suggestion.test.d.ts +2 -0
  124. package/dist/utils/emoji-suggestion.test.d.ts.map +1 -0
  125. package/dist/utils/emoji-suggestion.test.js +117 -0
  126. package/dist/utils/floating-helper.d.ts +60 -0
  127. package/dist/utils/floating-helper.d.ts.map +1 -0
  128. package/dist/utils/floating-helper.js +63 -0
  129. package/dist/utils/floating-helper.test.d.ts +2 -0
  130. package/dist/utils/floating-helper.test.d.ts.map +1 -0
  131. package/dist/utils/floating-helper.test.js +141 -0
  132. package/dist/utils/guard-vscode-paste.d.ts +19 -0
  133. package/dist/utils/guard-vscode-paste.d.ts.map +1 -0
  134. package/dist/utils/guard-vscode-paste.js +46 -0
  135. package/dist/utils/guard-vscode-paste.test.d.ts +2 -0
  136. package/dist/utils/guard-vscode-paste.test.d.ts.map +1 -0
  137. package/dist/utils/guard-vscode-paste.test.js +86 -0
  138. package/dist/utils/media-size.d.ts +29 -0
  139. package/dist/utils/media-size.d.ts.map +1 -0
  140. package/dist/utils/media-size.js +90 -0
  141. package/dist/utils/resize.d.ts +12 -0
  142. package/dist/utils/resize.d.ts.map +1 -1
  143. package/dist/utils/resize.js +5 -5
  144. package/dist/utils/sanitize.d.ts +2 -0
  145. package/dist/utils/sanitize.d.ts.map +1 -1
  146. package/dist/utils/sanitize.js +28 -3
  147. package/package.json +8 -1
@@ -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}.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-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-\[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-\[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))}.\!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}.resize-y{resize:vertical}.resize{resize:both}.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}.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-popover{background-color:var(--popover)}.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}.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-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}.text-destructive{color:var(--destructive)}.text-muted-foreground{color:var(--muted-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-xl{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.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)}.outline-none{outline:2px solid transparent;outline-offset:2px}.outline{outline-style:solid}.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-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;border-radius:8px;margin:.75em 0;cursor:pointer;transition:box-shadow .15s}.tiptap .hce-image{position:relative;display:block;width:-moz-fit-content;width:fit-content;max-width:100%;margin:.75em 0;box-sizing:border-box}.tiptap .hce-image img{display:block;width:100%;height:auto;margin:0}.pdf-frame{position:relative;display:flex;align-items:center;justify-content:center;border:1px solid var(--border);border-radius:8px;background:var(--muted)}.pdf-frame canvas{display:block;max-width:100%;border-radius:7px}.pdf-frame:focus{outline:1px solid var(--primary);outline-offset:2px}.pdf-overlay{position:absolute;inset:0;pointer-events:none;opacity:0;transition:opacity .15s ease;-moz-user-select:none;user-select:none;-webkit-user-select:none}.pdf-overlay .pdf-page-input{-moz-user-select:text;user-select:text;-webkit-user-select:text}.pdf-frame:hover .pdf-overlay,.pdf-overlay:focus-within,.tiptap[contenteditable=true] [data-type=pdfBlock].ProseMirror-selectednode .pdf-overlay{opacity:1}@media (hover:none){.pdf-overlay{opacity:1}}@media (prefers-reduced-motion:reduce){.pdf-overlay{transition:none}}.pdf-cluster{position:absolute;display:flex;align-items:center;gap:2px;padding:3px 5px;border-radius:999px;background:rgba(24,24,27,.42);backdrop-filter:blur(10px) saturate(1.1);color:#fff;pointer-events:auto;max-width:calc(100% - 12px);transition:background-color .15s ease}.pdf-cluster:hover{background:rgba(24,24,27,.62)}.pdf-cluster-end{top:6px;right:8px}.pdf-cluster-page{bottom:6px;left:50%;transform:translateX(-50%)}.pdf-nav-rail{position:sticky;top:0;height:100vh;max-height:100%;pointer-events:none}.pdf-nav{position:absolute;top:50%;transform:translateY(-50%);pointer-events:auto}.pdf-nav-prev{left:12px}.pdf-nav-next{right:12px}.pdf-overlay .pdf-ctl,.pdf-overlay .pdf-page,.pdf-overlay .pdf-preset{display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;border:0;background:transparent;padding:0;color:#e4e4e7;font-family:inherit;cursor:pointer;opacity:.92;transition:opacity .12s,color .12s}.pdf-overlay .pdf-ctl{width:20px;height:20px;flex:none}.pdf-overlay .pdf-ctl svg{width:14px;height:14px}.pdf-overlay .pdf-page,.pdf-overlay .pdf-preset{font-weight:500}.pdf-overlay .pdf-ctl:hover,.pdf-overlay .pdf-page:hover,.pdf-overlay .pdf-preset:hover{opacity:1;color:#fff}.pdf-overlay .pdf-ctl:disabled{opacity:.4;cursor:default}.pdf-overlay .pdf-ctl-danger:hover{opacity:1;color:#ff8f8f}.pdf-overlay .pdf-ctl:focus-visible,.pdf-overlay .pdf-page-input:focus-visible,.pdf-overlay .pdf-page:focus-visible,.pdf-overlay .pdf-preset:focus-visible{outline:2px solid hsla(0,0%,100%,.85);outline-offset:2px;border-radius:4px;opacity:1}.pdf-overlay .pdf-preset{height:18px;font-size:11px;line-height:1;font-variant-numeric:tabular-nums;flex:none}.pdf-overlay .pdf-preset.is-active,.pdf-overlay .pdf-preset.is-active:hover{opacity:1;color:#fff;font-weight:600;box-shadow:inset 0 -1px 0 0 currentColor}.pdf-overlay .pdf-fit{width:19px;height:18px;border-radius:3px}.pdf-overlay .pdf-fit svg{width:13px;height:13px}.pdf-overlay .pdf-fit.is-active,.pdf-overlay .pdf-fit.is-active:hover{opacity:1;color:#fff;box-shadow:inset 0 -1px 0 0 currentColor}.pdf-overlay [data-tip]{position:relative}.pdf-overlay [data-tip]:after{content:attr(data-tip);position:absolute;top:calc(100% + 7px);right:0;z-index:1;white-space:nowrap;font-size:11px;line-height:1.4;font-weight:400;padding:4px 8px;border-radius:5px;background:rgba(24,24,27,.94);backdrop-filter:blur(6px);color:#fff;box-shadow:0 4px 12px rgba(0,0,0,.35);opacity:0;pointer-events:none;transition:opacity .12s ease .35s}.pdf-overlay [data-tip]:focus-visible:after,.pdf-overlay [data-tip]:hover:after{opacity:1}.pdf-cluster-page [data-tip]:after{top:auto;bottom:calc(100% + 7px)}.pdf-nav-prev[data-tip]:after{right:auto;left:0}.pdf-overlay .pdf-page{height:16px;font-size:10px;line-height:1;font-variant-numeric:tabular-nums}.pdf-cluster-page{padding:2px 6px}.pdf-overlay .pdf-nav{width:30px;height:30px;padding:0;background:rgba(24,24,27,.42)}.pdf-overlay .pdf-nav:hover{background:rgba(24,24,27,.62)}.pdf-overlay .pdf-nav svg{width:18px;height:18px}.pdf-overlay .pdf-nav:disabled{opacity:.4}.pdf-divider{flex:none;width:1px;height:11px;margin:0 3px;background:hsla(0,0%,100%,.3)}.pdf-overlay .pdf-page-input{box-sizing:border-box;height:20px;width:46px;padding:0 5px;font-size:12px;text-align:center;font-variant-numeric:tabular-nums;background:rgba(24,24,27,.85);border:1px solid hsla(0,0%,100%,.5);color:#fff;border-radius:4px;font-family:inherit;outline:none}.pdf-status{display:flex;align-items:center;justify-content:center;gap:8px;padding:2.5rem 1rem;font-size:.875rem;color:var(--muted-foreground);text-align:center}.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;font:inherit;width:24px;height:24px;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:calc(-2px + 1lh/2);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:clamp(6px,.42em,11px) solid;border-top:clamp(4.7px,.33em,8.6px) solid transparent;border-bottom:clamp(4.7px,.33em,8.6px) 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{font-size:2rem;line-height:1.25}.tiptap [data-type=details]:has(>div>summary[data-level="2"])>button{font-size:1.5rem;line-height:1.3}.tiptap [data-type=details]:has(>div>summary[data-level="3"])>button{font-size:1.25rem;line-height:1.35}.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:25px;top:calc(10px + .5lh);width:0;height:0;border-left:clamp(6px,.42em,11px) solid var(--muted-foreground);border-top:clamp(4.7px,.33em,8.6px) solid transparent;border-bottom:clamp(4.7px,.33em,8.6px) 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=image]):not([data-type=pdfBlock]):not([data-type=mbusVideo]):not([data-type=videoEmbed]):before,.ProseMirror-selectednoderange:not([data-type=image]):not([data-type=pdfBlock]):not([data-type=mbusVideo]):not([data-type=videoEmbed]):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}.tiptap[contenteditable=true] [data-type=image].ProseMirror-selectednode,.tiptap[contenteditable=true] [data-type=mbusVideo].ProseMirror-selectednode,.tiptap[contenteditable=true] [data-type=pdfBlock].ProseMirror-selectednode,.tiptap[contenteditable=true] [data-type=videoEmbed].ProseMirror-selectednode,.tiptap[contenteditable=true] img.ProseMirror-selectednode{outline:1px solid var(--primary);outline-offset:2px;border-radius:8px}.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}}[data-type=tabs]{margin:1em 0;border:1px solid var(--border);border-radius:10px;overflow:hidden}[data-type=tabs].ProseMirror-selectednode{outline:2px solid color-mix(in srgb,var(--primary) 30%,transparent)}.hce-tabs-bar{display:flex;flex-wrap:wrap;align-items:center;gap:4px;padding:5px 6px;border-bottom:1px solid var(--border);background:color-mix(in srgb,var(--muted) 55%,transparent);-webkit-user-select:none;-moz-user-select:none;user-select:none}.hce-tab-chip{position:relative;display:inline-flex;align-items:center;gap:2px;padding-right:2px;border-radius:6px;color:var(--muted-foreground);touch-action:none}.hce-tab-chip:hover{background:color-mix(in srgb,var(--primary) 8%,transparent)}.hce-tab-chip.is-active{background:color-mix(in srgb,var(--primary) 14%,transparent);color:var(--primary)}.hce-tab-chip-label{max-width:14rem;padding:3px 8px;border:0;background:transparent;color:inherit;font:inherit;font-size:.8125rem;font-weight:500;line-height:1.4;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;cursor:pointer}.hce-tab-chip.is-active .hce-tab-chip-label{font-weight:600}.hce-tab-chip-close{display:inline-flex;visibility:hidden;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:0;border-radius:4px;background:transparent;color:inherit;font-size:13px;line-height:1;cursor:pointer}.hce-tab-chip:hover .hce-tab-chip-close:not(.is-disabled){visibility:visible}.hce-tab-chip-close.is-disabled{cursor:default;pointer-events:none}.hce-tab-chip-close:hover{background:color-mix(in srgb,var(--foreground) 12%,transparent)}.hce-tabs-add{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;padding:0;border:0;border-radius:6px;background:transparent;color:var(--muted-foreground);font-size:15px;line-height:1;cursor:pointer}.hce-tabs-add:hover{background:color-mix(in srgb,var(--primary) 10%,transparent);color:var(--primary)}.hce-tabs-bar.is-dragging{cursor:grabbing}.hce-tab-chip.is-dragged{opacity:.45}.hce-tabs-bar.is-dragging .hce-tab-chip:hover .hce-tab-chip-close{visibility:hidden}.hce-tab-chip.is-drop-after:after,.hce-tab-chip.is-drop-before:before{content:"";position:absolute;top:2px;bottom:2px;width:2px;border-radius:1px;background:var(--primary)}.hce-tab-chip.is-drop-before:before{left:-3px}.hce-tab-chip.is-drop-after:after{right:-3px}.hce-tab-title-input{box-sizing:border-box;width:8rem;margin:2px;padding:2px 6px;border:1px solid var(--primary);border-radius:4px;background:var(--background);color:var(--foreground);font:inherit;font-size:.8125rem;outline:none}.hce-tabs-panels{padding:10px 12px}.hce-tabs-panels>[data-type=tab]{display:none}.hce-tabs-panels>[data-type=tab].hce-tab-active{display:block}[data-type=tabs]:not(.hce-tabs-live)>[data-type=tab]{display:none}[data-type=tabs]:not(.hce-tabs-live)>[data-type=tab]:first-child{display:block;padding:10px 12px}[data-type=tabs]:not(.hce-tabs-live):before{content:"";display:block;height:2rem;border-bottom:1px solid var(--border);background:color-mix(in srgb,var(--muted) 55%,transparent)}[data-type=tab]>p:only-child:empty:before,[data-type=tab]>p:only-child:has(>br:only-child):before{content:"빈 탭입니다. 내부를 클릭하거나 블록을 넣으세요.";float:left;height:0;color:var(--muted-foreground);opacity:.5;pointer-events:none}.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\:bg-muted:hover{background-color:var(--muted)}.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\: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)}
1
+ .pointer-events-none{pointer-events:none}.\!visible{visibility:visible!important}.visible{visibility:visible}.collapse{visibility:collapse}.static{position:static}.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}.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-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-\[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-\[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))}.\!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}.resize-y{resize:vertical}.resize{resize:both}.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}.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-popover{background-color:var(--popover)}.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}.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-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}.text-destructive{color:var(--destructive)}.text-muted-foreground{color:var(--muted-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-xl{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.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)}.outline-none{outline:2px solid transparent;outline-offset:2px}.outline{outline-style:solid}.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-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}@counter-style kors{system:cyclic;symbols:"ㄱ." "ㄴ." "ㄷ." "ㄹ." "ㅁ." "ㅂ." "ㅅ." "ㅇ." "ㅈ." "ㅊ." "ㅋ." "ㅌ." "ㅍ." "ㅎ.";suffix:" "}@counter-style korc{system:cyclic;symbols:"가." "나." "다." "라." "마." "바." "사." "아." "자." "차." "카." "타." "파." "하.";suffix:" "}.tiptap ol[type="1"]{list-style-type:decimal}.tiptap ol[type=a]{list-style-type:lower-alpha}.tiptap ol[type=i]{list-style-type:lower-roman}.tiptap ol[type=kors]{list-style-type:kors}.tiptap ol[type=korc]{list-style-type:korc}.tiptap ol.marker-1{list-style-type:decimal}.tiptap ol.marker-a{list-style-type:lower-alpha}.tiptap ol.marker-A{list-style-type:upper-alpha}.tiptap ol.marker-i{list-style-type:lower-roman}.tiptap ol.marker-I{list-style-type:upper-roman}.tiptap ol.marker-kors{list-style-type:kors}.tiptap ol.marker-korc{list-style-type:korc}.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;border-radius:8px;margin:.75em 0;cursor:pointer;transition:box-shadow .15s}.tiptap .hce-image{position:relative;display:block;width:-moz-fit-content;width:fit-content;max-width:100%;margin:.75em 0;box-sizing:border-box}.tiptap .hce-image img{display:block;width:100%;height:auto;margin:0}.pdf-frame{position:relative;display:flex;align-items:center;justify-content:center;border:1px solid var(--border);border-radius:8px;background:var(--muted)}.pdf-frame canvas{display:block;max-width:100%;border-radius:7px}.pdf-frame:focus{outline:1px solid var(--primary);outline-offset:2px}.pdf-overlay{position:absolute;inset:0;pointer-events:none;opacity:0;transition:opacity .15s ease;-moz-user-select:none;user-select:none;-webkit-user-select:none}.pdf-overlay .pdf-page-input{-moz-user-select:text;user-select:text;-webkit-user-select:text}.pdf-frame:hover .pdf-overlay,.pdf-overlay:focus-within,.tiptap[contenteditable=true] [data-type=pdfBlock].ProseMirror-selectednode .pdf-overlay{opacity:1}@media (hover:none){.pdf-overlay{opacity:1}}@media (prefers-reduced-motion:reduce){.pdf-overlay{transition:none}}.pdf-cluster{position:absolute;display:flex;align-items:center;gap:2px;padding:3px 5px;border-radius:999px;background:rgba(24,24,27,.42);backdrop-filter:blur(10px) saturate(1.1);color:#fff;pointer-events:auto;max-width:calc(100% - 12px);transition:background-color .15s ease}.pdf-cluster:hover{background:rgba(24,24,27,.62)}.pdf-cluster-end{top:6px;right:8px}.pdf-cluster-page{bottom:6px;left:50%;transform:translateX(-50%)}.pdf-nav-rail{position:sticky;top:0;height:100vh;max-height:100%;pointer-events:none}.pdf-nav{position:absolute;top:50%;transform:translateY(-50%);pointer-events:auto}.pdf-nav-prev{left:12px}.pdf-nav-next{right:12px}.pdf-overlay .pdf-ctl,.pdf-overlay .pdf-page,.pdf-overlay .pdf-preset{display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;border:0;background:transparent;padding:0;color:#e4e4e7;font-family:inherit;cursor:pointer;opacity:.92;transition:opacity .12s,color .12s}.pdf-overlay .pdf-ctl{width:20px;height:20px;flex:none}.pdf-overlay .pdf-ctl svg{width:14px;height:14px}.pdf-overlay .pdf-page,.pdf-overlay .pdf-preset{font-weight:500}.pdf-overlay .pdf-ctl:hover,.pdf-overlay .pdf-page:hover,.pdf-overlay .pdf-preset:hover{opacity:1;color:#fff}.pdf-overlay .pdf-ctl:disabled{opacity:.4;cursor:default}.pdf-overlay .pdf-ctl-danger:hover{opacity:1;color:#ff8f8f}.pdf-overlay .pdf-ctl:focus-visible,.pdf-overlay .pdf-page-input:focus-visible,.pdf-overlay .pdf-page:focus-visible,.pdf-overlay .pdf-preset:focus-visible{outline:2px solid hsla(0,0%,100%,.85);outline-offset:2px;border-radius:4px;opacity:1}.pdf-overlay .pdf-preset{height:18px;font-size:11px;line-height:1;font-variant-numeric:tabular-nums;flex:none}.pdf-overlay .pdf-preset.is-active,.pdf-overlay .pdf-preset.is-active:hover{opacity:1;color:#fff;font-weight:600;box-shadow:inset 0 -1px 0 0 currentColor}.pdf-overlay .pdf-fit{width:19px;height:18px;border-radius:3px}.pdf-overlay .pdf-fit svg{width:13px;height:13px}.pdf-overlay .pdf-fit.is-active,.pdf-overlay .pdf-fit.is-active:hover{opacity:1;color:#fff;box-shadow:inset 0 -1px 0 0 currentColor}.pdf-overlay [data-tip]{position:relative}.pdf-overlay [data-tip]:after{content:attr(data-tip);position:absolute;top:calc(100% + 7px);right:0;z-index:1;white-space:nowrap;font-size:11px;line-height:1.4;font-weight:400;padding:4px 8px;border-radius:5px;background:rgba(24,24,27,.94);backdrop-filter:blur(6px);color:#fff;box-shadow:0 4px 12px rgba(0,0,0,.35);opacity:0;pointer-events:none;transition:opacity .12s ease .35s}.pdf-overlay [data-tip]:focus-visible:after,.pdf-overlay [data-tip]:hover:after{opacity:1}.pdf-cluster-page [data-tip]:after{top:auto;bottom:calc(100% + 7px)}.pdf-nav-prev[data-tip]:after{right:auto;left:0}.pdf-overlay .pdf-page{height:16px;font-size:10px;line-height:1;font-variant-numeric:tabular-nums}.pdf-cluster-page{padding:2px 6px}.pdf-overlay .pdf-nav{width:30px;height:30px;padding:0;background:rgba(24,24,27,.42)}.pdf-overlay .pdf-nav:hover{background:rgba(24,24,27,.62)}.pdf-overlay .pdf-nav svg{width:18px;height:18px}.pdf-overlay .pdf-nav:disabled{opacity:.4}.pdf-divider{flex:none;width:1px;height:11px;margin:0 3px;background:hsla(0,0%,100%,.3)}.pdf-overlay .pdf-page-input{box-sizing:border-box;height:20px;width:46px;padding:0 5px;font-size:12px;text-align:center;font-variant-numeric:tabular-nums;background:rgba(24,24,27,.85);border:1px solid hsla(0,0%,100%,.5);color:#fff;border-radius:4px;font-family:inherit;outline:none}.pdf-status{display:flex;align-items:center;justify-content:center;gap:8px;padding:2.5rem 1rem;font-size:.875rem;color:var(--muted-foreground);text-align:center}.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;font:inherit;width:24px;height:24px;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:calc(-2px + 1lh/2);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:clamp(6px,.42em,11px) solid;border-top:clamp(4.7px,.33em,8.6px) solid transparent;border-bottom:clamp(4.7px,.33em,8.6px) 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{font-size:2rem;line-height:1.25}.tiptap [data-type=details]:has(>div>summary[data-level="2"])>button{font-size:1.5rem;line-height:1.3}.tiptap [data-type=details]:has(>div>summary[data-level="3"])>button{font-size:1.25rem;line-height:1.35}.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:25px;top:calc(10px + .5lh);width:0;height:0;border-left:clamp(6px,.42em,11px) solid var(--muted-foreground);border-top:clamp(4.7px,.33em,8.6px) solid transparent;border-bottom:clamp(4.7px,.33em,8.6px) 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}.tiptap.hce-floating-helper-on .is-empty:before{visibility:hidden}.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=image]):not([data-type=pdfBlock]):not([data-type=mbusVideo]):not([data-type=videoEmbed]):before,.ProseMirror-selectednoderange:not([data-type=image]):not([data-type=pdfBlock]):not([data-type=mbusVideo]):not([data-type=videoEmbed]):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}.tiptap[contenteditable=true] [data-type=image].ProseMirror-selectednode,.tiptap[contenteditable=true] [data-type=mbusVideo].ProseMirror-selectednode,.tiptap[contenteditable=true] [data-type=pdfBlock].ProseMirror-selectednode,.tiptap[contenteditable=true] [data-type=videoEmbed].ProseMirror-selectednode,.tiptap[contenteditable=true] img.ProseMirror-selectednode{outline:1px solid var(--primary);outline-offset:2px;border-radius:8px}.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}}[data-type=tabs]{margin:1em 0;border:1px solid var(--border);border-radius:10px;overflow:hidden}[data-type=tabs].ProseMirror-selectednode{outline:2px solid color-mix(in srgb,var(--primary) 30%,transparent)}.hce-tabs-bar{display:flex;flex-wrap:wrap;align-items:center;gap:4px;padding:5px 6px;border-bottom:1px solid var(--border);background:color-mix(in srgb,var(--muted) 55%,transparent);-webkit-user-select:none;-moz-user-select:none;user-select:none}.hce-tab-chip{position:relative;display:inline-flex;align-items:center;gap:2px;padding-right:2px;border-radius:6px;color:var(--muted-foreground);touch-action:none}.hce-tab-chip:hover{background:color-mix(in srgb,var(--primary) 8%,transparent)}.hce-tab-chip.is-active{background:color-mix(in srgb,var(--primary) 14%,transparent);color:var(--primary)}.hce-tab-chip-label{max-width:14rem;padding:3px 8px;border:0;background:transparent;color:inherit;font:inherit;font-size:.8125rem;font-weight:500;line-height:1.4;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;cursor:pointer}.hce-tab-chip.is-active .hce-tab-chip-label{font-weight:600}.hce-tab-chip-close{display:inline-flex;visibility:hidden;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:0;border-radius:4px;background:transparent;color:inherit;font-size:13px;line-height:1;cursor:pointer}.hce-tab-chip:hover .hce-tab-chip-close:not(.is-disabled){visibility:visible}.hce-tab-chip-close.is-disabled{cursor:default;pointer-events:none}.hce-tab-chip-close:hover{background:color-mix(in srgb,var(--foreground) 12%,transparent)}.hce-tabs-add{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;padding:0;border:0;border-radius:6px;background:transparent;color:var(--muted-foreground);font-size:15px;line-height:1;cursor:pointer}.hce-tabs-add:hover{background:color-mix(in srgb,var(--primary) 10%,transparent);color:var(--primary)}.hce-tabs-bar.is-dragging{cursor:grabbing}.hce-tab-chip.is-dragged{opacity:.45}.hce-tabs-bar.is-dragging .hce-tab-chip:hover .hce-tab-chip-close{visibility:hidden}.hce-tab-chip.is-drop-after:after,.hce-tab-chip.is-drop-before:before{content:"";position:absolute;top:2px;bottom:2px;width:2px;border-radius:1px;background:var(--primary)}.hce-tab-chip.is-drop-before:before{left:-3px}.hce-tab-chip.is-drop-after:after{right:-3px}.hce-tab-title-input{box-sizing:border-box;width:8rem;margin:2px;padding:2px 6px;border:1px solid var(--primary);border-radius:4px;background:var(--background);color:var(--foreground);font:inherit;font-size:.8125rem;outline:none}.hce-tabs-panels{padding:10px 12px}.hce-tabs-panels>[data-type=tab]{display:none}.hce-tabs-panels>[data-type=tab].hce-tab-active{display:block}[data-type=tabs]:not(.hce-tabs-live)>[data-type=tab]{display:none}[data-type=tabs]:not(.hce-tabs-live)>[data-type=tab]:first-child{display:block;padding:10px 12px}[data-type=tabs]:not(.hce-tabs-live):before{content:"";display:block;height:2rem;border-bottom:1px solid var(--border);background:color-mix(in srgb,var(--muted) 55%,transparent)}[data-type=tab]>p:only-child:empty:before,[data-type=tab]>p:only-child:has(>br:only-child):before{content:"빈 탭입니다. 내부를 클릭하거나 블록을 넣으세요.";float:left;height:0;color:var(--muted-foreground);opacity:.5;pointer-events:none}.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)}.tiptap .hce-upload-skeleton{position:relative;width:100%;overflow:hidden;border-radius:12px;border:1px solid var(--border,#d1d5db);background:color-mix(in srgb,var(--foreground,#111827) 6%,transparent);margin:.75em 0}.tiptap .hce-upload-skeleton[data-kind=file]{min-height:56px}.hce-upload-skeleton-shine{position:absolute;inset:0;transform:translateX(-120%);background:linear-gradient(105deg,transparent 20%,color-mix(in srgb,var(--background,#fff) 45%,transparent),transparent 80%);animation:hce-upload-shimmer 1.35s ease-in-out infinite}.hce-upload-skeleton-bar{position:absolute;left:14px;height:10px;border-radius:999px;background:color-mix(in srgb,var(--foreground,#111827) 14%,transparent)}.hce-upload-skeleton-bar.is-top{top:14px;width:min(160px,45%)}.hce-upload-skeleton-bar.is-mid{top:34px;width:min(280px,78%)}.hce-upload-skeleton-bar.is-low{top:54px;width:min(220px,62%)}.tiptap .hce-upload-skeleton[data-kind=file] .hce-upload-skeleton-bar.is-low,.tiptap .hce-upload-skeleton[data-kind=file] .hce-upload-skeleton-bar.is-mid{display:none}@keyframes hce-upload-shimmer{0%{transform:translateX(-120%)}to{transform:translateX(120%)}}.tiptap .hce-media-toolbar-anchor{position:relative;display:block;height:0}.tiptap .hce-media-toolbar{position:absolute;left:50%;top:6px;transform:translateX(-50%);z-index:30;display:flex;align-items:center;gap:2px;padding:4px;border-radius:8px;border:1px solid var(--border,#d1d5db);background:var(--background,#fff);box-shadow:0 4px 16px rgba(0,0,0,.12);white-space:nowrap}.hce-media-toolbar-chip{border:0;background:transparent;border-radius:6px;padding:3px 8px;font-size:12px;line-height:1.4;color:var(--foreground,#111827);cursor:pointer}.hce-media-toolbar-chip:hover{background-color:color-mix(in srgb,var(--foreground,#111827) 8%,transparent)}.hce-media-toolbar-chip[aria-pressed=true]{background-color:color-mix(in srgb,var(--primary) 12%,transparent);color:var(--primary)}.hce-media-toolbar-separator{width:1px;height:16px;margin:0 4px;background:var(--border,#d1d5db)}.tiptap img[data-align=center]{display:block;margin-left:auto;margin-right:auto}.tiptap img[data-align=right]{display:block;margin-left:auto}.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\: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\: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)}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * `emojis-list`·`emojis-keywords` 는 타입 선언이 없는 순수 데이터 패키지다
3
+ * (main 은 `@ts-ignore` 로 넘겼다 — strict 에서는 선언을 세우는 쪽이 맞다).
4
+ * 두 배열은 **같은 인덱스가 짝**이다(`emojis[i]` ↔ `keywords[i]`).
5
+ * 길이는 다르다(emojis 3075, keywords 2477) — 키워드 없는 꼬리는 검색에서 자연히 빠진다.
6
+ */
7
+ declare module 'emojis-list' {
8
+ const emojis: string[];
9
+ export default emojis;
10
+ }
11
+
12
+ declare module 'emojis-keywords' {
13
+ const keywords: string[];
14
+ export default keywords;
15
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * 이모지 `:` 자동완성의 **로직 절반** — 정올 main(`plugin/command/emoji.ts`) 이식.
3
+ *
4
+ * main 은 `@tiptap/suggestion` 플러그인에 얹었지만 여기서는 코드 의존을 늘리지 않고
5
+ * 슬래시 메뉴(`TipTapEditor` 의 `handleUpdate`)와 같은 방식 — 에디터 update 때마다 커서
6
+ * 앞 텍스트를 읽어 판정 — 을 쓴다. 이 파일은 순수 함수만 두고(테스트 대상), 팝업·키보드는
7
+ * `EmojiSuggestionMenu.svelte` 가 맡는다.
8
+ *
9
+ * 검색 의미론은 main 과 동일하다: `:smi` → 키워드(`:smile:` 꼴)에 `:smi` 가 **부분 문자열**
10
+ * 로 들어가는 이모지를 앞에서부터 최대 10개. 키워드는 영문뿐이다(main 수준).
11
+ */
12
+ import type { EditorState } from '@tiptap/pm/state';
13
+ export interface EmojiSuggestion {
14
+ /** 삽입할 이모지 문자. */
15
+ emoji: string;
16
+ /** `:smile:` 꼴 키워드 — 목록에 이모지 옆에 그대로 보여 준다(main 과 같은 표기). */
17
+ keyword: string;
18
+ }
19
+ export interface EmojiQueryMatch {
20
+ /** `:` 위치(문서 좌표). 삽입 시 여기부터 커서까지 지운다. */
21
+ from: number;
22
+ /** 커서 위치(문서 좌표). */
23
+ to: number;
24
+ /** `:` 뒤에 친 검색어(콜론 제외). 빈 문자열이면 방금 `:` 만 친 상태다. */
25
+ query: string;
26
+ }
27
+ /** 후보 최대 수 — main 과 같다. */
28
+ export declare const EMOJI_SUGGESTION_MAX = 10;
29
+ /**
30
+ * 커서 앞 텍스트에서 진행 중인 `:query` 를 찾는 패턴. `:` 는 **줄 시작이나 공백 뒤**에서만
31
+ * 트리거된다(main 이 쓴 `@tiptap/suggestion` 의 기본 prefix 규칙과 같다 — `예: 값` 같은
32
+ * 일반 문장 속 콜론에 팝업이 뜨지 않게 하는 조건이다). 검색어에 공백·콜론이 들어오면
33
+ * (`:x `, `::`) 판정이 끝난 것으로 본다.
34
+ */
35
+ export declare const EMOJI_QUERY_REGEX: RegExp;
36
+ /** 키워드에 `:query`(소문자화)가 들어가는 이모지를 앞에서부터 최대 `max`개. */
37
+ export declare function searchEmojis(query: string, max?: number): EmojiSuggestion[];
38
+ /**
39
+ * 지금 커서 자리에서 이모지 자동완성이 진행 중인지 판정한다. 아니면 `null`.
40
+ *
41
+ * 슬래시 메뉴(`handleUpdate`)와 같은 제외 규칙을 지킨다:
42
+ * - 선택이 펼쳐져 있으면(드래그 중) 안 띄운다.
43
+ * - 코드블록 안에서는 안 띄운다(`std::vector` 같은 코드가 트리거되면 안 된다 —
44
+ * `::` 는 어차피 패턴에서 빠지지만 가드를 맞춰 둔다).
45
+ * - 줄이 `/` 로 시작하면 슬래시 메뉴 영역이다 — 두 팝업이 겹치면 Enter 를 서로 뺏는다.
46
+ */
47
+ export declare function findEmojiQuery(state: EditorState): EmojiQueryMatch | null;
48
+ //# sourceMappingURL=emoji-suggestion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emoji-suggestion.d.ts","sourceRoot":"","sources":["../../src/utils/emoji-suggestion.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAIpD,MAAM,WAAW,eAAe;IAC/B,kBAAkB;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC/B,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,oBAAoB;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAC;CACd;AAED,2BAA2B;AAC3B,eAAO,MAAM,oBAAoB,KAAK,CAAC;AAEvC;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,QAAwB,CAAC;AAEvD,sDAAsD;AACtD,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,GAAE,MAA6B,GAAG,eAAe,EAAE,CAajG;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,GAAG,eAAe,GAAG,IAAI,CAezE"}
@@ -0,0 +1,51 @@
1
+ import emojis from 'emojis-list';
2
+ import keywords from 'emojis-keywords';
3
+ /** 후보 최대 수 — main 과 같다. */
4
+ export const EMOJI_SUGGESTION_MAX = 10;
5
+ /**
6
+ * 커서 앞 텍스트에서 진행 중인 `:query` 를 찾는 패턴. `:` 는 **줄 시작이나 공백 뒤**에서만
7
+ * 트리거된다(main 이 쓴 `@tiptap/suggestion` 의 기본 prefix 규칙과 같다 — `예: 값` 같은
8
+ * 일반 문장 속 콜론에 팝업이 뜨지 않게 하는 조건이다). 검색어에 공백·콜론이 들어오면
9
+ * (`:x `, `::`) 판정이 끝난 것으로 본다.
10
+ */
11
+ export const EMOJI_QUERY_REGEX = /(?:^|\s):([^\s:]*)$/;
12
+ /** 키워드에 `:query`(소문자화)가 들어가는 이모지를 앞에서부터 최대 `max`개. */
13
+ export function searchEmojis(query, max = EMOJI_SUGGESTION_MAX) {
14
+ const normalizedQuery = `:${query.toLowerCase()}`;
15
+ const found = [];
16
+ for (let i = 0; i < emojis.length; i++) {
17
+ const keyword = keywords[i];
18
+ if (keyword && keyword.includes(normalizedQuery)) {
19
+ found.push({ emoji: emojis[i], keyword });
20
+ if (found.length >= max)
21
+ break;
22
+ }
23
+ }
24
+ return found;
25
+ }
26
+ /**
27
+ * 지금 커서 자리에서 이모지 자동완성이 진행 중인지 판정한다. 아니면 `null`.
28
+ *
29
+ * 슬래시 메뉴(`handleUpdate`)와 같은 제외 규칙을 지킨다:
30
+ * - 선택이 펼쳐져 있으면(드래그 중) 안 띄운다.
31
+ * - 코드블록 안에서는 안 띄운다(`std::vector` 같은 코드가 트리거되면 안 된다 —
32
+ * `::` 는 어차피 패턴에서 빠지지만 가드를 맞춰 둔다).
33
+ * - 줄이 `/` 로 시작하면 슬래시 메뉴 영역이다 — 두 팝업이 겹치면 Enter 를 서로 뺏는다.
34
+ */
35
+ export function findEmojiQuery(state) {
36
+ const { empty, from, $from } = state.selection;
37
+ if (!empty)
38
+ return null;
39
+ if ($from.parent.type.spec.code)
40
+ return null;
41
+ const lineStart = $from.start();
42
+ // 리프 노드(이미지 등)는 한 글자짜리 표지로 세워 인덱스↔문서 좌표를 1:1로 유지한다.
43
+ const lineText = state.doc.textBetween(lineStart, from, '\n', '');
44
+ if (lineText.startsWith('/'))
45
+ return null;
46
+ const match = EMOJI_QUERY_REGEX.exec(lineText);
47
+ if (!match)
48
+ return null;
49
+ const colonIndex = match.index + (match[0].startsWith(':') ? 0 : 1);
50
+ return { from: lineStart + colonIndex, to: from, query: match[1] };
51
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=emoji-suggestion.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emoji-suggestion.test.d.ts","sourceRoot":"","sources":["../../src/utils/emoji-suggestion.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,117 @@
1
+ import { describe, it, expect, afterEach } from 'vitest';
2
+ import { Editor } from '@tiptap/core';
3
+ import StarterKit from '@tiptap/starter-kit';
4
+ import { searchEmojis, findEmojiQuery, EMOJI_SUGGESTION_MAX, EMOJI_QUERY_REGEX } from './emoji-suggestion';
5
+ describe('이모지 자동완성 · 검색 (searchEmojis)', () => {
6
+ it('키워드 부분 일치로 찾고, 정확한 키워드도 물려 온다', () => {
7
+ const results = searchEmojis('smile');
8
+ expect(results.length).toBeGreaterThan(0);
9
+ expect(results.length).toBeLessThanOrEqual(EMOJI_SUGGESTION_MAX);
10
+ for (const result of results) {
11
+ expect(result.keyword).toContain(':smile');
12
+ expect(result.emoji.length).toBeGreaterThan(0);
13
+ }
14
+ expect(results.some((result) => result.keyword === ':smile:')).toBe(true);
15
+ });
16
+ it('대문자로 쳐도 같은 결과다 (소문자 정규화)', () => {
17
+ expect(searchEmojis('SMILE')).toEqual(searchEmojis('smile'));
18
+ });
19
+ it('빈 검색어(`:` 만 친 상태)는 전부 매치 — 최대 10개에서 끊는다', () => {
20
+ expect(searchEmojis('').length).toBe(EMOJI_SUGGESTION_MAX);
21
+ expect(searchEmojis('a').length).toBe(EMOJI_SUGGESTION_MAX);
22
+ });
23
+ it('없는 검색어는 빈 배열', () => {
24
+ expect(searchEmojis('이런이모지는없다zzz')).toEqual([]);
25
+ });
26
+ it('max 인자로 개수를 줄일 수 있다', () => {
27
+ expect(searchEmojis('', 3)).toHaveLength(3);
28
+ });
29
+ /*
30
+ * ⚠️ 두 데이터 패키지는 **같은 인덱스가 짝**이라는 가정 위에 서 있다
31
+ * (emojis-list 3.0.0 ↔ emojis-keywords 2.0.0, main 과 같은 버전 고정).
32
+ * 버전이 엇갈려 정렬이 어긋나면 엉뚱한 이모지가 나온다 — 첫 항목으로 못박는다.
33
+ */
34
+ it('이모지↔키워드 인덱스 정렬이 맞다 (:mahjong: → 🀄️)', () => {
35
+ const results = searchEmojis('mahjong');
36
+ expect(results[0]?.keyword).toBe(':mahjong:');
37
+ expect(results[0]?.emoji).toBe('🀄️');
38
+ });
39
+ });
40
+ describe('이모지 자동완성 · 판정 (findEmojiQuery)', () => {
41
+ let editor;
42
+ function createEditor(content, cursorAtEnd = true) {
43
+ editor = new Editor({
44
+ element: document.createElement('div'),
45
+ extensions: [StarterKit],
46
+ content
47
+ });
48
+ if (cursorAtEnd) {
49
+ editor.commands.setTextSelection(editor.state.doc.content.size - 1);
50
+ }
51
+ return editor;
52
+ }
53
+ afterEach(() => {
54
+ editor?.destroy();
55
+ });
56
+ it('줄 시작의 `:query` 를 찾는다 — 지울 범위(from~to)까지', () => {
57
+ createEditor('<p>:smi</p>');
58
+ const match = findEmojiQuery(editor.state);
59
+ expect(match).toEqual({ from: 1, to: 5, query: 'smi' });
60
+ });
61
+ it('공백 뒤의 `:` 도 트리거다', () => {
62
+ createEditor('<p>hello :sm</p>');
63
+ const match = findEmojiQuery(editor.state);
64
+ expect(match?.query).toBe('sm');
65
+ expect(match?.from).toBe(7);
66
+ });
67
+ it('`:` 만 친 상태는 빈 검색어로 잡는다', () => {
68
+ createEditor('<p>:</p>');
69
+ expect(findEmojiQuery(editor.state)?.query).toBe('');
70
+ });
71
+ it('단어에 붙은 콜론(`예: 값` 류)은 트리거가 아니다', () => {
72
+ createEditor('<p>a:b</p>');
73
+ expect(findEmojiQuery(editor.state)).toBeNull();
74
+ });
75
+ it('`::` 는 트리거가 아니다 (C++ 스코프 연산자)', () => {
76
+ createEditor('<p>::x</p>');
77
+ expect(findEmojiQuery(editor.state)).toBeNull();
78
+ });
79
+ it('검색어에 공백이 들어오면 판정이 끝난다', () => {
80
+ createEditor('<p>:x y</p>');
81
+ expect(findEmojiQuery(editor.state)).toBeNull();
82
+ });
83
+ it('`/` 로 시작하는 줄은 슬래시 메뉴 영역 — 안 띄운다', () => {
84
+ createEditor('<p>/cmd :x</p>');
85
+ expect(findEmojiQuery(editor.state)).toBeNull();
86
+ });
87
+ it('코드블록 안에서는 안 띄운다', () => {
88
+ createEditor('<pre><code>:smi</code></pre>');
89
+ expect(findEmojiQuery(editor.state)).toBeNull();
90
+ });
91
+ it('선택이 펼쳐져 있으면(드래그) 안 띄운다', () => {
92
+ createEditor('<p>:smi</p>', false);
93
+ editor.commands.setTextSelection({ from: 1, to: 3 });
94
+ expect(findEmojiQuery(editor.state)).toBeNull();
95
+ });
96
+ it('삽입 흐름 — 판정한 범위를 지우고 이모지 + 공백이 남는다', () => {
97
+ createEditor('<p>:smile</p>');
98
+ const match = findEmojiQuery(editor.state);
99
+ expect(match).not.toBeNull();
100
+ const [{ emoji }] = searchEmojis(match.query);
101
+ editor
102
+ .chain()
103
+ .deleteRange({ from: match.from, to: match.to })
104
+ .insertContent(`${emoji} `)
105
+ .run();
106
+ expect(editor.getText()).toBe(`${emoji} `);
107
+ });
108
+ });
109
+ describe('이모지 자동완성 · 패턴 (EMOJI_QUERY_REGEX)', () => {
110
+ it('허용/차단 꼴을 못박는다', () => {
111
+ expect(EMOJI_QUERY_REGEX.test(':smi')).toBe(true);
112
+ expect(EMOJI_QUERY_REGEX.test('말 뒤 :smi')).toBe(true);
113
+ expect(EMOJI_QUERY_REGEX.test('word:smi')).toBe(false);
114
+ expect(EMOJI_QUERY_REGEX.test('std::vector')).toBe(false);
115
+ expect(EMOJI_QUERY_REGEX.test(':x 뒤공백')).toBe(false);
116
+ });
117
+ });
@@ -0,0 +1,60 @@
1
+ /**
2
+ * 빈 줄 플로팅 헬퍼의 **판정 절반** — 화면 절반은 `components/FloatingHelper.svelte`.
3
+ *
4
+ * 이모지 자동완성(`emoji-suggestion.ts` + `EmojiSuggestionMenu.svelte`)과 같은 분할이다:
5
+ * 상태 판정·커맨드는 여기(순수 TS, vitest 로 검증), 위치 계산·렌더는 컴포넌트가 맡는다.
6
+ *
7
+ * main(정올 `Floating.svelte`)은 svelte-tiptap `FloatingMenu` + floating-ui 를 썼지만
8
+ * 여기는 **직접 구현**이다 — 이 패키지에 svelte-tiptap 이 없고, floating-ui 는 tiptap
9
+ * 전이 의존성으로만 존재해(선언 안 됨) 기대면 안 된다. 등장 조건은 main 이 쓰던
10
+ * tiptap 기본 `shouldShow`(포커스된 최상위 빈 textblock)를 옮겨 왔다.
11
+ */
12
+ import type { Editor } from "@tiptap/core";
13
+ import type { EditorState } from "@tiptap/pm/state";
14
+ /**
15
+ * 헬퍼가 떠 있는 동안 에디터 루트(`.tiptap`)에 붙는 클래스.
16
+ *
17
+ * ⚠️ **placeholder 겹침 방지용이다.** 이 패키지는 `.is-empty::before` 로 커서가 있는
18
+ * 빈 블록마다 안내문을 띄우는데, 헬퍼도 같은 자리에 같은 취지의 문구를 띄운다 —
19
+ * 두 문구가 겹쳐 보인다. 그래서 헬퍼가 보이는 동안 `editor.css` 의
20
+ * `.tiptap.hce-floating-helper-on .is-empty::before` 규칙이 placeholder 를 숨긴다
21
+ * (main `82c412a9` 의 `floating-menu-visible` 과 같은 방식).
22
+ */
23
+ export declare const FLOATING_HELPER_ON_CLASS = "hce-floating-helper-on";
24
+ /**
25
+ * 상태만 보고 "헬퍼를 띄울 자리인가"를 판정한다.
26
+ *
27
+ * main 이 위임했던 tiptap FloatingMenu 기본 `shouldShow` 의 이식 + 한 가지 의도적 차이:
28
+ * - 커서가 접혀 있고(selection.empty)
29
+ * - 최상위 깊이(depth 1)의
30
+ * - **문단(paragraph)** 이며 — main 은 모든 textblock(빈 제목 포함)이었지만, 이
31
+ * 패키지는 빈 제목에 "제목 1" 같은 전용 placeholder 를 띄우므로 제목에서는
32
+ * placeholder 에게 자리를 내준다(제목에서 헬퍼가 뜨면 그 안내가 숨는다).
33
+ * - 내용이 완전히 비어 있어야 한다(`content.size === 0` — 인라인 수식·이미지처럼
34
+ * textContent 가 "" 인 노드가 들어 있어도 빈 줄이 아니다).
35
+ *
36
+ * 슬래시(`/…`)·이모지(`:…`) 트리거 텍스트가 있으면 블록이 비어 있지 않으므로
37
+ * 이 판정만으로도 두 팝업이 뜨는 동안에는 자연히 숨는다.
38
+ */
39
+ export declare function isEmptyRootParagraph(state: EditorState): boolean;
40
+ /**
41
+ * 최종 표시 판정. 포커스·읽기 전용·팝업 상호배제는 컴포넌트가 아는 값이라 주입받는다.
42
+ *
43
+ * `suppressed` 는 슬래시·이모지 메뉴 열림이다 — 위 판정으로도 대부분 숨지만,
44
+ * 두 팝업은 `position:fixed` 뷰포트 좌표라 좌표계가 달라 자동 회피가 안 되므로
45
+ * **열려 있는 동안은 무조건 끈다**(main `f0f955b1`·`b518d4f9` 의 lifecycle desync 교훈).
46
+ */
47
+ export declare function floatingHelperVisible(editor: Editor, opts: {
48
+ focused: boolean;
49
+ suppressed: boolean;
50
+ }): boolean;
51
+ /**
52
+ * 수식 버튼. 슬래시 메뉴의 `수식` 항목과 **같은 커맨드**를 쓴다 — 프롬프트(MathModal)를
53
+ * 띄워 수식 블록을 넣는다. main 은 빈 `math_inline` 노드를 심고 NodeSelection 으로
54
+ * 골라 두는 방식이었지만, 이 패키지의 수식 편집 진입점은 전부 프롬프트 경유라
55
+ * (입력 규칙 제외) 그 관례를 따른다.
56
+ */
57
+ export declare function helperInsertMath(editor: Editor): boolean;
58
+ /** 코드 버튼. 슬래시 메뉴의 `코드` 항목과 같은 커맨드다. */
59
+ export declare function helperInsertCodeBlock(editor: Editor): boolean;
60
+ //# sourceMappingURL=floating-helper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"floating-helper.d.ts","sourceRoot":"","sources":["../../src/utils/floating-helper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD;;;;;;;;GAQG;AACH,eAAO,MAAM,wBAAwB,2BAA2B,CAAC;AAEjE;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAOhE;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,GAC9C,OAAO,CAIT;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAExD;AAED,uCAAuC;AACvC,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE7D"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * 헬퍼가 떠 있는 동안 에디터 루트(`.tiptap`)에 붙는 클래스.
3
+ *
4
+ * ⚠️ **placeholder 겹침 방지용이다.** 이 패키지는 `.is-empty::before` 로 커서가 있는
5
+ * 빈 블록마다 안내문을 띄우는데, 헬퍼도 같은 자리에 같은 취지의 문구를 띄운다 —
6
+ * 두 문구가 겹쳐 보인다. 그래서 헬퍼가 보이는 동안 `editor.css` 의
7
+ * `.tiptap.hce-floating-helper-on .is-empty::before` 규칙이 placeholder 를 숨긴다
8
+ * (main `82c412a9` 의 `floating-menu-visible` 과 같은 방식).
9
+ */
10
+ export const FLOATING_HELPER_ON_CLASS = "hce-floating-helper-on";
11
+ /**
12
+ * 상태만 보고 "헬퍼를 띄울 자리인가"를 판정한다.
13
+ *
14
+ * main 이 위임했던 tiptap FloatingMenu 기본 `shouldShow` 의 이식 + 한 가지 의도적 차이:
15
+ * - 커서가 접혀 있고(selection.empty)
16
+ * - 최상위 깊이(depth 1)의
17
+ * - **문단(paragraph)** 이며 — main 은 모든 textblock(빈 제목 포함)이었지만, 이
18
+ * 패키지는 빈 제목에 "제목 1" 같은 전용 placeholder 를 띄우므로 제목에서는
19
+ * placeholder 에게 자리를 내준다(제목에서 헬퍼가 뜨면 그 안내가 숨는다).
20
+ * - 내용이 완전히 비어 있어야 한다(`content.size === 0` — 인라인 수식·이미지처럼
21
+ * textContent 가 "" 인 노드가 들어 있어도 빈 줄이 아니다).
22
+ *
23
+ * 슬래시(`/…`)·이모지(`:…`) 트리거 텍스트가 있으면 블록이 비어 있지 않으므로
24
+ * 이 판정만으로도 두 팝업이 뜨는 동안에는 자연히 숨는다.
25
+ */
26
+ export function isEmptyRootParagraph(state) {
27
+ const { $anchor, empty } = state.selection;
28
+ if (!empty)
29
+ return false;
30
+ if ($anchor.depth !== 1)
31
+ return false;
32
+ const parent = $anchor.parent;
33
+ if (parent.type.name !== "paragraph")
34
+ return false;
35
+ return parent.content.size === 0;
36
+ }
37
+ /**
38
+ * 최종 표시 판정. 포커스·읽기 전용·팝업 상호배제는 컴포넌트가 아는 값이라 주입받는다.
39
+ *
40
+ * `suppressed` 는 슬래시·이모지 메뉴 열림이다 — 위 판정으로도 대부분 숨지만,
41
+ * 두 팝업은 `position:fixed` 뷰포트 좌표라 좌표계가 달라 자동 회피가 안 되므로
42
+ * **열려 있는 동안은 무조건 끈다**(main `f0f955b1`·`b518d4f9` 의 lifecycle desync 교훈).
43
+ */
44
+ export function floatingHelperVisible(editor, opts) {
45
+ if (!editor.isEditable)
46
+ return false;
47
+ if (!opts.focused || opts.suppressed)
48
+ return false;
49
+ return isEmptyRootParagraph(editor.state);
50
+ }
51
+ /**
52
+ * 수식 버튼. 슬래시 메뉴의 `수식` 항목과 **같은 커맨드**를 쓴다 — 프롬프트(MathModal)를
53
+ * 띄워 수식 블록을 넣는다. main 은 빈 `math_inline` 노드를 심고 NodeSelection 으로
54
+ * 골라 두는 방식이었지만, 이 패키지의 수식 편집 진입점은 전부 프롬프트 경유라
55
+ * (입력 규칙 제외) 그 관례를 따른다.
56
+ */
57
+ export function helperInsertMath(editor) {
58
+ return editor.chain().focus().promptMathDisplay().run();
59
+ }
60
+ /** 코드 버튼. 슬래시 메뉴의 `코드` 항목과 같은 커맨드다. */
61
+ export function helperInsertCodeBlock(editor) {
62
+ return editor.chain().focus().setCodeBlock().run();
63
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=floating-helper.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"floating-helper.test.d.ts","sourceRoot":"","sources":["../../src/utils/floating-helper.test.ts"],"names":[],"mappings":""}