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,2538 @@
1
+ import React, { createContext, useState, useRef, useContext, useEffect, useMemo, useCallback } from 'react';
2
+ import classNames from 'classnames';
3
+ import { u as useDelayedBoolean } from './useDelayedBoolean-a387d85b.js';
4
+ import BackboneEvents from 'backbone-events-standalone';
5
+ import { useTheme, useEntryStructure, useEmbedOriginUrl, useChapter, useDownloadableFile } from 'pageflow-scrolled/entryState';
6
+ import Measure from 'react-measure';
7
+ import PropTypes from 'prop-types';
8
+
9
+ const OnScreenObserverRootContext = createContext();
10
+ const OnScreenObserverRootProvider = OnScreenObserverRootContext.Provider;
11
+ function useOnScreen(ref, {
12
+ rootMargin,
13
+ onIntersecting,
14
+ onChange,
15
+ skipIframeFix
16
+ } = {}) {
17
+ var _useContext;
18
+ const [isIntersecting, setIntersecting] = useState(false);
19
+ const onIntersectingRef = useRef();
20
+ const onChangeRef = useRef();
21
+ const root = (_useContext = useContext(OnScreenObserverRootContext)) === null || _useContext === void 0 ? void 0 : _useContext.current;
22
+ useEffect(() => {
23
+ onIntersectingRef.current = onIntersecting;
24
+ }, [onIntersecting]);
25
+ useEffect(() => {
26
+ onChangeRef.current = onChange;
27
+ }, [onChange]);
28
+ useEffect(() => {
29
+ const current = ref.current;
30
+ const observer = createIntersectionObserver(entries => {
31
+ // Even when observing only a single element, multiple entries
32
+ // may have queued up. In Chrome this can be observed when
33
+ // moving an observed element in the DOM: The callback is
34
+ // invoked once with two entries for the same target, one
35
+ // claiming the element no longer intersects and one - with a
36
+ // later timestamp - saying that is does intersect. Assuming
37
+ // entries are ordered according to time, we only consider the
38
+ // last entry.
39
+ const entry = entries[entries.length - 1];
40
+ setIntersecting(entry.isIntersecting);
41
+ if (entry.isIntersecting && onIntersectingRef.current) {
42
+ onIntersectingRef.current();
43
+ }
44
+ if (onChangeRef.current) {
45
+ onChangeRef.current(entry.isIntersecting);
46
+ }
47
+ }, {
48
+ rootMargin,
49
+ root
50
+ }, skipIframeFix);
51
+ if (ref.current) {
52
+ observer.observe(current);
53
+ }
54
+ return () => {
55
+ observer.unobserve(current);
56
+ };
57
+ }, [ref, rootMargin, root, skipIframeFix]);
58
+ return isIntersecting;
59
+ }
60
+ function createIntersectionObserver(callback, options, skipIframeFix) {
61
+ if (skipIframeFix || options.root) {
62
+ return new IntersectionObserver(callback, options);
63
+ }
64
+
65
+ // Positive root margins are ignored in iframes [1] (i.e. in
66
+ // the Pageflow editor). To make it work, the iframe document
67
+ // needs to be passed as `root` [2].
68
+ // This leads to a `TypeError`, though, in browers that do not
69
+ // support this yet (e.g. Chrome 80). We catch the error and
70
+ // skip passing the `root` option.
71
+ //
72
+ // [1] https://github.com/w3c/IntersectionObserver/issues/283
73
+ // [2] https://github.com/w3c/IntersectionObserver/issues/372
74
+ try {
75
+ let optionsWithIframeFix = options;
76
+ if (options.rootMargin && window.parent !== window) {
77
+ optionsWithIframeFix = {
78
+ ...options,
79
+ root: window.document
80
+ };
81
+ }
82
+ return new IntersectionObserver(callback, optionsWithIframeFix);
83
+ } catch (e) {
84
+ // Normally we would check for TypeError here. Since the polyfill
85
+ // throws a generic error, we retry either way and trust that the
86
+ // error will happen again if it is not related to the `root`
87
+ // option.
88
+ return createIntersectionObserver(callback, options, true);
89
+ }
90
+ }
91
+
92
+ var _jsxFileName = "/home/tfischbach/code/pageflow/entry_types/scrolled/package/src/frontend/storylineActivity.js";
93
+ const StorylineActivityContext = createContext('active');
94
+ const MainStorylineCoverageContext = createContext({
95
+ mainStorylineCovered: false,
96
+ setMainStorylineCovered: () => {}
97
+ });
98
+ function MainStorylineActivity({
99
+ activeExcursion,
100
+ children
101
+ }) {
102
+ const {
103
+ mainStorylineCovered
104
+ } = useContext(MainStorylineCoverageContext);
105
+ const mode = activeExcursion ? mainStorylineCovered ? 'covered' : 'background' : 'active';
106
+ return /*#__PURE__*/React.createElement(StorylineActivityContext.Provider, {
107
+ value: mode,
108
+ __self: this,
109
+ __source: {
110
+ fileName: _jsxFileName,
111
+ lineNumber: 18,
112
+ columnNumber: 5
113
+ }
114
+ }, children);
115
+ }
116
+ function MainStorylineCoverageProvider({
117
+ children
118
+ }) {
119
+ const [mainStorylineCovered, setMainStorylineCovered] = useState(false);
120
+ const value = useMemo(() => ({
121
+ mainStorylineCovered,
122
+ setMainStorylineCovered
123
+ }), [mainStorylineCovered]);
124
+ return /*#__PURE__*/React.createElement(MainStorylineCoverageContext.Provider, {
125
+ value: value,
126
+ __self: this,
127
+ __source: {
128
+ fileName: _jsxFileName,
129
+ lineNumber: 29,
130
+ columnNumber: 5
131
+ }
132
+ }, children);
133
+ }
134
+ function useStorylineActivity() {
135
+ return useContext(StorylineActivityContext);
136
+ }
137
+ function useMainStorylineCoverage() {
138
+ return useContext(MainStorylineCoverageContext);
139
+ }
140
+
141
+ var styles = {"wrapper":"useScrollPositionLifecycle-module_wrapper__1a6Kr","isActiveProbe":"useScrollPositionLifecycle-module_isActiveProbe__3VKB5"};
142
+
143
+ var _jsxFileName$1 = "/home/tfischbach/code/pageflow/entry_types/scrolled/package/src/frontend/useScrollPositionLifecycle.js";
144
+ const StaticPreviewContext = createContext(false);
145
+ function StaticPreview({
146
+ children
147
+ }) {
148
+ return /*#__PURE__*/React.createElement(StaticPreviewContext.Provider, {
149
+ value: true,
150
+ __self: this,
151
+ __source: {
152
+ fileName: _jsxFileName$1,
153
+ lineNumber: 13,
154
+ columnNumber: 5
155
+ }
156
+ }, children);
157
+ }
158
+
159
+ /**
160
+ * Use inside a content element component to determine whether the
161
+ * component is being rendered in a static preview, e.g. editor
162
+ * thumbnails.
163
+ *
164
+ * @example
165
+ * const isStaticPreview = useIsStaticPreview();
166
+ */
167
+ function useIsStaticPreview() {
168
+ return useContext(StaticPreviewContext);
169
+ }
170
+ function createScrollPositionLifecycleProvider(Context) {
171
+ return function ScrollPositionLifecycleProvider({
172
+ children,
173
+ onActivate,
174
+ entersWithFadeTransition
175
+ }) {
176
+ const ref = useRef();
177
+ const isActiveProbeRef = useRef();
178
+ const isStaticPreview = useContext(StaticPreviewContext);
179
+ const mode = useStorylineActivity();
180
+ const shouldLoad = useOnScreen(ref, {
181
+ rootMargin: '200% 0px 200% 0px'
182
+ });
183
+ const shouldPrepare = useOnScreen(ref, {
184
+ rootMargin: '25% 0px 25% 0px'
185
+ }) && !isStaticPreview;
186
+
187
+ // Sections that enter with fade transition only become visible
188
+ // once they reach the center of the viewport. We want to reflect
189
+ // that in `isVisible`/`onVisible` to prevent background videos
190
+ // from starting too soon. Since fade section might still exit
191
+ // with a scroll transition, we want to keep `isVisible` true
192
+ // until the section has completely left the viewport. We do not
193
+ // care about when exactly a background video pauses.
194
+ //
195
+ // Note that with fade transitions sections actually stay visible
196
+ // a bit longer while they are still fading out. This is handled
197
+ // by `isVisibleWithDelay` below.
198
+ const shouldBeVisible = useOnScreen(ref, {
199
+ rootMargin: entersWithFadeTransition ? '0px 0px -50% 0px' : undefined
200
+ }) && !isStaticPreview;
201
+ const shouldBeActive = useOnScreen(isActiveProbeRef, {
202
+ rootMargin: '-50% 0px -50% 0px',
203
+ onIntersecting: onActivate
204
+ }) && !isStaticPreview;
205
+
206
+ // useDelayedBoolean causes an extra render once the delay has
207
+ // elapsed. When entersWithFadeTransition is false,
208
+ // isVisibleWithDelay is never used, though. Since hooks can not
209
+ // be wrapped in conditionals, we ensure that the value passed to
210
+ // useDelayedBoolean is always false if entersWithFadeTransition
211
+ // is false. This prevents the extra render.
212
+ const isVisibleWithDelay = useDelayedBoolean(shouldBeVisible && entersWithFadeTransition, {
213
+ fromTrueToFalse: 1000
214
+ });
215
+ const isVisible = entersWithFadeTransition ? isVisibleWithDelay : shouldBeVisible;
216
+ // Elements in covered storylines are not visible.
217
+ // Elements in background storylines are visible (but not active).
218
+ // Elements in active storylines are both visible and active.
219
+ const isVisibleFinal = isVisible && mode !== 'covered';
220
+ const inForeground = mode === 'active';
221
+
222
+ // We want to make sure that `onActivate` is never called before
223
+ // `onVisible`, no matter in which order the intersection
224
+ // observers above fire.
225
+ const isActive = isVisibleFinal && shouldBeActive && inForeground;
226
+ const value = useMemo(() => ({
227
+ shouldLoad,
228
+ shouldPrepare,
229
+ isVisible: isVisibleFinal,
230
+ isActive,
231
+ inForeground
232
+ }), [shouldLoad, shouldPrepare, isVisibleFinal, isActive, inForeground]);
233
+ return /*#__PURE__*/React.createElement("div", {
234
+ ref: ref,
235
+ className: classNames(styles.wrapper),
236
+ __self: this,
237
+ __source: {
238
+ fileName: _jsxFileName$1,
239
+ lineNumber: 94,
240
+ columnNumber: 7
241
+ }
242
+ }, /*#__PURE__*/React.createElement("div", {
243
+ ref: isActiveProbeRef,
244
+ className: styles.isActiveProbe,
245
+ __self: this,
246
+ __source: {
247
+ fileName: _jsxFileName$1,
248
+ lineNumber: 95,
249
+ columnNumber: 9
250
+ }
251
+ }), /*#__PURE__*/React.createElement(Context.Provider, {
252
+ value: value,
253
+ __self: this,
254
+ __source: {
255
+ fileName: _jsxFileName$1,
256
+ lineNumber: 97,
257
+ columnNumber: 9
258
+ }
259
+ }, children));
260
+ };
261
+ }
262
+ function createScrollPositionLifecycleHook(Context) {
263
+ return function useScrollPositionLifecycle({
264
+ onActivate,
265
+ onDeactivate,
266
+ onVisible,
267
+ onInvisible,
268
+ onEnterBackground,
269
+ onEnterForeground
270
+ } = {}) {
271
+ const result = useContext(Context);
272
+ const wasActive = useRef();
273
+ const wasVisible = useRef();
274
+ const wasForeground = useRef();
275
+ const {
276
+ isActive,
277
+ isVisible,
278
+ inForeground
279
+ } = result || {};
280
+ useEffect(() => {
281
+ if (!wasVisible.current && isVisible && onVisible) {
282
+ onVisible();
283
+ }
284
+ if (!wasActive.current && isActive && onActivate) {
285
+ onActivate();
286
+ } else if (wasActive.current && !isActive && onDeactivate) {
287
+ onDeactivate();
288
+ }
289
+ if (wasForeground.current && !inForeground && onEnterBackground) {
290
+ onEnterBackground();
291
+ } else if (!wasForeground.current && inForeground && onEnterForeground) {
292
+ onEnterForeground();
293
+ }
294
+ if (wasVisible.current && !isVisible && onInvisible) {
295
+ onInvisible();
296
+ }
297
+ wasActive.current = isActive;
298
+ wasVisible.current = isVisible;
299
+ wasForeground.current = inForeground;
300
+ });
301
+ return result;
302
+ };
303
+ }
304
+
305
+ var _jsxFileName$2 = "/home/tfischbach/code/pageflow/entry_types/scrolled/package/src/frontend/extensionRegistry.js";
306
+ function extensible(name, Component) {
307
+ return function ExtensibleComponent(props) {
308
+ const isStaticPreview = useIsStaticPreview();
309
+ const extensions = useExtensions();
310
+ if (isStaticPreview) {
311
+ return /*#__PURE__*/React.createElement(Component, Object.assign({}, props, {
312
+ __self: this,
313
+ __source: {
314
+ fileName: _jsxFileName$2,
315
+ lineNumber: 11,
316
+ columnNumber: 14
317
+ }
318
+ }));
319
+ }
320
+ const Alternative = extensions.alternatives[name];
321
+ if (Alternative) {
322
+ return /*#__PURE__*/React.createElement(Alternative, Object.assign({}, props, {
323
+ __self: this,
324
+ __source: {
325
+ fileName: _jsxFileName$2,
326
+ lineNumber: 17,
327
+ columnNumber: 14
328
+ }
329
+ }));
330
+ }
331
+ const Decorator = extensions.decorators[name];
332
+ if (Decorator) {
333
+ return /*#__PURE__*/React.createElement(Decorator, Object.assign({}, props, {
334
+ __self: this,
335
+ __source: {
336
+ fileName: _jsxFileName$2,
337
+ lineNumber: 23,
338
+ columnNumber: 14
339
+ }
340
+ }), /*#__PURE__*/React.createElement(Component, Object.assign({}, props, {
341
+ __self: this,
342
+ __source: {
343
+ fileName: _jsxFileName$2,
344
+ lineNumber: 23,
345
+ columnNumber: 36
346
+ }
347
+ })));
348
+ }
349
+ return /*#__PURE__*/React.createElement(Component, Object.assign({}, props, {
350
+ __self: this,
351
+ __source: {
352
+ fileName: _jsxFileName$2,
353
+ lineNumber: 26,
354
+ columnNumber: 12
355
+ }
356
+ }));
357
+ };
358
+ }
359
+ function provideExtensions({
360
+ decorators: d,
361
+ alternatives: a
362
+ } = {}) {
363
+ decorators = d || {};
364
+ alternatives = a || {};
365
+ notifyListeners();
366
+ }
367
+ function ExtensionsProvider({
368
+ children
369
+ }) {
370
+ const [version, setVersion] = useState(0);
371
+ useEffect(() => subscribe(() => setVersion(v => v + 1)), []);
372
+ return /*#__PURE__*/React.createElement(ExtensionsContext.Provider, {
373
+ value: version,
374
+ __self: this,
375
+ __source: {
376
+ fileName: _jsxFileName$2,
377
+ lineNumber: 48,
378
+ columnNumber: 5
379
+ }
380
+ }, children);
381
+ }
382
+ let decorators = {};
383
+ let alternatives = {};
384
+ let listeners = [];
385
+ const ExtensionsContext = createContext(0);
386
+ function useExtensions() {
387
+ useContext(ExtensionsContext);
388
+ return {
389
+ decorators,
390
+ alternatives
391
+ };
392
+ }
393
+ function subscribe(listener) {
394
+ listeners = [...listeners, listener];
395
+ return () => {
396
+ listeners = listeners.filter(l => l !== listener);
397
+ };
398
+ }
399
+ function notifyListeners() {
400
+ listeners.forEach(l => l());
401
+ }
402
+
403
+ /**
404
+ * Register new types of content elements.
405
+ * @name frontend_contentElementTypes
406
+ */
407
+ class ContentElementTypeRegistry {
408
+ constructor() {
409
+ this.types = {};
410
+ }
411
+
412
+ /**
413
+ * Register a new type of content element.
414
+ *
415
+ * @param {string} typeName - Name of the content element type.
416
+ * @param {Object} options
417
+ * @param {React.Component} options.component
418
+ * @param {boolean} [options.supportsWrappingAroundFloats] -
419
+ * In sections with centered layout, content elements can be
420
+ * floated to the left or right. By default all content
421
+ * elements are cleared to position them below floating
422
+ * elements. If a content element renders mainly text that
423
+ * can wrap around floating elements, clearing can be
424
+ * disabled via this option.
425
+ * @memberof frontend_contentElementTypes
426
+ *
427
+ * @example
428
+ *
429
+ * // frontend.js
430
+ *
431
+ * import {frontend} from 'pageflow-scrolled/frontend';
432
+ * import {InlineImage} from './InlineImage';
433
+ *
434
+ * frontend.contentElementTypes.register('inlineImage', {
435
+ * component: InlineImage
436
+ * });
437
+ */
438
+ register(typeName, options) {
439
+ this.types[typeName] = options;
440
+ }
441
+ getComponent(typeName) {
442
+ return this.types[typeName] && this.types[typeName].component;
443
+ }
444
+ getOptions(typeName) {
445
+ return this.types[typeName];
446
+ }
447
+ consentVendors({
448
+ contentElements,
449
+ t
450
+ }) {
451
+ const vendorsByName = {};
452
+ contentElements.forEach(contentElement => {
453
+ const type = this.types[contentElement.typeName];
454
+ const consentVendors = typeof type.consentVendors === 'function' ? type.consentVendors({
455
+ configuration: contentElement.configuration,
456
+ t
457
+ }) : type.consentVendors || [];
458
+ consentVendors.forEach(vendor => {
459
+ vendorsByName[vendor.name] = vendor;
460
+ });
461
+ });
462
+ return Object.values(vendorsByName);
463
+ }
464
+ }
465
+
466
+ /**
467
+ * Register new types of widgets.
468
+ * @name frontend_widgetTypes
469
+ */
470
+ class WidgetTypeRegistry {
471
+ constructor() {
472
+ this.types = {};
473
+ }
474
+
475
+ /**
476
+ * Register a new type of widget.
477
+ *
478
+ * @param {string} typeName - Name of the content element type.
479
+ * @param {Object} options
480
+ * @param {React.Component} options.component
481
+ * @memberof frontend_widgetTypes
482
+ *
483
+ * @example
484
+ *
485
+ * // frontend.js
486
+ *
487
+ * import {frontend} from 'pageflow-scrolled/frontend';
488
+ * import {CustomNavigationBar} from './CustomNavigationBar';
489
+ *
490
+ * frontend.contentElementTypes.register('customNavigationBar', {
491
+ * component: CustomNavigationBar
492
+ * });
493
+ */
494
+ register(typeName, options) {
495
+ if (!options.component) {
496
+ throw new Error(`Missing required component option for widget type '${typeName}'.`);
497
+ }
498
+ this.types[typeName] = options;
499
+ }
500
+ getComponent(typeName) {
501
+ if (!this.types[typeName]) {
502
+ throw new Error(`Unknown widget type '${typeName}'. Consider calling frontent.widgetTypes.register.`);
503
+ }
504
+ return this.types[typeName].component;
505
+ }
506
+ getPresenceProvider(typeName) {
507
+ var _this$types$typeName;
508
+ return (_this$types$typeName = this.types[typeName]) === null || _this$types$typeName === void 0 ? void 0 : _this$types$typeName.presenceProvider;
509
+ }
510
+ }
511
+
512
+ const api = {
513
+ contentElementTypes: new ContentElementTypeRegistry(),
514
+ widgetTypes: new WidgetTypeRegistry(),
515
+ /**
516
+ * Custom error boundary component to wrap content elements.
517
+ * Allows integration with error monitoring tools. The component receives
518
+ * typeName (string), configuration (object), fallback (function returning
519
+ * default UI), and children (content element).
520
+ *
521
+ * @name frontend_contentElementErrorBoundary
522
+ * @type {React.Component}
523
+ */
524
+ contentElementErrorBoundary: undefined
525
+ };
526
+
527
+ var _jsxFileName$3 = "/home/tfischbach/code/pageflow/entry_types/scrolled/package/src/frontend/useContentElementAttributes.js";
528
+ const ContentElementAttributesContext = createContext({});
529
+ function ContentElementAttributesProvider({
530
+ id,
531
+ permaId,
532
+ width,
533
+ position,
534
+ inlineComments,
535
+ children
536
+ }) {
537
+ const attributes = useMemo(() => ({
538
+ contentElementId: id,
539
+ contentElementPermaId: permaId,
540
+ width,
541
+ position,
542
+ inlineComments
543
+ }), [id, permaId, width, position, inlineComments]);
544
+ return /*#__PURE__*/React.createElement(ContentElementAttributesContext.Provider, {
545
+ value: attributes,
546
+ __self: this,
547
+ __source: {
548
+ fileName: _jsxFileName$3,
549
+ lineNumber: 15,
550
+ columnNumber: 5
551
+ }
552
+ }, children);
553
+ }
554
+ function useContentElementAttributes() {
555
+ return useContext(ContentElementAttributesContext);
556
+ }
557
+
558
+ var _jsxFileName$4 = "/home/tfischbach/code/pageflow/entry_types/scrolled/package/src/frontend/useContentElementLifecycle.js";
559
+ const ContentElementLifecycleContext = createContext();
560
+ const LifecycleProvider = createScrollPositionLifecycleProvider(ContentElementLifecycleContext);
561
+ const useLifecycle = createScrollPositionLifecycleHook(ContentElementLifecycleContext);
562
+ function ContentElementLifecycleProvider({
563
+ type,
564
+ children,
565
+ override
566
+ }) {
567
+ const {
568
+ lifecycle
569
+ } = api.contentElementTypes.getOptions(type);
570
+ if (override) {
571
+ return /*#__PURE__*/React.createElement(ContentElementLifecycleContext.Provider, {
572
+ value: override,
573
+ children: children,
574
+ __self: this,
575
+ __source: {
576
+ fileName: _jsxFileName$4,
577
+ lineNumber: 25,
578
+ columnNumber: 7
579
+ }
580
+ });
581
+ } else if (lifecycle) {
582
+ return /*#__PURE__*/React.createElement(LifecycleProvider, {
583
+ __self: this,
584
+ __source: {
585
+ fileName: _jsxFileName$4,
586
+ lineNumber: 30,
587
+ columnNumber: 7
588
+ }
589
+ }, children);
590
+ } else {
591
+ return children;
592
+ }
593
+ }
594
+
595
+ /**
596
+ * Returns an object containing information about the scroll position
597
+ * related lifecylce of the content element. Requires the `lifecycle`
598
+ * option to be set to true in the `frontend.contentElements.register`
599
+ * call for the content element's type.
600
+ *
601
+ * * `shouldLoad` is true if the content element should start lazy
602
+ * load. Becomes true before `shouldPrepare`.
603
+ *
604
+ * * `shouldPrepare` is true if the content element is about to enter
605
+ * the viewport.
606
+ *
607
+ * * `isActive` is true if the content element is completely in the
608
+ * viewport.
609
+ *
610
+ * @param {Function} onActivate -
611
+ * Invoked when content element has entered the viewport.
612
+ *
613
+ * @param {Function} onDeactivate -
614
+ * Invoked when content element has left the viewport.
615
+ *
616
+ * @example
617
+ *
618
+ * const {isActive, shouldPrepare} = useContentElementLifecycle();
619
+ */
620
+ function useContentElementLifecycle(options) {
621
+ const result = useLifecycle(options);
622
+ if (!result) {
623
+ throw new Error('useContentElementLifecycle is only available in ' + 'content elements for which `lifecycle: true` has ' + 'been passed to frontend.contentElements.register');
624
+ }
625
+ return result;
626
+ }
627
+
628
+ // Offsets of the subject's top edge relative to the viewport's top
629
+ // edge at the milestones of a content element's view timeline.
630
+ //
631
+ // Elements that are pinned in the viewport for part of their scroll
632
+ // space are measured along a taller subject: They move with the
633
+ // subject's top edge until they are pinned and continue with the
634
+ // subject's bottom edge once they have been.
635
+ const milestones = {
636
+ firstVisible: ({
637
+ viewportHeight
638
+ }) => viewportHeight,
639
+ firstContained: ({
640
+ viewportHeight,
641
+ elementHeight
642
+ }) => viewportHeight - elementHeight,
643
+ reachesCenter: ({
644
+ viewportHeight
645
+ }) => viewportHeight / 2,
646
+ leavesCenter: ({
647
+ subjectHeight,
648
+ viewportHeight
649
+ }) => viewportHeight / 2 - subjectHeight,
650
+ lastContained: ({
651
+ subjectHeight,
652
+ elementHeight
653
+ }) => elementHeight - subjectHeight,
654
+ lastVisible: ({
655
+ subjectHeight
656
+ }) => -subjectHeight,
657
+ // The pinned position is only known while the element actually is
658
+ // pinned. That is exactly when progress along the pinned range is
659
+ // between 0 and 1, though: Before, the element's top edge coincides
660
+ // with the subject's, after, its bottom edge does. Both edges of the
661
+ // range therefore come out equally far off in those phases, which
662
+ // makes progress clamp to 0 respectively 1.
663
+ reachesPinnedPosition: ({
664
+ elementTop
665
+ }) => elementTop,
666
+ leavesPinnedPosition: ({
667
+ elementTop,
668
+ subjectHeight,
669
+ elementHeight
670
+ }) => elementTop - subjectHeight + elementHeight
671
+ };
672
+ const ranges = {
673
+ // Mirror the named ranges of CSS scroll driven animations.
674
+ cover: ['firstVisible', 'lastVisible'],
675
+ contain: ['firstContained', 'lastContained'],
676
+ entry: ['firstVisible', 'firstContained'],
677
+ exit: ['lastContained', 'lastVisible'],
678
+ // Same part of the page during which content elements become active
679
+ // and autoplayed videos play.
680
+ center: ['reachesCenter', 'leavesCenter'],
681
+ // Only elements that components like TwoColumn or
682
+ // ContentElementScrollSpace pin in the viewport have a pinned phase.
683
+ pinned: ['reachesPinnedPosition', 'leavesPinnedPosition']
684
+ };
685
+ const rangeAliases = {
686
+ // Elements that are pinned in the viewport hold the reader's
687
+ // attention while they stay in place. Elements that are not pinned
688
+ // at all do so while they pass the center of the viewport.
689
+ inFocus: hasPinnedPhase => hasPinnedPhase ? 'pinned' : 'center'
690
+ };
691
+ function getViewTimelineProgress({
692
+ range,
693
+ subjectRect,
694
+ elementRect,
695
+ viewportHeight
696
+ }) {
697
+ const hasPinnedPhase = subjectRect.height > elementRect.height;
698
+ const alias = rangeAliases[range];
699
+ const milestoneNames = ranges[alias ? alias(hasPinnedPhase) : range];
700
+ if (!milestoneNames) {
701
+ const supportedRanges = [...Object.keys(ranges), ...Object.keys(rangeAliases)];
702
+ throw new Error(`Unknown view timeline range '${range}'. ` + `Supported ranges: ${supportedRanges.join(', ')}.`);
703
+ }
704
+
705
+ // Without enough content next to it, a pinned element never reaches
706
+ // its pinned position and keeps moving with the page. Its own rect
707
+ // then is the subject covering the same range of the page.
708
+ const subject = hasPinnedPhase ? subjectRect : elementRect;
709
+ const [start, end] = orderEdges(milestoneNames.map(name => milestones[name]({
710
+ subjectHeight: subject.height,
711
+ elementTop: elementRect.top,
712
+ elementHeight: elementRect.height,
713
+ viewportHeight
714
+ })));
715
+ if (start === end) {
716
+ return subject.top <= start ? 1 : 0;
717
+ }
718
+ return clamp((start - subject.top) / (start - end));
719
+ }
720
+
721
+ // Milestones come out in reverse order for elements taller than the
722
+ // viewport: Such elements cover the viewport instead of being
723
+ // contained in it, so they stop being contained before they start
724
+ // being contained.
725
+ function orderEdges([start, end]) {
726
+ return start < end ? [end, start] : [start, end];
727
+ }
728
+ function clamp(value) {
729
+ return Math.min(Math.max(value, 0), 1);
730
+ }
731
+
732
+ var _jsxFileName$5 = "/home/tfischbach/code/pageflow/entry_types/scrolled/package/src/frontend/useContentElementViewTimelineProgress.js";
733
+ const ContentElementViewTimelineContext = createContext();
734
+
735
+ // Lets components that pin content elements in the viewport for part
736
+ // of their scroll space pass a function returning the pinned element
737
+ // and the subject that keeps moving with the page. Pinned content
738
+ // elements would otherwise stop making progress along their view
739
+ // timeline for exactly the part of the page that the extra scroll
740
+ // space was added for.
741
+ //
742
+ // Passing a function instead of refs lets components resolve elements
743
+ // they do not render themselves: Sticky boxes in TwoColumn walk up the
744
+ // DOM to find their group.
745
+ const ViewTimelinePinContext = createContext();
746
+ function ViewTimelinePinProvider({
747
+ getPinnedElements,
748
+ children
749
+ }) {
750
+ return /*#__PURE__*/React.createElement(ViewTimelinePinContext.Provider, {
751
+ value: getPinnedElements,
752
+ children: children,
753
+ __self: this,
754
+ __source: {
755
+ fileName: _jsxFileName$5,
756
+ lineNumber: 22,
757
+ columnNumber: 5
758
+ }
759
+ });
760
+ }
761
+ function ContentElementViewTimelineProvider({
762
+ type,
763
+ children
764
+ }) {
765
+ const {
766
+ viewTimeline
767
+ } = api.contentElementTypes.getOptions(type);
768
+ if (viewTimeline) {
769
+ return /*#__PURE__*/React.createElement(ViewTimelineProvider, {
770
+ __self: this,
771
+ __source: {
772
+ fileName: _jsxFileName$5,
773
+ lineNumber: 32,
774
+ columnNumber: 7
775
+ }
776
+ }, children);
777
+ } else {
778
+ return children;
779
+ }
780
+ }
781
+ function ViewTimelineProvider({
782
+ children
783
+ }) {
784
+ const getPinnedElements = useContext(ViewTimelinePinContext);
785
+ const ownElementRef = useRef();
786
+ const subscriptionsRef = useRef(new Set());
787
+
788
+ // Content element types can support view timelines without always
789
+ // observing scroll position. Only listen while there are
790
+ // subscriptions to prevent each of them from adding a handler.
791
+ const [hasSubscriptions, setHasSubscriptions] = useState(false);
792
+ const getElements = useCallback(() => getPinnedElements ? getPinnedElements() : {
793
+ subject: ownElementRef.current,
794
+ element: ownElementRef.current
795
+ }, [getPinnedElements]);
796
+ const viewTimeline = useMemo(() => ({
797
+ subscribe(range, callback) {
798
+ const subscription = {
799
+ range,
800
+ callback
801
+ };
802
+ subscriptionsRef.current.add(subscription);
803
+ setHasSubscriptions(true);
804
+ update(getElements(), [subscription]);
805
+ return () => {
806
+ subscriptionsRef.current.delete(subscription);
807
+ setHasSubscriptions(subscriptionsRef.current.size > 0);
808
+ };
809
+ }
810
+ }), [getElements]);
811
+ useEffect(() => {
812
+ if (!hasSubscriptions) {
813
+ return;
814
+ }
815
+ const subscriptions = subscriptionsRef.current;
816
+ let animationFrame;
817
+ function handle() {
818
+ if (animationFrame) {
819
+ return;
820
+ }
821
+ animationFrame = requestAnimationFrame(() => {
822
+ animationFrame = null;
823
+ update(getElements(), subscriptions);
824
+ });
825
+ }
826
+ window.addEventListener('scroll', handle);
827
+ window.addEventListener('resize', handle);
828
+ return () => {
829
+ cancelAnimationFrame(animationFrame);
830
+ window.removeEventListener('scroll', handle);
831
+ window.removeEventListener('resize', handle);
832
+ };
833
+ }, [getElements, hasSubscriptions]);
834
+ const content = /*#__PURE__*/React.createElement(ContentElementViewTimelineContext.Provider, {
835
+ value: viewTimeline,
836
+ __self: this,
837
+ __source: {
838
+ fileName: _jsxFileName$5,
839
+ lineNumber: 107,
840
+ columnNumber: 5
841
+ }
842
+ }, children);
843
+ if (getPinnedElements) {
844
+ return content;
845
+ }
846
+ return /*#__PURE__*/React.createElement("div", {
847
+ ref: ownElementRef,
848
+ __self: this,
849
+ __source: {
850
+ fileName: _jsxFileName$5,
851
+ lineNumber: 117,
852
+ columnNumber: 5
853
+ }
854
+ }, content);
855
+ }
856
+ function update({
857
+ subject,
858
+ element
859
+ }, subscriptions) {
860
+ const subjectRect = subject.getBoundingClientRect();
861
+ const elementRect = element === subject ? subjectRect : element.getBoundingClientRect();
862
+ const viewportHeight = window.innerHeight;
863
+ subscriptions.forEach(subscription => {
864
+ const progress = getViewTimelineProgress({
865
+ range: subscription.range,
866
+ subjectRect,
867
+ elementRect,
868
+ viewportHeight
869
+ });
870
+ if (progress !== subscription.lastProgress) {
871
+ subscription.lastProgress = progress;
872
+ subscription.callback(progress);
873
+ }
874
+ });
875
+ }
876
+
877
+ /**
878
+ * Invokes a callback with the progress of the content element along a
879
+ * range of its view timeline. Mirrors the concepts of CSS scroll
880
+ * driven animations: The content element acts as the subject of a
881
+ * view timeline of the page's scroll container. Requires the
882
+ * `viewTimeline` option to be set to true in the
883
+ * `frontend.contentElementTypes.register` call for the content
884
+ * element's type.
885
+ *
886
+ * Progress is passed to a callback instead of being returned to
887
+ * prevent rerendering the content element on every scroll frame.
888
+ *
889
+ * @param {Object} options
890
+ *
891
+ * @param {string} [options.range='cover'] -
892
+ * Which part of the content element's view timeline to measure:
893
+ *
894
+ * * `cover`: From the moment the content element starts entering
895
+ * the viewport until it has completely left it.
896
+ *
897
+ * * `contain`: While the content element is completely inside the
898
+ * viewport. For content elements taller than the viewport, while
899
+ * the content element completely covers the viewport.
900
+ *
901
+ * * `entry`: While the content element is entering the viewport.
902
+ *
903
+ * * `exit`: While the content element is leaving the viewport.
904
+ *
905
+ * * `center`: While the content element intersects the vertical
906
+ * center of the viewport, i.e. from its top edge passing the
907
+ * center until its bottom edge does.
908
+ *
909
+ * * `pinned`: While the content element stays pinned in the
910
+ * viewport, i.e. from the moment it reaches the position it is
911
+ * pinned at until it starts moving with the page again. Progress
912
+ * stays 1 for content elements that are not pinned at all.
913
+ *
914
+ * * `inFocus`: While the content element holds the reader's
915
+ * attention: `pinned` for content elements that are pinned in the
916
+ * viewport, `center` for all others.
917
+ *
918
+ * @param {Function} [options.onProgress] -
919
+ * Invoked with a number between 0 and 1 whenever progress along the
920
+ * range changes. Pass a falsy value to not observe scroll position
921
+ * at all.
922
+ *
923
+ * @example
924
+ *
925
+ * useContentElementViewTimelineProgress({
926
+ * range: 'cover',
927
+ * onProgress: progress => player.seekTo(progress)
928
+ * });
929
+ */
930
+ function useContentElementViewTimelineProgress({
931
+ range = 'cover',
932
+ onProgress
933
+ } = {}) {
934
+ const viewTimeline = useContext(ContentElementViewTimelineContext);
935
+ const onProgressRef = useRef();
936
+ onProgressRef.current = onProgress;
937
+ const enabled = !!onProgress;
938
+ useEffect(() => {
939
+ if (viewTimeline && enabled) {
940
+ return viewTimeline.subscribe(range, progress => onProgressRef.current(progress));
941
+ }
942
+ }, [viewTimeline, range, enabled]);
943
+ if (!viewTimeline) {
944
+ throw new Error('useContentElementViewTimelineProgress is only available in ' + 'content elements for which `viewTimeline: true` has ' + 'been passed to frontend.contentElementTypes.register');
945
+ }
946
+ }
947
+
948
+ const widths = {
949
+ xxs: -3,
950
+ xs: -2,
951
+ sm: -1,
952
+ md: 0,
953
+ lg: 1,
954
+ xl: 2,
955
+ full: 3
956
+ };
957
+ function widthName(width) {
958
+ return Object.keys(widths)[(width || 0) + 3];
959
+ }
960
+
961
+ const TrimDefaultMarginTopContext = createContext(false);
962
+ const TrimDefaultMarginTop = TrimDefaultMarginTopContext.Provider;
963
+ function useTrimDefaultMarginTop() {
964
+ return useContext(TrimDefaultMarginTopContext);
965
+ }
966
+
967
+ var styles$1 = {"wrapper":"ContentElementMargin-module_wrapper__20kIk","noTopMargin":"ContentElementMargin-module_noTopMargin__mB7t3"};
968
+
969
+ var _jsxFileName$6 = "/home/tfischbach/code/pageflow/entry_types/scrolled/package/src/frontend/ContentElementMargin.js";
970
+ function ContentElementMargin({
971
+ width,
972
+ first,
973
+ defaultMarginTop,
974
+ top,
975
+ bottom,
976
+ previousBottom,
977
+ children
978
+ }) {
979
+ const trimDefaultMarginTop = useTrimDefaultMarginTop();
980
+ if (width === widths.full) {
981
+ return children;
982
+ }
983
+ return /*#__PURE__*/React.createElement("div", {
984
+ className: classNames(styles$1.wrapper, {
985
+ [styles$1.noTopMargin]: trimDefaultMarginTop && first && !top
986
+ }),
987
+ style: {
988
+ '--margin-top': scaleProperty(top) || defaultMarginTop,
989
+ '--margin-bottom': scaleProperty(bottom),
990
+ '--prev-margin-bottom': scaleProperty(previousBottom)
991
+ },
992
+ __self: this,
993
+ __source: {
994
+ fileName: _jsxFileName$6,
995
+ lineNumber: 17,
996
+ columnNumber: 5
997
+ }
998
+ }, children);
999
+ }
1000
+ function scaleProperty(value) {
1001
+ return value && `var(--theme-content-element-margin-${value})`;
1002
+ }
1003
+
1004
+ var styles$2 = {"missing":"ContentElement-module_missing__2_1j9"};
1005
+
1006
+ var _jsxFileName$7 = "/home/tfischbach/code/pageflow/entry_types/scrolled/package/src/frontend/ContentElementErrorBoundary.js";
1007
+ function ContentElementErrorBoundary({
1008
+ typeName,
1009
+ configuration,
1010
+ children
1011
+ }) {
1012
+ const ErrorBoundary = api.contentElementErrorBoundary || DefaultErrorBoundary;
1013
+ const fallback = () => /*#__PURE__*/React.createElement(DefaultFallback, {
1014
+ type: typeName,
1015
+ __self: this,
1016
+ __source: {
1017
+ fileName: _jsxFileName$7,
1018
+ lineNumber: 8,
1019
+ columnNumber: 26
1020
+ }
1021
+ });
1022
+ return /*#__PURE__*/React.createElement(ErrorBoundary, {
1023
+ typeName: typeName,
1024
+ configuration: configuration,
1025
+ fallback: fallback,
1026
+ __self: this,
1027
+ __source: {
1028
+ fileName: _jsxFileName$7,
1029
+ lineNumber: 11,
1030
+ columnNumber: 5
1031
+ }
1032
+ }, children);
1033
+ }
1034
+ class DefaultErrorBoundary extends React.Component {
1035
+ constructor(props) {
1036
+ super(props);
1037
+ this.state = {
1038
+ hasError: false
1039
+ };
1040
+ }
1041
+ static getDerivedStateFromError(error) {
1042
+ return {
1043
+ hasError: true
1044
+ };
1045
+ }
1046
+ render() {
1047
+ if (this.state.hasError) {
1048
+ return this.props.fallback();
1049
+ }
1050
+ return this.props.children;
1051
+ }
1052
+ }
1053
+ function DefaultFallback({
1054
+ type
1055
+ }) {
1056
+ return /*#__PURE__*/React.createElement("div", {
1057
+ className: styles$2.missing,
1058
+ __self: this,
1059
+ __source: {
1060
+ fileName: _jsxFileName$7,
1061
+ lineNumber: 42,
1062
+ columnNumber: 5
1063
+ }
1064
+ }, "Error rendering element of type \"", type, "\"");
1065
+ }
1066
+
1067
+ var _jsxFileName$8 = "/home/tfischbach/code/pageflow/entry_types/scrolled/package/src/frontend/ContentElement.js";
1068
+ const ContentElement = React.memo(extensible('ContentElement', function ContentElement(props) {
1069
+ const Component = api.contentElementTypes.getComponent(props.type);
1070
+ const {
1071
+ defaultMarginTop,
1072
+ inlineComments
1073
+ } = api.contentElementTypes.getOptions(props.type) || {};
1074
+ if (Component) {
1075
+ return /*#__PURE__*/React.createElement(ContentElementAttributesProvider, {
1076
+ id: props.id,
1077
+ permaId: props.permaId,
1078
+ width: props.width,
1079
+ position: props.position,
1080
+ inlineComments: inlineComments,
1081
+ __self: this,
1082
+ __source: {
1083
+ fileName: _jsxFileName$8,
1084
+ lineNumber: 21,
1085
+ columnNumber: 9
1086
+ }
1087
+ }, /*#__PURE__*/React.createElement(ContentElementLifecycleProvider, {
1088
+ type: props.type,
1089
+ override: props.lifecycleOverride,
1090
+ __self: this,
1091
+ __source: {
1092
+ fileName: _jsxFileName$8,
1093
+ lineNumber: 22,
1094
+ columnNumber: 11
1095
+ }
1096
+ }, /*#__PURE__*/React.createElement(ContentElementMargin, {
1097
+ width: props.width,
1098
+ first: props.first,
1099
+ defaultMarginTop: defaultMarginTop,
1100
+ top: props.itemProps.marginTop,
1101
+ bottom: props.marginBottom,
1102
+ previousBottom: props.previousMarginBottom,
1103
+ __self: this,
1104
+ __source: {
1105
+ fileName: _jsxFileName$8,
1106
+ lineNumber: 24,
1107
+ columnNumber: 13
1108
+ }
1109
+ }, /*#__PURE__*/React.createElement(ContentElementViewTimelineProvider, {
1110
+ type: props.type,
1111
+ __self: this,
1112
+ __source: {
1113
+ fileName: _jsxFileName$8,
1114
+ lineNumber: 30,
1115
+ columnNumber: 15
1116
+ }
1117
+ }, /*#__PURE__*/React.createElement(ContentElementErrorBoundary, {
1118
+ typeName: props.type,
1119
+ configuration: props.itemProps,
1120
+ __self: this,
1121
+ __source: {
1122
+ fileName: _jsxFileName$8,
1123
+ lineNumber: 31,
1124
+ columnNumber: 17
1125
+ }
1126
+ }, /*#__PURE__*/React.createElement(Component, {
1127
+ sectionProps: props.sectionProps,
1128
+ customMargin: props.customMargin,
1129
+ configuration: props.itemProps,
1130
+ contentElementWidth: props.width,
1131
+ contentElementId: props.id,
1132
+ __self: this,
1133
+ __source: {
1134
+ fileName: _jsxFileName$8,
1135
+ lineNumber: 33,
1136
+ columnNumber: 19
1137
+ }
1138
+ }))))));
1139
+ } else {
1140
+ return /*#__PURE__*/React.createElement("div", {
1141
+ className: styles$2.missing,
1142
+ __self: this,
1143
+ __source: {
1144
+ fileName: _jsxFileName$8,
1145
+ lineNumber: 46,
1146
+ columnNumber: 14
1147
+ }
1148
+ }, "Element of unknown type \"", props.type, "\"");
1149
+ }
1150
+ }), arePropsEqual);
1151
+ function arePropsEqual(prevProps, nextProps) {
1152
+ return prevProps.id === nextProps.id && prevProps.permaId === nextProps.permaId && prevProps.type === nextProps.type && prevProps.first === nextProps.first && prevProps.position === nextProps.position && prevProps.width === nextProps.width && prevProps.itemProps === nextProps.itemProps && prevProps.marginBottom === nextProps.marginBottom && prevProps.previousMarginBottom === nextProps.previousMarginBottom && prevProps.customMargin === nextProps.customMargin && prevProps.sectionProps === nextProps.sectionProps && prevProps.lifecycleOverride === nextProps.lifecycleOverride;
1153
+ }
1154
+ ContentElement.defaultProps = {
1155
+ itemProps: {}
1156
+ };
1157
+
1158
+ var styles$3 = {"wrapper":"ContentElementScrollSpace-module_wrapper__2ZBwZ","inner":"ContentElementScrollSpace-module_inner__1FBgh"};
1159
+
1160
+ var _jsxFileName$9 = "/home/tfischbach/code/pageflow/entry_types/scrolled/package/src/frontend/ContentElementScrollSpace.js";
1161
+ function ContentElementScrollSpace({
1162
+ children
1163
+ }) {
1164
+ const ref = useRef();
1165
+ const innerRef = useRef();
1166
+ const getPinnedElements = useCallback(() => ({
1167
+ subject: ref.current,
1168
+ element: innerRef.current
1169
+ }), []);
1170
+ return /*#__PURE__*/React.createElement("div", {
1171
+ className: styles$3.wrapper,
1172
+ ref: ref,
1173
+ __self: this,
1174
+ __source: {
1175
+ fileName: _jsxFileName$9,
1176
+ lineNumber: 18,
1177
+ columnNumber: 5
1178
+ }
1179
+ }, /*#__PURE__*/React.createElement(ViewTimelinePinProvider, {
1180
+ getPinnedElements: getPinnedElements,
1181
+ __self: this,
1182
+ __source: {
1183
+ fileName: _jsxFileName$9,
1184
+ lineNumber: 19,
1185
+ columnNumber: 7
1186
+ }
1187
+ }, /*#__PURE__*/React.createElement(Measure, {
1188
+ bounds: true,
1189
+ innerRef: innerRef,
1190
+ __self: this,
1191
+ __source: {
1192
+ fileName: _jsxFileName$9,
1193
+ lineNumber: 20,
1194
+ columnNumber: 9
1195
+ }
1196
+ }, ({
1197
+ measureRef,
1198
+ contentRect
1199
+ }) => /*#__PURE__*/React.createElement("div", {
1200
+ ref: measureRef,
1201
+ className: styles$3.inner,
1202
+ style: {
1203
+ '--height': contentRect.bounds.height / 2
1204
+ },
1205
+ __self: this,
1206
+ __source: {
1207
+ fileName: _jsxFileName$9,
1208
+ lineNumber: 22,
1209
+ columnNumber: 13
1210
+ }
1211
+ }, children))));
1212
+ }
1213
+
1214
+ var _jsxFileName$a = "/home/tfischbach/code/pageflow/entry_types/scrolled/package/src/frontend/ContentElements.js";
1215
+ function ContentElements(props) {
1216
+ return /*#__PURE__*/React.createElement(React.Fragment, null, props.items.map((item, index) => props.children(item, renderScrollSpace(item, /*#__PURE__*/React.createElement(ContentElement, {
1217
+ key: item.id,
1218
+ id: item.id,
1219
+ permaId: item.permaId,
1220
+ type: item.type,
1221
+ first: index === 0,
1222
+ position: item.position,
1223
+ width: item.width,
1224
+ itemProps: item.props,
1225
+ marginBottom: item.marginBottom,
1226
+ previousMarginBottom: item.previousMarginBottom,
1227
+ customMargin: props.customMargin,
1228
+ sectionProps: props.sectionProps,
1229
+ __self: this,
1230
+ __source: {
1231
+ fileName: _jsxFileName$a,
1232
+ lineNumber: 14,
1233
+ columnNumber: 13
1234
+ }
1235
+ })), index)));
1236
+ }
1237
+ ContentElements.defaultProps = {
1238
+ children: (item, child) => child
1239
+ };
1240
+ function renderScrollSpace(item, children) {
1241
+ if (!item.standAlone) {
1242
+ return children;
1243
+ }
1244
+ return /*#__PURE__*/React.createElement(ContentElementScrollSpace, {
1245
+ key: item.id,
1246
+ children: children,
1247
+ __self: this,
1248
+ __source: {
1249
+ fileName: _jsxFileName$a,
1250
+ lineNumber: 44,
1251
+ columnNumber: 5
1252
+ }
1253
+ });
1254
+ }
1255
+
1256
+ function useMediaQuery(query, {
1257
+ active
1258
+ } = {
1259
+ active: true
1260
+ }) {
1261
+ const [doesMatch, setDoesMatch] = useState(false);
1262
+ useEffect(() => {
1263
+ if (!active) {
1264
+ return;
1265
+ }
1266
+ const onUpdateMatch = ({
1267
+ matches
1268
+ }) => {
1269
+ setDoesMatch(matches);
1270
+ };
1271
+ const matcher = window.matchMedia(query);
1272
+ matcher.addEventListener('change', onUpdateMatch);
1273
+ onUpdateMatch(matcher);
1274
+ return () => {
1275
+ matcher.removeEventListener('change', onUpdateMatch);
1276
+ };
1277
+ }, [query, setDoesMatch, active]);
1278
+ return active && doesMatch;
1279
+ }
1280
+
1281
+ var styles$4 = {"root":"TwoColumn-module_root__37EqL","group":"TwoColumn-module_group__3Hg2y","group-full":"TwoColumn-module_group-full__2OT4o","box":"TwoColumn-module_box__1Nils","inline":"TwoColumn-module_inline__1fPfM","width-lg":"TwoColumn-module_width-lg__2MD35","width-xl":"TwoColumn-module_width-xl__3Bxet","width-full":"TwoColumn-module_width-full__1QWYO","constrainContentWidth":"TwoColumn-module_constrainContentWidth__1cxa-","group-lg":"TwoColumn-module_group-lg__xgaPx","restrict-xxs":"TwoColumn-module_restrict-xxs__6il-H","restrict-xs":"TwoColumn-module_restrict-xs__AOezq","restrict-sm":"TwoColumn-module_restrict-sm__2rKty","align-left":"TwoColumn-module_align-left__QSe2G","align-right":"TwoColumn-module_align-right__3Dn4i","customMargin":"TwoColumn-module_customMargin__o0uxH","right":"TwoColumn-module_right__Fr52a","side":"TwoColumn-module_side__2xx0s","sticky":"TwoColumn-module_sticky__4LCDO TwoColumn-module_side__2xx0s"};
1282
+
1283
+ var _jsxFileName$b = "/home/tfischbach/code/pageflow/entry_types/scrolled/package/src/frontend/layouts/TwoColumn.js";
1284
+ function TwoColumn(props) {
1285
+ const shouldInline = useShouldInlineSticky();
1286
+ return /*#__PURE__*/React.createElement("div", {
1287
+ className: classNames(styles$4.root, styles$4[props.align], {
1288
+ [styles$4.constrainContentWidth]: props.constrainContentWidth
1289
+ }),
1290
+ __self: this,
1291
+ __source: {
1292
+ fileName: _jsxFileName$b,
1293
+ lineNumber: 17,
1294
+ columnNumber: 5
1295
+ }
1296
+ }, /*#__PURE__*/React.createElement("div", {
1297
+ className: classNames(styles$4.group),
1298
+ key: props.align,
1299
+ __self: this,
1300
+ __source: {
1301
+ fileName: _jsxFileName$b,
1302
+ lineNumber: 19,
1303
+ columnNumber: 7
1304
+ }
1305
+ }, /*#__PURE__*/React.createElement("div", Object.assign({
1306
+ className: classNames(styles$4.box, styles$4.inline),
1307
+ ref: props.contentAreaRef
1308
+ }, TwoColumn.contentAreaProbeProps, {
1309
+ __self: this,
1310
+ __source: {
1311
+ fileName: _jsxFileName$b,
1312
+ lineNumber: 20,
1313
+ columnNumber: 9
1314
+ }
1315
+ }))), renderItems(props, shouldInline), renderPlaceholder(props.placeholder));
1316
+ }
1317
+ TwoColumn.defaultProps = {
1318
+ align: 'left'
1319
+ };
1320
+ function useShouldInlineSticky() {
1321
+ var _theme$options$proper;
1322
+ const theme = useTheme();
1323
+ const root = ((_theme$options$proper = theme.options.properties) === null || _theme$options$proper === void 0 ? void 0 : _theme$options$proper.root) || {};
1324
+ const shouldInline = {
1325
+ [widths.md]: useMediaQuery(`(max-width: ${root.twoColumnStickyBreakpoint || '950px'})`),
1326
+ [widths.lg]: useMediaQuery(`(max-width: ${root.twoColumnStickyLgBreakpoint || '1200px'})`),
1327
+ [widths.xl]: useMediaQuery(`(max-width: ${root.twoColumnStickyXlBreakpoint || '1400px'})`)
1328
+ };
1329
+ return function (width) {
1330
+ return width <= widths.md ? shouldInline[widths.md] : shouldInline[width];
1331
+ };
1332
+ }
1333
+
1334
+ // Used in tests to render markers around groups
1335
+ TwoColumn.GroupComponent = 'div';
1336
+
1337
+ // Used to set data-testids on probe element
1338
+ TwoColumn.contentAreaProbeProps = {};
1339
+ function renderItems(props, shouldInline) {
1340
+ const groups = groupItemsByPosition(props.items, shouldInline, props.isContentPadded);
1341
+ return groups.map((group, groupIndex) => /*#__PURE__*/React.createElement(TwoColumn.GroupComponent, {
1342
+ key: groupIndex,
1343
+ className: classNames(styles$4.group, styles$4[`group-${widthName(group.width)}`]),
1344
+ __self: this,
1345
+ __source: {
1346
+ fileName: _jsxFileName$b,
1347
+ lineNumber: 59,
1348
+ columnNumber: 5
1349
+ }
1350
+ }, group.boxes.map((box, boxIndex) => renderItemGroup(props, box, boxIndex))));
1351
+ }
1352
+ function renderItemGroup(props, box, key) {
1353
+ if (box.items.length) {
1354
+ return /*#__PURE__*/React.createElement(Box, {
1355
+ key: key,
1356
+ box: box,
1357
+ __self: this,
1358
+ __source: {
1359
+ fileName: _jsxFileName$b,
1360
+ lineNumber: 72,
1361
+ columnNumber: 7
1362
+ }
1363
+ }, props.children( /*#__PURE__*/React.createElement(ContentElements, {
1364
+ sectionProps: props.sectionProps,
1365
+ customMargin: box.customMargin,
1366
+ items: box.items,
1367
+ __self: this,
1368
+ __source: {
1369
+ fileName: _jsxFileName$b,
1370
+ lineNumber: 74,
1371
+ columnNumber: 11
1372
+ }
1373
+ }, (item, child) => restrictWidth(item.effectiveWidth, item.effectiveAlignment, child)), {
1374
+ position: box.position,
1375
+ width: box.width,
1376
+ customMargin: box.customMargin,
1377
+ lastMarginBottom: box.items[box.items.length - 1].marginBottom,
1378
+ openStart: box.openStart,
1379
+ openEnd: box.openEnd,
1380
+ atSectionStart: box.atSectionStart,
1381
+ atSectionEnd: box.atSectionEnd
1382
+ }));
1383
+ }
1384
+ }
1385
+ function Box({
1386
+ box,
1387
+ children
1388
+ }) {
1389
+ const ref = useRef();
1390
+ useStickyBoxHeight(ref, box.position === 'sticky');
1391
+ return /*#__PURE__*/React.createElement("div", {
1392
+ ref: ref,
1393
+ className: classNames(styles$4.box, styles$4[box.position], styles$4[`width-${widthName(box.width)}`], {
1394
+ [styles$4.customMargin]: box.customMargin
1395
+ }),
1396
+ __self: this,
1397
+ __source: {
1398
+ fileName: _jsxFileName$b,
1399
+ lineNumber: 103,
1400
+ columnNumber: 5
1401
+ }
1402
+ }, box.position === 'sticky' ? /*#__PURE__*/React.createElement(ViewTimelinePin, {
1403
+ boxRef: ref,
1404
+ children: children,
1405
+ __self: this,
1406
+ __source: {
1407
+ fileName: _jsxFileName$b,
1408
+ lineNumber: 109,
1409
+ columnNumber: 8
1410
+ }
1411
+ }) : children);
1412
+ }
1413
+ function useStickyBoxHeight(ref, sticky) {
1414
+ useEffect(() => {
1415
+ if (!sticky || typeof ResizeObserver === 'undefined') {
1416
+ return;
1417
+ }
1418
+ const box = ref.current;
1419
+ const observer = new ResizeObserver(entries => box.style.setProperty('--sticky-box-height', `${entries[entries.length - 1].contentRect.height}px`));
1420
+ observer.observe(box);
1421
+ return () => {
1422
+ observer.disconnect();
1423
+ box.style.removeProperty('--sticky-box-height');
1424
+ };
1425
+ }, [ref, sticky]);
1426
+ }
1427
+
1428
+ // Sticky boxes stay pinned while the rest of their group scrolls past.
1429
+ // The group therefore is the subject that drives view timelines of
1430
+ // content elements inside the box.
1431
+ function ViewTimelinePin({
1432
+ boxRef,
1433
+ children
1434
+ }) {
1435
+ const getPinnedElements = useCallback(() => ({
1436
+ subject: boxRef.current.closest(`.${styles$4.group}`),
1437
+ element: boxRef.current
1438
+ }), [boxRef]);
1439
+ return /*#__PURE__*/React.createElement(ViewTimelinePinProvider, {
1440
+ getPinnedElements: getPinnedElements,
1441
+ children: children,
1442
+ __self: this,
1443
+ __source: {
1444
+ fileName: _jsxFileName$b,
1445
+ lineNumber: 150,
1446
+ columnNumber: 5
1447
+ }
1448
+ });
1449
+ }
1450
+ function restrictWidth(width, alignment, children) {
1451
+ if (width >= 0) {
1452
+ return children;
1453
+ }
1454
+ return /*#__PURE__*/React.createElement("div", {
1455
+ className: classNames(styles$4[`restrict-${widthName(width)}`], styles$4[`align-${alignment}`]),
1456
+ __self: this,
1457
+ __source: {
1458
+ fileName: _jsxFileName$b,
1459
+ lineNumber: 161,
1460
+ columnNumber: 5
1461
+ }
1462
+ }, children);
1463
+ }
1464
+ function groupItemsByPosition(items, shouldInline, isContentPadded) {
1465
+ const groups = [];
1466
+ let currentGroup, currentBox;
1467
+ let firstInlineBox = null;
1468
+ let previousInlineBox = null;
1469
+ let previousInlineItem = null;
1470
+ let previousMarginBottom = null;
1471
+ items.reduce((previousPosition, item, index) => {
1472
+ var _item$props;
1473
+ let {
1474
+ customMargin: elementSupportsCustomMargin
1475
+ } = api.contentElementTypes.getOptions(item.type) || {};
1476
+ if (typeof elementSupportsCustomMargin === 'function') {
1477
+ elementSupportsCustomMargin = elementSupportsCustomMargin({
1478
+ configuration: item.props
1479
+ });
1480
+ }
1481
+ let width = item.width || 0;
1482
+ const position = onTheSide(item.position) && !shouldInline(width) ? item.position : 'inline';
1483
+ const customMargin = !!elementSupportsCustomMargin && width < widths.full;
1484
+ const alignment = item.position === 'inline' && width < 0 ? item.alignment : null;
1485
+ if (onTheSide(item.position) && position === 'inline' && width > widths.md) {
1486
+ width -= 1;
1487
+ }
1488
+ const boxWidth = position === 'inline' ? Math.max(width, widths.md) : width;
1489
+ if (!currentGroup || previousPosition !== position || onTheSide(position) && currentBox.customMargin !== customMargin || currentBox.width !== boxWidth) {
1490
+ currentBox = null;
1491
+ if (!(onTheSide(previousPosition) && position === 'inline' && width <= widths.md)) {
1492
+ currentGroup = {
1493
+ width: onTheSide(position) ? widths.md : boxWidth,
1494
+ boxes: []
1495
+ };
1496
+ groups.push(currentGroup);
1497
+ }
1498
+ }
1499
+ if (!currentBox || currentBox.customMargin !== customMargin) {
1500
+ currentBox = {
1501
+ customMargin,
1502
+ position,
1503
+ width: boxWidth,
1504
+ items: []
1505
+ };
1506
+ if (position === 'inline') {
1507
+ if (!continueInlineBoxes(previousInlineBox, currentBox)) {
1508
+ previousMarginBottom = null;
1509
+ }
1510
+ markFirstInlineBoxAsAtSectionStart(currentBox);
1511
+ }
1512
+ currentGroup.boxes.push(currentBox);
1513
+ }
1514
+ item = {
1515
+ ...item,
1516
+ effectiveWidth: width,
1517
+ effectiveAlignment: alignment,
1518
+ marginBottom: (_item$props = item.props) === null || _item$props === void 0 ? void 0 : _item$props.marginBottom
1519
+ };
1520
+ currentBox.items.push(item);
1521
+ if (position === 'inline') {
1522
+ assignPreviousMarginBottom(previousInlineItem, item);
1523
+ previousInlineItem = item;
1524
+ previousInlineBox = currentBox;
1525
+ }
1526
+ return position;
1527
+ }, null);
1528
+ if (currentBox) {
1529
+ currentBox.atSectionEnd = true;
1530
+ }
1531
+ return groups;
1532
+ function markFirstInlineBoxAsAtSectionStart(inlineBox) {
1533
+ if (!firstInlineBox) {
1534
+ inlineBox.atSectionStart = !isContentPadded;
1535
+ firstInlineBox = currentBox;
1536
+ }
1537
+ }
1538
+ function assignPreviousMarginBottom(previousInlineItem, item) {
1539
+ if (previousMarginBottom) {
1540
+ item.previousMarginBottom = previousMarginBottom;
1541
+ previousInlineItem.marginBottom = null;
1542
+ previousMarginBottom = null;
1543
+ }
1544
+ if (item.marginBottom) {
1545
+ previousMarginBottom = item.marginBottom;
1546
+ }
1547
+ }
1548
+ }
1549
+ function continueInlineBoxes(previousInlineBox, currentBox) {
1550
+ if (previousInlineBox && isContinuable(previousInlineBox) && isContinuable(currentBox)) {
1551
+ previousInlineBox.openEnd = true;
1552
+ currentBox.openStart = true;
1553
+ return true;
1554
+ }
1555
+ return false;
1556
+ }
1557
+ function isContinuable(box) {
1558
+ return box.width <= widths.md && !box.customMargin;
1559
+ }
1560
+ function onTheSide(position) {
1561
+ return position === 'side' || position === 'sticky';
1562
+ }
1563
+ function renderPlaceholder(placeholder) {
1564
+ if (!placeholder) {
1565
+ return null;
1566
+ }
1567
+ return /*#__PURE__*/React.createElement("div", {
1568
+ className: classNames(styles$4.group),
1569
+ __self: this,
1570
+ __source: {
1571
+ fileName: _jsxFileName$b,
1572
+ lineNumber: 307,
1573
+ columnNumber: 5
1574
+ }
1575
+ }, /*#__PURE__*/React.createElement("div", {
1576
+ className: classNames(styles$4.box, styles$4.inline),
1577
+ __self: this,
1578
+ __source: {
1579
+ fileName: _jsxFileName$b,
1580
+ lineNumber: 308,
1581
+ columnNumber: 7
1582
+ }
1583
+ }, placeholder));
1584
+ }
1585
+
1586
+ var styles$5 = {"outer":"Center-module_outer__3Rr0H","customMargin":"Center-module_customMargin__1es3t","outer-full":"Center-module_outer-full__3dknO","box":"Center-module_box__3pZbI","box-lg":"Center-module_box-lg__3t3-e","box-xl":"Center-module_box-xl__1zdnc","box-full":"Center-module_box-full__1YKgB","constrainContentWidth":"Center-module_constrainContentWidth__3BThN","outer-lg":"Center-module_outer-lg__fEKHC","clear":"Center-module_clear__jJEap","selfClear-left":"Center-module_selfClear-left__39q7E","selfClear-right":"Center-module_selfClear-right__1T_fm","selfClear-both":"Center-module_selfClear-both__2WDEC","inner-xxs":"Center-module_inner-xxs__1oroz","inner-xs":"Center-module_inner-xs__3FRT8","inner-sm":"Center-module_inner-sm__-oQ0E","align-left":"Center-module_align-left__1rYBX","align-right":"Center-module_align-right__1uglq","inner-left":"Center-module_inner-left__2z9Ea","inner-right":"Center-module_inner-right__KBkVt","sideBySide":"Center-module_sideBySide__-YsP0","inner-md":"Center-module_inner-md__3dLC3","inner-lg":"Center-module_inner-lg__2GQbs","inner-xl":"Center-module_inner-xl__3dOME"};
1587
+
1588
+ var _jsxFileName$c = "/home/tfischbach/code/pageflow/entry_types/scrolled/package/src/frontend/layouts/Center.js";
1589
+ const floatedPositions = ['left', 'right'];
1590
+ function Center(props) {
1591
+ const groups = groupItems(props.items);
1592
+ return /*#__PURE__*/React.createElement("div", {
1593
+ className: classNames(styles$5.root, {
1594
+ [styles$5.constrainContentWidth]: props.constrainContentWidth
1595
+ }),
1596
+ __self: this,
1597
+ __source: {
1598
+ fileName: _jsxFileName$c,
1599
+ lineNumber: 17,
1600
+ columnNumber: 5
1601
+ }
1602
+ }, /*#__PURE__*/React.createElement("div", {
1603
+ ref: props.contentAreaRef,
1604
+ __self: this,
1605
+ __source: {
1606
+ fileName: _jsxFileName$c,
1607
+ lineNumber: 19,
1608
+ columnNumber: 7
1609
+ }
1610
+ }), groups.map((group, groupIndex) => {
1611
+ return /*#__PURE__*/React.createElement("div", {
1612
+ key: groupIndex,
1613
+ className: classNames(styles$5.outer, styles$5[`outer-${widthName(group.width)}`], {
1614
+ [styles$5.customMargin]: group.customMargin
1615
+ }),
1616
+ __self: this,
1617
+ __source: {
1618
+ fileName: _jsxFileName$c,
1619
+ lineNumber: 23,
1620
+ columnNumber: 11
1621
+ }
1622
+ }, /*#__PURE__*/React.createElement("div", {
1623
+ className: classNames(styles$5.box, styles$5[`box-${widthName(group.width)}`]),
1624
+ __self: this,
1625
+ __source: {
1626
+ fileName: _jsxFileName$c,
1627
+ lineNumber: 27,
1628
+ columnNumber: 13
1629
+ }
1630
+ }, props.children( /*#__PURE__*/React.createElement(ContentElements, {
1631
+ sectionProps: props.sectionProps,
1632
+ items: group.items,
1633
+ customMargin: group.customMargin,
1634
+ __self: this,
1635
+ __source: {
1636
+ fileName: _jsxFileName$c,
1637
+ lineNumber: 30,
1638
+ columnNumber: 17
1639
+ }
1640
+ }, (item, child, itemIndex) => {
1641
+ const alignment = getWidth(item) < 0 && item.position === 'inline' ? item.alignment : null;
1642
+ return /*#__PURE__*/React.createElement("div", {
1643
+ key: item.id,
1644
+ className: classNames(styles$5[`selfClear-${selfClear(group.items, itemIndex)}`]),
1645
+ __self: this,
1646
+ __source: {
1647
+ fileName: _jsxFileName$c,
1648
+ lineNumber: 37,
1649
+ columnNumber: 23
1650
+ }
1651
+ }, /*#__PURE__*/React.createElement("div", {
1652
+ className: classNames(styles$5[`inner-${item.position}`], styles$5[`inner-${widthName(item.width)}`], styles$5[`align-${alignment}`], {
1653
+ [styles$5.clear]: clearItem(group.items, itemIndex)
1654
+ }, {
1655
+ [styles$5[`sideBySide`]]: sideBySideFloat(group.items, itemIndex)
1656
+ }),
1657
+ __self: this,
1658
+ __source: {
1659
+ fileName: _jsxFileName$c,
1660
+ lineNumber: 39,
1661
+ columnNumber: 25
1662
+ }
1663
+ }, child));
1664
+ }), boxProps(groups, groupIndex, props.isContentPadded))));
1665
+ }), renderPlaceholder$1(props.placeholder));
1666
+ }
1667
+ function groupItems(items) {
1668
+ const groups = [];
1669
+ let currentGroup;
1670
+ items.forEach(item => {
1671
+ var _item$props;
1672
+ const width = isFloated(item) ? widths.md : groupWidth(item);
1673
+ const customMargin = hasCustomMargin(item);
1674
+ if (!currentGroup || currentGroup.width !== width || currentGroup.customMargin !== customMargin) {
1675
+ currentGroup = {
1676
+ items: [],
1677
+ position: 'inline',
1678
+ width,
1679
+ customMargin
1680
+ };
1681
+ groups.push(currentGroup);
1682
+ }
1683
+ currentGroup.items.push({
1684
+ ...item,
1685
+ marginBottom: (_item$props = item.props) === null || _item$props === void 0 ? void 0 : _item$props.marginBottom
1686
+ });
1687
+ });
1688
+ return groups;
1689
+ }
1690
+ function boxProps(groups, index, isContentPadded) {
1691
+ const group = groups[index];
1692
+ const lastItem = group.items[group.items.length - 1];
1693
+ return {
1694
+ position: group.position,
1695
+ width: group.width,
1696
+ customMargin: group.customMargin,
1697
+ lastMarginBottom: lastItem.marginBottom,
1698
+ atSectionStart: index === 0 && !isContentPadded,
1699
+ atSectionEnd: index === groups.length - 1
1700
+ };
1701
+ }
1702
+ function selfClear(items, index) {
1703
+ const item = items[index];
1704
+ const next = items[index + 1];
1705
+ if (supportsWrappingAroundFloats(item) || isFloated(item) && (!next || clearItem(items, index + 1))) {
1706
+ return 'both';
1707
+ } else if (isFloated(item)) {
1708
+ return item.position === 'left' ? 'right' : 'left';
1709
+ }
1710
+ return 'none';
1711
+ }
1712
+ function clearItem(items, index) {
1713
+ return supportsWrappingAroundFloats(items[index]) ? followsSideBySideElements(items, index) : !isFloatedFollowingOppositeFloated(items, index);
1714
+ }
1715
+ function followsSideBySideElements(items, index) {
1716
+ return index > 1 && (items[index - 1].position === 'left' && items[index - 2].position === 'right' || items[index - 1].position === 'right' && items[index - 2].position === 'left');
1717
+ }
1718
+ function sideBySideFloat(items, index) {
1719
+ return isFloatedFollowingOppositeFloated(items, index) || isFloatedFollowedByOppositeFloated(items, index);
1720
+ }
1721
+ function isFloatedFollowingOppositeFloated(items, index) {
1722
+ return index > 0 && isFloated(items[index]) && isFloated(items[index - 1]) && items[index].position !== items[index - 1].position;
1723
+ }
1724
+ function isFloatedFollowedByOppositeFloated(items, index) {
1725
+ return index < items.length - 1 && isFloated(items[index]) && isFloated(items[index + 1]) && items[index].position !== items[index + 1].position;
1726
+ }
1727
+ function isFloated(item) {
1728
+ return floatedPositions.includes(item.position);
1729
+ }
1730
+ function supportsWrappingAroundFloats(item) {
1731
+ const {
1732
+ supportsWrappingAroundFloats
1733
+ } = api.contentElementTypes.getOptions(item.type);
1734
+ return supportsWrappingAroundFloats;
1735
+ }
1736
+ function hasCustomMargin(item) {
1737
+ const position = item.position;
1738
+ let {
1739
+ customMargin: elementSupportsCustomMargin
1740
+ } = api.contentElementTypes.getOptions(item.type) || {};
1741
+ if (typeof elementSupportsCustomMargin === 'function') {
1742
+ elementSupportsCustomMargin = elementSupportsCustomMargin({
1743
+ configuration: item.props
1744
+ });
1745
+ }
1746
+ return !!(elementSupportsCustomMargin && position === 'inline' && getWidth(item) < widths.full);
1747
+ }
1748
+ function groupWidth(item) {
1749
+ return Math.max(getWidth(item), widths.md);
1750
+ }
1751
+ function getWidth(item) {
1752
+ return item.width || widths.md;
1753
+ }
1754
+ function renderPlaceholder$1(placeholder) {
1755
+ if (!placeholder) {
1756
+ return null;
1757
+ }
1758
+ return /*#__PURE__*/React.createElement("div", {
1759
+ className: classNames(styles$5.outer),
1760
+ __self: this,
1761
+ __source: {
1762
+ fileName: _jsxFileName$c,
1763
+ lineNumber: 183,
1764
+ columnNumber: 5
1765
+ }
1766
+ }, /*#__PURE__*/React.createElement("div", {
1767
+ className: classNames(styles$5.item),
1768
+ __self: this,
1769
+ __source: {
1770
+ fileName: _jsxFileName$c,
1771
+ lineNumber: 184,
1772
+ columnNumber: 7
1773
+ }
1774
+ }, placeholder));
1775
+ }
1776
+
1777
+ var _jsxFileName$d = "/home/tfischbach/code/pageflow/entry_types/scrolled/package/src/frontend/layouts/index.js";
1778
+ const Layout = React.memo(extensible('LayoutWithPlaceholder', LayoutWithoutInlineEditing), (prevProps, nextProps) => prevProps.sectionId === nextProps.sectionId && prevProps.items === nextProps.items && prevProps.appearance === nextProps.appearance && prevProps.contentAreaRef === nextProps.contentAreaRef && prevProps.sectionProps === nextProps.sectionProps && prevProps.isContentPadded === nextProps.isContentPadded && prevProps.constrainContentWidth === nextProps.constrainContentWidth);
1779
+ function LayoutWithoutInlineEditing(props) {
1780
+ if (props.sectionProps.layout === 'center' || props.sectionProps.layout === 'centerRagged') {
1781
+ return /*#__PURE__*/React.createElement(Center, Object.assign({}, props, {
1782
+ __self: this,
1783
+ __source: {
1784
+ fileName: _jsxFileName$d,
1785
+ lineNumber: 26,
1786
+ columnNumber: 13
1787
+ }
1788
+ }));
1789
+ } else if (props.sectionProps.layout === 'right') {
1790
+ return /*#__PURE__*/React.createElement(TwoColumn, Object.assign({
1791
+ align: "right"
1792
+ }, props, {
1793
+ __self: this,
1794
+ __source: {
1795
+ fileName: _jsxFileName$d,
1796
+ lineNumber: 29,
1797
+ columnNumber: 13
1798
+ }
1799
+ }));
1800
+ } else {
1801
+ return /*#__PURE__*/React.createElement(TwoColumn, Object.assign({}, props, {
1802
+ __self: this,
1803
+ __source: {
1804
+ fileName: _jsxFileName$d,
1805
+ lineNumber: 32,
1806
+ columnNumber: 13
1807
+ }
1808
+ }));
1809
+ }
1810
+ }
1811
+ Layout.defaultProps = {
1812
+ layout: 'left'
1813
+ };
1814
+
1815
+ function scrollToElement(element, {
1816
+ align,
1817
+ ifNeeded,
1818
+ behavior
1819
+ } = {}) {
1820
+ const rect = element.getBoundingClientRect();
1821
+ if (ifNeeded && isInViewport(align, rect)) {
1822
+ return;
1823
+ }
1824
+ window.scrollTo({
1825
+ top: rect.top + window.scrollY + getAlignOffset(align, rect),
1826
+ behavior: behavior || 'smooth'
1827
+ });
1828
+ }
1829
+ function getAlignOffset(align, rect) {
1830
+ if (align === 'start') {
1831
+ return 0;
1832
+ } else if (align === 'center') {
1833
+ return (rect.height - window.innerHeight) / 2;
1834
+ } else if (align === 'nearEnd') {
1835
+ return rect.height - window.innerHeight * 0.75;
1836
+ } else {
1837
+ return -window.innerHeight * 0.25;
1838
+ }
1839
+ }
1840
+ function isInViewport(align, rect) {
1841
+ if (align === 'nearEnd') {
1842
+ const bottom = rect.top + rect.height;
1843
+ return bottom > 0 && bottom <= window.innerHeight;
1844
+ } else {
1845
+ return rect.top >= 0 && rect.top < window.innerHeight;
1846
+ }
1847
+ }
1848
+
1849
+ var _jsxFileName$e = "/home/tfischbach/code/pageflow/entry_types/scrolled/package/src/frontend/useScrollTarget.js";
1850
+ const ScrollTargetEmitterContext = createContext();
1851
+ function ScrollTargetEmitterProvider({
1852
+ children
1853
+ }) {
1854
+ const emitter = useMemo(() => Object.assign({}, BackboneEvents), []);
1855
+ return /*#__PURE__*/React.createElement(ScrollTargetEmitterContext.Provider, {
1856
+ value: emitter,
1857
+ __self: this,
1858
+ __source: {
1859
+ fileName: _jsxFileName$e,
1860
+ lineNumber: 12,
1861
+ columnNumber: 5
1862
+ }
1863
+ }, children);
1864
+ }
1865
+ function useScrollToTarget() {
1866
+ const emitter = useContext(ScrollTargetEmitterContext);
1867
+ return useCallback(({
1868
+ id,
1869
+ align,
1870
+ ifNeeded,
1871
+ behavior
1872
+ }) => {
1873
+ emitter.trigger(id, {
1874
+ align,
1875
+ ifNeeded,
1876
+ behavior
1877
+ });
1878
+ }, [emitter]);
1879
+ }
1880
+ function useScrollTarget(id) {
1881
+ const ref = useRef();
1882
+ const emitter = useContext(ScrollTargetEmitterContext);
1883
+ useEffect(() => {
1884
+ const handler = options => {
1885
+ if (ref.current) {
1886
+ scrollToElement(ref.current, options);
1887
+ }
1888
+ };
1889
+ emitter.on(id, handler);
1890
+ return () => emitter.off(id, handler);
1891
+ }, [id, emitter]);
1892
+ return ref;
1893
+ }
1894
+
1895
+ var _jsxFileName$f = "/home/tfischbach/code/pageflow/entry_types/scrolled/package/src/frontend/backgroundColor.js";
1896
+ const DarkBackgroundContext = createContext(true);
1897
+ function BackgroundColorProvider({
1898
+ dark,
1899
+ invert,
1900
+ children
1901
+ }) {
1902
+ const previousValue = useDarkBackground();
1903
+ return /*#__PURE__*/React.createElement(DarkBackgroundContext.Provider, {
1904
+ value: getValue({
1905
+ dark,
1906
+ invert,
1907
+ previousValue
1908
+ }),
1909
+ __self: this,
1910
+ __source: {
1911
+ fileName: _jsxFileName$f,
1912
+ lineNumber: 9,
1913
+ columnNumber: 5
1914
+ }
1915
+ }, children);
1916
+ }
1917
+ function getValue({
1918
+ dark,
1919
+ invert,
1920
+ previousValue
1921
+ }) {
1922
+ if (dark !== undefined) {
1923
+ return dark;
1924
+ } else if (invert === true) {
1925
+ return !previousValue;
1926
+ } else {
1927
+ return previousValue;
1928
+ }
1929
+ }
1930
+
1931
+ /**
1932
+ * Use to invert elements depending on whether they are rendered on a
1933
+ * dark or light background to ensure correct display in inverted
1934
+ * sections or in sections with card appearance.
1935
+ *
1936
+ * @return {boolean}
1937
+ */
1938
+ function useDarkBackground() {
1939
+ return useContext(DarkBackgroundContext);
1940
+ }
1941
+
1942
+ var _jsxFileName$g = "/home/tfischbach/code/pageflow/entry_types/scrolled/package/src/frontend/useActiveExcursion.js";
1943
+ const ActiveExcursionContext = createContext({
1944
+ activeExcursion: undefined,
1945
+ activateExcursionOfSection: () => {},
1946
+ returnFromExcursion: () => {}
1947
+ });
1948
+ function ActiveExcursionProvider({
1949
+ children
1950
+ }) {
1951
+ const entryStructure = useEntryStructure();
1952
+ const scrollToTarget = useScrollToTarget();
1953
+ const [activeExcursionId, setActiveExcursionId] = useState();
1954
+ const [scrollTarget, setScrollTarget] = useState();
1955
+ const returnUrlRef = useRef(null);
1956
+ useEffect(() => {
1957
+ function handleHashChange(event) {
1958
+ const hash = window.__ACTIVE_EXCURSION__ ||
1959
+ // Used in Storybook
1960
+ window.location.hash.slice(1);
1961
+ const {
1962
+ excursion,
1963
+ sectionId
1964
+ } = findScrollTargetByHash(hash);
1965
+ if (excursion && (event === null || event === void 0 ? void 0 : event.oldURL) && !returnUrlRef.current) {
1966
+ returnUrlRef.current = event.oldURL;
1967
+ }
1968
+ setActiveExcursionId(prevExcursionId => {
1969
+ const excursionChanged = (excursion === null || excursion === void 0 ? void 0 : excursion.id) !== prevExcursionId;
1970
+ if (excursionChanged && sectionId) {
1971
+ setScrollTarget(sectionId);
1972
+ }
1973
+ return excursion === null || excursion === void 0 ? void 0 : excursion.id;
1974
+ });
1975
+ }
1976
+ function findScrollTargetByHash(hash) {
1977
+ if (hash.startsWith('section-')) {
1978
+ const permaId = parseInt(hash.replace('section-', ''), 10);
1979
+ for (const chapter of entryStructure.excursions) {
1980
+ const section = chapter.sections.find(s => s.permaId === permaId);
1981
+ if (section) {
1982
+ var _chapter$sections$;
1983
+ const isFirstSection = section.id === ((_chapter$sections$ = chapter.sections[0]) === null || _chapter$sections$ === void 0 ? void 0 : _chapter$sections$.id);
1984
+ return {
1985
+ excursion: chapter,
1986
+ sectionId: isFirstSection ? null : section.id
1987
+ };
1988
+ }
1989
+ }
1990
+ for (const chapter of entryStructure.main) {
1991
+ const section = chapter.sections.find(s => s.permaId === permaId);
1992
+ if (section) {
1993
+ return {
1994
+ excursion: null,
1995
+ sectionId: section.id
1996
+ };
1997
+ }
1998
+ }
1999
+ return {
2000
+ excursion: null,
2001
+ sectionId: null
2002
+ };
2003
+ }
2004
+ const excursion = entryStructure.excursions.find(chapter => chapter.chapterSlug === hash);
2005
+ if (excursion) {
2006
+ return {
2007
+ excursion,
2008
+ sectionId: null
2009
+ };
2010
+ }
2011
+ const mainChapter = entryStructure.main.find(chapter => chapter.chapterSlug === hash);
2012
+ if (mainChapter) {
2013
+ var _mainChapter$sections;
2014
+ return {
2015
+ excursion: null,
2016
+ sectionId: (_mainChapter$sections = mainChapter.sections[0]) === null || _mainChapter$sections === void 0 ? void 0 : _mainChapter$sections.id
2017
+ };
2018
+ }
2019
+ return {
2020
+ excursion: null,
2021
+ sectionId: null
2022
+ };
2023
+ }
2024
+ handleHashChange();
2025
+ window.addEventListener('hashchange', handleHashChange);
2026
+ return () => window.removeEventListener('hashchange', handleHashChange);
2027
+ }, [entryStructure]);
2028
+ useEffect(() => {
2029
+ if (!scrollTarget) {
2030
+ return;
2031
+ }
2032
+ setTimeout(() => {
2033
+ scrollToTarget({
2034
+ id: scrollTarget
2035
+ });
2036
+ }, 500);
2037
+ setScrollTarget(null);
2038
+ }, [scrollTarget, scrollToTarget]);
2039
+ const activateExcursionOfSection = useCallback(({
2040
+ id
2041
+ }) => {
2042
+ const excursion = entryStructure.excursions.find(chapter => chapter.sections.find(section => section.id === id));
2043
+ if (excursion) {
2044
+ returnUrlRef.current = returnUrlRef.current || window.location.href;
2045
+ window.history.replaceState(null, null, '#' + excursion.chapterSlug);
2046
+ }
2047
+ setActiveExcursionId(excursion === null || excursion === void 0 ? void 0 : excursion.id);
2048
+ }, [entryStructure]);
2049
+ const returnFromExcursion = useCallback(() => {
2050
+ setActiveExcursionId(undefined);
2051
+ if (returnUrlRef.current) {
2052
+ window.history.replaceState(null, null, returnUrlRef.current);
2053
+ returnUrlRef.current = null;
2054
+ }
2055
+ }, []);
2056
+ const activeExcursion = useMemo(() => {
2057
+ return entryStructure.excursions.find(excursion => excursion.id === activeExcursionId);
2058
+ }, [entryStructure, activeExcursionId]);
2059
+ const value = useMemo(() => ({
2060
+ activeExcursion,
2061
+ activateExcursionOfSection,
2062
+ returnFromExcursion
2063
+ }), [activeExcursion, activateExcursionOfSection, returnFromExcursion]);
2064
+ return /*#__PURE__*/React.createElement(ActiveExcursionContext.Provider, {
2065
+ value: value,
2066
+ __self: this,
2067
+ __source: {
2068
+ fileName: _jsxFileName$g,
2069
+ lineNumber: 132,
2070
+ columnNumber: 5
2071
+ }
2072
+ }, children);
2073
+ }
2074
+ function useActiveExcursion() {
2075
+ return useContext(ActiveExcursionContext);
2076
+ }
2077
+
2078
+ function camelize(snakeCase) {
2079
+ return snakeCase.replace(/[_-][a-z]/g, function (match) {
2080
+ return match[1].toUpperCase();
2081
+ });
2082
+ }
2083
+
2084
+ /**
2085
+ * Resolve a palette color to a CSS custom property.
2086
+ *
2087
+ * @example
2088
+ * <div style={{backgroundColor: paletteColor(configuration.backgroundColor)}}>
2089
+ */
2090
+ function paletteColor(value) {
2091
+ if (!value) {
2092
+ return undefined;
2093
+ }
2094
+ if (value[0] === '#') {
2095
+ return value;
2096
+ }
2097
+ return `var(--theme-palette-color-${value})`;
2098
+ }
2099
+
2100
+ var textStyles = {"text-2xs":"16px","text-xs":"18px","text-s":"20px","text-base":"22px","text-md":"33px","text-l":"40px","text-2l":"50px","text-xl":"66px","text-2xl":"88px","text-3xl":"110px","text-4xl":"200px","text-5xl":"350px","heading-lg":"Text-module_heading-lg__FKxzu typography-headingLg typography-heading","heading-md":"Text-module_heading-md__1q5Ss typography-headingMd typography-heading","heading-sm":"Text-module_heading-sm__2awaz typography-headingSm typography-heading","heading-xs":"Text-module_heading-xs__21nHy typography-headingXs typography-heading","headingTagline-lg":"Text-module_headingTagline-lg__1O2TQ typography-headingTaglineLg typography-headingTagline","headingTagline-md":"Text-module_headingTagline-md__2hrVS typography-headingTaglineMd typography-headingTagline","headingTagline-sm":"Text-module_headingTagline-sm__1Fw2J typography-headingTaglineSm typography-headingTagline","headingSubtitle-lg":"Text-module_headingSubtitle-lg__15kj0 typography-headingSubtitleLg typography-headingSubtitle","headingSubtitle-md":"Text-module_headingSubtitle-md__2_qtz typography-headingSubtitleMd typography-headingSubtitle","headingSubtitle-sm":"Text-module_headingSubtitle-sm__MOc_6 typography-headingSubtitleSm typography-headingSubtitle","body":"Text-module_body__4oWD- typography-body","caption":"Text-module_caption__3_6Au typography-caption","question":"Text-module_question__ByVAq typography-question","questionAnswer":"Text-module_questionAnswer__2Hdmc typography-questionAnswer","quoteText-lg":"Text-module_quoteText-lg__3ZnZi typography-quoteText typography-quoteTextLg","quoteText-md":"Text-module_quoteText-md__2eooO typography-quoteText typography-quoteTextMd","quoteText-sm":"Text-module_quoteText-sm__5nKex typography-quoteText typography-quoteTextSm","quoteText-xs":"Text-module_quoteText-xs__2p5on typography-quoteText typography-quoteTextXs","quoteAttribution":"Text-module_quoteAttribution__VBqLw typography-quoteAttribution","quoteAttribution-lg":"Text-module_quoteAttribution-lg__23pl- Text-module_quoteAttribution__VBqLw typography-quoteAttribution typography-quoteAttributionLg","quoteAttribution-md":"Text-module_quoteAttribution-md__2BnBN Text-module_quoteAttribution__VBqLw typography-quoteAttribution typography-quoteAttributionMd","quoteAttribution-sm":"Text-module_quoteAttribution-sm__17vbI Text-module_quoteAttribution__VBqLw typography-quoteAttribution typography-quoteAttributionSm","quoteAttribution-xs":"Text-module_quoteAttribution-xs__3v3BW Text-module_quoteAttribution__VBqLw typography-quoteAttribution typography-quoteAttributionXs","counterNumber":"Text-module_counterNumber__DkyhC typography-counterNumber","counterUnit":"Text-module_counterUnit__1N5v7 typography-counterUnit","counterDescription":"Text-module_counterDescription__34NjQ typography-counterDescription","hotspotsTooltipTitle":"Text-module_hotspotsTooltipTitle__2KROf typography-hotspotTooltipTitle","hotspotsTooltipDescription":"Text-module_hotspotsTooltipDescription__2l9v5 typography-hotspotTooltipDescription","hotspotsTooltipLink":"Text-module_hotspotsTooltipLink__2F2aj typography-hotspotTooltipLink typography-linkButton","teaserTitle-lg":"Text-module_teaserTitle-lg__K3MFG typography-externalLinkTitle typography-externalLinkTitleLg","teaserTitle-md":"Text-module_teaserTitle-md__tBZIn typography-externalLinkTitle typography-externalLinkTitleMd","teaserTitle-sm":"Text-module_teaserTitle-sm__ZXQCr typography-externalLinkTitle typography-externalLinkTitleSm","teaserTagline-lg":"Text-module_teaserTagline-lg__8JW7Z typography-externalLinkTagline typography-externalLinkTaglineLg","teaserTagline-md":"Text-module_teaserTagline-md__45HLL typography-externalLinkTagline typography-externalLinkTaglineMd","teaserTagline-sm":"Text-module_teaserTagline-sm__1vzOr typography-externalLinkTagline typography-externalLinkTaglineSm","teaserDescription-lg":"Text-module_teaserDescription-lg__1ysIZ typography-externalLinkDescription","teaserDescription-md":"Text-module_teaserDescription-md__1JtRs typography-externalLinkDescription","teaserDescription-sm":"Text-module_teaserDescription-sm__2VRao typography-externalLinkDescription","teaserLink":"Text-module_teaserLink__XEWHU typography-teaserLink typography-linkButton","infoTableLabel":"Text-module_infoTableLabel__w9kbv typography-infoTableLabel","infoTableValue":"Text-module_infoTableValue__2elOY typography-infoTableValue"};
2101
+
2102
+ /**
2103
+ * Render some text using the default typography scale.
2104
+ *
2105
+ * @param {Object} props
2106
+ * @param {string} props.scaleCategory -
2107
+ * One of the styles `'heading-lg'`, `'heading-md'`, `'heading-sm'`,`'heading-xs'`,
2108
+ * `'headingTagline-lg'`, `'headingTagline-md'`, `'headingTagline-sm'`,
2109
+ * `'headingSubtitle-lg'`, `'headingSubtitle-md'`, `'headingSubtitle-sm'`,
2110
+ * `'body'`, `'caption'`, `'question'`, `'questionAnswer'`,
2111
+ * `'quoteText-lg'`, `'quoteText-md'`, `'quoteText-sm'`, `'quoteText-xs'`, `'quoteAttribution'`,
2112
+ * `'counterNumber'`, `'counterUnit'`, `'counterDescription'`,
2113
+ * `'infoTableLabel'`, `'infoTableValue`'.
2114
+ * `'hotspotsTooltipTitle'`, `'hotspotsTooltipDescription`', `'hotspotsTooltipLink`',
2115
+ * `'teaserTitle-lg'`, `'teaserTitle-md'`, `'teaserTitle-sm'`,
2116
+ * `'teaserTagline-lg'`, `'teaserTagline-md'`, `'teaserTagline-sm'`,
2117
+ * `'teaserDescription-lg'`, `'teaserDescription-md'`, `'teaserDescription-sm'`,
2118
+ * `'teaserLink'`.
2119
+ * @param {string} [props.typographyVariant] - Suffix for variant class name.
2120
+ * @param {string} [props.typographySize] - Suffix for size class name.
2121
+ * @param {string} [props.inline] - Render a span instread of a div.
2122
+ * @param {string} props.children - Nodes to render with specified typography.
2123
+ */
2124
+ function Text({
2125
+ inline,
2126
+ scaleCategory,
2127
+ typographyVariant,
2128
+ typographySize,
2129
+ children
2130
+ }) {
2131
+ const variantClassName = typographyVariant && `typography-${scaleCategory.split('-')[0]}-${typographyVariant}`;
2132
+ const sizeClassName = typographySize && `typography-${scaleCategory}-${typographySize}`;
2133
+ return React.createElement(inline ? 'span' : 'div', {
2134
+ className: classNames(textStyles[scaleCategory], variantClassName, sizeClassName)
2135
+ }, children);
2136
+ }
2137
+ Text.propTypes = {
2138
+ children: PropTypes.node.isRequired,
2139
+ inline: PropTypes.bool,
2140
+ typographyVariant: PropTypes.string,
2141
+ typographySize: PropTypes.string,
2142
+ scaleCategory: PropTypes.oneOf(['heading-lg', 'heading-md', 'heading-sm', 'heading-xs', 'headingTagline-lg', 'headingTagline-md', 'headingTagline-sm', 'headingSubtitle-lg', 'headingSubtitle-md', 'headingSubtitle-sm', 'quoteText-lg', 'quoteText-md', 'quoteText-sm', 'quoteText-xs', 'quoteAttribution-lg', 'quoteAttribution-md', 'quoteAttribution-sm', 'quoteAttribution-xs', 'hotspotsTooltipTitle', 'hotspotsTooltipDescription', 'hotspotsTooltipLink', 'teaserTitle-lg', 'teaserTitle-md', 'teaserTitle-sm', 'teaserTagline-lg', 'teaserTagline-md', 'teaserTagline-sm', 'teaserDescription-lg', 'teaserDescription-md', 'teaserDescription-sm', 'teaserLink', 'counterNumber', 'counterUnit', 'counterDescription', 'infoTableLabel', 'infoTableValue', 'body', 'caption', 'question', 'questionAnswer'])
2143
+ };
2144
+
2145
+ var _jsxFileName$h = "/home/tfischbach/code/pageflow/entry_types/scrolled/package/src/frontend/Link.js";
2146
+ function Link({
2147
+ attributes,
2148
+ children,
2149
+ href,
2150
+ openInNewTab
2151
+ }) {
2152
+ const embedOriginUrl = useEmbedOriginUrl();
2153
+ if (href === null || href === void 0 ? void 0 : href.chapter) {
2154
+ return /*#__PURE__*/React.createElement(ChapterLink, {
2155
+ attributes: attributes,
2156
+ chapterPermaId: href.chapter,
2157
+ __self: this,
2158
+ __source: {
2159
+ fileName: _jsxFileName$h,
2160
+ lineNumber: 10,
2161
+ columnNumber: 7
2162
+ }
2163
+ }, children);
2164
+ } else if (href === null || href === void 0 ? void 0 : href.section) {
2165
+ return /*#__PURE__*/React.createElement("a", Object.assign({}, attributes, {
2166
+ href: `#section-${href.section}`,
2167
+ __self: this,
2168
+ __source: {
2169
+ fileName: _jsxFileName$h,
2170
+ lineNumber: 17,
2171
+ columnNumber: 12
2172
+ }
2173
+ }), children);
2174
+ }
2175
+ if (href === null || href === void 0 ? void 0 : href.file) {
2176
+ return /*#__PURE__*/React.createElement(FileLink, {
2177
+ attributes: attributes,
2178
+ fileOptions: href.file,
2179
+ __self: this,
2180
+ __source: {
2181
+ fileName: _jsxFileName$h,
2182
+ lineNumber: 24,
2183
+ columnNumber: 7
2184
+ }
2185
+ }, children);
2186
+ } else {
2187
+ const targetAttributes = getTargetAttributes({
2188
+ href,
2189
+ openInNewTab,
2190
+ embedOriginUrl
2191
+ });
2192
+ return /*#__PURE__*/React.createElement("a", Object.assign({}, attributes, targetAttributes, {
2193
+ href: href,
2194
+ __self: this,
2195
+ __source: {
2196
+ fileName: _jsxFileName$h,
2197
+ lineNumber: 33,
2198
+ columnNumber: 12
2199
+ }
2200
+ }), children);
2201
+ }
2202
+ }
2203
+ function ChapterLink({
2204
+ attributes,
2205
+ children,
2206
+ chapterPermaId
2207
+ }) {
2208
+ const chapter = useChapter({
2209
+ permaId: chapterPermaId
2210
+ });
2211
+ return /*#__PURE__*/React.createElement("a", Object.assign({}, attributes, {
2212
+ href: `#${(chapter === null || chapter === void 0 ? void 0 : chapter.chapterSlug) || ''}`,
2213
+ __self: this,
2214
+ __source: {
2215
+ fileName: _jsxFileName$h,
2216
+ lineNumber: 44,
2217
+ columnNumber: 10
2218
+ }
2219
+ }), children);
2220
+ }
2221
+ function FileLink({
2222
+ attributes,
2223
+ children,
2224
+ fileOptions
2225
+ }) {
2226
+ const file = useDownloadableFile(fileOptions);
2227
+ return /*#__PURE__*/React.createElement("a", Object.assign({}, attributes, {
2228
+ target: "_blank",
2229
+ rel: "noopener noreferrer",
2230
+ href: file === null || file === void 0 ? void 0 : file.urls.download,
2231
+ __self: this,
2232
+ __source: {
2233
+ fileName: _jsxFileName$h,
2234
+ lineNumber: 53,
2235
+ columnNumber: 10
2236
+ }
2237
+ }), children);
2238
+ }
2239
+ function getTargetAttributes({
2240
+ href,
2241
+ openInNewTab,
2242
+ embedOriginUrl
2243
+ }) {
2244
+ if (openInNewTab) {
2245
+ return {
2246
+ target: '_blank',
2247
+ rel: 'noopener noreferrer'
2248
+ };
2249
+ }
2250
+ if (embedOriginUrl && typeof href === 'string' && !href.startsWith('#') && !href.startsWith(embedOriginUrl)) {
2251
+ return {
2252
+ target: '_top'
2253
+ };
2254
+ }
2255
+ return {};
2256
+ }
2257
+
2258
+ var textStyles$1 = {"darkContentTextColor":"var(--theme-dark-content-text-color, #222)","lightContentTextColor":"var(--theme-light-content-text-color, #fff)","contentLinkColor":"var(--content-link-color)","root":"EditableText-module_root__2v1tU","justify":"EditableText-module_justify__1pNdv","light":"EditableText-module_light__2c29h","dark":"EditableText-module_dark__2ym90","link":"EditableText-module_link__3vDbl typography-contentLink","bold":"EditableText-module_bold__tGw26","sub":"EditableText-module_sub__pNBwN","sup":"EditableText-module_sup__RJJlq"};
2259
+
2260
+ var _jsxFileName$i = "/home/tfischbach/code/pageflow/entry_types/scrolled/package/src/frontend/EditableText.js";
2261
+ const defaultValue = [{
2262
+ type: 'paragraph',
2263
+ children: [{
2264
+ text: ''
2265
+ }]
2266
+ }];
2267
+ function PlainEditableText({
2268
+ value,
2269
+ className,
2270
+ scaleCategory = 'body',
2271
+ typographyVariant,
2272
+ typographySize
2273
+ }) {
2274
+ return /*#__PURE__*/React.createElement("div", {
2275
+ className: classNames(textStyles$1.root, className),
2276
+ __self: this,
2277
+ __source: {
2278
+ fileName: _jsxFileName$i,
2279
+ lineNumber: 23,
2280
+ columnNumber: 5
2281
+ }
2282
+ }, /*#__PURE__*/React.createElement(Text, {
2283
+ scaleCategory: scaleCategory,
2284
+ typographyVariant: typographyVariant,
2285
+ typographySize: typographySize,
2286
+ __self: this,
2287
+ __source: {
2288
+ fileName: _jsxFileName$i,
2289
+ lineNumber: 24,
2290
+ columnNumber: 7
2291
+ }
2292
+ }, render(value || defaultValue)));
2293
+ }
2294
+ const EditableText = extensible('EditableText', PlainEditableText);
2295
+ function render(children) {
2296
+ return children.map((element, index) => {
2297
+ if (element.type && element.children) {
2298
+ return renderElement({
2299
+ attributes: {
2300
+ key: index
2301
+ },
2302
+ element,
2303
+ children: render(element.children)
2304
+ });
2305
+ } else {
2306
+ return renderLeaf({
2307
+ attributes: {
2308
+ key: index
2309
+ },
2310
+ leaf: element,
2311
+ children: children.length === 1 && element.text.trim() === '' ? '\uFEFF' : element.text
2312
+ });
2313
+ }
2314
+ });
2315
+ }
2316
+ function renderElement({
2317
+ attributes,
2318
+ children,
2319
+ element
2320
+ }) {
2321
+ const variantClassName = element.variant && ['typography-textBlock', camelize(element.type), element.variant].join('-');
2322
+ const sizeClassName = element.size && ['typography-textBlock', camelize(element.type), element.size].join('-');
2323
+ const className = classNames(variantClassName, sizeClassName, {
2324
+ [textStyles$1.justify]: element.textAlign === 'justify'
2325
+ });
2326
+ const inlineStyles = {
2327
+ ...(element.color && {
2328
+ color: paletteColor(element.color)
2329
+ })
2330
+ };
2331
+ switch (element.type) {
2332
+ case 'block-quote':
2333
+ return /*#__PURE__*/React.createElement("blockquote", Object.assign({}, attributes, {
2334
+ className: className,
2335
+ style: inlineStyles,
2336
+ __self: this,
2337
+ __source: {
2338
+ fileName: _jsxFileName$i,
2339
+ lineNumber: 73,
2340
+ columnNumber: 7
2341
+ }
2342
+ }), children);
2343
+ case 'bulleted-list':
2344
+ return /*#__PURE__*/React.createElement("ul", Object.assign({}, attributes, {
2345
+ className: className,
2346
+ style: inlineStyles,
2347
+ __self: this,
2348
+ __source: {
2349
+ fileName: _jsxFileName$i,
2350
+ lineNumber: 81,
2351
+ columnNumber: 7
2352
+ }
2353
+ }), children);
2354
+ case 'numbered-list':
2355
+ return /*#__PURE__*/React.createElement("ol", Object.assign({}, attributes, {
2356
+ className: className,
2357
+ style: inlineStyles,
2358
+ __self: this,
2359
+ __source: {
2360
+ fileName: _jsxFileName$i,
2361
+ lineNumber: 89,
2362
+ columnNumber: 7
2363
+ }
2364
+ }), children);
2365
+ case 'list-item':
2366
+ return /*#__PURE__*/React.createElement("li", Object.assign({}, attributes, {
2367
+ __self: this,
2368
+ __source: {
2369
+ fileName: _jsxFileName$i,
2370
+ lineNumber: 96,
2371
+ columnNumber: 12
2372
+ }
2373
+ }), children);
2374
+ case 'heading':
2375
+ const {
2376
+ key,
2377
+ ...otherAttributes
2378
+ } = attributes;
2379
+ return /*#__PURE__*/React.createElement(Heading, {
2380
+ key: key,
2381
+ attributes: otherAttributes,
2382
+ className: className,
2383
+ inlineStyles: inlineStyles,
2384
+ __self: this,
2385
+ __source: {
2386
+ fileName: _jsxFileName$i,
2387
+ lineNumber: 101,
2388
+ columnNumber: 7
2389
+ }
2390
+ }, children);
2391
+ case 'link':
2392
+ return renderLink({
2393
+ attributes,
2394
+ children,
2395
+ element
2396
+ });
2397
+ default:
2398
+ return /*#__PURE__*/React.createElement("p", Object.assign({}, attributes, {
2399
+ className: className,
2400
+ style: inlineStyles,
2401
+ __self: this,
2402
+ __source: {
2403
+ fileName: _jsxFileName$i,
2404
+ lineNumber: 112,
2405
+ columnNumber: 7
2406
+ }
2407
+ }), children);
2408
+ }
2409
+ }
2410
+ function Heading({
2411
+ attributes,
2412
+ className,
2413
+ inlineStyles,
2414
+ children
2415
+ }) {
2416
+ const darkBackground = useDarkBackground();
2417
+ return /*#__PURE__*/React.createElement("h2", Object.assign({}, attributes, {
2418
+ className: classNames(className, darkBackground ? textStyles$1.light : textStyles$1.dark, 'scope-headings', textStyles['heading-xs']),
2419
+ style: inlineStyles,
2420
+ __self: this,
2421
+ __source: {
2422
+ fileName: _jsxFileName$i,
2423
+ lineNumber: 125,
2424
+ columnNumber: 5
2425
+ }
2426
+ }), children);
2427
+ }
2428
+ function renderLink({
2429
+ attributes,
2430
+ children,
2431
+ element
2432
+ }) {
2433
+ const {
2434
+ key,
2435
+ ...otherAttributes
2436
+ } = attributes;
2437
+ return /*#__PURE__*/React.createElement(Link, {
2438
+ key: key,
2439
+ attributes: {
2440
+ ...otherAttributes,
2441
+ className: textStyles$1.link
2442
+ },
2443
+ href: element.href,
2444
+ openInNewTab: element.openInNewTab,
2445
+ children: children,
2446
+ __self: this,
2447
+ __source: {
2448
+ fileName: _jsxFileName$i,
2449
+ lineNumber: 140,
2450
+ columnNumber: 5
2451
+ }
2452
+ });
2453
+ }
2454
+ function renderLeaf({
2455
+ attributes,
2456
+ children,
2457
+ leaf
2458
+ }) {
2459
+ if (leaf.bold) {
2460
+ children = /*#__PURE__*/React.createElement("strong", {
2461
+ className: textStyles$1.bold,
2462
+ __self: this,
2463
+ __source: {
2464
+ fileName: _jsxFileName$i,
2465
+ lineNumber: 150,
2466
+ columnNumber: 16
2467
+ }
2468
+ }, children);
2469
+ }
2470
+ if (leaf.italic) {
2471
+ children = /*#__PURE__*/React.createElement("em", {
2472
+ __self: this,
2473
+ __source: {
2474
+ fileName: _jsxFileName$i,
2475
+ lineNumber: 154,
2476
+ columnNumber: 16
2477
+ }
2478
+ }, children);
2479
+ }
2480
+ if (leaf.underline) {
2481
+ children = /*#__PURE__*/React.createElement("u", {
2482
+ __self: this,
2483
+ __source: {
2484
+ fileName: _jsxFileName$i,
2485
+ lineNumber: 158,
2486
+ columnNumber: 16
2487
+ }
2488
+ }, children);
2489
+ }
2490
+ if (leaf.strikethrough) {
2491
+ children = /*#__PURE__*/React.createElement("s", {
2492
+ __self: this,
2493
+ __source: {
2494
+ fileName: _jsxFileName$i,
2495
+ lineNumber: 162,
2496
+ columnNumber: 16
2497
+ }
2498
+ }, children);
2499
+ }
2500
+ if (leaf.sub) {
2501
+ children = /*#__PURE__*/React.createElement("sub", {
2502
+ className: textStyles$1.sub,
2503
+ __self: this,
2504
+ __source: {
2505
+ fileName: _jsxFileName$i,
2506
+ lineNumber: 166,
2507
+ columnNumber: 16
2508
+ }
2509
+ }, children);
2510
+ }
2511
+ if (leaf.sup) {
2512
+ children = /*#__PURE__*/React.createElement("sup", {
2513
+ className: textStyles$1.sup,
2514
+ __self: this,
2515
+ __source: {
2516
+ fileName: _jsxFileName$i,
2517
+ lineNumber: 170,
2518
+ columnNumber: 16
2519
+ }
2520
+ }, children);
2521
+ }
2522
+ return /*#__PURE__*/React.createElement("span", Object.assign({}, attributes, {
2523
+ __self: this,
2524
+ __source: {
2525
+ fileName: _jsxFileName$i,
2526
+ lineNumber: 173,
2527
+ columnNumber: 10
2528
+ }
2529
+ }), children);
2530
+ }
2531
+
2532
+ const FloatingPortalRootContext = createContext();
2533
+ function useFloatingPortalRoot() {
2534
+ return useContext(FloatingPortalRootContext);
2535
+ }
2536
+ const FloatingPortalRootProvider = FloatingPortalRootContext.Provider;
2537
+
2538
+ export { useScrollTarget as A, BackgroundColorProvider as B, ContentElementAttributesProvider as C, Layout as D, EditableText as E, FloatingPortalRootProvider as F, ExtensionsProvider as G, ActiveExcursionProvider as H, StaticPreview as I, camelize as J, renderLink as K, Link as L, MainStorylineCoverageProvider as M, renderLeaf as N, OnScreenObserverRootProvider as O, scrollToElement as P, LayoutWithoutInlineEditing as Q, renderElement as R, ScrollTargetEmitterProvider as S, Text as T, PlainEditableText as U, textStyles$1 as V, useActiveExcursion as a, MainStorylineActivity as b, useMainStorylineCoverage as c, api as d, extensible as e, useDarkBackground as f, useContentElementAttributes as g, useContentElementLifecycle as h, ContentElementLifecycleContext as i, useContentElementViewTimelineProgress as j, ContentElementViewTimelineContext as k, getViewTimelineProgress as l, useIsStaticPreview as m, useStorylineActivity as n, useFloatingPortalRoot as o, provideExtensions as p, paletteColor as q, widthName as r, useOnScreen as s, createScrollPositionLifecycleProvider as t, useScrollToTarget as u, createScrollPositionLifecycleHook as v, widths as w, useMediaQuery as x, TrimDefaultMarginTop as y, ContentElement as z };