@widgetic/editor 3.11.4 → 4.0.2

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 (497) hide show
  1. package/README.md +245 -0
  2. package/dist/assets/fonts.json +331 -0
  3. package/dist/assets/icons/ic-browser/audio.svg +7 -0
  4. package/dist/assets/icons/ic-browser/document.svg +11 -0
  5. package/dist/assets/icons/ic-browser/error.svg +5 -0
  6. package/dist/assets/icons/ic-browser/folder.svg +28 -0
  7. package/dist/assets/icons/ic-browser/player-pause.svg +1 -0
  8. package/dist/assets/icons/ic-browser/player-play.svg +1 -0
  9. package/dist/assets/icons/ic-browser/trash.svg +1 -0
  10. package/dist/assets/icons/ic-fixed-position/background-deselected.svg +3 -0
  11. package/dist/assets/icons/ic-fixed-position/background-selected.svg +3 -0
  12. package/dist/assets/icons/ic-fixed-position/bottom-left-background-deselected.svg +3 -0
  13. package/dist/assets/icons/ic-fixed-position/bottom-left-background-selected.svg +3 -0
  14. package/dist/assets/icons/ic-fixed-position/bottom-left-icon.svg +4 -0
  15. package/dist/assets/icons/ic-fixed-position/bottom-right-background-deselected.svg +3 -0
  16. package/dist/assets/icons/ic-fixed-position/bottom-right-background-selected.svg +3 -0
  17. package/dist/assets/icons/ic-fixed-position/bottom-right-icon.svg +4 -0
  18. package/dist/assets/icons/ic-fixed-position/center-bottom-icon.svg +5 -0
  19. package/dist/assets/icons/ic-fixed-position/center-center-icon.svg +3 -0
  20. package/dist/assets/icons/ic-fixed-position/center-left-icon.svg +5 -0
  21. package/dist/assets/icons/ic-fixed-position/center-right-icon.svg +5 -0
  22. package/dist/assets/icons/ic-fixed-position/center-top-icon.svg +5 -0
  23. package/dist/assets/icons/ic-fixed-position/top-left-background-deselected.svg +3 -0
  24. package/dist/assets/icons/ic-fixed-position/top-left-background-selected.svg +3 -0
  25. package/dist/assets/icons/ic-fixed-position/top-left-icon.svg +4 -0
  26. package/dist/assets/icons/ic-fixed-position/top-right-background-deselected.svg +3 -0
  27. package/dist/assets/icons/ic-fixed-position/top-right-background-selected.svg +3 -0
  28. package/dist/assets/icons/ic-fixed-position/top-right-icon.svg +4 -0
  29. package/dist/assets/icons/trash.svg +1 -0
  30. package/dist/components/MockWidget.svelte +108 -0
  31. package/dist/components/MockWidget.svelte.d.ts +22 -0
  32. package/dist/components/WidgetPreview.svelte +852 -0
  33. package/dist/components/WidgetPreview.svelte.d.ts +100 -0
  34. package/dist/components/color-select/ColorSelect.svelte +258 -0
  35. package/dist/components/color-select/ColorSelect.svelte.d.ts +42 -0
  36. package/dist/components/color-select/color.d.ts +25 -0
  37. package/dist/components/color-select/color.js +21 -0
  38. package/dist/components/color-select/constants.d.ts +5 -0
  39. package/dist/components/color-select/constants.js +5 -0
  40. package/dist/components/color-select/render.d.ts +5 -0
  41. package/dist/components/color-select/render.js +77 -0
  42. package/dist/components/color-select/shaders.d.ts +3 -0
  43. package/dist/components/color-select/shaders.js +8 -0
  44. package/dist/components/editors/EmbedEditor.svelte +700 -0
  45. package/dist/components/editors/EmbedEditor.svelte.d.ts +50 -0
  46. package/dist/components/editors/PropsEditor.svelte +4009 -0
  47. package/dist/components/editors/PropsEditor.svelte.d.ts +62 -0
  48. package/dist/components/editors/props-editor.css +73 -0
  49. package/dist/components/ic/AngleInputController.svelte +276 -0
  50. package/dist/components/ic/AngleInputController.svelte.d.ts +26 -0
  51. package/dist/components/ic/BrowserInputController.svelte +731 -0
  52. package/dist/components/ic/BrowserInputController.svelte.d.ts +39 -0
  53. package/dist/components/ic/CheckboxInputController.svelte +203 -0
  54. package/dist/components/ic/CheckboxInputController.svelte.d.ts +41 -0
  55. package/dist/components/ic/ColorPickerInputController.svelte +1584 -0
  56. package/dist/components/ic/ColorPickerInputController.svelte.d.ts +50 -0
  57. package/dist/components/ic/DateFieldInputController.svelte +453 -0
  58. package/dist/components/ic/DateFieldInputController.svelte.d.ts +35 -0
  59. package/dist/components/ic/DatePickerInputController.svelte +364 -0
  60. package/dist/components/ic/DatePickerInputController.svelte.d.ts +28 -0
  61. package/dist/components/ic/DropdownInputController.svelte +226 -0
  62. package/dist/components/ic/DropdownInputController.svelte.d.ts +43 -0
  63. package/dist/components/ic/FixedPositionInputController.svelte +353 -0
  64. package/dist/components/ic/FixedPositionInputController.svelte.d.ts +23 -0
  65. package/dist/components/ic/FontInputController.svelte +2098 -0
  66. package/dist/components/ic/FontInputController.svelte.d.ts +47 -0
  67. package/dist/components/ic/InputControllerHeader.svelte +147 -0
  68. package/dist/components/ic/InputControllerHeader.svelte.d.ts +23 -0
  69. package/dist/components/ic/NumberControls.svelte +299 -0
  70. package/dist/components/ic/NumberControls.svelte.d.ts +30 -0
  71. package/dist/components/ic/NumberInputController.svelte +397 -0
  72. package/dist/components/ic/NumberInputController.svelte.d.ts +30 -0
  73. package/dist/components/ic/PositionInputController.svelte +252 -0
  74. package/dist/components/ic/PositionInputController.svelte.d.ts +37 -0
  75. package/dist/components/ic/RadioGroupInputController.svelte +162 -0
  76. package/dist/components/ic/RadioGroupInputController.svelte.d.ts +38 -0
  77. package/dist/components/ic/RangeCalendarInputController.svelte +262 -0
  78. package/dist/components/ic/RangeCalendarInputController.svelte.d.ts +32 -0
  79. package/dist/components/ic/RoundedCornersInputController.svelte +469 -0
  80. package/dist/components/ic/RoundedCornersInputController.svelte.d.ts +37 -0
  81. package/dist/components/ic/SliderInputController.svelte +411 -0
  82. package/dist/components/ic/SliderInputController.svelte.d.ts +46 -0
  83. package/dist/components/ic/SliderRangeInputController.svelte +155 -0
  84. package/dist/components/ic/SliderRangeInputController.svelte.d.ts +33 -0
  85. package/dist/components/ic/SwitchInputController.svelte +107 -0
  86. package/dist/components/ic/SwitchInputController.svelte.d.ts +24 -0
  87. package/dist/components/ic/TagsInputController.svelte +125 -0
  88. package/dist/components/ic/TagsInputController.svelte.d.ts +27 -0
  89. package/dist/components/ic/TextAreaInputController.svelte +1932 -0
  90. package/dist/components/ic/TextAreaInputController.svelte.d.ts +14 -0
  91. package/dist/components/ic/TextAreaPreviewInputController.svelte +478 -0
  92. package/dist/components/ic/TextAreaPreviewInputController.svelte.d.ts +28 -0
  93. package/dist/components/ic/TextInputController.svelte +70 -0
  94. package/dist/components/ic/TextInputController.svelte.d.ts +30 -0
  95. package/dist/components/ic/TimeInputController.svelte +434 -0
  96. package/dist/components/ic/TimeInputController.svelte.d.ts +25 -0
  97. package/dist/components/ic/VectorInputController.svelte +1826 -0
  98. package/dist/components/ic/VectorInputController.svelte.d.ts +47 -0
  99. package/dist/components/ic/index.d.ts +39 -0
  100. package/dist/components/ic/index.js +24 -0
  101. package/dist/components/ic/shared/CategoryTabs.svelte +40 -0
  102. package/dist/components/ic/shared/CategoryTabs.svelte.d.ts +25 -0
  103. package/dist/components/ic/shared/ItemGrid.svelte +181 -0
  104. package/dist/components/ic/shared/ItemGrid.svelte.d.ts +35 -0
  105. package/dist/components/ic/shared/RecentItemsSection.svelte +260 -0
  106. package/dist/components/ic/shared/RecentItemsSection.svelte.d.ts +35 -0
  107. package/dist/components/ic/shared/index.d.ts +8 -0
  108. package/dist/components/ic/shared/index.js +9 -0
  109. package/dist/components/icons/addnew.svelte +21 -0
  110. package/dist/components/icons/addnew.svelte.d.ts +20 -0
  111. package/dist/components/icons/drag.svelte +29 -0
  112. package/dist/components/icons/drag.svelte.d.ts +20 -0
  113. package/dist/components/icons/drag.svg +1 -0
  114. package/dist/components/icons/locked.svelte +4 -0
  115. package/dist/components/icons/locked.svelte.d.ts +26 -0
  116. package/dist/components/icons/locked.svg +4 -0
  117. package/dist/components/icons/ok.svelte +20 -0
  118. package/dist/components/icons/ok.svelte.d.ts +20 -0
  119. package/dist/components/icons/ok.svg +11 -0
  120. package/dist/components/icons/unlocked.svelte +4 -0
  121. package/dist/components/icons/unlocked.svelte.d.ts +26 -0
  122. package/dist/components/icons/unlocked.svg +4 -0
  123. package/dist/components/icons/x.svelte +14 -0
  124. package/dist/components/icons/x.svelte.d.ts +20 -0
  125. package/dist/components/icons/x.svg +5 -0
  126. package/dist/components/ui/arrows/OpacitySliderArrows.svelte +43 -0
  127. package/dist/components/ui/arrows/OpacitySliderArrows.svelte.d.ts +23 -0
  128. package/dist/components/ui/checkerboard-background/CheckerboardBackground.svelte +15 -0
  129. package/dist/components/ui/checkerboard-background/CheckerboardBackground.svelte.d.ts +20 -0
  130. package/dist/config.d.ts +11 -0
  131. package/dist/config.js +31 -0
  132. package/dist/index.d.ts +5 -0
  133. package/dist/index.js +9 -0
  134. package/dist/stores/userSession.d.ts +7 -0
  135. package/dist/stores/userSession.js +28 -0
  136. package/dist/utils/FontManager.d.ts +278 -0
  137. package/dist/utils/FontManager.js +1302 -0
  138. package/dist/utils/MediaManager.d.ts +35 -0
  139. package/dist/utils/MediaManager.js +59 -0
  140. package/dist/utils/VectorManager.d.ts +190 -0
  141. package/dist/utils/VectorManager.js +754 -0
  142. package/dist/utils/colorAutocomplete.d.ts +10 -0
  143. package/dist/utils/colorAutocomplete.js +28 -0
  144. package/dist/utils/colorNames.d.ts +3 -0
  145. package/dist/utils/colorNames.js +152 -0
  146. package/dist/utils/colorTransparency.d.ts +52 -0
  147. package/dist/utils/colorTransparency.js +114 -0
  148. package/dist/utils/fontUtils.d.ts +34 -0
  149. package/dist/utils/fontUtils.js +132 -0
  150. package/dist/utils/passiveEvents.js +20 -0
  151. package/dist/utils/recentColors.d.ts +10 -0
  152. package/dist/utils/recentColors.js +63 -0
  153. package/dist/utils/skipFonts.d.ts +3 -0
  154. package/dist/utils/skipFonts.js +49 -0
  155. package/dist/utils/vectorUtils.d.ts +34 -0
  156. package/dist/utils/vectorUtils.js +71 -0
  157. package/dist/utils.d.ts +11 -0
  158. package/dist/utils.js +38 -0
  159. package/package.json +134 -74
  160. package/.babelrc +0 -10
  161. package/.bowerrc +0 -4
  162. package/.nvmrc +0 -1
  163. package/Gruntfile.coffee +0 -69
  164. package/bower.json +0 -28
  165. package/css/browser/entries/activateable.styl +0 -29
  166. package/css/browser/entries/audio.styl +0 -39
  167. package/css/browser/entries/folder.styl +0 -79
  168. package/css/browser/entries/image.styl +0 -26
  169. package/css/browser/entries/index.styl +0 -66
  170. package/css/browser/entries/rss.styl +0 -11
  171. package/css/browser/entries/video.styl +0 -11
  172. package/css/browser/index.styl +0 -86
  173. package/css/browser/intent/index.styl +0 -61
  174. package/css/browser/nav/index.styl +0 -73
  175. package/css/browser/social-browser.styl +0 -23
  176. package/css/controls/clock.styl +0 -110
  177. package/css/controls/config.styl +0 -6
  178. package/css/controls/control-audio-details.styl +0 -63
  179. package/css/controls/control-audio.styl +0 -28
  180. package/css/controls/control-browser.styl +0 -48
  181. package/css/controls/control-color.styl +0 -423
  182. package/css/controls/control-date_time.styl +0 -191
  183. package/css/controls/control-dropdown.styl +0 -79
  184. package/css/controls/control-font.styl +0 -147
  185. package/css/controls/control-image-details.styl +0 -35
  186. package/css/controls/control-image.styl +0 -43
  187. package/css/controls/control-order-picker.styl +0 -29
  188. package/css/controls/control-position.styl +0 -390
  189. package/css/controls/control-range.styl +0 -68
  190. package/css/controls/control-scale.styl +0 -30
  191. package/css/controls/control-slider.styl +0 -38
  192. package/css/controls/control-spinner.styl +0 -39
  193. package/css/controls/control-textarea.styl +0 -52
  194. package/css/controls/control-toggle.styl +0 -34
  195. package/css/controls/control-url.styl +0 -32
  196. package/css/controls/control-video-details.styl +0 -85
  197. package/css/controls/control-video.styl +0 -43
  198. package/css/controls/general.styl +0 -98
  199. package/css/controls/index.styl +0 -25
  200. package/css/editor/colors.styl +0 -7
  201. package/css/editor/content/directinput.styl +0 -47
  202. package/css/editor/content/index.styl +0 -111
  203. package/css/editor/content/message.styl +0 -53
  204. package/css/editor/content/tabs.styl +0 -75
  205. package/css/editor/copied-from-old-style.styl +0 -197
  206. package/css/editor/details/bulk-editor.styl +0 -104
  207. package/css/editor/details/index.styl +0 -21
  208. package/css/editor/details/item.styl +0 -153
  209. package/css/editor/embed.styl +0 -106
  210. package/css/editor/footer.styl +0 -180
  211. package/css/editor/full-editor.styl +0 -16
  212. package/css/editor/index.styl +0 -124
  213. package/css/editor/login-popup.styl +0 -13
  214. package/css/editor/preview.styl +0 -257
  215. package/css/editor/skin/editor/index.styl +0 -54
  216. package/css/editor/skin/editor/tabs.styl +0 -111
  217. package/css/editor/skin/index.styl +0 -138
  218. package/css/editor/skin/popup.styl +0 -152
  219. package/css/editor/skin/presets/dropdown.styl +0 -61
  220. package/css/editor/skin/presets/index.styl +0 -86
  221. package/css/editor/skin/presets/list.styl +0 -244
  222. package/css/editor/tooltips.styl +0 -85
  223. package/css/fonts.styl +0 -47
  224. package/css/icons/BlogvioEditor.dev.svg +0 -112
  225. package/css/icons.styl +0 -16
  226. package/css/img/arrow-right-rounded-v-small.png +0 -0
  227. package/css/img/browser-folder-separator.png +0 -0
  228. package/css/img/calendar-input-icons.png +0 -0
  229. package/css/img/check.png +0 -0
  230. package/css/img/close.png +0 -0
  231. package/css/img/composition/edit-icon.png +0 -0
  232. package/css/img/content/audio-icon.png +0 -0
  233. package/css/img/content/folder-icon.png +0 -0
  234. package/css/img/content/messages/error-background.png +0 -0
  235. package/css/img/content/messages/error-icon.png +0 -0
  236. package/css/img/content/messages/notification-background.png +0 -0
  237. package/css/img/content/messages/notification-icon.png +0 -0
  238. package/css/img/content/no-files-audio.png +0 -0
  239. package/css/img/content/no-files-image.png +0 -0
  240. package/css/img/content/no-files-video.png +0 -0
  241. package/css/img/content/no-files.png +0 -0
  242. package/css/img/content/rss-icon.png +0 -0
  243. package/css/img/content/selected.png +0 -0
  244. package/css/img/content/video-icon.png +0 -0
  245. package/css/img/content/with-control-text.png +0 -0
  246. package/css/img/control-dropdown-arrow.png +0 -0
  247. package/css/img/control-image-valid.png +0 -0
  248. package/css/img/control-position-icon.png +0 -0
  249. package/css/img/control-scale-lock-icon.png +0 -0
  250. package/css/img/control-slider-arrows-hover.png +0 -0
  251. package/css/img/control-slider-arrows.png +0 -0
  252. package/css/img/control-spinner-buttons-hover.png +0 -0
  253. package/css/img/control-spinner-buttons.png +0 -0
  254. package/css/img/control-textarea-bold-active.png +0 -0
  255. package/css/img/control-textarea-bold.png +0 -0
  256. package/css/img/control-textarea-italic-active.png +0 -0
  257. package/css/img/control-textarea-italic.png +0 -0
  258. package/css/img/control-textarea-underline-active.png +0 -0
  259. package/css/img/control-textarea-underline.png +0 -0
  260. package/css/img/custom-checkbox-sprite.png +0 -0
  261. package/css/img/details/item-collapse-icon.png +0 -0
  262. package/css/img/details/item-expand-icon.png +0 -0
  263. package/css/img/details/item-sort-icon.png +0 -0
  264. package/css/img/done-arrow.png +0 -0
  265. package/css/img/fb-logo-icon-w.png +0 -0
  266. package/css/img/grid-icons.png +0 -0
  267. package/css/img/icon-reference.png +0 -0
  268. package/css/img/indicator.png +0 -0
  269. package/css/img/loader.gif +0 -0
  270. package/css/img/loaders/audio-white.png +0 -0
  271. package/css/img/loaders/audio.png +0 -0
  272. package/css/img/loaders/photo-white.png +0 -0
  273. package/css/img/loaders/photo.png +0 -0
  274. package/css/img/loaders/util-white.png +0 -0
  275. package/css/img/loaders/util.png +0 -0
  276. package/css/img/loaders/video-white.png +0 -0
  277. package/css/img/loaders/video.png +0 -0
  278. package/css/img/maximize.png +0 -0
  279. package/css/img/minimize.png +0 -0
  280. package/css/img/next-btn.png +0 -0
  281. package/css/img/search-icon-sprite.png +0 -0
  282. package/css/img/services/blogvio.png +0 -0
  283. package/css/img/services/drive.png +0 -0
  284. package/css/img/services/dropbox-login.png +0 -0
  285. package/css/img/services/dropbox.png +0 -0
  286. package/css/img/services/facebook-login.png +0 -0
  287. package/css/img/services/facebook.png +0 -0
  288. package/css/img/services/flickr-login.png +0 -0
  289. package/css/img/services/flickr.png +0 -0
  290. package/css/img/services/instagram-login.png +0 -0
  291. package/css/img/services/instagram.png +0 -0
  292. package/css/img/services/text.png +0 -0
  293. package/css/img/services/uploads.png +0 -0
  294. package/css/img/services/uploads.svg +0 -689
  295. package/css/img/services/webaddress-bw.png +0 -0
  296. package/css/img/services/webaddress.png +0 -0
  297. package/css/img/services/webadress.png +0 -0
  298. package/css/img/services/websearch.png +0 -0
  299. package/css/img/services/wix.png +0 -0
  300. package/css/img/skin/item-active-indicator.png +0 -0
  301. package/css/img/skin/item-hover-icon.png +0 -0
  302. package/css/img/skin/overwrite.png +0 -0
  303. package/css/img/skin/popup-name-icon.png +0 -0
  304. package/css/img/skin/popup-save.png +0 -0
  305. package/css/img/skin/preset.png +0 -0
  306. package/css/img/skin/presets-arrow-purple.png +0 -0
  307. package/css/img/tw-icon-w.png +0 -0
  308. package/css/img/warning.png +0 -0
  309. package/css/img/white-rounded-check.png +0 -0
  310. package/css/index.styl +0 -9
  311. package/css/mixins.styl +0 -62
  312. package/css/scrollable.styl +0 -101
  313. package/karma.conf.js +0 -73
  314. package/lib/control.js +0 -1
  315. package/lib/controls.js +0 -1
  316. package/lib/core.editor.js +0 -4
  317. package/lib/core.js +0 -1
  318. package/lib/core.vendor.js +0 -3
  319. package/lib/dev/control.js +0 -845
  320. package/lib/dev/controls.js +0 -7774
  321. package/lib/dev/core.editor.js +0 -6439
  322. package/lib/dev/core.js +0 -1486
  323. package/lib/dev/core.vendor.js +0 -10708
  324. package/lib/dev/editor.css +0 -166
  325. package/lib/dev/editor.js +0 -29710
  326. package/lib/dev/editor.vendor.js +0 -15119
  327. package/lib/dev/jquery.nanoscroller.js.map +0 -10
  328. package/lib/editor.css +0 -167
  329. package/lib/editor.js +0 -49
  330. package/lib/editor.vendor.js +0 -11
  331. package/src/api/index.coffee +0 -23
  332. package/src/api/mixin.coffee +0 -89
  333. package/src/browser/controller/entry/audio.coffee +0 -38
  334. package/src/browser/controller/entry/button.coffee +0 -16
  335. package/src/browser/controller/entry/file.coffee +0 -35
  336. package/src/browser/controller/entry/folder.coffee +0 -14
  337. package/src/browser/controller/entry/image.coffee +0 -24
  338. package/src/browser/controller/entry/index.coffee +0 -18
  339. package/src/browser/controller/entry/rss.coffee +0 -5
  340. package/src/browser/controller/entry/video.coffee +0 -4
  341. package/src/browser/controller/index.coffee +0 -289
  342. package/src/browser/controller/instagram.coffee +0 -129
  343. package/src/browser/controller/navbar.coffee +0 -48
  344. package/src/browser/controller/social.coffee +0 -213
  345. package/src/browser/model/entry.coffee +0 -18
  346. package/src/browser/model/index.coffee +0 -34
  347. package/src/core/controller/font-loader.coffee +0 -65
  348. package/src/core/controller/lazyload.coffee +0 -14
  349. package/src/core/controller/overlay.coffee +0 -146
  350. package/src/core/controller/popup.coffee +0 -36
  351. package/src/core/controller/scrollable.coffee +0 -68
  352. package/src/core/controls/audio.coffee +0 -56
  353. package/src/core/controls/browser.coffee +0 -271
  354. package/src/core/controls/color.coffee +0 -121
  355. package/src/core/controls/date-time/calendar/index.coffee +0 -99
  356. package/src/core/controls/date-time/calendar/months.coffee +0 -52
  357. package/src/core/controls/date-time/calendar/years.coffee +0 -58
  358. package/src/core/controls/date-time/clock.coffee +0 -62
  359. package/src/core/controls/date-time/helper.coffee +0 -31
  360. package/src/core/controls/date-time/index.coffee +0 -62
  361. package/src/core/controls/date-time/popup.coffee +0 -56
  362. package/src/core/controls/details/audio.coffee +0 -33
  363. package/src/core/controls/details/image.coffee +0 -19
  364. package/src/core/controls/details/video.coffee +0 -14
  365. package/src/core/controls/dropdown.coffee +0 -100
  366. package/src/core/controls/font/font-item.coffee +0 -22
  367. package/src/core/controls/font/font-list.coffee +0 -108
  368. package/src/core/controls/font/fonts-popup.coffee +0 -91
  369. package/src/core/controls/font/index.coffee +0 -66
  370. package/src/core/controls/image.coffee +0 -37
  371. package/src/core/controls/index.coffee +0 -88
  372. package/src/core/controls/orderPicker.coffee +0 -93
  373. package/src/core/controls/position/grid-panel.coffee +0 -75
  374. package/src/core/controls/position/index.coffee +0 -98
  375. package/src/core/controls/position/panel.coffee +0 -68
  376. package/src/core/controls/position/pixel-panel.coffee +0 -54
  377. package/src/core/controls/position/popup.coffee +0 -63
  378. package/src/core/controls/position/reference-panel.coffee +0 -26
  379. package/src/core/controls/range.coffee +0 -191
  380. package/src/core/controls/rss.coffee +0 -16
  381. package/src/core/controls/scale.coffee +0 -78
  382. package/src/core/controls/slider.coffee +0 -122
  383. package/src/core/controls/stepper.coffee +0 -97
  384. package/src/core/controls/text.coffee +0 -54
  385. package/src/core/controls/textarea.coffee +0 -78
  386. package/src/core/controls/toggle.coffee +0 -29
  387. package/src/core/controls/url.coffee +0 -88
  388. package/src/core/controls/video.coffee +0 -9
  389. package/src/core/embed/api.js +0 -178
  390. package/src/core/embed/controller.js +0 -331
  391. package/src/core/models/composition.coffee +0 -178
  392. package/src/core/models/content.coffee +0 -79
  393. package/src/core/models/skin.coffee +0 -91
  394. package/src/core/models/user.coffee +0 -6
  395. package/src/core/models/widget.coffee +0 -88
  396. package/src/core/router/index.coffee +0 -44
  397. package/src/core/services/container/index.js +0 -18
  398. package/src/core/services/container/instance.js +0 -3
  399. package/src/core/services/content.js +0 -80
  400. package/src/core/services/instagram.coffee +0 -47
  401. package/src/core/services/mixin/events.js +0 -17
  402. package/src/core/services/service.js +0 -1
  403. package/src/core/services/sounds.js +0 -81
  404. package/src/core/services/uploads.js +0 -299
  405. package/src/core/utils/popup.coffee +0 -67
  406. package/src/core/utils/should-show.coffee +0 -12
  407. package/src/core/views/audio-details.pug +0 -9
  408. package/src/core/views/audio.pug +0 -7
  409. package/src/core/views/browser.pug +0 -4
  410. package/src/core/views/color.pug +0 -8
  411. package/src/core/views/date-time/calendar.pug +0 -3
  412. package/src/core/views/date-time/clock.pug +0 -12
  413. package/src/core/views/date-time/grid.pug +0 -6
  414. package/src/core/views/date-time/input.pug +0 -4
  415. package/src/core/views/date-time/table.pug +0 -6
  416. package/src/core/views/dropdown.pug +0 -9
  417. package/src/core/views/font/font-item.pug +0 -3
  418. package/src/core/views/font/fonts-list.pug +0 -7
  419. package/src/core/views/font/fonts-popup.pug +0 -5
  420. package/src/core/views/font/index.pug +0 -7
  421. package/src/core/views/image-details.pug +0 -6
  422. package/src/core/views/image.pug +0 -5
  423. package/src/core/views/input-layout.pug +0 -15
  424. package/src/core/views/order-items.pug +0 -7
  425. package/src/core/views/order-picker.pug +0 -7
  426. package/src/core/views/pixelpanel.pug +0 -69
  427. package/src/core/views/position.pug +0 -10
  428. package/src/core/views/range.pug +0 -9
  429. package/src/core/views/scale.pug +0 -7
  430. package/src/core/views/slider.pug +0 -6
  431. package/src/core/views/stepper.pug +0 -6
  432. package/src/core/views/text.pug +0 -4
  433. package/src/core/views/textarea.pug +0 -8
  434. package/src/core/views/toggle.pug +0 -5
  435. package/src/core/views/video-details.pug +0 -7
  436. package/src/core/views/video.pug +0 -4
  437. package/src/core/widget/index.coffee +0 -66
  438. package/src/editor/content/browser/dropzone.html +0 -268
  439. package/src/editor/content/browser/file.html +0 -124
  440. package/src/editor/content/browser/scroll-pane.html +0 -32
  441. package/src/editor/content/browser/service.html +0 -53
  442. package/src/editor/content/browser/upload.coffee +0 -44
  443. package/src/editor/content/browser/upload.html +0 -439
  444. package/src/editor/content/index.coffee +0 -294
  445. package/src/editor/content/input/field.coffee +0 -45
  446. package/src/editor/content/input/index.coffee +0 -115
  447. package/src/editor/content/service/base/photoitem.coffee +0 -49
  448. package/src/editor/content/service/cache.coffee +0 -20
  449. package/src/editor/content/service/default.coffee +0 -59
  450. package/src/editor/content/service/dropbox.coffee +0 -71
  451. package/src/editor/content/service/facebook.coffee +0 -143
  452. package/src/editor/content/service/flickr.coffee +0 -85
  453. package/src/editor/content/service/google-drive-sdk.coffee +0 -18
  454. package/src/editor/content/service/google-drive.coffee +0 -144
  455. package/src/editor/content/service/instagram-social.coffee +0 -84
  456. package/src/editor/content/service/instagram.coffee +0 -168
  457. package/src/editor/content/service/share-popup.coffee +0 -15
  458. package/src/editor/content/service/soundcloud.coffee +0 -163
  459. package/src/editor/content/tab.coffee +0 -27
  460. package/src/editor/details/bulk-editor/attributes-panel.coffee +0 -11
  461. package/src/editor/details/bulk-editor/index.coffee +0 -86
  462. package/src/editor/details/index.coffee +0 -156
  463. package/src/editor/details/item/attributes.coffee +0 -45
  464. package/src/editor/details/item/index.coffee +0 -82
  465. package/src/editor/editor.coffee +0 -274
  466. package/src/editor/footer/breadcrumb.coffee +0 -17
  467. package/src/editor/footer/index.coffee +0 -36
  468. package/src/editor/index.coffee +0 -79
  469. package/src/editor/listeners/embed-listener.coffee +0 -143
  470. package/src/editor/login-popup.coffee +0 -29
  471. package/src/editor/notification-controller.coffee +0 -35
  472. package/src/editor/popup.coffee +0 -68
  473. package/src/editor/remote-preview.coffee +0 -68
  474. package/src/editor/save/index.coffee +0 -62
  475. package/src/editor/skin/delete.coffee +0 -33
  476. package/src/editor/skin/editor/index.coffee +0 -188
  477. package/src/editor/skin/editor/panel.coffee +0 -37
  478. package/src/editor/skin/index.coffee +0 -126
  479. package/src/editor/skin/save.coffee +0 -58
  480. package/src/editor/skin/selector/index.coffee +0 -59
  481. package/src/editor/skin/selector/item.coffee +0 -123
  482. package/src/editor/skin/selector/list.coffee +0 -97
  483. package/src/editor/views/embed.pug +0 -10
  484. package/src/editor/views/loginbutton.pug +0 -8
  485. package/src/editor/views/popup.pug +0 -17
  486. package/src/editor/views/presets.pug +0 -8
  487. package/src/editor/views/presetslist-header.pug +0 -8
  488. package/src/editor/views/skinitem.pug +0 -13
  489. package/src/modules/control.js +0 -3
  490. package/src/modules/controls.js +0 -29
  491. package/src/modules/core.js +0 -19
  492. package/src/modules/editor.js +0 -80
  493. package/test/config.js +0 -3
  494. package/test/core/models/skin-spec.js +0 -209
  495. package/webpack.config.js +0 -46
  496. package/webpack.config.prod.js +0 -9
  497. /package/{src/core/views/date-time/popup.pug → dist/utils/passiveEvents.d.ts} +0 -0
@@ -0,0 +1,1932 @@
1
+ <!--
2
+ TextAreaInputController
3
+
4
+ A rich text editor component with advanced formatting capabilities:
5
+ - Text styling (bold, italic, underline)
6
+ - Headings and lists
7
+ - Color picker integration
8
+ - Link insertion
9
+ - Dynamic height adjustment
10
+
11
+ Key Features:
12
+ - Maintains editor state across format changes
13
+ - Handles complex selection scenarios
14
+ - Manages toolbar state based on text formatting
15
+ - Implements smooth height transitions
16
+ - Preserves cursor position during operations
17
+
18
+ Edge Cases:
19
+ - Handles empty selections gracefully
20
+ - Manages focus state during dropdown interactions
21
+ - Prevents recursive updates during state changes
22
+ - Maintains formatting consistency across operations
23
+ -->
24
+
25
+ <script lang="ts">
26
+ // Svelte imports
27
+ import { onMount, onDestroy } from 'svelte';
28
+ import { writable } from 'svelte/store';
29
+ import type { ComponentEvents } from 'svelte';
30
+
31
+ // Component config
32
+ import type { InputControllerConfig } from './index';
33
+
34
+ // Import Shadcn UI components
35
+ import { Button, ToggleGroup, Popover, Command } from '@widgetic/design-system/components';
36
+
37
+ // Import Lucide Icons
38
+ import {
39
+ IconBrush,
40
+ IconBold,
41
+ IconItalic,
42
+ IconUnderline,
43
+ IconLink,
44
+ ChevronDown,
45
+ X,
46
+ IconPilcrow,
47
+ IconList,
48
+ IconListNumbers,
49
+ IconListCheck
50
+ } from '@widgetic/design-system/icons';
51
+
52
+
53
+ // Import Shad Editor
54
+ import { ShadEditor, type TipTapEditor, type TipTapEditorLevel } from '@widgetic/design-system/shad-editor';
55
+
56
+ // Add local ColorPickerInputController import
57
+ import ColorPickerInputController from './ColorPickerInputController.svelte';
58
+
59
+ // Add this constant for the decoration type
60
+ const TRANSITION_DURATION = 250;
61
+
62
+ /**
63
+ * Component props
64
+ */
65
+ let {
66
+ class: className = '',
67
+ label,
68
+ value = $bindable(''),
69
+ onChange,
70
+ config = {},
71
+ description = undefined,
72
+ onFocus = () => {},
73
+ onClose = undefined
74
+ } = $props<{
75
+ class: string;
76
+ label: string;
77
+ value: string;
78
+ onChange: (newValue: string) => void;
79
+ config?: InputControllerConfig;
80
+ description?: string;
81
+ onFocus?: () => void;
82
+ onClose?: () => void;
83
+ }>();
84
+
85
+ // Use config values with fallbacks
86
+ const textColor = config.textColor || '#1a1a1a';
87
+
88
+ /**
89
+ * State Variables
90
+ */
91
+ let isInitialMount = $state(false); // Tracks initial component mounting to prevent unnecessary updates
92
+ let editorInstance: TipTapEditor | null = null; // Reference to TipTap editor instance
93
+ let textStyleDropdownOpen = $state(false); // Controls visibility of text style dropdown
94
+ let listStyleDropdownOpen = $state(false);
95
+ /**
96
+ * Format Tracking
97
+ * Maintains active format states for toolbar UI:
98
+ * - Prevents invalid format combinations
99
+ * - Updates reactively with selection changes
100
+ * - Syncs with editor commands
101
+ */
102
+ // Add type definition for formats
103
+ type FormatType = 'bold' | 'italic' | 'underline' | 'link';
104
+ type ActiveFormats = Record<FormatType, boolean>;
105
+ type FormatMapping = Record<FormatType, { value: string; icon: any }>;
106
+
107
+ let activeFormats = $state<ActiveFormats>({
108
+ bold: false,
109
+ italic: false,
110
+ underline: false,
111
+ link: false
112
+ });
113
+
114
+ const formatMapping: FormatMapping = {
115
+ bold: { value: 'b', icon: IconBold },
116
+ italic: { value: 'i', icon: IconItalic },
117
+ underline: { value: 'u', icon: IconUnderline },
118
+ link: { value: 'link', icon: IconLink }
119
+ };
120
+
121
+ let currentTextStyle = $state('text'); // Track current text style
122
+
123
+ let showColorPicker = $state(false);
124
+ let currentColor = $state(textColor);
125
+ let selectedTextRange: { from: number, to: number } | null = $state(null);
126
+
127
+ const textOptions = [
128
+ { value: 'text', label: 'Paragraph', icon: IconPilcrow },
129
+ { value: 'h1', label: 'H1' },
130
+ { value: 'h2', label: 'H2' },
131
+ { value: 'h3', label: 'H3' }
132
+ ];
133
+
134
+ const listOptions = [
135
+ { value: 'bulletList', label: 'Bullet List', icon: IconList },
136
+ { value: 'orderedList', label: 'Numbered List', icon: IconListNumbers },
137
+ { value: 'checkList', label: 'Check List', icon: IconListCheck }
138
+ ];
139
+
140
+ const content = writable(value);
141
+
142
+ // Create a store for managing dropdowns
143
+ const openDropdowns = writable<Set<string>>(new Set());
144
+
145
+ function toggleDropdown(id: string) {
146
+ openDropdowns.update(set => {
147
+ if (set.has(id)) {
148
+ set.delete(id);
149
+ } else {
150
+ set.add(id);
151
+ }
152
+ return set;
153
+ });
154
+ }
155
+
156
+ // Add these variables to track focus state
157
+ let editorHasFocus = $state(false);
158
+ let toolbarRef: HTMLDivElement;
159
+
160
+
161
+
162
+ // Update to use $derived for reactive statement
163
+ const editorStyle = $derived(`
164
+ --editor-min-height: auto;
165
+ --editor-max-height: none;
166
+ --transition-duration: 0ms;
167
+ --transition-timing: ease-out;
168
+ `);
169
+
170
+ // Add this with other state declarations
171
+ let editorClass = $derived(`border-none overflow-auto editor-height ${''}`);
172
+
173
+ // Add state to track if any dropdown is open
174
+ let isDropdownOpen = $state(false);
175
+
176
+ /**
177
+ * Editor Mount Handler
178
+ *
179
+ * Initializes the editor instance and sets up event listeners:
180
+ * 1. Sets initial content if provided
181
+ * 2. Configures editor options (autofocus, editability)
182
+ * 3. Sets up selection tracking for format updates
183
+ * 4. Manages focus/blur behavior and height transitions
184
+ * 5. Handles initial mount state
185
+ *
186
+ * Edge Cases:
187
+ * - Prevents height changes when dropdowns are open
188
+ * - Manages focus state during toolbar interactions
189
+ * - Handles selection preservation during format changes
190
+ */
191
+ // Add these new state variables after the other state declarations
192
+ let lastKnownContent = $state('');
193
+ let wasVisible = $state(true);
194
+
195
+ function handleEditorMount(e: any) {
196
+ editorInstance = e.detail.editor;
197
+
198
+ if (!editorInstance) {
199
+ console.error('Failed to initialize editor instance');
200
+ return;
201
+ }
202
+
203
+ // Restore content if we were previously hidden
204
+ if (!wasVisible && lastKnownContent) {
205
+ try {
206
+ const coloredContent = `<span style="color: ${textColor}">${lastKnownContent}</span>`;
207
+ editorInstance.commands.setContent(coloredContent);
208
+ } catch (error) {
209
+ console.error('Error restoring content after visibility change:', error);
210
+ }
211
+ } else if (value) {
212
+ try {
213
+ const coloredContent = `<span style="color: ${textColor}">${value}</span>`;
214
+ editorInstance.commands.setContent(coloredContent);
215
+
216
+ // Set caret to start after setting content
217
+ editorInstance.commands.setTextSelection(0);
218
+ } catch (error) {
219
+ console.error('Error setting initial content and color:', error);
220
+ }
221
+ }
222
+
223
+ // Disable auto-focus behavior
224
+ editorInstance.setOptions({
225
+ autofocus: false,
226
+ editable: true
227
+ });
228
+
229
+ // Add selection change listener
230
+ editorInstance.on('selectionUpdate', () => {
231
+ handleSelectionChange();
232
+ updateActiveFormats();
233
+ });
234
+
235
+ // Track focus state and handle height changes
236
+ editorInstance.on('focus', () => {
237
+ onFocus();
238
+ editorHasFocus = true;
239
+
240
+ // When focusing, ensure caret is at start if this is initial mount
241
+ if (isInitialMount && editorInstance) {
242
+ editorInstance.commands.setTextSelection(0);
243
+ }
244
+ });
245
+
246
+ // Update the blur handler inside handleEditorMount
247
+ editorInstance.on('blur', ({ event }) => {
248
+ const relatedTarget = (event as FocusEvent).relatedTarget as Node | null;
249
+ handleEditorBlur(relatedTarget);
250
+ });
251
+
252
+ // Set initial mount flag
253
+ isInitialMount = true;
254
+ setTimeout(() => {
255
+ isInitialMount = false;
256
+ // Check overflow only once after initial mount
257
+ setTimeout(() => {
258
+ checkContentOverflow();
259
+ }, 300); // Give it a bit more time to ensure content is fully rendered
260
+ }, 100);
261
+
262
+ updateActiveFormats();
263
+
264
+ // Helper function to check if content overflows viewport - only called once on mount
265
+ function checkContentOverflow() {
266
+ if (!editorInstance) return;
267
+ try {
268
+ const editorDom = editorInstance.view.dom;
269
+ const contentArea = editorDom.closest('.editor-content-area') as HTMLElement;
270
+
271
+ if (!contentArea) {
272
+ console.error('Could not find .editor-content-area parent element');
273
+ return;
274
+ }
275
+
276
+ const proseMirror = contentArea.querySelector('.ProseMirror') as HTMLElement;
277
+ if (!proseMirror) {
278
+ console.error('Could not find .ProseMirror element inside content area');
279
+ return;
280
+ }
281
+
282
+ // Get the actual content height (including padding)
283
+ const contentHeight = proseMirror.scrollHeight;
284
+ // Get the available container height
285
+ const containerHeight = contentArea.clientHeight;
286
+ const isOverflowing = contentHeight > containerHeight;
287
+
288
+ console.log('Initial overflow check:', {
289
+ contentHeight,
290
+ containerHeight,
291
+ difference: contentHeight - containerHeight,
292
+ isOverflowing
293
+ });
294
+
295
+ if (isOverflowing) {
296
+ proseMirror.style.backgroundColor = 'rgba(255, 0, 0, 0.1)';
297
+ }
298
+ } catch (error) {
299
+ console.error('Error checking content overflow:', error);
300
+ }
301
+ }
302
+
303
+ // Helper function to force caret and scroll to beginning
304
+ function forceCaretToStart() {
305
+ if (!editorInstance) return;
306
+ try {
307
+ // Only force caret to start if this is the initial mount
308
+ if (isInitialMount) {
309
+ // Force the caret (text selection) to the beginning
310
+ editorInstance.chain().setTextSelection({ from: 0, to: 0 }).run();
311
+ }
312
+ } catch (error) {
313
+ console.error('Error forcing caret to beginning:', error);
314
+ }
315
+ }
316
+
317
+ // Only call forceCaretToStart once during initial mount
318
+ if (isInitialMount) {
319
+ setTimeout(forceCaretToStart, 300);
320
+ }
321
+ }
322
+
323
+ function handleEditorUpdate(e: any) {
324
+ if (!editorInstance) return;
325
+
326
+ // bind:content on ShadEditor already assigned `value` before this event,
327
+ // so comparing to `value` skipped onChange and the compact preview never updated.
328
+ const newContent = e.detail?.html ?? editorInstance.getHTML?.() ?? '';
329
+ lastKnownContent = newContent;
330
+ content.set(newContent);
331
+ onChange?.(newContent);
332
+ updateActiveFormats();
333
+ currentTextStyle = getCurrentTextStyle();
334
+ }
335
+
336
+ /**
337
+ * Format Management System
338
+ *
339
+ * Handles text formatting operations and state:
340
+ * - Updates toolbar UI based on current selection
341
+ * - Manages format toggles (bold, italic, etc.)
342
+ * - Handles text style changes (headings, lists)
343
+ * - Preserves selection during format operations
344
+ *
345
+ * Selection Handling:
346
+ * - Tracks active formats only when text is selected
347
+ * - Resets formats when no selection exists
348
+ * - Maintains format state during dropdown operations
349
+ */
350
+ function updateActiveFormats() {
351
+ if (!editorInstance) return;
352
+
353
+ // Update activeFormats based on editor state
354
+ const newFormats = {
355
+ bold: editorInstance.isActive('bold'),
356
+ italic: editorInstance.isActive('italic'),
357
+ underline: editorInstance.isActive('underline'),
358
+ link: editorInstance.isActive('link')
359
+ };
360
+
361
+ // Only update if there's a change to prevent unnecessary rerenders
362
+ if (JSON.stringify(newFormats) !== JSON.stringify($state.snapshot(activeFormats))) {
363
+ activeFormats = newFormats;
364
+ console.log('Active formats updated:', $state.snapshot(activeFormats));
365
+ }
366
+ }
367
+
368
+ function applyFormat(format: FormatType, isAdding: boolean = true) {
369
+ if (!editorInstance) return;
370
+
371
+ try {
372
+ // Always focus first and start a chain
373
+ const chain = editorInstance.chain().focus() as any;
374
+
375
+ switch (format) {
376
+ case 'bold':
377
+ chain.toggleBold().run();
378
+ break;
379
+ case 'italic':
380
+ chain.toggleItalic().run();
381
+ break;
382
+ case 'underline':
383
+ chain.toggleUnderline().run();
384
+ break;
385
+ case 'link':
386
+ if (isAdding) {
387
+ const href = window.prompt('Enter URL');
388
+ if (href) {
389
+ chain.setLink({ href }).run();
390
+ }
391
+ } else {
392
+ chain.unsetLink().run();
393
+ }
394
+ break;
395
+ }
396
+
397
+ // Update formats after applying changes
398
+ setTimeout(() => {
399
+ updateActiveFormats();
400
+ }, 0);
401
+ } catch (error) {
402
+ console.error('Error applying format:', format, error);
403
+ }
404
+ }
405
+
406
+ function handleToggleChange(newValues: string[] | undefined): void {
407
+ if (!editorInstance) {
408
+ console.warn('No editor instance available');
409
+ return;
410
+ }
411
+
412
+ if (!newValues) {
413
+ console.warn('No new values provided');
414
+ return;
415
+ }
416
+
417
+ // Use $state.snapshot() for logging
418
+ const currentValues = $state.snapshot(toggleValues);
419
+ console.log('Toggle change:', { newValues, currentValues });
420
+
421
+ // Find which format was toggled by comparing the arrays
422
+ const added = newValues.filter(v => !currentValues.includes(v));
423
+ const removed = currentValues.filter(v => !newValues.includes(v));
424
+
425
+ // Handle the change
426
+ if (added.length > 0) {
427
+ // Find the format type for the added value
428
+ const format = Object.entries(formatMapping).find(([_, m]) => m.value === added[0])?.[0] as FormatType;
429
+ if (format) {
430
+ console.log('Applying format:', format);
431
+ applyFormat(format, true);
432
+ }
433
+ } else if (removed.length > 0) {
434
+ // Find the format type for the removed value
435
+ const format = Object.entries(formatMapping).find(([_, m]) => m.value === removed[0])?.[0] as FormatType;
436
+ if (format) {
437
+ console.log('Removing format:', format);
438
+ applyFormat(format, false);
439
+ }
440
+ }
441
+ }
442
+
443
+ // Update derived toggleValues with proper typing
444
+ const toggleValues = $derived(Object.entries(activeFormats)
445
+ .filter(([_, isActive]) => isActive)
446
+ .map(([format]) => formatMapping[format as FormatType].value)
447
+ );
448
+
449
+ // Restore handleTextStyleChange for other style changes
450
+ function handleTextStyleChange(value: string) {
451
+ if (!editorInstance) return;
452
+
453
+ try {
454
+ const { from, to } = editorInstance.state.selection;
455
+ const selectedText = editorInstance.state.doc.textBetween(from, to);
456
+
457
+ console.log('Changing style for text "%s" to:', (selectedText || 'No text selected'), value);
458
+
459
+ // Store the current scroll position and selection
460
+ const editorDom = editorInstance.view.dom;
461
+ const contentArea = editorDom.closest('.editor-content-area') as HTMLElement;
462
+ const scrollTop = contentArea ? contentArea.scrollTop : editorDom.scrollTop;
463
+ const selection = { from, to };
464
+
465
+ const chain = editorInstance.chain().focus() as any;
466
+
467
+ switch (value) {
468
+ case 'text':
469
+ chain.setNode('paragraph').run();
470
+ currentTextStyle = value;
471
+ break;
472
+ case 'h1':
473
+ case 'h2':
474
+ case 'h3':
475
+ const level = parseInt(value.charAt(1)) as TipTapEditorLevel;
476
+ chain.toggleHeading({ level }).run();
477
+ currentTextStyle = editorInstance.isActive('heading', { level }) ? value : 'text';
478
+ break;
479
+ case 'bulletList':
480
+ chain.toggleBulletList().run();
481
+ currentTextStyle = value;
482
+ break;
483
+ case 'orderedList':
484
+ chain.toggleOrderedList().run();
485
+ currentTextStyle = value;
486
+ break;
487
+ case 'checkList':
488
+ chain.toggleTaskList().run();
489
+ currentTextStyle = value;
490
+ break;
491
+ case 'blockquote':
492
+ chain.toggleBlockquote().run();
493
+ currentTextStyle = value;
494
+ break;
495
+ case 'code':
496
+ chain.toggleCode().run();
497
+ currentTextStyle = value;
498
+ break;
499
+ case 'strike':
500
+ chain.toggleStrike().run();
501
+ currentTextStyle = value;
502
+ break;
503
+ }
504
+
505
+ // Restore the scroll position and selection after the style change
506
+ requestAnimationFrame(() => {
507
+ if (contentArea) {
508
+ contentArea.scrollTop = scrollTop;
509
+ } else if (editorDom) {
510
+ editorDom.scrollTop = scrollTop;
511
+ }
512
+ // Restore selection
513
+ editorInstance?.chain()
514
+ .setTextSelection(selection)
515
+ .run();
516
+ });
517
+
518
+ updateActiveFormats();
519
+ textStyleDropdownOpen = false;
520
+ } catch (error) {
521
+ console.error('Error changing text style:', error);
522
+ }
523
+ }
524
+
525
+ function getCurrentTextStyle() {
526
+ if (!editorInstance) return 'text';
527
+
528
+ // Check for headings first
529
+ if (editorInstance.isActive('heading', { level: 1 })) return 'h1';
530
+ if (editorInstance.isActive('heading', { level: 2 })) return 'h2';
531
+ if (editorInstance.isActive('heading', { level: 3 })) return 'h3';
532
+
533
+ // Check for lists and other block-level formats
534
+ if (editorInstance.isActive('bulletList')) return 'bulletList';
535
+ if (editorInstance.isActive('orderedList')) return 'orderedList';
536
+ if (editorInstance.isActive('checkList')) return 'checkList';
537
+ if (editorInstance.isActive('blockquote')) return 'blockquote';
538
+ if (editorInstance.isActive('code')) return 'code';
539
+ if (editorInstance.isActive('strike')) return 'strike';
540
+
541
+ // If no block-level format is active, return the current text style
542
+ const marks = editorInstance.state.selection.$head.marks();
543
+ if (marks.length > 0) {
544
+ // Keep the current text style if there are inline marks
545
+ return currentTextStyle;
546
+ }
547
+
548
+ return 'text';
549
+ }
550
+ // Function to store text selection
551
+ function storeSelection() {
552
+ if (!editorInstance) return null;
553
+ const { from, to } = editorInstance.state.selection;
554
+ if (from === to) return null;
555
+ return { from, to };
556
+ }
557
+
558
+ // Function to restore text selection
559
+ function restoreSelection() {
560
+ if (!editorInstance || !selectedTextRange) return;
561
+ editorInstance.chain()
562
+ .setTextSelection({ from: selectedTextRange.from, to: selectedTextRange.to })
563
+ .run();
564
+ }
565
+
566
+ // Helper function to convert RGB to Hex
567
+ function rgbToHex(r: number, g: number, b: number): string {
568
+ const toHex = (n: number) => {
569
+ const hex = Math.round(n).toString(16);
570
+ return hex.length === 1 ? '0' + hex : hex;
571
+ };
572
+ return '#' + toHex(r) + toHex(g) + toHex(b);
573
+ }
574
+
575
+ // Update handleColorChange to use current selection if available
576
+ function handleColorChange(color: string) {
577
+ if (!editorInstance) return;
578
+
579
+ try {
580
+ // Get current selection
581
+ const { from, to } = editorInstance.state.selection;
582
+ const hasSelection = from !== to;
583
+
584
+ if (hasSelection) {
585
+ // Apply color to selection using the correct command
586
+ editorInstance.chain()
587
+ .setTextSelection({ from, to })
588
+ .setMark('textStyle', { color })
589
+ .run();
590
+
591
+ // Remove any highlight marks and restore selection visibility
592
+ editorInstance.chain()
593
+ .unsetMark('highlight')
594
+ .run();
595
+
596
+ // Remove hide-selection class
597
+ editorInstance.view.dom.classList.remove('hide-selection');
598
+
599
+ // Ensure editor has focus
600
+ editorInstance.commands.focus();
601
+ }
602
+ } catch (error) {
603
+ console.error('Error applying color:', error);
604
+ }
605
+ }
606
+
607
+ // $effect(() => {
608
+ // if (value !== $content && editorInstance) {
609
+ // console.log('External value changed:', value);
610
+ // content.set(value);
611
+ // editorInstance.commands.setContent(value);
612
+ // }
613
+ // });
614
+
615
+ // Add colorPickerOpen state
616
+ let colorPickerOpen = $state(false);
617
+
618
+ // Add function to handle color picker open/close
619
+ function handleColorPickerToggle() {
620
+ colorPickerOpen = !colorPickerOpen;
621
+ if (colorPickerOpen && selectedTextRange) {
622
+ restoreSelection();
623
+ }
624
+ }
625
+
626
+ // Update getSelectedTextColor to ensure hex format with 100% opacity
627
+ function getSelectedTextColor(): string {
628
+ if (!editorInstance) return currentColor;
629
+
630
+ const { from, to } = editorInstance.state.selection;
631
+ if (from === to) return currentColor;
632
+
633
+ // Get the color mark from the selection
634
+ const marks = editorInstance.state.doc.nodeAt(from)?.marks;
635
+ const colorMark = marks?.find(mark => mark.type.name === 'textStyle' && mark.attrs.color);
636
+
637
+ let color = colorMark?.attrs.color || currentColor;
638
+
639
+ // Convert RGB to Hex if needed
640
+ if (color.startsWith('rgb')) {
641
+ const matches = color.match(/\d+/g);
642
+ if (matches && matches.length >= 3) {
643
+ color = rgbToHex(
644
+ parseInt(matches[0]),
645
+ parseInt(matches[1]),
646
+ parseInt(matches[2])
647
+ );
648
+ }
649
+ }
650
+
651
+ // Ensure color is in hex format and has 100% opacity
652
+ if (color.length === 9) { // If it's a hex with alpha
653
+ color = color.substring(0, 7); // Remove alpha channel
654
+ }
655
+
656
+ return color;
657
+ }
658
+
659
+ // Update handleSelectionChange to properly handle color conversion
660
+ function handleSelectionChange() {
661
+ if (!editorInstance) return;
662
+
663
+ const { from, to } = editorInstance.state.selection;
664
+ const hasSelection = from !== to;
665
+
666
+ if (hasSelection) {
667
+ selectedRange = { from, to };
668
+
669
+ // Get the selected text and check for color mark
670
+ const marks = editorInstance.state.doc.nodeAt(from)?.marks || [];
671
+ const colorMark = marks.find(mark =>
672
+ mark.type.name === 'textStyle' && mark.attrs.color
673
+ );
674
+
675
+ // Update currentColor if a color mark is found
676
+ if (colorMark?.attrs.color) {
677
+ let color = colorMark.attrs.color;
678
+
679
+ // Convert RGB to Hex if needed
680
+ if (color.startsWith('rgb')) {
681
+ const matches = color.match(/\d+/g);
682
+ if (matches && matches.length >= 3) {
683
+ color = rgbToHex(
684
+ parseInt(matches[0]),
685
+ parseInt(matches[1]),
686
+ parseInt(matches[2])
687
+ );
688
+ }
689
+ }
690
+
691
+ // Remove alpha channel if present
692
+ if (color.length === 9) {
693
+ color = color.substring(0, 7);
694
+ }
695
+
696
+ currentColor = color;
697
+ }
698
+
699
+ console.log('Selection updated:', {
700
+ text: editorInstance.state.doc.textBetween(from, to),
701
+ range: { from, to },
702
+ style: currentTextStyle,
703
+ format: [
704
+ ...(editorInstance.isActive('bold') ? ['b'] : []),
705
+ ...(editorInstance.isActive('italic') ? ['i'] : []),
706
+ ...(editorInstance.isActive('underline') ? ['u'] : []),
707
+ ...(editorInstance.isActive('link') ? ['link'] : [])
708
+ ],
709
+ color: currentColor
710
+ });
711
+ } else {
712
+ selectedRange = null;
713
+ currentColor = textColor; // Reset to default color when deselecting
714
+ }
715
+ }
716
+
717
+ // Add this state to track animation
718
+ let isColorPickerAnimating = $state(false);
719
+
720
+ // Update handleColorButtonClick to ensure hex format
721
+ function handleColorButtonClick() {
722
+ if (!editorInstance) return;
723
+
724
+ const { from, to } = editorInstance.state.selection;
725
+ if (from !== to) {
726
+ selectedRange = { from, to };
727
+ isSelectionActive = true;
728
+
729
+ // Get and convert color to hex format
730
+ let selectedColor = getSelectedTextColor();
731
+ // Ensure we convert any rgb colors to hex
732
+ if (selectedColor.startsWith('rgb')) {
733
+ const matches = selectedColor.match(/\d+/g);
734
+ if (matches && matches.length >= 3) {
735
+ selectedColor = rgbToHex(
736
+ parseInt(matches[0]),
737
+ parseInt(matches[1]),
738
+ parseInt(matches[2])
739
+ );
740
+ }
741
+ }
742
+ // Remove any alpha channel
743
+ if (selectedColor.length === 9) {
744
+ selectedColor = selectedColor.substring(0, 7);
745
+ }
746
+
747
+ currentColor = selectedColor;
748
+
749
+ // Set focus to editor
750
+ editorHasFocus = true;
751
+ // editorInstance.commands.focus();
752
+
753
+ } else {
754
+ selectedRange = null;
755
+ isSelectionActive = false;
756
+ }
757
+
758
+ showColorPicker = true;
759
+ isColorPickerAnimating = true;
760
+
761
+ // console.log('Color picker toolbar opened with selection:', {
762
+ // range: selectedRange,
763
+ // color: currentColor,
764
+ // hasFocus: editorHasFocus,
765
+ // isActive
766
+ // });
767
+ }
768
+
769
+ // Update the event handler function to handle CustomEvent
770
+ function handleColorPickerInteraction(event: CustomEvent<any>) {
771
+ // Get the original MouseEvent from the detail if available
772
+ const mouseEvent = event.detail?.originalEvent as MouseEvent;
773
+ if (mouseEvent) {
774
+ // Prevent the default behavior that might clear the selection
775
+ mouseEvent.preventDefault();
776
+ mouseEvent.stopPropagation();
777
+ }
778
+
779
+ // Reapply the selection if it exists
780
+ if (selectedRange && editorInstance) {
781
+ editorInstance.chain()
782
+ .focus()
783
+ .setTextSelection(selectedRange)
784
+ .run();
785
+ }
786
+ }
787
+
788
+ // Update handleColorPickerClose function
789
+ function handleColorPickerClose() {
790
+ showColorPicker = false;
791
+ isColorPickerAnimating = false;
792
+ isSelectionActive = false;
793
+
794
+ if (editorInstance) {
795
+ // Create a chain to handle all operations
796
+ const chain = editorInstance.chain();
797
+
798
+ // Remove highlight if it exists
799
+ chain.unsetMark('highlight');
800
+
801
+ // Store current selection before cleanup
802
+ const currentSelection = editorInstance.state.selection;
803
+ const hasSelection = currentSelection.from !== currentSelection.to;
804
+
805
+ // Run the chain
806
+ chain.run();
807
+
808
+ // Remove hide-selection class
809
+ editorInstance.view.dom.classList.remove('hide-selection');
810
+
811
+ // Always focus the editor first
812
+ editorInstance.view.focus();
813
+
814
+ // Then reapply selection if it existed
815
+ if (hasSelection) {
816
+ editorInstance.commands.setTextSelection({
817
+ from: currentSelection.from,
818
+ to: currentSelection.to
819
+ });
820
+ }
821
+ }
822
+ }
823
+
824
+ // Add effect to handle clicks outside Color Select
825
+ $effect(() => {
826
+ const handleClickOutside = (event: MouseEvent) => {
827
+ const colorSelectModal = document.querySelector('[data-radix-popper-content-wrapper]');
828
+ const isClickingColorSelect = colorSelectModal?.contains(event.target as Node);
829
+
830
+ // Don't do anything if clicking within the color select modal
831
+ if (isClickingColorSelect) {
832
+ // Prevent any focus changes
833
+ event.preventDefault();
834
+ event.stopPropagation();
835
+ return;
836
+ }
837
+ };
838
+
839
+ if (isColorSelectOpen) {
840
+ document.addEventListener('mousedown', handleClickOutside);
841
+ return () => document.removeEventListener('mousedown', handleClickOutside);
842
+ }
843
+ });
844
+
845
+ /**
846
+ * Color Management System
847
+ *
848
+ * Handles text color operations:
849
+ * - Stores and restores text selection during color picker use
850
+ * - Manages color picker visibility state
851
+ * - Applies colors to selected text
852
+ * - Retrieves current text color for selected range
853
+ *
854
+ * Selection Preservation:
855
+ * - Stores selection before opening color picker
856
+ * - Restores selection after color picker closes
857
+ * - Handles edge cases when no text is selected
858
+ */
859
+
860
+ // Add this with the other function declarations in the script section
861
+ function handleToolbarInteraction(event: MouseEvent) {
862
+ const target = event.target as HTMLElement;
863
+
864
+ // If clicking toolbar elements or color picker, maintain expanded state
865
+ if (target.matches('input, button, [role="button"], [tabindex="0"]') ||
866
+ target.closest('.color-picker-container')) {
867
+ // Keep toolbar enabled since we're interacting with it
868
+ editorHasFocus = true;
869
+ return;
870
+ }
871
+
872
+ event.preventDefault();
873
+ event.stopPropagation();
874
+
875
+ // When clicking toolbar itself, maintain focus and enabled state
876
+ if (editorInstance) {
877
+ editorInstance.commands.focus();
878
+ editorHasFocus = true;
879
+ }
880
+ }
881
+
882
+ // Add this function to handle keyboard interactions
883
+ function handleToolbarKeyDown(event: KeyboardEvent) {
884
+ // Don't handle keyboard events for inputs and interactive elements
885
+ const target = event.target as HTMLElement;
886
+ if (target.matches('input, button, [role="button"], [tabindex="0"]')) {
887
+ return;
888
+ }
889
+
890
+ // Handle keyboard interactions for toolbar
891
+ if (event.key === 'Enter' || event.key === ' ') {
892
+ event.preventDefault();
893
+ handleToolbarInteraction(event as unknown as MouseEvent);
894
+ }
895
+ }
896
+
897
+ // Update the effect that maintains selection during color picker interactions
898
+ $effect(() => {
899
+ if (showColorPicker && selectedTextRange && editorInstance) {
900
+ const { from, to } = selectedTextRange;
901
+ editorInstance.chain()
902
+ .setTextSelection({ from, to })
903
+ .run();
904
+ }
905
+ });
906
+
907
+ // Add these near the top of the script section with other state declarations
908
+ let isColorSelectOpen = $state(false);
909
+
910
+ // Add handleKeyDown function
911
+ function handleKeyDown(event: KeyboardEvent) {
912
+ if (event.key === 'Escape') {
913
+ if (showColorPicker) {
914
+ event.preventDefault();
915
+ handleColorPickerClose();
916
+ }
917
+ }
918
+ }
919
+
920
+ // Update handleEditorBlur to maintain toolbar state
921
+ function handleEditorBlur(relatedTarget: Node | null) {
922
+ if (!editorInstance) return;
923
+
924
+ const colorSelectModal = document.querySelector('[data-radix-popper-content-wrapper]');
925
+ const popoverContent = document.querySelector('[role="dialog"]');
926
+ const commandMenu = document.querySelector('[cmdk-root]');
927
+
928
+ const isClickingInside = toolbarRef?.contains(relatedTarget) ||
929
+ editorInstance.view.dom.contains(relatedTarget as Node) ||
930
+ colorSelectModal?.contains(relatedTarget as Node) ||
931
+ popoverContent?.contains(relatedTarget as Node) ||
932
+ commandMenu?.contains(relatedTarget as Node);
933
+
934
+ if (!isClickingInside) {
935
+ editorHasFocus = false;
936
+ }
937
+ }
938
+
939
+ // Add this logging helper
940
+ function logTransitionState(source: string) {
941
+ // console.log(`Transition State [${source}]:`, {
942
+ // isTransitioning,
943
+ // editorHeight,
944
+ // isActive,
945
+ // editorHasFocus,
946
+ // isIdle: editorHeight === IDLE_HEIGHT
947
+ // });
948
+ }
949
+
950
+ // Add this function to handle popover state changes
951
+ function handlePopoverOpenChange(isOpen: boolean) {
952
+ textStyleDropdownOpen = isOpen;
953
+
954
+ // Ensure editor maintains focus when popover opens/closes
955
+ if (editorInstance) {
956
+ editorHasFocus = true;
957
+ editorInstance.commands.focus();
958
+ }
959
+ }
960
+
961
+ // Add this function to handle command item selection
962
+ function handleCommandSelect(value: string) {
963
+ if (!editorInstance) return;
964
+
965
+ // Change the text style to the selected value
966
+ handleTextStyleChange(value);
967
+
968
+ // Restore editor focus after command selection
969
+ setTimeout(() => {
970
+ if (!editorInstance) return;
971
+ editorHasFocus = true;
972
+ editorInstance.commands.focus();
973
+ }, 0);
974
+ }
975
+
976
+ // Add these variables to track button position
977
+ let triggerButtonRect = $state<DOMRect | null>(null);
978
+ let triggerButton: any;
979
+ let triggerButtonElement: HTMLButtonElement;
980
+
981
+ // Add function to update position using the button element directly
982
+ function updateTriggerPosition(buttonElement: HTMLButtonElement) {
983
+ triggerButtonRect = buttonElement.getBoundingClientRect();
984
+ }
985
+
986
+ // Add these state variables near the top with other state declarations
987
+ let selectedRange: { from: number, to: number } | null = $state(null);
988
+ let isSelectionActive = $state(false);
989
+
990
+ // Add this near the top of the script section with other constants
991
+ const STYLE_DROPDOWN_ID = 'text-style-dropdown';
992
+
993
+ // Add these functions near the top with other event handlers
994
+ function closeTextStyleDropdown() {
995
+ if (textStyleDropdownOpen) {
996
+ textStyleDropdownOpen = false;
997
+ // Restore focus to editor
998
+ if (!editorInstance) return;
999
+
1000
+ setTimeout(() => {
1001
+ if (!editorInstance) return;
1002
+ editorHasFocus = true;
1003
+ editorInstance.commands.focus();
1004
+ }, 0);
1005
+ }
1006
+ }
1007
+
1008
+ function handleScroll() {
1009
+ closeTextStyleDropdown();
1010
+ }
1011
+
1012
+ // Add to lifecycle management
1013
+ onMount(() => {
1014
+ window.addEventListener('scroll', handleScroll, true);
1015
+ });
1016
+
1017
+ onDestroy(() => {
1018
+ window.removeEventListener('scroll', handleScroll, true);
1019
+ });
1020
+
1021
+ // Add cleanup function
1022
+ onDestroy(() => {
1023
+ if (editorInstance) {
1024
+ // Store the current content before unmounting
1025
+ lastKnownContent = editorInstance.getHTML();
1026
+ wasVisible = false;
1027
+
1028
+ // Clean up editor instance
1029
+ editorInstance.destroy();
1030
+ editorInstance = null;
1031
+ }
1032
+ });
1033
+
1034
+ // Update mousedown handler to remove height changes
1035
+ function handleMouseDown(e: MouseEvent) {
1036
+ if (editorInstance) {
1037
+ const target = e.target as HTMLElement;
1038
+ const isInteractive = target.matches('button, input, [role="button"], [tabindex="0"]') ||
1039
+ target.closest('button, input, [role="button"], [tabindex="0"]');
1040
+
1041
+ if (!isInteractive) {
1042
+ e.preventDefault();
1043
+ e.stopPropagation();
1044
+
1045
+ // Just focus the editor
1046
+ editorHasFocus = true;
1047
+ editorInstance.commands.focus();
1048
+ }
1049
+ }
1050
+ }
1051
+
1052
+ // Update hit zone handler to remove transitions
1053
+ function handleHitZone(e: MouseEvent) {
1054
+ e.preventDefault();
1055
+ e.stopPropagation();
1056
+ if (editorInstance) {
1057
+ editorInstance.commands.focus();
1058
+ editorHasFocus = true;
1059
+ }
1060
+ }
1061
+ </script>
1062
+
1063
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
1064
+ <!-- svelte-ignore event_directive_deprecated -->
1065
+ <div
1066
+ class="text-area-input-controller {className ? className + ' ' : ''}flex flex-col"
1067
+ on:keydown={handleKeyDown}
1068
+ tabindex="-1"
1069
+ >
1070
+ <!-- Label section -->
1071
+ <div class="label-container flex items-center justify-between">
1072
+ <!-- svelte-ignore a11y_label_has_associated_control -->
1073
+ <label class="subtext text-grey5 cursor-default select-none truncate">{label}</label>
1074
+ </div>
1075
+
1076
+ <!-- Main editor container -->
1077
+ <div
1078
+ class="main-editor-container group relative w-full h-full rounded-small widgetic-colors bg-grey1 flex flex-col overflow-hidden"
1079
+ style={editorStyle}
1080
+ on:mousedown={handleMouseDown}
1081
+ >
1082
+ <!-- Toolbar at the top -->
1083
+ <div
1084
+ bind:this={toolbarRef}
1085
+ class="toolbar-container sticky top-0 left-0 right-0 h-[56px] bg-grey1 z-10 border-b border-grey2 overflow-visible select-none"
1086
+ on:mousedown={handleToolbarInteraction}
1087
+ on:click={handleToolbarInteraction}
1088
+ on:keydown={handleToolbarKeyDown}
1089
+ role="toolbar"
1090
+ aria-label="Text formatting toolbar"
1091
+ tabindex="-1"
1092
+ >
1093
+ <div class="toolbar-items-row relative flex items-center h-full w-full">
1094
+ <!-- Format cluster centered; close stays on the right -->
1095
+ <div class={`toolbar-items-container absolute inset-y-0 left-0 right-10 flex items-center justify-center gap-2 transition-transform duration-200 ease-out ${
1096
+ isColorPickerAnimating ? 'translate-y-[-200%]' :
1097
+ showColorPicker ? 'translate-y-[-200%]' :
1098
+ 'translate-y-0'
1099
+ }`}>
1100
+ <Button
1101
+ variant="outline"
1102
+ size="icon"
1103
+ class="color-picker-preview-button toolbar-button !h-8 !w-8 !min-w-8 !p-0 shrink-0"
1104
+ onclick={(e) => {
1105
+ e.stopPropagation();
1106
+ e.preventDefault();
1107
+ const button = e.currentTarget as HTMLButtonElement;
1108
+ button.blur();
1109
+ handleColorButtonClick();
1110
+ }}
1111
+ >
1112
+ <div class="toolbar-button-content flex h-full w-full items-center justify-center">
1113
+ <IconBrush
1114
+ class="!text-grey5 hover:!text-grey7"
1115
+ style="width: 20px !important; height: 20px !important; min-width: 20px !important; min-height: 20px !important; max-width: 20px !important; max-height: 20px !important; {selectedRange ? `color: ${currentColor} !important;` : ''}"
1116
+ />
1117
+ </div>
1118
+ </Button>
1119
+
1120
+ <!-- Text Formatting Toggle Group -->
1121
+ <ToggleGroup.Root
1122
+ type="multiple"
1123
+ size="sm"
1124
+ variant="outline"
1125
+ class="text-formatting-toggle-group inline-flex h-8 gap-2"
1126
+ value={toggleValues}
1127
+ onValueChange={(value) => {
1128
+ if (!editorInstance) return;
1129
+ if (value === undefined) return;
1130
+ handleToggleChange(value);
1131
+ }}
1132
+ >
1133
+ {#each Object.entries(formatMapping) as [format, { value, icon: Icon }] (format)}
1134
+ <ToggleGroup.Item
1135
+ {value}
1136
+ aria-label={`Toggle ${format}`}
1137
+ data-state={activeFormats[format as FormatType] ? 'on' : 'off'}
1138
+ class="toolbar-button shrink-0 !h-8 !w-8 !min-w-8 !p-0 {activeFormats[format as FormatType] ? 'bg-muted' : ''}"
1139
+ >
1140
+ <div class="toolbar-button-content flex h-full w-full items-center justify-center">
1141
+ <Icon
1142
+ class="text-current"
1143
+ style="width: 20px !important; height: 20px !important; min-width: 20px !important; min-height: 20px !important; max-width: 20px !important; max-height: 20px !important;"
1144
+ />
1145
+ </div>
1146
+ </ToggleGroup.Item>
1147
+ {/each}
1148
+ </ToggleGroup.Root>
1149
+
1150
+ <!-- Text Style Dropdown -->
1151
+ <div class="toolbar-text-style-ct inline-flex items-center shrink-0">
1152
+ <Popover.Root
1153
+ bind:open={textStyleDropdownOpen}
1154
+ onOpenChange={(e: any) => {
1155
+ handlePopoverOpenChange(e);
1156
+ textStyleDropdownOpen = e;
1157
+ }}
1158
+ >
1159
+ <Popover.Trigger>
1160
+ <Button
1161
+ bind:this={triggerButton}
1162
+ id="text-style-trigger"
1163
+ variant="outline"
1164
+ size="icon"
1165
+ class="toolbar-button toolbar-dropdown-trigger !h-8 !w-11 !min-w-11 !max-w-11 !p-0 justify-center"
1166
+ onclick={(e) => {
1167
+ e.stopPropagation();
1168
+ e.preventDefault();
1169
+
1170
+ const buttonElement = e.currentTarget as HTMLButtonElement;
1171
+ updateTriggerPosition(buttonElement);
1172
+ buttonElement.blur();
1173
+
1174
+ textStyleDropdownOpen = !textStyleDropdownOpen;
1175
+ }}
1176
+ >
1177
+ <div class="toolbar-button-content flex h-full w-full items-center justify-center gap-0.5 px-1">
1178
+ {#if currentTextStyle === 'text'}
1179
+ <IconPilcrow class="h-3.5 w-3.5 shrink-0" />
1180
+ {:else}
1181
+ <span class="text-xs">{textOptions.find(opt => opt.value === currentTextStyle)?.label || 'Text'}</span>
1182
+ {/if}
1183
+ <ChevronDown class="h-3 w-3 shrink-0" />
1184
+ </div>
1185
+ </Button>
1186
+ </Popover.Trigger>
1187
+
1188
+ <Popover.Content
1189
+ class="w-[200px] p-0"
1190
+ >
1191
+ <Command.Root>
1192
+ <Command.List>
1193
+ {#each textOptions as option}
1194
+ <Command.Item
1195
+ value={option.value}
1196
+ onclick={(e: any) => {
1197
+ e.stopPropagation();
1198
+ e.preventDefault();
1199
+ handleCommandSelect(option.value);
1200
+ }}
1201
+ class="flex items-center justify-between px-2 py-1.5 text-sm hover:bg-muted cursor-pointer"
1202
+ >
1203
+ {#if option.icon}
1204
+ <div class="flex items-center gap-2">
1205
+ {#if option.icon}
1206
+ <option.icon class="h-4 w-4" />
1207
+ {/if}
1208
+ <span>{option.label}</span>
1209
+ </div>
1210
+ {:else}
1211
+ <span>{option.label}</span>
1212
+ {/if}
1213
+ {#if option.value === currentTextStyle}
1214
+ <div class="h-4 w-4">✓</div>
1215
+ {/if}
1216
+ </Command.Item>
1217
+ {/each}
1218
+ </Command.List>
1219
+ </Command.Root>
1220
+ </Popover.Content>
1221
+ </Popover.Root>
1222
+ </div>
1223
+
1224
+ <!-- List Style Dropdown -->
1225
+ <div class="toolbar-list-style-ct inline-flex items-center shrink-0">
1226
+ <Popover.Root
1227
+ bind:open={listStyleDropdownOpen}
1228
+ onOpenChange={(e: any) => {
1229
+ handlePopoverOpenChange(e);
1230
+ listStyleDropdownOpen = e;
1231
+ }}
1232
+ >
1233
+ <Popover.Trigger>
1234
+ <Button
1235
+ variant="outline"
1236
+ size="icon"
1237
+ id="list-style-trigger"
1238
+ class="toolbar-button toolbar-dropdown-trigger !h-8 !w-11 !min-w-11 !max-w-11 !p-0 justify-center"
1239
+ onclick={(e) => {
1240
+ e.stopPropagation();
1241
+ e.preventDefault();
1242
+ const buttonElement = e.currentTarget as HTMLButtonElement;
1243
+ buttonElement.blur();
1244
+ listStyleDropdownOpen = !listStyleDropdownOpen;
1245
+ }}
1246
+ >
1247
+ <div class="toolbar-button-content flex h-full w-full items-center justify-center gap-0.5 px-1">
1248
+ {#if currentTextStyle && currentTextStyle.includes('List')}
1249
+ {@const activeListOption = listOptions.find(opt => opt.value === currentTextStyle)}
1250
+ {#if activeListOption?.icon}
1251
+ <activeListOption.icon class="h-3.5 w-3.5 shrink-0" />
1252
+ {/if}
1253
+ {:else}
1254
+ <IconList class="h-3.5 w-3.5 shrink-0" />
1255
+ {/if}
1256
+ <ChevronDown class="h-3 w-3 shrink-0" />
1257
+ </div>
1258
+ </Button>
1259
+ </Popover.Trigger>
1260
+
1261
+ <Popover.Content
1262
+ class="style-dropdown-container w-[300px] p-0"
1263
+ >
1264
+ <Command.Root>
1265
+ <Command.List>
1266
+ {#each listOptions as option}
1267
+ <Command.Item
1268
+ value={option.value}
1269
+ onclick={(e: any) => {
1270
+ e.stopPropagation();
1271
+ e.preventDefault();
1272
+ handleCommandSelect(option.value);
1273
+ }}
1274
+ class="flex items-center justify-between px-2 py-1.5 text-sm hover:bg-muted cursor-pointer"
1275
+ >
1276
+ <div class="flex items-center gap-2">
1277
+ {#if option.icon}
1278
+ <option.icon class="h-4 w-4" />
1279
+ {/if}
1280
+ <span>{option.label}</span>
1281
+ </div>
1282
+ {#if option.value === currentTextStyle}
1283
+ <div class="h-4 w-4">✓</div>
1284
+ {/if}
1285
+ </Command.Item>
1286
+ {/each}
1287
+ </Command.List>
1288
+ </Command.Root>
1289
+ </Popover.Content>
1290
+ </Popover.Root>
1291
+ </div>
1292
+ </div>
1293
+
1294
+ {#if onClose && !showColorPicker && !isColorPickerAnimating}
1295
+ <Button
1296
+ variant="ghost"
1297
+ class="toolbar-close-button ml-auto shrink-0 p-0 hover:bg-transparent h-8 w-8 mr-2 z-10"
1298
+ onclick={(e) => {
1299
+ e.stopPropagation();
1300
+ e.preventDefault();
1301
+ onClose();
1302
+ }}
1303
+ >
1304
+ <X class="h-6 w-6 text-grey5 hover:text-grey7" />
1305
+ </Button>
1306
+ {/if}
1307
+
1308
+ {#if showColorPicker || isColorPickerAnimating}
1309
+ <div class={`color-picker-parent flex items-center gap-2 absolute inset-0 z-20 bg-grey1 px-3 transition-transform duration-200 ease-out ${
1310
+ isColorPickerAnimating ? 'translate-y-0' :
1311
+ showColorPicker ? 'translate-y-0' :
1312
+ 'translate-y-[200%]'
1313
+ }`}>
1314
+ <Button
1315
+ variant="outline"
1316
+ size="icon"
1317
+ class="color-picker-close-button toolbar-button !h-8 !w-8 !p-0 shrink-0"
1318
+ onclick={(e) => {
1319
+ e.stopPropagation();
1320
+ e.preventDefault();
1321
+ const button = e.currentTarget as HTMLButtonElement;
1322
+ button.blur();
1323
+ handleColorPickerClose();
1324
+ }}
1325
+ >
1326
+ <div class="toolbar-button-content flex h-full w-full items-center justify-center">
1327
+ <X class="h-4 w-4" />
1328
+ </div>
1329
+ </Button>
1330
+
1331
+ <div class="color-picker-toolbar-slot relative w-[185px] shrink-0 overflow-visible">
1332
+ <ColorPickerInputController
1333
+ bind:value={currentColor}
1334
+ onChange={(color) => {
1335
+ currentColor = color;
1336
+ handleColorChange(color);
1337
+ }}
1338
+ controllerId="text-color-picker"
1339
+ {openDropdowns}
1340
+ {toggleDropdown}
1341
+ saveRecentColors={true}
1342
+ showOpacityControls={false}
1343
+ showRing={false}
1344
+ portalTarget="text-area-portal"
1345
+ on:mousedown={handleColorPickerInteraction}
1346
+ on:mousemove={handleColorPickerInteraction}
1347
+ on:focus={() => {
1348
+ if (editorInstance && selectedRange) {
1349
+ editorInstance.chain()
1350
+ .setTextSelection(selectedRange)
1351
+ .setMark('highlight', { color: 'var(--text-background-color)' })
1352
+ .run();
1353
+ editorInstance.view.dom.classList.add('hide-selection');
1354
+ }
1355
+ }}
1356
+ on:blur={() => {
1357
+ if (editorInstance) {
1358
+ editorInstance.chain().unsetMark('highlight').run();
1359
+ }
1360
+ }}
1361
+ />
1362
+ </div>
1363
+ </div>
1364
+ {/if}
1365
+ </div>
1366
+ </div>
1367
+
1368
+ <!-- Scrollable content area -->
1369
+ <div class="editor-content-area min-h-0 flex-1 overflow-y-auto overflow-x-hidden">
1370
+ <ShadEditor
1371
+ bind:content={value}
1372
+ showToolbar={false}
1373
+ class="shad-editor subtext {editorClass} {showColorPicker || textStyleDropdownOpen ? 'color-picking-active' : ''} {editorHasFocus ? 'editor-focused' : ''} {isSelectionActive ? 'selection-active' : ''}"
1374
+ on:mount={handleEditorMount}
1375
+ on:update={handleEditorUpdate}
1376
+ />
1377
+ </div>
1378
+ </div>
1379
+
1380
+ {#if description}
1381
+ <p class="text-sm text-muted-foreground mt-2">{description}</p>
1382
+ {/if}
1383
+ </div>
1384
+
1385
+ <style>
1386
+
1387
+ /* Update editor styles */
1388
+ :global(.text-area-input-controller .ProseMirror) {
1389
+ outline: none !important;
1390
+ width: 100%;
1391
+ min-height: 100%;
1392
+ height: auto;
1393
+ padding: var(--editor-padding-top, 0.35rem) var(--editor-padding-right, 0.35rem)
1394
+ var(--editor-padding-bottom, 0.35rem) var(--editor-padding-left, 0.35rem);
1395
+ background: transparent !important;
1396
+ border: none !important;
1397
+ border-radius: inherit;
1398
+ overflow: visible;
1399
+ margin-top: 0;
1400
+ scrollbar-width: thin;
1401
+ scrollbar-color: transparent transparent;
1402
+ }
1403
+
1404
+ :global(.ProseMirror p) {
1405
+ margin: 0;
1406
+ }
1407
+
1408
+ /* Remove height management styles */
1409
+ :global(.editor-height) {
1410
+ border: none;
1411
+ overflow: auto;
1412
+ }
1413
+
1414
+ /* Keep scrollbar styles */
1415
+ :global(.ProseMirror::-webkit-scrollbar) {
1416
+ width: 6px;
1417
+ margin-right: 2px;
1418
+ }
1419
+
1420
+ :global(.ProseMirror::-webkit-scrollbar-track) {
1421
+ background-color: transparent;
1422
+ margin-right: 2px;
1423
+ }
1424
+
1425
+ :global(.ProseMirror::-webkit-scrollbar-thumb) {
1426
+ background-color: hsl(var(--border)) !important;
1427
+ border-radius: 3px;
1428
+ margin-right: 2px;
1429
+ }
1430
+
1431
+ :global(.ProseMirror::-webkit-scrollbar-thumb:hover) {
1432
+ background-color: hsl(var(--muted-foreground) / 0.6) !important;
1433
+ }
1434
+
1435
+ /* Keep typography styles */
1436
+ :global(.ProseMirror p),
1437
+ :global(.ProseMirror h1),
1438
+ :global(.ProseMirror h2),
1439
+ :global(.ProseMirror h3),
1440
+ :global(.ProseMirror li p),
1441
+ :global(.ProseMirror [data-type="taskItem"] p) {
1442
+ margin: 0;
1443
+ line-height: 1.4;
1444
+ }
1445
+
1446
+ /* Heading specific styles */
1447
+ :global(.ProseMirror h1) { font-size: 2em; font-weight: 700; }
1448
+ :global(.ProseMirror h2) { font-size: 1.5em; font-weight: 700; }
1449
+ :global(.ProseMirror h3) { font-size: 1.17em; font-weight: 700; }
1450
+
1451
+ /* List styles - Consolidated */
1452
+ :global(.ProseMirror ul),
1453
+ :global(.ProseMirror ol),
1454
+ :global(.ProseMirror [data-type="taskList"]) {
1455
+ padding-left: 1.5rem;
1456
+ margin: 0;
1457
+ line-height: 1.4;
1458
+ }
1459
+
1460
+ :global(.ProseMirror li),
1461
+ :global(.ProseMirror [data-type="taskItem"]) {
1462
+ position: relative;
1463
+ padding-left: 0.5rem;
1464
+ margin: 0;
1465
+ }
1466
+
1467
+ /* Task list specific styles */
1468
+ :global(.ProseMirror [data-type="taskList"]) {
1469
+ list-style: none;
1470
+ padding-left: 0rem !important;
1471
+ }
1472
+
1473
+ :global(.ProseMirror [data-type="taskItem"]) {
1474
+ display: flex;
1475
+ align-items: flex-start;
1476
+ padding-left: 0 !important;
1477
+ margin-left: 0 !important;
1478
+ gap: 0.5rem;
1479
+ }
1480
+
1481
+ :global(.ProseMirror [data-type="taskItem"] label) {
1482
+ display: flex;
1483
+ align-items: center;
1484
+ margin: 0;
1485
+ padding: 0;
1486
+ }
1487
+
1488
+ :global(.ProseMirror [data-type="taskItem"] input[type="checkbox"]) {
1489
+ margin: 0;
1490
+ margin-top: 0.4em;
1491
+ }
1492
+
1493
+ /* Focus states - Consolidated */
1494
+ :global(.ProseMirror),
1495
+ :global(.ProseMirror:hover),
1496
+ :global(.ProseMirror:focus),
1497
+ :global(.ProseMirror:focus-visible),
1498
+ :global(.ProseMirror:focus-within),
1499
+ :global(.ProseMirror *),
1500
+ :global(.ProseMirror * *),
1501
+ :global(.ProseMirror-focused) {
1502
+ border-color: transparent !important;
1503
+ outline: none !important;
1504
+ box-shadow: none !important;
1505
+ }
1506
+
1507
+ /* Container focus styles */
1508
+ :global(.group:focus-within) {
1509
+ outline: none !important;
1510
+ }
1511
+
1512
+ /* Toolbar styles - Consolidated */
1513
+ :global(.toolbar-container button:focus),
1514
+ :global(.toolbar-container button:focus-visible),
1515
+ :global(.toolbar-container a:focus),
1516
+ :global(.toolbar-container a:focus-visible) {
1517
+ outline: none;
1518
+ box-shadow: none;
1519
+ }
1520
+
1521
+ :global(.toolbar-button) {
1522
+ position: relative !important;
1523
+ border: 1px solid hsl(var(--border)) !important;
1524
+ transition: border-color 0.2s ease-in-out, background-color 0.2s ease-in-out !important;
1525
+ }
1526
+
1527
+ :global(.toolbar-button:hover) {
1528
+ border-color: hsl(var(--grey3)) !important;
1529
+ background-color: hsl(var(--grey1)) !important;
1530
+ }
1531
+
1532
+ :global(.toolbar-button svg) {
1533
+ transition: color 0.2s ease-in-out !important;
1534
+ }
1535
+
1536
+ :global(.toolbar-button:hover svg) {
1537
+ color: hsl(var(--grey7)) !important;
1538
+ }
1539
+
1540
+ :global(.toolbar-button-content) {
1541
+ position: relative !important;
1542
+ z-index: 2 !important;
1543
+ }
1544
+
1545
+ :global(.toolbar-text-style-ct),
1546
+ :global(.toolbar-list-style-ct) {
1547
+ width: 44px;
1548
+ min-width: 44px;
1549
+ max-width: 44px;
1550
+ flex-shrink: 0;
1551
+ }
1552
+
1553
+ :global(.text-formatting-toggle-group button),
1554
+ :global(.color-picker-preview-button) {
1555
+ width: 2rem !important;
1556
+ min-width: 2rem !important;
1557
+ max-width: 2rem !important;
1558
+ height: 2rem !important;
1559
+ padding: 0 !important;
1560
+ }
1561
+
1562
+ :global(.toolbar-text-style-ct button),
1563
+ :global(.toolbar-list-style-ct button),
1564
+ :global(.toolbar-dropdown-trigger) {
1565
+ width: 44px !important;
1566
+ min-width: 44px !important;
1567
+ max-width: 44px !important;
1568
+ height: 2rem !important;
1569
+ padding: 0 !important;
1570
+ }
1571
+
1572
+ :global(.text-area-input-controller .editor-content-area) {
1573
+ scrollbar-width: thin;
1574
+ scrollbar-color: hsl(var(--grey3) / 0.5) transparent;
1575
+ }
1576
+
1577
+ :global(.text-area-input-controller .editor-content-area::-webkit-scrollbar) {
1578
+ width: 6px;
1579
+ }
1580
+
1581
+ :global(.text-area-input-controller .editor-content-area::-webkit-scrollbar-thumb) {
1582
+ background: hsl(var(--grey3) / 0.45);
1583
+ border-radius: 999px;
1584
+ }
1585
+
1586
+ /* Input styles */
1587
+ :global(input.h-8),
1588
+ :global(.input-container) {
1589
+ height: 2rem !important;
1590
+ min-height: 2rem !important;
1591
+ line-height: 2rem !important;
1592
+ padding-top: 0 !important;
1593
+ padding-bottom: 0 !important;
1594
+ font-size: 0.875rem !important;
1595
+ }
1596
+
1597
+ /* Color picker styles */
1598
+ :global(.color-picker-container) {
1599
+ display: flex !important;
1600
+ align-items: center !important;
1601
+ gap: 8px !important;
1602
+ }
1603
+
1604
+ :global(.color-picker-container input[type="text"]) {
1605
+ width: 162px !important;
1606
+ min-width: 162px !important;
1607
+ }
1608
+
1609
+ :global(.color-picker-container:focus-within) {
1610
+ z-index: 10;
1611
+ }
1612
+
1613
+ :global(.color-picker-container input[type="text"]),
1614
+ :global(.color-picker-container input[type="text"]:focus),
1615
+ :global(.color-picker-container input[type="text"]:focus-visible),
1616
+ :global(.color-picker-container input[type="text"]:focus-within),
1617
+ :global(.color-picker-container input[type="text"]:hover) {
1618
+ outline: none !important;
1619
+ border: 1px solid hsl(var(--border)) !important;
1620
+ box-shadow: none !important;
1621
+ --tw-ring-offset-width: 0 !important;
1622
+ --tw-ring-offset-color: transparent !important;
1623
+ --tw-ring-color: transparent !important;
1624
+ --tw-ring-offset-shadow: none !important;
1625
+ --tw-ring-shadow: none !important;
1626
+ }
1627
+
1628
+ /* Add these styles to ensure proper positioning */
1629
+ :global(.fixed) {
1630
+ position: fixed;
1631
+ }
1632
+
1633
+ :global(.z-50) {
1634
+ z-index: 50;
1635
+ }
1636
+
1637
+ /* Update existing styles to handle portaled content */
1638
+ :global([cmdk-root]) {
1639
+ position: relative;
1640
+ background: white;
1641
+ border-radius: 0.375rem;
1642
+ overflow: hidden;
1643
+ }
1644
+
1645
+ :global([cmdk-list]) {
1646
+ max-height: 300px;
1647
+ overflow-y: auto;
1648
+ }
1649
+
1650
+ :global([cmdk-item]) {
1651
+ cursor: pointer;
1652
+ padding: 0.5rem 1rem;
1653
+ }
1654
+
1655
+ :global([cmdk-item]:hover) {
1656
+ background-color: hsl(var(--muted));
1657
+ }
1658
+
1659
+ /* Add these styles to handle the portaled color suggestions */
1660
+ :global(.color-suggestions-portal) {
1661
+ position: fixed;
1662
+ z-index: 100;
1663
+ background: white;
1664
+ border-radius: 0.375rem;
1665
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
1666
+ border: 1px solid hsl(var(--border));
1667
+ }
1668
+
1669
+ /* Selection Styles */
1670
+ :global(.ProseMirror mark[data-color="#adcff5"]) {
1671
+ background-color: #b4d5fe !important;
1672
+ color: inherit !important;
1673
+ border-radius: 2px !important;
1674
+ padding: 2px 0 !important;
1675
+ margin: -2px 0 !important;
1676
+ }
1677
+
1678
+ /* Selection Styles */
1679
+ :global(.ProseMirror) {
1680
+ --selection-color: #b4d5fe;
1681
+ --text-background-color: #b4d5fe;
1682
+ }
1683
+
1684
+ /* Default selection style */
1685
+ :global(.ProseMirror ::selection) {
1686
+ background-color: var(--selection-color) !important;
1687
+ color: inherit !important;
1688
+ }
1689
+
1690
+ /* Selection style during color picker */
1691
+ :global(.ProseMirror.color-picking-active ::selection) {
1692
+ background-color: var(--selection-color) !important;
1693
+ color: inherit !important;
1694
+ }
1695
+
1696
+ /* Hide selection when text background is active */
1697
+ :global(.ProseMirror.hide-selection ::selection) {
1698
+ background-color: transparent !important;
1699
+ }
1700
+
1701
+ /* Text background highlight */
1702
+ :global(.ProseMirror mark[data-highlight]) {
1703
+ background-color: var(--text-background-color) !important;
1704
+ color: inherit !important;
1705
+ }
1706
+
1707
+ :global(.text-area) {
1708
+ height: 100% !important;
1709
+ width: 100% !important;
1710
+ border-radius: var(--radius-small) !important;
1711
+ overflow: hidden !important;
1712
+ background-color: hsl(var(--grey1)) !important;
1713
+ border: 1px solid hsl(var(--grey2));
1714
+ transition: border-color 0.2s ease !important;
1715
+ }
1716
+
1717
+ :global(.text-area .ProseMirror) {
1718
+ margin-top: 0 !important;
1719
+ padding: 8px 16px 24px 16px !important;
1720
+ background-color: transparent !important;
1721
+ cursor: text !important;
1722
+ border: none !important;
1723
+ }
1724
+
1725
+ /* Add portal border radius */
1726
+ :global(.portal-contents) {
1727
+ border-radius: var(--radius-small) !important;
1728
+ overflow: hidden !important;
1729
+ }
1730
+
1731
+ :global(.text-area .toolbar-container) {
1732
+ padding: 10px 0 !important;
1733
+ display: flex !important;
1734
+ gap: 0 !important;
1735
+ border-bottom: 1px solid hsl(var(--grey2)) !important;
1736
+ background-color: hsl(var(--grey1)) !important;
1737
+ }
1738
+
1739
+ :global(.text-area .toolbar-container button) {
1740
+ width: 32px !important;
1741
+ height: 32px !important;
1742
+ min-width: 32px !important;
1743
+ max-width: 32px !important;
1744
+ padding: 0 !important;
1745
+ background-color: white !important;
1746
+ border: 1px solid hsl(var(--grey2)) !important;
1747
+ border-radius: var(--radius) !important;
1748
+ display: flex !important;
1749
+ align-items: center !important;
1750
+ justify-content: center !important;
1751
+ transition: all 0.2s !important;
1752
+ }
1753
+
1754
+ :global(.text-area .toolbar-container button.toolbar-dropdown-trigger),
1755
+ :global(.text-area .toolbar-container #text-style-trigger),
1756
+ :global(.text-area .toolbar-container #list-style-trigger) {
1757
+ width: 44px !important;
1758
+ min-width: 44px !important;
1759
+ max-width: 44px !important;
1760
+ padding: 0 !important;
1761
+ }
1762
+
1763
+ :global(.text-area .toolbar-container .toolbar-items-container) {
1764
+ display: flex !important;
1765
+ align-items: center !important;
1766
+ justify-content: center !important;
1767
+ gap: 8px !important;
1768
+ height: 100% !important;
1769
+ position: absolute !important;
1770
+ inset: 0 2.5rem 0 0 !important;
1771
+ }
1772
+
1773
+ :global(.text-area #text-style-trigger) {
1774
+ margin-right: 0 !important;
1775
+ }
1776
+
1777
+ /* Color the brush icon based on selected color */
1778
+ :global(.text-area .color-picker-preview-button svg) {
1779
+ color: var(--selected-color, currentColor) !important;
1780
+ }
1781
+
1782
+ :global(.text-area .color-picker-preview-button:hover svg) {
1783
+ color: var(--selected-color, hsl(var(--grey7))) !important;
1784
+ }
1785
+ /* Button spacing */
1786
+ :global(.text-area .color-picker-preview-button) {
1787
+ margin-left: 0 !important;
1788
+ margin-right: 0 !important;
1789
+ }
1790
+
1791
+ :global(.text-area .text-formatting-toggle-group) {
1792
+ margin-right: 0 !important;
1793
+ display: flex !important;
1794
+ gap: 8px !important;
1795
+ }
1796
+
1797
+ :global(.text-area .text-formatting-toggle-group button) {
1798
+ margin: 0 !important;
1799
+ }
1800
+
1801
+ :global(.text-area .text-formatting-toggle-group button:not(:last-child)) {
1802
+ margin-right: 0 !important;
1803
+ }
1804
+
1805
+ :global(.text-area #text-style-trigger),
1806
+ :global(.text-area #list-style-trigger) {
1807
+ width: 44px !important;
1808
+ min-width: 44px !important;
1809
+ max-width: 44px !important;
1810
+ }
1811
+
1812
+ :global(.text-area .toolbar-container button:hover) {
1813
+ border-color: hsl(var(--grey2)) !important;
1814
+ }
1815
+
1816
+ :global(.text-area .toolbar-container button:active) {
1817
+ transform: scale(0.95) !important;
1818
+ }
1819
+
1820
+ :global(.text-area .toolbar-container button svg) {
1821
+ width: 20px !important;
1822
+ height: 20px !important;
1823
+ color: hsl(var(--grey5)) !important;
1824
+ transition: color 0.2s !important;
1825
+ }
1826
+
1827
+ :global(.text-area .toolbar-container button:hover svg) {
1828
+ color: hsl(var(--grey7)) !important;
1829
+ }
1830
+
1831
+ :global(.text-area .toolbar-container button[data-state="on"]) {
1832
+ background-color: hsl(var(--sage-green)) !important;
1833
+ border-color: hsl(var(--sage-green)) !important;
1834
+ color: white !important;
1835
+ }
1836
+
1837
+ :global(.text-area .toolbar-container button[data-state="on"] svg),
1838
+ :global(.text-area .toolbar-container button[data-state="on"] svg *) {
1839
+ color: white !important;
1840
+ stroke: white !important;
1841
+ }
1842
+
1843
+ :global(.text-area .toolbar-text-style-ct),
1844
+ :global(.text-area .toolbar-list-style-ct) {
1845
+ margin-left: 0 !important;
1846
+ }
1847
+
1848
+ /* Update the color picker button to show selected color */
1849
+ :global(.text-area .color-picker-preview-button) {
1850
+ position: relative !important;
1851
+ }
1852
+
1853
+ :global(.text-area .color-picker-preview-button::after) {
1854
+ display: none !important;
1855
+ }
1856
+
1857
+ /* Update icon color based on selection */
1858
+ :global(.text-area .color-picker-preview-button .toolbar-button-content svg) {
1859
+ transition: color 0.2s ease !important;
1860
+ }
1861
+
1862
+ :global(.text-area .color-picker-preview-button:hover .toolbar-button-content svg) {
1863
+ color: currentColor !important;
1864
+ }
1865
+
1866
+ /* Remove hit zone since we want clicks everywhere */
1867
+ .input-hit-zone {
1868
+ display: none;
1869
+ }
1870
+
1871
+ /* Make the main container clickable */
1872
+ .main-editor-container {
1873
+ cursor: text;
1874
+ }
1875
+
1876
+ :global(.text-area .toolbar-button.h-8:not(.toolbar-dropdown-trigger):not(#text-style-trigger):not(#list-style-trigger)) {
1877
+ width: 32px !important;
1878
+ }
1879
+
1880
+ :global(.text-area .toolbar-text-style-ct),
1881
+ :global(.text-area .toolbar-list-style-ct) {
1882
+ display: inline-flex !important;
1883
+ width: 44px !important;
1884
+ min-width: 44px !important;
1885
+ max-width: 44px !important;
1886
+ margin-left: 0 !important;
1887
+ padding-left: 0 !important;
1888
+ }
1889
+
1890
+ /* Update color picker container styles */
1891
+ :global(.color-picker-parent) {
1892
+ position: absolute;
1893
+ inset: 0;
1894
+ padding: 0 12px;
1895
+ display: flex;
1896
+ align-items: center;
1897
+ justify-content: flex-start;
1898
+ gap: 8px;
1899
+ }
1900
+
1901
+ /* ColorPicker uses absolute right-0 for the Design column; in the toolbar that
1902
+ pins the 185px input to the far right and the popover flush to the edge. */
1903
+ :global(.color-picker-toolbar-slot .input-controller-ct) {
1904
+ position: relative !important;
1905
+ right: auto !important;
1906
+ left: auto !important;
1907
+ }
1908
+
1909
+ :global(.color-picker-toolbar-slot .input-controller-header-ct) {
1910
+ display: none !important;
1911
+ }
1912
+
1913
+ :global(.color-picker-toolbar-slot .color-picker-input-controller-ct > .flex) {
1914
+ display: block !important;
1915
+ }
1916
+
1917
+ :global(.color-picker-parent input[type="text"]) {
1918
+ width: 162px !important;
1919
+ min-width: 162px !important;
1920
+ height: 36px !important;
1921
+ min-height: 36px !important;
1922
+ }
1923
+
1924
+ :global(.color-picker-close-button) {
1925
+ width: 36px !important;
1926
+ height: 36px !important;
1927
+ min-width: 36px !important;
1928
+ min-height: 36px !important;
1929
+ }
1930
+ </style>
1931
+
1932
+