pageflow 17.1.0 → 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 (302) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +319 -345
  3. data/README.md +3 -4
  4. data/admins/pageflow/accounts.rb +6 -6
  5. data/admins/pageflow/entry.rb +10 -8
  6. data/admins/pageflow/membership.rb +11 -11
  7. data/admins/pageflow/translations.rb +5 -5
  8. data/app/assets/images/pageflow/admin/icons/comment.svg +1 -0
  9. data/app/assets/javascripts/pageflow/dist/ui.js +1350 -630
  10. data/app/assets/javascripts/pageflow/editor/vendor.js +0 -1
  11. data/app/assets/javascripts/pageflow/ui.js +0 -1
  12. data/app/assets/stylesheets/pageflow/admin/entry_comments_indicator.scss +45 -0
  13. data/app/assets/stylesheets/pageflow/admin/permalink_input.scss +8 -1
  14. data/app/assets/stylesheets/pageflow/admin.scss +1 -0
  15. data/app/assets/stylesheets/pageflow/animations/spin.scss +9 -0
  16. data/app/assets/stylesheets/pageflow/animations.scss +1 -0
  17. data/app/assets/stylesheets/pageflow/editor/background_positioning.scss +21 -5
  18. data/app/assets/stylesheets/pageflow/editor/base.scss +9 -1
  19. data/app/assets/stylesheets/pageflow/editor/drop_down_button.scss +13 -1
  20. data/app/assets/stylesheets/pageflow/editor/edit_configuration_view.scss +5 -0
  21. data/app/assets/stylesheets/pageflow/editor/file_folders.scss +127 -0
  22. data/app/assets/stylesheets/pageflow/editor/file_meta_data.scss +0 -1
  23. data/app/assets/stylesheets/pageflow/editor/file_meta_data_overlay.scss +45 -0
  24. data/app/assets/stylesheets/pageflow/editor/file_preview.scss +138 -0
  25. data/app/assets/stylesheets/pageflow/editor/file_references.scss +68 -0
  26. data/app/assets/stylesheets/pageflow/editor/file_settings_dialog.scss +1 -1
  27. data/app/assets/stylesheets/pageflow/editor/file_stage_icons.scss +17 -0
  28. data/app/assets/stylesheets/pageflow/editor/file_stages.scss +25 -32
  29. data/app/assets/stylesheets/pageflow/editor/file_thumbnails.scss +31 -48
  30. data/app/assets/stylesheets/pageflow/editor/file_type_pills.scss +73 -0
  31. data/app/assets/stylesheets/pageflow/editor/files.scss +230 -50
  32. data/app/assets/stylesheets/pageflow/editor/filtered_files.scss +142 -14
  33. data/app/assets/stylesheets/pageflow/editor/folder_breadcrumb.scss +40 -0
  34. data/app/assets/stylesheets/pageflow/editor/info_box.scss +12 -0
  35. data/app/assets/stylesheets/pageflow/editor/inputs/edit_defaults_button.scss +15 -0
  36. data/app/assets/stylesheets/pageflow/editor/inputs.scss +1 -0
  37. data/app/assets/stylesheets/pageflow/editor/list.scss +88 -38
  38. data/app/assets/stylesheets/pageflow/editor/manage_files.scss +9 -0
  39. data/app/assets/stylesheets/pageflow/editor/menu.scss +14 -0
  40. data/app/assets/stylesheets/pageflow/editor/move_to_folder_dialog.scss +83 -0
  41. data/app/assets/stylesheets/pageflow/mixins/pageflow.scss +9 -5
  42. data/app/assets/stylesheets/pageflow/ui/color_picker.scss +230 -0
  43. data/app/assets/stylesheets/pageflow/ui/forms.scss +34 -4
  44. data/app/assets/stylesheets/pageflow/ui/functions.scss +12 -2
  45. data/app/assets/stylesheets/pageflow/ui/input/color_input.scss +9 -16
  46. data/app/assets/stylesheets/pageflow/ui/input/text_area_input.scss +15 -0
  47. data/app/assets/stylesheets/pageflow/ui/overrides.scss +8 -0
  48. data/app/assets/stylesheets/pageflow/ui/properties.scss +29 -0
  49. data/app/assets/stylesheets/pageflow/ui/tabs_view.scss +8 -3
  50. data/app/assets/stylesheets/pageflow/ui.scss +4 -2
  51. data/app/controllers/pageflow/editor/entries_controller.rb +1 -0
  52. data/app/controllers/pageflow/editor/file_folders_controller.rb +80 -0
  53. data/app/controllers/pageflow/editor/file_import_controller.rb +1 -0
  54. data/app/controllers/pageflow/editor/files_controller.rb +15 -6
  55. data/app/controllers/pageflow/editor/oembeds_controller.rb +21 -0
  56. data/app/controllers/pageflow/entries_controller.rb +17 -13
  57. data/app/controllers/pageflow/review/comment_thread_reads_controller.rb +30 -0
  58. data/app/controllers/pageflow/review/comment_threads_controller.rb +60 -0
  59. data/app/controllers/pageflow/review/comments_controller.rb +53 -0
  60. data/app/controllers/pageflow/revisions_controller.rb +4 -1
  61. data/app/helpers/pageflow/admin/entries_helper.rb +40 -0
  62. data/app/helpers/pageflow/admin/widgets_helper.rb +2 -2
  63. data/app/helpers/pageflow/common_entry_seed_helper.rb +5 -3
  64. data/app/helpers/pageflow/editor/config_helper.rb +3 -1
  65. data/app/helpers/pageflow/entries_helper.rb +24 -42
  66. data/app/helpers/pageflow/entry_json_seed_helper.rb +4 -4
  67. data/app/helpers/pageflow/public_i18n_helper.rb +9 -8
  68. data/app/helpers/pageflow/structured_data_helper.rb +4 -1
  69. data/app/helpers/pageflow/themes_helper.rb +1 -3
  70. data/app/helpers/pageflow/widgets_helper.rb +2 -1
  71. data/app/inputs/pageflow_permalink_input.rb +6 -2
  72. data/app/models/concerns/pageflow/auto_generated_perma_id.rb +11 -4
  73. data/app/models/concerns/pageflow/reusable_file.rb +1 -1
  74. data/app/models/concerns/pageflow/serialization_blacklist.rb +2 -4
  75. data/app/models/concerns/pageflow/translated_attributes.rb +101 -0
  76. data/app/models/concerns/pageflow/uploadable_file.rb +1 -1
  77. data/app/models/pageflow/comment.rb +30 -0
  78. data/app/models/pageflow/comment_thread.rb +65 -0
  79. data/app/models/pageflow/comment_thread_read.rb +22 -0
  80. data/app/models/pageflow/customized_theme.rb +3 -2
  81. data/app/models/pageflow/draft_entry.rb +20 -8
  82. data/app/models/pageflow/entry.rb +2 -0
  83. data/app/models/pageflow/entry_at_revision.rb +9 -1
  84. data/app/models/pageflow/entry_comment_summary.rb +114 -0
  85. data/app/models/pageflow/file_folder.rb +74 -0
  86. data/app/models/pageflow/file_reuse.rb +3 -2
  87. data/app/models/pageflow/file_usage.rb +8 -0
  88. data/app/models/pageflow/image_file.rb +24 -20
  89. data/app/models/pageflow/image_file_url_templates.rb +3 -3
  90. data/app/models/pageflow/legal_info.rb +38 -0
  91. data/app/models/pageflow/nested_revision_component_copy.rb +1 -1
  92. data/app/models/pageflow/permalink.rb +1 -0
  93. data/app/models/pageflow/revision.rb +6 -2
  94. data/app/models/pageflow/site.rb +10 -0
  95. data/app/models/pageflow/used_file.rb +8 -2
  96. data/app/models/pageflow/widget.rb +2 -2
  97. data/app/views/pageflow/audio_files/_audio_file.json.jbuilder +0 -1
  98. data/app/views/pageflow/editor/config/_seeds.json.jbuilder +4 -2
  99. data/app/views/pageflow/editor/entries/_entry.json.jbuilder +2 -1
  100. data/app/views/pageflow/editor/entries/seed.json.erb +1 -0
  101. data/app/views/pageflow/editor/file_folders/_file_folder.json.jbuilder +5 -0
  102. data/app/views/pageflow/editor/file_folders/create.json.jbuilder +1 -0
  103. data/app/views/pageflow/editor/file_folders/index.json.jbuilder +3 -0
  104. data/app/views/pageflow/editor/files/_file.json.jbuilder +2 -1
  105. data/app/views/pageflow/editor/image_files/_image_file.json.jbuilder +3 -0
  106. data/app/views/pageflow/editor/video_files/_video_file.json.jbuilder +3 -0
  107. data/app/views/pageflow/files/_file.json.jbuilder +2 -0
  108. data/app/views/pageflow/image_files/_image_file.json.jbuilder +0 -1
  109. data/app/views/pageflow/review/comment_threads/_comment_thread.json.jbuilder +20 -0
  110. data/app/views/pageflow/review/comment_threads/create.json.jbuilder +2 -0
  111. data/app/views/pageflow/review/comment_threads/index.json.jbuilder +13 -0
  112. data/app/views/pageflow/review/comments/_comment.json.jbuilder +13 -0
  113. data/app/views/pageflow/review/comments/create.json.jbuilder +1 -0
  114. data/app/views/pageflow/structured_data/_entry.json.jbuilder +2 -3
  115. data/app/views/pageflow/video_files/_video_file.json.jbuilder +0 -1
  116. data/config/locales/de.yml +152 -14
  117. data/config/locales/en.yml +150 -14
  118. data/config/routes.rb +14 -0
  119. data/db/migrate/20140418225525_setup_schema.rb +2 -2
  120. data/db/migrate/20251015000000_add_structured_data_type_name_to_revisions.rb +5 -0
  121. data/db/migrate/20251029142849_convert_legacy_social_embeds_to_unified_social_embed.rb +38 -0
  122. data/db/migrate/20251119083347_fix_main_storyline_positions.rb +16 -0
  123. data/db/migrate/20251119083348_ensure_scrolled_entries_have_excursion_storyline.rb +15 -0
  124. data/db/migrate/20260303000000_add_layout_version_to_revisions.rb +6 -0
  125. data/db/migrate/20260323000000_create_comment_threads_and_comments.rb +30 -0
  126. data/db/migrate/20260414000000_add_subject_range_to_comment_threads.rb +5 -0
  127. data/db/migrate/20260415000000_add_section_perma_id_to_comment_threads.rb +5 -0
  128. data/db/migrate/20260727000000_add_quote_to_comments.rb +5 -0
  129. data/db/migrate/20260728000000_create_file_folders.rb +17 -0
  130. data/db/migrate/20260805000000_add_attribute_translations_to_sites.rb +5 -0
  131. data/db/migrate/20260806000000_add_edited_at_to_comments.rb +5 -0
  132. data/db/migrate/20260810000000_create_pageflow_scrolled_lottie_files.rb +24 -0
  133. data/db/migrate/20260817000000_create_comment_thread_reads.rb +16 -0
  134. data/db/migrate/20260819000000_add_unread_comments_since_at_to_users.rb +18 -0
  135. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/editor.js +8665 -3890
  136. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/frontend.js +979 -3571
  137. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/react-client.js +20199 -28120
  138. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/react-server.js +18652 -26584
  139. data/entry_types/scrolled/app/assets/stylesheets/pageflow_scrolled/ui.scss +2 -0
  140. data/entry_types/scrolled/app/controllers/pageflow_scrolled/editor/content_elements_controller.rb +33 -3
  141. data/entry_types/scrolled/app/controllers/pageflow_scrolled/editor/sections_controller.rb +2 -3
  142. data/entry_types/scrolled/app/controllers/pageflow_scrolled/entries_controller.rb +21 -1
  143. data/entry_types/scrolled/app/helpers/pageflow_scrolled/cache_helper.rb +3 -3
  144. data/entry_types/scrolled/app/helpers/pageflow_scrolled/editor/entry_json_seed_helper.rb +7 -5
  145. data/entry_types/scrolled/app/helpers/pageflow_scrolled/editor/seed_html_helper.rb +5 -2
  146. data/entry_types/scrolled/app/helpers/pageflow_scrolled/entry_json_seed_helper.rb +13 -5
  147. data/entry_types/scrolled/app/helpers/pageflow_scrolled/i18n_helper.rb +28 -13
  148. data/entry_types/scrolled/app/helpers/pageflow_scrolled/packs_helper.rb +26 -11
  149. data/entry_types/scrolled/app/helpers/pageflow_scrolled/react_server_side_rendering_helper.rb +2 -2
  150. data/entry_types/scrolled/app/helpers/pageflow_scrolled/sprockets_helper.rb +16 -0
  151. data/entry_types/scrolled/app/helpers/pageflow_scrolled/themes_helper.rb +174 -3
  152. data/entry_types/scrolled/app/models/pageflow_scrolled/content_element.rb +49 -7
  153. data/entry_types/scrolled/app/models/pageflow_scrolled/lottie_file.rb +6 -0
  154. data/entry_types/scrolled/app/models/pageflow_scrolled/lottie_file_url_templates.rb +16 -0
  155. data/entry_types/scrolled/app/models/pageflow_scrolled/storyline.rb +1 -0
  156. data/entry_types/scrolled/app/views/pageflow_scrolled/entries/show.html.erb +13 -12
  157. data/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_entry.json.jbuilder +30 -10
  158. data/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_theme.json.jbuilder +9 -0
  159. data/entry_types/scrolled/app/views/pageflow_scrolled/favicons/_entry.html.erb +1 -1
  160. data/entry_types/scrolled/config/configuration_schemas/pageflow-scrolled.json +414 -0
  161. data/entry_types/scrolled/config/locales/de.yml +512 -65
  162. data/entry_types/scrolled/config/locales/en.yml +518 -52
  163. data/entry_types/scrolled/lib/pageflow_scrolled/additional_seed_data.rb +2 -2
  164. data/entry_types/scrolled/lib/pageflow_scrolled/configuration.rb +51 -6
  165. data/entry_types/scrolled/lib/pageflow_scrolled/configuration_schemas.rb +91 -0
  166. data/entry_types/scrolled/lib/pageflow_scrolled/engine.rb +2 -1
  167. data/entry_types/scrolled/lib/pageflow_scrolled/entry_file_reference_locations.rb +71 -0
  168. data/entry_types/scrolled/lib/pageflow_scrolled/entry_structured_data_types/faq_page.rb +58 -0
  169. data/entry_types/scrolled/lib/pageflow_scrolled/file_reference_locations.rb +69 -0
  170. data/entry_types/scrolled/lib/pageflow_scrolled/plugin.rb +205 -22
  171. data/entry_types/scrolled/lib/pageflow_scrolled/react_widget_type.rb +2 -4
  172. data/entry_types/scrolled/lib/pageflow_scrolled/seeds.rb +56 -36
  173. data/entry_types/scrolled/lib/pageflow_scrolled/theme_options_default_scale.rb +35 -0
  174. data/entry_types/scrolled/lib/pageflow_scrolled.rb +13 -0
  175. data/entry_types/scrolled/lib/tasks/pageflow_scrolled/storybook.rake +19 -1
  176. data/entry_types/scrolled/package/config/configurationSchemas.js +70 -0
  177. data/entry_types/scrolled/package/config/rollup/configurationSchemas.js +19 -0
  178. data/entry_types/scrolled/package/config/webpack.js +72 -0
  179. data/entry_types/scrolled/package/contentElements/hotspots-frontend.css +1 -1
  180. data/entry_types/scrolled/package/contentElements/hotspots-frontend.js +1181 -915
  181. data/entry_types/scrolled/package/contentElements/inlineBeforeAfter-frontend.css +1 -0
  182. data/entry_types/scrolled/package/contentElements/inlineBeforeAfter-frontend.js +219 -0
  183. data/entry_types/scrolled/package/contentElements/lottieAnimation-frontend.css +1 -0
  184. data/entry_types/scrolled/package/contentElements/lottieAnimation-frontend.js +244 -0
  185. data/entry_types/scrolled/package/contentElements/socialEmbed-frontend.css +1 -0
  186. data/entry_types/scrolled/package/contentElements/socialEmbed-frontend.js +823 -0
  187. data/entry_types/scrolled/package/contentElements/tikTokEmbed-frontend.js +71 -21
  188. data/entry_types/scrolled/package/contentElements/twitterEmbed-frontend.css +1 -0
  189. data/entry_types/scrolled/package/contentElements/twitterEmbed-frontend.js +277 -0
  190. data/entry_types/scrolled/package/contentElements/videoEmbed-frontend.css +1 -0
  191. data/entry_types/scrolled/package/contentElements/videoEmbed-frontend.js +244 -0
  192. data/entry_types/scrolled/package/contentElements-editor.js +1915 -1097
  193. data/entry_types/scrolled/package/contentElements-frontend.css +1 -1
  194. data/entry_types/scrolled/package/contentElements-frontend.js +3093 -1679
  195. data/entry_types/scrolled/package/editor.css +1 -0
  196. data/entry_types/scrolled/package/editor.js +8667 -4077
  197. data/entry_types/scrolled/package/entryState.js +1600 -0
  198. data/entry_types/scrolled/package/frontend/FloatingPortalRootProvider-20c600de.js +1979 -0
  199. data/entry_types/scrolled/package/frontend/FloatingPortalRootProvider-58189220.js +2538 -0
  200. data/entry_types/scrolled/package/frontend/{PhonePlatformContext-9f76033e.js → PhonePlatformContext-035a99fa.js} +7 -12
  201. data/entry_types/scrolled/package/frontend/PhonePlatformContext-9da43797.js +33 -0
  202. data/entry_types/scrolled/package/frontend/Placeholder.module-bf0966b4.js +5267 -0
  203. data/entry_types/scrolled/package/frontend/Placeholder.module-d22a9335.js +4180 -0
  204. data/entry_types/scrolled/package/frontend/ThemeIcon-ab834849.js +754 -0
  205. data/entry_types/scrolled/package/frontend/ThemeIcon-f6cb3a8f.js +773 -0
  206. data/entry_types/scrolled/package/frontend/{ToggleFullscreenCornerButton-788e9cdb.js → ToggleFullscreenCornerButton-30fd1124.js} +6 -6
  207. data/entry_types/scrolled/package/frontend/ToggleFullscreenCornerButton-61c25224.js +72 -0
  208. data/entry_types/scrolled/package/frontend/Viewer-1074fd59.js +147 -0
  209. data/entry_types/scrolled/package/frontend/Viewer-1482ca34.js +480 -0
  210. data/entry_types/scrolled/package/frontend/Viewer-70504231.js +210 -0
  211. data/entry_types/scrolled/package/frontend/{Viewer-0345ce57.js → Viewer-cc8d4072.js} +84 -92
  212. data/entry_types/scrolled/package/frontend/Wavesurfer-656e3c36.js +302 -0
  213. data/entry_types/scrolled/package/frontend/Wavesurfer-b753b838.js +385 -0
  214. data/entry_types/scrolled/package/frontend/commenting.css +1 -0
  215. data/entry_types/scrolled/package/frontend/extensions-167ae143.js +1455 -0
  216. data/entry_types/scrolled/package/frontend/extensions-2318f92b.js +5918 -0
  217. data/entry_types/scrolled/package/frontend/extensions-a461fd13.js +4890 -0
  218. data/entry_types/scrolled/package/frontend/extensions-c98269fd.js +1982 -0
  219. data/entry_types/scrolled/package/frontend/i18n-493cd2a6.js +93 -0
  220. data/entry_types/scrolled/package/frontend/i18n-e06cac14.js +100 -0
  221. data/entry_types/scrolled/package/frontend/{index-eb670c2f.js → index-2e5546f7.js} +36 -44
  222. data/entry_types/scrolled/package/frontend/index-de2b418d.js +130 -0
  223. data/entry_types/scrolled/package/frontend/index.css +1 -1
  224. data/entry_types/scrolled/package/frontend/index.js +1870 -875
  225. data/entry_types/scrolled/package/frontend/inlineEditing.css +1 -0
  226. data/entry_types/scrolled/package/frontend/useContentElementEditorState-a084912e.js +25 -0
  227. data/entry_types/scrolled/package/frontend/useDelayedBoolean-a387d85b.js +24 -0
  228. data/entry_types/scrolled/package/frontend/{usePhonePlatform-c2ba875d.js → usePhonePlatform-4ecb96d4.js} +1 -1
  229. data/entry_types/scrolled/package/frontend/usePhonePlatform-ce9ff08d.js +8 -0
  230. data/entry_types/scrolled/package/frontend-server.js +20 -209
  231. data/entry_types/scrolled/package/package.json +5 -3
  232. data/entry_types/scrolled/package/review.css +1 -0
  233. data/entry_types/scrolled/package/review.js +3306 -0
  234. data/entry_types/scrolled/package/testHelpers.js +836 -359
  235. data/entry_types/scrolled/package/widgets/consentBar.css +1 -1
  236. data/entry_types/scrolled/package/widgets/consentBar.js +269 -290
  237. data/entry_types/scrolled/package/widgets/defaultNavigation.css +2 -2
  238. data/entry_types/scrolled/package/widgets/defaultNavigation.js +911 -352
  239. data/entry_types/scrolled/package/widgets/excursionSheet.css +1 -1
  240. data/entry_types/scrolled/package/widgets/excursionSheet.js +87 -124
  241. data/entry_types/scrolled/package/widgets/iconInlineFileRights.css +1 -1
  242. data/entry_types/scrolled/package/widgets/iconInlineFileRights.js +62 -29
  243. data/entry_types/scrolled/package/widgets/iconScrollIndicator.js +32 -13
  244. data/entry_types/scrolled/package/widgets/mainStorylineSheet.css +1 -1
  245. data/entry_types/scrolled/package/widgets/mainStorylineSheet.js +56 -100
  246. data/entry_types/scrolled/package/widgets/textInlineFileRights.css +1 -1
  247. data/entry_types/scrolled/package/widgets/textInlineFileRights.js +33 -28
  248. data/entry_types/scrolled/package/widgets-server.js +1 -0
  249. data/entry_types/scrolled/spec/factories/lottie_files.rb +29 -0
  250. data/entry_types/scrolled/spec/fixtures/animation.lottie +0 -0
  251. data/entry_types/scrolled/spec/fixtures/font.woff +0 -0
  252. data/entry_types/scrolled/spec/fixtures/font.woff2 +0 -0
  253. data/lib/generators/pageflow/resque/resque_generator.rb +0 -2
  254. data/lib/pageflow/configuration.rb +49 -7
  255. data/lib/pageflow/deprecation.rb +19 -0
  256. data/lib/pageflow/engine.rb +1 -1
  257. data/lib/pageflow/entries_controller_env_helper.rb +32 -2
  258. data/lib/pageflow/entry_export_import/entry_serialization.rb +4 -4
  259. data/lib/pageflow/entry_export_import/page_type_versions.rb +2 -2
  260. data/lib/pageflow/entry_export_import/revision_serialization/import.rb +10 -0
  261. data/lib/pageflow/entry_export_import/revision_serialization.rb +3 -0
  262. data/lib/pageflow/entry_structured_data_types.rb +43 -0
  263. data/lib/pageflow/entry_type_configuration.rb +1 -0
  264. data/lib/pageflow/file_type.rb +2 -2
  265. data/lib/pageflow/file_types.rb +1 -1
  266. data/lib/pageflow/oembed_providers.rb +42 -0
  267. data/lib/pageflow/primary_domain_entry_redirect.rb +6 -0
  268. data/lib/pageflow/rails_version.rb +13 -2
  269. data/lib/pageflow/themes.rb +41 -0
  270. data/lib/pageflow/user_mixin.rb +12 -0
  271. data/lib/pageflow/version.rb +1 -1
  272. data/lib/pageflow.rb +1 -0
  273. data/package/config/eslint-rules/documented-in-toc.js +125 -0
  274. data/package/config/jest/index.js +0 -1
  275. data/package/config/webpack.js +0 -1
  276. data/package/config/webpack5.js +0 -1
  277. data/package/editor.js +4378 -1897
  278. data/package/frontend.js +647 -886
  279. data/package/package.json +2 -1
  280. data/package/review.js +384 -0
  281. data/package/testHelpers.js +248 -188
  282. data/package/ui.js +1346 -630
  283. data/package/vendor/stubs/wysihtml5.js +2 -0
  284. data/spec/factories/comment_thread_reads.rb +10 -0
  285. data/spec/factories/comment_threads.rb +10 -0
  286. data/spec/factories/comments.rb +9 -0
  287. data/spec/factories/file_folders.rb +8 -0
  288. data/spec/factories/published_entries.rb +2 -0
  289. metadata +188 -67
  290. data/app/assets/stylesheets/pageflow/editor/select_button.scss +0 -51
  291. data/entry_types/scrolled/app/helpers/pageflow_scrolled/generated_media_queries_helper.rb +0 -55
  292. data/entry_types/scrolled/package/frontend/FloatingPortalRootProvider-51914be7.js +0 -5439
  293. data/entry_types/scrolled/package/frontend/ThemeIcon-81f2f066.js +0 -1932
  294. data/entry_types/scrolled/package/frontend/Viewer-cdc549cc.js +0 -147
  295. data/entry_types/scrolled/package/frontend/Wavesurfer-1cdc3925.js +0 -313
  296. data/entry_types/scrolled/package/frontend/components-96660ffd.js +0 -3803
  297. data/entry_types/scrolled/package/frontend/inherits-539844a6.js +0 -99
  298. data/entry_types/scrolled/package/frontend/useContentElementEditorState-77fe6c79.js +0 -51
  299. data/entry_types/scrolled/package/widgets/excursionDialog.css +0 -1
  300. data/entry_types/scrolled/package/widgets/excursionDialog.js +0 -109
  301. data/lib/generators/pageflow/resque/templates/resque_enqueue_after_commit_patch.rb +0 -25
  302. data/package/vendor/jquery.minicolors.js +0 -1108
@@ -0,0 +1,1455 @@
1
+ import React, { createContext, useContext, useCallback, useState, useMemo, useRef, useEffect } from 'react';
2
+ import { flushSync } from 'react-dom';
3
+ import classNames from 'classnames';
4
+ import { a as useActiveExcursion, o as useFloatingPortalRoot, d as api, w as widths, g as useContentElementAttributes, U as PlainEditableText, N as renderLeaf, V as textStyles, T as Text, R as renderElement } from './FloatingPortalRootProvider-20c600de.js';
5
+ import './useDelayedBoolean-a387d85b.js';
6
+ import 'backbone-events-standalone';
7
+ import { useEntryMetadata } from 'pageflow-scrolled/entryState';
8
+ import 'i18n-js';
9
+ import { u as useI18n } from './i18n-493cd2a6.js';
10
+ import 'react-measure';
11
+ import { review, useCommentDisplayFilter, useLocatedCommentThreads, ActivityList, useUnreadThreadCount, useStoredCommentDisplayFilter, ReviewStateProvider, LocatedCommentThreadsProvider, CommentDisplayFilterProvider, ReviewMessageHandler, ThreadsBadge, ThreadList, useLocatedCommentThreadsForSubject, useAnchoredFloating, useRangeAnchors, useCommentThreads, useCommentHighlights, decorateCommentHighlights, RangeAnchor, commentHighlightStyles } from 'pageflow-scrolled/review';
12
+ import { useFloating, offset, shift, size, autoUpdate, FloatingPortal, flip } from '@floating-ui/react';
13
+ import { Node, Point, createEditor, Editor } from 'slate';
14
+ import { ReactEditor, withReact, Slate, Editable } from 'slate-react';
15
+ import { createReviewSession } from 'pageflow/review';
16
+
17
+ // Headings carry no ranged comments since EditableInlineText has no
18
+ // commenting alternative, so every comment refers to the header as a whole
19
+ // and the quote covers all three of its texts.
20
+ review.contentElementTypes.register('heading', {
21
+ extractQuote(configuration) {
22
+ const parts = [inlineText(configuration.tagline), mainText(configuration), inlineText(configuration.subtitle)];
23
+ return parts.map(part => part.trim()).filter(Boolean).join('\n') || null;
24
+ }
25
+ });
26
+
27
+ // Mirrors how EditableInlineText picks the legacy string value, so the quote
28
+ // never contains text the heading does not display.
29
+ function mainText(configuration) {
30
+ return configuration.value ? inlineText(configuration.value) : configuration.children || '';
31
+ }
32
+ function inlineText(value) {
33
+ return value ? value.map(node => Node.string(node)).join(' ') : '';
34
+ }
35
+
36
+ review.contentElementTypes.register('textBlock', {
37
+ compareRanges(a, b) {
38
+ if (!a && !b) return 0;
39
+ if (!a) return 1;
40
+ if (!b) return -1;
41
+ return Point.compare(rangeStart(a), rangeStart(b));
42
+ },
43
+ // Element wide comments stay unquoted: the whole text is too long to serve
44
+ // as a point of reference, and any edit anywhere in it would mark the quote
45
+ // outdated.
46
+ extractQuote(configuration, range) {
47
+ if (!range) return null;
48
+ const root = {
49
+ children: configuration.value || []
50
+ };
51
+ if (!Node.has(root, range.anchor.path) || !Node.has(root, range.focus.path)) {
52
+ return null;
53
+ }
54
+ const text = Node.fragment(root, range).map(node => Node.string(node)).join('\n').trim();
55
+ return text || null;
56
+ }
57
+ });
58
+ function rangeStart(range) {
59
+ return Point.isBefore(range.anchor, range.focus) ? range.anchor : range.focus;
60
+ }
61
+
62
+ const SelectedSubjectContext = createContext({
63
+ selectedSubject: null,
64
+ setSelectedSubject: () => {},
65
+ clearSelection: () => {}
66
+ });
67
+ const CommentNavigationContext = createContext({
68
+ count: 0,
69
+ position: 0,
70
+ goToNext: () => {},
71
+ goToPrevious: () => {},
72
+ goToThread: () => {}
73
+ });
74
+ function SelectedSubjectProvider({
75
+ children
76
+ }) {
77
+ const {
78
+ resolution
79
+ } = useCommentDisplayFilter();
80
+ const {
81
+ chapters
82
+ } = useLocatedCommentThreads();
83
+ const {
84
+ activateExcursionOfSection,
85
+ returnFromExcursion
86
+ } = useActiveExcursion();
87
+ const [selectedSubject, setSelectedSubject] = useState(null);
88
+ const allTargets = useMemo(() => navigableTargets(chapters), [chapters]);
89
+ const targets = useMemo(() => allTargets.filter(target => matchesResolution(target, resolution)), [allTargets, resolution]);
90
+ const clearSelection = useCallback(() => {
91
+ setSelectedSubject(null);
92
+ }, []);
93
+ const selectTarget = useCallback((target, options) => {
94
+ if (movesToDifferentSubject(selectedSubject, target)) {
95
+ if (target.excursion) {
96
+ activateExcursionOfSection({
97
+ id: target.sectionId
98
+ });
99
+ } else {
100
+ returnFromExcursion();
101
+ }
102
+ }
103
+ setSelectedSubject({
104
+ subjectType: target.subjectType,
105
+ subjectId: target.subjectId,
106
+ subjectRange: target.subjectRange,
107
+ highlightedThreadId: target.threadId,
108
+ ...options
109
+ });
110
+ }, [selectedSubject, activateExcursionOfSection, returnFromExcursion]);
111
+ const goTo = useCallback(step => {
112
+ if (targets.length === 0) {
113
+ return;
114
+ }
115
+ const current = currentTargetIndex(targets, selectedSubject);
116
+ const next = current < 0 ? step > 0 ? 0 : targets.length - 1 : (current + step + targets.length) % targets.length;
117
+ selectTarget(targets[next]);
118
+ }, [targets, selectedSubject, selectTarget]);
119
+ const goToThread = useCallback((threadId, options) => {
120
+ const target = allTargets.find(target => target.threadId === threadId);
121
+ if (target) {
122
+ selectTarget(target, options);
123
+ }
124
+ }, [allTargets, selectTarget]);
125
+ const position = useMemo(() => currentTargetIndex(targets, selectedSubject) + 1, [targets, selectedSubject]);
126
+ const selection = useMemo(() => ({
127
+ selectedSubject,
128
+ setSelectedSubject,
129
+ clearSelection
130
+ }), [selectedSubject, clearSelection]);
131
+ const navigation = useMemo(() => {
132
+ var _selectedSubject$high;
133
+ return {
134
+ count: targets.length,
135
+ position,
136
+ highlightedThreadId: (_selectedSubject$high = selectedSubject === null || selectedSubject === void 0 ? void 0 : selectedSubject.highlightedThreadId) !== null && _selectedSubject$high !== void 0 ? _selectedSubject$high : null,
137
+ goToNext: () => goTo(1),
138
+ goToPrevious: () => goTo(-1),
139
+ goToThread
140
+ };
141
+ }, [targets.length, position, selectedSubject, goTo, goToThread]);
142
+ return /*#__PURE__*/React.createElement(SelectedSubjectContext.Provider, {
143
+ value: selection
144
+ }, /*#__PURE__*/React.createElement(CommentNavigationContext.Provider, {
145
+ value: navigation
146
+ }, children));
147
+ }
148
+ function useCommentNavigation() {
149
+ return useContext(CommentNavigationContext);
150
+ }
151
+ function useSelectedSubject(subjectType, subjectId, subjectRange) {
152
+ var _selectedSubject$high2;
153
+ const {
154
+ selectedSubject,
155
+ setSelectedSubject,
156
+ clearSelection
157
+ } = useContext(SelectedSubjectContext);
158
+ const isSelected = selectedSubject && selectedSubject.subjectType === subjectType && selectedSubject.subjectId === subjectId && (!subjectRange || JSON.stringify(selectedSubject.subjectRange) === JSON.stringify(subjectRange));
159
+ const select = useCallback(options => {
160
+ setSelectedSubject({
161
+ subjectType,
162
+ subjectId,
163
+ subjectRange,
164
+ ...options
165
+ });
166
+ }, [setSelectedSubject, subjectType, subjectId, subjectRange]);
167
+ return {
168
+ isSelected,
169
+ hasSelection: !!selectedSubject,
170
+ select,
171
+ clearSelection,
172
+ revealOnly: !!(isSelected && selectedSubject.revealOnly),
173
+ showNewForm: isSelected && selectedSubject.showNewForm,
174
+ subjectRange: isSelected ? selectedSubject.subjectRange : undefined,
175
+ highlightedThreadId: isSelected ? (_selectedSubject$high2 = selectedSubject.highlightedThreadId) !== null && _selectedSubject$high2 !== void 0 ? _selectedSubject$high2 : null : null
176
+ };
177
+ }
178
+ function movesToDifferentSubject(selectedSubject, target) {
179
+ return !selectedSubject || subjectKey(selectedSubject) !== target.key;
180
+ }
181
+ function currentTargetIndex(targets, selectedSubject) {
182
+ if (!selectedSubject) {
183
+ return -1;
184
+ }
185
+ if (selectedSubject.highlightedThreadId != null) {
186
+ return targets.findIndex(target => target.threadId === selectedSubject.highlightedThreadId);
187
+ }
188
+ const key = subjectKey(selectedSubject);
189
+ return targets.findIndex(target => target.key === key);
190
+ }
191
+ function navigableTargets(chapters) {
192
+ const targets = [];
193
+ chapters.forEach(chapter => {
194
+ chapter.sections.forEach(section => {
195
+ const location = {
196
+ sectionId: section.id,
197
+ excursion: chapter.isExcursion
198
+ };
199
+ section.threads.forEach(thread => targets.push({
200
+ key: subjectKey({
201
+ subjectType: 'Section',
202
+ subjectId: section.permaId
203
+ }),
204
+ subjectType: 'Section',
205
+ subjectId: section.permaId,
206
+ threadId: thread.id,
207
+ resolved: !!thread.resolvedAt,
208
+ ...location
209
+ }));
210
+ section.contentElements.forEach(contentElement => {
211
+ pushTargets(targets, contentElement.threads, location);
212
+ });
213
+ });
214
+ });
215
+ return targets;
216
+ }
217
+ function pushTargets(targets, threads, location) {
218
+ threads.forEach(thread => targets.push({
219
+ key: subjectKey(thread),
220
+ subjectType: thread.subjectType,
221
+ subjectId: thread.subjectId,
222
+ subjectRange: thread.subjectRange,
223
+ threadId: thread.id,
224
+ resolved: !!thread.resolvedAt,
225
+ ...location
226
+ }));
227
+ }
228
+ function matchesResolution(target, resolution) {
229
+ return resolution === 'all' || resolution === 'unresolved' && !target.resolved || resolution === 'resolved' && target.resolved;
230
+ }
231
+ function subjectKey({
232
+ subjectType,
233
+ subjectId,
234
+ subjectRange
235
+ }) {
236
+ return `${subjectType}:${subjectId}:${subjectRange ? JSON.stringify(subjectRange) : ''}`;
237
+ }
238
+
239
+ const AddCommentModeContext = createContext({
240
+ active: false,
241
+ toggle: () => {},
242
+ deactivate: () => {},
243
+ preselect: () => {},
244
+ clearPreselection: () => {}
245
+ });
246
+ function AddCommentModeProvider({
247
+ children
248
+ }) {
249
+ const [active, setActive] = useState(false);
250
+ const preselectionRef = useRef(null);
251
+ const {
252
+ select
253
+ } = useSelectedSubject();
254
+ const toggle = useCallback(() => {
255
+ if (!active && preselectionRef.current) {
256
+ select(preselectionRef.current);
257
+ preselectionRef.current = null;
258
+ return;
259
+ }
260
+ setActive(prev => !prev);
261
+ }, [active, select]);
262
+ const deactivate = useCallback(() => {
263
+ setActive(false);
264
+ }, []);
265
+ const preselect = useCallback(subject => {
266
+ preselectionRef.current = subject;
267
+ }, []);
268
+ const clearPreselection = useCallback(subjectId => {
269
+ var _preselectionRef$curr;
270
+ if (((_preselectionRef$curr = preselectionRef.current) === null || _preselectionRef$curr === void 0 ? void 0 : _preselectionRef$curr.subjectId) === subjectId) {
271
+ preselectionRef.current = null;
272
+ }
273
+ }, []);
274
+ useEffect(() => {
275
+ if (!active) return;
276
+ function handleMouseDown(event) {
277
+ if (!event.target.closest('[data-add-comment-overlay]') && !event.target.closest('[data-add-comment-toggle]')) {
278
+ setActive(false);
279
+ }
280
+ }
281
+ document.addEventListener('mousedown', handleMouseDown);
282
+ return () => {
283
+ document.removeEventListener('mousedown', handleMouseDown);
284
+ };
285
+ }, [active]);
286
+ const value = useMemo(() => ({
287
+ active,
288
+ toggle,
289
+ deactivate,
290
+ preselect,
291
+ clearPreselection
292
+ }), [active, toggle, deactivate, preselect, clearPreselection]);
293
+ return /*#__PURE__*/React.createElement(AddCommentModeContext.Provider, {
294
+ value: value
295
+ }, children);
296
+ }
297
+ function useAddCommentMode() {
298
+ return useContext(AddCommentModeContext);
299
+ }
300
+
301
+ const storageKey = 'pageflow.scrolled.commentingVisible';
302
+ const CommentingVisibilityContext = createContext({
303
+ visible: true,
304
+ toggle: () => {}
305
+ });
306
+ function CommentingVisibilityProvider({
307
+ children
308
+ }) {
309
+ const [visible, setVisible] = useState(readStoredVisibility);
310
+ const toggle = useCallback(() => {
311
+ const next = !visible;
312
+ const flip = () => setVisible(next);
313
+
314
+ // Without flushSync the transition captures the pre-toggle DOM.
315
+ if (document.startViewTransition) {
316
+ document.startViewTransition(() => flushSync(flip));
317
+ } else {
318
+ flip();
319
+ }
320
+ storeVisibility(next);
321
+ }, [visible]);
322
+ const value = useMemo(() => ({
323
+ visible,
324
+ toggle
325
+ }), [visible, toggle]);
326
+ return /*#__PURE__*/React.createElement(CommentingVisibilityContext.Provider, {
327
+ value: value
328
+ }, children);
329
+ }
330
+ function useCommentingVisibility() {
331
+ return useContext(CommentingVisibilityContext);
332
+ }
333
+ function readStoredVisibility() {
334
+ var _getLocalStorage;
335
+ return ((_getLocalStorage = getLocalStorage()) === null || _getLocalStorage === void 0 ? void 0 : _getLocalStorage[storageKey]) !== 'false';
336
+ }
337
+ function storeVisibility(visible) {
338
+ const storage = getLocalStorage();
339
+ if (storage) {
340
+ storage[storageKey] = visible;
341
+ }
342
+ }
343
+ function getLocalStorage() {
344
+ try {
345
+ return typeof window === 'undefined' ? null : window.localStorage;
346
+ } catch (e) {
347
+ // Safari throws SecurityError when accessing window.localStorage
348
+ // if cookies/website data are disabled.
349
+ return null;
350
+ }
351
+ }
352
+
353
+ function _extends() {
354
+ _extends = Object.assign ? Object.assign.bind() : function (target) {
355
+ for (var i = 1; i < arguments.length; i++) {
356
+ var source = arguments[i];
357
+ for (var key in source) {
358
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
359
+ target[key] = source[key];
360
+ }
361
+ }
362
+ }
363
+ return target;
364
+ };
365
+ return _extends.apply(this, arguments);
366
+ }
367
+ var ActivityIcon = (({
368
+ styles = {},
369
+ ...props
370
+ }) => /*#__PURE__*/React.createElement("svg", _extends({
371
+ xmlns: "http://www.w3.org/2000/svg",
372
+ viewBox: "0 0 24 24",
373
+ fill: "none",
374
+ stroke: "currentColor",
375
+ strokeWidth: "2",
376
+ strokeLinecap: "round",
377
+ strokeLinejoin: "round",
378
+ width: "16",
379
+ height: "16"
380
+ }, props), /*#__PURE__*/React.createElement("path", {
381
+ d: "M3 12a9 9 0 109-9 9.75 9.75 0 00-6.74 2.74L3 8"
382
+ }), /*#__PURE__*/React.createElement("path", {
383
+ d: "M3 3v5h5m4-1v5l4 2"
384
+ })));
385
+
386
+ var styles = {"toolbar":"FloatingToolbar-module_toolbar__3iLrb","toggleIcon":"FloatingToolbar-module_toggleIcon__tzwy_","puck":"FloatingToolbar-module_puck__1N8t9","puckIdle":"FloatingToolbar-module_puckIdle__25dov","unreadDot":"FloatingToolbar-module_unreadDot__3Ykgi","navigation":"FloatingToolbar-module_navigation__2oEYm","button":"FloatingToolbar-module_button__2_Q49","count":"FloatingToolbar-module_count__37jUH","segmented":"FloatingToolbar-module_segmented__34nUI","chevronUp":"FloatingToolbar-module_chevronUp__tCL4E","chevronDown":"FloatingToolbar-module_chevronDown__2NELa","segment":"FloatingToolbar-module_segment__q3hcg","segmentCount":"FloatingToolbar-module_segmentCount__2Nsqk","addButton":"FloatingToolbar-module_addButton__2tgNA"};
387
+
388
+ var styles$1 = {"button":"ActivityButton-module_button__3BNt8","unseenDot":"ActivityButton-module_unseenDot__1w8QA","panel":"ActivityButton-module_panel__1tcQU","scroller":"ActivityButton-module_scroller__2RTTE"};
389
+
390
+ // Clears the default navigation: a 50px bar with an 8px progress bar.
391
+ const viewportPadding = {
392
+ top: 74,
393
+ right: 16,
394
+ bottom: 16,
395
+ left: 16
396
+ };
397
+ function ActivityButton() {
398
+ const {
399
+ t
400
+ } = useI18n({
401
+ locale: 'ui'
402
+ });
403
+ const [open, setOpen] = useState(false);
404
+ const unreadCount = useUnreadThreadCount();
405
+ const label = t('pageflow_scrolled.review.activity.toggle');
406
+ const {
407
+ clearSelection
408
+ } = useSelectedSubject();
409
+ const portalRoot = useFloatingPortalRoot();
410
+ const {
411
+ refs,
412
+ floatingStyles
413
+ } = useFloating({
414
+ open,
415
+ strategy: 'fixed',
416
+ placement: 'top-end',
417
+ middleware: [offset(8), shift({
418
+ padding: viewportPadding
419
+ }), size({
420
+ padding: viewportPadding,
421
+ apply({
422
+ availableHeight,
423
+ elements
424
+ }) {
425
+ elements.floating.style.maxHeight = `${availableHeight}px`;
426
+ }
427
+ })],
428
+ whileElementsMounted: autoUpdate
429
+ });
430
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("button", {
431
+ ref: refs.setReference,
432
+ className: classNames(styles.button, styles$1.button),
433
+ onClick: () => {
434
+ if (!open) {
435
+ clearSelection();
436
+ }
437
+ setOpen(!open);
438
+ },
439
+ "aria-expanded": open,
440
+ "aria-label": label,
441
+ title: label
442
+ }, /*#__PURE__*/React.createElement(ActivityIcon, null), unreadCount > 0 && /*#__PURE__*/React.createElement("span", {
443
+ className: styles$1.unseenDot
444
+ })), open && /*#__PURE__*/React.createElement(FloatingPortal, {
445
+ id: "floating-ui-above-navigation-widgets",
446
+ root: portalRoot
447
+ }, /*#__PURE__*/React.createElement(ActivityPanel, {
448
+ ref: refs.setFloating,
449
+ style: floatingStyles,
450
+ onClose: () => setOpen(false)
451
+ })));
452
+ }
453
+ const ActivityPanel = React.forwardRef(function ActivityPanel({
454
+ style,
455
+ onClose
456
+ }, ref) {
457
+ const {
458
+ t
459
+ } = useI18n({
460
+ locale: 'ui'
461
+ });
462
+ const {
463
+ goToThread,
464
+ highlightedThreadId
465
+ } = useCommentNavigation();
466
+ const panelRef = useRef();
467
+ const setRefs = useCallback(node => {
468
+ panelRef.current = node;
469
+ ref(node);
470
+ }, [ref]);
471
+ useEffect(() => {
472
+ function handleClick(event) {
473
+ var _panelRef$current;
474
+ if ((_panelRef$current = panelRef.current) === null || _panelRef$current === void 0 ? void 0 : _panelRef$current.contains(event.target)) return;
475
+ if (event.target.closest('[data-comment-toolbar]')) return;
476
+ onClose();
477
+ }
478
+
479
+ // An open popover would otherwise close itself on the same key.
480
+ function handleKeyDown(event) {
481
+ if (event.key === 'Escape') {
482
+ event.stopPropagation();
483
+ onClose();
484
+ }
485
+ }
486
+ document.addEventListener('mousedown', handleClick);
487
+ document.addEventListener('keydown', handleKeyDown, true);
488
+ return () => {
489
+ document.removeEventListener('mousedown', handleClick);
490
+ document.removeEventListener('keydown', handleKeyDown, true);
491
+ };
492
+ }, [onClose]);
493
+ return /*#__PURE__*/React.createElement("div", {
494
+ ref: setRefs,
495
+ className: styles$1.panel,
496
+ style: style,
497
+ role: "dialog",
498
+ "aria-label": t('pageflow_scrolled.review.activity.toggle'),
499
+ "data-comment-activity": true
500
+ }, /*#__PURE__*/React.createElement("div", {
501
+ className: styles$1.scroller
502
+ }, /*#__PURE__*/React.createElement(ActivityList, {
503
+ highlightedThreadId: highlightedThreadId,
504
+ onEntryClick: entry => goToThread(entry.threadId, {
505
+ revealOnly: true
506
+ })
507
+ })));
508
+ });
509
+
510
+ function _extends$1() {
511
+ _extends$1 = Object.assign ? Object.assign.bind() : function (target) {
512
+ for (var i = 1; i < arguments.length; i++) {
513
+ var source = arguments[i];
514
+ for (var key in source) {
515
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
516
+ target[key] = source[key];
517
+ }
518
+ }
519
+ }
520
+ return target;
521
+ };
522
+ return _extends$1.apply(this, arguments);
523
+ }
524
+ var AddCommentIcon = (({
525
+ styles = {},
526
+ ...props
527
+ }) => /*#__PURE__*/React.createElement("svg", _extends$1({
528
+ xmlns: "http://www.w3.org/2000/svg",
529
+ width: "24",
530
+ height: "24",
531
+ fill: "none",
532
+ stroke: "currentColor",
533
+ strokeWidth: "2",
534
+ strokeLinecap: "round",
535
+ strokeLinejoin: "round"
536
+ }, props), /*#__PURE__*/React.createElement("path", {
537
+ d: "M22 17a2 2 0 01-2 2H6.828a2 2 0 00-1.414.586l-2.202 2.202A.71.71 0 012 21.286V5a2 2 0 012-2h16a2 2 0 012 2zM12 8v6m-3-3h6"
538
+ })));
539
+
540
+ function _extends$2() {
541
+ _extends$2 = Object.assign ? Object.assign.bind() : function (target) {
542
+ for (var i = 1; i < arguments.length; i++) {
543
+ var source = arguments[i];
544
+ for (var key in source) {
545
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
546
+ target[key] = source[key];
547
+ }
548
+ }
549
+ }
550
+ return target;
551
+ };
552
+ return _extends$2.apply(this, arguments);
553
+ }
554
+ var CancelCommentIcon = (({
555
+ styles = {},
556
+ ...props
557
+ }) => /*#__PURE__*/React.createElement("svg", _extends$2({
558
+ xmlns: "http://www.w3.org/2000/svg",
559
+ width: "24",
560
+ height: "24",
561
+ fill: "none",
562
+ stroke: "currentColor",
563
+ strokeWidth: "2",
564
+ strokeLinecap: "round",
565
+ strokeLinejoin: "round"
566
+ }, props), /*#__PURE__*/React.createElement("path", {
567
+ d: "M22 17a2 2 0 01-2 2H6.828a2 2 0 00-1.414.586l-2.202 2.202A.71.71 0 012 21.286V5a2 2 0 012-2h16a2 2 0 012 2zm-7.5-8.5l-5 5m0-5l5 5"
568
+ })));
569
+
570
+ function _extends$3() {
571
+ _extends$3 = Object.assign ? Object.assign.bind() : function (target) {
572
+ for (var i = 1; i < arguments.length; i++) {
573
+ var source = arguments[i];
574
+ for (var key in source) {
575
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
576
+ target[key] = source[key];
577
+ }
578
+ }
579
+ }
580
+ return target;
581
+ };
582
+ return _extends$3.apply(this, arguments);
583
+ }
584
+ var ChevronIcon = (({
585
+ styles = {},
586
+ ...props
587
+ }) => /*#__PURE__*/React.createElement("svg", _extends$3({
588
+ xmlns: "http://www.w3.org/2000/svg",
589
+ viewBox: "0 0 24 24",
590
+ fill: "none",
591
+ stroke: "currentColor",
592
+ strokeWidth: "2",
593
+ strokeLinecap: "round",
594
+ strokeLinejoin: "round",
595
+ width: "16",
596
+ height: "16"
597
+ }, props), /*#__PURE__*/React.createElement("path", {
598
+ d: "M6 9l6 6 6-6"
599
+ })));
600
+
601
+ function _extends$4() {
602
+ _extends$4 = Object.assign ? Object.assign.bind() : function (target) {
603
+ for (var i = 1; i < arguments.length; i++) {
604
+ var source = arguments[i];
605
+ for (var key in source) {
606
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
607
+ target[key] = source[key];
608
+ }
609
+ }
610
+ }
611
+ return target;
612
+ };
613
+ return _extends$4.apply(this, arguments);
614
+ }
615
+ var HideCommentsIcon = (({
616
+ styles = {},
617
+ ...props
618
+ }) => /*#__PURE__*/React.createElement("svg", _extends$4({
619
+ xmlns: "http://www.w3.org/2000/svg",
620
+ viewBox: "0 0 24 24",
621
+ fill: "none",
622
+ stroke: "currentColor",
623
+ strokeWidth: "2",
624
+ strokeLinecap: "round",
625
+ strokeLinejoin: "round",
626
+ width: "16",
627
+ height: "16"
628
+ }, props), /*#__PURE__*/React.createElement("path", {
629
+ d: "M17.94 17.94A10.07 10.07 0 0112 20c-7 0-11-8-11-8a18.45 18.45 0 015.06-5.94M9.9 4.24A9.12 9.12 0 0112 4c7 0 11 8 11 8a18.5 18.5 0 01-2.16 3.19m-6.72-1.07a3 3 0 11-4.24-4.24M1 1l22 22"
630
+ })));
631
+
632
+ function _extends$5() {
633
+ _extends$5 = Object.assign ? Object.assign.bind() : function (target) {
634
+ for (var i = 1; i < arguments.length; i++) {
635
+ var source = arguments[i];
636
+ for (var key in source) {
637
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
638
+ target[key] = source[key];
639
+ }
640
+ }
641
+ }
642
+ return target;
643
+ };
644
+ return _extends$5.apply(this, arguments);
645
+ }
646
+ var ShowCommentsIcon = (({
647
+ styles = {},
648
+ ...props
649
+ }) => /*#__PURE__*/React.createElement("svg", _extends$5({
650
+ xmlns: "http://www.w3.org/2000/svg",
651
+ viewBox: "0 0 24 24",
652
+ fill: "none",
653
+ stroke: "currentColor",
654
+ strokeWidth: "2",
655
+ strokeLinecap: "round",
656
+ strokeLinejoin: "round",
657
+ width: "16",
658
+ height: "16"
659
+ }, props), /*#__PURE__*/React.createElement("path", {
660
+ d: "M21 11.5a8.38 8.38 0 01-.9 3.8 8.5 8.5 0 01-7.6 4.7 8.38 8.38 0 01-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 01-.9-3.8 8.5 8.5 0 014.7-7.6 8.38 8.38 0 013.8-.9h.5a8.48 8.48 0 018 8v.5z"
661
+ })));
662
+
663
+ function FloatingToolbar() {
664
+ const {
665
+ t
666
+ } = useI18n({
667
+ locale: 'ui'
668
+ });
669
+ const {
670
+ visible
671
+ } = useCommentingVisibility();
672
+ const {
673
+ active,
674
+ deactivate
675
+ } = useAddCommentMode();
676
+ useEffect(() => {
677
+ if (!visible && active) {
678
+ deactivate();
679
+ }
680
+ }, [visible, active, deactivate]);
681
+ if (!visible) {
682
+ return /*#__PURE__*/React.createElement(ShowCommentsButton, null);
683
+ }
684
+ return /*#__PURE__*/React.createElement("div", {
685
+ className: styles.toolbar,
686
+ role: "group",
687
+ "aria-label": t('pageflow_scrolled.review.comment_toolbar'),
688
+ "data-comment-toolbar": true
689
+ }, /*#__PURE__*/React.createElement(PositionIndicator, null), /*#__PURE__*/React.createElement(ResolutionToggleButton, null), /*#__PURE__*/React.createElement(NavigationArrows, null), /*#__PURE__*/React.createElement(ActivityButton, null), /*#__PURE__*/React.createElement(HideCommentsButton, null), /*#__PURE__*/React.createElement(AddCommentButton, null));
690
+ }
691
+ function HideCommentsButton() {
692
+ const {
693
+ t
694
+ } = useI18n({
695
+ locale: 'ui'
696
+ });
697
+ const {
698
+ toggle
699
+ } = useCommentingVisibility();
700
+ const label = t('pageflow_scrolled.review.hide_comments');
701
+ return /*#__PURE__*/React.createElement("button", {
702
+ className: styles.button,
703
+ onClick: toggle,
704
+ "aria-label": label,
705
+ title: label
706
+ }, /*#__PURE__*/React.createElement(HideCommentsIcon, {
707
+ className: styles.toggleIcon
708
+ }));
709
+ }
710
+ function ShowCommentsButton() {
711
+ const {
712
+ t
713
+ } = useI18n({
714
+ locale: 'ui'
715
+ });
716
+ const {
717
+ toggle
718
+ } = useCommentingVisibility();
719
+ const unreadCount = useUnreadThreadCount();
720
+ const unread = unreadCount > 0;
721
+ const label = unread ? t('pageflow_scrolled.review.show_comments_with_unread', {
722
+ count: unreadCount
723
+ }) : t('pageflow_scrolled.review.show_comments');
724
+ return /*#__PURE__*/React.createElement("button", {
725
+ className: styles.puck,
726
+ onClick: toggle,
727
+ "aria-label": label,
728
+ title: label
729
+ }, /*#__PURE__*/React.createElement(ShowCommentsIcon, {
730
+ className: styles.toggleIcon
731
+ }), unread && /*#__PURE__*/React.createElement("span", {
732
+ className: styles.unreadDot
733
+ }));
734
+ }
735
+ function PositionIndicator() {
736
+ const {
737
+ t
738
+ } = useI18n({
739
+ locale: 'ui'
740
+ });
741
+ const {
742
+ count,
743
+ position
744
+ } = useCommentNavigation();
745
+ return /*#__PURE__*/React.createElement("span", {
746
+ className: styles.count,
747
+ title: t('pageflow_scrolled.review.comment_count', {
748
+ count
749
+ })
750
+ }, position || '–', " /");
751
+ }
752
+ function NavigationArrows() {
753
+ const {
754
+ t
755
+ } = useI18n({
756
+ locale: 'ui'
757
+ });
758
+ const {
759
+ count,
760
+ goToPrevious,
761
+ goToNext
762
+ } = useCommentNavigation();
763
+ return /*#__PURE__*/React.createElement("div", {
764
+ className: styles.navigation
765
+ }, /*#__PURE__*/React.createElement("button", {
766
+ className: styles.button,
767
+ onClick: goToPrevious,
768
+ disabled: count === 0,
769
+ "aria-label": t('pageflow_scrolled.review.previous_comment'),
770
+ title: t('pageflow_scrolled.review.previous_comment')
771
+ }, /*#__PURE__*/React.createElement(ChevronIcon, {
772
+ className: styles.chevronUp
773
+ })), /*#__PURE__*/React.createElement("button", {
774
+ className: styles.button,
775
+ onClick: goToNext,
776
+ disabled: count === 0,
777
+ "aria-label": t('pageflow_scrolled.review.next_comment'),
778
+ title: t('pageflow_scrolled.review.next_comment')
779
+ }, /*#__PURE__*/React.createElement(ChevronIcon, {
780
+ className: styles.chevronDown
781
+ })));
782
+ }
783
+ const resolutions = ['unresolved', 'all'];
784
+ function ResolutionToggleButton() {
785
+ const {
786
+ t
787
+ } = useI18n({
788
+ locale: 'ui'
789
+ });
790
+ const {
791
+ resolution,
792
+ setResolution
793
+ } = useCommentDisplayFilter();
794
+ const {
795
+ threads
796
+ } = useLocatedCommentThreads();
797
+ const counts = {
798
+ unresolved: threads.filter(thread => !thread.resolvedAt).length,
799
+ all: threads.length
800
+ };
801
+ return /*#__PURE__*/React.createElement("div", {
802
+ className: styles.segmented,
803
+ role: "group",
804
+ "aria-label": t('pageflow_scrolled.review.filter.label')
805
+ }, resolutions.map(value => /*#__PURE__*/React.createElement("button", {
806
+ key: value,
807
+ type: "button",
808
+ className: styles.segment,
809
+ "aria-pressed": resolution === value,
810
+ onClick: () => setResolution(value)
811
+ }, t(`pageflow_scrolled.review.filter.${value}`), /*#__PURE__*/React.createElement("span", {
812
+ className: styles.segmentCount,
813
+ "aria-hidden": "true"
814
+ }, counts[value]))));
815
+ }
816
+ function AddCommentButton() {
817
+ const {
818
+ t
819
+ } = useI18n({
820
+ locale: 'ui'
821
+ });
822
+ const {
823
+ active,
824
+ toggle
825
+ } = useAddCommentMode();
826
+ const Icon = active ? CancelCommentIcon : AddCommentIcon;
827
+ const label = t(active ? 'pageflow_scrolled.review.cancel_add_comment' : 'pageflow_scrolled.review.add_comment');
828
+ return /*#__PURE__*/React.createElement("button", {
829
+ className: classNames(styles.button, styles.addButton),
830
+ onClick: toggle,
831
+ "data-add-comment-toggle": true,
832
+ "aria-label": label,
833
+ title: label
834
+ }, /*#__PURE__*/React.createElement(Icon, null));
835
+ }
836
+
837
+ const resolutionStorageKey = 'pageflow.scrolled.commentsResolution';
838
+ function EntryDecorator({
839
+ commentingInitialState,
840
+ children
841
+ }) {
842
+ const commentDisplayFilter = useStoredCommentDisplayFilter(resolutionStorageKey);
843
+ return /*#__PURE__*/React.createElement(ReviewStateProvider, {
844
+ initialState: commentingInitialState
845
+ }, /*#__PURE__*/React.createElement(ReviewSessionSetup, {
846
+ initialState: commentingInitialState
847
+ }), /*#__PURE__*/React.createElement(LocatedCommentThreadsProvider, null, /*#__PURE__*/React.createElement(CommentingVisibilityProvider, null, /*#__PURE__*/React.createElement(CommentDisplayFilterProvider, commentDisplayFilter, /*#__PURE__*/React.createElement(SelectedSubjectProvider, null, /*#__PURE__*/React.createElement(AddCommentModeProvider, null, children, /*#__PURE__*/React.createElement(FloatingToolbar, null)))))));
848
+ }
849
+ function ReviewSessionSetup({
850
+ initialState
851
+ }) {
852
+ const entryMetadata = useEntryMetadata();
853
+ const entryId = entryMetadata === null || entryMetadata === void 0 ? void 0 : entryMetadata.id;
854
+ useEffect(() => {
855
+ if (!entryId) return;
856
+ const session = createReviewSession({
857
+ entryId,
858
+ initialState
859
+ });
860
+ const handler = ReviewMessageHandler.create({
861
+ session,
862
+ targetWindow: window
863
+ });
864
+ if (!initialState) {
865
+ session.fetch();
866
+ }
867
+ return () => handler.dispose();
868
+ }, [entryId, initialState]);
869
+ return null;
870
+ }
871
+
872
+ var styles$2 = {"badge":"Popover-module_badge__16NvD","threadList":"Popover-module_threadList__2nA5p"};
873
+
874
+ function Popover({
875
+ subjectType,
876
+ subjectId,
877
+ subjectRange,
878
+ placement = 'bottom-start',
879
+ strategy = 'absolute',
880
+ hideNewTopicButton
881
+ }) {
882
+ const {
883
+ isSelected,
884
+ revealOnly,
885
+ showNewForm,
886
+ select,
887
+ clearSelection,
888
+ highlightedThreadId
889
+ } = useSelectedSubject(subjectType, subjectId, subjectRange);
890
+ const {
891
+ resolution
892
+ } = useCommentDisplayFilter();
893
+ const [reference, setReference] = useState(null);
894
+ useEffect(() => {
895
+ if (isSelected && highlightedThreadId != null) {
896
+ reference === null || reference === void 0 ? void 0 : reference.scrollIntoView({
897
+ block: 'center',
898
+ behavior: 'smooth'
899
+ });
900
+ }
901
+ }, [isSelected, highlightedThreadId, reference]);
902
+ function handleBadgeClick() {
903
+ if (isSelected && !revealOnly) {
904
+ clearSelection();
905
+ } else {
906
+ select(revealOnly ? {
907
+ highlightedThreadId
908
+ } : undefined);
909
+ }
910
+ }
911
+ return /*#__PURE__*/React.createElement("span", {
912
+ ref: setReference,
913
+ className: styles$2.badge
914
+ }, /*#__PURE__*/React.createElement(ThreadsBadge, {
915
+ subjectType: subjectType,
916
+ subjectId: subjectId,
917
+ subjectRange: subjectRange,
918
+ resolution: resolution,
919
+ revealedThreadId: highlightedThreadId,
920
+ mode: isSelected ? 'active' : undefined,
921
+ onClick: handleBadgeClick
922
+ }), isSelected && !revealOnly && /*#__PURE__*/React.createElement(OpenThreadList, {
923
+ reference: reference,
924
+ subjectType: subjectType,
925
+ subjectId: subjectId,
926
+ subjectRange: subjectRange,
927
+ placement: placement,
928
+ strategy: strategy,
929
+ showNewForm: showNewForm,
930
+ hideNewTopicButton: hideNewTopicButton,
931
+ highlightedThreadId: highlightedThreadId,
932
+ expandResolved: resolution === 'all',
933
+ onDismiss: clearSelection
934
+ }));
935
+ }
936
+ function OpenThreadList({
937
+ reference,
938
+ subjectType,
939
+ subjectId,
940
+ subjectRange,
941
+ placement,
942
+ strategy,
943
+ showNewForm,
944
+ hideNewTopicButton,
945
+ highlightedThreadId,
946
+ expandResolved,
947
+ onDismiss
948
+ }) {
949
+ const portalRoot = useFloatingPortalRoot();
950
+ const {
951
+ refs,
952
+ floatingStyles
953
+ } = useFloating({
954
+ open: true,
955
+ elements: {
956
+ reference
957
+ },
958
+ placement,
959
+ strategy,
960
+ middleware: [offset(8), flip({
961
+ fallbackPlacements: [placement.startsWith('top') ? 'bottom-start' : 'top-start'],
962
+ rootBoundary: 'document'
963
+ }), shift({
964
+ padding: 8
965
+ })],
966
+ whileElementsMounted: autoUpdate
967
+ });
968
+ useEffect(() => {
969
+ function handleClick(event) {
970
+ var _refs$floating$curren;
971
+ if (reference === null || reference === void 0 ? void 0 : reference.contains(event.target)) return;
972
+ if ((_refs$floating$curren = refs.floating.current) === null || _refs$floating$curren === void 0 ? void 0 : _refs$floating$curren.contains(event.target)) return;
973
+ if (event.target.closest('[data-comment-highlight]')) return;
974
+ if (event.target.closest('[data-comment-toolbar]')) return;
975
+ if (event.target.closest('[data-comment-menu]')) return;
976
+ onDismiss();
977
+ }
978
+ function handleKeyDown(event) {
979
+ if (event.key === 'Escape') {
980
+ onDismiss();
981
+ }
982
+ }
983
+ document.addEventListener('mousedown', handleClick);
984
+ document.addEventListener('keydown', handleKeyDown);
985
+ return () => {
986
+ document.removeEventListener('mousedown', handleClick);
987
+ document.removeEventListener('keydown', handleKeyDown);
988
+ };
989
+ }, [reference, refs.floating, onDismiss]);
990
+ return /*#__PURE__*/React.createElement(FloatingPortal, {
991
+ root: portalRoot
992
+ }, /*#__PURE__*/React.createElement("div", {
993
+ ref: refs.setFloating,
994
+ "data-floating-raised": true,
995
+ className: styles$2.threadList,
996
+ style: floatingStyles
997
+ }, /*#__PURE__*/React.createElement(ThreadList, {
998
+ subjectType: subjectType,
999
+ subjectId: subjectId,
1000
+ subjectRange: subjectRange,
1001
+ highlightedThreadId: highlightedThreadId,
1002
+ expandResolved: expandResolved,
1003
+ showNewForm: showNewForm,
1004
+ hideNewTopicButton: hideNewTopicButton
1005
+ })));
1006
+ }
1007
+
1008
+ var styles$3 = {"wrapper":"SectionDecorator-module_wrapper__3oQuz","commentBadge":"SectionDecorator-module_commentBadge__2MYch","sticky":"SectionDecorator-module_sticky__M1Elo","addButton":"SectionDecorator-module_addButton__3-FuB","pill":"SectionDecorator-module_pill__1wMMW AddCommentOverlay-module_pill__K6tzV"};
1009
+
1010
+ function SectionDecorator({
1011
+ section,
1012
+ children
1013
+ }) {
1014
+ const {
1015
+ visible
1016
+ } = useCommentingVisibility();
1017
+ const {
1018
+ active
1019
+ } = useAddCommentMode();
1020
+ const {
1021
+ isSelected,
1022
+ highlightedThreadId
1023
+ } = useSelectedSubject('Section', section.permaId);
1024
+ const {
1025
+ resolution
1026
+ } = useCommentDisplayFilter();
1027
+ const threads = useLocatedCommentThreadsForSubject({
1028
+ subjectType: 'Section',
1029
+ subjectId: section.permaId,
1030
+ resolution,
1031
+ revealedThreadId: highlightedThreadId
1032
+ });
1033
+ const hasThreads = threads.length > 0;
1034
+ if (!visible) {
1035
+ return children;
1036
+ }
1037
+ return /*#__PURE__*/React.createElement("div", {
1038
+ className: styles$3.wrapper
1039
+ }, children, /*#__PURE__*/React.createElement("div", {
1040
+ className: classNames(styles$3.commentBadge, {
1041
+ [styles$3.sticky]: hasThreads || active || isSelected
1042
+ })
1043
+ }, active ? /*#__PURE__*/React.createElement(AddCommentButton$1, {
1044
+ permaId: section.permaId
1045
+ }) : /*#__PURE__*/React.createElement(Popover, {
1046
+ subjectType: "Section",
1047
+ subjectId: section.permaId,
1048
+ placement: "top-start",
1049
+ strategy: "fixed"
1050
+ })));
1051
+ }
1052
+ function AddCommentButton$1({
1053
+ permaId
1054
+ }) {
1055
+ const {
1056
+ t
1057
+ } = useI18n({
1058
+ locale: 'ui'
1059
+ });
1060
+ const {
1061
+ deactivate
1062
+ } = useAddCommentMode();
1063
+ const {
1064
+ select
1065
+ } = useSelectedSubject('Section', permaId);
1066
+ function handleClick() {
1067
+ select({
1068
+ showNewForm: true
1069
+ });
1070
+ deactivate();
1071
+ }
1072
+ return /*#__PURE__*/React.createElement("button", {
1073
+ "data-add-comment-overlay": true,
1074
+ onClick: handleClick,
1075
+ className: styles$3.addButton,
1076
+ "aria-label": t('pageflow_scrolled.review.select_section')
1077
+ }, /*#__PURE__*/React.createElement("span", {
1078
+ className: styles$3.pill
1079
+ }, /*#__PURE__*/React.createElement(AddCommentIcon, null)));
1080
+ }
1081
+
1082
+ var styles$4 = {"highlight":"AddCommentOverlay-module_highlight__1VAyf","pill":"AddCommentOverlay-module_pill__K6tzV"};
1083
+
1084
+ function AddCommentOverlay({
1085
+ permaId
1086
+ }) {
1087
+ const {
1088
+ t
1089
+ } = useI18n({
1090
+ locale: 'ui'
1091
+ });
1092
+ const {
1093
+ active,
1094
+ deactivate
1095
+ } = useAddCommentMode();
1096
+ const {
1097
+ select
1098
+ } = useSelectedSubject('ContentElement', permaId);
1099
+ if (!active) return null;
1100
+ function handleClick() {
1101
+ select({
1102
+ showNewForm: true
1103
+ });
1104
+ deactivate();
1105
+ }
1106
+ return /*#__PURE__*/React.createElement("button", {
1107
+ onClick: handleClick,
1108
+ "data-add-comment-overlay": true,
1109
+ className: styles$4.highlight,
1110
+ "aria-label": t('pageflow_scrolled.review.select_content_element'),
1111
+ title: t('pageflow_scrolled.review.select_content_element')
1112
+ }, /*#__PURE__*/React.createElement("span", {
1113
+ className: styles$4.pill
1114
+ }, /*#__PURE__*/React.createElement(AddCommentIcon, null)));
1115
+ }
1116
+
1117
+ var styles$5 = {"wrapper":"ContentElementDecorator-module_wrapper__omtl-","selected":"ContentElementDecorator-module_selected__1xIK9","badge":"ContentElementDecorator-module_badge__3RBr6","badgeFlush":"ContentElementDecorator-module_badgeFlush__1lR32"};
1118
+
1119
+ function ContentElementDecorator({
1120
+ type,
1121
+ width,
1122
+ customMargin,
1123
+ permaId,
1124
+ children
1125
+ }) {
1126
+ const {
1127
+ inlineComments
1128
+ } = api.contentElementTypes.getOptions(type) || {};
1129
+ if (inlineComments) {
1130
+ return children;
1131
+ }
1132
+ return /*#__PURE__*/React.createElement(DefaultCommentDecorator, {
1133
+ permaId: permaId,
1134
+ flush: width === widths.full || customMargin
1135
+ }, children);
1136
+ }
1137
+ function DefaultCommentDecorator({
1138
+ permaId,
1139
+ flush,
1140
+ children
1141
+ }) {
1142
+ const {
1143
+ visible
1144
+ } = useCommentingVisibility();
1145
+ const {
1146
+ active
1147
+ } = useAddCommentMode();
1148
+ const {
1149
+ isSelected
1150
+ } = useSelectedSubject('ContentElement', permaId);
1151
+ if (!visible) {
1152
+ return children;
1153
+ }
1154
+ return /*#__PURE__*/React.createElement("div", {
1155
+ className: classNames(styles$5.wrapper, {
1156
+ [styles$5.selected]: isSelected
1157
+ })
1158
+ }, /*#__PURE__*/React.createElement("div", {
1159
+ inert: active ? '' : undefined
1160
+ }, children), /*#__PURE__*/React.createElement(AddCommentOverlay, {
1161
+ permaId: permaId
1162
+ }), /*#__PURE__*/React.createElement("div", {
1163
+ className: classNames(styles$5.badge, {
1164
+ [styles$5.badgeFlush]: flush
1165
+ })
1166
+ }, /*#__PURE__*/React.createElement(Popover, {
1167
+ subjectType: "ContentElement",
1168
+ subjectId: permaId
1169
+ })));
1170
+ }
1171
+
1172
+ var styles$6 = {"hint":"AddCommentHint-module_hint__1tsMa","tooltip":"AddCommentHint-module_tooltip__28laa"};
1173
+
1174
+ function AddCommentHint() {
1175
+ const {
1176
+ t
1177
+ } = useI18n({
1178
+ locale: 'ui'
1179
+ });
1180
+ return /*#__PURE__*/React.createElement("div", {
1181
+ className: styles$6.hint
1182
+ }, /*#__PURE__*/React.createElement("span", {
1183
+ className: styles$6.tooltip
1184
+ }, t('pageflow_scrolled.review.select_text_to_comment')));
1185
+ }
1186
+
1187
+ var styles$7 = {"floating":"PopoversColumn-module_floating__2fpOt"};
1188
+
1189
+ function PopoversColumn({
1190
+ highlights,
1191
+ anchors
1192
+ }) {
1193
+ return highlights.map(highlight => /*#__PURE__*/React.createElement(PositionedPopover, {
1194
+ key: highlight.key,
1195
+ rangeKey: highlight.key,
1196
+ subjectRange: highlight.range,
1197
+ anchors: anchors
1198
+ }));
1199
+ }
1200
+ function PositionedPopover({
1201
+ rangeKey,
1202
+ subjectRange,
1203
+ anchors
1204
+ }) {
1205
+ const {
1206
+ contentElementPermaId
1207
+ } = useContentElementAttributes();
1208
+ const {
1209
+ refs,
1210
+ floatingStyles,
1211
+ hasAnchor
1212
+ } = useAnchoredFloating(rangeKey, anchors, {
1213
+ placement: 'left-end'
1214
+ });
1215
+ if (!hasAnchor) return null;
1216
+ return /*#__PURE__*/React.createElement("div", {
1217
+ ref: refs.setFloating,
1218
+ className: styles$7.floating,
1219
+ style: floatingStyles
1220
+ }, /*#__PURE__*/React.createElement(Popover, {
1221
+ subjectType: "ContentElement",
1222
+ subjectId: contentElementPermaId,
1223
+ subjectRange: subjectRange,
1224
+ hideNewTopicButton: true
1225
+ }));
1226
+ }
1227
+
1228
+ const slateSelection = {
1229
+ inEditor(editor) {
1230
+ const domSelection = window.getSelection();
1231
+ if (!domSelection || !domSelection.anchorNode || !domSelection.focusNode || domSelection.isCollapsed) return null;
1232
+ if (!ReactEditor.hasDOMNode(editor, domSelection.anchorNode) || !ReactEditor.hasDOMNode(editor, domSelection.focusNode)) return null;
1233
+ try {
1234
+ return ReactEditor.toSlateRange(editor, domSelection);
1235
+ } catch (e) {
1236
+ return null;
1237
+ }
1238
+ }
1239
+ };
1240
+
1241
+ var commentingStyles = {"activeOverlay":"EditableTextHighlight-module_activeOverlay__6krun","clickable":"EditableTextHighlight-module_clickable__1nF8U"};
1242
+
1243
+ const defaultValue = [{
1244
+ type: 'paragraph',
1245
+ children: [{
1246
+ text: ''
1247
+ }]
1248
+ }];
1249
+ const EditableText = React.memo(function EditableText(props) {
1250
+ const {
1251
+ inlineComments
1252
+ } = useContentElementAttributes();
1253
+ const {
1254
+ visible
1255
+ } = useCommentingVisibility();
1256
+ if (inlineComments && visible) {
1257
+ return /*#__PURE__*/React.createElement(CommentingEditableText, props);
1258
+ }
1259
+ return /*#__PURE__*/React.createElement(PlainEditableText, props);
1260
+ });
1261
+ function CommentingEditableText({
1262
+ value,
1263
+ className,
1264
+ scaleCategory = 'body',
1265
+ typographyVariant,
1266
+ typographySize
1267
+ }) {
1268
+ const editor = useMemo(() => withLinks(withReact(createEditor())), []);
1269
+ const {
1270
+ anchors,
1271
+ registerAnchor
1272
+ } = useRangeAnchors();
1273
+ const {
1274
+ contentElementPermaId
1275
+ } = useContentElementAttributes();
1276
+ const {
1277
+ active,
1278
+ deactivate,
1279
+ preselect,
1280
+ clearPreselection
1281
+ } = useAddCommentMode();
1282
+ const {
1283
+ subjectRange,
1284
+ select,
1285
+ highlightedThreadId
1286
+ } = useSelectedSubject('ContentElement', contentElementPermaId);
1287
+ const {
1288
+ resolution
1289
+ } = useCommentDisplayFilter();
1290
+ const threads = useCommentThreads({
1291
+ subjectType: 'ContentElement',
1292
+ subjectId: contentElementPermaId,
1293
+ resolution,
1294
+ revealedThreadId: highlightedThreadId
1295
+ });
1296
+ const highlights = useCommentHighlights(threads, subjectRange);
1297
+ usePreselection(editor, contentElementPermaId, threads, active, preselect, clearPreselection);
1298
+ const handleMouseUp = useSelectTextOnMouseUp(active, editor, threads, deactivate, select);
1299
+ const decorate = useMemo(() => decorateCommentHighlights(editor, highlights), [editor, highlights]);
1300
+ const renderLeafCb = useCallback(({
1301
+ attributes,
1302
+ children,
1303
+ leaf
1304
+ }) => {
1305
+ if (leaf.commentHighlight) {
1306
+ children = /*#__PURE__*/React.createElement(ClickableHighlight, {
1307
+ subjectRange: leaf.subjectRange
1308
+ }, children);
1309
+ }
1310
+ if (leaf.lastInRange) {
1311
+ children = /*#__PURE__*/React.createElement(RangeAnchor, {
1312
+ rangeKey: leaf.rangeKey,
1313
+ onRegister: registerAnchor
1314
+ }, children);
1315
+ }
1316
+ return renderLeaf({
1317
+ attributes,
1318
+ children,
1319
+ leaf
1320
+ });
1321
+ }, [registerAnchor]);
1322
+ return /*#__PURE__*/React.createElement("div", {
1323
+ ref: anchors.containerRef,
1324
+ className: classNames(textStyles.root, className, {
1325
+ [commentingStyles.activeOverlay]: active && !subjectRange
1326
+ }),
1327
+ "data-add-comment-overlay": true,
1328
+ style: {
1329
+ position: 'relative'
1330
+ }
1331
+ }, /*#__PURE__*/React.createElement(Text, {
1332
+ scaleCategory: scaleCategory,
1333
+ typographyVariant: typographyVariant,
1334
+ typographySize: typographySize
1335
+ }, /*#__PURE__*/React.createElement(Slate, {
1336
+ editor: editor,
1337
+ value: value || defaultValue,
1338
+ onChange: () => {}
1339
+ }, /*#__PURE__*/React.createElement(Editable, {
1340
+ key: (subjectRange ? 'highlighted' : 'plain') + threads.length,
1341
+ onMouseUp: handleMouseUp,
1342
+ readOnly: true,
1343
+ decorate: decorate,
1344
+ renderElement: renderElement,
1345
+ renderLeaf: renderLeafCb
1346
+ }))), active && !subjectRange && /*#__PURE__*/React.createElement(AddCommentHint, null), /*#__PURE__*/React.createElement(PopoversColumn, {
1347
+ highlights: highlights,
1348
+ anchors: anchors
1349
+ }));
1350
+ }
1351
+ function ClickableHighlight({
1352
+ subjectRange,
1353
+ children
1354
+ }) {
1355
+ const {
1356
+ contentElementPermaId
1357
+ } = useContentElementAttributes();
1358
+ const {
1359
+ deactivate
1360
+ } = useAddCommentMode();
1361
+ const {
1362
+ isSelected,
1363
+ revealOnly,
1364
+ select,
1365
+ highlightedThreadId
1366
+ } = useSelectedSubject('ContentElement', contentElementPermaId, subjectRange);
1367
+ function handleClick(event) {
1368
+ if (event.target.closest('a')) return;
1369
+ if (isSelected && !revealOnly) return;
1370
+ deactivate();
1371
+ select(revealOnly ? {
1372
+ highlightedThreadId
1373
+ } : undefined);
1374
+ }
1375
+ return /*#__PURE__*/React.createElement("span", {
1376
+ className: classNames(commentHighlightStyles.highlight, {
1377
+ [commentHighlightStyles.selected]: isSelected,
1378
+ [commentingStyles.clickable]: !isSelected || revealOnly
1379
+ }),
1380
+ "data-comment-highlight": true,
1381
+ onClick: handleClick
1382
+ }, children);
1383
+ }
1384
+ function useSelectTextOnMouseUp(active, editor, threads, deactivate, select) {
1385
+ return useCallback(event => {
1386
+ if (!active) return;
1387
+ const slateRange = slateSelection.inEditor(editor) || topLevelRangeFromEvent(editor, event);
1388
+ if (!slateRange) return;
1389
+ const matchingThread = findMatchingThread(threads, slateRange);
1390
+ deactivate();
1391
+ select({
1392
+ subjectRange: (matchingThread === null || matchingThread === void 0 ? void 0 : matchingThread.subjectRange) || slateRange,
1393
+ showNewForm: !matchingThread
1394
+ });
1395
+ }, [active, editor, threads, deactivate, select]);
1396
+ }
1397
+ function topLevelRangeFromEvent(editor, event) {
1398
+ if (event.target.closest('a')) return null;
1399
+ if (event.target.closest('[data-comment-highlight]')) return null;
1400
+ try {
1401
+ const node = ReactEditor.toSlateNode(editor, event.target);
1402
+ const path = ReactEditor.findPath(editor, node);
1403
+ if (!path.length) return null;
1404
+ return Editor.range(editor, [path[0]]);
1405
+ } catch (e) {
1406
+ return null;
1407
+ }
1408
+ }
1409
+ function usePreselection(editor, contentElementPermaId, threads, active, preselect, clearPreselection) {
1410
+ useEffect(() => {
1411
+ function handleSelectionChange() {
1412
+ if (active) return;
1413
+ const slateRange = slateSelection.inEditor(editor);
1414
+ if (slateRange) {
1415
+ const matchingThread = findMatchingThread(threads, slateRange);
1416
+ preselect({
1417
+ subjectType: 'ContentElement',
1418
+ subjectId: contentElementPermaId,
1419
+ subjectRange: (matchingThread === null || matchingThread === void 0 ? void 0 : matchingThread.subjectRange) || slateRange,
1420
+ showNewForm: !matchingThread
1421
+ });
1422
+ } else {
1423
+ clearPreselection(contentElementPermaId);
1424
+ }
1425
+ }
1426
+ document.addEventListener('selectionchange', handleSelectionChange);
1427
+ return () => document.removeEventListener('selectionchange', handleSelectionChange);
1428
+ }, [editor, contentElementPermaId, threads, active, preselect, clearPreselection]);
1429
+ }
1430
+ function findMatchingThread(threads, slateRange) {
1431
+ const key = JSON.stringify(slateRange);
1432
+ return threads.find(t => JSON.stringify(t.subjectRange) === key);
1433
+ }
1434
+ function withLinks(editor) {
1435
+ const {
1436
+ isInline
1437
+ } = editor;
1438
+ editor.isInline = element => {
1439
+ return element.type === 'link' ? true : isInline(element);
1440
+ };
1441
+ return editor;
1442
+ }
1443
+
1444
+ const extensions = {
1445
+ decorators: {
1446
+ Entry: EntryDecorator,
1447
+ Section: SectionDecorator,
1448
+ ContentElement: ContentElementDecorator
1449
+ },
1450
+ alternatives: {
1451
+ EditableText
1452
+ }
1453
+ };
1454
+
1455
+ export { extensions };