@xleddyl/nuxt-cms 0.9.4 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (431) hide show
  1. package/README.md +1 -1
  2. package/dist/module.d.mts +20 -1
  3. package/dist/module.json +1 -1
  4. package/dist/module.mjs +1037 -148
  5. package/dist/runtime/app/blocks/CmsBlocks.d.vue.ts +1 -1
  6. package/dist/runtime/app/blocks/CmsBlocks.vue +57 -9
  7. package/dist/runtime/app/blocks/CmsBlocks.vue.d.ts +1 -1
  8. package/dist/runtime/app/blocks/CmsField.d.ts +24 -0
  9. package/dist/runtime/app/blocks/CmsField.js +16 -0
  10. package/dist/runtime/app/blocks/node.d.ts +37 -0
  11. package/dist/runtime/app/blocks/node.js +17 -0
  12. package/dist/runtime/app/blocks/resolve.d.ts +18 -0
  13. package/dist/runtime/app/blocks/resolve.js +34 -0
  14. package/dist/runtime/app/components/cms/BlockPicker.d.vue.ts +22 -0
  15. package/dist/runtime/app/components/cms/BlockPicker.vue +87 -0
  16. package/dist/runtime/app/components/cms/BlockPicker.vue.d.ts +22 -0
  17. package/dist/runtime/app/components/cms/BlockPickerPopover.d.vue.ts +38 -0
  18. package/dist/runtime/app/components/cms/BlockPickerPopover.vue +44 -0
  19. package/dist/runtime/app/components/cms/BlockPickerPopover.vue.d.ts +38 -0
  20. package/dist/runtime/app/components/cms/BlockTree.d.vue.ts +29 -0
  21. package/dist/runtime/app/components/cms/BlockTree.vue +322 -0
  22. package/dist/runtime/app/components/cms/BlockTree.vue.d.ts +29 -0
  23. package/dist/runtime/app/components/cms/BlocksField.vue +569 -218
  24. package/dist/runtime/app/components/cms/BrandMark.vue +7 -13
  25. package/dist/runtime/app/components/cms/ConfirmGroups.vue +15 -13
  26. package/dist/runtime/app/components/cms/{BlockPalette.vue.d.ts → EditorHistory.d.vue.ts} +6 -5
  27. package/dist/runtime/app/components/cms/EditorHistory.vue +34 -0
  28. package/dist/runtime/app/components/cms/{BlockPalette.d.vue.ts → EditorHistory.vue.d.ts} +6 -5
  29. package/dist/runtime/app/components/cms/EntryDrawer.d.vue.ts +11 -5
  30. package/dist/runtime/app/components/cms/EntryDrawer.vue +183 -152
  31. package/dist/runtime/app/components/cms/EntryDrawer.vue.d.ts +11 -5
  32. package/dist/runtime/app/components/cms/EntryForm.d.vue.ts +16 -4
  33. package/dist/runtime/app/components/cms/EntryForm.vue +106 -146
  34. package/dist/runtime/app/components/cms/EntryForm.vue.d.ts +16 -4
  35. package/dist/runtime/app/components/cms/FieldInput.vue +10 -2
  36. package/dist/runtime/app/components/cms/FormSections.d.vue.ts +22 -0
  37. package/dist/runtime/app/components/cms/FormSections.vue +71 -0
  38. package/dist/runtime/app/components/cms/FormSections.vue.d.ts +22 -0
  39. package/dist/runtime/app/components/cms/ImportModal.vue +46 -58
  40. package/dist/runtime/app/components/cms/LinkField.d.vue.ts +16 -0
  41. package/dist/runtime/app/components/cms/LinkField.vue +250 -0
  42. package/dist/runtime/app/components/cms/LinkField.vue.d.ts +16 -0
  43. package/dist/runtime/app/components/cms/ListFilters.vue +10 -12
  44. package/dist/runtime/app/components/cms/LocaleSwitch.d.vue.ts +2 -1
  45. package/dist/runtime/app/components/cms/LocaleSwitch.vue +29 -5
  46. package/dist/runtime/app/components/cms/LocaleSwitch.vue.d.ts +2 -1
  47. package/dist/runtime/app/components/cms/MediaDetail.d.vue.ts +2 -0
  48. package/dist/runtime/app/components/cms/MediaDetail.vue +112 -83
  49. package/dist/runtime/app/components/cms/MediaDetail.vue.d.ts +2 -0
  50. package/dist/runtime/app/components/cms/MediaField.vue +35 -25
  51. package/dist/runtime/app/components/cms/MediaFolderPicker.vue +26 -71
  52. package/dist/runtime/app/components/cms/MediaGallery.d.vue.ts +1 -0
  53. package/dist/runtime/app/components/cms/MediaGallery.vue +442 -419
  54. package/dist/runtime/app/components/cms/MediaGallery.vue.d.ts +1 -0
  55. package/dist/runtime/app/components/cms/MediaThumb.vue +9 -25
  56. package/dist/runtime/app/components/cms/MediaUpload.vue +1 -1
  57. package/dist/runtime/app/components/cms/{BlockOutline.d.vue.ts → NestedBlockList.d.vue.ts} +5 -5
  58. package/dist/runtime/app/components/cms/NestedBlockList.vue +87 -0
  59. package/dist/runtime/app/components/cms/{BlockOutline.vue.d.ts → NestedBlockList.vue.d.ts} +5 -5
  60. package/dist/runtime/app/components/cms/PoweredBy.vue +12 -5
  61. package/dist/runtime/app/components/cms/PresetModal.d.vue.ts +18 -0
  62. package/dist/runtime/app/components/cms/PresetModal.vue +70 -0
  63. package/dist/runtime/app/components/cms/PresetModal.vue.d.ts +18 -0
  64. package/dist/runtime/app/components/cms/RelationField.vue +2 -8
  65. package/dist/runtime/app/components/cms/SettingsAccount.vue +60 -71
  66. package/dist/runtime/app/components/cms/SettingsColumns.vue +47 -69
  67. package/dist/runtime/app/components/cms/SettingsEmptyAdd.d.vue.ts +13 -0
  68. package/dist/runtime/app/components/cms/SettingsEmptyAdd.vue +21 -0
  69. package/dist/runtime/app/components/cms/SettingsEmptyAdd.vue.d.ts +13 -0
  70. package/dist/runtime/app/components/cms/SettingsEntries.d.vue.ts +13 -0
  71. package/dist/runtime/app/components/cms/SettingsEntries.vue +50 -0
  72. package/dist/runtime/app/components/cms/SettingsEntries.vue.d.ts +13 -0
  73. package/dist/runtime/app/components/cms/SettingsEntry.d.vue.ts +1 -10
  74. package/dist/runtime/app/components/cms/SettingsEntry.vue +11 -95
  75. package/dist/runtime/app/components/cms/SettingsEntry.vue.d.ts +1 -10
  76. package/dist/runtime/app/components/cms/SettingsEntryActions.d.vue.ts +7 -0
  77. package/dist/runtime/app/components/cms/SettingsEntryActions.vue +42 -0
  78. package/dist/runtime/app/components/cms/SettingsEntryActions.vue.d.ts +7 -0
  79. package/dist/runtime/app/components/cms/SettingsEntryTabs.d.vue.ts +7 -0
  80. package/dist/runtime/app/components/cms/SettingsEntryTabs.vue +21 -0
  81. package/dist/runtime/app/components/cms/SettingsEntryTabs.vue.d.ts +7 -0
  82. package/dist/runtime/app/components/cms/SettingsFormAction.d.vue.ts +3 -0
  83. package/dist/runtime/app/components/cms/SettingsFormAction.vue +17 -0
  84. package/dist/runtime/app/components/cms/SettingsFormAction.vue.d.ts +3 -0
  85. package/dist/runtime/app/components/cms/SettingsLayout.vue +18 -14
  86. package/dist/runtime/app/components/cms/SettingsPresetForm.d.vue.ts +11 -0
  87. package/dist/runtime/app/components/cms/SettingsPresetForm.vue +60 -0
  88. package/dist/runtime/app/components/cms/SettingsPresetForm.vue.d.ts +11 -0
  89. package/dist/runtime/app/components/cms/SettingsPresets.d.vue.ts +13 -0
  90. package/dist/runtime/app/components/cms/SettingsPresets.vue +65 -0
  91. package/dist/runtime/app/components/cms/SettingsPresets.vue.d.ts +13 -0
  92. package/dist/runtime/app/components/cms/SettingsRecordActions.d.vue.ts +32 -0
  93. package/dist/runtime/app/components/cms/SettingsRecordActions.vue +45 -0
  94. package/dist/runtime/app/components/cms/SettingsRecordActions.vue.d.ts +32 -0
  95. package/dist/runtime/app/components/cms/SettingsRedirectActions.d.vue.ts +3 -0
  96. package/dist/runtime/app/components/cms/SettingsRedirectActions.vue +59 -0
  97. package/dist/runtime/app/components/cms/SettingsRedirectActions.vue.d.ts +3 -0
  98. package/dist/runtime/app/components/cms/SettingsRedirectForm.d.vue.ts +11 -0
  99. package/dist/runtime/app/components/cms/SettingsRedirectForm.vue +77 -0
  100. package/dist/runtime/app/components/cms/SettingsRedirectForm.vue.d.ts +11 -0
  101. package/dist/runtime/app/components/cms/SettingsRedirects.d.vue.ts +13 -0
  102. package/dist/runtime/app/components/cms/SettingsRedirects.vue +117 -0
  103. package/dist/runtime/app/components/cms/SettingsRedirects.vue.d.ts +13 -0
  104. package/dist/runtime/app/components/cms/SettingsSecretCard.d.vue.ts +17 -0
  105. package/dist/runtime/app/components/cms/SettingsSecretCard.vue +43 -0
  106. package/dist/runtime/app/components/cms/SettingsSecretCard.vue.d.ts +17 -0
  107. package/dist/runtime/app/components/cms/SettingsSite.d.vue.ts +3 -0
  108. package/dist/runtime/app/components/cms/SettingsSite.vue +140 -0
  109. package/dist/runtime/app/components/cms/SettingsSite.vue.d.ts +3 -0
  110. package/dist/runtime/app/components/cms/SettingsUserCreate.d.vue.ts +8 -0
  111. package/dist/runtime/app/components/cms/SettingsUserCreate.vue +82 -0
  112. package/dist/runtime/app/components/cms/SettingsUserCreate.vue.d.ts +8 -0
  113. package/dist/runtime/app/components/cms/SettingsUserDetail.d.vue.ts +11 -0
  114. package/dist/runtime/app/components/cms/SettingsUserDetail.vue +179 -0
  115. package/dist/runtime/app/components/cms/SettingsUserDetail.vue.d.ts +11 -0
  116. package/dist/runtime/app/components/cms/SettingsUsers.d.vue.ts +9 -6
  117. package/dist/runtime/app/components/cms/SettingsUsers.vue +88 -234
  118. package/dist/runtime/app/components/cms/SettingsUsers.vue.d.ts +9 -6
  119. package/dist/runtime/app/components/cms/SharePreview.d.vue.ts +18 -0
  120. package/dist/runtime/app/components/cms/SharePreview.vue +219 -0
  121. package/dist/runtime/app/components/cms/SharePreview.vue.d.ts +18 -0
  122. package/dist/runtime/app/components/cms/SlugField.vue +5 -3
  123. package/dist/runtime/app/components/cms/StatusBadge.vue +9 -8
  124. package/dist/runtime/app/components/cms/TranslationBadges.d.vue.ts +7 -0
  125. package/dist/runtime/app/components/cms/TranslationBadges.vue +45 -0
  126. package/dist/runtime/app/components/cms/TranslationBadges.vue.d.ts +7 -0
  127. package/dist/runtime/app/components/cms/TranslationMenu.d.vue.ts +17 -0
  128. package/dist/runtime/app/components/cms/TranslationMenu.vue +28 -0
  129. package/dist/runtime/app/components/cms/TranslationMenu.vue.d.ts +17 -0
  130. package/dist/runtime/app/components/cms/VisualEditor.d.vue.ts +22 -4
  131. package/dist/runtime/app/components/cms/VisualEditor.vue +1152 -335
  132. package/dist/runtime/app/components/cms/VisualEditor.vue.d.ts +22 -4
  133. package/dist/runtime/app/components/cms/WelcomeModal.vue +32 -50
  134. package/dist/runtime/app/composables/cms-clipboard.d.ts +8 -0
  135. package/dist/runtime/app/composables/cms-clipboard.js +38 -0
  136. package/dist/runtime/app/composables/cms-confirm.d.ts +6 -8
  137. package/dist/runtime/app/composables/cms-confirm.js +5 -7
  138. package/dist/runtime/app/composables/cms-entry-disabled.d.ts +5 -1
  139. package/dist/runtime/app/composables/cms-entry-disabled.js +7 -0
  140. package/dist/runtime/app/composables/cms-entry-form.d.ts +15 -0
  141. package/dist/runtime/app/composables/cms-entry-form.js +40 -0
  142. package/dist/runtime/app/composables/cms-entry-settings.d.ts +30 -0
  143. package/dist/runtime/app/composables/cms-entry-settings.js +122 -0
  144. package/dist/runtime/app/composables/cms-entry.d.ts +5 -1
  145. package/dist/runtime/app/composables/cms-entry.js +36 -11
  146. package/dist/runtime/app/composables/cms-history.d.ts +10 -0
  147. package/dist/runtime/app/composables/cms-history.js +24 -0
  148. package/dist/runtime/app/composables/cms-link-targets.d.ts +10 -0
  149. package/dist/runtime/app/composables/cms-link-targets.js +40 -0
  150. package/dist/runtime/app/composables/cms-link-usage.d.ts +1 -0
  151. package/dist/runtime/app/composables/cms-link-usage.js +45 -0
  152. package/dist/runtime/app/composables/cms-media-library.d.ts +19 -9
  153. package/dist/runtime/app/composables/cms-media-library.js +31 -13
  154. package/dist/runtime/app/composables/cms-media-uploader.js +6 -20
  155. package/dist/runtime/app/composables/cms-permissions.d.ts +18 -0
  156. package/dist/runtime/app/composables/cms-permissions.js +54 -0
  157. package/dist/runtime/app/composables/cms-presets.d.ts +11 -0
  158. package/dist/runtime/app/composables/cms-presets.js +40 -0
  159. package/dist/runtime/app/composables/cms-preview-mode.d.ts +4 -0
  160. package/dist/runtime/app/composables/cms-preview-mode.js +8 -0
  161. package/dist/runtime/app/composables/cms-query.d.ts +3 -0
  162. package/dist/runtime/app/composables/cms-query.js +45 -20
  163. package/dist/runtime/app/composables/cms-record-list.d.ts +31 -0
  164. package/dist/runtime/app/composables/cms-record-list.js +75 -0
  165. package/dist/runtime/app/composables/cms-route.d.ts +6 -0
  166. package/dist/runtime/app/composables/cms-route.js +36 -0
  167. package/dist/runtime/app/composables/cms-runtime.d.ts +1 -0
  168. package/dist/runtime/app/composables/cms-save-handoff.d.ts +4 -0
  169. package/dist/runtime/app/composables/cms-save-handoff.js +19 -0
  170. package/dist/runtime/app/composables/cms-seo.d.ts +12 -0
  171. package/dist/runtime/app/composables/cms-seo.js +69 -0
  172. package/dist/runtime/app/composables/cms-settings-form.d.ts +13 -0
  173. package/dist/runtime/app/composables/cms-settings-form.js +29 -0
  174. package/dist/runtime/app/composables/cms-settings-sections.d.ts +26 -0
  175. package/dist/runtime/app/composables/cms-settings-sections.js +181 -0
  176. package/dist/runtime/app/composables/cms-settings-stores.d.ts +52 -0
  177. package/dist/runtime/app/composables/cms-settings-stores.js +156 -0
  178. package/dist/runtime/app/composables/cms-settings.d.ts +3 -3
  179. package/dist/runtime/app/composables/cms-settings.js +14 -8
  180. package/dist/runtime/app/composables/cms-site-disabled.d.ts +7 -0
  181. package/dist/runtime/app/composables/cms-site-disabled.js +8 -0
  182. package/dist/runtime/app/composables/cms-site.d.ts +7 -0
  183. package/dist/runtime/app/composables/cms-site.js +22 -0
  184. package/dist/runtime/app/composables/cms-toast.d.ts +2 -8
  185. package/dist/runtime/app/composables/cms-toast.js +3 -9
  186. package/dist/runtime/app/composables/cms-translation-actions.d.ts +15 -0
  187. package/dist/runtime/app/composables/cms-translation-actions.js +108 -0
  188. package/dist/runtime/app/css-url.d.ts +4 -0
  189. package/dist/runtime/app/image/CmsImage.d.vue.ts +89 -0
  190. package/dist/runtime/app/image/CmsImage.vue +91 -0
  191. package/dist/runtime/app/image/CmsImage.vue.d.ts +89 -0
  192. package/dist/runtime/app/layouts/cms-admin.d.vue.ts +2 -2
  193. package/dist/runtime/app/layouts/cms-admin.vue +98 -76
  194. package/dist/runtime/app/layouts/cms-admin.vue.d.ts +2 -2
  195. package/dist/runtime/app/layouts/cms-editor.vue +7 -2
  196. package/dist/runtime/app/links/CmsLink.d.vue.ts +18 -0
  197. package/dist/runtime/app/links/CmsLink.vue +18 -0
  198. package/dist/runtime/app/links/CmsLink.vue.d.ts +18 -0
  199. package/dist/runtime/app/middleware/cms-auth.js +13 -1
  200. package/dist/runtime/app/pages/admin-collection.vue +473 -297
  201. package/dist/runtime/app/pages/admin-content.vue +190 -53
  202. package/dist/runtime/app/pages/admin-entry.vue +79 -75
  203. package/dist/runtime/app/pages/admin-index.vue +18 -5
  204. package/dist/runtime/app/pages/admin-login.vue +1 -1
  205. package/dist/runtime/app/pages/admin-logout.vue +1 -1
  206. package/dist/runtime/app/pages/admin-media.vue +3 -3
  207. package/dist/runtime/app/pages/admin-preview.vue +112 -24
  208. package/dist/runtime/app/plugins/cms-field.d.ts +2 -0
  209. package/dist/runtime/app/plugins/cms-field.js +8 -0
  210. package/dist/runtime/app/plugins/cms-preview-banner.client.d.ts +2 -0
  211. package/dist/runtime/app/plugins/cms-preview-banner.client.js +19 -0
  212. package/dist/runtime/app/plugins/cms-preview.d.ts +2 -0
  213. package/dist/runtime/app/plugins/cms-preview.js +27 -0
  214. package/dist/runtime/app/preview/CmsPreviewBanner.d.vue.ts +7 -0
  215. package/dist/runtime/app/preview/CmsPreviewBanner.vue +63 -0
  216. package/dist/runtime/app/preview/CmsPreviewBanner.vue.d.ts +7 -0
  217. package/dist/runtime/app/preview/PreviewOverlay.d.vue.ts +17 -3
  218. package/dist/runtime/app/preview/PreviewOverlay.vue +629 -166
  219. package/dist/runtime/app/preview/PreviewOverlay.vue.d.ts +17 -3
  220. package/dist/runtime/app/preview/field-marker.d.ts +12 -0
  221. package/dist/runtime/app/preview/field-marker.js +20 -0
  222. package/dist/runtime/app/preview/inline-text.d.ts +15 -0
  223. package/dist/runtime/app/preview/inline-text.js +158 -0
  224. package/dist/runtime/app/utils/block-editor.d.ts +22 -0
  225. package/dist/runtime/app/utils/block-editor.js +12 -0
  226. package/dist/runtime/app/utils/keyboard.d.ts +6 -0
  227. package/dist/runtime/app/utils/keyboard.js +52 -0
  228. package/dist/runtime/app/utils/redirects.d.ts +6 -0
  229. package/dist/runtime/app/utils/redirects.js +7 -0
  230. package/dist/runtime/app/utils/ui.d.ts +8 -0
  231. package/dist/runtime/app/utils/ui.js +15 -1
  232. package/dist/runtime/app/utils/users.d.ts +15 -0
  233. package/dist/runtime/app/utils/users.js +14 -0
  234. package/dist/runtime/assets/cms.css +1 -1
  235. package/dist/runtime/generate.js +16 -2
  236. package/dist/runtime/server/api/collection-export.get.js +3 -2
  237. package/dist/runtime/server/api/collection-import.post.js +39 -11
  238. package/dist/runtime/server/api/collection.get.js +27 -9
  239. package/dist/runtime/server/api/collection.post.js +28 -11
  240. package/dist/runtime/server/api/collection.put.js +35 -13
  241. package/dist/runtime/server/api/item.delete.js +19 -7
  242. package/dist/runtime/server/api/item.get.js +3 -2
  243. package/dist/runtime/server/api/item.put.js +52 -18
  244. package/dist/runtime/server/api/link-usage.post.d.ts +5 -0
  245. package/dist/runtime/server/api/link-usage.post.js +21 -0
  246. package/dist/runtime/server/api/media-delete.post.js +4 -2
  247. package/dist/runtime/server/api/media-download.get.js +2 -2
  248. package/dist/runtime/server/api/media-folder.delete.js +8 -2
  249. package/dist/runtime/server/api/media-folder.patch.js +10 -2
  250. package/dist/runtime/server/api/media-folder.post.js +4 -2
  251. package/dist/runtime/server/api/media-move.post.js +7 -4
  252. package/dist/runtime/server/api/media-presign.post.js +2 -2
  253. package/dist/runtime/server/api/media-upload.put.js +2 -2
  254. package/dist/runtime/server/api/media-usage.post.d.ts +2 -4
  255. package/dist/runtime/server/api/media-usage.post.js +13 -9
  256. package/dist/runtime/server/api/media.delete.js +4 -2
  257. package/dist/runtime/server/api/media.get.js +22 -7
  258. package/dist/runtime/server/api/media.post.js +4 -2
  259. package/dist/runtime/server/api/media.put.js +33 -16
  260. package/dist/runtime/server/api/preset.delete.d.ts +4 -0
  261. package/dist/runtime/server/api/preset.delete.js +9 -0
  262. package/dist/runtime/server/api/preset.put.d.ts +3 -0
  263. package/dist/runtime/server/api/preset.put.js +23 -0
  264. package/dist/runtime/server/api/presets-field.get.d.ts +3 -0
  265. package/dist/runtime/server/api/presets-field.get.js +13 -0
  266. package/dist/runtime/server/api/presets-field.post.d.ts +3 -0
  267. package/dist/runtime/server/api/presets-field.post.js +36 -0
  268. package/dist/runtime/server/api/presets.get.d.ts +3 -0
  269. package/dist/runtime/server/api/presets.get.js +7 -0
  270. package/dist/runtime/server/api/preview-link.delete.d.ts +4 -0
  271. package/dist/runtime/server/api/preview-link.delete.js +15 -0
  272. package/dist/runtime/server/api/preview-links.get.d.ts +3 -0
  273. package/dist/runtime/server/api/preview-links.get.js +10 -0
  274. package/dist/runtime/server/api/preview-links.post.d.ts +3 -0
  275. package/dist/runtime/server/api/preview-links.post.js +17 -0
  276. package/dist/runtime/server/api/preview.get.d.ts +3 -0
  277. package/dist/runtime/server/api/preview.get.js +7 -0
  278. package/dist/runtime/server/api/redirect.delete.d.ts +4 -0
  279. package/dist/runtime/server/api/redirect.delete.js +10 -0
  280. package/dist/runtime/server/api/redirect.put.d.ts +3 -0
  281. package/dist/runtime/server/api/redirect.put.js +8 -0
  282. package/dist/runtime/server/api/redirects-import.post.d.ts +3 -0
  283. package/dist/runtime/server/api/redirects-import.post.js +13 -0
  284. package/dist/runtime/server/api/redirects.get.d.ts +3 -0
  285. package/dist/runtime/server/api/redirects.get.js +7 -0
  286. package/dist/runtime/server/api/redirects.post.d.ts +3 -0
  287. package/dist/runtime/server/api/redirects.post.js +7 -0
  288. package/dist/runtime/server/api/search.get.js +8 -3
  289. package/dist/runtime/server/api/settings.delete.js +2 -2
  290. package/dist/runtime/server/api/settings.get.js +4 -2
  291. package/dist/runtime/server/api/settings.put.js +2 -2
  292. package/dist/runtime/server/api/site.get.d.ts +3 -0
  293. package/dist/runtime/server/api/site.get.js +7 -0
  294. package/dist/runtime/server/api/site.put.d.ts +3 -0
  295. package/dist/runtime/server/api/site.put.js +16 -0
  296. package/dist/runtime/server/api/tags.get.js +3 -2
  297. package/dist/runtime/server/api/user.delete.js +8 -2
  298. package/dist/runtime/server/api/user.put.js +14 -4
  299. package/dist/runtime/server/api/users.get.js +2 -2
  300. package/dist/runtime/server/api/users.post.js +8 -4
  301. package/dist/runtime/server/middleware/hidden-site.d.ts +2 -0
  302. package/dist/runtime/server/middleware/hidden-site.js +8 -0
  303. package/dist/runtime/server/middleware/preview-links.d.ts +2 -0
  304. package/dist/runtime/server/middleware/preview-links.js +6 -0
  305. package/dist/runtime/server/middleware/redirects.d.ts +2 -0
  306. package/dist/runtime/server/middleware/redirects.js +18 -0
  307. package/dist/runtime/server/plugins/session-validate.js +4 -1
  308. package/dist/runtime/server/plugins/webhooks.d.ts +3 -0
  309. package/dist/runtime/server/plugins/webhooks.js +27 -0
  310. package/dist/runtime/server/routes/graphql.js +5 -3
  311. package/dist/runtime/server/routes/robots.d.ts +2 -0
  312. package/dist/runtime/server/routes/robots.js +16 -0
  313. package/dist/runtime/server/routes/sitemap.d.ts +2 -0
  314. package/dist/runtime/server/routes/sitemap.js +67 -0
  315. package/dist/runtime/server/utils/cached-value.d.ts +5 -0
  316. package/dist/runtime/server/utils/cached-value.js +24 -0
  317. package/dist/runtime/server/utils/content-routes.d.ts +5 -0
  318. package/dist/runtime/server/utils/content-routes.js +29 -0
  319. package/dist/runtime/server/utils/field-rules.d.ts +19 -0
  320. package/dist/runtime/server/utils/field-rules.js +72 -0
  321. package/dist/runtime/server/utils/graphql.d.ts +3 -1
  322. package/dist/runtime/server/utils/graphql.js +143 -28
  323. package/dist/runtime/server/utils/hooks.d.ts +14 -0
  324. package/dist/runtime/server/utils/hooks.js +71 -0
  325. package/dist/runtime/server/utils/import.d.ts +7 -2
  326. package/dist/runtime/server/utils/import.js +108 -14
  327. package/dist/runtime/server/utils/link-usage.d.ts +4 -0
  328. package/dist/runtime/server/utils/link-usage.js +28 -0
  329. package/dist/runtime/server/utils/media-references.d.ts +6 -1
  330. package/dist/runtime/server/utils/media-references.js +49 -20
  331. package/dist/runtime/server/utils/media-usage.d.ts +2 -0
  332. package/dist/runtime/server/utils/media-usage.js +5 -3
  333. package/dist/runtime/server/utils/page-rows.d.ts +2 -0
  334. package/dist/runtime/server/utils/page-rows.js +42 -29
  335. package/dist/runtime/server/utils/permissions.d.ts +14 -0
  336. package/dist/runtime/server/utils/permissions.js +43 -0
  337. package/dist/runtime/server/utils/presets.d.ts +18 -0
  338. package/dist/runtime/server/utils/presets.js +68 -0
  339. package/dist/runtime/server/utils/preview-links.d.ts +207 -0
  340. package/dist/runtime/server/utils/preview-links.js +161 -0
  341. package/dist/runtime/server/utils/redirects.d.ts +31 -0
  342. package/dist/runtime/server/utils/redirects.js +240 -0
  343. package/dist/runtime/server/utils/registry.js +4 -1
  344. package/dist/runtime/server/utils/relations.d.ts +8 -0
  345. package/dist/runtime/server/utils/relations.js +25 -6
  346. package/dist/runtime/server/utils/require-admin.d.ts +0 -1
  347. package/dist/runtime/server/utils/require-admin.js +4 -8
  348. package/dist/runtime/server/utils/search.d.ts +1 -0
  349. package/dist/runtime/server/utils/search.js +44 -19
  350. package/dist/runtime/server/utils/site.d.ts +23 -0
  351. package/dist/runtime/server/utils/site.js +79 -0
  352. package/dist/runtime/server/utils/sitemap.d.ts +12 -0
  353. package/dist/runtime/server/utils/sitemap.js +109 -0
  354. package/dist/runtime/server/utils/user-management.d.ts +4 -0
  355. package/dist/runtime/server/utils/user-management.js +20 -0
  356. package/dist/runtime/server/utils/users.d.ts +1 -1
  357. package/dist/runtime/server/utils/users.js +1 -1
  358. package/dist/runtime/server/utils/visibility.d.ts +1 -0
  359. package/dist/runtime/server/utils/visibility.js +6 -1
  360. package/dist/runtime/server/utils/webhooks.d.ts +24 -0
  361. package/dist/runtime/server/utils/webhooks.js +90 -0
  362. package/dist/runtime/shared/block-paths.d.ts +66 -0
  363. package/dist/runtime/shared/block-paths.js +310 -0
  364. package/dist/runtime/shared/block-picker.d.ts +18 -0
  365. package/dist/runtime/shared/block-picker.js +31 -0
  366. package/dist/runtime/shared/block-signature.d.ts +4 -0
  367. package/dist/runtime/shared/block-signature.js +46 -0
  368. package/dist/runtime/shared/clipboard.d.ts +31 -0
  369. package/dist/runtime/shared/clipboard.js +206 -0
  370. package/dist/runtime/shared/conditions.d.ts +36 -0
  371. package/dist/runtime/shared/conditions.js +100 -0
  372. package/dist/runtime/shared/content-routes.d.ts +42 -0
  373. package/dist/runtime/shared/content-routes.js +237 -0
  374. package/dist/runtime/shared/duplicate.js +2 -1
  375. package/dist/runtime/shared/editor-layout.d.ts +18 -0
  376. package/dist/runtime/shared/editor-layout.js +9 -0
  377. package/dist/runtime/shared/field-options.d.ts +21 -0
  378. package/dist/runtime/shared/field-options.js +90 -0
  379. package/dist/runtime/shared/graphql-sdl.d.ts +1 -0
  380. package/dist/runtime/shared/graphql-sdl.js +50 -26
  381. package/dist/runtime/shared/history.d.ts +27 -0
  382. package/dist/runtime/shared/history.js +123 -0
  383. package/dist/runtime/shared/hooks.d.ts +45 -0
  384. package/dist/runtime/shared/hooks.js +28 -0
  385. package/dist/runtime/shared/index.d.ts +90 -21
  386. package/dist/runtime/shared/index.js +121 -37
  387. package/dist/runtime/shared/inline-text.d.ts +38 -0
  388. package/dist/runtime/shared/inline-text.js +85 -0
  389. package/dist/runtime/shared/layout.d.ts +2 -1
  390. package/dist/runtime/shared/layout.js +3 -0
  391. package/dist/runtime/shared/links.d.ts +48 -0
  392. package/dist/runtime/shared/links.js +155 -0
  393. package/dist/runtime/shared/list-filters.d.ts +2 -0
  394. package/dist/runtime/shared/list-filters.js +2 -0
  395. package/dist/runtime/shared/media-focal.d.ts +30 -0
  396. package/dist/runtime/shared/media-focal.js +52 -0
  397. package/dist/runtime/shared/migrations-dir.d.ts +14 -0
  398. package/dist/runtime/shared/migrations-dir.js +48 -2
  399. package/dist/runtime/shared/presets.d.ts +67 -0
  400. package/dist/runtime/shared/presets.js +127 -0
  401. package/dist/runtime/shared/preview-links.d.ts +64 -0
  402. package/dist/runtime/shared/preview-links.js +54 -0
  403. package/dist/runtime/shared/preview.d.ts +124 -21
  404. package/dist/runtime/shared/preview.js +419 -81
  405. package/dist/runtime/shared/redirects.d.ts +75 -0
  406. package/dist/runtime/shared/redirects.js +230 -0
  407. package/dist/runtime/shared/roles.d.ts +57 -0
  408. package/dist/runtime/shared/roles.js +293 -0
  409. package/dist/runtime/shared/save-state.d.ts +8 -0
  410. package/dist/runtime/shared/save-state.js +15 -0
  411. package/dist/runtime/shared/search.d.ts +16 -1
  412. package/dist/runtime/shared/search.js +41 -7
  413. package/dist/runtime/shared/seo.d.ts +167 -0
  414. package/dist/runtime/shared/seo.js +335 -0
  415. package/dist/runtime/shared/transfer.js +2 -1
  416. package/dist/runtime/shared/translations.d.ts +29 -0
  417. package/dist/runtime/shared/translations.js +123 -0
  418. package/dist/runtime/shared/users.d.ts +1 -1
  419. package/dist/runtime/shared/validation.d.ts +23 -1
  420. package/dist/runtime/shared/validation.js +214 -64
  421. package/dist/runtime/webhooks.d.ts +33 -0
  422. package/dist/runtime/webhooks.js +57 -0
  423. package/dist/types.d.mts +5 -1
  424. package/package.json +6 -2
  425. package/dist/runtime/app/components/cms/BlockOutline.vue +0 -88
  426. package/dist/runtime/app/components/cms/BlockPalette.vue +0 -31
  427. package/dist/runtime/app/components/cms/SettingsModal.d.vue.ts +0 -12
  428. package/dist/runtime/app/components/cms/SettingsModal.vue +0 -126
  429. package/dist/runtime/app/components/cms/SettingsModal.vue.d.ts +0 -12
  430. package/dist/runtime/app/composables/cms-field-focus.d.ts +0 -4
  431. package/dist/runtime/app/composables/cms-field-focus.js +0 -20
@@ -1,104 +1,149 @@
1
1
  <template>
2
- <div ref="root" class="cms-preview-overlay" :class="{ 'is-dragging': drag?.moved }">
3
- <template v-for="box in boxes" :key="box.index">
4
- <div
5
- v-if="box.index === hovered || box.index === selected"
6
- class="cms-preview-outline"
7
- :class="{ 'is-selected': box.index === selected }"
8
- :style="outlineStyle(box)"
2
+ <div
3
+ ref="root"
4
+ class="cms-preview-overlay"
5
+ :class="{ 'is-dragging': drag?.moved }"
6
+ v-bind="cmsTokenRoot(cmsPreviewTheme)"
7
+ >
8
+ <div
9
+ v-for="box in outlined"
10
+ :key="`outline-${box.key}`"
11
+ class="cms-preview-outline"
12
+ :class="{
13
+ 'is-selected': box.key === selectedKey,
14
+ 'is-highlighted': box.key === highlightedKey && box.key !== selectedKey,
15
+ 'is-drop-target': box.key === dropTarget?.parent
16
+ }"
17
+ :style="rectStyle(box)"
18
+ >
19
+ <span class="cms-preview-label">{{ box.label }}</span>
20
+ </div>
21
+ <div
22
+ v-for="tool in toolbars"
23
+ :key="`toolbar-${tool.box.key}`"
24
+ class="cms-preview-toolbar"
25
+ :class="{ 'is-selected': tool.selected }"
26
+ :style="{ top: `${tool.top}px`, left: `${tool.right}px` }"
27
+ role="toolbar"
28
+ :aria-label="`${tool.box.label} block`"
29
+ >
30
+ <button
31
+ type="button"
32
+ class="cms-preview-tool cms-preview-handle"
33
+ :aria-label="`Move ${tool.box.label}: drag, or use the arrow keys`"
34
+ title="Drag to reorder"
35
+ @pointerdown="startDrag($event, tool.box)"
36
+ @keydown="onHandleKey($event, tool.box)"
37
+ @click="onHandleClick(tool.box)"
38
+ >
39
+ <KIcon :name="cmsIcon('bars-2')" />
40
+ </button>
41
+ <button
42
+ v-if="tool.box.path.length > 2"
43
+ type="button"
44
+ class="cms-preview-tool"
45
+ aria-label="Select the parent block"
46
+ title="Select the parent block"
47
+ @click="emit('message', { type: 'select', path: parentBlockPath(tool.box.path) })"
48
+ >
49
+ <KIcon :name="cmsIcon('arrow-up-left')" />
50
+ </button>
51
+ <button
52
+ type="button"
53
+ class="cms-preview-tool"
54
+ :aria-label="tool.horizontal ? 'Move left' : 'Move up'"
55
+ :title="tool.horizontal ? 'Move left' : 'Move up'"
56
+ :disabled="tool.box.index === 0"
57
+ @click="moveBy(tool.box, -1)"
9
58
  >
10
- <span class="cms-preview-label">{{ labelOf(box) }}</span>
11
- </div>
12
- <div
13
- v-if="box.index === hovered || box.index === selected"
14
- class="cms-preview-toolbar"
15
- :class="{ 'is-selected': box.index === selected }"
16
- :style="toolbarStyle(box)"
17
- role="toolbar"
18
- :aria-label="`${labelOf(box)} block`"
59
+ <KIcon :name="cmsIcon(tool.horizontal ? 'arrow-left' : 'arrow-up')" />
60
+ </button>
61
+ <button
62
+ type="button"
63
+ class="cms-preview-tool"
64
+ :aria-label="tool.horizontal ? 'Move right' : 'Move down'"
65
+ :title="tool.horizontal ? 'Move right' : 'Move down'"
66
+ :disabled="tool.box.index >= listLength(tool.box.list) - 1"
67
+ @click="moveBy(tool.box, 1)"
19
68
  >
20
- <button
21
- type="button"
22
- class="cms-preview-tool cms-preview-handle"
23
- :aria-label="`Move ${labelOf(box)}: drag, or use the up and down arrow keys`"
24
- title="Drag to reorder"
25
- @pointerdown="startDrag($event, box.index)"
26
- @keydown="onHandleKey($event, box.index)"
27
- @click="onHandleClick(box.index)"
28
- >
29
- <KIcon :name="cmsIcon('bars-2')" />
30
- </button>
31
- <button
32
- type="button"
33
- class="cms-preview-tool"
34
- aria-label="Move up"
35
- title="Move up"
36
- :disabled="box.index === 0"
37
- @click="emitMove(box.index, box.index - 1)"
38
- >
39
- <KIcon :name="cmsIcon('arrow-up')" />
40
- </button>
41
- <button
42
- type="button"
43
- class="cms-preview-tool"
44
- aria-label="Move down"
45
- title="Move down"
46
- :disabled="box.index >= total - 1"
47
- @click="emitMove(box.index, box.index + 1)"
48
- >
49
- <KIcon :name="cmsIcon('arrow-down')" />
50
- </button>
51
- <span class="cms-preview-separator" />
52
- <button
53
- type="button"
54
- class="cms-preview-tool"
55
- aria-label="Duplicate"
56
- title="Duplicate"
57
- :disabled="!canAdd"
58
- @click="emit('message', { type: 'duplicate', index: box.index })"
59
- >
60
- <KIcon :name="cmsIcon('document-duplicate')" />
61
- </button>
62
- <button
63
- v-if="hideable(box)"
64
- type="button"
65
- class="cms-preview-tool"
66
- aria-label="Hide"
67
- title="Hide"
68
- @click="emit('message', { type: 'toggle-hidden', index: box.index })"
69
- >
70
- <KIcon :name="cmsIcon('eye-slash')" />
71
- </button>
72
- <button
73
- type="button"
74
- class="cms-preview-tool is-danger"
75
- aria-label="Delete"
76
- title="Delete"
77
- @click="emit('message', { type: 'remove', index: box.index })"
78
- >
79
- <KIcon :name="cmsIcon('trash')" />
80
- </button>
81
- </div>
82
- </template>
69
+ <KIcon :name="cmsIcon(tool.horizontal ? 'arrow-right' : 'arrow-down')" />
70
+ </button>
71
+ <span class="cms-preview-separator" />
72
+ <button
73
+ type="button"
74
+ class="cms-preview-tool"
75
+ aria-label="Duplicate"
76
+ title="Duplicate"
77
+ :disabled="!canAddTo(tool.box.list)"
78
+ @click="emit('message', { type: 'duplicate', path: tool.box.path })"
79
+ >
80
+ <KIcon :name="cmsIcon('document-duplicate')" />
81
+ </button>
82
+ <button
83
+ v-if="tool.hideable"
84
+ type="button"
85
+ class="cms-preview-tool"
86
+ aria-label="Hide"
87
+ title="Hide"
88
+ @click="emit('message', { type: 'toggle-hidden', path: tool.box.path })"
89
+ >
90
+ <KIcon :name="cmsIcon('eye-slash')" />
91
+ </button>
92
+ <button
93
+ type="button"
94
+ class="cms-preview-tool is-danger"
95
+ aria-label="Delete"
96
+ title="Delete"
97
+ @click="emit('message', { type: 'remove', path: tool.box.path })"
98
+ >
99
+ <KIcon :name="cmsIcon('trash')" />
100
+ </button>
101
+ </div>
102
+
103
+ <div
104
+ v-if="fieldBox && !drag"
105
+ class="cms-preview-field"
106
+ :class="{ 'is-editing': fieldBox.editing }"
107
+ :style="{
108
+ top: `${fieldBox.top}px`,
109
+ left: `${fieldBox.left}px`,
110
+ width: `${fieldBox.width}px`,
111
+ height: `${fieldBox.height}px`
112
+ }"
113
+ >
114
+ <span
115
+ class="cms-preview-field-label"
116
+ :class="{ 'is-above': fieldBox.top + fieldBox.height > viewportHeight - 32 }"
117
+ >
118
+ {{ fieldBox.label }}
119
+ </span>
120
+ </div>
83
121
 
84
122
  <button
85
123
  v-for="slot in insertSlots"
86
- :key="`insert-${slot.index}-${slot.edge}`"
124
+ :key="`insert-${slot.key}-${slot.edge}`"
87
125
  type="button"
88
126
  class="cms-preview-insert"
89
127
  :class="{ 'is-near': slot.near }"
90
128
  :style="{ top: `${slot.y}px`, left: `${slot.x}px` }"
91
- :aria-label="`Insert a block at position ${slot.index + 1}`"
129
+ :data-cms-insert="slot.key"
130
+ :aria-label="slot.label"
92
131
  title="Insert a block"
93
- @click="emit('message', { type: 'insert', index: slot.index })"
132
+ @click="emit('message', { type: 'insert', path: slot.path })"
94
133
  >
95
134
  <KIcon :name="cmsIcon('plus')" />
96
135
  </button>
97
136
 
98
137
  <div
99
- v-if="drag?.moved && dropY !== null"
138
+ v-if="drag?.moved && dropTarget"
100
139
  class="cms-preview-dropline"
101
- :style="{ top: `${dropY}px`, left: `${dropLeft}px`, width: `${dropWidth}px` }"
140
+ :class="{ 'is-vertical': dropTarget.line.vertical }"
141
+ :style="{
142
+ top: `${dropTarget.line.y}px`,
143
+ left: `${dropTarget.line.x}px`,
144
+ width: dropTarget.line.vertical ? void 0 : `${dropTarget.line.size}px`,
145
+ height: dropTarget.line.vertical ? `${dropTarget.line.size}px` : void 0
146
+ }"
102
147
  />
103
148
  </div>
104
149
  </template>
@@ -106,56 +151,231 @@
106
151
  <script setup>
107
152
  import { Icon as KIcon } from "@xleddyl/443-components-vue";
108
153
  import { cmsIcon } from "../utils/ui";
109
- import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from "#imports";
154
+ import { computed, nextTick, onBeforeUnmount, onMounted, ref, shallowRef, watch } from "#imports";
155
+ import {
156
+ blockAt,
157
+ blockListAt,
158
+ blockListPath,
159
+ blockPathIndex,
160
+ blockPathStartsWith,
161
+ blocksFieldAt,
162
+ formatBlockPath,
163
+ isBlockItemPath,
164
+ parentBlockPath,
165
+ parseBlockPath,
166
+ resolveBlockPath
167
+ } from "../../shared/block-paths";
168
+ import {
169
+ editableText,
170
+ inlineFieldPath,
171
+ inlineTextLimit,
172
+ isInlineTextField,
173
+ isPlainTextContent,
174
+ matchesInlineValue,
175
+ normalizeInlineText
176
+ } from "../../shared/inline-text";
110
177
  import { canAddBlock } from "../../shared/index";
111
- import { canHideBlock, insertionIndex, moveTargetForInsertion } from "../../shared/preview";
178
+ import {
179
+ CMS_CLIPBOARD_MAX_LENGTH,
180
+ canHideBlock,
181
+ canMoveBlock,
182
+ clipboardActionApplies,
183
+ editorShortcut,
184
+ insertionIndex,
185
+ isHorizontalList,
186
+ previewFieldConfig,
187
+ shortcutApplies
188
+ } from "../../shared/preview";
189
+ import { clipboardTarget, onApplePlatform, shortcutTarget } from "../utils/keyboard";
190
+ import { startInlineText } from "./inline-text";
191
+ import { cmsPreviewTheme, cmsTokenRoot } from "./field-marker";
112
192
  const props = defineProps({
113
193
  field: { type: Object, required: true },
114
- total: { type: Number, required: true },
115
- selected: { type: [Number, null], required: true },
194
+ fieldKey: { type: String, required: true },
195
+ fields: { type: [Object, null], required: true },
196
+ blocks: { type: Array, required: true },
197
+ item: { type: [Object, null], required: true },
198
+ locale: { type: String, required: true },
199
+ editable: { type: Boolean, required: true },
200
+ lockedFields: { type: Array, required: true },
201
+ selected: { type: [Array, null], required: true },
202
+ highlighted: { type: [Array, null], required: true },
116
203
  version: { type: Number, required: true }
117
204
  });
118
- const emit = defineEmits(["message"]);
205
+ const emit = defineEmits(["message", "inline"]);
119
206
  const root = ref(null);
120
207
  const boxes = ref([]);
208
+ const placeholders = ref([]);
121
209
  const hovered = ref(null);
210
+ const hoveredField = ref(null);
211
+ const fieldBox = ref(null);
212
+ const editing = shallowRef(null);
122
213
  const viewportWidth = ref(0);
123
214
  const viewportHeight = ref(0);
124
215
  const drag = ref(null);
125
216
  let refocus = false;
126
217
  let suppressClick = false;
127
218
  let frame = 0;
128
- function labelOf(box) {
129
- return props.field.blocks?.[box.type]?.label ?? box.type;
219
+ const rootFields = computed(() => ({ [props.fieldKey]: props.field }));
220
+ const rootValues = computed(() => ({ [props.fieldKey]: props.blocks }));
221
+ const selectedKey = computed(() => props.selected ? formatBlockPath(props.selected) : null);
222
+ const highlightedKey = computed(
223
+ () => props.highlighted ? formatBlockPath(props.highlighted) : null
224
+ );
225
+ const boxIndex = computed(() => new Map(boxes.value.map((box) => [box.key, box])));
226
+ const groups = computed(() => {
227
+ const map = /* @__PURE__ */ new Map();
228
+ for (const box of boxes.value) {
229
+ const list = map.get(box.list) ?? [];
230
+ list.push(box);
231
+ map.set(box.list, list);
232
+ }
233
+ for (const list of map.values()) list.sort((a, b) => a.index - b.index);
234
+ return map;
235
+ });
236
+ function listLength(list) {
237
+ const path = parseBlockPath(list);
238
+ return path ? blockListAt(rootValues.value, path)?.length ?? 0 : 0;
130
239
  }
131
- function hideable(box) {
132
- return canHideBlock(props.field.blocks?.[box.type]);
240
+ function canAddTo(list) {
241
+ const path = parseBlockPath(list);
242
+ const field = path ? blocksFieldAt(rootFields.value, rootValues.value, path) : null;
243
+ return !!field && canAddBlock(field, listLength(list));
244
+ }
245
+ function blockLabel(path, type) {
246
+ return resolveBlockPath(rootFields.value, rootValues.value, path)?.block?.label ?? type;
247
+ }
248
+ function readPath(text) {
249
+ const path = parseBlockPath(text);
250
+ return path && isBlockItemPath(path) && path[0] === props.fieldKey ? path : null;
133
251
  }
134
252
  function measure() {
135
253
  frame = 0;
136
254
  viewportWidth.value = window.innerWidth;
137
255
  viewportHeight.value = window.innerHeight;
138
- const found = [];
139
- for (const element of document.querySelectorAll("[data-cms-block]")) {
140
- const index = Number(element.dataset.cmsBlock);
141
- if (!Number.isInteger(index)) continue;
256
+ const found = /* @__PURE__ */ new Map();
257
+ for (const element of document.querySelectorAll("[data-cms-block-path]")) {
258
+ const path = readPath(element.dataset.cmsBlockPath);
259
+ if (!path) continue;
260
+ const key = formatBlockPath(path);
261
+ if (found.has(key)) continue;
142
262
  const rect = element.getBoundingClientRect();
143
- found.push({
144
- index,
145
- type: element.dataset.cmsBlockType ?? "",
263
+ const type = element.dataset.cmsBlockType ?? "";
264
+ found.set(key, {
265
+ key,
266
+ path,
267
+ list: formatBlockPath(blockListPath(path)),
268
+ index: blockPathIndex(path),
269
+ type,
270
+ label: blockLabel(path, type),
146
271
  top: rect.top,
147
272
  left: rect.left,
148
273
  width: rect.width,
149
274
  height: rect.height,
150
- bottom: rect.bottom
275
+ bottom: rect.bottom,
276
+ right: rect.right
151
277
  });
152
278
  }
153
- boxes.value = found.sort((a, b) => a.top - b.top);
279
+ boxes.value = [...found.values()].sort((a, b) => a.path.length - b.path.length || a.top - b.top);
280
+ const slots = [];
281
+ for (const element of document.querySelectorAll("[data-cms-insert]")) {
282
+ if (root.value?.contains(element)) continue;
283
+ const path = readPath(element.dataset.cmsInsert);
284
+ if (!path) continue;
285
+ const rect = element.getBoundingClientRect();
286
+ slots.push({
287
+ list: formatBlockPath(blockListPath(path)),
288
+ index: blockPathIndex(path),
289
+ top: rect.top,
290
+ bottom: rect.bottom,
291
+ left: rect.left,
292
+ right: rect.right
293
+ });
294
+ }
295
+ placeholders.value = slots;
296
+ measureField();
297
+ }
298
+ function measureField() {
299
+ const hit = editing.value?.hit ?? hoveredField.value;
300
+ if (!hit || !hit.element.isConnected) {
301
+ fieldBox.value = null;
302
+ return;
303
+ }
304
+ const rect = hit.element.getBoundingClientRect();
305
+ fieldBox.value = {
306
+ top: rect.top,
307
+ left: rect.left,
308
+ width: rect.width,
309
+ height: rect.height,
310
+ label: hit.field.label,
311
+ editing: hit === editing.value?.hit
312
+ };
313
+ }
314
+ function fieldValue(hit) {
315
+ return hit.path ? blockAt(rootValues.value, hit.path)?.[hit.key] : props.item?.[hit.key];
316
+ }
317
+ function startEditing(hit, point) {
318
+ const { path, key, field } = hit;
319
+ const locale = props.locale;
320
+ const multiline = !!field.textarea;
321
+ emit("inline", { path, key, value: fieldValue(hit), settled: false });
322
+ const session = startInlineText(hit.element, {
323
+ multiline,
324
+ maxLength: inlineTextLimit(field),
325
+ point,
326
+ onInput: (value, commit) => emit(
327
+ "message",
328
+ commit ? { type: "field-input", path, key, locale, value, commit: true } : { type: "field-input", path, key, locale, value }
329
+ ),
330
+ onStop: (value) => {
331
+ editing.value = null;
332
+ emit("inline", { path, key, value: value === "" ? null : value, settled: true });
333
+ measureField();
334
+ }
335
+ });
336
+ editing.value = { hit, session };
337
+ measureField();
338
+ }
339
+ function canEditInline(hit) {
340
+ if (!props.editable || !isInlineTextField(hit.field) || !isPlainTextContent(hit.element))
341
+ return false;
342
+ if (props.lockedFields.includes(inlineFieldPath(hit.path, hit.key))) return false;
343
+ const text = normalizeInlineText(editableText(hit.element), !!hit.field.textarea);
344
+ return matchesInlineValue(text, fieldValue(hit));
345
+ }
346
+ function onDoubleClick(event) {
347
+ if (editing.value || drag.value || insideOverlay(event.target)) return;
348
+ const hit = fieldHitOf(event.target);
349
+ if (!hit || !canEditInline(hit)) return;
350
+ event.preventDefault();
351
+ startEditing(hit, { x: event.clientX, y: event.clientY });
352
+ }
353
+ function insideEditing(target) {
354
+ return target instanceof Node && !!editing.value?.hit.element.contains(target);
355
+ }
356
+ function blockElementOf(target) {
357
+ return target instanceof Element ? target.closest("[data-cms-block-path]") : null;
358
+ }
359
+ function fieldHitOf(target) {
360
+ const element = target instanceof Element ? target.closest("[data-cms-field]") : null;
361
+ const key = element?.dataset.cmsField;
362
+ if (!element || !key) return null;
363
+ const block = blockElementOf(element);
364
+ const path = block ? readPath(block.dataset.cmsBlockPath) : null;
365
+ if (block && !path) return null;
366
+ const field = previewFieldConfig(
367
+ { path, key },
368
+ rootFields.value,
369
+ rootValues.value,
370
+ props.fields,
371
+ props.fieldKey
372
+ );
373
+ return field ? { element, path, key, field } : null;
154
374
  }
155
375
  function scheduleMeasure() {
156
376
  if (!frame) frame = requestAnimationFrame(measure);
157
377
  }
158
- function outlineStyle(box) {
378
+ function rectStyle(box) {
159
379
  return {
160
380
  top: `${box.top}px`,
161
381
  left: `${box.left}px`,
@@ -163,70 +383,195 @@ function outlineStyle(box) {
163
383
  height: `${box.height}px`
164
384
  };
165
385
  }
166
- function toolbarStyle(box) {
167
- const top = Math.min(Math.max(box.top + 8, 8), Math.max(box.bottom - 44, 8));
168
- const right = Math.min(box.left + box.width, viewportWidth.value) - 8;
169
- return { top: `${top}px`, left: `${right}px` };
386
+ const outlined = computed(() => {
387
+ const keys = /* @__PURE__ */ new Set([hovered.value, selectedKey.value, highlightedKey.value]);
388
+ if (dropTarget.value?.parent) keys.add(dropTarget.value.parent);
389
+ return boxes.value.filter((box) => keys.has(box.key));
390
+ });
391
+ const TOOLBAR_WIDTH = 240;
392
+ const TOOLBAR_HEIGHT = 40;
393
+ function toolbarPlace(box, avoid) {
394
+ const above = box.top - TOOLBAR_HEIGHT - 2;
395
+ let top = box.path.length > 2 && above >= 8 ? above : Math.min(Math.max(box.top + 8, 8), Math.max(box.bottom - 44, 8));
396
+ const right = Math.min(box.right, viewportWidth.value) - 8;
397
+ if (avoid && Math.abs(top - avoid.top) < TOOLBAR_HEIGHT && Math.abs(right - avoid.right) < TOOLBAR_WIDTH)
398
+ top = avoid.top + TOOLBAR_HEIGHT;
399
+ return { top, right };
400
+ }
401
+ function horizontalList(list) {
402
+ return isHorizontalList(groups.value.get(list) ?? []);
170
403
  }
404
+ const toolbars = computed(() => {
405
+ if (!props.editable) return [];
406
+ const selectedBox = selectedKey.value ? boxIndex.value.get(selectedKey.value) : void 0;
407
+ const hoveredBox = hovered.value && hovered.value !== selectedKey.value ? boxIndex.value.get(hovered.value) : void 0;
408
+ const tools = [];
409
+ let first = null;
410
+ for (const [box, selected] of [
411
+ [selectedBox, true],
412
+ [hoveredBox, false]
413
+ ]) {
414
+ if (!box) continue;
415
+ const place = toolbarPlace(box, first);
416
+ first ??= place;
417
+ tools.push({
418
+ box,
419
+ selected,
420
+ ...place,
421
+ horizontal: horizontalList(box.list),
422
+ hideable: canHideBlock(
423
+ resolveBlockPath(rootFields.value, rootValues.value, box.path)?.block
424
+ )
425
+ });
426
+ }
427
+ return tools;
428
+ });
171
429
  const INSERT_MARGIN = 14;
172
- const canAdd = computed(() => canAddBlock(props.field, props.total));
173
430
  const insertSlots = computed(() => {
174
- if (!canAdd.value) return [];
175
- const list = boxes.value;
176
- const near = /* @__PURE__ */ new Set([hovered.value, props.selected]);
431
+ if (!props.editable) return [];
432
+ const lists = /* @__PURE__ */ new Set([props.fieldKey]);
433
+ const near = /* @__PURE__ */ new Set([hovered.value, selectedKey.value]);
434
+ for (const key of near) {
435
+ const box = key ? boxIndex.value.get(key) : void 0;
436
+ if (!box) continue;
437
+ lists.add(box.list);
438
+ for (const list of groups.value.keys())
439
+ if (list.startsWith(`${box.key}.`) && list.split(".").length === box.path.length + 1)
440
+ lists.add(list);
441
+ }
177
442
  const maxY = viewportHeight.value - INSERT_MARGIN;
178
443
  const clampY = (y) => Math.min(Math.max(y, INSERT_MARGIN), Math.max(maxY, INSERT_MARGIN));
179
- return list.flatMap((box, position) => {
180
- const next = list[position + 1];
181
- const x = box.left + box.width / 2;
182
- const after = {
183
- index: box.index + 1,
184
- edge: "after",
185
- y: clampY(next ? (box.bottom + next.top) / 2 : box.bottom),
186
- x,
187
- near: near.has(box.index) || !!next && near.has(next.index)
188
- };
189
- if (position > 0) return [after];
190
- const before = {
191
- index: box.index,
192
- edge: "before",
193
- y: clampY(box.top),
444
+ return [...lists].flatMap((list) => {
445
+ const members = groups.value.get(list);
446
+ const listPath = parseBlockPath(list);
447
+ if (!members?.length || !listPath || !canAddTo(list)) return [];
448
+ const horizontal = isHorizontalList(members);
449
+ const nested = listPath.length > 1;
450
+ const fieldLabel = nested ? blocksFieldAt(rootFields.value, rootValues.value, listPath)?.label : void 0;
451
+ const slot = (index, edge, x, y, isNear) => ({
452
+ key: `${list}.${index}`,
453
+ path: [...listPath, index],
454
+ edge,
194
455
  x,
195
- near: near.has(box.index)
196
- };
197
- return [before, after];
456
+ y: clampY(y),
457
+ near: isNear,
458
+ label: `Insert a block${fieldLabel ? ` in ${fieldLabel}` : ""} at position ${index + 1}`
459
+ });
460
+ return members.flatMap((box, position) => {
461
+ const next = members[position + 1];
462
+ const isNear = near.has(box.key) || !!next && near.has(next.key);
463
+ const middleY = (box.top + box.bottom) / 2;
464
+ const after = next && horizontal && next.left >= box.right - 1 ? slot(box.index + 1, "after", (box.right + next.left) / 2, middleY, isNear) : horizontal && !next ? slot(box.index + 1, "after", box.right, middleY, isNear) : slot(
465
+ box.index + 1,
466
+ "after",
467
+ box.left + box.width / 2,
468
+ next ? (box.bottom + next.top) / 2 : box.bottom,
469
+ isNear
470
+ );
471
+ if (position > 0) return [after];
472
+ const before = horizontal ? slot(box.index, "before", box.left, middleY, near.has(box.key)) : slot(box.index, "before", box.left + box.width / 2, box.top, near.has(box.key));
473
+ return [before, after];
474
+ });
198
475
  });
199
476
  });
200
- const dropIndex = computed(
201
- () => drag.value ? insertionIndex(boxes.value, drag.value.y, props.total) : null
202
- );
203
- const dropY = computed(() => {
204
- if (dropIndex.value === null) return null;
205
- const list = boxes.value;
206
- const position = list.findIndex((box) => box.index >= dropIndex.value);
207
- if (position === -1) return list.at(-1)?.bottom ?? null;
208
- const previous = list[position - 1];
209
- return previous ? (previous.bottom + list[position].top) / 2 : list[position].top;
477
+ function contains(rect, x, y) {
478
+ return x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
479
+ }
480
+ function dropLine(members, index) {
481
+ const horizontal = isHorizontalList(members);
482
+ const position = members.findIndex((box) => box.index >= index);
483
+ const previous = position === -1 ? members.at(-1) : members[position - 1];
484
+ const current = position === -1 ? void 0 : members[position];
485
+ const top = Math.min(...members.map((box) => box.top));
486
+ const bottom = Math.max(...members.map((box) => box.bottom));
487
+ const left = Math.min(...members.map((box) => box.left));
488
+ const right = Math.max(...members.map((box) => box.right));
489
+ if (horizontal) {
490
+ const x = previous && current ? (previous.right + current.left) / 2 : current ? current.left : previous.right;
491
+ return { x, y: top, size: bottom - top, vertical: true };
492
+ }
493
+ const y = previous && current ? (previous.bottom + current.top) / 2 : current ? current.top : previous.bottom;
494
+ return { x: left, y, size: right - left, vertical: false };
495
+ }
496
+ const dropTarget = computed(() => {
497
+ const current = drag.value;
498
+ if (!current?.moved) return null;
499
+ const candidates = /* @__PURE__ */ new Map();
500
+ for (const [list, members] of groups.value) candidates.set(list, { members });
501
+ for (const placeholder of placeholders.value) {
502
+ const entry = candidates.get(placeholder.list) ?? { members: [] };
503
+ entry.placeholder = placeholder;
504
+ candidates.set(placeholder.list, entry);
505
+ }
506
+ let best = null;
507
+ for (const [list, entry] of candidates) {
508
+ const listPath = parseBlockPath(list);
509
+ if (!listPath || !canMoveBlock(rootFields.value, rootValues.value, current.from, listPath))
510
+ continue;
511
+ const parent = listPath.length > 1 ? formatBlockPath(listPath.slice(0, -1)) : null;
512
+ const region = parent ? boxIndex.value.get(parent) : null;
513
+ if (parent && (!region || !contains(region, current.x, current.y))) continue;
514
+ if (best && best.list.length >= listPath.length) continue;
515
+ best = { list: listPath, parent, ...entry };
516
+ }
517
+ if (!best) return null;
518
+ const fromList = blockListPath(current.from);
519
+ const fromIndex = blockPathIndex(current.from);
520
+ const sameList = formatBlockPath(fromList) === formatBlockPath(best.list);
521
+ const visible = best.members.filter((box) => !blockPathStartsWith(box.path, current.from));
522
+ if (!visible.length) {
523
+ const placeholder = best.placeholder;
524
+ if (!placeholder) return null;
525
+ return {
526
+ list: best.list,
527
+ index: placeholder.index,
528
+ parent: best.parent,
529
+ line: {
530
+ x: placeholder.left,
531
+ y: (placeholder.top + placeholder.bottom) / 2,
532
+ size: placeholder.right - placeholder.left,
533
+ vertical: false
534
+ }
535
+ };
536
+ }
537
+ const index = insertionIndex(
538
+ best.members,
539
+ { x: current.x, y: current.y },
540
+ listLength(formatBlockPath(best.list))
541
+ );
542
+ if (sameList && (index === fromIndex || index === fromIndex + 1)) return null;
543
+ return { list: best.list, index, parent: best.parent, line: dropLine(best.members, index) };
210
544
  });
211
- const dropLeft = computed(() => boxes.value[0]?.left ?? 0);
212
- const dropWidth = computed(() => boxes.value[0]?.width ?? viewportWidth.value);
213
- function emitMove(from, to, focus = false) {
214
- if (to < 0 || to >= props.total || from === to) return;
545
+ function emitMove(from, list, index, focus = false) {
546
+ const to = [...list, index];
215
547
  emit("message", focus ? { type: "move", from, to, focus: true } : { type: "move", from, to });
216
548
  }
217
- function onHandleKey(event, index) {
218
- if (event.key !== "ArrowUp" && event.key !== "ArrowDown") return;
549
+ function moveBy(box, delta, focus = false) {
550
+ const target = box.index + delta;
551
+ if (target < 0 || target >= listLength(box.list)) return;
552
+ emitMove(box.path, blockListPath(box.path), delta > 0 ? target + 1 : target, focus);
553
+ }
554
+ function onHandleKey(event, box) {
555
+ const delta = event.key === "ArrowUp" || event.key === "ArrowLeft" ? -1 : event.key === "ArrowDown" || event.key === "ArrowRight" ? 1 : 0;
556
+ if (!delta) return;
219
557
  event.preventDefault();
220
558
  refocus = true;
221
- emitMove(index, event.key === "ArrowUp" ? index - 1 : index + 1, true);
559
+ moveBy(box, delta, true);
222
560
  }
223
- function onHandleClick(index) {
561
+ function onHandleClick(box) {
224
562
  if (drag.value?.moved) return;
225
- emit("message", { type: "select", index });
563
+ emit("message", { type: "select", path: box.path });
226
564
  }
227
- function startDrag(event, index) {
228
- if (event.button !== 0) return;
229
- drag.value = { from: index, startY: event.clientY, y: event.clientY, moved: false };
565
+ function startDrag(event, box) {
566
+ if (event.button !== 0 || !props.editable) return;
567
+ drag.value = {
568
+ from: box.path,
569
+ startX: event.clientX,
570
+ startY: event.clientY,
571
+ x: event.clientX,
572
+ y: event.clientY,
573
+ moved: false
574
+ };
230
575
  window.addEventListener("pointermove", onDragMove);
231
576
  window.addEventListener("pointerup", onDragEnd);
232
577
  window.addEventListener("pointercancel", cancelDrag);
@@ -234,8 +579,10 @@ function startDrag(event, index) {
234
579
  function onDragMove(event) {
235
580
  const current = drag.value;
236
581
  if (!current) return;
582
+ current.x = event.clientX;
237
583
  current.y = event.clientY;
238
- if (!current.moved && Math.abs(event.clientY - current.startY) > 4) {
584
+ const distance = Math.hypot(event.clientX - current.startX, event.clientY - current.startY);
585
+ if (!current.moved && distance > 4) {
239
586
  current.moved = true;
240
587
  document.documentElement.classList.add("cms-preview-grabbing");
241
588
  }
@@ -254,10 +601,11 @@ function stopDrag() {
254
601
  }
255
602
  function onDragEnd() {
256
603
  const current = drag.value;
604
+ const target = dropTarget.value;
257
605
  stopDrag();
258
- if (current?.moved && dropIndex.value !== null) {
606
+ if (current?.moved) {
259
607
  suppressClick = true;
260
- emitMove(current.from, moveTargetForInsertion(current.from, dropIndex.value));
608
+ if (target) emitMove(current.from, target.list, target.index);
261
609
  }
262
610
  setTimeout(() => {
263
611
  drag.value = null;
@@ -268,20 +616,32 @@ function cancelDrag() {
268
616
  stopDrag();
269
617
  drag.value = null;
270
618
  }
271
- function blockIndexOf(target) {
272
- const element = target instanceof Element ? target.closest("[data-cms-block]") : null;
273
- const index = element ? Number(element.dataset.cmsBlock) : NaN;
274
- return Number.isInteger(index) ? index : null;
619
+ function blockPathOf(target) {
620
+ const element = blockElementOf(target);
621
+ return element ? readPath(element.dataset.cmsBlockPath) : null;
275
622
  }
276
623
  function insideOverlay(target) {
277
624
  return target instanceof Node && !!root.value?.contains(target);
278
625
  }
279
626
  function onPointerMove(event) {
280
627
  if (drag.value || insideOverlay(event.target)) return;
281
- hovered.value = blockIndexOf(event.target);
628
+ const path = blockPathOf(event.target);
629
+ hovered.value = path ? formatBlockPath(path) : null;
630
+ const hit = fieldHitOf(event.target);
631
+ if (hit?.element !== hoveredField.value?.element) {
632
+ hoveredField.value = hit;
633
+ measureField();
634
+ }
282
635
  }
283
636
  function onPointerLeave() {
284
- if (!drag.value) hovered.value = null;
637
+ if (drag.value) return;
638
+ hovered.value = null;
639
+ hoveredField.value = null;
640
+ fieldBox.value = null;
641
+ }
642
+ function insertTargetOf(target) {
643
+ const element = target?.closest("[data-cms-insert]");
644
+ return element ? readPath(element.dataset.cmsInsert) : null;
285
645
  }
286
646
  function onClick(event) {
287
647
  if (suppressClick) {
@@ -291,33 +651,127 @@ function onClick(event) {
291
651
  return;
292
652
  }
293
653
  if (insideOverlay(event.target)) return;
654
+ if (insideEditing(event.target)) {
655
+ event.preventDefault();
656
+ event.stopPropagation();
657
+ return;
658
+ }
294
659
  const target = event.target instanceof Element ? event.target : null;
660
+ const insert = insertTargetOf(target);
661
+ if (insert) {
662
+ event.preventDefault();
663
+ event.stopPropagation();
664
+ if (props.editable) emit("message", { type: "insert", path: insert });
665
+ return;
666
+ }
295
667
  if (target?.closest("a, button, input, select, textarea, label, summary")) event.preventDefault();
296
668
  if (target?.closest("[data-cms-preview-keep]")) return;
297
669
  event.stopPropagation();
298
- emit("message", { type: "select", index: blockIndexOf(event.target) });
670
+ const hit = fieldHitOf(event.target);
671
+ emit(
672
+ "message",
673
+ hit ? { type: "focus-field", path: hit.path, key: hit.key } : { type: "select", path: blockPathOf(event.target) }
674
+ );
299
675
  }
300
676
  function onSubmit(event) {
301
677
  event.preventDefault();
302
678
  }
679
+ function selectedBlock() {
680
+ const path = props.selected;
681
+ return path && blockAt(rootValues.value, path) ? path : null;
682
+ }
303
683
  function onKeydown(event) {
304
- if (event.key === "Escape" && props.selected !== null) {
305
- emit("message", { type: "select", index: null });
684
+ if (event.defaultPrevented || event.isComposing) return;
685
+ const action = editorShortcut(event, onApplePlatform());
686
+ const path = selectedBlock();
687
+ if (!action || !shortcutApplies(action, shortcutTarget(event, path !== null))) return;
688
+ if (!props.editable && action !== "deselect") return;
689
+ event.preventDefault();
690
+ if (action === "undo" || action === "redo" || action === "save") {
691
+ emit("message", { type: action });
692
+ return;
306
693
  }
694
+ if (!path) return;
695
+ const list = blockListPath(path);
696
+ const index = blockPathIndex(path);
697
+ const key = formatBlockPath(list);
698
+ switch (action) {
699
+ case "remove":
700
+ emit("message", { type: "remove", path });
701
+ break;
702
+ case "duplicate":
703
+ if (canAddTo(key)) emit("message", { type: "duplicate", path });
704
+ break;
705
+ case "move-up":
706
+ case "move-down": {
707
+ const box = boxIndex.value.get(formatBlockPath(path));
708
+ if (box) moveBy(box, action === "move-up" ? -1 : 1);
709
+ break;
710
+ }
711
+ case "insert-after":
712
+ case "insert-before":
713
+ if (canAddTo(key))
714
+ emit("message", {
715
+ type: "insert",
716
+ path: [...list, action === "insert-after" ? index + 1 : index]
717
+ });
718
+ break;
719
+ case "deselect":
720
+ emit("message", { type: "select", path: parentBlockPath(path) });
721
+ break;
722
+ }
723
+ }
724
+ function onClipboard(event) {
725
+ if (event.defaultPrevented) return;
726
+ const action = event.type;
727
+ if (!props.editable && action !== "copy") return;
728
+ const path = selectedBlock();
729
+ if (!clipboardActionApplies(action, clipboardTarget(event, path !== null))) return;
730
+ if (action !== "paste") {
731
+ if (path) emit("message", { type: action, path });
732
+ return;
733
+ }
734
+ event.preventDefault();
735
+ const at = path ? [...blockListPath(path), blockPathIndex(path) + 1] : [props.fieldKey, props.blocks.length];
736
+ const text = event.clipboardData?.getData("text/plain") ?? "";
737
+ emit(
738
+ "message",
739
+ text && text.length <= CMS_CLIPBOARD_MAX_LENGTH ? { type: "paste", path: at, text } : { type: "paste", path: at }
740
+ );
741
+ }
742
+ function blockElement(path) {
743
+ for (let end = path.length; end >= 2; end -= 2) {
744
+ const key = formatBlockPath(path.slice(0, end));
745
+ const element = document.querySelector(`[data-cms-block-path="${key}"]`);
746
+ if (element?.getClientRects().length) return element;
747
+ }
748
+ return null;
307
749
  }
308
750
  function revealSelected() {
309
- if (props.selected === null || drag.value) return;
310
- const element = document.querySelector(`[data-cms-block="${props.selected}"]`);
751
+ if (!props.selected || drag.value) return;
752
+ const element = blockElement(props.selected);
311
753
  if (!element) return;
312
754
  const rect = element.getBoundingClientRect();
313
755
  if (rect.bottom < 0 || rect.top > window.innerHeight) {
314
756
  element.scrollIntoView({ block: "center", behavior: "smooth" });
315
757
  }
316
758
  }
759
+ async function reveal(path) {
760
+ await nextTick();
761
+ const element = blockElement(path);
762
+ if (!element || drag.value) return;
763
+ const rect = element.getBoundingClientRect();
764
+ if (rect.top >= 0 && rect.bottom <= window.innerHeight) return;
765
+ const tall = rect.height > window.innerHeight * 0.8;
766
+ element.scrollIntoView({ block: tall ? "start" : "center", behavior: "smooth" });
767
+ }
768
+ watch(hovered, (key) => emit("message", { type: "hover", path: key ? parseBlockPath(key) : null }));
769
+ defineExpose({ reveal });
317
770
  watch(
318
771
  () => props.version,
319
772
  async () => {
320
773
  await nextTick();
774
+ if (editing.value && !editing.value.hit.element.isConnected) editing.value.session.stop(true);
321
775
  measure();
322
776
  if (refocus) {
323
777
  refocus = false;
@@ -326,7 +780,7 @@ watch(
326
780
  }
327
781
  );
328
782
  watch(
329
- () => props.selected,
783
+ () => selectedKey.value,
330
784
  async () => {
331
785
  await nextTick();
332
786
  revealSelected();
@@ -339,8 +793,12 @@ onMounted(() => {
339
793
  document.addEventListener("pointermove", onPointerMove, { passive: true });
340
794
  document.documentElement.addEventListener("pointerleave", onPointerLeave);
341
795
  document.addEventListener("click", onClick, true);
796
+ document.addEventListener("dblclick", onDoubleClick, true);
342
797
  document.addEventListener("submit", onSubmit, true);
343
798
  document.addEventListener("keydown", onKeydown);
799
+ document.addEventListener("copy", onClipboard);
800
+ document.addEventListener("cut", onClipboard);
801
+ document.addEventListener("paste", onClipboard);
344
802
  document.addEventListener("load", scheduleMeasure, true);
345
803
  window.addEventListener("scroll", scheduleMeasure, { passive: true, capture: true });
346
804
  window.addEventListener("resize", scheduleMeasure);
@@ -353,12 +811,17 @@ onMounted(() => {
353
811
  });
354
812
  onBeforeUnmount(() => {
355
813
  stopDrag();
814
+ editing.value?.session.stop(true);
356
815
  if (frame) cancelAnimationFrame(frame);
357
816
  document.removeEventListener("pointermove", onPointerMove);
358
817
  document.documentElement.removeEventListener("pointerleave", onPointerLeave);
359
818
  document.removeEventListener("click", onClick, true);
819
+ document.removeEventListener("dblclick", onDoubleClick, true);
360
820
  document.removeEventListener("submit", onSubmit, true);
361
821
  document.removeEventListener("keydown", onKeydown);
822
+ document.removeEventListener("copy", onClipboard);
823
+ document.removeEventListener("cut", onClipboard);
824
+ document.removeEventListener("paste", onClipboard);
362
825
  document.removeEventListener("load", scheduleMeasure, true);
363
826
  window.removeEventListener("scroll", scheduleMeasure, { capture: true });
364
827
  window.removeEventListener("resize", scheduleMeasure);