@placeholderco/placeholder-ui 1.0.12 → 2.0.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 (276) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +134 -130
  3. package/dist/app.css +178 -0
  4. package/dist/bootstrap.min.css +3600 -0
  5. package/dist/cards/GitCard.svelte +115 -0
  6. package/dist/cards/GitCard.svelte.d.ts +22 -0
  7. package/dist/display/Avatar.svelte +29 -17
  8. package/dist/display/Avatar.svelte.d.ts +12 -2
  9. package/dist/display/LinkCollection.svelte +40 -18
  10. package/dist/display/LinkCollection.svelte.d.ts +9 -2
  11. package/dist/display/Paper.svelte +31 -19
  12. package/dist/display/Paper.svelte.d.ts +12 -3
  13. package/dist/display/alert/Alert.svelte +129 -0
  14. package/dist/display/alert/Alert.svelte.d.ts +15 -0
  15. package/dist/display/alert/AlertVariant.d.ts +1 -0
  16. package/dist/display/alert/AlertVariant.js +1 -0
  17. package/dist/display/filetree/FileTree.svelte +259 -0
  18. package/dist/display/filetree/FileTree.svelte.d.ts +76 -0
  19. package/dist/display/filetree/FileTreeItem.svelte +396 -0
  20. package/dist/display/filetree/FileTreeItem.svelte.d.ts +40 -0
  21. package/dist/display/filetree/FileTreeNode.d.ts +46 -0
  22. package/dist/display/filetree/FileTreeNode.js +115 -0
  23. package/dist/display/filetree/index.d.ts +5 -0
  24. package/dist/display/filetree/index.js +3 -0
  25. package/dist/editors/CodeMirror.svelte +306 -0
  26. package/dist/editors/CodeMirror.svelte.d.ts +31 -0
  27. package/dist/editors/tiptap/LinkActionMenu.svelte +307 -0
  28. package/dist/editors/tiptap/LinkActionMenu.svelte.d.ts +8 -0
  29. package/dist/editors/tiptap/TipTap.svelte +856 -0
  30. package/dist/editors/tiptap/TipTap.svelte.d.ts +54 -0
  31. package/dist/editors/tiptap/TipTapBubble.svelte +790 -0
  32. package/dist/editors/tiptap/TipTapBubble.svelte.d.ts +44 -0
  33. package/dist/editors/tiptap/collaboration.d.ts +55 -0
  34. package/dist/editors/tiptap/collaboration.js +1 -0
  35. package/dist/editors/tiptap/extensions/Alert.d.ts +18 -0
  36. package/dist/editors/tiptap/extensions/Alert.js +72 -0
  37. package/dist/editors/tiptap/extensions/CodeBlockEditor.d.ts +21 -0
  38. package/dist/editors/tiptap/extensions/CodeBlockEditor.js +326 -0
  39. package/dist/editors/tiptap/extensions/Div.d.ts +19 -0
  40. package/dist/editors/tiptap/extensions/Div.js +89 -0
  41. package/dist/editors/tiptap/extensions/Span.d.ts +5 -0
  42. package/dist/editors/tiptap/extensions/Span.js +56 -0
  43. package/dist/editors/tiptap/extensions/codeBlockEditor.css +236 -0
  44. package/dist/editors/tiptap/extensions/codeBlockLanguages.d.ts +17 -0
  45. package/dist/editors/tiptap/extensions/codeBlockLanguages.js +124 -0
  46. package/dist/editors/tiptap/extensions/index.d.ts +7 -0
  47. package/dist/editors/tiptap/extensions/index.js +5 -0
  48. package/dist/editors/tiptap/toolbar/AlertButton.svelte +261 -0
  49. package/dist/editors/tiptap/toolbar/AlertButton.svelte.d.ts +7 -0
  50. package/dist/editors/tiptap/toolbar/AlignCenterButton.svelte +18 -0
  51. package/dist/editors/tiptap/toolbar/AlignCenterButton.svelte.d.ts +7 -0
  52. package/dist/editors/tiptap/toolbar/AlignJustifyButton.svelte +18 -0
  53. package/dist/editors/tiptap/toolbar/AlignJustifyButton.svelte.d.ts +7 -0
  54. package/dist/editors/tiptap/toolbar/AlignLeftButton.svelte +18 -0
  55. package/dist/editors/tiptap/toolbar/AlignLeftButton.svelte.d.ts +7 -0
  56. package/dist/editors/tiptap/toolbar/AlignRightButton.svelte +18 -0
  57. package/dist/editors/tiptap/toolbar/AlignRightButton.svelte.d.ts +7 -0
  58. package/dist/editors/tiptap/toolbar/BoldButton.svelte +18 -0
  59. package/dist/editors/tiptap/toolbar/BoldButton.svelte.d.ts +7 -0
  60. package/dist/editors/tiptap/toolbar/BulletListButton.svelte +18 -0
  61. package/dist/editors/tiptap/toolbar/BulletListButton.svelte.d.ts +7 -0
  62. package/dist/editors/tiptap/toolbar/CodeBlockButton.svelte +18 -0
  63. package/dist/editors/tiptap/toolbar/CodeBlockButton.svelte.d.ts +7 -0
  64. package/dist/editors/tiptap/toolbar/CodeButton.svelte +18 -0
  65. package/dist/editors/tiptap/toolbar/CodeButton.svelte.d.ts +7 -0
  66. package/dist/editors/tiptap/toolbar/ColorButton.svelte +299 -0
  67. package/dist/editors/tiptap/toolbar/ColorButton.svelte.d.ts +20 -0
  68. package/dist/editors/tiptap/toolbar/DocumentButton.svelte +58 -0
  69. package/dist/editors/tiptap/toolbar/DocumentButton.svelte.d.ts +9 -0
  70. package/dist/editors/tiptap/toolbar/HeadingButton.svelte +30 -0
  71. package/dist/editors/tiptap/toolbar/HeadingButton.svelte.d.ts +8 -0
  72. package/dist/editors/tiptap/toolbar/HtmlButton.svelte +68 -0
  73. package/dist/editors/tiptap/toolbar/HtmlButton.svelte.d.ts +7 -0
  74. package/dist/editors/tiptap/toolbar/ImageButton.svelte +54 -0
  75. package/dist/editors/tiptap/toolbar/ImageButton.svelte.d.ts +8 -0
  76. package/dist/editors/tiptap/toolbar/ItalicButton.svelte +18 -0
  77. package/dist/editors/tiptap/toolbar/ItalicButton.svelte.d.ts +7 -0
  78. package/dist/editors/tiptap/toolbar/LinkButton.svelte +257 -0
  79. package/dist/editors/tiptap/toolbar/LinkButton.svelte.d.ts +7 -0
  80. package/dist/editors/tiptap/toolbar/OrderedListButton.svelte +18 -0
  81. package/dist/editors/tiptap/toolbar/OrderedListButton.svelte.d.ts +7 -0
  82. package/dist/editors/tiptap/toolbar/RedoButton.svelte +18 -0
  83. package/dist/editors/tiptap/toolbar/RedoButton.svelte.d.ts +7 -0
  84. package/dist/editors/tiptap/toolbar/StrikethroughButton.svelte +18 -0
  85. package/dist/editors/tiptap/toolbar/StrikethroughButton.svelte.d.ts +7 -0
  86. package/dist/editors/tiptap/toolbar/SubscriptButton.svelte +18 -0
  87. package/dist/editors/tiptap/toolbar/SubscriptButton.svelte.d.ts +7 -0
  88. package/dist/editors/tiptap/toolbar/SuperscriptButton.svelte +18 -0
  89. package/dist/editors/tiptap/toolbar/SuperscriptButton.svelte.d.ts +7 -0
  90. package/dist/editors/tiptap/toolbar/TableButton.svelte +258 -0
  91. package/dist/editors/tiptap/toolbar/TableButton.svelte.d.ts +7 -0
  92. package/dist/editors/tiptap/toolbar/ToolbarButton.svelte +84 -0
  93. package/dist/editors/tiptap/toolbar/ToolbarButton.svelte.d.ts +10 -0
  94. package/dist/editors/tiptap/toolbar/UnderlineButton.svelte +18 -0
  95. package/dist/editors/tiptap/toolbar/UnderlineButton.svelte.d.ts +7 -0
  96. package/dist/editors/tiptap/toolbar/UndoButton.svelte +18 -0
  97. package/dist/editors/tiptap/toolbar/UndoButton.svelte.d.ts +7 -0
  98. package/dist/form/Autocomplete.svelte +86 -135
  99. package/dist/form/Autocomplete.svelte.d.ts +6 -8
  100. package/dist/form/AutocompleteMulti.svelte +385 -227
  101. package/dist/form/AutocompleteMulti.svelte.d.ts +59 -10
  102. package/dist/form/Checkbox.svelte +59 -54
  103. package/dist/form/Checkbox.svelte.d.ts +14 -5
  104. package/dist/form/Chips.svelte +29 -13
  105. package/dist/form/Chips.svelte.d.ts +16 -2
  106. package/dist/form/ComboBox.svelte +30 -20
  107. package/dist/form/ComboBox.svelte.d.ts +1 -1
  108. package/dist/form/ComboBoxItemBuilder.svelte +161 -188
  109. package/dist/form/ComboBoxItemBuilder.svelte.d.ts +19 -2
  110. package/dist/form/ComboBoxMulti.svelte +38 -24
  111. package/dist/form/ComboBoxMulti.svelte.d.ts +1 -1
  112. package/dist/form/CronBuilder.svelte +84 -67
  113. package/dist/form/CronBuilder.svelte.d.ts +16 -3
  114. package/dist/form/DatePicker.svelte +148 -195
  115. package/dist/form/DateRangePicker.svelte +101 -98
  116. package/dist/form/DateTimePicker.svelte +167 -208
  117. package/dist/form/DateTimePicker.svelte.d.ts +10 -2
  118. package/dist/form/FormGroup.svelte +33 -10
  119. package/dist/form/FormGroup.svelte.d.ts +12 -2
  120. package/dist/form/Number.svelte +70 -47
  121. package/dist/form/Number.svelte.d.ts +36 -6
  122. package/dist/form/Radio.svelte +18 -18
  123. package/dist/form/RadioGroup.svelte +23 -12
  124. package/dist/form/RadioGroup.svelte.d.ts +13 -2
  125. package/dist/form/SegmentedControl.svelte +76 -56
  126. package/dist/form/SegmentedControl.svelte.d.ts +9 -4
  127. package/dist/form/Select.svelte +150 -233
  128. package/dist/form/Select.svelte.d.ts +29 -5
  129. package/dist/form/SelectMulti.svelte +163 -277
  130. package/dist/form/SelectMulti.svelte.d.ts +36 -7
  131. package/dist/form/Slider.svelte +183 -269
  132. package/dist/form/Slider.svelte.d.ts +32 -17
  133. package/dist/form/StringArrayBuilder.svelte +249 -0
  134. package/dist/form/StringArrayBuilder.svelte.d.ts +15 -0
  135. package/dist/form/Switch.svelte +164 -106
  136. package/dist/form/Switch.svelte.d.ts +22 -3
  137. package/dist/form/TextArea.svelte +49 -29
  138. package/dist/form/TextArea.svelte.d.ts +23 -3
  139. package/dist/form/Textbox.svelte +69 -68
  140. package/dist/form/Textbox.svelte.d.ts +32 -4
  141. package/dist/form/TimePicker.svelte +42 -47
  142. package/dist/form/TimePicker.svelte.d.ts +12 -2
  143. package/dist/form/comboBoxCore.svelte.d.ts +99 -0
  144. package/dist/form/comboBoxCore.svelte.js +243 -0
  145. package/dist/icon/Icon.svelte +8 -3
  146. package/dist/icon/Icon.svelte.d.ts +8 -3
  147. package/dist/icon/file-type-bmp.svg +1 -0
  148. package/dist/icon/file-type-csv.svg +1 -0
  149. package/dist/icon/file-type-doc.svg +1 -0
  150. package/dist/icon/file-type-docx.svg +1 -0
  151. package/dist/icon/file-type-jpg.svg +1 -0
  152. package/dist/icon/file-type-pdf.svg +1 -0
  153. package/dist/icon/file-type-png.svg +1 -0
  154. package/dist/icon/file-type-ppt.svg +1 -0
  155. package/dist/icon/file-type-svg.svg +1 -0
  156. package/dist/icon/file-type-txt.svg +1 -0
  157. package/dist/icon/file-type-xls.svg +1 -0
  158. package/dist/icon/file-type-zip.svg +1 -0
  159. package/dist/icon/index.d.ts +166 -151
  160. package/dist/icon/index.js +166 -152
  161. package/dist/icon/logo-placeholder.svg +6 -0
  162. package/dist/icon/source-code.svg +1 -0
  163. package/dist/icon/sun-moon.svg +1 -0
  164. package/dist/icon/table.svg +6 -0
  165. package/dist/index.d.ts +87 -26
  166. package/dist/index.js +25 -28
  167. package/dist/layout/AppShell.svelte +12 -162
  168. package/dist/layout/AppShell.svelte.d.ts +6 -27
  169. package/dist/layout/CustomNavbar.svelte +9 -7
  170. package/dist/layout/CustomNavbar.svelte.d.ts +4 -2
  171. package/dist/layout/Navbar.svelte +161 -129
  172. package/dist/layout/Navbar.svelte.d.ts +29 -15
  173. package/dist/layout/NavbarItemDisplay.svelte +2 -2
  174. package/dist/layout/NavbarItemView.svelte +182 -0
  175. package/dist/layout/NavbarItemView.svelte.d.ts +10 -0
  176. package/dist/layout/Sidenav.svelte +280 -341
  177. package/dist/layout/Sidenav.svelte.d.ts +36 -4
  178. package/dist/models/ComboBoxItem.d.ts +2 -0
  179. package/dist/models/Employee.d.ts +53 -0
  180. package/dist/models/Employee.js +23 -0
  181. package/dist/models/Hyperlink.d.ts +3 -1
  182. package/dist/models/LinkCollectionItem.d.ts +3 -1
  183. package/dist/models/NavbarItem.d.ts +6 -2
  184. package/dist/theme.svelte.d.ts +0 -1
  185. package/dist/theme.svelte.js +46 -58
  186. package/dist/ui/Accordion.svelte +81 -242
  187. package/dist/ui/Accordion.svelte.d.ts +37 -14
  188. package/dist/ui/AccordionItem.svelte +303 -0
  189. package/dist/ui/AccordionItem.svelte.d.ts +21 -0
  190. package/dist/ui/ActionIcon.svelte +25 -21
  191. package/dist/ui/ActionIcon.svelte.d.ts +15 -2
  192. package/dist/ui/Badge.svelte +163 -171
  193. package/dist/ui/Badge.svelte.d.ts +13 -5
  194. package/dist/ui/Button.svelte +178 -205
  195. package/dist/ui/Button.svelte.d.ts +19 -2
  196. package/dist/ui/ButtonVariant.d.ts +15 -1
  197. package/dist/ui/ContextMenu.svelte +146 -0
  198. package/dist/ui/ContextMenu.svelte.d.ts +37 -0
  199. package/dist/ui/ContextMenuList.svelte +188 -0
  200. package/dist/ui/ContextMenuList.svelte.d.ts +12 -0
  201. package/dist/ui/Dialog.svelte +183 -111
  202. package/dist/ui/Dialog.svelte.d.ts +21 -4
  203. package/dist/ui/Drawer.svelte +237 -184
  204. package/dist/ui/Drawer.svelte.d.ts +20 -2
  205. package/dist/ui/Dropdown.svelte +24 -14
  206. package/dist/ui/Dropdown.svelte.d.ts +11 -2
  207. package/dist/ui/Dropzone.svelte +159 -57
  208. package/dist/ui/Dropzone.svelte.d.ts +29 -2
  209. package/dist/ui/Link.svelte +12 -4
  210. package/dist/ui/Link.svelte.d.ts +8 -2
  211. package/dist/ui/Loader.svelte +23 -18
  212. package/dist/ui/Loader.svelte.d.ts +5 -2
  213. package/dist/ui/Logo.svelte +37 -0
  214. package/dist/ui/Logo.svelte.d.ts +16 -0
  215. package/dist/ui/MultiSortable.svelte +287 -0
  216. package/dist/ui/MultiSortable.svelte.d.ts +50 -0
  217. package/dist/ui/Pagination.svelte +15 -9
  218. package/dist/ui/Pagination.svelte.d.ts +6 -2
  219. package/dist/ui/Popover.svelte +43 -65
  220. package/dist/ui/Popover.svelte.d.ts +14 -5
  221. package/dist/ui/ProgressBar.svelte +28 -30
  222. package/dist/ui/ProgressBarVariant.d.ts +7 -1
  223. package/dist/ui/SegmentedControl.svelte +0 -0
  224. package/dist/ui/SegmentedControl.svelte.d.ts +26 -0
  225. package/dist/ui/Sortable.svelte +163 -0
  226. package/dist/ui/Sortable.svelte.d.ts +47 -0
  227. package/dist/ui/Table.svelte +383 -80
  228. package/dist/ui/Table.svelte.d.ts +43 -2
  229. package/dist/ui/Tabs.svelte +22 -18
  230. package/dist/ui/Tabs.svelte.d.ts +6 -2
  231. package/dist/ui/ThemeSwitcher.svelte +26 -7
  232. package/dist/ui/ThemeSwitcher.svelte.d.ts +4 -2
  233. package/dist/ui/Tooltip.svelte +312 -180
  234. package/dist/ui/Tooltip.svelte.d.ts +4 -3
  235. package/dist/uiTheme.svelte.d.ts +86 -0
  236. package/dist/uiTheme.svelte.js +214 -0
  237. package/dist/util/DateFunctions.js +1 -1
  238. package/dist/util/DragDrop.d.ts +50 -0
  239. package/dist/util/DragDrop.js +154 -0
  240. package/dist/util/NavigateTo.js +2 -2
  241. package/dist/util/dayjs.d.ts +4 -0
  242. package/dist/util/dayjs.js +15 -0
  243. package/package.json +66 -26
  244. package/dist/display/Alert.svelte +0 -179
  245. package/dist/display/Alert.svelte.d.ts +0 -13
  246. package/dist/form/FileInput.svelte +0 -235
  247. package/dist/form/FileInput.svelte.d.ts +0 -23
  248. package/dist/form/PasswordInput.svelte +0 -253
  249. package/dist/form/PasswordInput.svelte.d.ts +0 -34
  250. package/dist/form/Rating.svelte +0 -235
  251. package/dist/form/Rating.svelte.d.ts +0 -21
  252. package/dist/styles/components.css +0 -199
  253. package/dist/styles/dark.css +0 -146
  254. package/dist/styles/index.css +0 -116
  255. package/dist/styles/reset.css +0 -110
  256. package/dist/styles/semantic.css +0 -86
  257. package/dist/styles/tokens.css +0 -203
  258. package/dist/styles/utilities.css +0 -523
  259. package/dist/ui/Breadcrumbs.svelte +0 -131
  260. package/dist/ui/Breadcrumbs.svelte.d.ts +0 -16
  261. package/dist/ui/LoadingOverlay.svelte +0 -53
  262. package/dist/ui/LoadingOverlay.svelte.d.ts +0 -11
  263. package/dist/ui/Progress.svelte +0 -191
  264. package/dist/ui/Progress.svelte.d.ts +0 -15
  265. package/dist/ui/RingProgress.svelte +0 -141
  266. package/dist/ui/RingProgress.svelte.d.ts +0 -18
  267. package/dist/ui/Skeleton.svelte +0 -85
  268. package/dist/ui/Skeleton.svelte.d.ts +0 -12
  269. package/dist/ui/Stepper.svelte +0 -355
  270. package/dist/ui/Stepper.svelte.d.ts +0 -24
  271. package/dist/ui/Timeline.svelte +0 -225
  272. package/dist/ui/Timeline.svelte.d.ts +0 -23
  273. /package/dist/{actions → util}/ClickOutside.d.ts +0 -0
  274. /package/dist/{actions → util}/ClickOutside.js +0 -0
  275. /package/dist/{transitions → util}/Transitions.d.ts +0 -0
  276. /package/dist/{transitions → util}/Transitions.js +0 -0
@@ -0,0 +1,856 @@
1
+ <script lang="ts">
2
+ import { onMount, onDestroy } from 'svelte';
3
+ import { Editor, Extension, type AnyExtension } from '@tiptap/core';
4
+ import { StarterKit } from '@tiptap/starter-kit';
5
+ import { BubbleMenu } from '@tiptap/extension-bubble-menu';
6
+ import Underline from '@tiptap/extension-underline';
7
+ import TextAlign from '@tiptap/extension-text-align';
8
+ import Link from '@tiptap/extension-link';
9
+ import Subscript from '@tiptap/extension-subscript';
10
+ import Superscript from '@tiptap/extension-superscript';
11
+ import Image from '@tiptap/extension-image';
12
+ import { TableKit } from '@tiptap/extension-table';
13
+ import Color from '@tiptap/extension-color';
14
+ import Placeholder from '@tiptap/extension-placeholder';
15
+ import { TextStyle } from '@tiptap/extension-text-style';
16
+ import Collaboration from '@tiptap/extension-collaboration';
17
+ import { CollaborationCaret } from '@tiptap/extension-collaboration-caret';
18
+ import { Alert, CodeBlockEditor, Div, Span, type CodeBlocksOptions } from './extensions/index.js';
19
+ import type { CollaborationConfig } from './collaboration.js';
20
+ import FormGroup from '../../form/FormGroup.svelte';
21
+ import LinkActionMenu from './LinkActionMenu.svelte';
22
+ import UndoButton from './toolbar/UndoButton.svelte';
23
+ import RedoButton from './toolbar/RedoButton.svelte';
24
+ import HeadingButton from './toolbar/HeadingButton.svelte';
25
+ import BulletListButton from './toolbar/BulletListButton.svelte';
26
+ import OrderedListButton from './toolbar/OrderedListButton.svelte';
27
+ import BoldButton from './toolbar/BoldButton.svelte';
28
+ import ItalicButton from './toolbar/ItalicButton.svelte';
29
+ import StrikethroughButton from './toolbar/StrikethroughButton.svelte';
30
+ import CodeButton from './toolbar/CodeButton.svelte';
31
+ import UnderlineButton from './toolbar/UnderlineButton.svelte';
32
+ import ColorButton from './toolbar/ColorButton.svelte';
33
+ import LinkButton from './toolbar/LinkButton.svelte';
34
+ import SuperscriptButton from './toolbar/SuperscriptButton.svelte';
35
+ import SubscriptButton from './toolbar/SubscriptButton.svelte';
36
+ import AlignLeftButton from './toolbar/AlignLeftButton.svelte';
37
+ import AlignCenterButton from './toolbar/AlignCenterButton.svelte';
38
+ import AlignRightButton from './toolbar/AlignRightButton.svelte';
39
+ import AlignJustifyButton from './toolbar/AlignJustifyButton.svelte';
40
+ import ImageButton from './toolbar/ImageButton.svelte';
41
+ import AlertButton from './toolbar/AlertButton.svelte';
42
+ import HtmlButton from './toolbar/HtmlButton.svelte';
43
+ import DocumentButton from './toolbar/DocumentButton.svelte';
44
+ import TableButton from './toolbar/TableButton.svelte';
45
+ import CodeBlockButton from './toolbar/CodeBlockButton.svelte';
46
+
47
+ /** Result returned from a document upload: the link text and its destination URL */
48
+ export interface DocumentUploadResult {
49
+ /** Visible link text inserted into the editor */
50
+ label: string;
51
+ /** Destination URL the hyperlink points to */
52
+ url: string;
53
+ }
54
+
55
+ export interface TipTapProps {
56
+ /** HTML content value (bindable). Ignored when collaboration is enabled. */
57
+ value?: string;
58
+ /** Label text displayed above the editor */
59
+ label?: string;
60
+ /** Mark field as required (shows asterisk) */
61
+ required?: boolean;
62
+ /** CSS classes for the FormGroup wrapper */
63
+ groupClass?: string;
64
+ /** Tooltip text on hover */
65
+ tooltipText?: string;
66
+ /** Position of the tooltip */
67
+ tooltipLocation?: 'top' | 'bottom' | 'left' | 'right';
68
+ /** Enable editing mode */
69
+ editable?: boolean;
70
+ /** Placeholder text when editor is empty */
71
+ placeholder?: string;
72
+ /** Additional CSS classes */
73
+ class?: string;
74
+ /** Async handler for image uploads, returns URL or null */
75
+ onImageUpload?: (file: File) => Promise<string | null>;
76
+ /** Async handler for document uploads. The app uploads the file and returns the
77
+ * link label and URL, which are inserted as a hyperlink. Returns null to cancel. */
78
+ onDocumentUpload?: (file: File) => Promise<DocumentUploadResult | null>;
79
+ /** Callback when content changes */
80
+ onUpdate?: (html: string) => void;
81
+ /** Opt-in real-time collaboration config. When provided, content syncs via Yjs. */
82
+ collaboration?: CollaborationConfig;
83
+ /** Opt-in rich code blocks: CodeMirror-powered editing with syntax highlighting,
84
+ * autocompletion and a per-block language picker. Pass true for all languages
85
+ * or a config to narrow the offered languages and set the default. */
86
+ codeBlocks?: boolean | CodeBlocksOptions;
87
+ /** Additional TipTap extensions to register with the editor */
88
+ extensions?: AnyExtension[];
89
+ }
90
+
91
+ let {
92
+ value = $bindable(''),
93
+ label = '',
94
+ required = false,
95
+ groupClass = '',
96
+ tooltipText = undefined,
97
+ tooltipLocation = 'top',
98
+ editable = true,
99
+ placeholder = 'Start typing...',
100
+ class: className = '',
101
+ onImageUpload,
102
+ onDocumentUpload,
103
+ onUpdate,
104
+ collaboration,
105
+ codeBlocks = false,
106
+ extensions: customExtensions = []
107
+ }: TipTapProps = $props();
108
+
109
+ let element: HTMLElement | undefined = $state();
110
+ let linkBubbleMenuElement: HTMLDivElement | undefined = $state();
111
+ let editorState: { editor: Editor | null } = $state({ editor: null });
112
+ let isDragging = $state(false);
113
+
114
+ // Handle dropped files
115
+ async function handleDrop(event: DragEvent) {
116
+ if (!onImageUpload || !editorState.editor) return;
117
+
118
+ event.preventDefault();
119
+ isDragging = false;
120
+
121
+ const files = event.dataTransfer?.files;
122
+ if (!files?.length) return;
123
+
124
+ for (const file of files) {
125
+ if (file.type.startsWith('image/')) {
126
+ const imageUrl = await onImageUpload(file);
127
+ if (imageUrl) {
128
+ editorState.editor.chain().focus().setImage({ src: imageUrl }).run();
129
+ }
130
+ }
131
+ }
132
+ }
133
+
134
+ // Handle drag over
135
+ function handleDragOver(event: DragEvent) {
136
+ if (!onImageUpload) return;
137
+ event.preventDefault();
138
+ isDragging = true;
139
+ }
140
+
141
+ // Handle drag leave
142
+ function handleDragLeave(event: DragEvent) {
143
+ if (!onImageUpload) return;
144
+ // Only set to false if we're leaving the container entirely
145
+ const relatedTarget = event.relatedTarget as Node | null;
146
+ if (!element?.contains(relatedTarget)) {
147
+ isDragging = false;
148
+ }
149
+ }
150
+
151
+ // Handle paste events
152
+ async function handlePaste(event: ClipboardEvent) {
153
+ if (!onImageUpload || !editorState.editor) return;
154
+
155
+ const items = event.clipboardData?.items;
156
+ if (!items) return;
157
+
158
+ for (const item of items) {
159
+ if (item.type.startsWith('image/')) {
160
+ event.preventDefault();
161
+ const file = item.getAsFile();
162
+ if (file) {
163
+ const imageUrl = await onImageUpload(file);
164
+ if (imageUrl) {
165
+ editorState.editor.chain().focus().setImage({ src: imageUrl }).run();
166
+ }
167
+ }
168
+ break;
169
+ }
170
+ }
171
+ }
172
+
173
+ // Strip color declarations from inline styles in pasted HTML so pasted text
174
+ // inherits the editor's colours instead of carrying over the source colours.
175
+ function stripPastedColors(html: string): string {
176
+ if (typeof window === 'undefined') return html;
177
+
178
+ const container = document.createElement('div');
179
+ container.innerHTML = html;
180
+
181
+ container.querySelectorAll<HTMLElement>('[style]').forEach((el) => {
182
+ const cleaned = el.style.cssText
183
+ .split(';')
184
+ .map((decl) => decl.trim())
185
+ .filter((decl) => {
186
+ if (!decl) return false;
187
+ const prop = decl.slice(0, decl.indexOf(':')).trim().toLowerCase();
188
+ return prop !== 'color' && prop !== '-webkit-text-fill-color';
189
+ })
190
+ .join('; ');
191
+
192
+ if (cleaned) {
193
+ el.setAttribute('style', cleaned);
194
+ } else {
195
+ el.removeAttribute('style');
196
+ }
197
+ });
198
+
199
+ // Drop legacy <font color> attributes as well.
200
+ container.querySelectorAll('font[color]').forEach((el) => el.removeAttribute('color'));
201
+
202
+ return container.innerHTML;
203
+ }
204
+
205
+ function handleEditorClick(event: MouseEvent) {
206
+ const target = event.target as HTMLElement | null;
207
+ const link = target?.closest('a');
208
+
209
+ if (!link || !element?.contains(link)) {
210
+ return;
211
+ }
212
+
213
+ event.preventDefault();
214
+
215
+ const position = editorState.editor?.view.posAtCoords({
216
+ left: event.clientX,
217
+ top: event.clientY
218
+ });
219
+
220
+ if (position) {
221
+ editorState.editor?.chain().setTextSelection(position.pos).extendMarkRange('link').run();
222
+ }
223
+ }
224
+
225
+ // Custom Tab Handler Extension
226
+ const TabHandler = Extension.create({
227
+ name: 'tabHandler',
228
+
229
+ addKeyboardShortcuts() {
230
+ return {
231
+ Tab: ({ editor }) => {
232
+ // Rich code blocks handle Tab inside CodeMirror; never replace a
233
+ // selected code block with spaces
234
+ if (codeBlocks && editor.isActive('codeBlock')) {
235
+ return false;
236
+ }
237
+
238
+ // If in a list, indent the list item
239
+ if (editor.isActive('listItem')) {
240
+ return editor.commands.sinkListItem('listItem');
241
+ }
242
+
243
+ // If in a table, move to the next cell
244
+ if (editor.isActive('table')) {
245
+ return editor.commands.goToNextCell();
246
+ }
247
+
248
+ // Otherwise, insert two spaces (or you can use '\t' for a tab character)
249
+ return editor.commands.insertContent(' ');
250
+ },
251
+ 'Shift-Tab': ({ editor }) => {
252
+ // If in a list, outdent the list item
253
+ if (editor.isActive('listItem')) {
254
+ return editor.commands.liftListItem('listItem');
255
+ }
256
+
257
+ // If in a table, move to the previous cell
258
+ if (editor.isActive('table')) {
259
+ return editor.commands.goToPreviousCell();
260
+ }
261
+
262
+ return false;
263
+ }
264
+ };
265
+ }
266
+ });
267
+
268
+ onMount(() => {
269
+ const extensions = [
270
+ // Div and Span must come before StarterKit to have higher priority
271
+ Div,
272
+ Span,
273
+ StarterKit.configure({
274
+ undoRedo: collaboration ? false : undefined,
275
+ link: false,
276
+ underline: false,
277
+ codeBlock: codeBlocks ? false : undefined
278
+ }),
279
+ Underline,
280
+ TextStyle,
281
+ Color,
282
+ Placeholder.configure({
283
+ placeholder: placeholder
284
+ }),
285
+ TextAlign.configure({
286
+ types: ['heading', 'paragraph', 'div', 'span']
287
+ }),
288
+ Link.configure({
289
+ openOnClick: false,
290
+ enableClickSelection: true,
291
+ HTMLAttributes: {
292
+ class: 'editor-link'
293
+ }
294
+ }),
295
+ Subscript,
296
+ Superscript,
297
+ Image,
298
+ Alert,
299
+ TabHandler,
300
+ TableKit.configure({ table: { resizable: true } }),
301
+ ...customExtensions
302
+ ];
303
+
304
+ if (codeBlocks) {
305
+ const codeBlocksConfig = typeof codeBlocks === 'object' ? codeBlocks : {};
306
+ extensions.push(
307
+ CodeBlockEditor.configure({
308
+ languages: codeBlocksConfig.languages ?? null,
309
+ defaultLanguage: codeBlocksConfig.defaultLanguage ?? 'javascript'
310
+ })
311
+ );
312
+ }
313
+
314
+ if (linkBubbleMenuElement) {
315
+ extensions.push(
316
+ BubbleMenu.configure({
317
+ pluginKey: 'linkActionBubbleMenu',
318
+ element: linkBubbleMenuElement,
319
+ shouldShow: ({ editor }) => Boolean(editor.getAttributes('link').href),
320
+ options: {
321
+ placement: 'top',
322
+ offset: 8
323
+ }
324
+ })
325
+ );
326
+ }
327
+
328
+ if (collaboration) {
329
+ extensions.push(
330
+ Collaboration.configure({ fragment: collaboration.fragment }),
331
+ CollaborationCaret.configure({
332
+ provider: collaboration.provider,
333
+ user: collaboration.user
334
+ })
335
+ );
336
+ }
337
+
338
+ editorState.editor = new Editor({
339
+ element: element,
340
+ extensions,
341
+ content: collaboration ? undefined : value,
342
+ editable: editable,
343
+ editorProps: {
344
+ transformPastedHTML: stripPastedColors
345
+ },
346
+ onTransaction: ({ editor }) => {
347
+ // Trigger reactivity
348
+ editorState = { editor };
349
+ },
350
+ onUpdate: ({ editor }) => {
351
+ const html = editor.getHTML();
352
+ value = html;
353
+ if (onUpdate) {
354
+ onUpdate(html);
355
+ }
356
+ }
357
+ });
358
+
359
+ if (element) {
360
+ element.addEventListener('click', handleEditorClick, true);
361
+ // Add paste event listener for image paste support
362
+ element.addEventListener('paste', handlePaste as unknown as EventListener);
363
+ }
364
+ });
365
+
366
+ onDestroy(() => {
367
+ element?.removeEventListener('click', handleEditorClick, true);
368
+ element?.removeEventListener('paste', handlePaste as unknown as EventListener);
369
+ editorState.editor?.destroy();
370
+ });
371
+
372
+ // Public API methods
373
+ export function getHTML(): string {
374
+ const editor = editorState.editor;
375
+ if (!editor || editor.isDestroyed) return '';
376
+ return editor.getHTML();
377
+ }
378
+
379
+ export function getJSON(): object {
380
+ const editor = editorState.editor;
381
+ if (!editor || editor.isDestroyed) return {};
382
+ return editor.getJSON();
383
+ }
384
+
385
+ export function setContent(html: string) {
386
+ const editor = editorState.editor;
387
+ if (!editor || editor.isDestroyed) return;
388
+ editor.commands.setContent(html);
389
+ }
390
+
391
+ export function clear() {
392
+ const editor = editorState.editor;
393
+ if (!editor || editor.isDestroyed) return;
394
+ editor.commands.clearContent();
395
+ }
396
+
397
+ export function focus() {
398
+ const editor = editorState.editor;
399
+ if (!editor || editor.isDestroyed) return;
400
+ editor.commands.focus();
401
+ }
402
+ </script>
403
+
404
+ <FormGroup {label} {required} class={groupClass} {tooltipLocation} {tooltipText}>
405
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
406
+ <div
407
+ class="editor-container {className}"
408
+ class:dragging={isDragging}
409
+ ondragover={handleDragOver}
410
+ ondragleave={handleDragLeave}
411
+ ondrop={handleDrop}
412
+ >
413
+ {#if editorState.editor && editable}
414
+ <div class="toolbar">
415
+ <div class="toolbar-group">
416
+ <UndoButton editor={editorState.editor} />
417
+ <RedoButton editor={editorState.editor} />
418
+ </div>
419
+
420
+ <div class="toolbar-divider"></div>
421
+
422
+ <div class="toolbar-group">
423
+ <HeadingButton editor={editorState.editor} level={1} />
424
+ <HeadingButton editor={editorState.editor} level={2} />
425
+ <HeadingButton editor={editorState.editor} level={3} />
426
+ </div>
427
+
428
+ <div class="toolbar-divider"></div>
429
+
430
+ <div class="toolbar-group">
431
+ <BoldButton editor={editorState.editor} />
432
+ <ItalicButton editor={editorState.editor} />
433
+ <StrikethroughButton editor={editorState.editor} />
434
+ <CodeButton editor={editorState.editor} />
435
+ {#if codeBlocks}
436
+ <CodeBlockButton editor={editorState.editor} />
437
+ {/if}
438
+ <UnderlineButton editor={editorState.editor} />
439
+ <ColorButton editor={editorState.editor} />
440
+ </div>
441
+
442
+ <div class="toolbar-divider"></div>
443
+
444
+ <div class="toolbar-group">
445
+ <BulletListButton editor={editorState.editor} />
446
+ <OrderedListButton editor={editorState.editor} />
447
+ </div>
448
+
449
+ <div class="toolbar-divider"></div>
450
+
451
+ <div class="toolbar-group">
452
+ <TableButton editor={editorState.editor} />
453
+ </div>
454
+
455
+ <div class="toolbar-divider"></div>
456
+
457
+ <div class="toolbar-group">
458
+ <LinkButton editor={editorState.editor} />
459
+ <SuperscriptButton editor={editorState.editor} />
460
+ <SubscriptButton editor={editorState.editor} />
461
+ </div>
462
+
463
+ <div class="toolbar-divider"></div>
464
+
465
+ <div class="toolbar-group">
466
+ <AlignLeftButton editor={editorState.editor} />
467
+ <AlignCenterButton editor={editorState.editor} />
468
+ <AlignRightButton editor={editorState.editor} />
469
+ <AlignJustifyButton editor={editorState.editor} />
470
+ </div>
471
+
472
+ {#if onImageUpload || onDocumentUpload}
473
+ <div class="toolbar-divider"></div>
474
+
475
+ <div class="toolbar-group">
476
+ {#if onImageUpload}
477
+ <ImageButton editor={editorState.editor} {onImageUpload} />
478
+ {/if}
479
+ {#if onDocumentUpload}
480
+ <DocumentButton editor={editorState.editor} {onDocumentUpload} />
481
+ {/if}
482
+ </div>
483
+ {/if}
484
+
485
+ <div class="toolbar-divider"></div>
486
+
487
+ <div class="toolbar-group">
488
+ <AlertButton editor={editorState.editor} />
489
+ </div>
490
+
491
+ <div class="toolbar-divider"></div>
492
+
493
+ <div class="toolbar-group">
494
+ <HtmlButton editor={editorState.editor} />
495
+ </div>
496
+ </div>
497
+ {/if}
498
+
499
+ <div
500
+ bind:this={linkBubbleMenuElement}
501
+ class="link-bubble-menu"
502
+ style="visibility: hidden; opacity: 0; position: absolute;"
503
+ >
504
+ {#if editorState.editor}
505
+ <LinkActionMenu editor={editorState.editor} {editable} />
506
+ {/if}
507
+ </div>
508
+
509
+ <div class="editor-content" bind:this={element}></div>
510
+ </div>
511
+ </FormGroup>
512
+
513
+ <style>
514
+ .editor-container {
515
+ position: relative;
516
+ border: 1px solid var(--border-color);
517
+ border-radius: 6px;
518
+ background: var(--paper-body-bg);
519
+ font-family: var(--ui-font-family);
520
+ transition: border-color 0.2s ease;
521
+ }
522
+
523
+ .editor-container.dragging {
524
+ border-color: var(--ui-tertiary);
525
+ border-style: dashed;
526
+ }
527
+
528
+ .toolbar {
529
+ display: flex;
530
+ align-items: center;
531
+ gap: 4px;
532
+ padding: 6px;
533
+ border-bottom: 1px solid var(--border-color);
534
+ background: var(--paper-title-bg);
535
+ border-radius: 6px 6px 0 0;
536
+ flex-wrap: wrap;
537
+ }
538
+
539
+ .toolbar-group {
540
+ display: flex;
541
+ align-items: center;
542
+ gap: 2px;
543
+ }
544
+
545
+ .toolbar-divider {
546
+ width: 1px;
547
+ height: 24px;
548
+ background: var(--border-color);
549
+ margin: 0 4px;
550
+ }
551
+
552
+ .link-bubble-menu {
553
+ z-index: 1100;
554
+ }
555
+
556
+ .editor-content {
557
+ padding: 16px;
558
+ min-height: 200px;
559
+ color: var(--text-color);
560
+ }
561
+
562
+ /* TipTap Editor Styles */
563
+ .editor-content :global(.ProseMirror) {
564
+ outline: none;
565
+ }
566
+
567
+ .editor-content :global(.ProseMirror p) {
568
+ margin: 0 0 1em 0;
569
+ }
570
+
571
+ .editor-content :global(.ProseMirror h1) {
572
+ font-size: 2em;
573
+ font-weight: bold;
574
+ margin: 0.67em 0;
575
+ }
576
+
577
+ .editor-content :global(.ProseMirror h2) {
578
+ font-size: 1.5em;
579
+ font-weight: bold;
580
+ margin: 0.75em 0;
581
+ }
582
+
583
+ .editor-content :global(.ProseMirror h3) {
584
+ font-size: 1.17em;
585
+ font-weight: bold;
586
+ margin: 0.83em 0;
587
+ }
588
+
589
+ .editor-content :global(.ProseMirror ul),
590
+ .editor-content :global(.ProseMirror ol) {
591
+ padding-left: 1.5em;
592
+ margin: 1em 0;
593
+ }
594
+
595
+ .editor-content :global(.ProseMirror code) {
596
+ background: var(--page-bg);
597
+ padding: 2px 6px;
598
+ border-radius: 3px;
599
+ font-family: 'Monaco', 'Courier New', monospace;
600
+ font-size: 0.9em;
601
+ color: var(--ui-accent-dark);
602
+ }
603
+
604
+ :global(.dark) .editor-content :global(.ProseMirror code) {
605
+ color: var(--ui-accent);
606
+ }
607
+
608
+ .editor-content :global(.ProseMirror a) {
609
+ color: var(--ui-tertiary-dark);
610
+ text-decoration: underline;
611
+ cursor: pointer;
612
+ pointer-events: auto;
613
+ }
614
+
615
+ :global(.dark) .editor-content :global(.ProseMirror a) {
616
+ color: var(--ui-tertiary);
617
+ }
618
+
619
+ .editor-content :global(.ProseMirror a.editor-link) {
620
+ cursor: pointer;
621
+ pointer-events: auto;
622
+ }
623
+
624
+ .editor-content :global(.ProseMirror a.editor-link:hover) {
625
+ background: rgba(var(--ui-primary-rgbc), 0.1);
626
+ }
627
+
628
+ :global(.dark) .editor-content :global(.ProseMirror a.editor-link:hover) {
629
+ background: rgba(var(--ui-accent-rgbc), 0.1);
630
+ }
631
+
632
+ /* Ensure the editor remains clickable while links show the action menu. */
633
+ .editor-content :global(.ProseMirror) {
634
+ pointer-events: auto;
635
+ }
636
+
637
+ .editor-content :global(.ProseMirror img) {
638
+ max-width: 100%;
639
+ height: auto;
640
+ }
641
+
642
+ /* Table styles */
643
+ .editor-content :global(.ProseMirror .tableWrapper) {
644
+ overflow-x: auto;
645
+ margin: 1em 0;
646
+ }
647
+
648
+ .editor-content :global(.ProseMirror table) {
649
+ border-collapse: collapse;
650
+ table-layout: fixed;
651
+ width: 100%;
652
+ overflow: hidden;
653
+ }
654
+
655
+ .editor-content :global(.ProseMirror th),
656
+ .editor-content :global(.ProseMirror td) {
657
+ position: relative;
658
+ border: 1px solid var(--border-color);
659
+ padding: 6px 10px;
660
+ vertical-align: top;
661
+ min-width: 1em;
662
+ box-sizing: border-box;
663
+ }
664
+
665
+ .editor-content :global(.ProseMirror th) {
666
+ background: var(--paper-title-bg);
667
+ font-weight: 600;
668
+ text-align: left;
669
+ }
670
+
671
+ .editor-content :global(.ProseMirror table p) {
672
+ margin: 0;
673
+ }
674
+
675
+ .editor-content :global(.ProseMirror .selectedCell::after) {
676
+ content: '';
677
+ position: absolute;
678
+ inset: 0;
679
+ background: rgba(var(--ui-primary-rgbc), 0.08);
680
+ pointer-events: none;
681
+ z-index: 2;
682
+ }
683
+
684
+ :global(.dark) .editor-content :global(.ProseMirror .selectedCell::after) {
685
+ background: rgba(var(--ui-accent-rgbc), 0.12);
686
+ }
687
+
688
+ .editor-content :global(.ProseMirror .column-resize-handle) {
689
+ position: absolute;
690
+ top: 0;
691
+ bottom: -2px;
692
+ right: -2px;
693
+ width: 4px;
694
+ background: var(--ui-tertiary);
695
+ pointer-events: none;
696
+ z-index: 20;
697
+ }
698
+
699
+ .editor-content :global(.ProseMirror.resize-cursor) {
700
+ cursor: col-resize;
701
+ }
702
+
703
+ .editor-content :global(.ProseMirror [style*='text-align: left']) {
704
+ text-align: left;
705
+ }
706
+
707
+ .editor-content :global(.ProseMirror [style*='text-align: center']) {
708
+ text-align: center;
709
+ }
710
+
711
+ .editor-content :global(.ProseMirror [style*='text-align: right']) {
712
+ text-align: right;
713
+ }
714
+
715
+ .editor-content :global(.ProseMirror [style*='text-align: justify']) {
716
+ text-align: justify;
717
+ }
718
+
719
+ /* Placeholder styles */
720
+ .editor-content :global(.ProseMirror p.is-editor-empty:first-child::before) {
721
+ content: attr(data-placeholder);
722
+ float: left;
723
+ color: var(--placeholder-color);
724
+ pointer-events: none;
725
+ height: 0;
726
+ }
727
+
728
+ /* Alert styles */
729
+ .editor-content :global(.ProseMirror .alert) {
730
+ display: flex;
731
+ flex-direction: column;
732
+ border-radius: 0.25rem;
733
+ padding: 0.5rem;
734
+ margin: 0.5rem 0;
735
+ }
736
+
737
+ .editor-content :global(.ProseMirror .alert-title) {
738
+ margin-bottom: 0.25rem;
739
+ font-weight: 700;
740
+ }
741
+
742
+ .editor-content :global(.ProseMirror .alert-title::before) {
743
+ content: attr(data-title-element);
744
+ display: none;
745
+ }
746
+
747
+ .editor-content :global(.ProseMirror .alert-content) {
748
+ line-height: 1.5;
749
+ }
750
+
751
+ /* Default variant - use pistachio theme */
752
+ .editor-content :global(.ProseMirror .alert-default) {
753
+ background: rgba(var(--ui-accent-rgbc), 0.3);
754
+ border: 1px solid var(--ui-accent);
755
+ color: var(--text-color);
756
+ }
757
+
758
+ .editor-content :global(.ProseMirror .alert-default .alert-title) {
759
+ color: var(--ui-primary);
760
+ }
761
+
762
+ /* Danger variant */
763
+ .editor-content :global(.ProseMirror .alert-danger) {
764
+ background: #f8d7da;
765
+ color: #58151c;
766
+ border: 1px solid #f1aeb5;
767
+ }
768
+
769
+ .editor-content :global(.ProseMirror .alert-danger .alert-title) {
770
+ color: #58151c;
771
+ }
772
+
773
+ /* Warning variant */
774
+ .editor-content :global(.ProseMirror .alert-warning) {
775
+ background: #fff3cd;
776
+ color: #664d03;
777
+ border: 1px solid #ffe69c;
778
+ }
779
+
780
+ .editor-content :global(.ProseMirror .alert-warning .alert-title) {
781
+ color: #664d03;
782
+ }
783
+
784
+ /* Dark mode alert variants */
785
+ :global(.dark) .editor-content :global(.ProseMirror .alert-default) {
786
+ background: rgba(var(--ui-primary-rgbc), 0.3);
787
+ border-color: var(--ui-primary);
788
+ }
789
+
790
+ :global(.dark) .editor-content :global(.ProseMirror .alert-default .alert-title) {
791
+ color: var(--white);
792
+ }
793
+
794
+ :global(.dark) .editor-content :global(.ProseMirror .alert-danger) {
795
+ background: #2c0b0e;
796
+ color: #ea868f;
797
+ border-color: #842029;
798
+ }
799
+
800
+ :global(.dark) .editor-content :global(.ProseMirror .alert-danger .alert-title) {
801
+ color: #ea868f;
802
+ }
803
+
804
+ :global(.dark) .editor-content :global(.ProseMirror .alert-warning) {
805
+ background: #332701;
806
+ color: #fff3cd;
807
+ border-color: #997404;
808
+ }
809
+
810
+ :global(.dark) .editor-content :global(.ProseMirror .alert-warning .alert-title) {
811
+ color: #fff3cd;
812
+ }
813
+
814
+ .editor-content :global(.alert p:last-child) {
815
+ margin-bottom: 0;
816
+ }
817
+
818
+ .editor-content :global(.tiptap p:last-child) {
819
+ margin-bottom: 0;
820
+ }
821
+
822
+ .editor-content :global(.alert) {
823
+ margin-bottom: 1rem !important;
824
+ }
825
+
826
+ /* Collaboration caret styles */
827
+ .editor-content :global(.collaboration-carets__caret) {
828
+ position: relative;
829
+ display: inline;
830
+ border-left: 2px solid;
831
+ margin-left: -1px;
832
+ margin-right: -1px;
833
+ pointer-events: none;
834
+ word-break: normal;
835
+ }
836
+
837
+ .editor-content :global(.collaboration-carets__label) {
838
+ position: absolute;
839
+ top: -1.4em;
840
+ left: -1px;
841
+ font-size: 12px;
842
+ font-weight: 600;
843
+ line-height: normal;
844
+ padding: 0.1rem 0.3rem;
845
+ border-radius: 3px 3px 3px 0;
846
+ color: #fff;
847
+ white-space: nowrap;
848
+ user-select: none;
849
+ pointer-events: none;
850
+ }
851
+
852
+ /* Collaboration selection highlight */
853
+ .editor-content :global(.ProseMirror-yjs-selection) {
854
+ display: inline;
855
+ }
856
+ </style>