@widgetic/editor 3.11.3 → 4.0.1

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 +3952 -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 +724 -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 +2062 -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 +1804 -0
  90. package/dist/components/ic/TextAreaInputController.svelte.d.ts +13 -0
  91. package/dist/components/ic/TextAreaPreviewInputController.svelte +476 -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 +5 -0
  131. package/dist/config.js +19 -0
  132. package/dist/index.d.ts +4 -0
  133. package/dist/index.js +8 -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 +276 -0
  137. package/dist/utils/FontManager.js +1283 -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,852 @@
1
+ <script lang="ts">
2
+ import { onMount, onDestroy, createEventDispatcher, tick } from 'svelte';
3
+ import { GenerateLoader } from '@widgetic/design-system/components';
4
+
5
+ const dispatch = createEventDispatcher<{
6
+ load: { src: string | null };
7
+ error: { src: string | null };
8
+ refresh: void;
9
+ openInTab: void;
10
+ resize: { width: number; height: number };
11
+ mobileViewport: { width: number; height: number };
12
+ desktopViewport: void;
13
+ iframeLoad: Event;
14
+ iframeError: Event;
15
+ retry: void;
16
+ fixErrors: void;
17
+ viewErrors: void;
18
+ retryPreview: void;
19
+ }>();
20
+
21
+ /** standalone = resolve URL + postMessage internally; controlled = parent supplies src/state */
22
+ export let mode: 'standalone' | 'controlled' = 'standalone';
23
+
24
+ let className = '';
25
+ export { className as class };
26
+ export let style: string = '';
27
+
28
+ // ── Standalone props (props-editor) ─────────────────────────────────────
29
+ export let widget: any = null;
30
+ export let apiBaseUrl: string = '';
31
+ export let widgetBuilderUrl: string = '';
32
+ export let designValues: any = {};
33
+ export let contentValues: any = {};
34
+
35
+ // ── Controlled props (widget-creator) ───────────────────────────────────
36
+ export let src: string | null = null;
37
+ export let displayUrl: string | null = null;
38
+ export let previewLoading: boolean = false;
39
+ export let previewHydrating: boolean = false;
40
+ export let previewError: string | null = null;
41
+ export let previewRetryCount: number = 0;
42
+ export let previewHasRuntimeError: boolean = false;
43
+ export let previewRuntimeErrorStatus: number | null = null;
44
+ export let isContentReady: boolean = false;
45
+ export let isLoadingUrl: boolean = false;
46
+ export let isGeneratingCode: boolean = false;
47
+ export let forceMockReady: boolean = false;
48
+ export let debugMode: boolean = false;
49
+ export let iframeReloadKey = 0;
50
+
51
+ // ── Layout / chrome ─────────────────────────────────────────────────────
52
+ export let width: string = '100%';
53
+ export let height: string = '100%';
54
+ export let contentHeight: string = '100%';
55
+ export let showUrlBar: boolean = false;
56
+ export let showUrlBarButtons: boolean = true;
57
+ /** Mobile + desktop viewport buttons in URL bar (before New tab) */
58
+ export let showViewportButtons: boolean = true;
59
+ export let mobileViewportWidth: number = 390;
60
+ export let mobileViewportHeight: number = 667;
61
+ export let enableResize: boolean = false;
62
+ /** Observe stage size and fill it (desktop modal) */
63
+ export let autoFitStage: boolean = false;
64
+ /** No padding/border on preview-content-container — matches widget-creator Edit panel */
65
+ export let compactChrome: boolean = false;
66
+ /** Fixed preview stage size; inner iframe resizes within these bounds */
67
+ export let boundsWidth: number | null = null;
68
+ export let boundsHeight: number | null = null;
69
+ export let resizeWidth: number | null = null;
70
+ export let resizeHeight: number | null = null;
71
+
72
+ export let iframeEl: HTMLIFrameElement | null = null;
73
+
74
+ // ── Standalone internal state ───────────────────────────────────────────
75
+ let internalIframeSrc: string | null = null;
76
+ let iframeLoaded = false;
77
+ let iframeError = false;
78
+ let errorMessage = '';
79
+ let isWidgetPublished = false;
80
+ let triedFallback = false;
81
+ let pendingWidget: any = null;
82
+ let activeWidgetKey: string | null = null;
83
+ let pendingMessages: Record<string, unknown>[] = [];
84
+ let widgetReady = false;
85
+ let isResolvingUrl = false;
86
+
87
+ const MIN_WIDTH = 120;
88
+ const MIN_HEIGHT = 80;
89
+ const HANDLE_MARGIN = 6;
90
+ /** Inset padding so resize handles (-4px) and dimension badge stay inside bounds */
91
+ const RESIZE_PAD_X = 8;
92
+ const RESIZE_PAD_TOP = 8;
93
+ const RESIZE_PAD_BOTTOM = 22;
94
+ let isResizing = false;
95
+ let contentContainerEl: HTMLElement | null = null;
96
+ let resizeStageEl: HTMLElement | null = null;
97
+ let stageResizeObserver: ResizeObserver | null = null;
98
+
99
+ export function getResizeLimits(): { maxWidth: number; maxHeight: number } {
100
+ const stageEl = resizeStageEl ?? contentContainerEl;
101
+ if (stageEl) {
102
+ return {
103
+ maxWidth: Math.max(MIN_WIDTH, stageEl.clientWidth),
104
+ maxHeight: Math.max(MIN_HEIGHT, stageEl.clientHeight),
105
+ };
106
+ }
107
+ if (hasFixedBounds && boundsWidth != null && boundsHeight != null) {
108
+ return {
109
+ maxWidth: Math.max(MIN_WIDTH, boundsWidth - RESIZE_PAD_X * 2),
110
+ maxHeight: Math.max(MIN_HEIGHT, boundsHeight - RESIZE_PAD_TOP - RESIZE_PAD_BOTTOM),
111
+ };
112
+ }
113
+ return { maxWidth: 720, maxHeight: 420 };
114
+ }
115
+
116
+ /** Firefox/Chrome skip painting a cross-origin iframe that started at opacity 0 or inside a CSS filter until a reflow (opening DevTools). */
117
+ let iframePaintNudgeGeneration = 0;
118
+ export function nudgeIframePaint(): void {
119
+ const el = iframeEl;
120
+ if (!el) return;
121
+ const generation = ++iframePaintNudgeGeneration;
122
+ // Force a 1px layout twitch, then ALWAYS clear inline size so w-full/h-full can track the wrapper.
123
+ // Restoring a previous pixel width (from overlapping nudges) permanently capped the iframe
124
+ // smaller than the resize stage — widgets looked letterboxed / "not responsive".
125
+ const twitchWidth = Math.max(1, el.offsetWidth + 1);
126
+ el.style.width = `${twitchWidth}px`;
127
+ void el.offsetHeight;
128
+ requestAnimationFrame(() => {
129
+ if (generation !== iframePaintNudgeGeneration) return;
130
+ el.style.width = '';
131
+ el.style.height = '';
132
+ });
133
+ }
134
+
135
+ /** Drop any stuck inline iframe size whenever the stage pixel size changes. */
136
+ $: if (iframeEl && (resizeWidth != null || resizeHeight != null)) {
137
+ iframeEl.style.width = '';
138
+ iframeEl.style.height = '';
139
+ }
140
+
141
+ /** Fill the available preview stage (e.g. desktop modal) */
142
+ export function fitToContainer(): void {
143
+ const attemptFit = (attemptsLeft: number) => {
144
+ const stageEl = resizeStageEl ?? contentContainerEl;
145
+ const limits = getResizeLimits();
146
+ const stageReady =
147
+ !!stageEl && stageEl.clientWidth > MIN_WIDTH && stageEl.clientHeight > MIN_HEIGHT;
148
+ if (!stageReady && attemptsLeft > 0) {
149
+ requestAnimationFrame(() => attemptFit(attemptsLeft - 1));
150
+ return;
151
+ }
152
+ resizeWidth = limits.maxWidth;
153
+ resizeHeight = limits.maxHeight;
154
+ dispatch('resize', { width: limits.maxWidth, height: limits.maxHeight });
155
+ requestAnimationFrame(() => nudgeIframePaint());
156
+ };
157
+ attemptFit(24);
158
+ }
159
+
160
+ $: effectiveSrc = mode === 'controlled' ? src : internalIframeSrc;
161
+ $: effectiveDisplayUrl =
162
+ mode === 'controlled' ? displayUrl || src : internalIframeSrc;
163
+ $: mountedPreviewSrc =
164
+ effectiveSrc && effectiveSrc !== 'about:blank' ? effectiveSrc : null;
165
+ $: showStandaloneLoading =
166
+ mode === 'standalone' &&
167
+ (isResolvingUrl || !!effectiveSrc) &&
168
+ !iframeLoaded &&
169
+ !iframeError;
170
+ $: showControlledLoading =
171
+ mode === 'controlled' &&
172
+ (previewLoading || previewHydrating) &&
173
+ !previewHasRuntimeError;
174
+ $: showResizeHandles = enableResize && (mode === 'controlled' ? isContentReady : iframeLoaded);
175
+ $: hasFixedBounds = boundsWidth != null && boundsHeight != null;
176
+ $: containerPaddingStyle = enableResize
177
+ ? `padding: ${RESIZE_PAD_TOP}px ${RESIZE_PAD_X}px ${RESIZE_PAD_BOTTOM}px ${RESIZE_PAD_X}px;`
178
+ : !hasFixedBounds && !compactChrome && (showUrlBar || mode === 'controlled')
179
+ ? `padding: ${HANDLE_MARGIN}px;`
180
+ : '';
181
+ // Always clip — a too-wide iframe must not paint outside the stage when the Creator
182
+ // column shrinks (that looked like the widget being "cut off" on resize).
183
+ $: containerOverflowClass = 'overflow-hidden';
184
+ // Keep pixel preview size inside the stage whenever the parent layout changes.
185
+ $: if (enableResize && (resizeWidth != null || resizeHeight != null)) {
186
+ const { maxWidth, maxHeight } = getResizeLimits();
187
+ if (resizeWidth != null && resizeWidth > maxWidth) resizeWidth = maxWidth;
188
+ if (resizeHeight != null && resizeHeight > maxHeight) resizeHeight = maxHeight;
189
+ }
190
+ $: boundedContainerStyle = hasFixedBounds
191
+ ? `width: ${boundsWidth}px; height: ${boundsHeight}px; flex: 0 0 auto;`
192
+ : '';
193
+ $: iframeTitle =
194
+ mode === 'controlled'
195
+ ? 'Widget preview'
196
+ : `Widget preview – ${widget?.name || 'Widget'}`;
197
+
198
+ function buildWidgetUrl(w: any): string | null {
199
+ if (!w) return null;
200
+
201
+ const jsPath = w.jsPath || w.js_path;
202
+
203
+ if (jsPath) {
204
+ if (apiBaseUrl) {
205
+ const artifactPath = jsPath.match(/\/widgets\/[^/]+\/v\d+\/.+$/i);
206
+ if (artifactPath) {
207
+ const proxyUrl = `${apiBaseUrl}${artifactPath[0]}`;
208
+ console.log('[WidgetPreview] Using API proxy URL (R2):', proxyUrl);
209
+ return proxyUrl;
210
+ }
211
+ }
212
+ if (jsPath.startsWith('http')) return jsPath;
213
+ return `https://cdn.widgetic.com${jsPath.startsWith('/') ? '' : '/'}${jsPath}`;
214
+ }
215
+
216
+ if (widgetBuilderUrl && w.id) {
217
+ const previewUrl = `${widgetBuilderUrl.replace(/\/+$/, '')}/preview/${w.id}`;
218
+ console.log('[WidgetPreview] Using Worker preview URL (unpublished):', previewUrl);
219
+ return previewUrl;
220
+ }
221
+
222
+ console.log('[WidgetPreview] Widget not published and no Worker URL:', w.name, w.id);
223
+ return null;
224
+ }
225
+
226
+ function tryFallbackUrl(w: any): string | null {
227
+ if (!w?.id || !widgetBuilderUrl) return null;
228
+ return `${widgetBuilderUrl.replace(/\/+$/, '')}/preview/${w.id}`;
229
+ }
230
+
231
+ async function resolveWidgetPreviewUrl(w: any, primaryUrl: string): Promise<string> {
232
+ try {
233
+ const res = await fetch(primaryUrl, { method: 'GET', mode: 'cors' });
234
+ const contentType = res.headers.get('content-type') || '';
235
+ const looksLikeErrorPayload =
236
+ !res.ok || (contentType.includes('application/json') && !contentType.includes('html'));
237
+ if (looksLikeErrorPayload) {
238
+ const fallbackUrl = tryFallbackUrl(w);
239
+ if (fallbackUrl && !triedFallback) {
240
+ triedFallback = true;
241
+ console.log('[WidgetPreview] Primary URL failed, trying Worker fallback:', fallbackUrl);
242
+ return fallbackUrl;
243
+ }
244
+ }
245
+ } catch (err) {
246
+ const fallbackUrl = tryFallbackUrl(w);
247
+ if (fallbackUrl && !triedFallback) {
248
+ triedFallback = true;
249
+ console.log('[WidgetPreview] Primary URL unreachable, trying Worker fallback:', fallbackUrl);
250
+ return fallbackUrl;
251
+ }
252
+ console.warn('[WidgetPreview] URL probe failed:', primaryUrl, err);
253
+ }
254
+ return primaryUrl;
255
+ }
256
+
257
+ function beginWidgetLoad(w: any, url: string | null) {
258
+ pendingWidget = w;
259
+ triedFallback = false;
260
+ iframeLoaded = false;
261
+ iframeError = false;
262
+ widgetReady = false;
263
+ errorMessage = '';
264
+ pendingMessages = [];
265
+
266
+ if (!url) {
267
+ internalIframeSrc = null;
268
+ isResolvingUrl = false;
269
+ return;
270
+ }
271
+
272
+ isResolvingUrl = true;
273
+ console.log('[WidgetPreview] Resolving widget URL:', url);
274
+ void resolveWidgetPreviewUrl(w, url).then(async (resolvedUrl) => {
275
+ if (pendingWidget !== w) return;
276
+ isResolvingUrl = false;
277
+ internalIframeSrc = resolvedUrl;
278
+ await tick();
279
+ requestAnimationFrame(() => {
280
+ ensureIframeLoadDetected();
281
+ });
282
+ });
283
+ }
284
+
285
+ function ensureIframeLoadDetected() {
286
+ if (!iframeEl || (mode === 'standalone' && (iframeLoaded || iframeError))) return;
287
+
288
+ try {
289
+ const doc = iframeEl.contentDocument;
290
+ if (doc?.readyState === 'complete') {
291
+ void handleIframeLoad();
292
+ return;
293
+ }
294
+ } catch {
295
+ // Cross-origin
296
+ }
297
+
298
+ iframeEl.contentWindow?.postMessage({ type: 'widgetic:ping' }, '*');
299
+
300
+ window.setTimeout(() => {
301
+ if (mode === 'standalone' && !iframeLoaded && !iframeError && iframeEl && effectiveSrc) {
302
+ console.log('[WidgetPreview] Fallback: marking iframe loaded after ping timeout');
303
+ void handleIframeLoad();
304
+ }
305
+ }, 400);
306
+ }
307
+
308
+ $: if (mode === 'standalone' && widget) {
309
+ isWidgetPublished = !!(widget.jsPath || widget.js_path);
310
+ const newUrl = buildWidgetUrl(widget);
311
+ const widgetKey = `${widget.id}:${newUrl ?? 'none'}`;
312
+ if (widgetKey !== activeWidgetKey) {
313
+ activeWidgetKey = widgetKey;
314
+ beginWidgetLoad(widget, newUrl);
315
+ }
316
+ } else if (mode === 'standalone' && !widget) {
317
+ activeWidgetKey = null;
318
+ pendingWidget = null;
319
+ internalIframeSrc = null;
320
+ isWidgetPublished = false;
321
+ iframeLoaded = false;
322
+ iframeError = false;
323
+ errorMessage = '';
324
+ widgetReady = false;
325
+ isResolvingUrl = false;
326
+ }
327
+
328
+ $: if (mode === 'controlled' && src) {
329
+ requestAnimationFrame(() => ensureIframeLoadDetected());
330
+ }
331
+
332
+ $: if (mode === 'standalone' && iframeLoaded && iframeEl?.contentWindow) {
333
+ sendPropertiesToWidget(designValues, contentValues);
334
+ }
335
+
336
+ function sendPropertiesToWidget(design: any, content: any) {
337
+ if (!iframeEl?.contentWindow) return;
338
+ try {
339
+ const { items, ...genericContent } = content || {};
340
+
341
+ let contentItems: any[] | undefined;
342
+ if (items && typeof items === 'object') {
343
+ contentItems = Object.entries(items).map(([itemId, props]: [string, any]) => ({
344
+ id: itemId,
345
+ ...props
346
+ }));
347
+ }
348
+
349
+ const message = {
350
+ type: 'widgetic:update',
351
+ design,
352
+ content: genericContent,
353
+ contentItems
354
+ };
355
+ iframeEl.contentWindow.postMessage(message, '*');
356
+ console.log('[WidgetPreview] Sent property update to widget iframe', {
357
+ designKeys: design ? Object.keys(design) : [],
358
+ genericContentKeys: Object.keys(genericContent),
359
+ contentItemsCount: contentItems?.length,
360
+ iframeSrc: effectiveSrc?.substring(0, 80)
361
+ });
362
+ } catch (err) {
363
+ console.warn('[WidgetPreview] Failed to send postMessage:', err);
364
+ }
365
+ }
366
+
367
+ function flushPendingMessages() {
368
+ if (!iframeEl?.contentWindow || pendingMessages.length === 0) return;
369
+ for (const message of pendingMessages) {
370
+ iframeEl.contentWindow.postMessage(message, '*');
371
+ }
372
+ pendingMessages = [];
373
+ }
374
+
375
+ export function sendMessageToPreview(message: Record<string, unknown>): void {
376
+ if (mode === 'controlled') {
377
+ if (iframeEl?.contentWindow) {
378
+ iframeEl.contentWindow.postMessage(message, '*');
379
+ }
380
+ return;
381
+ }
382
+ if (widgetReady && iframeEl?.contentWindow) {
383
+ iframeEl.contentWindow.postMessage(message, '*');
384
+ return;
385
+ }
386
+ pendingMessages.push(message);
387
+ }
388
+
389
+ export function goToItem(index: number) {
390
+ sendMessageToPreview({ type: 'widgetic:goToItem', index });
391
+ }
392
+
393
+ export function refreshValues() {
394
+ sendPropertiesToWidget(designValues, contentValues);
395
+ }
396
+
397
+ async function handleIframeLoad() {
398
+ if (mode === 'controlled') {
399
+ if (src === 'about:blank' || iframeEl?.src?.includes('about:blank')) return;
400
+ dispatch('iframeLoad', new Event('load'));
401
+ requestAnimationFrame(() => nudgeIframePaint());
402
+ return;
403
+ }
404
+
405
+ if (iframeLoaded) return;
406
+ iframeLoaded = true;
407
+ iframeError = false;
408
+ widgetReady = true;
409
+ console.log('[WidgetPreview] iframe onload:', effectiveSrc);
410
+
411
+ if (iframeEl?.contentWindow) {
412
+ iframeEl.contentWindow.postMessage({ type: 'widgetic:ping' }, '*');
413
+ sendPropertiesToWidget(designValues, contentValues);
414
+ flushPendingMessages();
415
+ dispatch('load', { src: effectiveSrc });
416
+ }
417
+
418
+ await tick();
419
+ requestAnimationFrame(() => {
420
+ nudgeIframePaint();
421
+ });
422
+ }
423
+
424
+ function handleIframeError(event?: Event) {
425
+ if (mode === 'controlled') {
426
+ dispatch('iframeError', event || new Event('error'));
427
+ return;
428
+ }
429
+ iframeError = true;
430
+ iframeLoaded = false;
431
+ widgetReady = false;
432
+ errorMessage = 'Failed to load widget preview.';
433
+ console.error('[WidgetPreview] Widget iframe onerror:', effectiveSrc);
434
+ dispatch('error', { src: effectiveSrc });
435
+ }
436
+
437
+ function handleMessage(event: MessageEvent) {
438
+ const type = event.data?.type;
439
+ if (type === 'widgetic:ready' || type === 'widgetic:pong') {
440
+ if (mode === 'standalone') {
441
+ iframeLoaded = true;
442
+ iframeError = false;
443
+ widgetReady = true;
444
+ console.log('[WidgetPreview] Widget confirmed ready via postMessage');
445
+ sendPropertiesToWidget(designValues, contentValues);
446
+ flushPendingMessages();
447
+ }
448
+ }
449
+ }
450
+
451
+ function handleRefreshClick() {
452
+ if (mode === 'standalone' && widget) {
453
+ beginWidgetLoad(widget, buildWidgetUrl(widget));
454
+ }
455
+ dispatch('refresh');
456
+ }
457
+
458
+ function handleOpenInTabClick() {
459
+ const url = effectiveDisplayUrl || effectiveSrc;
460
+ if (url) window.open(url, '_blank');
461
+ dispatch('openInTab');
462
+ }
463
+
464
+ function applyMobileViewport() {
465
+ const { maxWidth, maxHeight } = getResizeLimits();
466
+ const w = Math.min(mobileViewportWidth, maxWidth);
467
+ const h = Math.min(mobileViewportHeight, maxHeight);
468
+ resizeWidth = w;
469
+ resizeHeight = h;
470
+ dispatch('resize', { width: w, height: h });
471
+ dispatch('mobileViewport', { width: w, height: h });
472
+ }
473
+
474
+ function handleDesktopViewport() {
475
+ dispatch('desktopViewport');
476
+ }
477
+
478
+ function handleFitToAreaClick() {
479
+ fitToContainer();
480
+ dispatch('fitToArea');
481
+ }
482
+
483
+ function clampResizeToLimits() {
484
+ if (!enableResize || resizeWidth == null || resizeHeight == null) return;
485
+ const { maxWidth, maxHeight } = getResizeLimits();
486
+ const nextW = Math.min(resizeWidth, maxWidth);
487
+ const nextH = Math.min(resizeHeight, maxHeight);
488
+ if (nextW !== resizeWidth || nextH !== resizeHeight) {
489
+ resizeWidth = nextW;
490
+ resizeHeight = nextH;
491
+ dispatch('resize', { width: nextW, height: nextH });
492
+ }
493
+ }
494
+
495
+ function startResize(event: PointerEvent, signX: number, signY: number) {
496
+ event.preventDefault();
497
+ event.stopPropagation();
498
+ isResizing = true;
499
+ const startX = event.clientX;
500
+ const startY = event.clientY;
501
+
502
+ const { maxWidth, maxHeight } = getResizeLimits();
503
+ const startWidth = resizeWidth ?? maxWidth;
504
+ const startHeight = resizeHeight ?? maxHeight;
505
+
506
+ function onPointerMove(e: PointerEvent) {
507
+ const deltaX = (e.clientX - startX) * signX * 2;
508
+ const deltaY = (e.clientY - startY) * signY * 2;
509
+ resizeWidth = Math.max(MIN_WIDTH, Math.min(maxWidth, startWidth + deltaX));
510
+ resizeHeight = Math.max(MIN_HEIGHT, Math.min(maxHeight, startHeight + deltaY));
511
+ }
512
+
513
+ function endResize() {
514
+ isResizing = false;
515
+ document.removeEventListener('pointermove', onPointerMove);
516
+ document.removeEventListener('pointerup', endResize);
517
+ document.removeEventListener('pointercancel', endResize);
518
+ document.body.style.removeProperty('user-select');
519
+ document.body.style.removeProperty('cursor');
520
+ if (resizeWidth != null && resizeHeight != null) {
521
+ dispatch('resize', { width: resizeWidth, height: resizeHeight });
522
+ }
523
+ }
524
+
525
+ document.body.style.userSelect = 'none';
526
+ document.body.style.cursor = 'nwse-resize';
527
+ document.addEventListener('pointermove', onPointerMove);
528
+ document.addEventListener('pointerup', endResize);
529
+ document.addEventListener('pointercancel', endResize);
530
+ }
531
+
532
+ $: if (enableResize && contentContainerEl && (resizeWidth != null || resizeHeight != null)) {
533
+ clampResizeToLimits();
534
+ }
535
+
536
+ $: if (autoFitStage && resizeStageEl) {
537
+ stageResizeObserver?.disconnect();
538
+ stageResizeObserver = new ResizeObserver(() => {
539
+ fitToContainer();
540
+ });
541
+ stageResizeObserver.observe(resizeStageEl);
542
+ fitToContainer();
543
+ }
544
+
545
+ onMount(() => {
546
+ window.addEventListener('message', handleMessage);
547
+ });
548
+
549
+ onDestroy(() => {
550
+ window.removeEventListener('message', handleMessage);
551
+ stageResizeObserver?.disconnect();
552
+ document.body.style.removeProperty('user-select');
553
+ document.body.style.removeProperty('cursor');
554
+ });
555
+ </script>
556
+
557
+ <div
558
+ class="{className ? className + ' ' : ''}widget-preview-content-root flex flex-col min-h-0 user-select-none {hasFixedBounds ? 'w-auto shrink-0' : mode === 'standalone' && !showUrlBar ? 'relative overflow-hidden rounded-[4px] bg-transparent' : 'h-full w-full'}"
559
+ style="{style ? style + ';' : ''}{hasFixedBounds ? `width: ${boundsWidth}px;` : mode === 'standalone' && !showUrlBar ? `width: ${width}; height: ${height};` : ''}"
560
+ >
561
+ {#if showUrlBar}
562
+ <div class="preview-content-url-bar flex items-center gap-1.5 pb-1.5 min-w-0">
563
+ <span
564
+ class="preview-url-text flex-1 rounded border border-gray-300 px-2 py-1 text-xs text-gray-500 min-w-0 font-mono overflow-x-auto whitespace-nowrap"
565
+ >
566
+ {effectiveDisplayUrl || effectiveSrc || 'no URL'}
567
+ </span>
568
+ <button
569
+ type="button"
570
+ onclick={() => {
571
+ const url = effectiveDisplayUrl || effectiveSrc;
572
+ if (url) navigator.clipboard.writeText(url);
573
+ }}
574
+ title="Copy URL"
575
+ class="shrink-0 w-7 h-7 flex items-center justify-center rounded border border-gray-300 bg-white hover:bg-gray-100 text-sm cursor-pointer"
576
+ >
577
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
578
+ </button>
579
+ {#if showUrlBarButtons}
580
+ <button
581
+ type="button"
582
+ onclick={handleRefreshClick}
583
+ title="Refresh preview"
584
+ class="shrink-0 w-7 h-7 flex items-center justify-center rounded border border-gray-300 bg-white hover:bg-gray-100 text-sm cursor-pointer"
585
+ >🔄</button>
586
+ {#if showViewportButtons && enableResize}
587
+ <button
588
+ type="button"
589
+ onclick={handleFitToAreaClick}
590
+ title="Fit preview to panel"
591
+ class="preview-fit-to-area-btn shrink-0 w-7 h-7 flex items-center justify-center rounded border border-gray-300 bg-white hover:bg-gray-100 cursor-pointer"
592
+ >
593
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h6v6"/><path d="M9 21H3v-6"/><path d="M21 3l-7 7"/><path d="M3 21l7-7"/></svg>
594
+ </button>
595
+ <button
596
+ type="button"
597
+ onclick={applyMobileViewport}
598
+ title="Mobile viewport"
599
+ class="preview-mobile-viewport-btn shrink-0 w-7 h-7 flex items-center justify-center rounded border border-gray-300 bg-white hover:bg-gray-100 cursor-pointer"
600
+ >
601
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="5" y="2" width="14" height="20" rx="2" ry="2"/><line x1="12" y1="18" x2="12.01" y2="18"/></svg>
602
+ </button>
603
+ <button
604
+ type="button"
605
+ onclick={handleDesktopViewport}
606
+ title="Desktop viewport (full window)"
607
+ class="preview-desktop-viewport-btn shrink-0 w-7 h-7 flex items-center justify-center rounded border border-gray-300 bg-white hover:bg-gray-100 cursor-pointer"
608
+ >
609
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2" ry="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>
610
+ </button>
611
+ {/if}
612
+ <button
613
+ type="button"
614
+ onclick={handleOpenInTabClick}
615
+ title="Open in new tab"
616
+ class="shrink-0 px-2 h-7 flex items-center justify-center rounded border border-gray-300 bg-white hover:bg-gray-100 text-xs cursor-pointer whitespace-nowrap"
617
+ >↗ New tab</button>
618
+ {/if}
619
+ </div>
620
+ {/if}
621
+
622
+ <div
623
+ bind:this={contentContainerEl}
624
+ class="preview-content-container relative flex items-center justify-center {containerOverflowClass} {hasFixedBounds ? 'rounded-lg bg-gray-50 border border-gray-300 shrink-0' : compactChrome ? 'flex-1 min-h-0 h-full' : showUrlBar || mode === 'controlled' ? 'flex-1 min-h-0 rounded-lg bg-gray-50 border border-gray-300' : 'flex-1 min-h-0 h-full'}"
625
+ style="{boundedContainerStyle}{containerPaddingStyle}{contentHeight && (showUrlBar || mode === 'controlled') && !compactChrome && !hasFixedBounds ? ` min-height: 0;` : ''}"
626
+ >
627
+ {#if forceMockReady}
628
+ <div class="flex flex-col items-center justify-center w-full h-full bg-gray-100 text-gray-500">
629
+ <div class="text-4xl mb-2">🚀</div>
630
+ <div class="font-semibold">Mock Preview Mode</div>
631
+ <div class="text-sm">Preview simulated as Ready. URL: about:blank</div>
632
+ </div>
633
+
634
+ {:else if mode === 'standalone' && !widget}
635
+ <div class="widget-preview-select-ct flex items-center justify-center h-full text-sm text-gray-400">
636
+ Select a widget to preview
637
+ </div>
638
+
639
+ {:else if mode === 'standalone' && widget && !effectiveSrc && !isResolvingUrl && !iframeError}
640
+ <div class="widget-preview-unpublished-ct flex items-center justify-center h-full w-full">
641
+ <div class="widget-preview-unpublished-content-ct flex flex-col items-center gap-3 text-center px-6">
642
+ <div class="w-10 h-10 rounded-full bg-amber-50 flex items-center justify-center">
643
+ <svg class="w-5 h-5 text-amber-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
644
+ <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4.5c-.77-.833-2.694-.833-3.464 0L3.34 16.5c-.77.833.192 2.5 1.732 2.5z" />
645
+ </svg>
646
+ </div>
647
+ <div>
648
+ <p class="text-sm font-medium text-gray-600">{widget.name || 'Widget'}</p>
649
+ <p class="text-xs text-gray-400 mt-1">Not published yet</p>
650
+ </div>
651
+ <p class="text-[11px] text-gray-300 max-w-[220px]">
652
+ Publish the widget in Widget Creator to preview it here.
653
+ </p>
654
+ </div>
655
+ </div>
656
+
657
+ {:else if effectiveSrc || (mode === 'standalone' && isResolvingUrl)}
658
+ <div
659
+ bind:this={resizeStageEl}
660
+ class="{enableResize ? 'preview-resize-stage-ct absolute inset-0 overflow-hidden flex items-center justify-center' : 'preview-resize-stage-ct relative flex items-center justify-center w-full h-full'}"
661
+ >
662
+ <div
663
+ class="preview-iframe-wrapper relative"
664
+ style="width: {resizeWidth ? resizeWidth + 'px' : '100%'}; height: {resizeHeight ? resizeHeight + 'px' : '100%'}; transition: {isResizing ? 'none' : 'width 0.2s, height 0.2s'};"
665
+ >
666
+ {#if showResizeHandles}
667
+ <!-- svelte-ignore a11y-no-static-element-interactions -->
668
+ <div class="preview-resize-handle preview-resize-handle-tl" onpointerdown={(e) => startResize(e, -1, -1)}></div>
669
+ <!-- svelte-ignore a11y-no-static-element-interactions -->
670
+ <div class="preview-resize-handle preview-resize-handle-tr" onpointerdown={(e) => startResize(e, 1, -1)}></div>
671
+ <!-- svelte-ignore a11y-no-static-element-interactions -->
672
+ <div class="preview-resize-handle preview-resize-handle-bl" onpointerdown={(e) => startResize(e, -1, 1)}></div>
673
+ <!-- svelte-ignore a11y-no-static-element-interactions -->
674
+ <div class="preview-resize-handle preview-resize-handle-br" onpointerdown={(e) => startResize(e, 1, 1)}></div>
675
+ {/if}
676
+
677
+ {#if resizeWidth || resizeHeight}
678
+ <div
679
+ class="widget-preview-dimension-badge absolute left-1/2 -translate-x-1/2 text-[10px] bg-black/70 px-1.5 py-px rounded text-gray-300 select-none pointer-events-none z-20 whitespace-nowrap"
680
+ style="top: calc(100% + 4px);"
681
+ >
682
+ {resizeWidth != null ? Math.round(resizeWidth) + 'px' : '100%'} × {resizeHeight != null ? Math.round(resizeHeight) + 'px' : '100%'}
683
+ </div>
684
+ {/if}
685
+
686
+ <div class="preview-iframe-container relative w-full h-full overflow-hidden {compactChrome ? '' : showUrlBar || mode === 'controlled' || enableResize ? 'border border-gray-300' : ''}">
687
+ {#if mode === 'standalone' && iframeError}
688
+ <div class="widget-preview-error-ct absolute inset-0 flex items-center justify-center bg-white z-10 rounded">
689
+ <div class="widget-preview-error-content-ct flex flex-col items-center gap-2 text-center px-4">
690
+ <svg class="w-8 h-8 text-gray-300" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5">
691
+ <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z" />
692
+ </svg>
693
+ <span class="text-sm text-gray-500">{@html errorMessage || 'Failed to load widget.'}</span>
694
+ </div>
695
+ </div>
696
+ {:else if mode === 'controlled' && previewError && !isGeneratingCode}
697
+ <div class="preview-error-overlay absolute inset-0 z-10 flex h-full flex-col items-center justify-center bg-red-50/95 text-gray-700 p-6">
698
+ <div class="text-4xl mb-3">⚠️</div>
699
+ <div class="font-semibold text-lg text-red-600 mb-2">Preview Unavailable</div>
700
+ <div class="text-sm text-center max-w-md whitespace-pre-line text-gray-600 mb-4">{previewError}</div>
701
+ <div class="flex gap-3">
702
+ <button type="button" onclick={() => dispatch('retry')} class="px-3 py-1.5 text-xs rounded border border-blue-500 text-blue-600 bg-white hover:bg-blue-50 cursor-pointer">
703
+ 🔄 Retry {previewRetryCount > 0 ? `(${previewRetryCount})` : ''}
704
+ </button>
705
+ <button type="button" onclick={() => dispatch('openInTab')} class="px-3 py-1.5 text-xs rounded border border-gray-300 text-gray-600 bg-white hover:bg-gray-100 cursor-pointer">
706
+ Open in new tab
707
+ </button>
708
+ </div>
709
+ </div>
710
+ {/if}
711
+
712
+ {#if showStandaloneLoading}
713
+ <div class="widget-preview-loading-ct absolute inset-0 z-10 flex items-center justify-center bg-gray-50/80">
714
+ <GenerateLoader title="Loading widget…" subtitle="" size="md" />
715
+ </div>
716
+ {:else if showControlledLoading && !isGeneratingCode}
717
+ <div class="loading-overlay absolute inset-0 z-20 flex items-center justify-center bg-gray-50">
718
+ <GenerateLoader
719
+ title={!src && isLoadingUrl
720
+ ? 'Loading Preview…'
721
+ : previewHydrating
722
+ ? 'Loading Preview…'
723
+ : 'Loading Preview…'}
724
+ subtitle={!src && isLoadingUrl
725
+ ? 'Checking widget on Worker…'
726
+ : previewHydrating
727
+ ? 'Applying composition settings…'
728
+ : 'Connecting to the widget preview…'}
729
+ size="lg"
730
+ />
731
+ </div>
732
+ {/if}
733
+
734
+ {#if mode === 'controlled' && previewHasRuntimeError && !isGeneratingCode}
735
+ <div class="compilation-error-overlay absolute inset-0 z-20 flex flex-col items-center justify-center bg-red-50 text-red-700 p-6">
736
+ <div class="text-5xl mb-4">⚠️</div>
737
+ <div class="font-semibold text-xl mb-2">Code Has Compilation Errors</div>
738
+ <div class="text-sm text-center text-red-600 mb-4 max-w-md">
739
+ The generated code has syntax or compilation errors (HTTP {previewRuntimeErrorStatus}).
740
+ </div>
741
+ <div class="flex gap-3 flex-wrap justify-center">
742
+ <button type="button" onclick={() => dispatch('fixErrors')} class="px-4 py-2 text-xs rounded bg-red-600 hover:bg-red-700 text-white cursor-pointer border-0">🔧 Fix Errors</button>
743
+ <button type="button" onclick={() => dispatch('viewErrors')} class="px-3 py-1.5 text-xs rounded border border-orange-400 text-orange-600 bg-white hover:bg-orange-50 cursor-pointer">📋 View Errors</button>
744
+ <button type="button" onclick={() => dispatch('retryPreview')} class="px-3 py-1.5 text-xs rounded border border-red-300 text-red-600 bg-white hover:bg-red-50 cursor-pointer">🔄 Retry Preview</button>
745
+ </div>
746
+ </div>
747
+ {/if}
748
+
749
+ {#if mountedPreviewSrc}
750
+ {#key mode === 'controlled' ? `${iframeReloadKey}:${mountedPreviewSrc}` : mountedPreviewSrc}
751
+ <!-- svelte-ignore a11y-missing-attribute -->
752
+ <iframe
753
+ bind:this={iframeEl}
754
+ title={iframeTitle}
755
+ src={mountedPreviewSrc}
756
+ class="widget-preview-iframe h-full w-full border-0"
757
+ tabindex="-1"
758
+ sandbox={mode === 'controlled' ? undefined : 'allow-scripts allow-popups allow-forms'}
759
+ loading="eager"
760
+ allow="clipboard-read; clipboard-write"
761
+ onload={handleIframeLoad}
762
+ onerror={handleIframeError}
763
+ ></iframe>
764
+ {/key}
765
+ {/if}
766
+
767
+ {#if isResizing}
768
+ <div class="resize-iframe-blocker absolute inset-0 z-5 cursor-nwse-resize" style="background: transparent;"></div>
769
+ {/if}
770
+
771
+ {#if mode === 'controlled' && isGeneratingCode}
772
+ <GenerateLoader overlay title="Generating code…" size="lg" />
773
+ {/if}
774
+ </div>
775
+ </div>
776
+ </div>
777
+
778
+ {:else if mode === 'controlled'}
779
+ {#if isLoadingUrl}
780
+ <div class="flex h-full flex-col items-center justify-center p-6">
781
+ <GenerateLoader title="Loading Preview…" subtitle="" size="lg" />
782
+ </div>
783
+ {:else}
784
+ <div class="flex h-full flex-col items-center justify-center p-6 text-center text-sm text-gray-600">
785
+ {#if isGeneratingCode}
786
+ <GenerateLoader title="Generating code…" size="lg" />
787
+ {:else if previewError === 'NO_CODE_YET'}
788
+ <div class="font-semibold text-lg text-gray-700 mb-2">No Code Generated Yet</div>
789
+ {:else if previewError}
790
+ <div class="font-semibold text-lg text-red-600 mb-2">Preview Unavailable</div>
791
+ <div class="text-sm text-gray-600 mb-4">{previewError}</div>
792
+ <button type="button" onclick={() => dispatch('retry')} class="px-3 py-1.5 text-xs rounded border border-blue-500 text-blue-600 bg-white hover:bg-blue-50 cursor-pointer">🔄 Retry Build</button>
793
+ {:else if previewLoading}
794
+ <div class="text-lg font-medium text-gray-700">Building Preview...</div>
795
+ {:else}
796
+ <div class="text-lg text-gray-600 mb-2">🖼️ No Preview Available</div>
797
+ {/if}
798
+ </div>
799
+ {/if}
800
+ {/if}
801
+ </div>
802
+
803
+ {#if isResizing}
804
+ <div
805
+ class="widget-preview-resize-guard-ct fixed inset-0 z-999999 cursor-nwse-resize"
806
+ style="background: transparent;"
807
+ aria-hidden="true"
808
+ ></div>
809
+ {/if}
810
+ </div>
811
+
812
+ <style>
813
+ .preview-url-text::-webkit-scrollbar { display: none; }
814
+ .preview-url-text { scrollbar-width: none; }
815
+
816
+ .preview-resize-handle {
817
+ position: absolute;
818
+ width: 16px;
819
+ height: 16px;
820
+ z-index: 30;
821
+ border-radius: 2px;
822
+ }
823
+
824
+ .preview-resize-handle::before,
825
+ .preview-resize-handle::after {
826
+ content: '';
827
+ position: absolute;
828
+ background: #94a3b8;
829
+ border-radius: 1px;
830
+ }
831
+
832
+ .preview-resize-handle-tl { top: -4px; left: -4px; cursor: nwse-resize; }
833
+ .preview-resize-handle-tl::before { top: 0; left: 0; width: 10px; height: 2px; }
834
+ .preview-resize-handle-tl::after { top: 0; left: 0; width: 2px; height: 10px; }
835
+
836
+ .preview-resize-handle-tr { top: -4px; right: -4px; cursor: nesw-resize; }
837
+ .preview-resize-handle-tr::before { top: 0; right: 0; width: 10px; height: 2px; }
838
+ .preview-resize-handle-tr::after { top: 0; right: 0; width: 2px; height: 10px; }
839
+
840
+ .preview-resize-handle-bl { bottom: -4px; left: -4px; cursor: nesw-resize; }
841
+ .preview-resize-handle-bl::before { bottom: 0; left: 0; width: 10px; height: 2px; }
842
+ .preview-resize-handle-bl::after { bottom: 0; left: 0; width: 2px; height: 10px; }
843
+
844
+ .preview-resize-handle-br { bottom: -4px; right: -4px; cursor: nwse-resize; }
845
+ .preview-resize-handle-br::before { bottom: 0; right: 0; width: 10px; height: 2px; }
846
+ .preview-resize-handle-br::after { bottom: 0; right: 0; width: 2px; height: 10px; }
847
+
848
+ .preview-resize-handle:hover::before,
849
+ .preview-resize-handle:hover::after {
850
+ background: #64748b;
851
+ }
852
+ </style>