pageflow 17.0.5 → 17.2.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 (636) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +342 -41
  3. data/README.md +3 -5
  4. data/admins/pageflow/accounts.rb +22 -20
  5. data/admins/pageflow/entry.rb +76 -26
  6. data/admins/pageflow/entry_templates.rb +10 -9
  7. data/admins/pageflow/folder.rb +1 -1
  8. data/admins/pageflow/membership.rb +15 -15
  9. data/admins/pageflow/revisions.rb +5 -5
  10. data/admins/pageflow/site_root_entry.rb +64 -0
  11. data/admins/pageflow/sites.rb +12 -3
  12. data/admins/pageflow/translations.rb +75 -0
  13. data/admins/pageflow/user.rb +21 -35
  14. data/app/assets/images/pageflow/admin/icons/comment.svg +1 -0
  15. data/app/assets/javascripts/pageflow/admin/entries.js +30 -5
  16. data/app/assets/javascripts/pageflow/dist/ui.js +4228 -900
  17. data/app/assets/javascripts/pageflow/editor/vendor.js +0 -1
  18. data/app/assets/javascripts/pageflow/ui.js +0 -1
  19. data/app/assets/stylesheets/pageflow/admin/entries/index_table.scss +2 -1
  20. data/app/assets/stylesheets/pageflow/admin/entry_comments_indicator.scss +45 -0
  21. data/app/assets/stylesheets/pageflow/admin/permalink_input.scss +8 -0
  22. data/app/assets/stylesheets/pageflow/admin.scss +1 -0
  23. data/app/assets/stylesheets/pageflow/animations/spin.scss +9 -0
  24. data/app/assets/stylesheets/pageflow/animations.scss +1 -0
  25. data/app/assets/stylesheets/pageflow/editor/background_positioning.scss +27 -5
  26. data/app/assets/stylesheets/pageflow/editor/base.scss +11 -1
  27. data/app/assets/stylesheets/pageflow/editor/drop_down_button.scss +20 -2
  28. data/app/assets/stylesheets/pageflow/editor/edit_configuration_view.scss +5 -0
  29. data/app/assets/stylesheets/pageflow/editor/file_folders.scss +127 -0
  30. data/app/assets/stylesheets/pageflow/editor/file_meta_data.scss +5 -2
  31. data/app/assets/stylesheets/pageflow/editor/file_meta_data_overlay.scss +45 -0
  32. data/app/assets/stylesheets/pageflow/editor/file_preview.scss +138 -0
  33. data/app/assets/stylesheets/pageflow/editor/file_references.scss +68 -0
  34. data/app/assets/stylesheets/pageflow/editor/file_settings_dialog.scss +1 -1
  35. data/app/assets/stylesheets/pageflow/editor/file_stage_icons.scss +17 -0
  36. data/app/assets/stylesheets/pageflow/editor/file_stages.scss +25 -32
  37. data/app/assets/stylesheets/pageflow/editor/file_thumbnails.scss +31 -48
  38. data/app/assets/stylesheets/pageflow/editor/file_type_pills.scss +73 -0
  39. data/app/assets/stylesheets/pageflow/editor/files.scss +242 -50
  40. data/app/assets/stylesheets/pageflow/editor/filtered_files.scss +161 -9
  41. data/app/assets/stylesheets/pageflow/editor/folder_breadcrumb.scss +40 -0
  42. data/app/assets/stylesheets/pageflow/editor/info_box.scss +23 -3
  43. data/app/assets/stylesheets/pageflow/editor/inputs/edit_defaults_button.scss +15 -0
  44. data/app/assets/stylesheets/pageflow/editor/inputs.scss +1 -0
  45. data/app/assets/stylesheets/pageflow/editor/list.scss +89 -37
  46. data/app/assets/stylesheets/pageflow/editor/list_search_field.scss +52 -0
  47. data/app/assets/stylesheets/pageflow/editor/manage_files.scss +9 -0
  48. data/app/assets/stylesheets/pageflow/editor/menu.scss +14 -0
  49. data/app/assets/stylesheets/pageflow/editor/move_to_folder_dialog.scss +83 -0
  50. data/app/assets/stylesheets/pageflow/editor/outline.scss +0 -13
  51. data/app/assets/stylesheets/pageflow/editor/sortable.scss +12 -0
  52. data/app/assets/stylesheets/pageflow/mixins/buttons.scss +4 -4
  53. data/app/assets/stylesheets/pageflow/mixins/pageflow.scss +9 -5
  54. data/app/assets/stylesheets/pageflow/ui/color_picker.scss +230 -0
  55. data/app/assets/stylesheets/pageflow/ui/forms.scss +38 -4
  56. data/app/assets/stylesheets/pageflow/ui/functions.scss +12 -2
  57. data/app/assets/stylesheets/pageflow/ui/input/color_input.scss +9 -8
  58. data/app/assets/stylesheets/pageflow/ui/input/file_name_input.scss +37 -0
  59. data/app/assets/stylesheets/pageflow/ui/input/text_area_input.scss +15 -0
  60. data/app/assets/stylesheets/pageflow/ui/overrides.scss +8 -0
  61. data/app/assets/stylesheets/pageflow/ui/properties.scss +34 -0
  62. data/app/assets/stylesheets/pageflow/ui/tabs_view.scss +8 -3
  63. data/app/assets/stylesheets/pageflow/ui.scss +4 -1
  64. data/app/controllers/concerns/pageflow/controller_delegation.rb +1 -1
  65. data/app/controllers/concerns/pageflow/edit_locking.rb +17 -10
  66. data/app/controllers/concerns/pageflow/entry_password_protection.rb +1 -0
  67. data/app/controllers/concerns/pageflow/public_https_mode.rb +2 -1
  68. data/app/controllers/concerns/pageflow/quota_verification.rb +5 -4
  69. data/app/controllers/pageflow/admin/initial_passwords_controller.rb +1 -0
  70. data/app/controllers/pageflow/application_controller.rb +19 -19
  71. data/app/controllers/pageflow/chapters_controller.rb +3 -2
  72. data/app/controllers/pageflow/edit_locks_controller.rb +3 -2
  73. data/app/controllers/pageflow/editor/encoding_confirmations_controller.rb +1 -0
  74. data/app/controllers/pageflow/editor/entries_controller.rb +3 -1
  75. data/app/controllers/pageflow/editor/entry_publications_controller.rb +1 -0
  76. data/app/controllers/pageflow/editor/file_folders_controller.rb +80 -0
  77. data/app/controllers/pageflow/editor/file_import_controller.rb +4 -3
  78. data/app/controllers/pageflow/editor/files_controller.rb +20 -10
  79. data/app/controllers/pageflow/editor/oembeds_controller.rb +21 -0
  80. data/app/controllers/pageflow/editor/widgets_controller.rb +1 -0
  81. data/app/controllers/pageflow/entries_controller.rb +85 -21
  82. data/app/controllers/pageflow/feeds_controller.rb +1 -1
  83. data/app/controllers/pageflow/files_controller.rb +1 -0
  84. data/app/controllers/pageflow/pages_controller.rb +4 -2
  85. data/app/controllers/pageflow/review/comment_thread_reads_controller.rb +30 -0
  86. data/app/controllers/pageflow/review/comment_threads_controller.rb +60 -0
  87. data/app/controllers/pageflow/review/comments_controller.rb +53 -0
  88. data/app/controllers/pageflow/revisions_controller.rb +5 -1
  89. data/app/controllers/pageflow/sitemaps_controller.rb +1 -1
  90. data/app/controllers/pageflow/storylines_controller.rb +1 -0
  91. data/app/helpers/pageflow/admin/cutoff_modes_helper.rb +12 -0
  92. data/app/helpers/pageflow/admin/entries_helper.rb +41 -1
  93. data/app/helpers/pageflow/admin/entry_translations_helper.rb +18 -0
  94. data/app/helpers/pageflow/admin/features_helper.rb +1 -1
  95. data/app/helpers/pageflow/admin/form_helper.rb +3 -3
  96. data/app/helpers/pageflow/admin/locales_helper.rb +10 -2
  97. data/app/helpers/pageflow/admin/memberships_helper.rb +32 -32
  98. data/app/helpers/pageflow/admin/revisions_helper.rb +1 -1
  99. data/app/helpers/pageflow/admin/sites_helper.rb +22 -0
  100. data/app/helpers/pageflow/admin/users_helper.rb +7 -5
  101. data/app/helpers/pageflow/admin/widgets_helper.rb +5 -5
  102. data/app/helpers/pageflow/asset_urls_helper.rb +1 -1
  103. data/app/helpers/pageflow/audio_files_helper.rb +5 -2
  104. data/app/helpers/pageflow/background_image_helper.rb +7 -6
  105. data/app/helpers/pageflow/common_entry_seed_helper.rb +7 -7
  106. data/app/helpers/pageflow/editor/config_helper.rb +3 -1
  107. data/app/helpers/pageflow/editor/files_helper.rb +1 -1
  108. data/app/helpers/pageflow/embed_code_helper.rb +3 -3
  109. data/app/helpers/pageflow/entries_helper.rb +52 -46
  110. data/app/helpers/pageflow/entry_json_seed_helper.rb +7 -6
  111. data/app/helpers/pageflow/feeds_helper.rb +2 -2
  112. data/app/helpers/pageflow/file_background_images_helper.rb +2 -2
  113. data/app/helpers/pageflow/file_thumbnails_helper.rb +4 -3
  114. data/app/helpers/pageflow/files_helper.rb +5 -4
  115. data/app/helpers/pageflow/folders_helper.rb +8 -5
  116. data/app/helpers/pageflow/help_entries_helper.rb +2 -2
  117. data/app/helpers/pageflow/hreflang_links_helper.rb +37 -0
  118. data/app/helpers/pageflow/info_box_helper.rb +7 -11
  119. data/app/helpers/pageflow/media_query_helper.rb +3 -3
  120. data/app/helpers/pageflow/navigation_bar_helper.rb +1 -1
  121. data/app/helpers/pageflow/overview_helper.rb +1 -1
  122. data/app/helpers/pageflow/page_types_helper.rb +5 -5
  123. data/app/helpers/pageflow/pages_helper.rb +29 -15
  124. data/app/helpers/pageflow/public_i18n_helper.rb +10 -9
  125. data/app/helpers/pageflow/quota_helper.rb +4 -4
  126. data/app/helpers/pageflow/render_json_helper.rb +6 -3
  127. data/app/helpers/pageflow/revision_file_helper.rb +2 -1
  128. data/app/helpers/pageflow/sites_helper.rb +3 -3
  129. data/app/helpers/pageflow/social_share_helper.rb +24 -10
  130. data/app/helpers/pageflow/social_share_links_helper.rb +12 -9
  131. data/app/helpers/pageflow/structured_data_helper.rb +5 -2
  132. data/app/helpers/pageflow/stub_page_configuration.rb +7 -3
  133. data/app/helpers/pageflow/text_direction_helper.rb +1 -1
  134. data/app/helpers/pageflow/themes_helper.rb +2 -4
  135. data/app/helpers/pageflow/video_files_helper.rb +29 -13
  136. data/app/helpers/pageflow/widgets_helper.rb +8 -6
  137. data/app/inputs/pageflow_permalink_input.rb +8 -3
  138. data/app/jobs/pageflow/application_job.rb +1 -0
  139. data/app/jobs/pageflow/entry_export_import/upload_and_publish_file_job.rb +1 -1
  140. data/app/jobs/pageflow/poll_meta_data_from_zencoder_job.rb +1 -0
  141. data/app/jobs/pageflow/poll_zencoder_job.rb +3 -2
  142. data/app/jobs/pageflow/process_image_or_text_track_job.rb +1 -0
  143. data/app/jobs/pageflow/prune_auto_snapshots_job.rb +1 -0
  144. data/app/jobs/pageflow/request_meta_data_from_zencoder_job.rb +1 -0
  145. data/app/jobs/pageflow/submit_file_to_zencoder_job.rb +1 -0
  146. data/app/mailers/pageflow/user_mailer.rb +1 -0
  147. data/app/models/concerns/pageflow/auto_generated_perma_id.rb +20 -1
  148. data/app/models/concerns/pageflow/entry_publication_states.rb +7 -3
  149. data/app/models/concerns/pageflow/feature_target.rb +8 -4
  150. data/app/models/concerns/pageflow/output_source.rb +3 -3
  151. data/app/models/concerns/pageflow/permalinkable.rb +2 -1
  152. data/app/models/concerns/pageflow/reusable_file.rb +24 -24
  153. data/app/models/concerns/pageflow/serialization_blacklist.rb +3 -5
  154. data/app/models/concerns/pageflow/suspendable.rb +5 -3
  155. data/app/models/concerns/pageflow/theme_referencer.rb +1 -1
  156. data/app/models/concerns/pageflow/translatable.rb +62 -0
  157. data/app/models/concerns/pageflow/translated_attributes.rb +101 -0
  158. data/app/models/concerns/pageflow/uploadable_file.rb +6 -6
  159. data/app/models/pageflow/account.rb +6 -5
  160. data/app/models/pageflow/account_member_query.rb +1 -1
  161. data/app/models/pageflow/account_role_query.rb +1 -1
  162. data/app/models/pageflow/application_query.rb +1 -1
  163. data/app/models/pageflow/application_record.rb +1 -1
  164. data/app/models/pageflow/audio_file.rb +4 -4
  165. data/app/models/pageflow/audio_file_url_templates.rb +1 -1
  166. data/app/models/pageflow/authentication_token.rb +2 -2
  167. data/app/models/pageflow/chapter.rb +6 -1
  168. data/app/models/pageflow/chapter_scaffold.rb +2 -4
  169. data/app/models/pageflow/cname_site_request_scope.rb +1 -1
  170. data/app/models/pageflow/comment.rb +30 -0
  171. data/app/models/pageflow/comment_thread.rb +65 -0
  172. data/app/models/pageflow/comment_thread_read.rb +22 -0
  173. data/app/models/pageflow/customized_theme.rb +9 -8
  174. data/app/models/pageflow/draft_entry.rb +49 -9
  175. data/app/models/pageflow/edit_lock.rb +19 -21
  176. data/app/models/pageflow/encoding_confirmation.rb +2 -2
  177. data/app/models/pageflow/entries_feed.rb +2 -2
  178. data/app/models/pageflow/entry.rb +46 -30
  179. data/app/models/pageflow/entry_at_revision.rb +14 -2
  180. data/app/models/pageflow/entry_comment_summary.rb +114 -0
  181. data/app/models/pageflow/entry_duplicate.rb +8 -5
  182. data/app/models/pageflow/entry_publication.rb +2 -2
  183. data/app/models/pageflow/entry_role_query.rb +4 -4
  184. data/app/models/pageflow/entry_template.rb +4 -4
  185. data/app/models/pageflow/entry_title_or_account_name_query.rb +2 -2
  186. data/app/models/pageflow/entry_translation_group.rb +42 -0
  187. data/app/models/pageflow/file_folder.rb +74 -0
  188. data/app/models/pageflow/file_reuse.rb +5 -4
  189. data/app/models/pageflow/file_usage.rb +18 -3
  190. data/app/models/pageflow/folder.rb +2 -2
  191. data/app/models/pageflow/home_button.rb +7 -7
  192. data/app/models/pageflow/image_file.rb +44 -25
  193. data/app/models/pageflow/image_file_url_templates.rb +4 -4
  194. data/app/models/pageflow/invitation_form.rb +2 -1
  195. data/app/models/pageflow/legal_info.rb +38 -0
  196. data/app/models/pageflow/managed_user_query.rb +1 -1
  197. data/app/models/pageflow/membership.rb +5 -5
  198. data/app/models/pageflow/nested_revision_component_copy.rb +263 -0
  199. data/app/models/pageflow/null_user.rb +1 -1
  200. data/app/models/pageflow/overview_button.rb +1 -1
  201. data/app/models/pageflow/page.rb +7 -3
  202. data/app/models/pageflow/permalink.rb +24 -2
  203. data/app/models/pageflow/permalink_directory.rb +7 -0
  204. data/app/models/pageflow/permalink_redirect.rb +7 -0
  205. data/app/models/pageflow/positioned_file.rb +5 -5
  206. data/app/models/pageflow/potential_entry_translations.rb +55 -0
  207. data/app/models/pageflow/potential_memberships.rb +5 -4
  208. data/app/models/pageflow/published_entry.rb +62 -11
  209. data/app/models/pageflow/revision.rb +29 -16
  210. data/app/models/pageflow/roles.rb +14 -18
  211. data/app/models/pageflow/site.rb +46 -3
  212. data/app/models/pageflow/site_root_entry_form.rb +27 -0
  213. data/app/models/pageflow/sitemaps.rb +10 -1
  214. data/app/models/pageflow/storyline.rb +5 -2
  215. data/app/models/pageflow/storyline_scaffold.rb +1 -1
  216. data/app/models/pageflow/text_track_file.rb +1 -1
  217. data/app/models/pageflow/text_track_file_url_templates.rb +1 -1
  218. data/app/models/pageflow/theme_customization_file.rb +3 -2
  219. data/app/models/pageflow/thumbnail_file_resolver.rb +1 -1
  220. data/app/models/pageflow/url_template.rb +1 -1
  221. data/app/models/pageflow/used_file.rb +13 -3
  222. data/app/models/pageflow/user_name_query.rb +2 -2
  223. data/app/models/pageflow/video_file.rb +22 -15
  224. data/app/models/pageflow/video_file_url_templates.rb +6 -4
  225. data/app/models/pageflow/widget.rb +5 -4
  226. data/app/models/pageflow/with_file_usage_extension.rb +1 -1
  227. data/app/models/pageflow/zencoder_attachment.rb +8 -8
  228. data/app/policies/pageflow/account_policy.rb +3 -1
  229. data/app/policies/pageflow/admin/admin_only_tab_policy.rb +1 -0
  230. data/app/policies/pageflow/admin/entry_tab_policy.rb +1 -0
  231. data/app/policies/pageflow/application_policy.rb +2 -0
  232. data/app/policies/pageflow/entry_policy.rb +7 -1
  233. data/app/policies/pageflow/entry_template_policy.rb +2 -1
  234. data/app/policies/pageflow/file_policy.rb +4 -7
  235. data/app/policies/pageflow/folder_policy.rb +18 -8
  236. data/app/policies/pageflow/membership_policy.rb +6 -4
  237. data/app/policies/pageflow/site_policy.rb +10 -3
  238. data/app/policies/pageflow/user_policy.rb +6 -4
  239. data/app/state_machines/pageflow/image_and_text_track_processing_state_machine.rb +3 -2
  240. data/app/state_machines/pageflow/media_encoding_state_machine.rb +5 -4
  241. data/app/views/admin/accounts/_entry_template_details.html.arb +2 -2
  242. data/app/views/admin/entries/_attributes_table.html.arb +6 -5
  243. data/app/views/admin/entries/_form.html.erb +2 -1
  244. data/app/views/admin/entries/_permalink_inputs.html.erb +9 -2
  245. data/app/views/admin/entry_templates/_form.html.erb +1 -3
  246. data/app/views/admin/site_root_entry/choose.html.erb +19 -0
  247. data/app/views/admin/sites/_fields.html.erb +14 -1
  248. data/app/views/admin/translations/_form.html.erb +31 -0
  249. data/app/views/admin/users/_attributes_table.html.arb +13 -0
  250. data/app/views/components/pageflow/admin/add_membership_button.rb +13 -12
  251. data/app/views/components/pageflow/admin/custom_scopes_renderer.rb +1 -0
  252. data/app/views/components/pageflow/admin/embed_code_field.rb +1 -0
  253. data/app/views/components/pageflow/admin/embedded_index_table.rb +9 -10
  254. data/app/views/components/pageflow/admin/entries_tab.rb +1 -0
  255. data/app/views/components/pageflow/admin/entry_publication_state_indicator.rb +6 -5
  256. data/app/views/components/pageflow/admin/entry_templates_tab.rb +2 -1
  257. data/app/views/components/pageflow/admin/entry_translations_tab.rb +102 -0
  258. data/app/views/components/pageflow/admin/entry_user_badge_list.rb +1 -0
  259. data/app/views/components/pageflow/admin/extensible_attributes_table.rb +9 -8
  260. data/app/views/components/pageflow/admin/features_tab.rb +1 -0
  261. data/app/views/components/pageflow/admin/grouped_folder_list.rb +1 -0
  262. data/app/views/components/pageflow/admin/icon_link_to.rb +1 -0
  263. data/app/views/components/pageflow/admin/members_tab.rb +4 -3
  264. data/app/views/components/pageflow/admin/membership_role_with_tooltip.rb +3 -2
  265. data/app/views/components/pageflow/admin/revisions_tab.rb +14 -10
  266. data/app/views/components/pageflow/admin/sites_tab.rb +1 -0
  267. data/app/views/components/pageflow/admin/tabs_view.rb +1 -0
  268. data/app/views/components/pageflow/admin/timestamp.rb +6 -5
  269. data/app/views/components/pageflow/admin/user_account_badge_list.rb +2 -3
  270. data/app/views/components/pageflow/admin/user_accounts_tab.rb +1 -0
  271. data/app/views/components/pageflow/admin/user_entries_tab.rb +1 -0
  272. data/app/views/components/pageflow/admin/users_tab.rb +1 -0
  273. data/app/views/pageflow/audio_files/_audio_file.json.jbuilder +0 -1
  274. data/app/views/pageflow/editor/config/_seeds.json.jbuilder +5 -3
  275. data/app/views/pageflow/editor/entries/_entry.json.jbuilder +2 -1
  276. data/app/views/pageflow/editor/entries/index.json.jbuilder +1 -1
  277. data/app/views/pageflow/editor/entries/seed.json.erb +1 -0
  278. data/app/views/pageflow/editor/entries/show.json.jbuilder +1 -1
  279. data/app/views/pageflow/editor/entry_publications/check.json.jbuilder +2 -2
  280. data/app/views/pageflow/editor/file_folders/_file_folder.json.jbuilder +5 -0
  281. data/app/views/pageflow/editor/file_folders/create.json.jbuilder +1 -0
  282. data/app/views/pageflow/editor/file_folders/index.json.jbuilder +3 -0
  283. data/app/views/pageflow/editor/files/_file.json.jbuilder +7 -14
  284. data/app/views/pageflow/editor/files/create.json.jbuilder +1 -1
  285. data/app/views/pageflow/editor/files/index.json.jbuilder +1 -1
  286. data/app/views/pageflow/editor/image_files/_image_file.json.jbuilder +3 -0
  287. data/app/views/pageflow/editor/sites/_site.json.jbuilder +1 -0
  288. data/app/views/pageflow/editor/video_files/_video_file.json.jbuilder +4 -3
  289. data/app/views/pageflow/entries/share_menu/_bluesky_link.html.erb +8 -0
  290. data/app/views/pageflow/entries/share_menu/_threads_link.html.erb +8 -0
  291. data/app/views/pageflow/files/_file.json.jbuilder +5 -3
  292. data/app/views/pageflow/image_files/_image_file.json.jbuilder +0 -1
  293. data/app/views/pageflow/review/comment_threads/_comment_thread.json.jbuilder +20 -0
  294. data/app/views/pageflow/review/comment_threads/create.json.jbuilder +2 -0
  295. data/app/views/pageflow/review/comment_threads/index.json.jbuilder +13 -0
  296. data/app/views/pageflow/review/comments/_comment.json.jbuilder +13 -0
  297. data/app/views/pageflow/review/comments/create.json.jbuilder +1 -0
  298. data/app/views/pageflow/sitemaps/index.xml.builder +9 -1
  299. data/app/views/pageflow/social_share/_entry_meta_tags.html.erb +1 -1
  300. data/app/views/pageflow/social_share/_page_meta_tags.html.erb +1 -1
  301. data/app/views/pageflow/structured_data/_entry.json.jbuilder +2 -3
  302. data/app/views/pageflow/video_files/_video_file.json.jbuilder +0 -1
  303. data/config/initializers/active_admin_patches.rb +3 -6
  304. data/config/initializers/admin_resource_tabs.rb +3 -0
  305. data/config/initializers/paperclip.rb +1 -0
  306. data/config/initializers/symmetric_encryption.rb +1 -1
  307. data/config/initializers/zencoder.rb +24 -13
  308. data/config/locales/de.yml +256 -12
  309. data/config/locales/en.yml +253 -15
  310. data/config/routes.rb +29 -13
  311. data/config/spring.rb +2 -1
  312. data/db/migrate/20140418225525_setup_schema.rb +2 -2
  313. data/db/migrate/20190306161431_copy_file_attributes_of_failed_uploads.rb +2 -2
  314. data/db/migrate/20190820152900_drop_accounts_themes.rb +2 -1
  315. data/db/migrate/20191202145757_create_pageflow_scrolled_sections.rb +11 -11
  316. data/db/migrate/20191202150657_create_pageflow_scrolled_chapters.rb +1 -1
  317. data/db/migrate/20191202154723_create_pageflow_scrolled_content_elements.rb +9 -9
  318. data/db/migrate/20191219143450_add_position_to_content_elements.rb +2 -1
  319. data/db/migrate/20200117133200_change_revision_appearance_option_default_and_null.rb +2 -1
  320. data/db/migrate/20200122115400_create_pageflow_entry_templates.rb +25 -25
  321. data/db/migrate/20200206134400_convert_legacy_scrolled_content_element_types.rb +3 -3
  322. data/db/migrate/20221215120856_associate_entry_templates_with_sites.rb +2 -2
  323. data/db/migrate/20230120092923_create_other_files.rb +2 -1
  324. data/db/migrate/20230419083307_create_pageflow_entry_translation_group.rb +9 -0
  325. data/db/migrate/20240612110434_add_cutoff_mode_name_to_sites.rb +5 -0
  326. data/db/migrate/20240918084059_create_pageflow_permalink_redirects.rb +14 -0
  327. data/db/migrate/20250508172234_ensure_scrolled_entries_have_main_storyline.rb +14 -0
  328. data/db/migrate/20250617090048_add_custom404_entry_to_sites.rb +5 -0
  329. data/db/migrate/20250617100000_add_perma_id_counter_to_entries.rb +28 -0
  330. data/db/migrate/20250722174123_add_perma_id_to_chapters.rb +10 -0
  331. data/db/migrate/20250725080603_add_perma_id_indexes_to_revision_components.rb +13 -0
  332. data/db/migrate/20250726000000_add_display_name_to_file_usages.rb +5 -0
  333. data/db/migrate/20251015000000_add_structured_data_type_name_to_revisions.rb +5 -0
  334. data/db/migrate/20251029142849_convert_legacy_social_embeds_to_unified_social_embed.rb +38 -0
  335. data/db/migrate/20251119083347_fix_main_storyline_positions.rb +16 -0
  336. data/db/migrate/20251119083348_ensure_scrolled_entries_have_excursion_storyline.rb +15 -0
  337. data/db/migrate/20260303000000_add_layout_version_to_revisions.rb +6 -0
  338. data/db/migrate/20260323000000_create_comment_threads_and_comments.rb +30 -0
  339. data/db/migrate/20260414000000_add_subject_range_to_comment_threads.rb +5 -0
  340. data/db/migrate/20260415000000_add_section_perma_id_to_comment_threads.rb +5 -0
  341. data/db/migrate/20260727000000_add_quote_to_comments.rb +5 -0
  342. data/db/migrate/20260728000000_create_file_folders.rb +17 -0
  343. data/db/migrate/20260805000000_add_attribute_translations_to_sites.rb +5 -0
  344. data/db/migrate/20260806000000_add_edited_at_to_comments.rb +5 -0
  345. data/db/migrate/20260810000000_create_pageflow_scrolled_lottie_files.rb +24 -0
  346. data/db/migrate/20260817000000_create_comment_thread_reads.rb +16 -0
  347. data/db/migrate/20260819000000_add_unread_comments_since_at_to_users.rb +18 -0
  348. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/editor.js +12599 -5398
  349. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/frontend.js +1275 -4560
  350. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/react-client.js +20204 -22
  351. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/react-server.js +18657 -19
  352. data/entry_types/paged/app/controllers/pageflow_paged/entries_controller.rb +1 -0
  353. data/entry_types/paged/app/helpers/pageflow_paged/page_background_asset_helper.rb +1 -1
  354. data/entry_types/paged/app/helpers/pageflow_paged/third_party_embed_consent_helper.rb +7 -7
  355. data/entry_types/paged/app/views/pageflow_paged/editor/entries/_seed.json.jbuilder +1 -0
  356. data/entry_types/paged/app/views/pageflow_paged/entries/show.html.erb +1 -0
  357. data/entry_types/paged/lib/pageflow_paged/plugin.rb +4 -0
  358. data/entry_types/paged/lib/pageflow_paged/react/page_type.rb +1 -1
  359. data/entry_types/paged/lib/pageflow_paged/react/widget_type.rb +3 -3
  360. data/entry_types/paged/lib/pageflow_paged.rb +1 -1
  361. data/entry_types/scrolled/app/assets/stylesheets/pageflow_scrolled/ui.scss +2 -0
  362. data/entry_types/scrolled/app/controllers/pageflow_scrolled/editor/chapters_controller.rb +5 -3
  363. data/entry_types/scrolled/app/controllers/pageflow_scrolled/editor/content_elements_controller.rb +35 -5
  364. data/entry_types/scrolled/app/controllers/pageflow_scrolled/editor/sections_controller.rb +4 -5
  365. data/entry_types/scrolled/app/controllers/pageflow_scrolled/entries_controller.rb +23 -2
  366. data/entry_types/scrolled/app/helpers/pageflow_scrolled/cache_helper.rb +3 -3
  367. data/entry_types/scrolled/app/helpers/pageflow_scrolled/editor/entry_json_seed_helper.rb +8 -5
  368. data/entry_types/scrolled/app/helpers/pageflow_scrolled/editor/seed_html_helper.rb +7 -3
  369. data/entry_types/scrolled/app/helpers/pageflow_scrolled/entry_json_seed_helper.rb +72 -10
  370. data/entry_types/scrolled/app/helpers/pageflow_scrolled/i18n_helper.rb +28 -13
  371. data/entry_types/scrolled/app/helpers/pageflow_scrolled/packs_helper.rb +41 -12
  372. data/entry_types/scrolled/app/helpers/pageflow_scrolled/react_server_side_rendering_helper.rb +23 -25
  373. data/entry_types/scrolled/app/helpers/pageflow_scrolled/sprockets_helper.rb +16 -0
  374. data/entry_types/scrolled/app/helpers/pageflow_scrolled/themes_helper.rb +189 -3
  375. data/entry_types/scrolled/app/models/pageflow_scrolled/chapter.rb +15 -14
  376. data/entry_types/scrolled/app/models/pageflow_scrolled/content_element.rb +61 -7
  377. data/entry_types/scrolled/app/models/pageflow_scrolled/lottie_file.rb +6 -0
  378. data/entry_types/scrolled/app/models/pageflow_scrolled/lottie_file_url_templates.rb +16 -0
  379. data/entry_types/scrolled/app/models/pageflow_scrolled/section.rb +12 -1
  380. data/entry_types/scrolled/app/models/pageflow_scrolled/storyline.rb +20 -1
  381. data/entry_types/scrolled/app/views/pageflow_scrolled/editor/entries/_head.html.erb +1 -0
  382. data/entry_types/scrolled/app/views/pageflow_scrolled/editor/sections/_section_with_content_elements.json.jbuilder +2 -2
  383. data/entry_types/scrolled/app/views/pageflow_scrolled/entries/show.html.erb +15 -12
  384. data/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_entry.json.jbuilder +45 -17
  385. data/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_entry_translations.json.jbuilder +14 -0
  386. data/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_theme.json.jbuilder +34 -5
  387. data/entry_types/scrolled/app/views/pageflow_scrolled/favicons/_entry.html.erb +1 -1
  388. data/entry_types/scrolled/app/views/pageflow_scrolled/storylines/_storyline.json.jbuilder +7 -0
  389. data/entry_types/scrolled/config/configuration_schemas/pageflow-scrolled.json +414 -0
  390. data/entry_types/scrolled/config/locales/de.yml +1094 -78
  391. data/entry_types/scrolled/config/locales/en.yml +1083 -78
  392. data/entry_types/scrolled/config/routes.rb +18 -8
  393. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/install_generator.rb +11 -11
  394. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/templates/theme/logoDarkVariantDesktop.svg +56 -0
  395. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/templates/theme/logoDarkVariantMobile.svg +22 -0
  396. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/templates/themes_plugin.rb.tt +26 -11
  397. data/entry_types/scrolled/lib/pageflow_scrolled/additional_packs.rb +27 -8
  398. data/entry_types/scrolled/lib/pageflow_scrolled/additional_seed_data.rb +2 -2
  399. data/entry_types/scrolled/lib/pageflow_scrolled/additional_theme_assets.rb +27 -0
  400. data/entry_types/scrolled/lib/pageflow_scrolled/configuration.rb +67 -10
  401. data/entry_types/scrolled/lib/pageflow_scrolled/configuration_schemas.rb +91 -0
  402. data/entry_types/scrolled/lib/pageflow_scrolled/content_element_consent_vendors.rb +1 -1
  403. data/entry_types/scrolled/lib/pageflow_scrolled/engine.rb +2 -1
  404. data/entry_types/scrolled/lib/pageflow_scrolled/entry_file_reference_locations.rb +71 -0
  405. data/entry_types/scrolled/lib/pageflow_scrolled/entry_structured_data_types/faq_page.rb +58 -0
  406. data/entry_types/scrolled/lib/pageflow_scrolled/file_reference_locations.rb +69 -0
  407. data/entry_types/scrolled/lib/pageflow_scrolled/plugin.rb +222 -19
  408. data/entry_types/scrolled/lib/pageflow_scrolled/react_widget_type.rb +2 -4
  409. data/entry_types/scrolled/lib/pageflow_scrolled/seeds.rb +76 -54
  410. data/entry_types/scrolled/lib/pageflow_scrolled/theme_options_default_scale.rb +35 -0
  411. data/entry_types/scrolled/lib/pageflow_scrolled.rb +14 -1
  412. data/entry_types/scrolled/lib/tasks/pageflow_scrolled/storybook.rake +24 -5
  413. data/entry_types/scrolled/package/config/configurationSchemas.js +70 -0
  414. data/entry_types/scrolled/package/config/rollup/configurationSchemas.js +19 -0
  415. data/entry_types/scrolled/package/config/webpack.js +94 -0
  416. data/entry_types/scrolled/package/contentElements/hotspots-frontend.css +1 -0
  417. data/entry_types/scrolled/package/contentElements/hotspots-frontend.js +1795 -0
  418. data/entry_types/scrolled/package/contentElements/inlineBeforeAfter-frontend.css +1 -0
  419. data/entry_types/scrolled/package/contentElements/inlineBeforeAfter-frontend.js +219 -0
  420. data/entry_types/scrolled/package/contentElements/lottieAnimation-frontend.css +1 -0
  421. data/entry_types/scrolled/package/contentElements/lottieAnimation-frontend.js +244 -0
  422. data/entry_types/scrolled/package/contentElements/socialEmbed-frontend.css +1 -0
  423. data/entry_types/scrolled/package/contentElements/socialEmbed-frontend.js +823 -0
  424. data/entry_types/scrolled/package/contentElements/tikTokEmbed-frontend.css +1 -0
  425. data/entry_types/scrolled/package/contentElements/tikTokEmbed-frontend.js +109 -0
  426. data/entry_types/scrolled/package/contentElements/twitterEmbed-frontend.css +1 -0
  427. data/entry_types/scrolled/package/contentElements/twitterEmbed-frontend.js +277 -0
  428. data/entry_types/scrolled/package/contentElements/videoEmbed-frontend.css +1 -0
  429. data/entry_types/scrolled/package/contentElements/videoEmbed-frontend.js +244 -0
  430. data/entry_types/scrolled/package/contentElements-editor.js +3155 -583
  431. data/entry_types/scrolled/package/contentElements-frontend.css +1 -1
  432. data/entry_types/scrolled/package/contentElements-frontend.js +3375 -1585
  433. data/entry_types/scrolled/package/editor.css +1 -0
  434. data/entry_types/scrolled/package/editor.js +8452 -2867
  435. data/entry_types/scrolled/package/entryState.js +1600 -0
  436. data/entry_types/scrolled/package/frontend/FloatingPortalRootProvider-20c600de.js +1979 -0
  437. data/entry_types/scrolled/package/frontend/FloatingPortalRootProvider-58189220.js +2538 -0
  438. data/entry_types/scrolled/package/frontend/{PhonePlatformContext-4ec6b2de.js → PhonePlatformContext-035a99fa.js} +9 -15
  439. data/entry_types/scrolled/package/frontend/PhonePlatformContext-9da43797.js +33 -0
  440. data/entry_types/scrolled/package/frontend/Placeholder.module-bf0966b4.js +5267 -0
  441. data/entry_types/scrolled/package/frontend/Placeholder.module-d22a9335.js +4180 -0
  442. data/entry_types/scrolled/package/frontend/ThemeIcon-ab834849.js +754 -0
  443. data/entry_types/scrolled/package/frontend/ThemeIcon-f6cb3a8f.js +773 -0
  444. data/entry_types/scrolled/package/frontend/ToggleFullscreenCornerButton-30fd1124.js +39 -0
  445. data/entry_types/scrolled/package/frontend/ToggleFullscreenCornerButton-61c25224.js +72 -0
  446. data/entry_types/scrolled/package/frontend/Viewer-1074fd59.js +147 -0
  447. data/entry_types/scrolled/package/frontend/Viewer-1482ca34.js +480 -0
  448. data/entry_types/scrolled/package/frontend/Viewer-70504231.js +210 -0
  449. data/entry_types/scrolled/package/frontend/{Viewer-1bb5597c.js → Viewer-cc8d4072.js} +100 -135
  450. data/entry_types/scrolled/package/frontend/Wavesurfer-656e3c36.js +302 -0
  451. data/entry_types/scrolled/package/frontend/Wavesurfer-b753b838.js +385 -0
  452. data/entry_types/scrolled/package/frontend/commenting.css +1 -0
  453. data/entry_types/scrolled/package/frontend/extensions-167ae143.js +1455 -0
  454. data/entry_types/scrolled/package/frontend/extensions-2318f92b.js +5918 -0
  455. data/entry_types/scrolled/package/frontend/extensions-a461fd13.js +4890 -0
  456. data/entry_types/scrolled/package/frontend/extensions-c98269fd.js +1982 -0
  457. data/entry_types/scrolled/package/frontend/i18n-493cd2a6.js +93 -0
  458. data/entry_types/scrolled/package/frontend/i18n-e06cac14.js +100 -0
  459. data/entry_types/scrolled/package/frontend/{index-11f32f10.js → index-2e5546f7.js} +39 -54
  460. data/entry_types/scrolled/package/frontend/index-de2b418d.js +130 -0
  461. data/entry_types/scrolled/package/frontend/index.css +1 -1
  462. data/entry_types/scrolled/package/frontend/index.js +1976 -1367
  463. data/entry_types/scrolled/package/frontend/inlineEditing.css +1 -0
  464. data/entry_types/scrolled/package/frontend/useContentElementEditorState-a084912e.js +25 -0
  465. data/entry_types/scrolled/package/frontend/useDelayedBoolean-a387d85b.js +24 -0
  466. data/entry_types/scrolled/package/frontend/usePhonePlatform-4ecb96d4.js +8 -0
  467. data/entry_types/scrolled/package/frontend/usePhonePlatform-ce9ff08d.js +8 -0
  468. data/entry_types/scrolled/package/frontend-server.js +20 -210
  469. data/entry_types/scrolled/package/package.json +22 -12
  470. data/entry_types/scrolled/package/review.css +1 -0
  471. data/entry_types/scrolled/package/review.js +3306 -0
  472. data/entry_types/scrolled/package/testHelpers.js +952 -239
  473. data/entry_types/scrolled/package/values/widgets.module.css +18 -0
  474. data/entry_types/scrolled/package/widgets/consentBar.css +1 -1
  475. data/entry_types/scrolled/package/widgets/consentBar.js +275 -315
  476. data/entry_types/scrolled/package/widgets/defaultNavigation.css +2 -2
  477. data/entry_types/scrolled/package/widgets/defaultNavigation.js +961 -432
  478. data/entry_types/scrolled/package/widgets/excursionSheet.css +1 -0
  479. data/entry_types/scrolled/package/widgets/excursionSheet.js +225 -0
  480. data/entry_types/scrolled/package/widgets/iconInlineFileRights.css +1 -1
  481. data/entry_types/scrolled/package/widgets/iconInlineFileRights.js +62 -32
  482. data/entry_types/scrolled/package/widgets/iconScrollIndicator.css +1 -0
  483. data/entry_types/scrolled/package/widgets/iconScrollIndicator.js +67 -0
  484. data/entry_types/scrolled/package/widgets/mainStorylineSheet.css +1 -0
  485. data/entry_types/scrolled/package/widgets/mainStorylineSheet.js +100 -0
  486. data/entry_types/scrolled/package/widgets/textInlineFileRights.css +1 -1
  487. data/entry_types/scrolled/package/widgets/textInlineFileRights.js +48 -26
  488. data/entry_types/scrolled/package/widgets-server.js +2 -0
  489. data/entry_types/scrolled/spec/factories/chapters.rb +14 -1
  490. data/entry_types/scrolled/spec/factories/content_elements.rb +1 -1
  491. data/entry_types/scrolled/spec/factories/lottie_files.rb +29 -0
  492. data/entry_types/scrolled/spec/fixtures/animation.lottie +0 -0
  493. data/entry_types/scrolled/spec/fixtures/font.woff +0 -0
  494. data/entry_types/scrolled/spec/fixtures/font.woff2 +0 -0
  495. data/lib/generators/pageflow/active_admin_initializer/active_admin_initializer_generator.rb +5 -3
  496. data/lib/generators/pageflow/assets/assets_generator.rb +7 -5
  497. data/lib/generators/pageflow/cancan/cancan_generator.rb +2 -1
  498. data/lib/generators/pageflow/cancan/templates/ability.rb +1 -1
  499. data/lib/generators/pageflow/error_pages/error_pages_generator.rb +2 -1
  500. data/lib/generators/pageflow/initializer/initializer_generator.rb +3 -2
  501. data/lib/generators/pageflow/install/install_generator.rb +2 -2
  502. data/lib/generators/pageflow/procfile/procfile_generator.rb +2 -1
  503. data/lib/generators/pageflow/resque/resque_generator.rb +4 -4
  504. data/lib/generators/pageflow/resque/templates/resque.rake +1 -1
  505. data/lib/generators/pageflow/routes/routes_generator.rb +4 -2
  506. data/lib/generators/pageflow/seeds/seeds_generator.rb +3 -2
  507. data/lib/generators/pageflow/seeds/templates/seeds.rb +6 -6
  508. data/lib/generators/pageflow/theme/theme_generator.rb +2 -1
  509. data/lib/generators/pageflow/user/user_generator.rb +2 -1
  510. data/lib/pageflow/ability_mixin.rb +25 -15
  511. data/lib/pageflow/active_admin_patches/views/attributes_table.rb +1 -0
  512. data/lib/pageflow/active_admin_patches/views/pages/base.rb +3 -2
  513. data/lib/pageflow/active_admin_patches/views/table_for.rb +1 -0
  514. data/lib/pageflow/additional_headers.rb +27 -0
  515. data/lib/pageflow/admin/attributes_table_rows.rb +3 -3
  516. data/lib/pageflow/admin/tabs.rb +1 -1
  517. data/lib/pageflow/built_in_file_type.rb +1 -1
  518. data/lib/pageflow/built_in_page_types_plugin.rb +1 -1
  519. data/lib/pageflow/built_in_widget_type.rb +2 -2
  520. data/lib/pageflow/built_in_widget_types_plugin.rb +2 -1
  521. data/lib/pageflow/configuration.rb +183 -18
  522. data/lib/pageflow/cutoff_modes.rb +39 -0
  523. data/lib/pageflow/deprecation.rb +19 -0
  524. data/lib/pageflow/editor_controller.rb +6 -10
  525. data/lib/pageflow/engine.rb +5 -6
  526. data/lib/pageflow/entries_controller_env_helper.rb +32 -2
  527. data/lib/pageflow/entry_export_import/attachment_files.rb +1 -1
  528. data/lib/pageflow/entry_export_import/entry_serialization.rb +9 -8
  529. data/lib/pageflow/entry_export_import/file_mappings.rb +1 -0
  530. data/lib/pageflow/entry_export_import/page_type_versions.rb +2 -2
  531. data/lib/pageflow/entry_export_import/revision_serialization/import.rb +11 -1
  532. data/lib/pageflow/entry_export_import/revision_serialization.rb +3 -0
  533. data/lib/pageflow/entry_export_import.rb +3 -3
  534. data/lib/pageflow/entry_structured_data_types.rb +43 -0
  535. data/lib/pageflow/entry_type_configuration.rb +1 -0
  536. data/lib/pageflow/entry_types.rb +2 -2
  537. data/lib/pageflow/feature.rb +1 -1
  538. data/lib/pageflow/features.rb +4 -6
  539. data/lib/pageflow/file_importers.rb +4 -4
  540. data/lib/pageflow/file_type.rb +5 -5
  541. data/lib/pageflow/file_types.rb +4 -4
  542. data/lib/pageflow/global_config_api.rb +5 -6
  543. data/lib/pageflow/help_entries.rb +7 -7
  544. data/lib/pageflow/help_entry.rb +1 -1
  545. data/lib/pageflow/hooks.rb +1 -1
  546. data/lib/pageflow/nested_revision_component.rb +9 -27
  547. data/lib/pageflow/news_item_api.rb +1 -1
  548. data/lib/pageflow/oembed_providers.rb +42 -0
  549. data/lib/pageflow/page_type.rb +2 -3
  550. data/lib/pageflow/page_types.rb +3 -3
  551. data/lib/pageflow/paperclip_interpolations/support.rb +1 -1
  552. data/lib/pageflow/paperclip_processors/vtt.rb +1 -0
  553. data/lib/pageflow/paperclip_processors/webp.rb +2 -2
  554. data/lib/pageflow/partial_editor_fragment_renderer.rb +2 -2
  555. data/lib/pageflow/plugin.rb +1 -2
  556. data/lib/pageflow/primary_domain_entry_redirect.rb +6 -0
  557. data/lib/pageflow/quota.rb +9 -5
  558. data/lib/pageflow/quotas.rb +1 -1
  559. data/lib/pageflow/rails_version.rb +14 -2
  560. data/lib/pageflow/react.rb +1 -1
  561. data/lib/pageflow/revision_component.rb +8 -40
  562. data/lib/pageflow/revision_components.rb +16 -6
  563. data/lib/pageflow/seeds.rb +12 -16
  564. data/lib/pageflow/theme.rb +1 -1
  565. data/lib/pageflow/theme_customizations.rb +10 -10
  566. data/lib/pageflow/themes.rb +44 -3
  567. data/lib/pageflow/user_mixin.rb +18 -6
  568. data/lib/pageflow/version.rb +1 -1
  569. data/lib/pageflow/widget_type.rb +4 -4
  570. data/lib/pageflow/widget_types.rb +9 -9
  571. data/lib/pageflow/zencoder_api.rb +32 -42
  572. data/lib/pageflow/zencoder_audio_output_definition.rb +14 -13
  573. data/lib/pageflow/zencoder_meta_data_output_definition.rb +3 -2
  574. data/lib/pageflow/zencoder_output_definition.rb +16 -14
  575. data/lib/pageflow/zencoder_video_output_definition.rb +140 -88
  576. data/lib/pageflow.rb +8 -2
  577. data/lib/tasks/pageflow_tasks.rake +1 -1
  578. data/package/config/eslint-rules/documented-in-toc.js +125 -0
  579. data/package/config/jest/index.js +0 -1
  580. data/package/config/webpack.js +0 -1
  581. data/package/config/webpack5.js +0 -1
  582. data/package/editor.js +4880 -2313
  583. data/package/frontend.js +710 -1223
  584. data/package/package.json +3 -1
  585. data/package/review.js +384 -0
  586. data/package/testHelpers.js +257 -243
  587. data/package/ui.js +1487 -813
  588. data/package/vendor/stubs/wysihtml5.js +2 -0
  589. data/spec/factories/accounts.rb +37 -22
  590. data/spec/factories/audio_files.rb +2 -2
  591. data/spec/factories/authentication_tokens.rb +4 -4
  592. data/spec/factories/chapters.rb +4 -4
  593. data/spec/factories/comment_thread_reads.rb +10 -0
  594. data/spec/factories/comment_threads.rb +10 -0
  595. data/spec/factories/comments.rb +9 -0
  596. data/spec/factories/draft_entries.rb +14 -6
  597. data/spec/factories/edit_locks.rb +1 -1
  598. data/spec/factories/entries.rb +28 -19
  599. data/spec/factories/entry_translation_groups.rb +6 -0
  600. data/spec/factories/file_folders.rb +8 -0
  601. data/spec/factories/file_usages.rb +2 -1
  602. data/spec/factories/folders.rb +1 -1
  603. data/spec/factories/image_files.rb +2 -2
  604. data/spec/factories/pages.rb +3 -3
  605. data/spec/factories/published_entries.rb +28 -8
  606. data/spec/factories/revisions.rb +1 -1
  607. data/spec/factories/sites.rb +6 -0
  608. data/spec/factories/test_multi_attachment_files.rb +1 -1
  609. data/spec/factories/text_track_files.rb +1 -1
  610. data/spec/factories/uploadable_files.rb +1 -1
  611. data/spec/factories/users.rb +6 -6
  612. data/spec/factories/video_files.rb +2 -2
  613. data/spec/factories/widgets.rb +1 -1
  614. data/spec/fixtures/7x15_rotated.jpg +0 -0
  615. data/vendor/assets/javascripts/wysihtml-toolbar.js +19288 -0
  616. metadata +266 -92
  617. data/app/assets/stylesheets/pageflow/editor/select_button.scss +0 -51
  618. data/config/initializers/revision_components.rb +0 -5
  619. data/config/locales/twitter_to_x.de.yml +0 -6
  620. data/config/locales/twitter_to_x.en.yml +0 -6
  621. data/entry_types/scrolled/app/helpers/pageflow_scrolled/generated_media_queries_helper.rb +0 -55
  622. data/entry_types/scrolled/config/locales/twitter_to_x.de.yml +0 -12
  623. data/entry_types/scrolled/config/locales/twitter_to_x.en.yml +0 -12
  624. data/entry_types/scrolled/config/locales/vr_image_projection.de.yml +0 -24
  625. data/entry_types/scrolled/config/locales/vr_image_projection.en.yml +0 -24
  626. data/entry_types/scrolled/package/frontend/EditableInlineText.module-ebd22921.js +0 -5497
  627. data/entry_types/scrolled/package/frontend/ToggleFullscreenCornerButton-b79159cc.js +0 -107
  628. data/entry_types/scrolled/package/frontend/Viewer-1ecf3375.js +0 -154
  629. data/entry_types/scrolled/package/frontend/Wavesurfer-7d9cf1b7.js +0 -333
  630. data/entry_types/scrolled/package/frontend/arrowRight-62998af9.js +0 -77
  631. data/entry_types/scrolled/package/frontend/components-024a9893.js +0 -2853
  632. data/entry_types/scrolled/package/frontend/createSuper-d0f30da3.js +0 -115
  633. data/entry_types/scrolled/package/frontend/i18n-ce13a8bf.js +0 -1129
  634. data/entry_types/scrolled/package/frontend/useContentElementEditorState-4f4c3cf6.js +0 -52
  635. data/lib/generators/pageflow/resque/templates/resque_enqueue_after_commit_patch.rb +0 -25
  636. data/package/vendor/jquery.minicolors.js +0 -1108
@@ -0,0 +1,4890 @@
1
+ import { features } from 'pageflow/frontend';
2
+ import React, { useMemo, useState, useCallback, useContext, useEffect, useRef, forwardRef, createContext, memo } from 'react';
3
+ import classNames from 'classnames';
4
+ import { P as scrollToElement, g as useContentElementAttributes, n as useStorylineActivity, w as widths, d as api, o as useFloatingPortalRoot, u as useScrollToTarget, Q as LayoutWithoutInlineEditing, f as useDarkBackground, R as renderElement, N as renderLeaf$1, T as Text$1 } from './FloatingPortalRootProvider-20c600de.js';
5
+ import './useDelayedBoolean-a387d85b.js';
6
+ import { v as ContentElementEditorCommandEmitterContext, a as usePostMessageListener, a4 as MotifAreaVisibilityProvider, a5 as ForcePaddingContext, a6 as ContentElementConfigurationUpdateContext, a7 as WidgetConfigurationUpdateContext, N as getAppearanceSectionScopeName, a3 as SectionThumbnail, t as useContentElementEditorCommandSubscription, l as frontendStyles, a8 as createRenderElement, a9 as usePhoneLayout, aa as tableStyles, s as styles$j } from './Placeholder.module-d22a9335.js';
7
+ import BackboneEvents from 'backbone-events-standalone';
8
+ import { useEntryStateDispatch, useTheme, updateContentElementConfiguration, updateWidgetConfiguration, useChapter, useMainStoryline, useDownloadableFile } from 'pageflow-scrolled/entryState';
9
+ import 'i18n-js';
10
+ import { u as useI18n } from './i18n-493cd2a6.js';
11
+ import 'striptags';
12
+ import 'react-measure';
13
+ import { P as PhonePlatformContext } from './PhonePlatformContext-035a99fa.js';
14
+ import { u as useContentElementEditorState, C as ContentElementEditorStateContext } from './useContentElementEditorState-a084912e.js';
15
+ import './ThemeIcon-ab834849.js';
16
+ import { ReviewStateProvider, LocatedCommentThreadsProvider, CommentDisplayFilterProvider, useCommentThreads, useCommentDisplayFilter, useLocatedCommentThreadsForSubject, ThreadsBadge, useAnchoredFloating, useUnreadActivityCount, Badge, alignToContainerEdge, useRangeAnchors, useCommentHighlights, decorateCommentHighlights, RangeAnchor, commentHighlightStyles } from 'pageflow-scrolled/review';
17
+ import { DndProvider, useDrop, useDrag } from 'react-dnd';
18
+ import { HTML5Backend } from 'react-dnd-html5-backend';
19
+ import { useFloating, hide, shift, autoUpdate, FloatingPortal, offset, arrow, inline, FloatingArrow } from '@floating-ui/react';
20
+ import { Range, Transforms, Editor, Node as Node$1, Element as Element$1, Path, Text, createEditor } from 'slate';
21
+ import { ReactEditor, useSlate, withReact, Slate, Editable } from 'slate-react';
22
+ import { withHistory } from 'slate-history';
23
+ import debounce from 'debounce';
24
+
25
+ const Context = React.createContext({});
26
+ function EditorStateProvider(props) {
27
+ const [selection, setSelectionState] = useState(null);
28
+ const setSelection = useCallback(selection => {
29
+ if (window.parent !== window) {
30
+ window.parent.postMessage({
31
+ type: 'SELECTED',
32
+ payload: selection || {}
33
+ }, window.location.origin);
34
+ }
35
+ setSelectionState(selection);
36
+ }, []);
37
+ const value = useMemo(() => ({
38
+ selection,
39
+ setSelection
40
+ }), [setSelection, selection]);
41
+ return /*#__PURE__*/React.createElement(Context.Provider, {
42
+ value: value
43
+ }, props.children);
44
+ }
45
+ function useEditorSelection(options) {
46
+ const {
47
+ selection,
48
+ setSelection
49
+ } = useContext(Context);
50
+ const resetSelection = useCallback(() => {
51
+ setSelection(null);
52
+ }, [setSelection]);
53
+ const select = useCallback(selection => {
54
+ setSelection(selection || options);
55
+ }, [setSelection, options]);
56
+ return useMemo(() => {
57
+ if (!setSelection) return {};
58
+ const isSelected = !!(selection && options && selection.id === options.id && selection.type === options.type && selection.subjectType === options.subjectType && selection.subjectId === options.subjectId);
59
+ return {
60
+ range: selection === null || selection === void 0 ? void 0 : selection.range,
61
+ isSelected,
62
+ selection: isSelected ? selection : null,
63
+ select,
64
+ resetSelection
65
+ };
66
+ }, [options, selection, setSelection, select, resetSelection]);
67
+ }
68
+
69
+ function useContentElementEditorCommandEmitter() {
70
+ return useMemo(() => Object.assign({}, BackboneEvents), []);
71
+ }
72
+ function ContentElementEditorCommandSubscriptionProvider({
73
+ emitter,
74
+ children
75
+ }) {
76
+ return /*#__PURE__*/React.createElement(ContentElementEditorCommandEmitterContext.Provider, {
77
+ value: emitter
78
+ }, children);
79
+ }
80
+
81
+ function EntryDecorator({
82
+ commentingInitialState,
83
+ children
84
+ }) {
85
+ const contentElementEditorCommandEmitter = useContentElementEditorCommandEmitter();
86
+ return /*#__PURE__*/React.createElement(EditorStateProvider, null, /*#__PURE__*/React.createElement(ReviewStateProvider, {
87
+ initialState: commentingInitialState
88
+ }, /*#__PURE__*/React.createElement(MessageHandler, {
89
+ contentElementEditorCommandEmitter: contentElementEditorCommandEmitter
90
+ }), /*#__PURE__*/React.createElement(LocatedCommentThreadsProvider, null, /*#__PURE__*/React.createElement(CommentDisplayFilterFromEditor, null, /*#__PURE__*/React.createElement(ContentElementEditorCommandSubscriptionProvider, {
91
+ emitter: contentElementEditorCommandEmitter
92
+ }, children)))));
93
+ }
94
+
95
+ // The reviewer picks which resolutions to see in the editor's sidebar
96
+ // menu, so the preview only follows what the editor tells it.
97
+ function CommentDisplayFilterFromEditor({
98
+ children
99
+ }) {
100
+ const [filter, setFilter] = useState({
101
+ resolution: 'unresolved',
102
+ alwaysShowComments: true
103
+ });
104
+ usePostMessageListener(useCallback(data => {
105
+ if (data.type === 'CHANGE_COMMENT_DISPLAY_FILTER') {
106
+ setFilter(data.payload);
107
+ }
108
+ }, []));
109
+ return /*#__PURE__*/React.createElement(CommentDisplayFilterProvider, {
110
+ resolution: filter.resolution,
111
+ alwaysShowComments: filter.alwaysShowComments
112
+ }, children);
113
+ }
114
+ function MessageHandler({
115
+ contentElementEditorCommandEmitter
116
+ }) {
117
+ const {
118
+ select
119
+ } = useEditorSelection();
120
+ const dispatch = useEntryStateDispatch();
121
+ const receiveMessage = useCallback(data => {
122
+ if (data.type === 'ACTION') {
123
+ dispatch(data.payload);
124
+ } else if (data.type === 'SELECT') {
125
+ select(data.payload);
126
+ } else if (data.type === 'CONTENT_ELEMENT_EDITOR_COMMAND') {
127
+ contentElementEditorCommandEmitter.trigger(`command:${data.payload.contentElementId}`, data.payload.command);
128
+ }
129
+ }, [dispatch, select, contentElementEditorCommandEmitter]);
130
+ usePostMessageListener(receiveMessage);
131
+ useEffect(() => {
132
+ if (window.parent !== window) {
133
+ window.parent.postMessage({
134
+ type: 'READY'
135
+ }, window.location.origin);
136
+ }
137
+ }, []);
138
+ return null;
139
+ }
140
+
141
+ // Scroll points are used to preserve scroll position when toggling
142
+ // the editor phone preview. Each ContentElementDecorator renders a
143
+ // `data-scrollpoint` attribute with a unique value on its wrapper
144
+ // div. Before toggling the phone preview mode, the `EntryPreviewView`
145
+ // sends a `SAVE_SCROLL_POINT` message. `getCurrentScrollPoint` looks
146
+ // through all DOM elements with `data-scrollpoint` attributes and
147
+ // stores the unique id of the element with the smallest non-negative
148
+ // y coordinate in the viewport (i.e. the first content element inside
149
+ // the viewport). `ScrollPointMessageHandler` responds with a
150
+ // `SAVED_SCROLL_POINT` message which makes `EntryPreviewView` toggle
151
+ // the preview mode. Once the preview has been resized,
152
+ // `EntryPreviewView` sends a `RESTORE_SCROLL_POINT`
153
+ // message. `restoreScrollPoint` looks up the new position of the
154
+ // element with the saved scroll point and scrolls it into view.
155
+ //
156
+ // When a content element is selected, we want to keep that element
157
+ // in the viewport instead. The `SelectionRect` therefore renders a
158
+ // `data-scrollpoint=selection` attribute. If an element with such an
159
+ // attribute is present, `getCurrentScrollPoint` prefers it over all
160
+ // other scroll points. Since text block elements render a selection
161
+ // rect around the current paragraph, scroll position is also
162
+ // preserved correctly inside long text blocks.
163
+
164
+ function ScrollPointMessageHandler() {
165
+ const scrollPoint = useRef();
166
+ const receiveMessage = useCallback(data => {
167
+ if (data.type === 'SAVE_SCROLL_POINT') {
168
+ scrollPoint.current = getCurrentScrollPoint();
169
+ window.parent.postMessage({
170
+ type: 'SAVED_SCROLL_POINT'
171
+ }, window.location.origin);
172
+ } else if (data.type === 'RESTORE_SCROLL_POINT') {
173
+ if (scrollPoint.current) {
174
+ restoreScrollPoint(scrollPoint.current);
175
+ }
176
+ } else if (data.type === 'SCROLL_TO_CONTENT_ELEMENT') {
177
+ scrollToContentElement(data.payload);
178
+ }
179
+ }, []);
180
+ usePostMessageListener(receiveMessage);
181
+ return null;
182
+ }
183
+ function scrollToContentElement({
184
+ id,
185
+ ...options
186
+ }) {
187
+ const element = document.querySelector(`[data-scrollpoint="${id}"]`);
188
+ if (element) {
189
+ scrollToElement(element, options);
190
+ }
191
+ }
192
+ function getCurrentScrollPoint() {
193
+ let scrollPointElement = getSelectionScrollPointElement() || getScrollPointElementWithMinimumTopPositionInViewport();
194
+ return scrollPointElement === null || scrollPointElement === void 0 ? void 0 : scrollPointElement.getAttribute('data-scrollpoint');
195
+ }
196
+ function getSelectionScrollPointElement() {
197
+ return document.querySelector('[data-scrollpoint=selection]');
198
+ }
199
+ function getScrollPointElementWithMinimumTopPositionInViewport() {
200
+ let minTop = Infinity;
201
+ let scrollPointElement;
202
+ const scrollPoints = document.querySelectorAll('[data-scrollpoint]');
203
+ for (let i = 0; i < scrollPoints.length; i++) {
204
+ const rect = scrollPoints[i].getBoundingClientRect();
205
+ if (rect.top > 0 && rect.top < minTop) {
206
+ minTop = rect.top;
207
+ scrollPointElement = scrollPoints[i];
208
+ }
209
+ }
210
+ return scrollPointElement;
211
+ }
212
+ function restoreScrollPoint(name) {
213
+ let element = document.querySelector(`[data-scrollpoint="${name}"]`);
214
+ if (element) {
215
+ window.scrollTo({
216
+ top: element.getBoundingClientRect().top + window.scrollY - 100,
217
+ behavior: 'smooth'
218
+ });
219
+ }
220
+ }
221
+
222
+ function ContentDecorator(props) {
223
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ScrollPointMessageHandler, null), /*#__PURE__*/React.createElement(DndProvider, {
224
+ backend: HTML5Backend
225
+ }, props.children));
226
+ }
227
+
228
+ var styles = {"wrapper":"SectionDecorator-module_wrapper__3sTk3","highlighted":"SectionDecorator-module_highlighted__18FyB","lineAbove":"SectionDecorator-module_lineAbove__BZqEr","lineBelow":"SectionDecorator-module_lineBelow__1RbG-","selected":"SectionDecorator-module_selected__1gcmF","transitionSelected":"SectionDecorator-module_transitionSelected__Wklk6","controls":"SectionDecorator-module_controls__LVEJG","transitionToolbar-after":"SectionDecorator-module_transitionToolbar-after__2_DVO SectionDecorator-module_toolbar__2Va1D","toolbar":"SectionDecorator-module_toolbar__2Va1D","commentBadge":"SectionDecorator-module_commentBadge__dSkqW","sticky":"SectionDecorator-module_sticky__3ALcJ","clipBadgeCorner":"SectionDecorator-module_clipBadgeCorner__3n3iG","commenting":"SectionDecorator-module_commenting__2IONO","transitionToolbar-before":"SectionDecorator-module_transitionToolbar-before__KipOO SectionDecorator-module_toolbar__2Va1D"};
229
+
230
+ var styles$1 = {"wrapper":"BackdropDecorator-module_wrapper__X-h1o","visible":"BackdropDecorator-module_visible__3VqiR","inner":"BackdropDecorator-module_inner__14JfF"};
231
+
232
+ var styles$2 = {"wrapper":"ContentElementDecorator-module_wrapper__NQgFN"};
233
+
234
+ var styles$3 = {"wrapper":"WidgetSelectionRect-module_wrapper__1ktq9","selected":"WidgetSelectionRect-module_selected__2nm_L"};
235
+
236
+ var styles$4 = {"indicator":"PaddingIndicator-module_indicator__1XR6g","selected":"PaddingIndicator-module_selected__2nryl","indicator-top":"PaddingIndicator-module_indicator-top__3CQ9Y PaddingIndicator-module_indicator__1XR6g","indicator-bottom":"PaddingIndicator-module_indicator-bottom__31WQe PaddingIndicator-module_indicator__1XR6g","none":"PaddingIndicator-module_none__3QJ9B","motif":"PaddingIndicator-module_motif__1s4Z2","tooltip":"PaddingIndicator-module_tooltip__3lItX"};
237
+
238
+ var styles$5 = {"Toolbar":"Toolbar-module_Toolbar__1INSj","button":"Toolbar-module_button__de5BW","activeButton":"Toolbar-module_activeButton__2sOLP","collapsible":"Toolbar-module_collapsible__3sivb"};
239
+
240
+ function Toolbar({
241
+ buttons,
242
+ onButtonClick,
243
+ iconSize,
244
+ collapsible
245
+ }) {
246
+ return /*#__PURE__*/React.createElement("div", {
247
+ className: classNames(styles$5.Toolbar, {
248
+ [styles$5.collapsible]: collapsible
249
+ }),
250
+ contentEditable: false
251
+ }, buttons.map(button => {
252
+ const Icon = button.icon;
253
+ return /*#__PURE__*/React.createElement("button", {
254
+ key: button.name,
255
+ title: button.text,
256
+ className: classNames(styles$5.button, {
257
+ [styles$5.activeButton]: button.active
258
+ }),
259
+ onMouseDown: event => {
260
+ event.preventDefault();
261
+ event.stopPropagation();
262
+ onButtonClick(button.name);
263
+ }
264
+ }, /*#__PURE__*/React.createElement(Icon, {
265
+ width: iconSize,
266
+ height: iconSize
267
+ }));
268
+ }));
269
+ }
270
+ Toolbar.defaultProps = {
271
+ iconSize: 15
272
+ };
273
+
274
+ // Bundles an element's two comment-related editor selections - the
275
+ // highlighted comment thread and the pending new thread - which are
276
+ // mutually exclusive since the editor has a single selection at a time.
277
+ // Returns the active state plus actions to select the comments, a
278
+ // specific thread or a new thread. `type` is the comments selection type
279
+ // ('contentElementComments' or 'sectionComments'); `subjectType` and
280
+ // `subjectId` identify the new-thread subject.
281
+ function useCommentSelection({
282
+ type,
283
+ id,
284
+ subjectType,
285
+ subjectId
286
+ }) {
287
+ const {
288
+ isSelected: commentsSelected,
289
+ selection: commentsSelection,
290
+ select: selectComments
291
+ } = useEditorSelection(useMemo(() => ({
292
+ type,
293
+ id
294
+ }), [type, id]));
295
+ const {
296
+ isSelected: newThreadActive,
297
+ range: newThreadRange,
298
+ select: selectNewThreadSelection
299
+ } = useEditorSelection(useMemo(() => ({
300
+ type: 'newThread',
301
+ subjectType,
302
+ subjectId
303
+ }), [subjectType, subjectId]));
304
+ const selectThread = useCallback((threadId, options) => selectComments({
305
+ type,
306
+ id,
307
+ highlightedThreadId: threadId,
308
+ ...options
309
+ }), [selectComments, type, id]);
310
+ const selectNewThread = useCallback(range => range ? selectNewThreadSelection({
311
+ type: 'newThread',
312
+ subjectType,
313
+ subjectId,
314
+ range
315
+ }) : selectNewThreadSelection(), [selectNewThreadSelection, subjectType, subjectId]);
316
+ return {
317
+ selected: commentsSelected ? 'comments' : newThreadActive ? 'newThread' : null,
318
+ highlightedThreadId: commentsSelection === null || commentsSelection === void 0 ? void 0 : commentsSelection.highlightedThreadId,
319
+ newThreadRange: newThreadActive ? newThreadRange : undefined,
320
+ selectComments,
321
+ selectThread,
322
+ selectNewThread
323
+ };
324
+ }
325
+ function useContentElementCommentSelection() {
326
+ const {
327
+ contentElementId,
328
+ contentElementPermaId
329
+ } = useContentElementAttributes();
330
+ return useCommentSelection({
331
+ type: 'contentElementComments',
332
+ id: contentElementId,
333
+ subjectType: 'ContentElement',
334
+ subjectId: contentElementPermaId
335
+ });
336
+ }
337
+
338
+ // Handles the SELECT_COMMENT_THREAD message the editor posts when a
339
+ // thread is clicked in the comments sidebar. Fetches the subject's
340
+ // threads itself - including resolved ones, so a resolved thread can be
341
+ // revealed when clicked - ignores threads of other subjects, scrolls
342
+ // the relevant element into view and calls `selectThread` to make the
343
+ // matching editor selection. `beforeSelect` runs right before that, for
344
+ // callers that need to prepare for it (e.g. move the editor cursor into
345
+ // the thread's block). Shared by the content element and section
346
+ // decorators and the EditableText editor so the handling lives in one
347
+ // place instead of inside each badge. The selection names the editor as
348
+ // its source, which tells the editor it is looking at its own request
349
+ // coming back rather than at the reviewer picking a subject in the
350
+ // preview.
351
+ function useSelectCommentThreadHandler({
352
+ subjectType,
353
+ subjectId,
354
+ getScrollTarget,
355
+ beforeSelect,
356
+ selectThread
357
+ }) {
358
+ const threads = useCommentThreads({
359
+ subjectType,
360
+ subjectId
361
+ });
362
+ usePostMessageListener(useCallback(data => {
363
+ if (data.type !== 'SELECT_COMMENT_THREAD') return;
364
+ const {
365
+ threadId
366
+ } = data.payload;
367
+ if (!threads.some(thread => thread.id === threadId)) return;
368
+ const scrollTarget = getScrollTarget && getScrollTarget(threadId);
369
+ if (scrollTarget) {
370
+ scrollTarget.scrollIntoView({
371
+ block: 'nearest',
372
+ behavior: 'smooth'
373
+ });
374
+ }
375
+ if (beforeSelect) beforeSelect(threadId);
376
+ selectThread(threadId, {
377
+ source: 'editor'
378
+ });
379
+ }, [threads, getScrollTarget, beforeSelect, selectThread]));
380
+ }
381
+
382
+ function _extends() {
383
+ _extends = Object.assign ? Object.assign.bind() : function (target) {
384
+ for (var i = 1; i < arguments.length; i++) {
385
+ var source = arguments[i];
386
+ for (var key in source) {
387
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
388
+ target[key] = source[key];
389
+ }
390
+ }
391
+ }
392
+ return target;
393
+ };
394
+ return _extends.apply(this, arguments);
395
+ }
396
+ var transitionIcon = (({
397
+ styles = {},
398
+ ...props
399
+ }) => /*#__PURE__*/React.createElement("svg", _extends({
400
+ "aria-hidden": "true",
401
+ "data-prefix": "fas",
402
+ "data-icon": "random",
403
+ className: (styles["svg-inline--fa"] || "svg-inline--fa") + " " + (styles["fa-random"] || "fa-random") + " " + (styles["fa-w-16"] || "fa-w-16"),
404
+ xmlns: "http://www.w3.org/2000/svg",
405
+ viewBox: "0 0 512 512"
406
+ }, props), /*#__PURE__*/React.createElement("path", {
407
+ fill: "currentColor",
408
+ d: "M504.971 359.029c9.373 9.373 9.373 24.569 0 33.941l-80 79.984c-15.01 15.01-40.971 4.49-40.971-16.971V416h-58.785a12.004 12.004 0 01-8.773-3.812l-70.556-75.596 53.333-57.143L352 336h32v-39.981c0-21.438 25.943-31.998 40.971-16.971l80 79.981zM12 176h84l52.781 56.551 53.333-57.143-70.556-75.596A11.999 11.999 0 00122.785 96H12c-6.627 0-12 5.373-12 12v56c0 6.627 5.373 12 12 12zm372 0v39.984c0 21.46 25.961 31.98 40.971 16.971l80-79.984c9.373-9.373 9.373-24.569 0-33.941l-80-79.981C409.943 24.021 384 34.582 384 56.019V96h-58.785a12.004 12.004 0 00-8.773 3.812L96 336H12c-6.627 0-12 5.373-12 12v56c0 6.627 5.373 12 12 12h110.785c3.326 0 6.503-1.381 8.773-3.812L352 176h32z"
409
+ })));
410
+
411
+ function SectionDecorator({
412
+ backdrop,
413
+ section,
414
+ contentElements,
415
+ transitions,
416
+ children
417
+ }) {
418
+ var _backdrop$contentElem;
419
+ const {
420
+ t
421
+ } = useI18n({
422
+ locale: 'ui'
423
+ });
424
+ const commentingEnabled = features.isEnabled('commenting');
425
+ const {
426
+ isSelected: isSectionSelected,
427
+ select,
428
+ resetSelection
429
+ } = useEditorSelection({
430
+ id: section.id,
431
+ type: 'sectionSettings'
432
+ });
433
+ const {
434
+ isSelected: isPaddingSelected
435
+ } = useEditorSelection({
436
+ id: section.id,
437
+ type: 'sectionPaddings'
438
+ });
439
+ const {
440
+ selected: commentSelectionState,
441
+ selectComments,
442
+ selectThread,
443
+ selectNewThread
444
+ } = useCommentSelection({
445
+ type: 'sectionComments',
446
+ id: section.id,
447
+ subjectType: 'Section',
448
+ subjectId: section.permaId
449
+ });
450
+
451
+ // Viewing a section's comments or composing a new thread on it.
452
+ const commentsSelected = commentSelectionState !== null;
453
+
454
+ // The section reads as selected while its comments are open, so the
455
+ // section and the sidebar comment panel stay visually in sync.
456
+ const isSelected = isSectionSelected || isPaddingSelected || commentsSelected;
457
+ const {
458
+ resolution,
459
+ alwaysShowComments
460
+ } = useCommentDisplayFilter();
461
+ const threads = useLocatedCommentThreadsForSubject({
462
+ subjectType: 'Section',
463
+ subjectId: section.permaId,
464
+ resolution
465
+ });
466
+ const hasThreads = threads.length > 0;
467
+ const wrapperRef = useRef();
468
+ useSelectCommentThreadHandler({
469
+ subjectType: 'Section',
470
+ subjectId: section.permaId,
471
+ getScrollTarget: useCallback(() => wrapperRef.current, []),
472
+ selectThread
473
+ });
474
+ const clipBadgeCorner = commentingEnabled && (isSectionSelected || isPaddingSelected) && !hasThreads;
475
+ const {
476
+ isSelected: isBackdropElementSelected
477
+ } = useEditorSelection({
478
+ id: (_backdrop$contentElem = backdrop.contentElement) === null || _backdrop$contentElem === void 0 ? void 0 : _backdrop$contentElem.id,
479
+ type: 'contentElement'
480
+ });
481
+ const {
482
+ isSelected: isHighlighted
483
+ } = useEditorSelection({
484
+ id: section.id,
485
+ type: 'section'
486
+ });
487
+ const transitionSelection = useEditorSelection({
488
+ id: section.id,
489
+ type: 'sectionTransition'
490
+ });
491
+ const nextTransitionSelection = useEditorSelection({
492
+ id: section.nextSection && section.nextSection.id,
493
+ type: 'sectionTransition'
494
+ });
495
+ const lastContentElement = contentElements[contentElements.length - 1];
496
+ const {
497
+ isSelected: isLastContentElementSelected
498
+ } = useEditorSelection({
499
+ id: lastContentElement && lastContentElement.id,
500
+ type: 'contentElement'
501
+ });
502
+ function selectIfOutsideContentItem(event) {
503
+ if (!event.target.closest(`.${styles$2.wrapper}`) && !event.target.closest(`.${styles$1.wrapper}`) && !event.target.closest(`.${styles$3.wrapper}`) && !event.target.closest(`.${styles$4.indicator}`) && !event.target.closest(`.${styles.commentBadge}`) && !event.target.closest('#fullscreenRoot') && !event.target.closest('[data-floating-ui-portal]')) {
504
+ isSectionSelected ? resetSelection() : select();
505
+ }
506
+ }
507
+ return /*#__PURE__*/React.createElement("div", {
508
+ ref: wrapperRef,
509
+ "aria-label": t('pageflow_scrolled.inline_editing.select_section'),
510
+ "aria-selected": isSelected,
511
+ className: className(isSelected, transitionSelection, isHighlighted, isBackdropElementSelected, transitions, clipBadgeCorner, commentingEnabled),
512
+ onMouseDown: selectIfOutsideContentItem
513
+ }, /*#__PURE__*/React.createElement("div", {
514
+ className: styles.controls
515
+ }, renderEditTransitionButton({
516
+ id: section.previousSection && section.id,
517
+ selection: transitionSelection,
518
+ position: 'before'
519
+ }), renderEditTransitionButton({
520
+ id: section.nextSection && section.nextSection.id,
521
+ selection: nextTransitionSelection,
522
+ position: 'after'
523
+ })), /*#__PURE__*/React.createElement(MotifAreaVisibilityProvider, {
524
+ visible: isSelected
525
+ }, /*#__PURE__*/React.createElement(ForcePaddingContext.Provider, {
526
+ value: isLastContentElementSelected || isSectionSelected || isHighlighted || commentsSelected
527
+ }, children)), commentingEnabled && /*#__PURE__*/React.createElement("div", {
528
+ className: classNames(styles.commentBadge, {
529
+ [styles.sticky]: hasThreads || commentsSelected
530
+ })
531
+ }, /*#__PURE__*/React.createElement(ThreadsBadge, {
532
+ subjectType: "Section",
533
+ subjectId: section.permaId,
534
+ resolution: resolution,
535
+ mode: commentsSelected ? 'active' : isSelected ? 'icon' : alwaysShowComments ? 'dot' : 'none',
536
+ onClick: () => hasThreads ? selectComments() : selectNewThread()
537
+ })));
538
+ }
539
+ function className(isSelected, transitionSelection, isHighlighted, isBackdropElementSelected, transitions, clipBadgeCorner, commenting) {
540
+ return classNames(styles.wrapper, {
541
+ [styles.selected]: isSelected,
542
+ [styles.highlighted]: isHighlighted,
543
+ [styles.lineAbove]: isBackdropElementSelected && transitions[0].startsWith('fade'),
544
+ [styles.lineBelow]: isBackdropElementSelected && transitions[1].startsWith('fade'),
545
+ [styles.transitionSelected]: transitionSelection.isSelected,
546
+ [styles.clipBadgeCorner]: clipBadgeCorner,
547
+ [styles.commenting]: commenting
548
+ });
549
+ }
550
+ function renderEditTransitionButton({
551
+ id,
552
+ position,
553
+ selection
554
+ }) {
555
+ if (!id) {
556
+ return null;
557
+ }
558
+ return /*#__PURE__*/React.createElement("div", {
559
+ className: styles[`transitionToolbar-${position}`]
560
+ }, /*#__PURE__*/React.createElement(EditTransitionButton, {
561
+ id: id,
562
+ selection: selection,
563
+ position: position
564
+ }));
565
+ }
566
+ function EditTransitionButton({
567
+ id,
568
+ position,
569
+ selection
570
+ }) {
571
+ const {
572
+ t
573
+ } = useI18n({
574
+ locale: 'ui'
575
+ });
576
+ return /*#__PURE__*/React.createElement(EditSectionButton, {
577
+ id: id,
578
+ selection: selection,
579
+ text: t(`pageflow_scrolled.inline_editing.edit_section_transition_${position}`),
580
+ icon: transitionIcon
581
+ });
582
+ }
583
+ function EditSectionButton({
584
+ id,
585
+ selection,
586
+ icon,
587
+ text
588
+ }) {
589
+ return /*#__PURE__*/React.createElement(Toolbar, {
590
+ buttons: [{
591
+ name: 'button',
592
+ active: selection.isSelected,
593
+ icon,
594
+ text
595
+ }],
596
+ iconSize: 20,
597
+ onButtonClick: () => selection.select()
598
+ });
599
+ }
600
+
601
+ var styles$6 = {"selectionWidth":"1px","selectionPadding":"-0.5em","main":"SelectionRect-module_main__3AOhG","draggable":"SelectionRect-module_draggable__3Qp53","tug":"SelectionRect-module_tug__DmW1G","openSides":"SelectionRect-module_openSides__bf5fO","inset":"SelectionRect-module_inset__3den3","selected":"SelectionRect-module_selected__1PhM6","toolbar":"SelectionRect-module_toolbar__3nPrd","insert":"SelectionRect-module_insert__w0Tl0","insertHovered":"SelectionRect-module_insertHovered__VTsDD","start":"SelectionRect-module_start__3_nAf","insert-before":"SelectionRect-module_insert-before__2Tyq5 SelectionRect-module_insert__w0Tl0","end":"SelectionRect-module_end__3qOoK","insert-after":"SelectionRect-module_insert-after__3FJ4R SelectionRect-module_insert__w0Tl0","hasCommentBadge":"SelectionRect-module_hasCommentBadge__RuLsP","insertButton":"SelectionRect-module_insertButton__1g-ZG","dragHandle":"SelectionRect-module_dragHandle__2vVhP","commentBadge":"SelectionRect-module_commentBadge__3e0x_","commentBadgeInset":"SelectionRect-module_commentBadgeInset__3YISH"};
602
+
603
+ function _extends$1() {
604
+ _extends$1 = Object.assign ? Object.assign.bind() : function (target) {
605
+ for (var i = 1; i < arguments.length; i++) {
606
+ var source = arguments[i];
607
+ for (var key in source) {
608
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
609
+ target[key] = source[key];
610
+ }
611
+ }
612
+ }
613
+ return target;
614
+ };
615
+ return _extends$1.apply(this, arguments);
616
+ }
617
+ var PlusIcon = (({
618
+ styles = {},
619
+ ...props
620
+ }) => /*#__PURE__*/React.createElement("svg", _extends$1({
621
+ xmlns: "http://www.w3.org/2000/svg",
622
+ viewBox: "0 0 512 512"
623
+ }, props), /*#__PURE__*/React.createElement("path", {
624
+ d: "M256 0C114.844 0 0 114.839 0 256s114.844 256 256 256 256-114.839 256-256S397.156 0 256 0zm133.594 272.699H272.699v116.895c0 9.225-7.48 16.699-16.699 16.699-9.219 0-16.699-7.475-16.699-16.699V272.699H122.406c-9.219 0-16.699-7.475-16.699-16.699 0-9.225 7.48-16.699 16.699-16.699h116.895V122.406c0-9.225 7.48-16.699 16.699-16.699 9.219 0 16.699 7.475 16.699 16.699v116.895h116.895c9.219 0 16.699 7.475 16.699 16.699.001 9.225-7.48 16.699-16.699 16.699z"
625
+ })));
626
+
627
+ function _extends$2() {
628
+ _extends$2 = Object.assign ? Object.assign.bind() : function (target) {
629
+ for (var i = 1; i < arguments.length; i++) {
630
+ var source = arguments[i];
631
+ for (var key in source) {
632
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
633
+ target[key] = source[key];
634
+ }
635
+ }
636
+ }
637
+ return target;
638
+ };
639
+ return _extends$2.apply(this, arguments);
640
+ }
641
+ var MoveIcon = (({
642
+ styles = {},
643
+ ...props
644
+ }) => /*#__PURE__*/React.createElement("svg", _extends$2({
645
+ "aria-hidden": "true",
646
+ "data-prefix": "fas",
647
+ "data-icon": "arrows-alt",
648
+ className: (styles["svg-inline--fa"] || "svg-inline--fa") + " " + (styles["fa-arrows-alt"] || "fa-arrows-alt") + " " + (styles["fa-w-16"] || "fa-w-16"),
649
+ xmlns: "http://www.w3.org/2000/svg",
650
+ viewBox: "0 0 512 512"
651
+ }, props), /*#__PURE__*/React.createElement("path", {
652
+ fill: "currentColor",
653
+ d: "M352.201 425.775l-79.196 79.196c-9.373 9.373-24.568 9.373-33.941 0l-79.196-79.196c-15.119-15.119-4.411-40.971 16.971-40.97h51.162L228 284H127.196v51.162c0 21.382-25.851 32.09-40.971 16.971L7.029 272.937c-9.373-9.373-9.373-24.569 0-33.941L86.225 159.8c15.119-15.119 40.971-4.411 40.971 16.971V228H228V127.196h-51.23c-21.382 0-32.09-25.851-16.971-40.971l79.196-79.196c9.373-9.373 24.568-9.373 33.941 0l79.196 79.196c15.119 15.119 4.411 40.971-16.971 40.971h-51.162V228h100.804v-51.162c0-21.382 25.851-32.09 40.97-16.971l79.196 79.196c9.373 9.373 9.373 24.569 0 33.941L425.773 352.2c-15.119 15.119-40.971 4.411-40.97-16.971V284H284v100.804h51.23c21.382 0 32.09 25.851 16.971 40.971z"
654
+ })));
655
+
656
+ const SelectionRect = forwardRef(function SelectionRect(props, ref) {
657
+ return /*#__PURE__*/React.createElement("div", {
658
+ ref: ref,
659
+ className: classNames(styles$6.main, {
660
+ [styles$6.openSides]: props.full && !props.inset,
661
+ [styles$6.tug]: props.full || props.customMargin,
662
+ [styles$6.inset]: props.inset,
663
+ [styles$6.selected]: props.selected,
664
+ [styles$6.draggable]: props.drag,
665
+ [styles$6.hasCommentBadge]: props.commentBadge && !props.commentBadgeInset,
666
+ [styles$6.start]: props.selected && props.start,
667
+ [styles$6.end]: props.selected && props.end
668
+ }),
669
+ "aria-label": props.ariaLabel,
670
+ "aria-selected": props.selected,
671
+ "data-scrollpoint": props.scrollPoint ? 'selection' : undefined,
672
+ onClick: props.onClick
673
+ }, renderDragHandle(props), renderCommentBadge(props), renderToolbar(props), /*#__PURE__*/React.createElement(InsertButton, Object.assign({}, props, {
674
+ at: "before"
675
+ })), props.children, /*#__PURE__*/React.createElement(InsertButton, Object.assign({}, props, {
676
+ at: "after"
677
+ })));
678
+ });
679
+ function InsertButton(props) {
680
+ const [insertHovered, setInsertHovered] = useState(false);
681
+ return /*#__PURE__*/React.createElement("div", {
682
+ className: classNames(styles$6[`insert-${props.at}`], {
683
+ [styles$6.insertHovered]: insertHovered
684
+ }),
685
+ contentEditable: false
686
+ }, /*#__PURE__*/React.createElement("button", {
687
+ className: styles$6.insertButton,
688
+ title: props.insertButtonTitles && props.insertButtonTitles[props.at],
689
+ onMouseDown: event => event.preventDefault(),
690
+ onClick: () => props.onInsertButtonClick(props.at),
691
+ onMouseEnter: () => setInsertHovered(true),
692
+ onMouseLeave: () => setInsertHovered(false)
693
+ }, /*#__PURE__*/React.createElement(PlusIcon, {
694
+ width: 15,
695
+ height: 15,
696
+ fill: "currentColor"
697
+ })));
698
+ }
699
+ function renderDragHandle({
700
+ drag,
701
+ dragHandleTitle
702
+ }) {
703
+ if (!drag) {
704
+ return null;
705
+ }
706
+ return /*#__PURE__*/React.createElement("div", {
707
+ ref: drag,
708
+ className: styles$6.dragHandle,
709
+ title: dragHandleTitle
710
+ }, /*#__PURE__*/React.createElement(MoveIcon, null));
711
+ }
712
+ function renderCommentBadge({
713
+ commentBadge,
714
+ commentBadgeInset
715
+ }) {
716
+ if (!commentBadge) {
717
+ return null;
718
+ }
719
+ return /*#__PURE__*/React.createElement("div", {
720
+ className: classNames(styles$6.commentBadge, {
721
+ [styles$6.commentBadgeInset]: commentBadgeInset
722
+ }),
723
+ onClick: e => e.stopPropagation()
724
+ }, commentBadge);
725
+ }
726
+ function renderToolbar({
727
+ toolbarButtons,
728
+ onToolbarButtonClick,
729
+ start
730
+ }) {
731
+ if (toolbarButtons && start) {
732
+ return /*#__PURE__*/React.createElement("div", {
733
+ className: styles$6.toolbar
734
+ }, /*#__PURE__*/React.createElement(Toolbar, {
735
+ buttons: toolbarButtons,
736
+ collapsible: true,
737
+ onButtonClick: onToolbarButtonClick
738
+ }));
739
+ }
740
+ }
741
+ SelectionRect.defaultProps = {
742
+ start: true,
743
+ end: true
744
+ };
745
+
746
+ var styles$7 = {"target":"DropTargets-module_target__Z2N2d","isOver":"DropTargets-module_isOver__3ksFy","before":"DropTargets-module_before__cAXo1 DropTargets-module_target__Z2N2d","after":"DropTargets-module_after__2Q8QU DropTargets-module_target__Z2N2d"};
747
+
748
+ function DropTargets({
749
+ accept,
750
+ canDrop,
751
+ onDrop
752
+ }) {
753
+ const [{
754
+ canDropBefore,
755
+ isBefore
756
+ }, dropBefore] = useDrop({
757
+ accept,
758
+ canDrop: item => canDrop({
759
+ at: 'before',
760
+ id: item.id
761
+ }),
762
+ collect: monitor => ({
763
+ canDropBefore: monitor.canDrop(),
764
+ isBefore: monitor.isOver() && monitor.canDrop()
765
+ }),
766
+ drop: item => onDrop({
767
+ at: 'before',
768
+ id: item.id,
769
+ range: item.range
770
+ })
771
+ });
772
+ const [{
773
+ canDropAfter,
774
+ isAfter
775
+ }, dropAfter] = useDrop({
776
+ accept,
777
+ canDrop: item => canDrop({
778
+ at: 'after',
779
+ id: item.id
780
+ }),
781
+ collect: monitor => ({
782
+ canDropAfter: monitor.canDrop(),
783
+ isAfter: monitor.isOver() && monitor.canDrop()
784
+ }),
785
+ drop: item => onDrop({
786
+ at: 'after',
787
+ id: item.id,
788
+ range: item.range
789
+ })
790
+ });
791
+ return /*#__PURE__*/React.createElement(React.Fragment, null, canDropBefore && /*#__PURE__*/React.createElement("div", {
792
+ ref: dropBefore,
793
+ "data-testid": "drop-before",
794
+ className: classNames(styles$7.before, {
795
+ [styles$7.isOver]: isBefore
796
+ })
797
+ }), canDropAfter && /*#__PURE__*/React.createElement("div", {
798
+ ref: dropAfter,
799
+ "data-testid": "drop-after",
800
+ title: "bar",
801
+ className: classNames(styles$7.after, {
802
+ [styles$7.isOver]: isAfter
803
+ })
804
+ }));
805
+ }
806
+
807
+ function Scale({
808
+ scaleName,
809
+ themeProperties,
810
+ scaleTranslations,
811
+ defaultValuePropertyName,
812
+ scope
813
+ }) {
814
+ const root = themeProperties.root || {};
815
+ const scaleProperties = Object.keys(root).filter(name => name.indexOf(`${scaleName}-`) === 0);
816
+ const values = scaleProperties.map(name => name.split('-').pop());
817
+ const texts = values.map(value => {
818
+ var _scaleTranslations$sc;
819
+ return (_scaleTranslations$sc = scaleTranslations[scaleName]) === null || _scaleTranslations$sc === void 0 ? void 0 : _scaleTranslations$sc[value];
820
+ });
821
+ const cssValues = scaleProperties.map(propertyName => root[propertyName]);
822
+ return {
823
+ values,
824
+ texts,
825
+ defaultValue: getDefaultValue()
826
+ };
827
+ function getDefaultValue() {
828
+ var _themeProperties$scop, _themeProperties$scop2, _themeProperties$root;
829
+ if (!defaultValuePropertyName) {
830
+ return undefined;
831
+ }
832
+ const defaultCssValue = (_themeProperties$scop = (_themeProperties$scop2 = themeProperties[scope]) === null || _themeProperties$scop2 === void 0 ? void 0 : _themeProperties$scop2[defaultValuePropertyName]) !== null && _themeProperties$scop !== void 0 ? _themeProperties$scop : (_themeProperties$root = themeProperties.root) === null || _themeProperties$root === void 0 ? void 0 : _themeProperties$root[defaultValuePropertyName];
833
+ if (!defaultCssValue) {
834
+ return undefined;
835
+ }
836
+ const index = cssValues.indexOf(defaultCssValue);
837
+ return index >= 0 ? values[index] : undefined;
838
+ }
839
+ }
840
+
841
+ var styles$8 = {"indicator":"MarginIndicator-module_indicator__eise1","indicator-top":"MarginIndicator-module_indicator-top__2igv4 MarginIndicator-module_indicator__eise1","indicator-bottom":"MarginIndicator-module_indicator-bottom__2-qSB MarginIndicator-module_indicator__eise1","tooltip":"MarginIndicator-module_tooltip__1cC4b","inset":"MarginIndicator-module_inset__xg51Q"};
842
+
843
+ function MarginIndicator({
844
+ marginValue,
845
+ position,
846
+ tooltipInset
847
+ }) {
848
+ var _theme$options, _theme$translations;
849
+ const {
850
+ isSelected
851
+ } = useContentElementEditorState();
852
+ const theme = useTheme();
853
+ const {
854
+ t
855
+ } = useI18n({
856
+ locale: 'ui'
857
+ });
858
+ const scale = Scale({
859
+ scaleName: 'contentElementMargin',
860
+ themeProperties: ((_theme$options = theme.options) === null || _theme$options === void 0 ? void 0 : _theme$options.properties) || {},
861
+ scaleTranslations: ((_theme$translations = theme.translations) === null || _theme$translations === void 0 ? void 0 : _theme$translations.scales) || {},
862
+ defaultValuePropertyName: 'contentElementMarginStyleDefault'
863
+ });
864
+ const index = scale.values.indexOf(marginValue);
865
+ if (!isSelected || !marginValue || index < 0) {
866
+ return null;
867
+ }
868
+ const label = t(`pageflow_scrolled.inline_editing.content_element_margin_${position}`);
869
+ return /*#__PURE__*/React.createElement("div", {
870
+ "aria-label": label,
871
+ className: styles$8[`indicator-${position}`],
872
+ style: {
873
+ '--indicator-height': `var(--theme-content-element-margin-${marginValue})`
874
+ }
875
+ }, /*#__PURE__*/React.createElement("div", {
876
+ className: classNames(styles$8.tooltip, {
877
+ [styles$8.inset]: tooltipInset
878
+ }),
879
+ title: label
880
+ }, scale.texts[index]));
881
+ }
882
+
883
+ function postInsertContentElementMessage({
884
+ id,
885
+ at,
886
+ splitPoint
887
+ }) {
888
+ window.parent.postMessage({
889
+ type: 'INSERT_CONTENT_ELEMENT',
890
+ payload: {
891
+ id,
892
+ at,
893
+ splitPoint
894
+ }
895
+ }, window.location.origin);
896
+ }
897
+ function postMoveContentElementMessage({
898
+ id,
899
+ range,
900
+ to
901
+ }) {
902
+ window.parent.postMessage({
903
+ type: 'MOVE_CONTENT_ELEMENT',
904
+ payload: {
905
+ id,
906
+ range,
907
+ to
908
+ }
909
+ }, window.location.origin);
910
+ }
911
+ function postUpdateContentElementMessage({
912
+ id,
913
+ configuration,
914
+ commentThreadSubjectRanges
915
+ }) {
916
+ window.parent.postMessage({
917
+ type: 'UPDATE_CONTENT_ELEMENT',
918
+ payload: {
919
+ id,
920
+ configuration,
921
+ commentThreadSubjectRanges
922
+ }
923
+ }, window.location.origin);
924
+ }
925
+ function postUpdateWidgetMessage({
926
+ role,
927
+ configuration
928
+ }) {
929
+ window.parent.postMessage({
930
+ type: 'UPDATE_WIDGET',
931
+ payload: {
932
+ role,
933
+ configuration
934
+ }
935
+ }, window.location.origin);
936
+ }
937
+ function postUpdateTransientContentElementStateMessage({
938
+ id,
939
+ state
940
+ }) {
941
+ window.parent.postMessage({
942
+ type: 'UPDATE_TRANSIENT_CONTENT_ELEMENT_STATE',
943
+ payload: {
944
+ id,
945
+ state
946
+ }
947
+ }, window.location.origin);
948
+ }
949
+ function postSelectLinkDestinationMessage() {
950
+ window.parent.postMessage({
951
+ type: 'SELECT_LINK_DESTINATION'
952
+ }, window.location.origin);
953
+ }
954
+
955
+ function ContentElementConfigurationUpdateProvider({
956
+ id,
957
+ permaId,
958
+ children
959
+ }) {
960
+ const dispatch = useEntryStateDispatch();
961
+ const update = useCallback((configuration, {
962
+ commentThreadSubjectRanges
963
+ } = {}) => {
964
+ postUpdateContentElementMessage({
965
+ id,
966
+ configuration,
967
+ commentThreadSubjectRanges
968
+ });
969
+ updateContentElementConfiguration({
970
+ dispatch,
971
+ permaId,
972
+ configuration
973
+ });
974
+ }, [dispatch, permaId, id]);
975
+ return /*#__PURE__*/React.createElement(ContentElementConfigurationUpdateContext.Provider, {
976
+ value: update
977
+ }, children);
978
+ }
979
+
980
+ function ContentElementEditorStateProvider({
981
+ id,
982
+ permaId,
983
+ children
984
+ }) {
985
+ const {
986
+ isSelected,
987
+ select,
988
+ range
989
+ } = useEditorSelection(useMemo(() => ({
990
+ id,
991
+ type: 'contentElement'
992
+ }), [id]));
993
+ const {
994
+ isSelected: commentsSelected,
995
+ select: selectComments
996
+ } = useEditorSelection(useMemo(() => ({
997
+ id,
998
+ type: 'contentElementComments'
999
+ }), [id]));
1000
+ const {
1001
+ isSelected: newThreadSelected,
1002
+ select: selectNewThread
1003
+ } = useEditorSelection(useMemo(() => ({
1004
+ type: 'newThread',
1005
+ subjectType: 'ContentElement',
1006
+ subjectId: permaId
1007
+ }), [permaId]));
1008
+ const storylineMode = useStorylineActivity();
1009
+ const inForeground = storylineMode === 'active';
1010
+ const type = inForeground ? isSelected ? 'contentElement' : commentsSelected ? 'contentElementComments' : newThreadSelected ? 'newThread' : null : null;
1011
+ const previousTransientState = useRef({});
1012
+ const setTransientState = useCallback(state => {
1013
+ if (!shallowEqual(state, previousTransientState.current)) {
1014
+ postUpdateTransientContentElementStateMessage({
1015
+ id,
1016
+ state
1017
+ });
1018
+ previousTransientState.current = state;
1019
+ }
1020
+ }, [id]);
1021
+ const value = useMemo(() => ({
1022
+ isEditable: true,
1023
+ select,
1024
+ selectComments,
1025
+ selectNewThread,
1026
+ isSelected: !!type,
1027
+ type,
1028
+ range,
1029
+ setTransientState
1030
+ }), [select, selectComments, selectNewThread, type, range, setTransientState]);
1031
+ return /*#__PURE__*/React.createElement(ContentElementEditorStateContext.Provider, {
1032
+ value: value
1033
+ }, children);
1034
+ }
1035
+ function shallowEqual(obj1, obj2) {
1036
+ return Object.keys(obj1).length === Object.keys(obj2).length && Object.keys(obj1).every(key => Object.prototype.hasOwnProperty.call(obj2, key) && obj1[key] === obj2[key]);
1037
+ }
1038
+
1039
+ function ContentElementDecorator(props) {
1040
+ return /*#__PURE__*/React.createElement("div", {
1041
+ className: styles$2.wrapper,
1042
+ "data-scrollpoint": props.id
1043
+ }, /*#__PURE__*/React.createElement(ContentElementEditorStateProvider, {
1044
+ id: props.id,
1045
+ permaId: props.permaId
1046
+ }, /*#__PURE__*/React.createElement(OptionalSelectionRect, props, /*#__PURE__*/React.createElement(ContentElementConfigurationUpdateProvider, {
1047
+ id: props.id,
1048
+ permaId: props.permaId
1049
+ }, renderMarginIndicators(props), props.children))));
1050
+ }
1051
+ function OptionalSelectionRect(props) {
1052
+ const {
1053
+ customSelectionRect
1054
+ } = api.contentElementTypes.getOptions(props.type) || {};
1055
+ if (customSelectionRect) {
1056
+ return props.children;
1057
+ } else {
1058
+ return /*#__PURE__*/React.createElement(DefaultSelectionRect, props, props.children);
1059
+ }
1060
+ }
1061
+ function DefaultSelectionRect(props) {
1062
+ const {
1063
+ isSelected,
1064
+ type,
1065
+ select,
1066
+ selectComments,
1067
+ selectNewThread
1068
+ } = useContentElementEditorState();
1069
+ const commentsSelected = type === 'contentElementComments' || type === 'newThread';
1070
+ const {
1071
+ resolution,
1072
+ alwaysShowComments
1073
+ } = useCommentDisplayFilter();
1074
+ const {
1075
+ t
1076
+ } = useI18n({
1077
+ locale: 'ui'
1078
+ });
1079
+ const selectionRectRef = useRef();
1080
+ useSelectCommentThreadHandler({
1081
+ subjectType: 'ContentElement',
1082
+ subjectId: props.permaId,
1083
+ getScrollTarget: useCallback(() => selectionRectRef.current, []),
1084
+ selectThread: useCallback((threadId, options) => selectComments({
1085
+ type: 'contentElementComments',
1086
+ id: props.id,
1087
+ highlightedThreadId: threadId,
1088
+ ...options
1089
+ }), [selectComments, props.id])
1090
+ });
1091
+ const [, drag, preview] = useDrag({
1092
+ item: {
1093
+ type: 'contentElement',
1094
+ id: props.id
1095
+ }
1096
+ });
1097
+ return /*#__PURE__*/React.createElement(SelectionRect, {
1098
+ ref: selectionRectRef,
1099
+ selected: isSelected,
1100
+ scrollPoint: isSelected,
1101
+ drag: drag,
1102
+ dragHandleTitle: t('pageflow_scrolled.inline_editing.drag_content_element'),
1103
+ full: props.width === widths.full,
1104
+ customMargin: props.customMargin,
1105
+ inset: props.position === 'backdrop',
1106
+ commentBadge: features.isEnabled('commenting') && /*#__PURE__*/React.createElement(ThreadsBadge, {
1107
+ subjectType: "ContentElement",
1108
+ subjectId: props.permaId,
1109
+ resolution: resolution,
1110
+ mode: commentsSelected ? 'active' : isSelected ? 'icon' : alwaysShowComments ? 'dot' : 'none',
1111
+ onClick: threads => threads.length === 0 ? selectNewThread() : selectComments()
1112
+ }),
1113
+ commentBadgeInset: !isSelected,
1114
+ ariaLabel: t('pageflow_scrolled.inline_editing.select_content_element'),
1115
+ insertButtonTitles: t('pageflow_scrolled.inline_editing.insert_content_element'),
1116
+ onClick: () => select(),
1117
+ onInsertButtonClick: at => postInsertContentElementMessage({
1118
+ id: props.id,
1119
+ at
1120
+ })
1121
+ }, /*#__PURE__*/React.createElement("div", {
1122
+ ref: preview
1123
+ }, props.children), /*#__PURE__*/React.createElement(DropTargets, {
1124
+ accept: "contentElement",
1125
+ canDrop: ({
1126
+ id
1127
+ }) => id !== props.id,
1128
+ onDrop: ({
1129
+ id,
1130
+ range,
1131
+ at
1132
+ }) => postMoveContentElementMessage({
1133
+ id,
1134
+ range,
1135
+ to: {
1136
+ id: props.id,
1137
+ at
1138
+ }
1139
+ })
1140
+ }));
1141
+ }
1142
+ function renderMarginIndicators(props) {
1143
+ var _props$itemProps, _props$itemProps2;
1144
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(MarginIndicator, {
1145
+ marginValue: (_props$itemProps = props.itemProps) === null || _props$itemProps === void 0 ? void 0 : _props$itemProps.marginTop,
1146
+ position: "top",
1147
+ tooltipInset: props.width === widths.full || props.customMargin
1148
+ }), /*#__PURE__*/React.createElement(MarginIndicator, {
1149
+ marginValue: (_props$itemProps2 = props.itemProps) === null || _props$itemProps2 === void 0 ? void 0 : _props$itemProps2.marginBottom,
1150
+ position: "bottom",
1151
+ tooltipInset: props.width === widths.full || props.customMargin
1152
+ }));
1153
+ }
1154
+
1155
+ const WidgetEditorStateContext = createContext({});
1156
+ function useWidgetEditorState() {
1157
+ return useContext(WidgetEditorStateContext);
1158
+ }
1159
+ function SelectableWidgetDecorator({
1160
+ role,
1161
+ props,
1162
+ children
1163
+ }) {
1164
+ const {
1165
+ isSelected,
1166
+ select
1167
+ } = useEditorSelection(useMemo(() => ({
1168
+ id: role,
1169
+ type: 'widget'
1170
+ }), [role]));
1171
+ const value = useMemo(() => ({
1172
+ isSelected,
1173
+ select
1174
+ }), [isSelected, select]);
1175
+ return /*#__PURE__*/React.createElement(WidgetEditorStateContext.Provider, {
1176
+ value: value
1177
+ }, children);
1178
+ }
1179
+
1180
+ function WidgetConfigurationUpdateProvider({
1181
+ role,
1182
+ children
1183
+ }) {
1184
+ const dispatch = useEntryStateDispatch();
1185
+ const update = useCallback(configuration => {
1186
+ postUpdateWidgetMessage({
1187
+ role,
1188
+ configuration
1189
+ });
1190
+ updateWidgetConfiguration({
1191
+ dispatch,
1192
+ role,
1193
+ configuration
1194
+ });
1195
+ }, [dispatch, role]);
1196
+ return /*#__PURE__*/React.createElement(WidgetConfigurationUpdateContext.Provider, {
1197
+ value: update
1198
+ }, children);
1199
+ }
1200
+
1201
+ function WidgetDecorator(props) {
1202
+ return /*#__PURE__*/React.createElement(WidgetConfigurationUpdateProvider, {
1203
+ role: props.role
1204
+ }, props.children);
1205
+ }
1206
+
1207
+ var styles$9 = {"reference":"ActionButtons-module_reference__27uyP","buttons":"ActionButtons-module_buttons__1Hz2Z","button":"ActionButtons-module_button__1wzIk","iconOnly":"ActionButtons-module_iconOnly__1VEGK","floating":"ActionButtons-module_floating__18Epj","escaped":"ActionButtons-module_escaped__2M1PU","size-lg":"ActionButtons-module_size-lg__2b0Dw","position-outside":"ActionButtons-module_position-outside__1rpXW","position-outsideLeft":"ActionButtons-module_position-outsideLeft__3bo3f","position-outsideIndented":"ActionButtons-module_position-outsideIndented__2LZds","position-inside":"ActionButtons-module_position-inside__IDFN8","position-center":"ActionButtons-module_position-center__1ff85","position-topRight":"ActionButtons-module_position-topRight__3HrcE"};
1208
+
1209
+ function _extends$3() {
1210
+ _extends$3 = Object.assign ? Object.assign.bind() : function (target) {
1211
+ for (var i = 1; i < arguments.length; i++) {
1212
+ var source = arguments[i];
1213
+ for (var key in source) {
1214
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
1215
+ target[key] = source[key];
1216
+ }
1217
+ }
1218
+ }
1219
+ return target;
1220
+ };
1221
+ return _extends$3.apply(this, arguments);
1222
+ }
1223
+ var background = (({
1224
+ styles = {},
1225
+ ...props
1226
+ }) => /*#__PURE__*/React.createElement("svg", _extends$3({
1227
+ xmlns: "http://www.w3.org/2000/svg",
1228
+ viewBox: "0 0 448 512"
1229
+ }, props), /*#__PURE__*/React.createElement("path", {
1230
+ d: "M64 32C28.7 32 0 60.7 0 96v200c0 35.3 28.7 64 64 64h208c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64z"
1231
+ }), /*#__PURE__*/React.createElement("path", {
1232
+ d: "M363.494 144v48H384c8.8 0 16 7.2 16 16v200c0 8.8-7.2 16-16 16H176c-8.8 0-16-7.2-16-16v-21.16h-48V408c0 35.3 28.7 64 64 64h208c35.3 0 64-28.7 64-64V208c0-35.3-28.7-64-64-64z"
1233
+ })));
1234
+
1235
+ function _extends$4() {
1236
+ _extends$4 = Object.assign ? Object.assign.bind() : function (target) {
1237
+ for (var i = 1; i < arguments.length; i++) {
1238
+ var source = arguments[i];
1239
+ for (var key in source) {
1240
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
1241
+ target[key] = source[key];
1242
+ }
1243
+ }
1244
+ }
1245
+ return target;
1246
+ };
1247
+ return _extends$4.apply(this, arguments);
1248
+ }
1249
+ var foreground = (({
1250
+ styles = {},
1251
+ ...props
1252
+ }) => /*#__PURE__*/React.createElement("svg", _extends$4({
1253
+ xmlns: "http://www.w3.org/2000/svg",
1254
+ viewBox: "0 0 448 512"
1255
+ }, props), /*#__PURE__*/React.createElement("path", {
1256
+ d: "M363.494 148v168.365c0 41.077-33.397 74.475-74.474 74.475H112V412c0 35.3 28.7 64 64 64h208c35.3 0 64-28.7 64-64V212c0-35.3-28.7-64-64-64z"
1257
+ }), /*#__PURE__*/React.createElement("path", {
1258
+ d: "M272 84c8.8 0 16 7.2 16 16v200c0 8.8-7.2 16-16 16H64c-8.8 0-16-7.2-16-16V100c0-8.8 7.2-16 16-16zM64 36C28.7 36 0 64.7 0 100v200c0 35.3 28.7 64 64 64h208c35.3 0 64-28.7 64-64V100c0-35.3-28.7-64-64-64z"
1259
+ })));
1260
+
1261
+ function _extends$5() {
1262
+ _extends$5 = Object.assign ? Object.assign.bind() : function (target) {
1263
+ for (var i = 1; i < arguments.length; i++) {
1264
+ var source = arguments[i];
1265
+ for (var key in source) {
1266
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
1267
+ target[key] = source[key];
1268
+ }
1269
+ }
1270
+ }
1271
+ return target;
1272
+ };
1273
+ return _extends$5.apply(this, arguments);
1274
+ }
1275
+ var pencil = (({
1276
+ styles = {},
1277
+ ...props
1278
+ }) => /*#__PURE__*/React.createElement("svg", _extends$5({
1279
+ xmlns: "http://www.w3.org/2000/svg",
1280
+ viewBox: "0 0 512 512"
1281
+ }, props), /*#__PURE__*/React.createElement("path", {
1282
+ d: "M410.3 231l11.3-11.3-33.9-33.9-62.1-62.1-33.9-33.9-11.3 11.3-22.6 22.6L58.6 322.9c-10.4 10.4-18 23.3-22.2 37.4L1 480.7c-2.5 8.4-.2 17.5 6.1 23.7s15.3 8.5 23.7 6.1l120.3-35.4c14.1-4.2 27-11.8 37.4-22.2l199.2-199.2 22.6-22.7zM160 399.4l-9.1 22.7c-4 3.1-8.5 5.4-13.3 6.9l-78.2 23 23-78.1c1.4-4.9 3.8-9.4 6.9-13.3l22.7-9.1v32c0 8.8 7.2 16 16 16h32zM362.7 18.7l-14.4 14.5-22.6 22.6-11.4 11.3 33.9 33.9 62.1 62.1 33.9 33.9 11.3-11.3 22.6-22.6 14.5-14.5c25-25 25-65.5 0-90.5l-39.3-39.4c-25-25-65.5-25-90.5 0zm-47.4 168l-144 144c-6.2 6.2-16.4 6.2-22.6 0s-6.2-16.4 0-22.6l144-144c6.2-6.2 16.4-6.2 22.6 0s6.2 16.4 0 22.6z"
1283
+ })));
1284
+
1285
+ function _extends$6() {
1286
+ _extends$6 = Object.assign ? Object.assign.bind() : function (target) {
1287
+ for (var i = 1; i < arguments.length; i++) {
1288
+ var source = arguments[i];
1289
+ for (var key in source) {
1290
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
1291
+ target[key] = source[key];
1292
+ }
1293
+ }
1294
+ }
1295
+ return target;
1296
+ };
1297
+ return _extends$6.apply(this, arguments);
1298
+ }
1299
+ var LinkIcon = (({
1300
+ styles = {},
1301
+ ...props
1302
+ }) => /*#__PURE__*/React.createElement("svg", _extends$6({
1303
+ "aria-hidden": "true",
1304
+ "data-prefix": "fas",
1305
+ "data-icon": "link",
1306
+ className: (styles["svg-inline--fa"] || "svg-inline--fa") + " " + (styles["fa-link"] || "fa-link") + " " + (styles["fa-w-16"] || "fa-w-16"),
1307
+ xmlns: "http://www.w3.org/2000/svg",
1308
+ viewBox: "0 0 512 512"
1309
+ }, props), /*#__PURE__*/React.createElement("path", {
1310
+ fill: "currentColor",
1311
+ d: "M326.612 185.391c59.747 59.809 58.927 155.698.36 214.59-.11.12-.24.25-.36.37l-67.2 67.2c-59.27 59.27-155.699 59.262-214.96 0-59.27-59.26-59.27-155.7 0-214.96l37.106-37.106c9.84-9.84 26.786-3.3 27.294 10.606.648 17.722 3.826 35.527 9.69 52.721 1.986 5.822.567 12.262-3.783 16.612l-13.087 13.087c-28.026 28.026-28.905 73.66-1.155 101.96 28.024 28.579 74.086 28.749 102.325.51l67.2-67.19c28.191-28.191 28.073-73.757 0-101.83-3.701-3.694-7.429-6.564-10.341-8.569a16.037 16.037 0 01-6.947-12.606c-.396-10.567 3.348-21.456 11.698-29.806l21.054-21.055c5.521-5.521 14.182-6.199 20.584-1.731a152.482 152.482 0 0120.522 17.197zM467.547 44.449c-59.261-59.262-155.69-59.27-214.96 0l-67.2 67.2c-.12.12-.25.25-.36.37-58.566 58.892-59.387 154.781.36 214.59a152.454 152.454 0 0020.521 17.196c6.402 4.468 15.064 3.789 20.584-1.731l21.054-21.055c8.35-8.35 12.094-19.239 11.698-29.806a16.037 16.037 0 00-6.947-12.606c-2.912-2.005-6.64-4.875-10.341-8.569-28.073-28.073-28.191-73.639 0-101.83l67.2-67.19c28.239-28.239 74.3-28.069 102.325.51 27.75 28.3 26.872 73.934-1.155 101.96l-13.087 13.087c-4.35 4.35-5.769 10.79-3.783 16.612 5.864 17.194 9.042 34.999 9.69 52.721.509 13.906 17.454 20.446 27.294 10.606l37.106-37.106c59.271-59.259 59.271-155.699.001-214.959z"
1312
+ })));
1313
+
1314
+ function _extends$7() {
1315
+ _extends$7 = Object.assign ? Object.assign.bind() : function (target) {
1316
+ for (var i = 1; i < arguments.length; i++) {
1317
+ var source = arguments[i];
1318
+ for (var key in source) {
1319
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
1320
+ target[key] = source[key];
1321
+ }
1322
+ }
1323
+ }
1324
+ return target;
1325
+ };
1326
+ return _extends$7.apply(this, arguments);
1327
+ }
1328
+ var unlink = (({
1329
+ styles = {},
1330
+ ...props
1331
+ }) => /*#__PURE__*/React.createElement("svg", _extends$7({
1332
+ xmlns: "http://www.w3.org/2000/svg",
1333
+ viewBox: "0 0 512 512",
1334
+ "aria-hidden": "true"
1335
+ }, props), /*#__PURE__*/React.createElement("path", {
1336
+ d: "M360 0c-39-.001-78 14.8-107 44.4L185 112l-1 1 57 56s1 0 1-1l67-67c28-28.2 74-28.1 102 1 28 28 27 73-1 101l-13 14c-4 4-6 10-4 16 6 17 9 35 10 53 1 14 18 20 27 11l38-38c59-59 59-155 0-214.6C438 14.8 399 .001 360 0zm-63 165c-4 0-8 2-11 5l-22 21v1l107 107c2-41-13-82-44-114a152 152 0 00-21-17c-3-2-6-3-9-3zM93.3 211c-4.1 0-8.4 1-11.7 4l-37.1 38c-59.3 59-59.3 155 0 215C104 527 200 527 259 468l68-68v-1l-56-56s-1 0-1 1l-67 67c-28 28-74 28-102-1-28.2-28-27.4-73 1-101l13-14c4-4 6-10 4-16-6-17-10-35-10-53 0-9-8-15-15.7-15zm47.7 2c-2 41 13 82 44 114a152 152 0 0021 17c6 4 15 4 20-2l22-21v-1L141 213z"
1337
+ }), /*#__PURE__*/React.createElement("path", {
1338
+ stroke: "#000",
1339
+ strokeWidth: "68.787",
1340
+ strokeLinecap: "round",
1341
+ d: "M64 64l384 384"
1342
+ })));
1343
+
1344
+ const icons = {
1345
+ background,
1346
+ foreground,
1347
+ link: LinkIcon,
1348
+ pencil,
1349
+ unlink
1350
+ };
1351
+ function ActionButtons({
1352
+ buttons,
1353
+ position,
1354
+ portal,
1355
+ floatingStrategy,
1356
+ size = 'md'
1357
+ }) {
1358
+ var _middlewareData$hide;
1359
+ const iconSize = size === 'md' ? 15 : 20;
1360
+ const {
1361
+ refs,
1362
+ floatingStyles,
1363
+ middlewareData
1364
+ } = useFloating({
1365
+ strategy: floatingStrategy,
1366
+ placement: position === 'center' ? 'bottom' : position === 'inside' ? 'top-end' : position === 'outsideLeft' ? 'bottom-start' : position === 'topRight' ? 'top-end' : 'bottom-end',
1367
+ middleware: portal && [hide({
1368
+ strategy: 'escaped'
1369
+ }), shift({
1370
+ elementContext: 'reference'
1371
+ })],
1372
+ whileElementsMounted: autoUpdate
1373
+ });
1374
+ return /*#__PURE__*/React.createElement("span", {
1375
+ className: classNames(styles$9.reference, styles$9[`position-${position}`]),
1376
+ ref: refs.setReference
1377
+ }, /*#__PURE__*/React.createElement(Portal, {
1378
+ enabled: !!portal,
1379
+ aboveNavigationWidgets: portal === 'aboveNavigationWidgets'
1380
+ }, /*#__PURE__*/React.createElement("div", {
1381
+ ref: refs.setFloating,
1382
+ className: classNames(styles$9.floating, {
1383
+ [styles$9.escaped]: (_middlewareData$hide = middlewareData.hide) === null || _middlewareData$hide === void 0 ? void 0 : _middlewareData$hide.escaped
1384
+ }),
1385
+ style: floatingStyles
1386
+ }, /*#__PURE__*/React.createElement("div", {
1387
+ className: styles$9.buttons
1388
+ }, buttons.map(({
1389
+ icon,
1390
+ text,
1391
+ onClick,
1392
+ iconOnly
1393
+ }, index) => {
1394
+ const Icon = icons[icon];
1395
+ return /*#__PURE__*/React.createElement("button", {
1396
+ key: index,
1397
+ className: classNames(styles$9.button, styles$9[`size-${size}`], {
1398
+ [styles$9.iconOnly]: iconOnly
1399
+ }),
1400
+ onClick: onClick,
1401
+ title: iconOnly ? text : undefined,
1402
+ "aria-label": iconOnly ? text : undefined
1403
+ }, /*#__PURE__*/React.createElement(Icon, {
1404
+ width: iconSize,
1405
+ height: iconSize
1406
+ }), !iconOnly && text);
1407
+ })))));
1408
+ }
1409
+ function Portal({
1410
+ enabled,
1411
+ aboveNavigationWidgets,
1412
+ children
1413
+ }) {
1414
+ const floatingPortalRoot = useFloatingPortalRoot();
1415
+ if (enabled) {
1416
+ return /*#__PURE__*/React.createElement(FloatingPortal, {
1417
+ id: aboveNavigationWidgets ? 'floating-ui-above-navigation-widgets' : undefined,
1418
+ root: floatingPortalRoot
1419
+ }, children);
1420
+ } else {
1421
+ return children;
1422
+ }
1423
+ }
1424
+
1425
+ function ActionButton({
1426
+ icon,
1427
+ text,
1428
+ onClick,
1429
+ iconOnly,
1430
+ ...rest
1431
+ }) {
1432
+ return /*#__PURE__*/React.createElement(ActionButtons, Object.assign({}, rest, {
1433
+ buttons: [{
1434
+ icon,
1435
+ text,
1436
+ onClick,
1437
+ iconOnly
1438
+ }]
1439
+ }));
1440
+ }
1441
+
1442
+ function BackdropDecorator({
1443
+ backdrop,
1444
+ motifAreaState,
1445
+ children
1446
+ }) {
1447
+ var _backdrop$contentElem, _backdrop$contentElem2;
1448
+ const {
1449
+ t
1450
+ } = useI18n({
1451
+ locale: 'ui'
1452
+ });
1453
+ const {
1454
+ isSelected: isSectionSelected,
1455
+ select: selectSection
1456
+ } = useEditorSelection({
1457
+ id: (_backdrop$contentElem = backdrop.contentElement) === null || _backdrop$contentElem === void 0 ? void 0 : _backdrop$contentElem.sectionId,
1458
+ type: 'sectionSettings'
1459
+ });
1460
+ const {
1461
+ isSelected: isBackdropElementSelected,
1462
+ select: selectBackdropElement
1463
+ } = useEditorSelection({
1464
+ id: (_backdrop$contentElem2 = backdrop.contentElement) === null || _backdrop$contentElem2 === void 0 ? void 0 : _backdrop$contentElem2.id,
1465
+ type: 'contentElement'
1466
+ });
1467
+ const scrollToTarget = useScrollToTarget();
1468
+ let text, icon, handleClick;
1469
+ if (isBackdropElementSelected) {
1470
+ text = t('pageflow_scrolled.inline_editing.back_to_section');
1471
+ icon = 'foreground';
1472
+ handleClick = () => selectSection();
1473
+ } else if (backdrop.contentElement) {
1474
+ text = t('pageflow_scrolled.inline_editing.select_backdrop_content_element');
1475
+ icon = 'background';
1476
+ handleClick = () => {
1477
+ scrollToTarget({
1478
+ id: backdrop.contentElement.sectionId,
1479
+ align: 'start'
1480
+ });
1481
+ selectBackdropElement();
1482
+ };
1483
+ } else {
1484
+ return children;
1485
+ }
1486
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
1487
+ className: classNames(styles$1.wrapper, {
1488
+ [styles$1.visible]: isBackdropElementSelected || isSectionSelected
1489
+ }),
1490
+ style: {
1491
+ height: motifAreaState.paddingTop
1492
+ }
1493
+ }, /*#__PURE__*/React.createElement("div", {
1494
+ className: styles$1.inner
1495
+ }, /*#__PURE__*/React.createElement(ActionButton, {
1496
+ size: "lg",
1497
+ position: "center",
1498
+ icon: icon,
1499
+ text: text,
1500
+ onClick: handleClick
1501
+ }))), children);
1502
+ }
1503
+
1504
+ function BackgroundContentElementDecorator({
1505
+ contentElement,
1506
+ children
1507
+ }) {
1508
+ const {
1509
+ isSelected
1510
+ } = useEditorSelection({
1511
+ id: contentElement === null || contentElement === void 0 ? void 0 : contentElement.id,
1512
+ type: 'contentElement'
1513
+ });
1514
+ const {
1515
+ isSelected: isSectionSelected
1516
+ } = useEditorSelection({
1517
+ id: contentElement === null || contentElement === void 0 ? void 0 : contentElement.sectionId,
1518
+ type: 'sectionSettings'
1519
+ });
1520
+ return /*#__PURE__*/React.createElement("div", {
1521
+ style: {
1522
+ pointerEvents: isSelected || isSectionSelected ? 'auto' : 'none'
1523
+ }
1524
+ }, children);
1525
+ }
1526
+
1527
+ function _extends$8() {
1528
+ _extends$8 = Object.assign ? Object.assign.bind() : function (target) {
1529
+ for (var i = 1; i < arguments.length; i++) {
1530
+ var source = arguments[i];
1531
+ for (var key in source) {
1532
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
1533
+ target[key] = source[key];
1534
+ }
1535
+ }
1536
+ }
1537
+ return target;
1538
+ };
1539
+ return _extends$8.apply(this, arguments);
1540
+ }
1541
+ var paddingTopIcon = (({
1542
+ styles = {},
1543
+ ...props
1544
+ }) => /*#__PURE__*/React.createElement("svg", _extends$8({
1545
+ xmlns: "http://www.w3.org/2000/svg",
1546
+ width: "18",
1547
+ height: "18",
1548
+ viewBox: "0 3 24 27",
1549
+ fill: "none",
1550
+ stroke: "currentColor",
1551
+ strokeWidth: "2",
1552
+ strokeLinecap: "round",
1553
+ strokeLinejoin: "round",
1554
+ className: (styles["lucide"] || "lucide") + " " + (styles["lucide-unfold-vertical-icon"] || "lucide-unfold-vertical-icon") + " " + (styles["lucide-unfold-vertical"] || "lucide-unfold-vertical")
1555
+ }, props), /*#__PURE__*/React.createElement("path", {
1556
+ d: "M12 22v-6m-8-4H2m8 0H8m8 0h-2m8 0h-2m-5 7l-3 3-3-3"
1557
+ })));
1558
+
1559
+ function _extends$9() {
1560
+ _extends$9 = Object.assign ? Object.assign.bind() : function (target) {
1561
+ for (var i = 1; i < arguments.length; i++) {
1562
+ var source = arguments[i];
1563
+ for (var key in source) {
1564
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
1565
+ target[key] = source[key];
1566
+ }
1567
+ }
1568
+ }
1569
+ return target;
1570
+ };
1571
+ return _extends$9.apply(this, arguments);
1572
+ }
1573
+ var paddingBottomIcon = (({
1574
+ styles = {},
1575
+ ...props
1576
+ }) => /*#__PURE__*/React.createElement("svg", _extends$9({
1577
+ xmlns: "http://www.w3.org/2000/svg",
1578
+ width: "18",
1579
+ height: "18",
1580
+ viewBox: "0 -3 24 21",
1581
+ fill: "none",
1582
+ stroke: "currentColor",
1583
+ strokeWidth: "2",
1584
+ strokeLinecap: "round",
1585
+ strokeLinejoin: "round",
1586
+ className: (styles["lucide"] || "lucide") + " " + (styles["lucide-unfold-vertical-icon"] || "lucide-unfold-vertical-icon") + " " + (styles["lucide-unfold-vertical"] || "lucide-unfold-vertical")
1587
+ }, props), /*#__PURE__*/React.createElement("path", {
1588
+ d: "M12 8V2M4 12H2m8 0H8m8 0h-2m8 0h-2m-5-7l-3-3-3 3"
1589
+ })));
1590
+
1591
+ const paddingIcons = {
1592
+ top: paddingTopIcon,
1593
+ bottom: paddingBottomIcon
1594
+ };
1595
+ const scaleNames = {
1596
+ top: 'sectionPaddingTop',
1597
+ bottom: 'sectionPaddingBottom'
1598
+ };
1599
+ const scaleDefaultPropertyNames = {
1600
+ sectionPaddingTop: 'sectionDefaultPaddingTop',
1601
+ sectionPaddingBottom: 'sectionDefaultPaddingBottom'
1602
+ };
1603
+ function PaddingIndicator({
1604
+ section,
1605
+ motifAreaState,
1606
+ paddingValue,
1607
+ position,
1608
+ suppressed
1609
+ }) {
1610
+ const Icon = paddingIcons[position];
1611
+ const theme = useTheme();
1612
+ const {
1613
+ t
1614
+ } = useI18n({
1615
+ locale: 'ui'
1616
+ });
1617
+ const {
1618
+ isSelected: isSectionSelected
1619
+ } = useEditorSelection({
1620
+ id: section.id,
1621
+ type: 'sectionSettings'
1622
+ });
1623
+ const {
1624
+ isSelected: isPaddingSelected,
1625
+ select
1626
+ } = useEditorSelection({
1627
+ id: section.id,
1628
+ type: 'sectionPaddings',
1629
+ position
1630
+ });
1631
+ const motifPadding = (motifAreaState === null || motifAreaState === void 0 ? void 0 : motifAreaState.paddingTop) > 0;
1632
+ if (isSectionSelected || isPaddingSelected) {
1633
+ return /*#__PURE__*/React.createElement("div", {
1634
+ "aria-label": t(`pageflow_scrolled.inline_editing.edit_section_padding_${position}`),
1635
+ className: classNames(styles$4[`indicator-${position}`], {
1636
+ [styles$4.selected]: isPaddingSelected,
1637
+ [styles$4.motif]: motifPadding,
1638
+ [styles$4.none]: !motifPadding && (paddingValue === 'none' || suppressed)
1639
+ }),
1640
+ onClick: () => select()
1641
+ }, /*#__PURE__*/React.createElement("div", {
1642
+ className: styles$4.tooltip
1643
+ }, /*#__PURE__*/React.createElement(Icon, null), getPaddingText()));
1644
+ } else {
1645
+ return null;
1646
+ }
1647
+ function getPaddingText() {
1648
+ var _theme$options, _theme$translations;
1649
+ if (motifPadding) {
1650
+ return t('pageflow_scrolled.inline_editing.expose_motif_area');
1651
+ }
1652
+ if (suppressed) {
1653
+ const key = position === 'top' ? 'pageflow_scrolled.inline_editing.padding_suppressed_before_full_width' : 'pageflow_scrolled.inline_editing.padding_suppressed_after_full_width';
1654
+ return t(key);
1655
+ }
1656
+ const scaleName = scaleNames[position];
1657
+ const scope = getAppearanceSectionScopeName(section.appearance);
1658
+ const scale = Scale({
1659
+ scaleName,
1660
+ themeProperties: ((_theme$options = theme.options) === null || _theme$options === void 0 ? void 0 : _theme$options.properties) || {},
1661
+ scaleTranslations: ((_theme$translations = theme.translations) === null || _theme$translations === void 0 ? void 0 : _theme$translations.scales) || {},
1662
+ defaultValuePropertyName: scaleDefaultPropertyNames[scaleName],
1663
+ scope
1664
+ });
1665
+ const value = paddingValue || scale.defaultValue;
1666
+ const index = scale.values.indexOf(value);
1667
+ return scale.texts[index];
1668
+ }
1669
+ }
1670
+
1671
+ function ForegroundDecorator({
1672
+ section,
1673
+ motifAreaState,
1674
+ sectionPadding,
1675
+ suppressedPaddings,
1676
+ children
1677
+ }) {
1678
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(PaddingIndicator, {
1679
+ section: section,
1680
+ motifAreaState: motifAreaState,
1681
+ paddingValue: sectionPadding === null || sectionPadding === void 0 ? void 0 : sectionPadding.paddingTop,
1682
+ suppressed: suppressedPaddings === null || suppressedPaddings === void 0 ? void 0 : suppressedPaddings.top,
1683
+ position: "top"
1684
+ }), children, /*#__PURE__*/React.createElement(PaddingIndicator, {
1685
+ section: section,
1686
+ paddingValue: sectionPadding === null || sectionPadding === void 0 ? void 0 : sectionPadding.paddingBottom,
1687
+ suppressed: suppressedPaddings === null || suppressedPaddings === void 0 ? void 0 : suppressedPaddings.bottom,
1688
+ position: "bottom"
1689
+ }));
1690
+ }
1691
+
1692
+ var styles$a = {"container":"ContentElementInsertButton-module_container__3dvUS","hovered":"ContentElementInsertButton-module_hovered__3Pggi","button":"ContentElementInsertButton-module_button__2-eE2"};
1693
+
1694
+ function ContentElementInsertButton({
1695
+ onClick
1696
+ }) {
1697
+ const [hovered, setHovered] = useState();
1698
+ const {
1699
+ t
1700
+ } = useI18n({
1701
+ locale: 'ui'
1702
+ });
1703
+ return /*#__PURE__*/React.createElement("div", {
1704
+ className: classNames(styles$a.container, {
1705
+ [styles$a.hovered]: hovered
1706
+ })
1707
+ }, /*#__PURE__*/React.createElement("button", {
1708
+ className: styles$a.button,
1709
+ title: t('pageflow_scrolled.inline_editing.add_content_element'),
1710
+ onClick: onClick,
1711
+ onMouseDown: event => event.stopPropagation(),
1712
+ onMouseEnter: () => setHovered(true),
1713
+ onMouseLeave: () => setHovered(false)
1714
+ }, /*#__PURE__*/React.createElement(PlusIcon, {
1715
+ width: 15,
1716
+ height: 15,
1717
+ fill: "currentColor"
1718
+ })));
1719
+ }
1720
+
1721
+ function LayoutWithPlaceholder(props) {
1722
+ const {
1723
+ isSelected
1724
+ } = useEditorSelection({
1725
+ id: props.sectionId,
1726
+ type: 'section'
1727
+ });
1728
+ const {
1729
+ isSelected: settingsSelected
1730
+ } = useEditorSelection({
1731
+ id: props.sectionId,
1732
+ type: 'sectionSettings'
1733
+ });
1734
+ const placeholder = isSelected || settingsSelected ? /*#__PURE__*/React.createElement(ContentElementInsertButton, {
1735
+ onClick: () => postInsertContentElementMessage({
1736
+ at: 'endOfSection',
1737
+ id: props.sectionId
1738
+ })
1739
+ }) : null;
1740
+ return /*#__PURE__*/React.createElement(LayoutWithoutInlineEditing, Object.assign({}, props, {
1741
+ placeholder: placeholder
1742
+ }));
1743
+ }
1744
+
1745
+ const originalToSlateRange = ReactEditor.toSlateRange;
1746
+ ReactEditor.toSlateRange = function (editor, domRange) {
1747
+ try {
1748
+ return originalToSlateRange.apply(this, arguments);
1749
+ } catch (e) {
1750
+ if (e.message.startsWith('Cannot resolve a Slate point from DOM point') && domRange === window.getSelection() && editor.selection) {
1751
+ console.warn('Ignored "Cannot resolve a Slate point from DOM point" - selection outside editor');
1752
+ return editor.selection;
1753
+ }
1754
+ throw e;
1755
+ }
1756
+ };
1757
+
1758
+ function useCachedValue(value, {
1759
+ defaultValue,
1760
+ onReset,
1761
+ onDebouncedChange,
1762
+ delay = 2000
1763
+ } = {}) {
1764
+ const [cachedValue, setCachedValue] = useState(value || defaultValue);
1765
+ const previousValue = useRef(value);
1766
+ useEffect(() => {
1767
+ if (previousValue.current !== value && value !== cachedValue) {
1768
+ onReset && onReset(value);
1769
+ setCachedValue(value);
1770
+ }
1771
+ }, [onReset, value, cachedValue]);
1772
+ useEffect(() => {
1773
+ previousValue.current = value;
1774
+ });
1775
+ const debouncedHandler = useDebouncedCallback(onDebouncedChange, delay);
1776
+ const setValue = useCallback(value => {
1777
+ setCachedValue(previousValue => {
1778
+ if (previousValue !== value) {
1779
+ debouncedHandler(value);
1780
+ }
1781
+ return value;
1782
+ });
1783
+ }, [debouncedHandler]);
1784
+ return [cachedValue, setValue];
1785
+ }
1786
+
1787
+ // Debounce callback even if the callback function changes across renders.
1788
+ function useDebouncedCallback(callback, delay) {
1789
+ const mostRecentCallback = useRef(null);
1790
+ const debouncedHandler = useRef(null);
1791
+ useEffect(() => {
1792
+ mostRecentCallback.current = callback;
1793
+ }, [callback]);
1794
+ useEffect(() => {
1795
+ debouncedHandler.current = debounce(value => {
1796
+ if (mostRecentCallback.current) {
1797
+ mostRecentCallback.current(value);
1798
+ }
1799
+ }, delay);
1800
+ return () => {
1801
+ debouncedHandler.current.flush();
1802
+ };
1803
+ }, [delay]);
1804
+ return useCallback((...args) => debouncedHandler.current(...args), []);
1805
+ }
1806
+
1807
+ var styles$b = {"placeholder":"TextPlaceholder-module_placeholder__sgVwx"};
1808
+
1809
+ function TextPlaceholder({
1810
+ text,
1811
+ visible,
1812
+ className
1813
+ }) {
1814
+ if (!text || !visible) {
1815
+ return null;
1816
+ }
1817
+ return /*#__PURE__*/React.createElement("div", {
1818
+ className: styles$b.placeholder
1819
+ }, /*#__PURE__*/React.createElement("div", {
1820
+ className: className
1821
+ }, text));
1822
+ }
1823
+
1824
+ function rangeOverlapsSelection(range, selection) {
1825
+ if (!range || !selection) return false;
1826
+ const selStart = Range.start(selection);
1827
+ const selEnd = Range.end(selection);
1828
+ const selStartBlock = selStart.path[0];
1829
+ let selEndBlock = selEnd.path[0];
1830
+ if (selEndBlock !== selStartBlock && selEnd.offset === 0) {
1831
+ selEndBlock -= 1;
1832
+ }
1833
+ const startBlock = Range.start(range).path[0];
1834
+ return selStartBlock <= startBlock && startBlock <= selEndBlock;
1835
+ }
1836
+
1837
+ // The cursor that comment marks are measured against, so that the badge
1838
+ // column and the highlight overlay agree on which of them the reviewer
1839
+ // has selected.
1840
+ //
1841
+ // Treats `editor.selection` as a live cursor only while the editor is
1842
+ // focused. After the user clicks away, slate-react's throttled
1843
+ // `selectionchange` listener can sync a clamped DOM cursor back into
1844
+ // `editor.selection`, which would otherwise pass as a selection without
1845
+ // there being one.
1846
+ //
1847
+ // Falls back to the start point of the highlighted thread's range, so
1848
+ // that its block keeps counting as selected once focus has drifted away
1849
+ // from the slate editor — following a comment from the sidebar leaves it
1850
+ // outside. Just the start point, not the full range, to stay consistent
1851
+ // with rangeOverlapsSelection, which anchors to range starts.
1852
+ function useOverlapSelection(highlightedRange) {
1853
+ const editor = useSlate();
1854
+ const editorSelection = ReactEditor.isFocused(editor) ? editor.selection : null;
1855
+ const fallbackPoint = highlightedRange && Range.start(highlightedRange);
1856
+ return editorSelection || fallbackPoint && {
1857
+ anchor: fallbackPoint,
1858
+ focus: fallbackPoint
1859
+ };
1860
+ }
1861
+
1862
+ var styles$c = {"darkContentTextColor":"var(--theme-dark-content-text-color, #222)","lightContentTextColor":"var(--theme-light-content-text-color, #fff)","box":"BadgeColumn-module_box___7PO_","onDark":"BadgeColumn-module_onDark__3xkyl","onLight":"BadgeColumn-module_onLight__1xTpi"};
1863
+
1864
+ const noThreads = [];
1865
+ function BadgeColumn({
1866
+ highlights,
1867
+ highlightedRange,
1868
+ anchors
1869
+ }) {
1870
+ const editor = useSlate();
1871
+
1872
+ // The same for every badge, so resolved once here rather than per badge.
1873
+ const overlapSelection = useOverlapSelection(highlightedRange);
1874
+ return highlights.map(highlight => /*#__PURE__*/React.createElement(PositionedBadge, {
1875
+ key: highlight.key,
1876
+ editor: editor,
1877
+ highlight: highlight,
1878
+ overlapSelection: overlapSelection,
1879
+ anchors: anchors
1880
+ }));
1881
+ }
1882
+ function PositionedBadge({
1883
+ editor,
1884
+ highlight,
1885
+ overlapSelection,
1886
+ anchors
1887
+ }) {
1888
+ var _highlight$thread2;
1889
+ const {
1890
+ selected,
1891
+ highlightedThreadId,
1892
+ selectComments,
1893
+ selectThread
1894
+ } = useContentElementCommentSelection();
1895
+ const {
1896
+ alwaysShowComments
1897
+ } = useCommentDisplayFilter();
1898
+ const {
1899
+ refs,
1900
+ floatingStyles,
1901
+ hasAnchor
1902
+ } = useAnchoredFloating(highlight.key, anchors, {
1903
+ placement: 'left-start'
1904
+ });
1905
+ const threads = useMemo(() => highlight.thread ? [highlight.thread] : noThreads, [highlight.thread]);
1906
+ const unreadCount = useUnreadActivityCount(threads);
1907
+ const handleClick = useCallback(() => {
1908
+ var _highlight$thread;
1909
+ if (highlight.key === 'selection') {
1910
+ selectComments();
1911
+ return;
1912
+ }
1913
+
1914
+ // Don't try to also clear the DOM selection here: calling
1915
+ // removeAllRanges fires a selectionchange that slate-react's
1916
+ // listener picks up and uses to overwrite editor.selection back
1917
+ // to null — undoing this Transforms.select and dropping the
1918
+ // selection rect. The visible text selection therefore lingers
1919
+ // on screen until the user's next interaction with the editor;
1920
+ // slate's internal state (which downstream consumers depend on)
1921
+ // stays correct.
1922
+ Transforms.select(editor, Range.start(highlight.range));
1923
+ selectThread((_highlight$thread = highlight.thread) === null || _highlight$thread === void 0 ? void 0 : _highlight$thread.id);
1924
+ }, [editor, highlight, selectComments, selectThread]);
1925
+ if (!hasAnchor) return null;
1926
+ const isHighlightedThread = !!highlight.thread && highlightedThreadId === highlight.thread.id;
1927
+ const isActive = isHighlightedThread || highlight.key === 'selection' && selected === 'newThread';
1928
+ const mode = isActive ? 'active' : rangeOverlapsSelection(highlight.range, overlapSelection) ? undefined : alwaysShowComments ? 'dot' : 'none';
1929
+ return /*#__PURE__*/React.createElement("div", {
1930
+ ref: refs.setFloating,
1931
+ className: styles$c.box,
1932
+ style: floatingStyles
1933
+ }, /*#__PURE__*/React.createElement(Badge, {
1934
+ counter: 1,
1935
+ mode: mode,
1936
+ resolved: !!((_highlight$thread2 = highlight.thread) === null || _highlight$thread2 === void 0 ? void 0 : _highlight$thread2.resolvedAt),
1937
+ unreadCount: unreadCount,
1938
+ onClick: handleClick
1939
+ }));
1940
+ }
1941
+
1942
+ function useEffectiveSelection(editor, onChange) {
1943
+ const isDragging = useEditorDragging(editor);
1944
+ useEffect(() => {
1945
+ const {
1946
+ selection
1947
+ } = editor;
1948
+ if (isDragging || !selection || !ReactEditor.isFocused(editor) || Range.isCollapsed(selection) || Editor.string(editor, selection) === '') {
1949
+ onChange(null);
1950
+ return;
1951
+ }
1952
+ onChange(selection);
1953
+ }, [editor, editor.selection, isDragging, onChange]);
1954
+ }
1955
+ function useEditorDragging(editor) {
1956
+ const [isDragging, setIsDragging] = useState(false);
1957
+ useEffect(() => {
1958
+ const editorEl = ReactEditor.toDOMNode(editor, editor);
1959
+ function handleMouseDown() {
1960
+ setIsDragging(true);
1961
+ function handleMouseUp() {
1962
+ // Selection sometimes only resets after mouseup has fired
1963
+ // when clicking inside an existing selection.
1964
+ setTimeout(() => setIsDragging(false), 10);
1965
+ }
1966
+ document.addEventListener('mouseup', handleMouseUp, {
1967
+ once: true
1968
+ });
1969
+ }
1970
+ editorEl.addEventListener('mousedown', handleMouseDown);
1971
+ return () => editorEl.removeEventListener('mousedown', handleMouseDown);
1972
+ }, [editor]);
1973
+ return isDragging;
1974
+ }
1975
+
1976
+ function useStartNewThread(editor) {
1977
+ const {
1978
+ inlineComments
1979
+ } = useContentElementAttributes();
1980
+ const commentingEnabled = features.isEnabled('commenting') && inlineComments;
1981
+ const {
1982
+ selectNewThread
1983
+ } = useContentElementCommentSelection();
1984
+ if (!commentingEnabled) return null;
1985
+ return () => selectNewThread(editor.selection);
1986
+ }
1987
+
1988
+ function PendingSelectionBadge({
1989
+ containerRef
1990
+ }) {
1991
+ const editor = useSlate();
1992
+ const [isVisible, setIsVisible] = useState(false);
1993
+ const darkBackground = useDarkBackground();
1994
+ const startNewThread = useStartNewThread(editor);
1995
+ const {
1996
+ refs,
1997
+ floatingStyles
1998
+ } = useFloating({
1999
+ placement: 'left-start',
2000
+ middleware: [alignToContainerEdge(containerRef, {
2001
+ mainAxisOffset: 32
2002
+ })]
2003
+ });
2004
+ useEffectiveSelection(editor, useCallback(selection => {
2005
+ if (!selection) {
2006
+ setIsVisible(false);
2007
+ return;
2008
+ }
2009
+ const domRange = ReactEditor.toDOMRange(editor, selection);
2010
+ refs.setPositionReference({
2011
+ getBoundingClientRect: () => domRange.getBoundingClientRect(),
2012
+ getClientRects: () => domRange.getClientRects()
2013
+ });
2014
+ setIsVisible(true);
2015
+ }, [editor, refs]));
2016
+ if (!isVisible) return null;
2017
+ return /*#__PURE__*/React.createElement("div", {
2018
+ ref: refs.setFloating,
2019
+ className: classNames(styles$c.box, darkBackground ? styles$c.onDark : styles$c.onLight),
2020
+ style: floatingStyles
2021
+ }, /*#__PURE__*/React.createElement(Badge, {
2022
+ counter: 0,
2023
+ mode: "icon",
2024
+ onClick: startNewThread
2025
+ }));
2026
+ }
2027
+
2028
+ // Keeps a Slate `rangeRef` per comment thread alive so that ongoing
2029
+ // text edits stay reflected in the thread's effective subject range
2030
+ // without round-tripping through the server. When the upstream value
2031
+ // is replaced (e.g. after a structural shift applied by the editor),
2032
+ // `EditableText` calls `resetRangeRefs` from `useCachedValue`'s
2033
+ // `onReset`, which fires from an effect *before* `setCachedValue`
2034
+ // triggers the re-render in which Slate's `<Slate>` useMemo replaces
2035
+ // `editor.children` with the new value. So `resetRangeRefs` only
2036
+ // drops the stale refs and arms `pendingResyncRef`; the second effect
2037
+ // below consumes that flag on the next render — by which point
2038
+ // `editor.children` has flipped — and rebuilds against the new
2039
+ // content. Rebuilding inside `resetRangeRefs` would sync against the
2040
+ // still-old content and skip migrated threads whose new path doesn't
2041
+ // yet exist there.
2042
+ function useCommentRangeRefs(editor, threads) {
2043
+ const rangeRefsMap = useRef(new Map());
2044
+ const pendingResyncRef = useRef(false);
2045
+ const syncRangeRefs = useCallback(threads => {
2046
+ const map = rangeRefsMap.current;
2047
+ const currentIds = new Set(threads.map(t => t.id));
2048
+ for (const [id, rangeRef] of map) {
2049
+ if (!currentIds.has(id)) {
2050
+ rangeRef.unref();
2051
+ map.delete(id);
2052
+ }
2053
+ }
2054
+ for (const thread of threads) {
2055
+ if (!map.has(thread.id) && isValidRange(editor, thread.subjectRange)) {
2056
+ map.set(thread.id, Editor.rangeRef(editor, thread.subjectRange, {
2057
+ affinity: 'inward'
2058
+ }));
2059
+ }
2060
+ }
2061
+ }, [editor]);
2062
+ useEffect(() => {
2063
+ syncRangeRefs(threads);
2064
+ }, [threads, syncRangeRefs]);
2065
+ useEffect(() => {
2066
+ const map = rangeRefsMap.current;
2067
+ return () => {
2068
+ for (const rangeRef of map.values()) {
2069
+ rangeRef.unref();
2070
+ }
2071
+ map.clear();
2072
+ };
2073
+ }, [editor]);
2074
+ useEffect(() => {
2075
+ if (pendingResyncRef.current) {
2076
+ pendingResyncRef.current = false;
2077
+ syncRangeRefs(threads);
2078
+ }
2079
+ });
2080
+ const resetRangeRefs = useCallback(() => {
2081
+ for (const rangeRef of rangeRefsMap.current.values()) {
2082
+ rangeRef.unref();
2083
+ }
2084
+ rangeRefsMap.current.clear();
2085
+ pendingResyncRef.current = true;
2086
+ }, []);
2087
+ const trackedThreads = threads.map(t => {
2088
+ const rangeRef = rangeRefsMap.current.get(t.id);
2089
+ return (rangeRef === null || rangeRef === void 0 ? void 0 : rangeRef.current) ? {
2090
+ ...t,
2091
+ subjectRange: rangeRef.current
2092
+ } : t;
2093
+ });
2094
+ const getTrackedSubjectRanges = useCallback(() => {
2095
+ const ranges = {};
2096
+ threads.forEach(t => {
2097
+ const rangeRef = rangeRefsMap.current.get(t.id);
2098
+ if (rangeRef === null || rangeRef === void 0 ? void 0 : rangeRef.current) {
2099
+ ranges[t.id] = rangeRef.current;
2100
+ }
2101
+ });
2102
+ return ranges;
2103
+ }, [threads]);
2104
+ return {
2105
+ trackedThreads,
2106
+ resetRangeRefs,
2107
+ getTrackedSubjectRanges
2108
+ };
2109
+ }
2110
+ function isValidRange(editor, range) {
2111
+ return range && Node$1.has(editor, range.anchor.path) && Node$1.has(editor, range.focus.path);
2112
+ }
2113
+
2114
+ const noThreads$1 = [];
2115
+
2116
+ // Bundles all commenting-related state and render helpers for the
2117
+ // EditableText editor. Returns `enabled: false` when commenting is
2118
+ // disabled for the current content element; consumers can then skip
2119
+ // the commenting-specific decorate/BadgeColumn paths.
2120
+ function useCommenting(editor) {
2121
+ const {
2122
+ contentElementPermaId,
2123
+ inlineComments
2124
+ } = useContentElementAttributes();
2125
+ const enabled = features.isEnabled('commenting') && inlineComments;
2126
+
2127
+ // Track ranges for resolved threads too, so their subject ranges keep
2128
+ // following live edits and stay correct once a thread is reopened.
2129
+ // Resolved threads are merely hidden from the highlight overlay until
2130
+ // they become the highlighted thread (see `visibleThreads`).
2131
+ const elementThreads = useCommentThreads({
2132
+ subjectType: 'ContentElement',
2133
+ subjectId: contentElementPermaId
2134
+ });
2135
+ const threads = enabled ? elementThreads : noThreads$1;
2136
+ const {
2137
+ trackedThreads,
2138
+ resetRangeRefs,
2139
+ getTrackedSubjectRanges
2140
+ } = useCommentRangeRefs(editor, threads);
2141
+ const {
2142
+ anchors,
2143
+ registerAnchor
2144
+ } = useRangeAnchors();
2145
+ const {
2146
+ resolution
2147
+ } = useCommentDisplayFilter();
2148
+ const {
2149
+ highlightedThreadId,
2150
+ newThreadRange,
2151
+ selectThread
2152
+ } = useContentElementCommentSelection();
2153
+
2154
+ // Move the cursor into the thread's block before the handler selects
2155
+ // it, so `Selection`'s `cursorLeftHighlightedThreadBlock` does not
2156
+ // treat a pre-existing cursor as having left the comment and re-select
2157
+ // the content element, which would hide the highlight again. Routing
2158
+ // through the handler also reveals a resolved thread (via
2159
+ // `visibleThreads`) when it is selected.
2160
+ useSelectCommentThreadHandler({
2161
+ subjectType: 'ContentElement',
2162
+ subjectId: contentElementPermaId,
2163
+ getScrollTarget: useCallback(threadId => {
2164
+ const range = getTrackedSubjectRanges()[threadId];
2165
+ return range ? domElementAtRangeStart(editor, range) : null;
2166
+ }, [editor, getTrackedSubjectRanges]),
2167
+ beforeSelect: useCallback(threadId => {
2168
+ const range = getTrackedSubjectRanges()[threadId];
2169
+ if (range) {
2170
+ Transforms.select(editor, Range.start(range));
2171
+ }
2172
+ }, [editor, getTrackedSubjectRanges]),
2173
+ selectThread
2174
+ });
2175
+
2176
+ // Build highlights for all tracked threads, resolved ones included, so
2177
+ // the thread ids at the cursor (which scope the comments sidebar) cover
2178
+ // them too. Only `visibleHighlights` get a text overlay and a badge.
2179
+ const highlights = useCommentHighlights(trackedThreads, newThreadRange);
2180
+ const visibleHighlights = useMemo(() => highlights.filter(highlight => isVisible(highlight, {
2181
+ resolution,
2182
+ highlightedThreadId
2183
+ })), [highlights, resolution, highlightedThreadId]);
2184
+
2185
+ // Stands in for the cursor once focus has left the editor, for the
2186
+ // badges as much as for the overlay.
2187
+ const highlightedRange = useMemo(() => {
2188
+ var _visibleHighlights$fi;
2189
+ return (_visibleHighlights$fi = visibleHighlights.find(highlight => {
2190
+ var _highlight$thread;
2191
+ return ((_highlight$thread = highlight.thread) === null || _highlight$thread === void 0 ? void 0 : _highlight$thread.id) === highlightedThreadId;
2192
+ })) === null || _visibleHighlights$fi === void 0 ? void 0 : _visibleHighlights$fi.range;
2193
+ }, [visibleHighlights, highlightedThreadId]);
2194
+ const decorate = useMemo(() => enabled ? decorateCommentHighlights(editor, visibleHighlights) : null, [editor, visibleHighlights, enabled]);
2195
+ const withCommentHighlightDecoration = useCallback(({
2196
+ attributes,
2197
+ children,
2198
+ leaf
2199
+ }) => {
2200
+ if (leaf.commentHighlight) {
2201
+ children = /*#__PURE__*/React.createElement(HighlightSpan, {
2202
+ rangeKey: leaf.rangeKey,
2203
+ subjectRange: leaf.subjectRange,
2204
+ highlightedRange: highlightedRange,
2205
+ resolved: leaf.resolved
2206
+ }, children);
2207
+ }
2208
+ if (leaf.firstInRange) {
2209
+ children = /*#__PURE__*/React.createElement(RangeAnchor, {
2210
+ rangeKey: leaf.rangeKey,
2211
+ onRegister: registerAnchor
2212
+ }, children);
2213
+ }
2214
+ return {
2215
+ attributes,
2216
+ children,
2217
+ leaf
2218
+ };
2219
+ // `threads` and `newThreadRange` are included to invalidate this
2220
+ // callback (and the `renderLeaf` that wraps it) when decorations
2221
+ // change. Without that, slate-react's `MemoizedText` would skip
2222
+ // re-rendering leaves whose decorations changed because its memo
2223
+ // equality function does not compare `decorations`.
2224
+ // eslint-disable-next-line react-hooks/exhaustive-deps
2225
+ }, [registerAnchor, contentElementPermaId, threads, newThreadRange, highlightedThreadId, highlightedRange, resolution]);
2226
+ return {
2227
+ enabled,
2228
+ highlights,
2229
+ visibleHighlights,
2230
+ highlightedRange,
2231
+ anchors,
2232
+ decorate,
2233
+ withCommentHighlightDecoration,
2234
+ resetRangeRefs,
2235
+ getTrackedSubjectRanges
2236
+ };
2237
+ }
2238
+
2239
+ // The range of a thread being composed and the thread the reviewer picked
2240
+ // show even where the resolution filter would hide them.
2241
+ function isVisible({
2242
+ thread
2243
+ }, {
2244
+ resolution,
2245
+ highlightedThreadId
2246
+ }) {
2247
+ return !thread || thread.id === highlightedThreadId || resolution === 'all' || !thread.resolvedAt;
2248
+ }
2249
+
2250
+ // A resolved thread has no badge yet to scroll itself into view, so the
2251
+ // commented text is scrolled directly. The leaf DOM already exists, so
2252
+ // this resolves even before the highlight re-renders.
2253
+ function domElementAtRangeStart(editor, range) {
2254
+ try {
2255
+ const start = Range.start(range);
2256
+ const domRange = ReactEditor.toDOMRange(editor, {
2257
+ anchor: start,
2258
+ focus: start
2259
+ });
2260
+ const {
2261
+ startContainer
2262
+ } = domRange;
2263
+ return startContainer.nodeType === Node.ELEMENT_NODE ? startContainer : startContainer.parentElement;
2264
+ } catch (e) {
2265
+ // toDOMRange throws when the range is not currently rendered.
2266
+ return null;
2267
+ }
2268
+ }
2269
+ function HighlightSpan({
2270
+ rangeKey,
2271
+ subjectRange,
2272
+ highlightedRange,
2273
+ resolved,
2274
+ children
2275
+ }) {
2276
+ const threadId = parseInt(rangeKey, 10);
2277
+ const {
2278
+ selected,
2279
+ highlightedThreadId
2280
+ } = useContentElementCommentSelection();
2281
+ const {
2282
+ alwaysShowComments
2283
+ } = useCommentDisplayFilter();
2284
+
2285
+ // Comes through the slate context, which reaches this span on every
2286
+ // selection change even though the memoized leaf around it does not
2287
+ // re-render for one.
2288
+ const overlapSelection = useOverlapSelection(highlightedRange);
2289
+ const isSelected = selected === 'comments' && highlightedThreadId === threadId || rangeKey === 'selection' && selected === 'newThread';
2290
+
2291
+ // The question the badge column asks as well: what the reviewer has not
2292
+ // selected is what an uncluttered view leaves out.
2293
+ if (!alwaysShowComments && !isSelected && !rangeOverlapsSelection(subjectRange, overlapSelection)) {
2294
+ return children;
2295
+ }
2296
+ return /*#__PURE__*/React.createElement("span", {
2297
+ className: classNames(commentHighlightStyles.highlight, {
2298
+ [commentHighlightStyles.resolved]: resolved,
2299
+ [commentHighlightStyles.selected]: isSelected && !resolved
2300
+ })
2301
+ }, children);
2302
+ }
2303
+
2304
+ function withCustomInsertBreak(editor) {
2305
+ const {
2306
+ insertBreak
2307
+ } = editor;
2308
+ editor.insertBreak = function () {
2309
+ const {
2310
+ selection
2311
+ } = editor;
2312
+ if (selection && Range.isCollapsed(selection)) {
2313
+ const match = Editor.above(editor, {
2314
+ match: n => Editor.isBlock(editor, n)
2315
+ });
2316
+ if (match) {
2317
+ const [block, path] = match;
2318
+ if (Editor.isEnd(editor, selection.anchor, path) && block.type === 'heading') {
2319
+ Transforms.insertNodes(editor, {
2320
+ type: 'paragraph',
2321
+ children: [{
2322
+ text: ''
2323
+ }]
2324
+ });
2325
+ return;
2326
+ }
2327
+ }
2328
+ }
2329
+ insertBreak();
2330
+ };
2331
+ return editor;
2332
+ }
2333
+
2334
+ var styles$d = {"linkTooltip":"LinkTooltip-module_linkTooltip__esBv0","thumbnail":"LinkTooltip-module_thumbnail__3Vzce","thumbnailClickMask":"LinkTooltip-module_thumbnailClickMask__3iSZw","newTab":"LinkTooltip-module_newTab__3uW7O","chapterNumber":"LinkTooltip-module_chapterNumber__YUvjI"};
2335
+
2336
+ function _extends$a() {
2337
+ _extends$a = Object.assign ? Object.assign.bind() : function (target) {
2338
+ for (var i = 1; i < arguments.length; i++) {
2339
+ var source = arguments[i];
2340
+ for (var key in source) {
2341
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
2342
+ target[key] = source[key];
2343
+ }
2344
+ }
2345
+ }
2346
+ return target;
2347
+ };
2348
+ return _extends$a.apply(this, arguments);
2349
+ }
2350
+ var ExternalLinkIcon = (({
2351
+ styles = {},
2352
+ ...props
2353
+ }) => /*#__PURE__*/React.createElement("svg", _extends$a({
2354
+ "aria-hidden": "true",
2355
+ "data-prefix": "fas",
2356
+ "data-icon": "external-link-alt",
2357
+ className: (styles["svg-inline--fa"] || "svg-inline--fa") + " " + (styles["fa-external-link-alt"] || "fa-external-link-alt") + " " + (styles["fa-w-16"] || "fa-w-16"),
2358
+ xmlns: "http://www.w3.org/2000/svg",
2359
+ viewBox: "0 0 512 512"
2360
+ }, props), /*#__PURE__*/React.createElement("path", {
2361
+ fill: "currentColor",
2362
+ d: "M432 320h-32a16 16 0 00-16 16v112H64V128h144a16 16 0 0016-16V80a16 16 0 00-16-16H48a48 48 0 00-48 48v352a48 48 0 0048 48h352a48 48 0 0048-48V336a16 16 0 00-16-16zM488 0H360c-21.37 0-32.05 25.91-17 41l35.73 35.73L135 320.37a24 24 0 000 34L157.67 377a24 24 0 0034 0l243.61-243.68L471 169c15 15 41 4.5 41-17V24a24 24 0 00-24-24z"
2363
+ })));
2364
+
2365
+ const UpdateContext = createContext();
2366
+ function LinkTooltipProvider(props) {
2367
+ const update = useContext(UpdateContext);
2368
+ if (update) {
2369
+ return props.children;
2370
+ } else {
2371
+ return /*#__PURE__*/React.createElement(LinkTooltipProviderInner, props);
2372
+ }
2373
+ }
2374
+ function LinkTooltipProviderInner({
2375
+ disabled,
2376
+ position,
2377
+ floatingStrategy,
2378
+ onClick,
2379
+ children,
2380
+ align = 'left',
2381
+ gap = 10
2382
+ }) {
2383
+ const storylineMode = useStorylineActivity();
2384
+ const [state, setState] = useState();
2385
+ const arrowRef = useRef();
2386
+ const {
2387
+ refs,
2388
+ floatingStyles,
2389
+ context: floatingContext
2390
+ } = useFloating({
2391
+ strategy: floatingStrategy,
2392
+ placement: `${position === 'below' ? 'bottom' : 'top'}${align === 'left' ? '-start' : ''}`,
2393
+ middleware: [offset(gap), shift(), arrow({
2394
+ element: arrowRef,
2395
+ padding: 10
2396
+ }), inline()],
2397
+ whileElementsMounted: autoUpdate
2398
+ });
2399
+ const update = useMemo(() => {
2400
+ let timeout;
2401
+ return {
2402
+ activate(href, openInNewTab, linkRef) {
2403
+ clearTimeout(timeout);
2404
+ timeout = null;
2405
+ refs.setReference(linkRef.current);
2406
+ setState({
2407
+ href,
2408
+ openInNewTab
2409
+ });
2410
+ },
2411
+ keep() {
2412
+ clearTimeout(timeout);
2413
+ timeout = null;
2414
+ },
2415
+ deactivate({
2416
+ delay = 200
2417
+ } = {}) {
2418
+ if (!timeout) {
2419
+ timeout = setTimeout(() => {
2420
+ timeout = null;
2421
+ setState(null);
2422
+ }, delay);
2423
+ }
2424
+ }
2425
+ };
2426
+ }, [refs]);
2427
+ useEffect(() => {
2428
+ if (storylineMode !== 'active') {
2429
+ update.deactivate({
2430
+ delay: 0
2431
+ });
2432
+ }
2433
+ }, [storylineMode, update]);
2434
+ return /*#__PURE__*/React.createElement(UpdateContext.Provider, {
2435
+ value: update
2436
+ }, /*#__PURE__*/React.createElement(FloatingPortal, {
2437
+ root: useFloatingPortalRoot()
2438
+ }, /*#__PURE__*/React.createElement(LinkTooltip, {
2439
+ state: state,
2440
+ setFloating: refs.setFloating,
2441
+ floatingStyles: floatingStyles,
2442
+ floatingContext: floatingContext,
2443
+ arrowRef: arrowRef,
2444
+ onClick: onClick,
2445
+ disabled: disabled
2446
+ })), children);
2447
+ }
2448
+ function LinkPreview({
2449
+ disabled,
2450
+ href,
2451
+ openInNewTab,
2452
+ children,
2453
+ className
2454
+ }) {
2455
+ const {
2456
+ activate,
2457
+ deactivate
2458
+ } = useContext(UpdateContext);
2459
+ const ref = useRef();
2460
+ useEffect(() => {
2461
+ if (disabled) {
2462
+ deactivate({
2463
+ delay: 0
2464
+ });
2465
+ }
2466
+ }, [disabled, deactivate]);
2467
+ return /*#__PURE__*/React.createElement("span", {
2468
+ ref: ref,
2469
+ className: className,
2470
+ onMouseEnter: () => !disabled && activate(href, openInNewTab, ref),
2471
+ onMouseLeave: () => !disabled && deactivate()
2472
+ }, children);
2473
+ }
2474
+ function LinkTooltip({
2475
+ disabled,
2476
+ setFloating,
2477
+ floatingStyles,
2478
+ floatingContext,
2479
+ arrowRef,
2480
+ onClick,
2481
+ state
2482
+ }) {
2483
+ const {
2484
+ keep,
2485
+ deactivate
2486
+ } = useContext(UpdateContext);
2487
+ if (disabled || !state || !state.href) {
2488
+ return null;
2489
+ }
2490
+ function handleClick(event) {
2491
+ event.stopPropagation();
2492
+ if (onClick) {
2493
+ onClick(event);
2494
+ }
2495
+ }
2496
+ return /*#__PURE__*/React.createElement("div", {
2497
+ ref: setFloating,
2498
+ className: classNames(styles$d.linkTooltip),
2499
+ onClick: handleClick,
2500
+ onMouseEnter: keep,
2501
+ onMouseLeave: deactivate,
2502
+ style: floatingStyles
2503
+ }, /*#__PURE__*/React.createElement(FloatingArrow, {
2504
+ ref: arrowRef,
2505
+ context: floatingContext
2506
+ }), /*#__PURE__*/React.createElement(LinkDestination, {
2507
+ href: state.href,
2508
+ openInNewTab: state.openInNewTab
2509
+ }));
2510
+ }
2511
+ function LinkDestination({
2512
+ href,
2513
+ openInNewTab
2514
+ }) {
2515
+ if (href === null || href === void 0 ? void 0 : href.chapter) {
2516
+ return /*#__PURE__*/React.createElement(ChapterLinkDestination, {
2517
+ permaId: href.chapter
2518
+ });
2519
+ } else if (href === null || href === void 0 ? void 0 : href.section) {
2520
+ return /*#__PURE__*/React.createElement(SectionLinkDestination, {
2521
+ permaId: href.section
2522
+ });
2523
+ } else if (href === null || href === void 0 ? void 0 : href.file) {
2524
+ return /*#__PURE__*/React.createElement(FileLinkDestination, {
2525
+ fileOptions: href.file
2526
+ });
2527
+ } else {
2528
+ return /*#__PURE__*/React.createElement(ExternalLinkDestination, {
2529
+ href: href,
2530
+ openInNewTab: openInNewTab
2531
+ });
2532
+ }
2533
+ }
2534
+ function ChapterLinkDestination({
2535
+ permaId
2536
+ }) {
2537
+ const chapter = useChapter({
2538
+ permaId
2539
+ });
2540
+ const mainStoryline = useMainStoryline();
2541
+ const {
2542
+ t
2543
+ } = useI18n({
2544
+ locale: 'ui'
2545
+ });
2546
+ if (!chapter) {
2547
+ return /*#__PURE__*/React.createElement("span", null, t('pageflow_scrolled.inline_editing.link_tooltip.deleted_chapter'));
2548
+ }
2549
+ const isExcursion = mainStoryline && chapter.storylineId !== mainStoryline.id;
2550
+ if (isExcursion) {
2551
+ return /*#__PURE__*/React.createElement("a", {
2552
+ href: `#${chapter.chapterSlug}`,
2553
+ title: t('pageflow_scrolled.inline_editing.link_tooltip.visit_excursion')
2554
+ }, chapter.title ? t('pageflow_scrolled.inline_editing.link_tooltip.excursion_with_title', {
2555
+ title: chapter.title
2556
+ }) : t('pageflow_scrolled.inline_editing.link_tooltip.untitled_excursion'));
2557
+ }
2558
+ return /*#__PURE__*/React.createElement("a", {
2559
+ href: `#${chapter.chapterSlug}`,
2560
+ title: t('pageflow_scrolled.inline_editing.link_tooltip.visit_chapter')
2561
+ }, /*#__PURE__*/React.createElement("span", {
2562
+ className: styles$d.chapterNumber
2563
+ }, t('pageflow_scrolled.inline_editing.link_tooltip.chapter_number', {
2564
+ number: chapter.index + 1
2565
+ })), " ", chapter.title);
2566
+ }
2567
+ function SectionLinkDestination({
2568
+ permaId
2569
+ }) {
2570
+ const {
2571
+ t
2572
+ } = useI18n({
2573
+ locale: 'ui'
2574
+ });
2575
+ return /*#__PURE__*/React.createElement("div", {
2576
+ className: styles$d.thumbnail
2577
+ }, /*#__PURE__*/React.createElement(SectionThumbnail, {
2578
+ sectionPermaId: permaId
2579
+ }), /*#__PURE__*/React.createElement("a", {
2580
+ href: `#section-${permaId}`,
2581
+ className: styles$d.thumbnailClickMask,
2582
+ title: t('pageflow_scrolled.inline_editing.link_tooltip.visit_section')
2583
+ }));
2584
+ }
2585
+ function ExternalLinkDestination({
2586
+ href,
2587
+ openInNewTab
2588
+ }) {
2589
+ const {
2590
+ t
2591
+ } = useI18n({
2592
+ locale: 'ui'
2593
+ });
2594
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("a", {
2595
+ href: href,
2596
+ target: "_blank",
2597
+ rel: "noopener noreferrer"
2598
+ }, href, /*#__PURE__*/React.createElement(ExternalLinkIcon, {
2599
+ width: 10,
2600
+ height: 10
2601
+ })), /*#__PURE__*/React.createElement("div", {
2602
+ className: styles$d.newTab
2603
+ }, openInNewTab ? t('pageflow_scrolled.inline_editing.link_tooltip.opens_in_new_tab') : t('pageflow_scrolled.inline_editing.link_tooltip.opens_in_same_tab')));
2604
+ }
2605
+ function FileLinkDestination({
2606
+ fileOptions
2607
+ }) {
2608
+ const file = useDownloadableFile(fileOptions);
2609
+ const {
2610
+ t
2611
+ } = useI18n({
2612
+ locale: 'ui'
2613
+ });
2614
+ if (!file) {
2615
+ return /*#__PURE__*/React.createElement("span", null, t('pageflow_scrolled.inline_editing.link_tooltip.deleted_file'));
2616
+ }
2617
+ return /*#__PURE__*/React.createElement("a", {
2618
+ href: file.urls.download,
2619
+ target: "_blank",
2620
+ rel: "noopener noreferrer"
2621
+ }, file.displayName, /*#__PURE__*/React.createElement(ExternalLinkIcon, {
2622
+ width: 10,
2623
+ height: 10
2624
+ }));
2625
+ }
2626
+
2627
+ function withLinks(editor) {
2628
+ const {
2629
+ isInline
2630
+ } = editor;
2631
+ editor.isInline = element => {
2632
+ return element.type === 'link' ? true : isInline(element);
2633
+ };
2634
+ return editor;
2635
+ }
2636
+ const renderElementWithLinkPreview = wrapRenderElementWithLinkPreview(renderElement);
2637
+ function wrapRenderElementWithLinkPreview(renderElement) {
2638
+ return function (options) {
2639
+ if (options.element.type === 'link') {
2640
+ return /*#__PURE__*/React.createElement(LinkPreview, {
2641
+ href: options.element.href,
2642
+ openInNewTab: options.element.openInNewTab
2643
+ }, renderElement(options));
2644
+ } else {
2645
+ return renderElement(options);
2646
+ }
2647
+ };
2648
+ }
2649
+
2650
+ // Used to render drop targets between paragraphs only when a content
2651
+ // element is currently being dragged over the element. `react-dnd`
2652
+ // causes "Update on unmounted component warning" when dropping an
2653
+ // element removes a drop target [1]. As a workaround, couple
2654
+ // rendering of drop targets to asynchronously updated state. That way
2655
+ // the drop target is only removed after element has been dropped.
2656
+ //
2657
+ // [1] https://github.com/react-dnd/react-dnd/issues/1573
2658
+ function useDropTargetsActive() {
2659
+ const [dropTargetsActive, setDropTargetsActive] = useState(false);
2660
+ const [{
2661
+ canDrop
2662
+ }, drop] = useDrop({
2663
+ accept: 'contentElement',
2664
+ collect: monitor => ({
2665
+ canDrop: monitor.canDrop() && monitor.isOver()
2666
+ })
2667
+ });
2668
+ useEffect(() => {
2669
+ if (canDrop) {
2670
+ setDropTargetsActive(true);
2671
+ } else {
2672
+ const timeout = setTimeout(() => {
2673
+ setDropTargetsActive(false);
2674
+ }, 10);
2675
+ return () => {
2676
+ clearTimeout(timeout);
2677
+ };
2678
+ }
2679
+ }, [canDrop]);
2680
+ return [dropTargetsActive, drop];
2681
+ }
2682
+
2683
+ let abortPreviousCall;
2684
+ function useSelectLinkDestination() {
2685
+ return () => {
2686
+ return new Promise((resolve, reject) => {
2687
+ if (abortPreviousCall) {
2688
+ abortPreviousCall();
2689
+ }
2690
+ abortPreviousCall = () => {
2691
+ window.removeEventListener('message', receive);
2692
+ reject();
2693
+ };
2694
+ postSelectLinkDestinationMessage();
2695
+ window.addEventListener('message', receive);
2696
+ function receive(message) {
2697
+ if (window.location.href.indexOf(message.origin) === 0) {
2698
+ if (message.data.type === 'LINK_DESTINATION_SELECTED') {
2699
+ abortPreviousCall = null;
2700
+ window.removeEventListener('message', receive);
2701
+ resolve(message.data.payload);
2702
+ }
2703
+ }
2704
+ }
2705
+ });
2706
+ };
2707
+ }
2708
+
2709
+ const mutuallyExclusive = {
2710
+ sup: 'sub',
2711
+ sub: 'sup'
2712
+ };
2713
+ function toggleMark(editor, format) {
2714
+ const isActive = isMarkActive(editor, format);
2715
+ if (isActive) {
2716
+ Editor.removeMark(editor, format);
2717
+ } else {
2718
+ if (mutuallyExclusive[format] && isMarkActive(editor, mutuallyExclusive[format])) {
2719
+ Editor.removeMark(editor, mutuallyExclusive[format]);
2720
+ }
2721
+ Editor.addMark(editor, format, true);
2722
+ }
2723
+ }
2724
+ function isMarkActive(editor, format) {
2725
+ const marks = Editor.marks(editor);
2726
+ return marks ? marks[format] === true : false;
2727
+ }
2728
+
2729
+ function _extends$b() {
2730
+ _extends$b = Object.assign ? Object.assign.bind() : function (target) {
2731
+ for (var i = 1; i < arguments.length; i++) {
2732
+ var source = arguments[i];
2733
+ for (var key in source) {
2734
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
2735
+ target[key] = source[key];
2736
+ }
2737
+ }
2738
+ }
2739
+ return target;
2740
+ };
2741
+ return _extends$b.apply(this, arguments);
2742
+ }
2743
+ var BoldIcon = (({
2744
+ styles = {},
2745
+ ...props
2746
+ }) => /*#__PURE__*/React.createElement("svg", _extends$b({
2747
+ "aria-hidden": "true",
2748
+ "data-prefix": "fas",
2749
+ "data-icon": "bold",
2750
+ className: (styles["svg-inline--fa"] || "svg-inline--fa") + " " + (styles["fa-bold"] || "fa-bold") + " " + (styles["fa-w-12"] || "fa-w-12"),
2751
+ xmlns: "http://www.w3.org/2000/svg",
2752
+ viewBox: "0 0 384 512"
2753
+ }, props), /*#__PURE__*/React.createElement("path", {
2754
+ fill: "currentColor",
2755
+ d: "M333.49 238a122 122 0 0027-65.21C367.87 96.49 308 32 233.42 32H34a16 16 0 00-16 16v48a16 16 0 0016 16h31.87v288H34a16 16 0 00-16 16v48a16 16 0 0016 16h209.32c70.8 0 134.14-51.75 141-122.4 4.74-48.45-16.39-92.06-50.83-119.6zM145.66 112h87.76a48 48 0 010 96h-87.76zm87.76 288h-87.76V288h87.76a56 56 0 010 112z"
2756
+ })));
2757
+
2758
+ function _extends$c() {
2759
+ _extends$c = Object.assign ? Object.assign.bind() : function (target) {
2760
+ for (var i = 1; i < arguments.length; i++) {
2761
+ var source = arguments[i];
2762
+ for (var key in source) {
2763
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
2764
+ target[key] = source[key];
2765
+ }
2766
+ }
2767
+ }
2768
+ return target;
2769
+ };
2770
+ return _extends$c.apply(this, arguments);
2771
+ }
2772
+ var UnderlineIcon = (({
2773
+ styles = {},
2774
+ ...props
2775
+ }) => /*#__PURE__*/React.createElement("svg", _extends$c({
2776
+ "aria-hidden": "true",
2777
+ "data-prefix": "fas",
2778
+ "data-icon": "underline",
2779
+ className: (styles["svg-inline--fa"] || "svg-inline--fa") + " " + (styles["fa-underline"] || "fa-underline") + " " + (styles["fa-w-14"] || "fa-w-14"),
2780
+ xmlns: "http://www.w3.org/2000/svg",
2781
+ viewBox: "0 0 448 512"
2782
+ }, props), /*#__PURE__*/React.createElement("path", {
2783
+ fill: "currentColor",
2784
+ d: "M32 64h32v160c0 88.22 71.78 160 160 160s160-71.78 160-160V64h32a16 16 0 0016-16V16a16 16 0 00-16-16H272a16 16 0 00-16 16v32a16 16 0 0016 16h32v160a80 80 0 01-160 0V64h32a16 16 0 0016-16V16a16 16 0 00-16-16H32a16 16 0 00-16 16v32a16 16 0 0016 16zm400 384H16a16 16 0 00-16 16v32a16 16 0 0016 16h416a16 16 0 0016-16v-32a16 16 0 00-16-16z"
2785
+ })));
2786
+
2787
+ function _extends$d() {
2788
+ _extends$d = Object.assign ? Object.assign.bind() : function (target) {
2789
+ for (var i = 1; i < arguments.length; i++) {
2790
+ var source = arguments[i];
2791
+ for (var key in source) {
2792
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
2793
+ target[key] = source[key];
2794
+ }
2795
+ }
2796
+ }
2797
+ return target;
2798
+ };
2799
+ return _extends$d.apply(this, arguments);
2800
+ }
2801
+ var ItalicIcon = (({
2802
+ styles = {},
2803
+ ...props
2804
+ }) => /*#__PURE__*/React.createElement("svg", _extends$d({
2805
+ "aria-hidden": "true",
2806
+ "data-prefix": "fas",
2807
+ "data-icon": "italic",
2808
+ className: (styles["svg-inline--fa"] || "svg-inline--fa") + " " + (styles["fa-italic"] || "fa-italic") + " " + (styles["fa-w-10"] || "fa-w-10"),
2809
+ xmlns: "http://www.w3.org/2000/svg",
2810
+ viewBox: "0 0 320 512"
2811
+ }, props), /*#__PURE__*/React.createElement("path", {
2812
+ fill: "currentColor",
2813
+ d: "M320 48v32a16 16 0 01-16 16h-62.76l-80 320H208a16 16 0 0116 16v32a16 16 0 01-16 16H16a16 16 0 01-16-16v-32a16 16 0 0116-16h62.76l80-320H112a16 16 0 01-16-16V48a16 16 0 0116-16h192a16 16 0 0116 16z"
2814
+ })));
2815
+
2816
+ function _extends$e() {
2817
+ _extends$e = Object.assign ? Object.assign.bind() : function (target) {
2818
+ for (var i = 1; i < arguments.length; i++) {
2819
+ var source = arguments[i];
2820
+ for (var key in source) {
2821
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
2822
+ target[key] = source[key];
2823
+ }
2824
+ }
2825
+ }
2826
+ return target;
2827
+ };
2828
+ return _extends$e.apply(this, arguments);
2829
+ }
2830
+ var StrikethroughIcon = (({
2831
+ styles = {},
2832
+ ...props
2833
+ }) => /*#__PURE__*/React.createElement("svg", _extends$e({
2834
+ "aria-hidden": "true",
2835
+ "data-prefix": "fas",
2836
+ "data-icon": "strikethrough",
2837
+ className: (styles["svg-inline--fa"] || "svg-inline--fa") + " " + (styles["fa-strikethrough"] || "fa-strikethrough") + " " + (styles["fa-w-16"] || "fa-w-16"),
2838
+ xmlns: "http://www.w3.org/2000/svg",
2839
+ viewBox: "0 0 512 512"
2840
+ }, props), /*#__PURE__*/React.createElement("path", {
2841
+ fill: "currentColor",
2842
+ d: "M496 224H293.9l-87.17-26.83A43.55 43.55 0 01219.55 112h66.79A49.89 49.89 0 01331 139.58a16 16 0 0021.46 7.15l42.94-21.47a16 16 0 007.16-21.46l-.53-1A128 128 0 00287.51 32h-68a123.68 123.68 0 00-123 135.64c2 20.89 10.1 39.83 21.78 56.36H16a16 16 0 00-16 16v32a16 16 0 0016 16h480a16 16 0 0016-16v-32a16 16 0 00-16-16zm-180.24 96A43 43 0 01336 356.45 43.59 43.59 0 01292.45 400h-66.79A49.89 49.89 0 01181 372.42a16 16 0 00-21.46-7.15l-42.94 21.47a16 16 0 00-7.16 21.46l.53 1A128 128 0 00224.49 480h68a123.68 123.68 0 00123-135.64 114.25 114.25 0 00-5.34-24.36z"
2843
+ })));
2844
+
2845
+ function _extends$f() {
2846
+ _extends$f = Object.assign ? Object.assign.bind() : function (target) {
2847
+ for (var i = 1; i < arguments.length; i++) {
2848
+ var source = arguments[i];
2849
+ for (var key in source) {
2850
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
2851
+ target[key] = source[key];
2852
+ }
2853
+ }
2854
+ }
2855
+ return target;
2856
+ };
2857
+ return _extends$f.apply(this, arguments);
2858
+ }
2859
+ var SubIcon = (({
2860
+ styles = {},
2861
+ ...props
2862
+ }) => /*#__PURE__*/React.createElement("svg", _extends$f({
2863
+ xmlns: "http://www.w3.org/2000/svg",
2864
+ viewBox: "0 0 512 512"
2865
+ }, props), /*#__PURE__*/React.createElement("path", {
2866
+ d: "M32 64C14.3 64 0 78.3 0 96s14.3 32 32 32h15.3l89.6 128-89.6 128H32c-17.7 0-32 14.3-32 32s14.3 32 32 32h32c10.4 0 20.2-5.1 26.2-13.6L176 311.8l85.8 122.6c6 8.6 15.8 13.6 26.2 13.6h32c17.7 0 32-14.3 32-32s-14.3-32-32-32h-15.3l-89.6-128 89.6-128H320c17.7 0 32-14.3 32-32s-14.3-32-32-32h-32c-10.4 0-20.2 5.1-26.2 13.6L176 200.2 90.2 77.6C84.2 69.1 74.4 64 64 64H32zm448 256c0-11.1-5.7-21.4-15.2-27.2s-21.2-6.4-31.1-1.4l-32 16c-15.8 7.9-22.2 27.1-14.3 42.9C393 361.5 404.3 368 416 368v80c-17.7 0-32 14.3-32 32s14.3 32 32 32h64c17.7 0 32-14.3 32-32s-14.3-32-32-32V320z"
2867
+ })));
2868
+
2869
+ function _extends$g() {
2870
+ _extends$g = Object.assign ? Object.assign.bind() : function (target) {
2871
+ for (var i = 1; i < arguments.length; i++) {
2872
+ var source = arguments[i];
2873
+ for (var key in source) {
2874
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
2875
+ target[key] = source[key];
2876
+ }
2877
+ }
2878
+ }
2879
+ return target;
2880
+ };
2881
+ return _extends$g.apply(this, arguments);
2882
+ }
2883
+ var SupIcon = (({
2884
+ styles = {},
2885
+ ...props
2886
+ }) => /*#__PURE__*/React.createElement("svg", _extends$g({
2887
+ xmlns: "http://www.w3.org/2000/svg",
2888
+ viewBox: "0 0 512 512"
2889
+ }, props), /*#__PURE__*/React.createElement("path", {
2890
+ d: "M480 32c0-11.1-5.7-21.4-15.2-27.2s-21.2-6.4-31.1-1.4l-32 16c-15.8 7.9-22.2 27.1-14.3 42.9C393 73.5 404.3 80 416 80v80c-17.7 0-32 14.3-32 32s14.3 32 32 32h64c17.7 0 32-14.3 32-32s-14.3-32-32-32V32zM32 64C14.3 64 0 78.3 0 96s14.3 32 32 32h15.3l89.6 128-89.6 128H32c-17.7 0-32 14.3-32 32s14.3 32 32 32h32c10.4 0 20.2-5.1 26.2-13.6L176 311.8l85.8 122.6c6 8.6 15.8 13.6 26.2 13.6h32c17.7 0 32-14.3 32-32s-14.3-32-32-32h-15.3l-89.6-128 89.6-128H320c17.7 0 32-14.3 32-32s-14.3-32-32-32h-32c-10.4 0-20.2 5.1-26.2 13.6L176 200.2 90.2 77.6C84.2 69.1 74.4 64 64 64H32z"
2891
+ })));
2892
+
2893
+ function HoveringToolbar({
2894
+ children
2895
+ }) {
2896
+ const editor = useSlate();
2897
+ const {
2898
+ t
2899
+ } = useI18n({
2900
+ locale: 'ui'
2901
+ });
2902
+ const selectLinkDestination = useSelectLinkDestination();
2903
+ const [isOpen, setIsOpen] = useState(false);
2904
+ const {
2905
+ refs,
2906
+ floatingStyles
2907
+ } = useFloating({
2908
+ placement: 'bottom-start',
2909
+ middleware: [offset(5), shift({
2910
+ crossAxis: true,
2911
+ padding: {
2912
+ left: 10,
2913
+ right: 10
2914
+ }
2915
+ })]
2916
+ });
2917
+ useEffectiveSelection(editor, useCallback(selection => {
2918
+ if (!selection) {
2919
+ setIsOpen(false);
2920
+ return;
2921
+ }
2922
+ const domRange = ReactEditor.toDOMRange(editor, selection);
2923
+ refs.setPositionReference({
2924
+ getBoundingClientRect: () => domRange.getBoundingClientRect(),
2925
+ getClientRects: () => domRange.getClientRects()
2926
+ });
2927
+ setIsOpen(true);
2928
+ }, [editor, refs]));
2929
+ const floatingPortalRoot = useFloatingPortalRoot();
2930
+ return /*#__PURE__*/React.createElement(React.Fragment, null, isOpen && /*#__PURE__*/React.createElement(FloatingPortal, {
2931
+ root: floatingPortalRoot
2932
+ }, /*#__PURE__*/React.createElement("div", {
2933
+ ref: refs.setFloating,
2934
+ style: floatingStyles
2935
+ }, renderToolbar$1(editor, t, selectLinkDestination))), children);
2936
+ }
2937
+ function renderToolbar$1(editor, t, selectLinkDestination) {
2938
+ const buttons = [{
2939
+ name: 'bold',
2940
+ text: t('pageflow_scrolled.inline_editing.formats.bold'),
2941
+ icon: BoldIcon
2942
+ }, {
2943
+ name: 'italic',
2944
+ text: t('pageflow_scrolled.inline_editing.formats.italic'),
2945
+ icon: ItalicIcon
2946
+ }, {
2947
+ name: 'underline',
2948
+ text: t('pageflow_scrolled.inline_editing.formats.underline'),
2949
+ icon: UnderlineIcon
2950
+ }, {
2951
+ name: 'strikethrough',
2952
+ text: t('pageflow_scrolled.inline_editing.formats.strikethrough'),
2953
+ icon: StrikethroughIcon
2954
+ }, {
2955
+ name: 'sub',
2956
+ text: t('pageflow_scrolled.inline_editing.formats.sub'),
2957
+ icon: SubIcon
2958
+ }, {
2959
+ name: 'sup',
2960
+ text: t('pageflow_scrolled.inline_editing.formats.sup'),
2961
+ icon: SupIcon
2962
+ }, {
2963
+ name: 'link',
2964
+ text: isButtonActive(editor, 'link') ? t('pageflow_scrolled.inline_editing.remove_link') : t('pageflow_scrolled.inline_editing.insert_link'),
2965
+ icon: LinkIcon
2966
+ }].map(button => ({
2967
+ ...button,
2968
+ active: isButtonActive(editor, button.name)
2969
+ }));
2970
+ return /*#__PURE__*/React.createElement(Toolbar, {
2971
+ buttons: buttons,
2972
+ onButtonClick: name => handleButtonClick(editor, name, selectLinkDestination)
2973
+ });
2974
+ }
2975
+ function handleButtonClick(editor, format, selectLinkDestination) {
2976
+ if (format === 'link') {
2977
+ if (isLinkActive(editor)) {
2978
+ unwrapLink(editor);
2979
+ } else {
2980
+ selectLinkDestination().then(({
2981
+ href,
2982
+ openInNewTab
2983
+ }) => {
2984
+ wrapLink(editor, href, openInNewTab);
2985
+ }, () => {});
2986
+ }
2987
+ } else {
2988
+ toggleMark(editor, format);
2989
+ }
2990
+ }
2991
+ function isButtonActive(editor, format) {
2992
+ if (format === 'link') {
2993
+ return isLinkActive(editor);
2994
+ } else {
2995
+ return isMarkActive(editor, format);
2996
+ }
2997
+ }
2998
+ function unwrapLink(editor) {
2999
+ Transforms.unwrapNodes(editor, {
3000
+ match: n => n.type === 'link'
3001
+ });
3002
+ }
3003
+ function wrapLink(editor, href, openInNewTab) {
3004
+ const link = {
3005
+ type: 'link',
3006
+ href,
3007
+ openInNewTab,
3008
+ children: []
3009
+ };
3010
+ Transforms.wrapNodes(editor, link, {
3011
+ split: true
3012
+ });
3013
+ Transforms.collapse(editor, {
3014
+ edge: 'end'
3015
+ });
3016
+ }
3017
+ function isLinkActive(editor) {
3018
+ const [link] = Editor.nodes(editor, {
3019
+ match: n => n.type === 'link'
3020
+ });
3021
+ return !!link;
3022
+ }
3023
+
3024
+ var styles$e = {"container":"index-module_container__3dD9z","shy":"index-module_shy__KgWjc","selected":"index-module_selected__mE58y","selection":"index-module_selection__3dUiD"};
3025
+
3026
+ // True when the cursor's top-level block differs from the highlighted
3027
+ // thread's start block. Editing in the same block as the highlighted
3028
+ // thread should keep the highlight in place (so the comment can be
3029
+ // referenced while editing); only block changes mean the user moved
3030
+ // past the comment's anchor.
3031
+ function cursorLeftHighlightedThreadBlock({
3032
+ editor,
3033
+ highlightedThreadId,
3034
+ highlights
3035
+ }) {
3036
+ var _highlights$find;
3037
+ if (!highlightedThreadId || !highlights) {
3038
+ return false;
3039
+ }
3040
+ const highlightedRange = (_highlights$find = highlights.find(h => {
3041
+ var _h$thread;
3042
+ return ((_h$thread = h.thread) === null || _h$thread === void 0 ? void 0 : _h$thread.id) === highlightedThreadId;
3043
+ })) === null || _highlights$find === void 0 ? void 0 : _highlights$find.range;
3044
+ if (!highlightedRange) return false;
3045
+ return editor.selection.anchor.path[0] !== highlightedRange.anchor.path[0];
3046
+ }
3047
+
3048
+ // True when the cursor sits at a different range than the pending
3049
+ // new-thread range AND the editor is focused. The focus guard is
3050
+ // important: clicking the pending badge itself moves focus to the
3051
+ // portaled badge button and can drift editor.selection — but that
3052
+ // drift is not the user moving away from the new thread.
3053
+ function cursorMovedFromPendingNewThreadRange({
3054
+ editor,
3055
+ newThreadRange
3056
+ }) {
3057
+ if (!ReactEditor.isFocused(editor)) return false;
3058
+ return !Range.equals(editor.selection, newThreadRange);
3059
+ }
3060
+
3061
+ function getUniformSelectedNode(editor, propertyName) {
3062
+ const currentNodeEntries = [...Editor.nodes(editor, {
3063
+ match: n => !!n.type,
3064
+ mode: 'highest'
3065
+ })];
3066
+ const values = [...new Set(currentNodeEntries.map(([node, path]) => node[propertyName]))];
3067
+ return values.length === 1 ? currentNodeEntries[0][0] : null;
3068
+ }
3069
+
3070
+ function isBlockActive(editor, format) {
3071
+ const [match] = Editor.nodes(editor, {
3072
+ match: n => n.type === format
3073
+ });
3074
+ return !!match;
3075
+ }
3076
+ const listTypes = ['numbered-list', 'bulleted-list'];
3077
+ function toggleBlock(editor, format) {
3078
+ const isActive = isBlockActive(editor, format);
3079
+ const isList = listTypes.includes(format);
3080
+ Transforms.unwrapNodes(editor, {
3081
+ match: n => listTypes.includes(n.type),
3082
+ split: true
3083
+ });
3084
+ Transforms.setNodes(editor, {
3085
+ type: isActive ? 'paragraph' : isList ? 'list-item' : format
3086
+ });
3087
+ if (!isActive && isList) {
3088
+ const block = {
3089
+ type: format,
3090
+ children: [],
3091
+ ...preserveColorAndTypographyVariant(editor)
3092
+ };
3093
+ Transforms.wrapNodes(editor, block);
3094
+ }
3095
+ }
3096
+ function applyTypographyVariant(editor, variant) {
3097
+ applyProperties(editor, {
3098
+ variant
3099
+ });
3100
+ }
3101
+ function applyTypographySize(editor, size) {
3102
+ applyProperties(editor, {
3103
+ size
3104
+ });
3105
+ }
3106
+ function applyColor(editor, color) {
3107
+ applyProperties(editor, {
3108
+ color
3109
+ });
3110
+ }
3111
+ function applyTextAlign(editor, textAlign) {
3112
+ applyProperties(editor, {
3113
+ textAlign: textAlign === 'justify' ? 'justify' : undefined
3114
+ });
3115
+ }
3116
+ function applyProperties(editor, properties) {
3117
+ Transforms.setNodes(editor, properties, {
3118
+ mode: 'highest'
3119
+ });
3120
+ applyPropertiesToListItems(editor, properties);
3121
+ }
3122
+ function applyPropertiesToListItems(editor, properties) {
3123
+ const lists = Editor.nodes(editor, {
3124
+ match: n => listTypes.includes(n.type)
3125
+ });
3126
+ for (const [, listPath] of lists) {
3127
+ const items = Editor.nodes(editor, {
3128
+ at: listPath,
3129
+ match: n => n.type === 'list-item'
3130
+ });
3131
+ for (const [, itemPath] of items) {
3132
+ Transforms.setNodes(editor, properties, {
3133
+ at: itemPath
3134
+ });
3135
+ }
3136
+ }
3137
+ }
3138
+ function preserveColorAndTypographyVariant(editor) {
3139
+ const nodeEntry = Editor.above(editor, {
3140
+ at: Range.start(editor.selection),
3141
+ match: n => !!n.type
3142
+ });
3143
+ const result = {};
3144
+ if (nodeEntry && nodeEntry[0].variant) {
3145
+ result.variant = nodeEntry[0].variant;
3146
+ }
3147
+ if (nodeEntry && nodeEntry[0].color) {
3148
+ result.color = nodeEntry[0].color;
3149
+ }
3150
+ return result;
3151
+ }
3152
+ function withBlockNormalization({
3153
+ onlyParagraphs
3154
+ }, editor) {
3155
+ if (!onlyParagraphs) {
3156
+ return editor;
3157
+ }
3158
+ const {
3159
+ normalizeNode
3160
+ } = editor;
3161
+ editor.normalizeNode = ([node, path]) => {
3162
+ if (path.length === 0) {
3163
+ for (const [child, childPath] of Node$1.children(editor, path)) {
3164
+ if (Element$1.isElement(child) && child.type !== 'paragraph') {
3165
+ Transforms.unwrapNodes(editor, {
3166
+ match: n => listTypes.includes(n.type),
3167
+ split: true,
3168
+ at: childPath
3169
+ });
3170
+ Transforms.setNodes(editor, {
3171
+ type: 'paragraph'
3172
+ }, {
3173
+ at: childPath
3174
+ });
3175
+ }
3176
+ }
3177
+ }
3178
+ return normalizeNode([node, path]);
3179
+ };
3180
+ return editor;
3181
+ }
3182
+
3183
+ function commentThreadIdsAtSelection(highlights, selection) {
3184
+ if (!selection) return [];
3185
+ return highlights.filter(h => h.thread && rangeOverlapsSelection(h.range, selection)).map(h => h.thread.id);
3186
+ }
3187
+
3188
+ function computeBounds(editor) {
3189
+ if (!editor.selection) {
3190
+ return [0, 0];
3191
+ }
3192
+ const startPoint = Range.start(editor.selection);
3193
+ const endPoint = Range.end(editor.selection);
3194
+ const startPath = startPoint.path.slice(0, 1);
3195
+ let endPath = endPoint.path.slice(0, 1);
3196
+ if (!Path.equals(startPath, endPath) && endPoint.offset === 0) {
3197
+ endPath = Path.previous(endPath);
3198
+ }
3199
+ return [startPath[0], endPath[0]];
3200
+ }
3201
+
3202
+ // Range to seed a new comment thread on the current slate selection.
3203
+ // When the selection is collapsed (just a cursor), expand to the full
3204
+ // surrounding top-level block so the new thread anchors to the whole
3205
+ // paragraph rather than a zero-width point.
3206
+ function newCommentThreadSubjectRange(editor) {
3207
+ if (!editor.selection) return undefined;
3208
+ if (Range.isCollapsed(editor.selection)) {
3209
+ const blockIdx = editor.selection.anchor.path[0];
3210
+ return {
3211
+ anchor: Editor.point(editor, [blockIdx], {
3212
+ edge: 'start'
3213
+ }),
3214
+ focus: Editor.point(editor, [blockIdx], {
3215
+ edge: 'end'
3216
+ })
3217
+ };
3218
+ }
3219
+ return editor.selection;
3220
+ }
3221
+
3222
+ function _extends$h() {
3223
+ _extends$h = Object.assign ? Object.assign.bind() : function (target) {
3224
+ for (var i = 1; i < arguments.length; i++) {
3225
+ var source = arguments[i];
3226
+ for (var key in source) {
3227
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
3228
+ target[key] = source[key];
3229
+ }
3230
+ }
3231
+ }
3232
+ return target;
3233
+ };
3234
+ return _extends$h.apply(this, arguments);
3235
+ }
3236
+ var TextIcon = (({
3237
+ styles = {},
3238
+ ...props
3239
+ }) => /*#__PURE__*/React.createElement("svg", _extends$h({
3240
+ "aria-hidden": "true",
3241
+ "data-prefix": "fas",
3242
+ "data-icon": "align-justify",
3243
+ className: (styles["svg-inline--fa"] || "svg-inline--fa") + " " + (styles["fa-align-justify"] || "fa-align-justify") + " " + (styles["fa-w-14"] || "fa-w-14"),
3244
+ xmlns: "http://www.w3.org/2000/svg",
3245
+ viewBox: "0 0 448 512"
3246
+ }, props), /*#__PURE__*/React.createElement("path", {
3247
+ fill: "currentColor",
3248
+ d: "M432 416H16a16 16 0 00-16 16v32a16 16 0 0016 16h416a16 16 0 0016-16v-32a16 16 0 00-16-16zm0-128H16a16 16 0 00-16 16v32a16 16 0 0016 16h416a16 16 0 0016-16v-32a16 16 0 00-16-16zm0-128H16a16 16 0 00-16 16v32a16 16 0 0016 16h416a16 16 0 0016-16v-32a16 16 0 00-16-16zm0-128H16A16 16 0 000 48v32a16 16 0 0016 16h416a16 16 0 0016-16V48a16 16 0 00-16-16z"
3249
+ })));
3250
+
3251
+ function _extends$i() {
3252
+ _extends$i = Object.assign ? Object.assign.bind() : function (target) {
3253
+ for (var i = 1; i < arguments.length; i++) {
3254
+ var source = arguments[i];
3255
+ for (var key in source) {
3256
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
3257
+ target[key] = source[key];
3258
+ }
3259
+ }
3260
+ }
3261
+ return target;
3262
+ };
3263
+ return _extends$i.apply(this, arguments);
3264
+ }
3265
+ var HeadingIcon = (({
3266
+ styles = {},
3267
+ ...props
3268
+ }) => /*#__PURE__*/React.createElement("svg", _extends$i({
3269
+ "aria-hidden": "true",
3270
+ "data-prefix": "fas",
3271
+ "data-icon": "heading",
3272
+ className: (styles["svg-inline--fa"] || "svg-inline--fa") + " " + (styles["fa-heading"] || "fa-heading") + " " + (styles["fa-w-16"] || "fa-w-16"),
3273
+ xmlns: "http://www.w3.org/2000/svg",
3274
+ viewBox: "0 0 512 512"
3275
+ }, props), /*#__PURE__*/React.createElement("path", {
3276
+ fill: "currentColor",
3277
+ d: "M448 96v320h32a16 16 0 0116 16v32a16 16 0 01-16 16H320a16 16 0 01-16-16v-32a16 16 0 0116-16h32V288H160v128h32a16 16 0 0116 16v32a16 16 0 01-16 16H32a16 16 0 01-16-16v-32a16 16 0 0116-16h32V96H32a16 16 0 01-16-16V48a16 16 0 0116-16h160a16 16 0 0116 16v32a16 16 0 01-16 16h-32v128h192V96h-32a16 16 0 01-16-16V48a16 16 0 0116-16h160a16 16 0 0116 16v32a16 16 0 01-16 16z"
3278
+ })));
3279
+
3280
+ function _extends$j() {
3281
+ _extends$j = Object.assign ? Object.assign.bind() : function (target) {
3282
+ for (var i = 1; i < arguments.length; i++) {
3283
+ var source = arguments[i];
3284
+ for (var key in source) {
3285
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
3286
+ target[key] = source[key];
3287
+ }
3288
+ }
3289
+ }
3290
+ return target;
3291
+ };
3292
+ return _extends$j.apply(this, arguments);
3293
+ }
3294
+ var OlIcon = (({
3295
+ styles = {},
3296
+ ...props
3297
+ }) => /*#__PURE__*/React.createElement("svg", _extends$j({
3298
+ "aria-hidden": "true",
3299
+ "data-prefix": "fas",
3300
+ "data-icon": "list-ol",
3301
+ className: (styles["svg-inline--fa"] || "svg-inline--fa") + " " + (styles["fa-list-ol"] || "fa-list-ol") + " " + (styles["fa-w-16"] || "fa-w-16"),
3302
+ xmlns: "http://www.w3.org/2000/svg",
3303
+ viewBox: "0 0 512 512"
3304
+ }, props), /*#__PURE__*/React.createElement("path", {
3305
+ fill: "currentColor",
3306
+ d: "M61.77 401l17.5-20.15a19.92 19.92 0 005.07-14.19v-3.31C84.34 356 80.5 352 73 352H16a8 8 0 00-8 8v16a8 8 0 008 8h22.83a157.41 157.41 0 00-11 12.31l-5.61 7c-4 5.07-5.25 10.13-2.8 14.88l1.05 1.93c3 5.76 6.29 7.88 12.25 7.88h4.73c10.33 0 15.94 2.44 15.94 9.09 0 4.72-4.2 8.22-14.36 8.22a41.54 41.54 0 01-15.47-3.12c-6.49-3.88-11.74-3.5-15.6 3.12l-5.59 9.31c-3.72 6.13-3.19 11.72 2.63 15.94 7.71 4.69 20.38 9.44 37 9.44 34.16 0 48.5-22.75 48.5-44.12-.03-14.38-9.12-29.76-28.73-34.88zM496 224H176a16 16 0 00-16 16v32a16 16 0 0016 16h320a16 16 0 0016-16v-32a16 16 0 00-16-16zm0-160H176a16 16 0 00-16 16v32a16 16 0 0016 16h320a16 16 0 0016-16V80a16 16 0 00-16-16zm0 320H176a16 16 0 00-16 16v32a16 16 0 0016 16h320a16 16 0 0016-16v-32a16 16 0 00-16-16zM16 160h64a8 8 0 008-8v-16a8 8 0 00-8-8H64V40a8 8 0 00-8-8H32a8 8 0 00-7.14 4.42l-8 16A8 8 0 0024 64h8v64H16a8 8 0 00-8 8v16a8 8 0 008 8zm-3.91 160H80a8 8 0 008-8v-16a8 8 0 00-8-8H41.32c3.29-10.29 48.34-18.68 48.34-56.44 0-29.06-25-39.56-44.47-39.56-21.36 0-33.8 10-40.46 18.75-4.37 5.59-3 10.84 2.8 15.37l8.58 6.88c5.61 4.56 11 2.47 16.12-2.44a13.44 13.44 0 019.46-3.84c3.33 0 9.28 1.56 9.28 8.75C51 248.19 0 257.31 0 304.59v4C0 316 5.08 320 12.09 320z"
3307
+ })));
3308
+
3309
+ function _extends$k() {
3310
+ _extends$k = Object.assign ? Object.assign.bind() : function (target) {
3311
+ for (var i = 1; i < arguments.length; i++) {
3312
+ var source = arguments[i];
3313
+ for (var key in source) {
3314
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
3315
+ target[key] = source[key];
3316
+ }
3317
+ }
3318
+ }
3319
+ return target;
3320
+ };
3321
+ return _extends$k.apply(this, arguments);
3322
+ }
3323
+ var UlIcon = (({
3324
+ styles = {},
3325
+ ...props
3326
+ }) => /*#__PURE__*/React.createElement("svg", _extends$k({
3327
+ "aria-hidden": "true",
3328
+ "data-prefix": "fas",
3329
+ "data-icon": "list-ul",
3330
+ className: (styles["svg-inline--fa"] || "svg-inline--fa") + " " + (styles["fa-list-ul"] || "fa-list-ul") + " " + (styles["fa-w-16"] || "fa-w-16"),
3331
+ xmlns: "http://www.w3.org/2000/svg",
3332
+ viewBox: "0 0 512 512"
3333
+ }, props), /*#__PURE__*/React.createElement("path", {
3334
+ fill: "currentColor",
3335
+ d: "M48 48a48 48 0 1048 48 48 48 0 00-48-48zm0 160a48 48 0 1048 48 48 48 0 00-48-48zm0 160a48 48 0 1048 48 48 48 0 00-48-48zm448 16H176a16 16 0 00-16 16v32a16 16 0 0016 16h320a16 16 0 0016-16v-32a16 16 0 00-16-16zm0-320H176a16 16 0 00-16 16v32a16 16 0 0016 16h320a16 16 0 0016-16V80a16 16 0 00-16-16zm0 160H176a16 16 0 00-16 16v32a16 16 0 0016 16h320a16 16 0 0016-16v-32a16 16 0 00-16-16z"
3336
+ })));
3337
+
3338
+ function _extends$l() {
3339
+ _extends$l = Object.assign ? Object.assign.bind() : function (target) {
3340
+ for (var i = 1; i < arguments.length; i++) {
3341
+ var source = arguments[i];
3342
+ for (var key in source) {
3343
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
3344
+ target[key] = source[key];
3345
+ }
3346
+ }
3347
+ }
3348
+ return target;
3349
+ };
3350
+ return _extends$l.apply(this, arguments);
3351
+ }
3352
+ var QuoteIcon = (({
3353
+ styles = {},
3354
+ ...props
3355
+ }) => /*#__PURE__*/React.createElement("svg", _extends$l({
3356
+ "aria-hidden": "true",
3357
+ "data-prefix": "fas",
3358
+ "data-icon": "quote-right",
3359
+ className: (styles["svg-inline--fa"] || "svg-inline--fa") + " " + (styles["fa-quote-right"] || "fa-quote-right") + " " + (styles["fa-w-16"] || "fa-w-16"),
3360
+ xmlns: "http://www.w3.org/2000/svg",
3361
+ viewBox: "0 0 512 512"
3362
+ }, props), /*#__PURE__*/React.createElement("path", {
3363
+ fill: "currentColor",
3364
+ d: "M464 32H336c-26.5 0-48 21.5-48 48v128c0 26.5 21.5 48 48 48h80v64c0 35.3-28.7 64-64 64h-8c-13.3 0-24 10.7-24 24v48c0 13.3 10.7 24 24 24h8c88.4 0 160-71.6 160-160V80c0-26.5-21.5-48-48-48zm-288 0H48C21.5 32 0 53.5 0 80v128c0 26.5 21.5 48 48 48h80v64c0 35.3-28.7 64-64 64h-8c-13.3 0-24 10.7-24 24v48c0 13.3 10.7 24 24 24h8c88.4 0 160-71.6 160-160V80c0-26.5-21.5-48-48-48z"
3365
+ })));
3366
+
3367
+ function Selection(props) {
3368
+ const editor = useSlate();
3369
+ const {
3370
+ t
3371
+ } = useI18n({
3372
+ locale: 'ui'
3373
+ });
3374
+ const ref = useRef();
3375
+ const outerRef = useRef();
3376
+ const innerRef = useRef();
3377
+ const boundsRef = useRef();
3378
+ const lastRangeRef = useRef();
3379
+ const {
3380
+ setTransientState,
3381
+ select,
3382
+ isSelected: isContentElementSelected,
3383
+ type,
3384
+ range
3385
+ } = useContentElementEditorState();
3386
+ const {
3387
+ selected,
3388
+ highlightedThreadId,
3389
+ newThreadRange
3390
+ } = useContentElementCommentSelection();
3391
+ const newThreadActive = selected === 'newThread';
3392
+ useEffect(() => {
3393
+ var _getUniformSelectedNo, _getUniformSelectedNo2, _getUniformSelectedNo3, _getUniformSelectedNo4;
3394
+ const {
3395
+ selection
3396
+ } = editor;
3397
+ if (!ref.current) {
3398
+ return;
3399
+ }
3400
+ if (type === 'contentElement' && range && lastRangeRef.current !== range) {
3401
+ lastRangeRef.current = range;
3402
+ if (range[1] === range[0] + 1) {
3403
+ Transforms.select(editor, Editor.point(editor, [range[0]], {
3404
+ edge: 'start'
3405
+ }));
3406
+ } else {
3407
+ Transforms.select(editor, {
3408
+ anchor: Editor.point(editor, [range[0]], {
3409
+ edge: 'start'
3410
+ }),
3411
+ focus: Editor.point(editor, [range[1] - 1], {
3412
+ edge: 'end'
3413
+ })
3414
+ });
3415
+ }
3416
+ ReactEditor.focus(editor);
3417
+ }
3418
+ if (!selection) {
3419
+ if (boundsRef.current) {
3420
+ hideRect(ref.current);
3421
+ boundsRef.current = null;
3422
+ }
3423
+ return;
3424
+ }
3425
+ if (!isContentElementSelected && boundsRef.current) {
3426
+ hideRect(ref.current);
3427
+ boundsRef.current = null;
3428
+ Transforms.deselect(editor);
3429
+ return;
3430
+ }
3431
+ if (!isContentElementSelected && !boundsRef.current) {
3432
+ // Only treat the selection as user-initiated when the editor is
3433
+ // actually focused. After an external value replacement, the
3434
+ // browser may clamp its DOM cursor to the start of the
3435
+ // shrunken contenteditable; slate-react's throttled
3436
+ // `selectionchange` listener then re-syncs that cursor into
3437
+ // `editor.selection`. Without this guard, that synthetic
3438
+ // selection would re-select the content element here.
3439
+ if (!ReactEditor.isFocused(editor)) {
3440
+ return;
3441
+ }
3442
+ select();
3443
+ }
3444
+ const [start, end] = computeBounds(editor);
3445
+ if (type === 'contentElementComments' && cursorLeftHighlightedThreadBlock({
3446
+ editor,
3447
+ highlightedThreadId,
3448
+ highlights: props.highlights
3449
+ })) {
3450
+ select();
3451
+ return;
3452
+ }
3453
+ if (newThreadActive && newThreadRange && cursorMovedFromPendingNewThreadRange({
3454
+ editor,
3455
+ newThreadRange
3456
+ })) {
3457
+ select();
3458
+ return;
3459
+ }
3460
+ setTransientState({
3461
+ editableTextIsSingleBlock: editor.children.length <= 1,
3462
+ exampleNode: getUniformSelectedNode(editor, 'type'),
3463
+ typographyVariant: (_getUniformSelectedNo = getUniformSelectedNode(editor, 'variant')) === null || _getUniformSelectedNo === void 0 ? void 0 : _getUniformSelectedNo.variant,
3464
+ typographySize: (_getUniformSelectedNo2 = getUniformSelectedNode(editor, 'size')) === null || _getUniformSelectedNo2 === void 0 ? void 0 : _getUniformSelectedNo2.size,
3465
+ color: (_getUniformSelectedNo3 = getUniformSelectedNode(editor, 'color')) === null || _getUniformSelectedNo3 === void 0 ? void 0 : _getUniformSelectedNo3.color,
3466
+ textAlign: (_getUniformSelectedNo4 = getUniformSelectedNode(editor, 'textAlign')) === null || _getUniformSelectedNo4 === void 0 ? void 0 : _getUniformSelectedNo4.textAlign,
3467
+ commentThreadIdsAtSelection: commentThreadIdsAtSelection(props.highlights || [], editor.selection),
3468
+ newCommentThreadSubjectRange: newCommentThreadSubjectRange(editor)
3469
+ });
3470
+ boundsRef.current = {
3471
+ start,
3472
+ end
3473
+ };
3474
+ updateRect(editor, start, end, outerRef.current, ref.current, innerRef.current);
3475
+ });
3476
+ useEffect(() => {
3477
+ if (!isContentElementSelected) return;
3478
+ function handleResize() {
3479
+ if (boundsRef.current) {
3480
+ updateRect(editor, boundsRef.current.start, boundsRef.current.end, outerRef.current, ref.current, innerRef.current);
3481
+ }
3482
+ }
3483
+ window.addEventListener('resize', handleResize);
3484
+ return () => window.removeEventListener('resize', handleResize);
3485
+ }, [isContentElementSelected, editor]);
3486
+ const [, drag] = useDrag({
3487
+ item: {
3488
+ type: 'contentElement',
3489
+ id: props.contentElementId
3490
+ },
3491
+ begin: () => ({
3492
+ type: 'contentElement',
3493
+ id: props.contentElementId,
3494
+ range: [boundsRef.current.start, boundsRef.current.end + 1]
3495
+ })
3496
+ });
3497
+ return /*#__PURE__*/React.createElement("div", {
3498
+ ref: outerRef
3499
+ }, /*#__PURE__*/React.createElement("div", {
3500
+ ref: ref,
3501
+ className: styles$e.selection
3502
+ }, /*#__PURE__*/React.createElement(SelectionRect, {
3503
+ selected: true,
3504
+ drag: drag,
3505
+ scrollPoint: isContentElementSelected,
3506
+ insertButtonTitles: t('pageflow_scrolled.inline_editing.insert_content_element'),
3507
+ onInsertButtonClick: at => {
3508
+ if (at === 'before' && boundsRef.current.start === 0 || at === 'after' && !Node$1.has(editor, [boundsRef.current.end + 1])) {
3509
+ postInsertContentElementMessage({
3510
+ id: props.contentElementId,
3511
+ at
3512
+ });
3513
+ } else {
3514
+ postInsertContentElementMessage({
3515
+ id: props.contentElementId,
3516
+ at: 'split',
3517
+ splitPoint: at === 'before' ? boundsRef.current.start : boundsRef.current.end + 1
3518
+ });
3519
+ }
3520
+ },
3521
+ toolbarButtons: toolbarButtons(t).map(button => ({
3522
+ ...button,
3523
+ active: isBlockActive(editor, button.name)
3524
+ })),
3525
+ onToolbarButtonClick: name => toggleBlock(editor, name)
3526
+ }, /*#__PURE__*/React.createElement("div", {
3527
+ ref: innerRef
3528
+ }))));
3529
+ }
3530
+ function hideRect(el) {
3531
+ el.removeAttribute('style');
3532
+ }
3533
+ function updateRect(editor, startIndex, endIndex, outer, el, inner) {
3534
+ const [startDOMNode, endDOMNode] = getDOMNodes(editor, startIndex, endIndex);
3535
+ if (startDOMNode && endDOMNode) {
3536
+ const startRect = startDOMNode.getBoundingClientRect();
3537
+ const endRect = endDOMNode.getBoundingClientRect();
3538
+ const outerRect = outer.getBoundingClientRect();
3539
+ el.style.display = 'block';
3540
+ el.style.top = `${startRect.top - outerRect.top}px`;
3541
+ inner.style.height = `${endRect.bottom - startRect.top}px`;
3542
+ }
3543
+ }
3544
+ function getDOMNodes(editor, startIndex, endIndex) {
3545
+ const startNode = Node$1.get(editor, [startIndex]);
3546
+ const endNode = Node$1.get(editor, [endIndex]);
3547
+ try {
3548
+ const startDOMNode = ReactEditor.toDOMNode(editor, startNode);
3549
+ const endDOMNode = ReactEditor.toDOMNode(editor, endNode);
3550
+ return [startDOMNode, endDOMNode];
3551
+ } catch (e) {
3552
+ return [];
3553
+ }
3554
+ }
3555
+ function toolbarButtons(t) {
3556
+ return [{
3557
+ name: 'paragraph',
3558
+ text: t('pageflow_scrolled.inline_editing.formats.paragraph'),
3559
+ icon: TextIcon
3560
+ }, {
3561
+ name: 'heading',
3562
+ text: t('pageflow_scrolled.inline_editing.formats.heading'),
3563
+ icon: HeadingIcon
3564
+ }, {
3565
+ name: 'numbered-list',
3566
+ text: t('pageflow_scrolled.inline_editing.formats.ordered_list'),
3567
+ icon: OlIcon
3568
+ }, {
3569
+ name: 'bulleted-list',
3570
+ text: t('pageflow_scrolled.inline_editing.formats.bulleted_list'),
3571
+ icon: UlIcon
3572
+ }, {
3573
+ name: 'block-quote',
3574
+ text: t('pageflow_scrolled.inline_editing.formats.block_quote'),
3575
+ icon: QuoteIcon
3576
+ }];
3577
+ }
3578
+
3579
+ var styles$f = {"container":"DropTargets-module_container__3vudG","dropTarget":"DropTargets-module_dropTarget__3mmox","dropIndicator":"DropTargets-module_dropIndicator__2zu4d","isOver":"DropTargets-module_isOver__2usWn"};
3580
+
3581
+ function DropTargets$1({
3582
+ contentElementId
3583
+ }) {
3584
+ const editor = useSlate();
3585
+ const [targets, setTargets] = useState();
3586
+ const containerRef = useRef();
3587
+ useEffect(() => {
3588
+ if (!targets) {
3589
+ setTargets(measureHeights(editor, containerRef.current));
3590
+ }
3591
+ }, [targets, editor]);
3592
+ return /*#__PURE__*/React.createElement("div", {
3593
+ ref: containerRef,
3594
+ className: styles$f.container
3595
+ }, renderDropTargets(targets || [], contentElementId));
3596
+ }
3597
+ function renderDropTargets(targets, contentElementId) {
3598
+ function handleDrop(item, index) {
3599
+ if (index === 0) {
3600
+ postMoveContentElementMessage({
3601
+ id: item.id,
3602
+ range: item.range,
3603
+ to: {
3604
+ at: 'before',
3605
+ id: contentElementId
3606
+ }
3607
+ });
3608
+ } else if (index === targets.length - 1) {
3609
+ postMoveContentElementMessage({
3610
+ id: item.id,
3611
+ range: item.range,
3612
+ to: {
3613
+ at: 'after',
3614
+ id: contentElementId
3615
+ }
3616
+ });
3617
+ } else {
3618
+ postMoveContentElementMessage({
3619
+ id: item.id,
3620
+ range: item.range,
3621
+ to: {
3622
+ at: 'split',
3623
+ id: contentElementId,
3624
+ splitPoint: index
3625
+ }
3626
+ });
3627
+ }
3628
+ }
3629
+ return targets.map((target, index) => /*#__PURE__*/React.createElement(DropTarget, Object.assign({}, target, {
3630
+ key: index,
3631
+ onDrop: item => handleDrop(item, index)
3632
+ })));
3633
+ }
3634
+ function DropTarget({
3635
+ display,
3636
+ top,
3637
+ height,
3638
+ indicatorTop,
3639
+ onDrop
3640
+ }) {
3641
+ const [{
3642
+ isOver
3643
+ }, drop] = useDrop({
3644
+ accept: 'contentElement',
3645
+ collect: monitor => ({
3646
+ isOver: monitor.isOver()
3647
+ }),
3648
+ drop: item => onDrop(item)
3649
+ });
3650
+ return /*#__PURE__*/React.createElement("div", {
3651
+ ref: drop,
3652
+ className: classNames(styles$f.dropTarget, {
3653
+ [styles$f.isOver]: isOver
3654
+ }),
3655
+ style: {
3656
+ display,
3657
+ top,
3658
+ height
3659
+ }
3660
+ }, /*#__PURE__*/React.createElement("div", {
3661
+ className: styles$f.dropIndicator,
3662
+ style: {
3663
+ top: indicatorTop
3664
+ }
3665
+ }));
3666
+ }
3667
+ function measureHeights(editor, container) {
3668
+ const containerRect = container.getBoundingClientRect();
3669
+ let lastTargetDimensions = {
3670
+ top: 0,
3671
+ height: 0
3672
+ };
3673
+ let lastRectBottom = 0;
3674
+ const targetDimensions = editor.children.map((child, index) => {
3675
+ const node = Node$1.get(editor, [index]);
3676
+ const domNode = ReactEditor.toDOMNode(editor, node);
3677
+ const rect = domNode.getBoundingClientRect();
3678
+ const top = lastTargetDimensions.top + lastTargetDimensions.height;
3679
+ const bottom = rect.top + rect.height / 2 - containerRect.top;
3680
+ const targetDimensions = {
3681
+ top,
3682
+ height: bottom - top,
3683
+ display: editor.selection && Range.includes(editor.selection, [index]) ? 'none' : undefined,
3684
+ indicatorTop: index > 0 ? lastRectBottom + (rect.top - lastRectBottom) / 2 - containerRect.top - top : 0
3685
+ };
3686
+ lastRectBottom = rect.bottom;
3687
+ lastTargetDimensions = targetDimensions;
3688
+ return targetDimensions;
3689
+ });
3690
+ return [...targetDimensions, {
3691
+ top: lastTargetDimensions.top + lastTargetDimensions.height,
3692
+ height: containerRect.height - (lastTargetDimensions.top + lastTargetDimensions.height),
3693
+ indicatorTop: containerRect.height - (lastTargetDimensions.top + lastTargetDimensions.height)
3694
+ }];
3695
+ }
3696
+
3697
+ const shy = '\u00AD';
3698
+ function decorateCharacter([node, path], character, attributes, {
3699
+ length
3700
+ }) {
3701
+ if (Text.isText(node)) {
3702
+ const parts = node.text.split(character);
3703
+ parts.pop();
3704
+ let i = 0;
3705
+ return parts.map(part => {
3706
+ i += part.length + 1;
3707
+ return {
3708
+ anchor: {
3709
+ path,
3710
+ offset: i - 1
3711
+ },
3712
+ focus: {
3713
+ path,
3714
+ offset: i - 1 + length
3715
+ },
3716
+ ...attributes
3717
+ };
3718
+ });
3719
+ }
3720
+ return [];
3721
+ }
3722
+ function deleteCharacter(editor, node, path, regExp, offset = 0) {
3723
+ const match = regExp.exec(node.text);
3724
+ if (match) {
3725
+ Transforms.delete(editor, {
3726
+ at: {
3727
+ path,
3728
+ offset: match.index + offset
3729
+ },
3730
+ distance: 1,
3731
+ unit: 'character'
3732
+ });
3733
+ return true;
3734
+ }
3735
+ return false;
3736
+ }
3737
+
3738
+ function useLineBreakHandler(editor) {
3739
+ return useCallback(event => {
3740
+ if (event.key !== 'Enter') {
3741
+ return;
3742
+ }
3743
+ if (event.altKey === true) {
3744
+ editor.insertText(shy);
3745
+ event.preventDefault();
3746
+ } else if (event.shiftKey === true) {
3747
+ editor.insertText('\n');
3748
+ event.preventDefault();
3749
+ }
3750
+ }, [editor]);
3751
+ }
3752
+ function decorateLineBreaks(nodeEntry) {
3753
+ return decorateCharacter(nodeEntry, shy, {
3754
+ shy: true
3755
+ }, {
3756
+ length: 1
3757
+ });
3758
+ }
3759
+ function renderLeafWithLineBreakDecoration({
3760
+ leaf,
3761
+ children,
3762
+ attributes
3763
+ }) {
3764
+ if (leaf.shy) {
3765
+ children = /*#__PURE__*/React.createElement("span", {
3766
+ className: styles$e.shy
3767
+ }, children);
3768
+ }
3769
+ return renderLeaf$1({
3770
+ leaf,
3771
+ children,
3772
+ attributes
3773
+ });
3774
+ }
3775
+ function withLineBreakNormalization(editor) {
3776
+ const {
3777
+ normalizeNode
3778
+ } = editor;
3779
+ editor.normalizeNode = ([node, path]) => {
3780
+ if (node.text) {
3781
+ if (deleteCharacter(editor, node, path, new RegExp(`${shy}\\s`)) || deleteCharacter(editor, node, path, new RegExp(`^${shy}`)) || deleteCharacter(editor, node, path, new RegExp(`\\s${shy}`), 1) || deleteCharacter(editor, node, path, new RegExp(`${shy}${shy}`))) {
3782
+ return;
3783
+ }
3784
+ }
3785
+ return normalizeNode([node, path]);
3786
+ };
3787
+ return editor;
3788
+ }
3789
+
3790
+ function useShortcutHandler(editor) {
3791
+ return useCallback(event => {
3792
+ if (!event.ctrlKey) {
3793
+ return;
3794
+ }
3795
+ if (event.key === 'z') {
3796
+ event.preventDefault();
3797
+ editor.undo();
3798
+ } else if (event.key === 'y') {
3799
+ event.preventDefault();
3800
+ editor.redo();
3801
+ } else if (event.key === 'b') {
3802
+ event.preventDefault();
3803
+ toggleMark(editor, 'bold');
3804
+ } else if (event.key === 'i') {
3805
+ event.preventDefault();
3806
+ toggleMark(editor, 'italic');
3807
+ } else if (event.key === 'u') {
3808
+ event.preventDefault();
3809
+ toggleMark(editor, 'underline');
3810
+ } else if (event.key === 'S') {
3811
+ event.preventDefault();
3812
+ toggleMark(editor, 'strikethrough');
3813
+ } else if (event.key === ',') {
3814
+ event.preventDefault();
3815
+ toggleMark(editor, 'sup');
3816
+ } else if (event.key === ';') {
3817
+ event.preventDefault();
3818
+ toggleMark(editor, 'sub');
3819
+ }
3820
+ }, [editor]);
3821
+ }
3822
+
3823
+ function duplicateNodes(editor) {
3824
+ if (!editor.selection) {
3825
+ return;
3826
+ }
3827
+ const selectedEntries = Array.from(Editor.nodes(editor, {
3828
+ at: editor.selection,
3829
+ mode: 'highest',
3830
+ match: n => Element$1.isElement(n)
3831
+ }));
3832
+ if (selectedEntries.length === 0) {
3833
+ return;
3834
+ }
3835
+ const clonedNodes = selectedEntries.map(([node]) => JSON.parse(JSON.stringify(node)));
3836
+ const lastPath = selectedEntries[selectedEntries.length - 1][1];
3837
+ const insertAt = lastPath[0] + 1;
3838
+ Transforms.insertNodes(editor, clonedNodes, {
3839
+ at: [insertAt]
3840
+ });
3841
+ Transforms.select(editor, {
3842
+ anchor: Editor.start(editor, [insertAt]),
3843
+ focus: Editor.end(editor, [insertAt + clonedNodes.length - 1])
3844
+ });
3845
+ }
3846
+
3847
+ const selectedClassName = styles$e.selected;
3848
+ const EditableText = React.memo(function EditableText({
3849
+ value,
3850
+ contentElementId,
3851
+ placeholder,
3852
+ onChange,
3853
+ selectionRect,
3854
+ className,
3855
+ placeholderClassName,
3856
+ scaleCategory = 'body',
3857
+ typographyVariant,
3858
+ typographySize,
3859
+ autoFocus,
3860
+ floatingControlsPosition = 'above'
3861
+ }) {
3862
+ const editor = useMemo(() => withLinks(withCustomInsertBreak(withBlockNormalization({
3863
+ onlyParagraphs: !selectionRect
3864
+ }, withLineBreakNormalization(withReact(withHistory(createEditor())))))), [selectionRect]);
3865
+ const handleLineBreaks = useLineBreakHandler(editor);
3866
+ const handleShortcuts = useShortcutHandler(editor);
3867
+ const handleKeyDown = useCallback(event => {
3868
+ handleLineBreaks(event);
3869
+ handleShortcuts(event);
3870
+ }, [handleLineBreaks, handleShortcuts]);
3871
+ useEffect(() => {
3872
+ if (autoFocus) {
3873
+ ReactEditor.focus(editor);
3874
+ }
3875
+ }, [autoFocus, editor]);
3876
+ const {
3877
+ enabled: commentingEnabled,
3878
+ anchors,
3879
+ highlights,
3880
+ visibleHighlights,
3881
+ highlightedRange,
3882
+ decorate: decorateComments,
3883
+ withCommentHighlightDecoration,
3884
+ resetRangeRefs,
3885
+ getTrackedSubjectRanges
3886
+ } = useCommenting(editor);
3887
+ const [cachedValue, setCachedValue] = useCachedValue(value, {
3888
+ defaultValue: [{
3889
+ type: 'paragraph',
3890
+ children: [{
3891
+ text: ''
3892
+ }]
3893
+ }],
3894
+ onDebouncedChange: nextValue => {
3895
+ if (onChange) {
3896
+ onChange(nextValue, {
3897
+ commentThreadSubjectRanges: getTrackedSubjectRanges()
3898
+ });
3899
+ }
3900
+ },
3901
+ onReset: nextValue => {
3902
+ resetSelectionIfOutsideNextValue(editor, nextValue);
3903
+ resetHistory(editor);
3904
+ resetRangeRefs();
3905
+ }
3906
+ });
3907
+ const {
3908
+ isSelected
3909
+ } = useContentElementEditorState();
3910
+ useContentElementEditorCommandSubscription(command => {
3911
+ if (command.type === 'REMOVE') {
3912
+ Transforms.removeNodes(editor, {
3913
+ mode: 'highest'
3914
+ });
3915
+ } else if (command.type === 'DUPLICATE') {
3916
+ duplicateNodes(editor);
3917
+ ReactEditor.focus(editor);
3918
+ } else if (command.type === 'MOVE_TO') {
3919
+ const {
3920
+ to
3921
+ } = command.payload;
3922
+ const [start, end] = computeBounds(editor);
3923
+ postMoveContentElementMessage({
3924
+ id: contentElementId,
3925
+ range: [start, end + 1],
3926
+ to
3927
+ });
3928
+ } else if (command.type === 'TRANSIENT_STATE_UPDATE') {
3929
+ if ('typographyVariant' in command.payload) {
3930
+ applyTypographyVariant(editor, command.payload.typographyVariant);
3931
+ }
3932
+ if ('typographySize' in command.payload) {
3933
+ applyTypographySize(editor, command.payload.typographySize);
3934
+ }
3935
+ if ('color' in command.payload) {
3936
+ applyColor(editor, command.payload.color);
3937
+ }
3938
+ if ('textAlign' in command.payload) {
3939
+ applyTextAlign(editor, command.payload.textAlign);
3940
+ }
3941
+ }
3942
+ });
3943
+ const [dropTargetsActive, dropTargetsRef] = useDropTargetsActive();
3944
+ const decorate = useMemo(() => {
3945
+ if (!commentingEnabled) {
3946
+ return decorateLineBreaks;
3947
+ }
3948
+ return entry => [...decorateLineBreaks(entry), ...decorateComments(entry)];
3949
+ }, [decorateComments, commentingEnabled]);
3950
+ const renderLeaf = useCallback(props => renderLeafWithLineBreakDecoration(withCommentHighlightDecoration(props)), [withCommentHighlightDecoration]);
3951
+ return /*#__PURE__*/React.createElement(Text$1, {
3952
+ scaleCategory: scaleCategory,
3953
+ typographyVariant: typographyVariant,
3954
+ typographySize: typographySize
3955
+ }, /*#__PURE__*/React.createElement("div", {
3956
+ className: classNames(styles$e.container, {
3957
+ [styles$e.selected]: isSelected
3958
+ }),
3959
+ ref: el => {
3960
+ dropTargetsRef(el);
3961
+ anchors.containerRef.current = el;
3962
+ }
3963
+ }, /*#__PURE__*/React.createElement(Slate, {
3964
+ editor: editor,
3965
+ value: cachedValue,
3966
+ onChange: setCachedValue
3967
+ }, /*#__PURE__*/React.createElement(LinkTooltipProvider, {
3968
+ disabled: editor.selection && !Range.isCollapsed(editor.selection),
3969
+ position: floatingControlsPosition
3970
+ }, selectionRect && /*#__PURE__*/React.createElement(Selection, {
3971
+ contentElementId: contentElementId,
3972
+ highlights: highlights
3973
+ }), dropTargetsActive && /*#__PURE__*/React.createElement(DropTargets$1, {
3974
+ contentElementId: contentElementId
3975
+ }), /*#__PURE__*/React.createElement(HoveringToolbar, null, /*#__PURE__*/React.createElement(Editable, {
3976
+ className: className,
3977
+ decorate: decorate,
3978
+ onKeyDown: handleKeyDown,
3979
+ renderElement: renderElementWithLinkPreview,
3980
+ renderLeaf: renderLeaf
3981
+ }))), commentingEnabled && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(BadgeColumn, {
3982
+ highlights: visibleHighlights,
3983
+ highlightedRange: highlightedRange,
3984
+ anchors: anchors
3985
+ }), /*#__PURE__*/React.createElement(PendingSelectionBadge, {
3986
+ containerRef: anchors.containerRef
3987
+ }))), /*#__PURE__*/React.createElement(TextPlaceholder, {
3988
+ text: placeholder,
3989
+ className: placeholderClassName,
3990
+ visible: isBlank(cachedValue)
3991
+ })));
3992
+ });
3993
+ function isBlank(value) {
3994
+ var _value$, _value$2, _value$2$children$;
3995
+ return value.length <= 1 && ((_value$ = value[0]) === null || _value$ === void 0 ? void 0 : _value$.children.length) <= 1 && value[0].type === 'paragraph' && !((_value$2 = value[0]) === null || _value$2 === void 0 ? void 0 : (_value$2$children$ = _value$2.children[0]) === null || _value$2$children$ === void 0 ? void 0 : _value$2$children$.text);
3996
+ }
3997
+ function resetSelectionIfOutsideNextValue(editor, nextValue) {
3998
+ const nextEditor = {
3999
+ children: nextValue
4000
+ };
4001
+ if (editor.selection && (!hasTextAtPoint(nextEditor, editor.selection.anchor) || !hasTextAtPoint(nextEditor, editor.selection.focus))) {
4002
+ Transforms.deselect(editor);
4003
+ // Also drop the browser's DOM cursor when it sits inside this
4004
+ // editor's contenteditable. Otherwise slate-react's throttled
4005
+ // `selectionchange` listener would later re-sync that stale
4006
+ // cursor — clamped to the start of the now-shrunken content —
4007
+ // back into `editor.selection`, and `Selection`'s auto-select
4008
+ // would treat it as a user click and re-select this content
4009
+ // element (overriding whatever the calling op selected, e.g. a
4010
+ // freshly inserted image).
4011
+ const domSelection = window.getSelection();
4012
+ const editorEl = ReactEditor.toDOMNode(editor, editor);
4013
+ if (domSelection && editorEl.contains(domSelection.anchorNode)) {
4014
+ domSelection.removeAllRanges();
4015
+ }
4016
+ }
4017
+ }
4018
+ function hasTextAtPoint(editor, point) {
4019
+ if (!Node$1.has(editor, point.path)) {
4020
+ return false;
4021
+ }
4022
+ const node = Node$1.get(editor, point.path);
4023
+ return Text.isText(node) && point.offset <= node.text.length;
4024
+ }
4025
+ function resetHistory(editor) {
4026
+ editor.history.undos = [];
4027
+ editor.history.redos = [];
4028
+ }
4029
+
4030
+ function useLineBreakHandler$1(editor) {
4031
+ return useCallback(event => {
4032
+ if (event.key !== 'Enter') {
4033
+ return true;
4034
+ }
4035
+
4036
+ // Soft hyphens used to be inserted with Shift + Enter.
4037
+ // Since Shift + Enter is now used for soft breaks in text blocks,
4038
+ // we switched to Alt + Enter. Since all line breaks in
4039
+ // EdtiableInlineText are soft, we also keep the old short cut
4040
+ if (event.shiftKey === true || event.altKey === true) {
4041
+ editor.insertText(shy);
4042
+ } else {
4043
+ editor.insertText('\n');
4044
+ }
4045
+ return false;
4046
+ }, [editor]);
4047
+ }
4048
+ function decorateLineBreaks$1(nodeEntry) {
4049
+ return [...decorateCharacter(nodeEntry, shy, {
4050
+ shy: true
4051
+ }, {
4052
+ length: 1
4053
+ }), ...decorateCharacter(nodeEntry, "\n", {
4054
+ newLine: true
4055
+ }, {
4056
+ length: 0
4057
+ })];
4058
+ }
4059
+ function withLineBreakNormalization$1(editor) {
4060
+ const {
4061
+ normalizeNode
4062
+ } = editor;
4063
+ editor.normalizeNode = ([node, path]) => {
4064
+ if (path.length === 0 && editor.children.length > 1) {
4065
+ Transforms.mergeNodes(editor);
4066
+ return;
4067
+ } else if (node.text) {
4068
+ if (deleteCharacter(editor, node, path, /\n\n/) || deleteCharacter(editor, node, path, new RegExp(`^\n`)) || deleteCharacter(editor, node, path, new RegExp(`${shy}\\s`)) || deleteCharacter(editor, node, path, new RegExp(`^${shy}`)) || deleteCharacter(editor, node, path, new RegExp(`\\s${shy}`), 1) || deleteCharacter(editor, node, path, new RegExp(`${shy}${shy}`))) {
4069
+ return;
4070
+ }
4071
+ }
4072
+ return normalizeNode([node, path]);
4073
+ };
4074
+ return editor;
4075
+ }
4076
+
4077
+ function useShortcutHandler$1(editor) {
4078
+ return useCallback(event => {
4079
+ if (!event.ctrlKey) {
4080
+ return;
4081
+ }
4082
+ if (event.key === 'z') {
4083
+ event.preventDefault();
4084
+ editor.undo();
4085
+ } else if (event.key === 'y') {
4086
+ event.preventDefault();
4087
+ editor.redo();
4088
+ }
4089
+ }, [editor]);
4090
+ }
4091
+
4092
+ var styles$g = {"shy":"index-module_shy__1E2-J","newLine":"index-module_newLine__1QnIs","selected":"index-module_selected__1U9ro","manualHyphens":"index-module_manualHyphens__16b2t"};
4093
+
4094
+ const EditableInlineText = memo(function EditableInlineText({
4095
+ value,
4096
+ defaultValue = '',
4097
+ hyphens,
4098
+ placeholder,
4099
+ onChange
4100
+ }) {
4101
+ var _cachedValue$, _cachedValue$$childre;
4102
+ const editor = useMemo(() => withLineBreakNormalization$1(withReact(withHistory(createEditor()))), []);
4103
+ const handleLineBreaks = useLineBreakHandler$1(editor);
4104
+ const handleShortcuts = useShortcutHandler$1(editor);
4105
+ const handleKeyDown = useCallback(event => {
4106
+ handleLineBreaks(event);
4107
+ handleShortcuts(event);
4108
+ }, [handleLineBreaks, handleShortcuts]);
4109
+ const [cachedValue, setCachedValue] = useCachedValue(value, {
4110
+ defaultValue: [{
4111
+ type: 'heading',
4112
+ children: [{
4113
+ text: defaultValue
4114
+ }]
4115
+ }],
4116
+ onDebouncedChange: onChange
4117
+ });
4118
+ const {
4119
+ isSelected
4120
+ } = useContentElementEditorState();
4121
+ return /*#__PURE__*/React.createElement("div", {
4122
+ className: classNames(frontendStyles.root, frontendStyles[`hyphens-${hyphens}`], {
4123
+ [styles$g.manualHyphens]: hyphens === 'manual'
4124
+ }, {
4125
+ [styles$g.selected]: isSelected
4126
+ }),
4127
+ spellCheck: "false"
4128
+ }, /*#__PURE__*/React.createElement(Slate, {
4129
+ editor: editor,
4130
+ value: cachedValue,
4131
+ onChange: setCachedValue
4132
+ }, /*#__PURE__*/React.createElement(Editable, {
4133
+ decorate: decorateLineBreaks$1,
4134
+ onKeyDown: handleKeyDown,
4135
+ renderElement: props => /*#__PURE__*/React.createElement(Element, props),
4136
+ renderLeaf: renderLeaf
4137
+ })), /*#__PURE__*/React.createElement(TextPlaceholder, {
4138
+ text: placeholder,
4139
+ visible: !((_cachedValue$ = cachedValue[0]) === null || _cachedValue$ === void 0 ? void 0 : (_cachedValue$$childre = _cachedValue$.children[0]) === null || _cachedValue$$childre === void 0 ? void 0 : _cachedValue$$childre.text)
4140
+ }));
4141
+ });
4142
+ function Element({
4143
+ attributes,
4144
+ children,
4145
+ element
4146
+ }) {
4147
+ return /*#__PURE__*/React.createElement("div", Object.assign({}, attributes, {
4148
+ style: {
4149
+ position: 'relative'
4150
+ }
4151
+ }), /*#__PURE__*/React.createElement("span", {
4152
+ className: frontendStyles.textEffects
4153
+ }, children));
4154
+ }
4155
+ function renderLeaf({
4156
+ attributes,
4157
+ children,
4158
+ leaf
4159
+ }) {
4160
+ if (leaf.shy) {
4161
+ children = /*#__PURE__*/React.createElement("span", {
4162
+ className: styles$g.shy
4163
+ }, children);
4164
+ }
4165
+ if (leaf.newLine) {
4166
+ children = /*#__PURE__*/React.createElement("span", {
4167
+ className: styles$g.newLine
4168
+ }, children);
4169
+ }
4170
+ return /*#__PURE__*/React.createElement("span", attributes, children);
4171
+ }
4172
+
4173
+ const Row = {
4174
+ match(editor) {
4175
+ const [rowMatch] = Editor.nodes(editor, {
4176
+ match: n => n.type === 'row'
4177
+ });
4178
+ return rowMatch;
4179
+ }
4180
+ };
4181
+ const Cell = {
4182
+ splitChildren(editor, {
4183
+ cellNode,
4184
+ point
4185
+ }) {
4186
+ const [leafNode, leafPath] = Editor.leaf(editor, point.path);
4187
+ const cursorOffset = point.offset;
4188
+ const text = leafNode.text || '';
4189
+ const beforeText = text.slice(0, cursorOffset);
4190
+ const afterText = text.slice(cursorOffset);
4191
+ const splitIndex = leafPath[leafPath.length - 1];
4192
+ const beforeNodes = [];
4193
+ const afterNodes = [];
4194
+ cellNode.children.forEach((node, index) => {
4195
+ if (index < splitIndex) {
4196
+ beforeNodes.push(node);
4197
+ } else if (index === splitIndex) {
4198
+ if (beforeText) {
4199
+ beforeNodes.push({
4200
+ ...node,
4201
+ text: beforeText
4202
+ });
4203
+ }
4204
+ if (afterText) {
4205
+ afterNodes.push({
4206
+ ...node,
4207
+ text: afterText
4208
+ });
4209
+ }
4210
+ } else {
4211
+ afterNodes.push(node);
4212
+ }
4213
+ });
4214
+ return [beforeNodes, afterNodes];
4215
+ },
4216
+ match(editor, {
4217
+ at
4218
+ } = {}) {
4219
+ const [cellMatch] = Editor.nodes(editor, {
4220
+ match: n => n.type === 'label' || n.type === 'value',
4221
+ at
4222
+ });
4223
+ return cellMatch;
4224
+ },
4225
+ inFirstLine(editor, point) {
4226
+ const [node] = Editor.node(editor, point.path);
4227
+ const text = Node$1.string(node);
4228
+ const firstLineBreak = text.indexOf('\n');
4229
+ return firstLineBreak === -1 || point.offset <= firstLineBreak;
4230
+ },
4231
+ inLastLine(editor, point) {
4232
+ const [node] = Editor.node(editor, point.path);
4233
+ const text = Node$1.string(node);
4234
+ const lastLineBreak = text.lastIndexOf('\n');
4235
+ return lastLineBreak === -1 || point.offset > lastLineBreak;
4236
+ },
4237
+ getPointAtStartOfLastLine(editor, cellPath) {
4238
+ const [node] = Editor.node(editor, cellPath);
4239
+ const text = Node$1.string(node);
4240
+ const lastLineBreak = text.lastIndexOf('\n');
4241
+ const offset = lastLineBreak === -1 ? 0 : lastLineBreak + 1;
4242
+ return {
4243
+ path: cellPath,
4244
+ offset
4245
+ };
4246
+ }
4247
+ };
4248
+ const CellPath = {
4249
+ columnIndex(path) {
4250
+ return path[path.length - 1];
4251
+ },
4252
+ rowIndex(path) {
4253
+ return path[path.length - 2];
4254
+ }
4255
+ };
4256
+
4257
+ const CellTransforms = {
4258
+ replaceContent(editor, nodes, {
4259
+ cellPath
4260
+ }) {
4261
+ Transforms.insertText(editor, '', {
4262
+ at: cellPath
4263
+ });
4264
+ if (nodes.length > 0) {
4265
+ Transforms.insertNodes(editor, nodes, {
4266
+ at: [...cellPath, 0]
4267
+ });
4268
+ }
4269
+ },
4270
+ deleteContentUntil(editor, {
4271
+ cellPath,
4272
+ point
4273
+ }) {
4274
+ if (!Editor.isStart(editor, point, cellPath)) {
4275
+ Transforms.delete(editor, {
4276
+ at: {
4277
+ anchor: Editor.start(editor, cellPath),
4278
+ focus: point
4279
+ }
4280
+ });
4281
+ }
4282
+ },
4283
+ deleteContentFrom(editor, {
4284
+ cellPath,
4285
+ point
4286
+ }) {
4287
+ if (!Editor.isEnd(editor, point, cellPath)) {
4288
+ Transforms.delete(editor, {
4289
+ at: {
4290
+ anchor: point,
4291
+ focus: Editor.end(editor, cellPath)
4292
+ }
4293
+ });
4294
+ }
4295
+ }
4296
+ };
4297
+
4298
+ const TableTransforms = {
4299
+ deleteRange(editor, [startPoint, endPoint]) {
4300
+ const startCellMatch = Cell.match(editor, {
4301
+ at: startPoint.path
4302
+ });
4303
+ const endCellMatch = Cell.match(editor, {
4304
+ at: endPoint.path
4305
+ });
4306
+ if (startCellMatch && endCellMatch) {
4307
+ const [startCellNode, startCellPath] = startCellMatch;
4308
+ const [endCellNode, endCellPath] = endCellMatch;
4309
+ if (!Path.equals(startCellPath, endCellPath)) {
4310
+ const rewrittenCellPath = getRewrittenCellPath(editor, startCellPath, endCellPath);
4311
+ const rows = Array.from(Editor.nodes(editor, {
4312
+ match: n => n.type === 'row',
4313
+ at: {
4314
+ anchor: startPoint,
4315
+ focus: endPoint
4316
+ }
4317
+ }));
4318
+ CellTransforms.deleteContentFrom(editor, {
4319
+ cellPath: startCellPath,
4320
+ point: startPoint
4321
+ });
4322
+ if (rewrittenCellPath) {
4323
+ var _beforeNodes;
4324
+ const beforeNodes = CellPath.columnIndex(startCellPath) === CellPath.columnIndex(endCellPath) ? Cell.splitChildren(editor, {
4325
+ cellNode: startCellNode,
4326
+ point: startPoint
4327
+ })[0] : [];
4328
+ const [, afterNodes] = Cell.splitChildren(editor, {
4329
+ cellNode: endCellNode,
4330
+ point: endPoint
4331
+ });
4332
+ CellTransforms.replaceContent(editor, beforeNodes.concat(afterNodes), {
4333
+ cellPath: rewrittenCellPath
4334
+ });
4335
+ Transforms.select(editor, {
4336
+ path: [...rewrittenCellPath, beforeNodes.length ? beforeNodes.length - 1 : 0],
4337
+ offset: ((_beforeNodes = beforeNodes[beforeNodes.length - 1]) === null || _beforeNodes === void 0 ? void 0 : _beforeNodes.text.length) || 0
4338
+ });
4339
+ rows.reverse().forEach(([_, rowPath]) => {
4340
+ if (rowPath[rowPath.length - 1] !== CellPath.rowIndex(rewrittenCellPath)) {
4341
+ Transforms.removeNodes(editor, {
4342
+ at: rowPath
4343
+ });
4344
+ }
4345
+ });
4346
+ } else {
4347
+ CellTransforms.deleteContentUntil(editor, {
4348
+ cellPath: endCellPath,
4349
+ point: endPoint
4350
+ });
4351
+ rows.slice(1, -1).reverse().forEach(([_, rowPath]) => {
4352
+ Transforms.removeNodes(editor, {
4353
+ at: rowPath
4354
+ });
4355
+ });
4356
+ Transforms.select(editor, startPoint);
4357
+ }
4358
+ return;
4359
+ }
4360
+ }
4361
+ }
4362
+ };
4363
+ function getRewrittenCellPath(editor, startCellPath, endCellPath) {
4364
+ if (CellPath.columnIndex(startCellPath) < CellPath.columnIndex(endCellPath)) {
4365
+ const [, rewrittenCellPath] = Editor.next(editor, {
4366
+ at: startCellPath
4367
+ });
4368
+ return rewrittenCellPath;
4369
+ } else if (CellPath.columnIndex(startCellPath) > CellPath.columnIndex(endCellPath)) {
4370
+ return null;
4371
+ } else if (CellPath.columnIndex(startCellPath) === 0) {
4372
+ return endCellPath;
4373
+ } else {
4374
+ return startCellPath;
4375
+ }
4376
+ }
4377
+
4378
+ function withFixedColumns(editor) {
4379
+ const {
4380
+ deleteBackward,
4381
+ deleteForward,
4382
+ deleteFragment
4383
+ } = editor;
4384
+ editor.insertBreak = () => {
4385
+ const cellMatch = Cell.match(editor);
4386
+ if (!cellMatch) {
4387
+ return;
4388
+ }
4389
+ const [cellNode, cellPath] = cellMatch;
4390
+ const rowPath = Path.parent(cellPath);
4391
+ const columnIndex = CellPath.columnIndex(cellPath);
4392
+ const newRowPath = Path.next(rowPath);
4393
+ const [beforeNodes, afterNodes] = Cell.splitChildren(editor, {
4394
+ cellNode,
4395
+ point: editor.selection.anchor
4396
+ });
4397
+ if (columnIndex === 0) {
4398
+ CellTransforms.replaceContent(editor, afterNodes, {
4399
+ cellPath
4400
+ });
4401
+ const newRow = {
4402
+ type: 'row',
4403
+ children: [{
4404
+ type: 'label',
4405
+ children: beforeNodes
4406
+ }, {
4407
+ type: 'value',
4408
+ children: [{
4409
+ text: ''
4410
+ }]
4411
+ }]
4412
+ };
4413
+ Transforms.insertNodes(editor, newRow, {
4414
+ at: rowPath
4415
+ });
4416
+ } else {
4417
+ CellTransforms.replaceContent(editor, beforeNodes, {
4418
+ cellPath
4419
+ });
4420
+ const newRow = {
4421
+ type: 'row',
4422
+ children: [{
4423
+ type: 'label',
4424
+ children: [{
4425
+ text: ''
4426
+ }]
4427
+ }, {
4428
+ type: 'value',
4429
+ children: afterNodes
4430
+ }]
4431
+ };
4432
+ Transforms.insertNodes(editor, newRow, {
4433
+ at: newRowPath
4434
+ });
4435
+ }
4436
+ Transforms.select(editor, {
4437
+ path: [...newRowPath, afterNodes.length ? columnIndex : 0, 0],
4438
+ offset: 0
4439
+ });
4440
+ };
4441
+ editor.deleteBackward = function () {
4442
+ if (!editor.selection || !Range.isCollapsed(editor.selection)) {
4443
+ return;
4444
+ }
4445
+ const cellMatch = Cell.match(editor);
4446
+ if (!cellMatch) {
4447
+ return;
4448
+ }
4449
+ const [, cellPath] = cellMatch;
4450
+ if (!Editor.isStart(editor, editor.selection.anchor, cellPath)) {
4451
+ deleteBackward.apply(this, arguments);
4452
+ return;
4453
+ }
4454
+ const [row, rowPath] = Editor.parent(editor, cellPath);
4455
+ const previousRowMatch = Editor.previous(editor, {
4456
+ at: rowPath
4457
+ });
4458
+ if (CellPath.columnIndex(cellPath) === 0) {
4459
+ if (previousRowMatch) {
4460
+ const [previousRow, previousRowPath] = previousRowMatch;
4461
+ if (Node$1.string(previousRow) === '') {
4462
+ Transforms.delete(editor, {
4463
+ at: previousRowPath
4464
+ });
4465
+ } else if (Node$1.string(row) === '') {
4466
+ Transforms.delete(editor, {
4467
+ at: rowPath
4468
+ });
4469
+ } else if (Node$1.string(Node$1.child(previousRow, 1)) === '') {
4470
+ TableTransforms.deleteRange(editor, [Editor.end(editor, [...previousRowPath, 0]), editor.selection.anchor]);
4471
+ } else {
4472
+ Transforms.select(editor, Editor.end(editor, previousRowPath));
4473
+ }
4474
+ }
4475
+ } else {
4476
+ if (previousRowMatch) {
4477
+ const [, previousRowPath] = previousRowMatch;
4478
+ if (Node$1.string(Node$1.child(row, 0)) === '') {
4479
+ TableTransforms.deleteRange(editor, [Editor.end(editor, previousRowPath), editor.selection.anchor]);
4480
+ return;
4481
+ }
4482
+ }
4483
+ Transforms.select(editor, Editor.end(editor, Path.previous(cellPath)));
4484
+ }
4485
+ };
4486
+ editor.deleteForward = () => {
4487
+ if (!editor.selection || !Range.isCollapsed(editor.selection)) {
4488
+ return;
4489
+ }
4490
+ const cellMatch = Cell.match(editor);
4491
+ if (!cellMatch) {
4492
+ return;
4493
+ }
4494
+ const [, cellPath] = cellMatch;
4495
+ if (!Editor.isEnd(editor, editor.selection.anchor, cellPath)) {
4496
+ deleteForward();
4497
+ return;
4498
+ }
4499
+ const columnIndex = cellPath[cellPath.length - 1];
4500
+ const [row, rowPath] = Editor.parent(editor, cellPath);
4501
+ const nextRowMatch = Editor.next(editor, {
4502
+ at: rowPath
4503
+ });
4504
+ if (columnIndex === 0) {
4505
+ if (Node$1.string(row) === '') {
4506
+ const previousRowMatch = Editor.previous(editor, {
4507
+ at: rowPath
4508
+ });
4509
+ if (previousRowMatch || nextRowMatch) {
4510
+ Transforms.delete(editor, {
4511
+ at: rowPath
4512
+ });
4513
+ if (Node$1.has(editor, rowPath)) {
4514
+ Transforms.select(editor, Editor.start(editor, rowPath));
4515
+ } else {
4516
+ const [, previousRowPath] = previousRowMatch;
4517
+ Transforms.select(editor, Editor.start(editor, previousRowPath));
4518
+ }
4519
+ }
4520
+ } else {
4521
+ if (nextRowMatch) {
4522
+ const [, nextRowPath] = nextRowMatch;
4523
+ if (Node$1.string(Node$1.child(row, 1)) === '') {
4524
+ TableTransforms.deleteRange(editor, [editor.selection.anchor, Editor.start(editor, nextRowPath)]);
4525
+ return;
4526
+ }
4527
+ }
4528
+ Transforms.select(editor, Editor.start(editor, Path.next(cellPath)));
4529
+ }
4530
+ } else {
4531
+ if (nextRowMatch) {
4532
+ const [nextRow, nextRowPath] = nextRowMatch;
4533
+ if (Node$1.string(nextRow) === '') {
4534
+ Transforms.delete(editor, {
4535
+ at: nextRowPath
4536
+ });
4537
+ } else if (Node$1.string(Node$1.child(nextRow, 0)) === '') {
4538
+ TableTransforms.deleteRange(editor, [editor.selection.anchor, Editor.start(editor, [...nextRowPath, 1])]);
4539
+ } else {
4540
+ Transforms.select(editor, Editor.start(editor, nextRowPath));
4541
+ }
4542
+ }
4543
+ }
4544
+ };
4545
+ editor.deleteFragment = () => {
4546
+ if (editor.selection && Range.isExpanded(editor.selection)) {
4547
+ if (TableTransforms.deleteRange(editor, Range.edges(editor.selection))) {
4548
+ return;
4549
+ }
4550
+ }
4551
+ deleteFragment();
4552
+ };
4553
+ editor.insertData = function (data) {
4554
+ const fragment = data.getData('application/x-slate-fragment');
4555
+ if (fragment) {
4556
+ const decoded = decodeURIComponent(window.atob(fragment));
4557
+ const parsed = JSON.parse(decoded);
4558
+ if (parsed.every(element => element['type'] === 'row')) {
4559
+ editor.insertFragment(parsed);
4560
+ return;
4561
+ }
4562
+ }
4563
+ const text = data.getData('text/plain');
4564
+ if (text) {
4565
+ editor.insertText(text);
4566
+ }
4567
+ };
4568
+ editor.insertFragment = function (fragment) {
4569
+ if (fragment.length === 1 && fragment[0].children.length === 1) {
4570
+ Transforms.insertFragment(editor, fragment[0].children[0].children);
4571
+ } else {
4572
+ const rowMatch = Row.match(editor);
4573
+ if (rowMatch) {
4574
+ ensureLabelAndValueCells(fragment);
4575
+ const [, rowPath] = rowMatch;
4576
+ const nextRowPath = Path.next(rowPath);
4577
+ const pathRef = Editor.pathRef(editor, nextRowPath);
4578
+ Transforms.insertNodes(editor, fragment, {
4579
+ at: nextRowPath
4580
+ });
4581
+ Transforms.select(editor, Editor.end(editor, Path.previous(pathRef.unref())));
4582
+ }
4583
+ }
4584
+ function ensureLabelAndValueCells(fragment) {
4585
+ if (fragment[0].children.length === 1) {
4586
+ fragment[0].children.unshift({
4587
+ type: 'label',
4588
+ children: [{
4589
+ text: ''
4590
+ }]
4591
+ });
4592
+ }
4593
+ if (fragment[fragment.length - 1].children.length === 1) {
4594
+ fragment[fragment.length - 1].children.push({
4595
+ type: 'value',
4596
+ children: [{
4597
+ text: ''
4598
+ }]
4599
+ });
4600
+ }
4601
+ }
4602
+ };
4603
+ return editor;
4604
+ }
4605
+
4606
+ function handleTableNavigation(editor, event, stacked) {
4607
+ if (stacked) {
4608
+ return;
4609
+ }
4610
+ const {
4611
+ selection
4612
+ } = editor;
4613
+ if (selection && Range.isCollapsed(selection)) {
4614
+ const cellMatch = Cell.match(editor);
4615
+ if (cellMatch) {
4616
+ const [, cellPath] = cellMatch;
4617
+ const rowPath = cellPath.slice(0, -1);
4618
+ if (event.key === 'ArrowUp' && Cell.inFirstLine(editor, selection.anchor)) {
4619
+ event.preventDefault();
4620
+ if (rowPath[rowPath.length - 1] > 0) {
4621
+ const previousRowPath = Path.previous(rowPath);
4622
+ const targetPath = [...previousRowPath, cellPath[cellPath.length - 1]];
4623
+ Transforms.select(editor, Cell.getPointAtStartOfLastLine(editor, Editor.start(editor, targetPath).path));
4624
+ }
4625
+ } else if (event.key === 'ArrowDown' && Cell.inLastLine(editor, selection.anchor)) {
4626
+ event.preventDefault();
4627
+ const nextRowPath = Path.next(rowPath);
4628
+ const targetPath = [...nextRowPath, cellPath[cellPath.length - 1]];
4629
+ if (Node$1.has(editor, targetPath)) {
4630
+ Transforms.select(editor, Editor.start(editor, targetPath));
4631
+ }
4632
+ }
4633
+ }
4634
+ }
4635
+ }
4636
+
4637
+ var styles$h = {"placeholder":"placeholders-module_placeholder__2j2eo"};
4638
+
4639
+ function createRenderElementWithPlaceholder(options) {
4640
+ const renderElement = createRenderElement(options);
4641
+ return function ({
4642
+ attributes,
4643
+ children,
4644
+ element
4645
+ }) {
4646
+ if ((element.type === 'label' || element.type === 'value') && options.showPlaceholders && Node$1.string(element) === '') {
4647
+ children = /*#__PURE__*/React.createElement(React.Fragment, null, children, /*#__PURE__*/React.createElement("span", {
4648
+ contentEditable: false,
4649
+ className: styles$h.placeholder,
4650
+ "data-text": element.type === 'label' ? options.labelPlaceholder : options.valuePlaceholder
4651
+ }));
4652
+ }
4653
+ return renderElement({
4654
+ attributes,
4655
+ children,
4656
+ element
4657
+ });
4658
+ };
4659
+ }
4660
+
4661
+ const EditableTable = React.memo(function EditableTable({
4662
+ value,
4663
+ onChange,
4664
+ className,
4665
+ labelScaleCategory = 'body',
4666
+ valueScaleCategory = 'body',
4667
+ labelPlaceholder,
4668
+ valuePlaceholder,
4669
+ floatingControlsPosition = 'below',
4670
+ stackedInPhoneLayout = false
4671
+ }) {
4672
+ const editor = useMemo(() => withFixedColumns(withLinks(withLineBreakNormalization(withReact(withHistory(createEditor()))))), []);
4673
+ const {
4674
+ isSelected
4675
+ } = useContentElementEditorState();
4676
+ const phoneLayout = usePhoneLayout();
4677
+ const stacked = stackedInPhoneLayout && phoneLayout;
4678
+ const handleLineBreaks = useLineBreakHandler(editor);
4679
+ const handleShortcuts = useShortcutHandler(editor);
4680
+ const handleKeyDown = useCallback(event => {
4681
+ handleLineBreaks(event);
4682
+ handleShortcuts(event);
4683
+ handleTableNavigation(editor, event, stacked);
4684
+ }, [editor, handleLineBreaks, handleShortcuts, stacked]);
4685
+ const [cachedValue, setCachedValue] = useCachedValue(value, {
4686
+ defaultValue: [{
4687
+ type: 'row',
4688
+ children: [{
4689
+ type: 'label',
4690
+ children: [{
4691
+ text: ''
4692
+ }]
4693
+ }, {
4694
+ type: 'value',
4695
+ children: [{
4696
+ text: ''
4697
+ }]
4698
+ }]
4699
+ }],
4700
+ onDebouncedChange: onChange
4701
+ });
4702
+ const showPlaceholders = cachedValue.length === 1;
4703
+ const renderElement = useMemo(() => wrapRenderElementWithLinkPreview(createRenderElementWithPlaceholder({
4704
+ labelScaleCategory,
4705
+ valueScaleCategory,
4706
+ labelPlaceholder,
4707
+ valuePlaceholder,
4708
+ showPlaceholders
4709
+ })), [labelScaleCategory, valueScaleCategory, labelPlaceholder, valuePlaceholder, showPlaceholders]);
4710
+ return /*#__PURE__*/React.createElement(Slate, {
4711
+ editor: editor,
4712
+ value: cachedValue,
4713
+ onChange: setCachedValue
4714
+ }, /*#__PURE__*/React.createElement(LinkTooltipProvider, {
4715
+ disabled: editor.selection && !Range.isCollapsed(editor.selection),
4716
+ position: floatingControlsPosition
4717
+ }, /*#__PURE__*/React.createElement(HoveringToolbar, {
4718
+ position: floatingControlsPosition
4719
+ }), /*#__PURE__*/React.createElement("table", {
4720
+ className: classNames(className, tableStyles.table, {
4721
+ [selectedClassName]: isSelected
4722
+ }),
4723
+ "data-stacked": stacked ? '' : undefined
4724
+ }, /*#__PURE__*/React.createElement(Editable, {
4725
+ as: "tbody",
4726
+ decorate: decorateLineBreaks,
4727
+ onKeyDown: handleKeyDown,
4728
+ renderElement: renderElement,
4729
+ renderLeaf: renderLeafWithLineBreakDecoration
4730
+ }))));
4731
+ });
4732
+
4733
+ var styles$i = {"wrapper":"EditableLink-module_wrapper__2sbJy"};
4734
+
4735
+ function EditableLink({
4736
+ className,
4737
+ href,
4738
+ openInNewTab,
4739
+ children,
4740
+ onChange,
4741
+ onClick,
4742
+ linkPreviewDisabled,
4743
+ linkPreviewPosition = 'below',
4744
+ linkPreviewAlign = 'center',
4745
+ floatingStrategy,
4746
+ actionButtonPosition = 'outside',
4747
+ actionButtonVisible = 'whenSelected',
4748
+ actionButtonPortal,
4749
+ allowRemove = false
4750
+ }) {
4751
+ const selectLinkDestination = useSelectLinkDestination();
4752
+ const {
4753
+ t
4754
+ } = useI18n({
4755
+ locale: 'ui'
4756
+ });
4757
+ const {
4758
+ isSelected: inSelectedContentElement
4759
+ } = useContentElementEditorState();
4760
+ const {
4761
+ isSelected: inSelectedWidget
4762
+ } = useWidgetEditorState();
4763
+ if (actionButtonVisible === 'whenSelected') {
4764
+ actionButtonVisible = inSelectedContentElement || inSelectedWidget;
4765
+ }
4766
+ function handleSelectLinkDestination() {
4767
+ selectLinkDestination().then(onChange, () => {});
4768
+ }
4769
+ function handleRemoveLink() {
4770
+ onChange(null);
4771
+ }
4772
+ return /*#__PURE__*/React.createElement("div", {
4773
+ className: styles$i.wrapper
4774
+ }, /*#__PURE__*/React.createElement(LinkTooltipProvider, {
4775
+ position: linkPreviewPosition,
4776
+ floatingStrategy: floatingStrategy,
4777
+ align: linkPreviewAlign,
4778
+ onClick: onClick,
4779
+ gap: 5
4780
+ }, /*#__PURE__*/React.createElement(LinkPreview, {
4781
+ disabled: linkPreviewDisabled,
4782
+ href: href,
4783
+ openInNewTab: openInNewTab,
4784
+ className: className
4785
+ }, children)), actionButtonVisible && /*#__PURE__*/React.createElement(ActionButtons, {
4786
+ buttons: [{
4787
+ icon: 'link',
4788
+ text: href ? t('pageflow_scrolled.inline_editing.change_link_destination') : t('pageflow_scrolled.inline_editing.select_link_destination'),
4789
+ onClick: handleSelectLinkDestination
4790
+ }, ...(allowRemove && href ? [{
4791
+ icon: 'unlink',
4792
+ iconOnly: true,
4793
+ text: t('pageflow_scrolled.inline_editing.remove_link'),
4794
+ onClick: handleRemoveLink
4795
+ }] : [])],
4796
+ position: actionButtonPosition,
4797
+ portal: actionButtonPortal,
4798
+ floatingStrategy: floatingStrategy
4799
+ }));
4800
+ }
4801
+
4802
+ function WidgetSelectionRect({
4803
+ children
4804
+ }) {
4805
+ const {
4806
+ select,
4807
+ isSelected
4808
+ } = useWidgetEditorState();
4809
+ return /*#__PURE__*/React.createElement("div", {
4810
+ className: classNames(styles$3.wrapper, {
4811
+ [styles$3.selected]: isSelected
4812
+ }),
4813
+ onClick: () => select()
4814
+ }, children);
4815
+ }
4816
+
4817
+ function PhonePlatformProvider({
4818
+ children
4819
+ }) {
4820
+ const [phoneEmulationMode, setPhoneEmulationMode] = useState(false);
4821
+ useEffect(() => {
4822
+ window.addEventListener('message', receive);
4823
+ function receive(event) {
4824
+ if (event.data.type === 'CHANGE_EMULATION_MODE') {
4825
+ if (event.data['payload'] === 'phone') {
4826
+ setPhoneEmulationMode(true);
4827
+ } else {
4828
+ setPhoneEmulationMode(false);
4829
+ }
4830
+ }
4831
+ }
4832
+ return () => window.removeEventListener('message', receive);
4833
+ });
4834
+ return /*#__PURE__*/React.createElement(PhonePlatformContext.Provider, {
4835
+ value: phoneEmulationMode
4836
+ }, children);
4837
+ }
4838
+
4839
+ function Placeholder() {
4840
+ return /*#__PURE__*/React.createElement("div", {
4841
+ className: styles$j.placeholder
4842
+ }, /*#__PURE__*/React.createElement("svg", {
4843
+ width: "100%",
4844
+ height: "100%",
4845
+ preserveAspectRatio: "none"
4846
+ }, /*#__PURE__*/React.createElement("line", {
4847
+ x1: "0",
4848
+ y1: "0",
4849
+ x2: "100%",
4850
+ y2: "100%",
4851
+ stroke: "rgba(255,255,255,0.2)",
4852
+ strokeWidth: "1"
4853
+ }), /*#__PURE__*/React.createElement("line", {
4854
+ x1: "100%",
4855
+ y1: "0",
4856
+ x2: "0",
4857
+ y2: "100%",
4858
+ stroke: "rgba(255,255,255,0.2)",
4859
+ strokeWidth: "1"
4860
+ })));
4861
+ }
4862
+
4863
+ const extensions = {
4864
+ decorators: {
4865
+ Entry: EntryDecorator,
4866
+ Content: ContentDecorator,
4867
+ Section: SectionDecorator,
4868
+ ContentElement: ContentElementDecorator,
4869
+ SelectableWidget: SelectableWidgetDecorator,
4870
+ Widget: WidgetDecorator,
4871
+ Backdrop: BackdropDecorator,
4872
+ BackgroundContentElement: BackgroundContentElementDecorator,
4873
+ Foreground: ForegroundDecorator
4874
+ },
4875
+ alternatives: {
4876
+ LayoutWithPlaceholder,
4877
+ EditableText,
4878
+ EditableInlineText,
4879
+ EditableTable,
4880
+ EditableLink,
4881
+ LinkTooltipProvider,
4882
+ WidgetSelectionRect,
4883
+ ActionButton,
4884
+ ActionButtons,
4885
+ PhonePlatformProvider,
4886
+ Placeholder
4887
+ }
4888
+ };
4889
+
4890
+ export { extensions };