@plone/volto 19.0.0-alpha.0 → 19.0.0-alpha.10

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 (367) hide show
  1. package/.eslintignore +2 -0
  2. package/.eslintrc +37 -0
  3. package/CHANGELOG.md +274 -2
  4. package/README.md +3 -6
  5. package/cypress/docker/prefixed-rules.yml +26 -0
  6. package/cypress/docker/prefixed.yml +24 -0
  7. package/cypress/support/commands.js +12 -6
  8. package/cypress/support/guillotina.js +1 -0
  9. package/cypress.config.js +1 -0
  10. package/locales/af.json +1 -0
  11. package/locales/ar.json +1 -0
  12. package/locales/bg.json +1 -0
  13. package/locales/bn.json +1 -0
  14. package/locales/ca/LC_MESSAGES/volto.po +96 -17
  15. package/locales/ca.json +1 -1
  16. package/locales/cs.json +1 -0
  17. package/locales/cy.json +1 -0
  18. package/locales/da.json +1 -0
  19. package/locales/de/LC_MESSAGES/volto.po +104 -25
  20. package/locales/de.json +1 -1
  21. package/locales/el.json +1 -0
  22. package/locales/en/LC_MESSAGES/volto.po +97 -18
  23. package/locales/en.json +1 -1
  24. package/locales/en_AU.json +1 -0
  25. package/locales/en_GB.json +1 -0
  26. package/locales/eo.json +1 -0
  27. package/locales/es/LC_MESSAGES/volto.po +97 -18
  28. package/locales/es.json +1 -1
  29. package/locales/et.json +1 -0
  30. package/locales/eu/LC_MESSAGES/volto.po +96 -17
  31. package/locales/eu.json +1 -1
  32. package/locales/fa.json +1 -0
  33. package/locales/fi/LC_MESSAGES/volto.po +96 -17
  34. package/locales/fi.json +1 -1
  35. package/locales/fr/LC_MESSAGES/volto.po +97 -18
  36. package/locales/fr.json +1 -1
  37. package/locales/fu.json +1 -0
  38. package/locales/gl.json +1 -0
  39. package/locales/he.json +1 -0
  40. package/locales/hi/LC_MESSAGES/volto.po +100 -21
  41. package/locales/hi.json +1 -1
  42. package/locales/hr.json +1 -0
  43. package/locales/hu.json +1 -0
  44. package/locales/hy.json +1 -0
  45. package/locales/id.json +1 -0
  46. package/locales/it/LC_MESSAGES/volto.po +101 -22
  47. package/locales/it.json +1 -1
  48. package/locales/ja/LC_MESSAGES/volto.po +96 -17
  49. package/locales/ja.json +1 -1
  50. package/locales/ka.json +1 -0
  51. package/locales/kn.json +1 -0
  52. package/locales/ko.json +1 -0
  53. package/locales/lt.json +1 -0
  54. package/locales/lv.json +1 -0
  55. package/locales/mi.json +1 -0
  56. package/locales/mk.json +1 -0
  57. package/locales/my.json +1 -0
  58. package/locales/nb_NO.json +1 -0
  59. package/locales/nl/LC_MESSAGES/volto.po +100 -21
  60. package/locales/nl.json +1 -1
  61. package/locales/nn.json +1 -0
  62. package/locales/pl.json +1 -0
  63. package/locales/pt/LC_MESSAGES/volto.po +96 -17
  64. package/locales/pt.json +1 -1
  65. package/locales/pt_BR/LC_MESSAGES/volto.po +116 -37
  66. package/locales/pt_BR.json +1 -1
  67. package/locales/rm.json +1 -0
  68. package/locales/ro/LC_MESSAGES/volto.po +100 -21
  69. package/locales/ro.json +1 -1
  70. package/locales/ru/LC_MESSAGES/volto.po +100 -21
  71. package/locales/ru.json +1 -1
  72. package/locales/sk.json +1 -0
  73. package/locales/sl.json +1 -0
  74. package/locales/sm.json +1 -0
  75. package/locales/sq.json +1 -0
  76. package/locales/sr.json +1 -0
  77. package/locales/sr@cyrl.json +1 -0
  78. package/locales/sr@latn.json +1 -0
  79. package/locales/sv.json +1 -1
  80. package/locales/ta.json +1 -0
  81. package/locales/te.json +1 -0
  82. package/locales/th.json +1 -0
  83. package/locales/to.json +1 -0
  84. package/locales/tr.json +1 -0
  85. package/locales/uk.json +1 -0
  86. package/locales/vi.json +1 -0
  87. package/locales/volto.pot +97 -18
  88. package/locales/zh_CN/LC_MESSAGES/volto.po +96 -17
  89. package/locales/zh_CN.json +1 -1
  90. package/locales/zh_Hant.json +1 -0
  91. package/locales/zh_Hant_HK.json +1 -0
  92. package/package.json +36 -27
  93. package/razzle.config.js +16 -0
  94. package/src/actions/actions/actions.test.js +3 -3
  95. package/src/actions/addons/addons.test.js +15 -12
  96. package/src/actions/aliases/aliases.test.js +1 -1
  97. package/src/actions/content/content.js +0 -1
  98. package/src/actions/controlpanels/controlpanels.js +13 -7
  99. package/src/actions/controlpanels/controlpanels.test.js +11 -5
  100. package/src/actions/querystring/querystring.test.js +2 -2
  101. package/src/actions/types/types.test.js +1 -1
  102. package/src/actions/users/users.js +2 -2
  103. package/src/components/manage/Actions/Actions.test.jsx +5 -1
  104. package/src/components/manage/Add/Add.jsx +27 -26
  105. package/src/components/manage/Add/Add.test.jsx +6 -3
  106. package/src/components/manage/Aliases/Aliases.test.jsx +7 -7
  107. package/src/components/manage/Blocks/Block/BlocksForm.jsx +1 -0
  108. package/src/components/manage/Blocks/Block/BlocksForm.test.jsx +48 -16
  109. package/src/components/manage/Blocks/Block/Edit.jsx +3 -1
  110. package/src/components/manage/Blocks/Block/EditBlockWrapper.jsx +9 -4
  111. package/src/components/manage/Blocks/Block/Settings.test.jsx +5 -1
  112. package/src/components/manage/Blocks/Block/StyleWrapper.jsx +11 -3
  113. package/src/components/manage/Blocks/Description/View.test.jsx +1 -1
  114. package/src/components/manage/Blocks/HTML/Edit.test.jsx +12 -5
  115. package/src/components/manage/Blocks/HTML/View.test.jsx +1 -1
  116. package/src/components/manage/Blocks/Image/Edit.jsx +5 -1
  117. package/src/components/manage/Blocks/Image/ImageSidebar.test.jsx +6 -2
  118. package/src/components/manage/Blocks/LeadImage/Edit.jsx +2 -2
  119. package/src/components/manage/Blocks/LeadImage/LeadImageSidebar.jsx +1 -1
  120. package/src/components/manage/Blocks/LeadImage/LeadImageSidebar.test.jsx +8 -1
  121. package/src/components/manage/Blocks/Listing/ImageGallery.jsx +6 -4
  122. package/src/components/manage/Blocks/Listing/View.test.jsx +3 -1
  123. package/src/components/manage/Blocks/Maps/Edit.jsx +2 -1
  124. package/src/components/manage/Blocks/Maps/MapsSidebar.test.jsx +5 -1
  125. package/src/components/manage/Blocks/Search/SearchBlockView.jsx +21 -4
  126. package/src/components/manage/Blocks/Search/components/DateRangeFacet.test.jsx +13 -7
  127. package/src/components/manage/Blocks/Search/components/SelectFacet.test.jsx +12 -6
  128. package/src/components/manage/Blocks/Teaser/Data.jsx +21 -7
  129. package/src/components/manage/Blocks/Teaser/DefaultBody.jsx +1 -1
  130. package/src/components/manage/Blocks/Teaser/schema.js +8 -3
  131. package/src/components/manage/Blocks/Title/Edit.jsx +8 -2
  132. package/src/components/manage/Blocks/ToC/variations/DefaultTocRenderer.test.jsx +11 -1
  133. package/src/components/manage/Blocks/Video/Edit.jsx +2 -1
  134. package/src/components/manage/Blocks/Video/VideoSidebar.test.jsx +5 -1
  135. package/src/components/manage/ConditionalLink/ConditionalLink.test.tsx +109 -0
  136. package/src/components/manage/ConditionalLink/ConditionalLink.tsx +36 -0
  137. package/src/components/manage/Contents/Contents.jsx +23 -2
  138. package/src/components/manage/Contents/Contents.test.jsx +36 -13
  139. package/src/components/manage/Contents/ContentsBreadcrumbs.Multilingual.test.jsx +18 -5
  140. package/src/components/manage/Contents/ContentsBreadcrumbs.jsx +20 -26
  141. package/src/components/manage/Contents/ContentsBreadcrumbs.test.jsx +14 -0
  142. package/src/components/manage/Contents/ContentsDeleteModal.jsx +258 -206
  143. package/src/components/manage/Contents/ContentsDeleteModal.stories.jsx +26 -8
  144. package/src/components/manage/Contents/ContentsItem.jsx +10 -2
  145. package/src/components/manage/Contents/ContentsPropertiesModal.test.jsx +5 -1
  146. package/src/components/manage/Contents/ContentsRenameModal.test.jsx +5 -1
  147. package/src/components/manage/Contents/ContentsTagsModal.test.jsx +5 -1
  148. package/src/components/manage/Contents/ContentsUploadModal.test.jsx +13 -22
  149. package/src/components/manage/Contents/ContentsWorkflowModal.test.jsx +5 -1
  150. package/src/components/manage/Contents/__mocks__/index.tsx +16 -0
  151. package/src/components/manage/Contents/__mocks__/index.vitest.tsx +5 -0
  152. package/src/components/manage/Controlpanels/AddonsControlpanel.test.jsx +28 -3
  153. package/src/components/manage/Controlpanels/Aliases.test.jsx +35 -3
  154. package/src/components/manage/Controlpanels/ContentType.jsx +1 -1
  155. package/src/components/manage/Controlpanels/ContentType.test.jsx +29 -3
  156. package/src/components/manage/Controlpanels/ContentTypeLayout.test.jsx +4 -2
  157. package/src/components/manage/Controlpanels/ContentTypes.test.jsx +25 -2
  158. package/src/components/manage/Controlpanels/Controlpanel.test.jsx +37 -6
  159. package/src/components/manage/Controlpanels/Controlpanels.test.jsx +47 -3
  160. package/src/components/manage/Controlpanels/Groups/GroupsControlpanel.jsx +3 -2
  161. package/src/components/manage/Controlpanels/Groups/GroupsControlpanel.test.jsx +15 -9
  162. package/src/components/manage/Controlpanels/ModerateComments.test.jsx +31 -5
  163. package/src/components/manage/Controlpanels/Rules/AddRule.test.jsx +13 -4
  164. package/src/components/manage/Controlpanels/Rules/ConfigureRule.test.jsx +9 -5
  165. package/src/components/manage/Controlpanels/Rules/EditRule.test.jsx +12 -4
  166. package/src/components/manage/Controlpanels/Rules/Rules.test.jsx +7 -3
  167. package/src/components/manage/Controlpanels/UndoControlpanel.test.jsx +33 -4
  168. package/src/components/manage/Controlpanels/Users/RenderUsers.jsx +156 -175
  169. package/src/components/manage/Controlpanels/Users/UserGroupMembershipControlPanel.test.jsx +3 -1
  170. package/src/components/manage/Controlpanels/Users/UsersControlpanel.jsx +575 -630
  171. package/src/components/manage/Controlpanels/Users/UsersControlpanel.test.jsx +16 -9
  172. package/src/components/manage/Delete/Delete.test.jsx +45 -4
  173. package/src/components/manage/Diff/Diff.test.jsx +15 -6
  174. package/src/components/manage/Diff/DiffField.test.jsx +12 -6
  175. package/src/components/manage/Display/Display.test.jsx +17 -6
  176. package/src/components/manage/Edit/Edit.jsx +2 -3
  177. package/src/components/manage/Edit/Edit.test.jsx +11 -3
  178. package/src/components/manage/Form/BlockDataForm.test.jsx +5 -1
  179. package/src/components/manage/Form/Form.jsx +32 -0
  180. package/src/components/manage/Form/Form.test.jsx +27 -19
  181. package/src/components/manage/Form/InlineForm.jsx +2 -2
  182. package/src/components/manage/Form/InlineForm.test.jsx +5 -1
  183. package/src/components/manage/Form/ModalForm.test.jsx +5 -1
  184. package/src/components/manage/Form/__mocks__/index.tsx +17 -0
  185. package/src/components/manage/Form/__mocks__/index.vitest.tsx +73 -0
  186. package/src/components/manage/History/History.test.jsx +3 -1
  187. package/src/components/manage/LinksToItem/LinksToItem.test.jsx +6 -4
  188. package/src/components/manage/MaybeWrap/MaybeWrap.tsx +15 -0
  189. package/src/components/manage/Multilingual/CompareLanguages.jsx +2 -5
  190. package/src/components/manage/Multilingual/CreateTranslation.jsx +8 -8
  191. package/src/components/manage/Multilingual/ManageTranslations.jsx +4 -2
  192. package/src/components/manage/Multilingual/ManageTranslations.test.jsx +8 -3
  193. package/src/components/manage/Multilingual/TranslationObject.jsx +1 -1
  194. package/src/components/manage/Preferences/ChangePassword.test.jsx +9 -2
  195. package/src/components/manage/Preferences/PersonalInformation.test.jsx +3 -1
  196. package/src/components/manage/Preferences/PersonalPreferences.test.jsx +20 -7
  197. package/src/components/manage/Rules/Rules.test.jsx +6 -3
  198. package/src/components/manage/Sharing/Sharing.test.jsx +3 -1
  199. package/src/components/manage/Sidebar/ObjectBrowserNav.jsx +2 -1
  200. package/src/components/manage/Sidebar/ObjectBrowserNav.test.jsx +3 -3
  201. package/src/components/manage/Sidebar/SidebarPortal.test.tsx +42 -0
  202. package/src/components/manage/Sidebar/SidebarPortal.tsx +48 -0
  203. package/src/components/manage/TemplateChooser/TemplateChooser.jsx +2 -1
  204. package/src/components/manage/Toolbar/More.jsx +4 -1
  205. package/src/components/manage/Toolbar/More.test.jsx +9 -7
  206. package/src/components/manage/Toolbar/PersonalTools.jsx +2 -1
  207. package/src/components/manage/Toolbar/Toolbar.jsx +3 -4
  208. package/src/components/manage/Toolbar/Types.jsx +7 -7
  209. package/src/components/manage/UniversalLink/UniversalLink.test.jsx +196 -14
  210. package/src/components/manage/UniversalLink/UniversalLink.tsx +215 -0
  211. package/src/components/manage/Widgets/ArrayWidget.test.jsx +22 -5
  212. package/src/components/manage/Widgets/CheckboxGroupWidget.test.jsx +12 -5
  213. package/src/components/manage/Widgets/DatetimeWidget.jsx +5 -0
  214. package/src/components/manage/Widgets/DatetimeWidget.test.jsx +21 -6
  215. package/src/components/manage/Widgets/FileWidget.jsx +14 -8
  216. package/src/components/manage/Widgets/ImageWidget.jsx +176 -40
  217. package/src/components/manage/Widgets/InternalUrlWidget.jsx +2 -0
  218. package/src/components/manage/Widgets/NumberWidget.test.jsx +8 -7
  219. package/src/components/manage/Widgets/ObjectBrowserWidget.jsx +3 -0
  220. package/src/components/manage/Widgets/ObjectListWidget.jsx +11 -1
  221. package/src/components/manage/Widgets/ObjectListWidget.test.jsx +18 -8
  222. package/src/components/manage/Widgets/ObjectWidget.test.jsx +5 -1
  223. package/src/components/manage/Widgets/RadioGroupWidget.test.jsx +12 -5
  224. package/src/components/manage/Widgets/RecurrenceWidget/RecurrenceWidget.test.jsx +12 -6
  225. package/src/components/manage/Widgets/RegistryImageWidget.test.jsx +44 -41
  226. package/src/components/manage/Widgets/SchemaWidget.test.jsx +12 -5
  227. package/src/components/manage/Widgets/SchemaWidgetFieldset.test.jsx +12 -5
  228. package/src/components/manage/Widgets/SelectAutoComplete.jsx +29 -12
  229. package/src/components/manage/Widgets/SelectAutoComplete.test.jsx +12 -6
  230. package/src/components/manage/Widgets/SelectWidget.jsx +3 -1
  231. package/src/components/manage/Widgets/SelectWidget.test.jsx +12 -6
  232. package/src/components/manage/Widgets/TimeWidget.test.jsx +13 -5
  233. package/src/components/manage/Widgets/TokenWidget.test.jsx +12 -6
  234. package/src/components/manage/Widgets/UrlWidget.jsx +2 -0
  235. package/src/components/manage/Widgets/VocabularyTermsWidget.test.jsx +18 -9
  236. package/src/components/manage/Widgets/__mocks__/index.tsx +16 -0
  237. package/src/components/manage/Widgets/__mocks__/index.vitest.tsx +41 -0
  238. package/src/components/manage/Workflow/Workflow.test.jsx +17 -7
  239. package/src/components/theme/AlternateHrefLangs/AlternateHrefLangs.jsx +1 -3
  240. package/src/components/theme/AlternateHrefLangs/AlternateHrefLangs.test.jsx +0 -4
  241. package/src/components/theme/App/App.jsx +3 -1
  242. package/src/components/theme/App/App.test.jsx +22 -17
  243. package/src/components/theme/AppExtras/AppExtras.test.jsx +6 -6
  244. package/src/components/theme/Avatar/Avatar.jsx +2 -1
  245. package/src/components/theme/Comments/CommentEditModal.test.jsx +5 -1
  246. package/src/components/theme/Comments/Comments.test.jsx +29 -12
  247. package/src/components/theme/ContactForm/ContactForm.test.jsx +8 -4
  248. package/src/components/theme/FormattedDate/FormattedDate.stories.jsx +20 -2
  249. package/src/components/theme/Header/Header.test.jsx +19 -13
  250. package/src/components/theme/Image/Image.jsx +11 -8
  251. package/src/components/theme/LanguageSelector/{LanguageSelector.test.jsx → LanguageSelector.test.tsx} +6 -6
  252. package/src/components/theme/LanguageSelector/LanguageSelector.tsx +89 -0
  253. package/src/components/theme/Logo/Logo.Multilingual.test.jsx +0 -5
  254. package/src/components/theme/Logout/Logout.test.jsx +1 -1
  255. package/src/components/theme/MultilingualRedirector/MultilingualRedirector.jsx +8 -12
  256. package/src/components/theme/MultilingualRedirector/MultilingualRedirector.test.jsx +3 -5
  257. package/src/components/theme/Navigation/NavItem.jsx +1 -5
  258. package/src/components/theme/Navigation/Navigation.Multilingual.test.jsx +0 -5
  259. package/src/components/theme/NotFound/NotFound.jsx +5 -2
  260. package/src/components/theme/NotFound/NotFound.test.jsx +3 -0
  261. package/src/components/theme/PasswordReset/PasswordReset.test.jsx +10 -1
  262. package/src/components/theme/PasswordReset/RequestPasswordReset.test.jsx +5 -1
  263. package/src/components/theme/PreviewImage/PreviewImage.jsx +1 -1
  264. package/src/components/theme/Register/Register.test.jsx +5 -1
  265. package/src/components/theme/RequestTimeout/RequestTimeout.jsx +1 -1
  266. package/src/components/theme/Search/Search.test.jsx +6 -4
  267. package/src/components/theme/Sitemap/Sitemap.jsx +6 -5
  268. package/src/components/theme/Sitemap/Sitemap.test.jsx +0 -1
  269. package/src/components/theme/TsTest/TsTest.test.tsx +0 -1
  270. package/src/components/theme/View/EventDatesInfo.test.jsx +12 -5
  271. package/src/components/theme/View/EventView.test.jsx +12 -5
  272. package/src/components/theme/View/FileView.jsx +9 -1
  273. package/src/components/theme/View/ListingView.test.jsx +2 -0
  274. package/src/components/theme/View/SummaryView.test.jsx +10 -0
  275. package/src/components/theme/View/TabularView.test.jsx +1 -0
  276. package/src/components/theme/View/View.jsx +1 -1
  277. package/src/components/theme/View/View.test.jsx +42 -23
  278. package/src/components/theme/Widgets/ImageWidget.jsx +2 -1
  279. package/src/config/ControlPanels.js +1 -0
  280. package/src/config/index.js +18 -25
  281. package/src/config/server.js +0 -2
  282. package/src/express-middleware/devproxy.js +20 -5
  283. package/src/helpers/Api/APIResourceWithAuth.js +8 -3
  284. package/src/helpers/Api/Api.js +7 -4
  285. package/src/helpers/Api/Api.plone.rest.test.js +11 -9
  286. package/src/helpers/Api/Api.test.js +11 -14
  287. package/src/helpers/AsyncConnect/AsyncConnect.test.jsx +145 -189
  288. package/src/helpers/AsyncConnect/ssr.js +4 -1
  289. package/src/helpers/AuthToken/AuthToken.test.js +60 -22
  290. package/src/helpers/Blocks/Blocks.test.js +1 -1
  291. package/src/helpers/Content/Content.js +23 -0
  292. package/src/helpers/Content/Content.test.js +39 -0
  293. package/src/helpers/Content/withClientSideContent.jsx +35 -0
  294. package/src/helpers/Extensions/withBlockSchemaEnhancer.jsx +4 -1
  295. package/src/helpers/Html/Html.jsx +13 -7
  296. package/src/helpers/Html/Html.test.jsx +32 -28
  297. package/src/helpers/LanguageMap/LanguageMap.js +115 -8
  298. package/src/helpers/Loadable/__mocks__/Loadable.jsx +16 -1
  299. package/src/helpers/Loadable/__mocks__/Loadable.vitest.jsx +39 -0
  300. package/src/helpers/MessageLabels/MessageLabels.js +5 -0
  301. package/src/helpers/Sitemap/Sitemap.js +4 -4
  302. package/src/helpers/Url/Url.js +32 -2
  303. package/src/helpers/Url/Url.test.js +62 -0
  304. package/src/helpers/Utils/withSaveAsDraft.jsx +241 -0
  305. package/src/hooks/user/useUser.js +1 -1
  306. package/src/middleware/Api.test.js +51 -0
  307. package/src/middleware/api.js +78 -29
  308. package/src/middleware/storeProtectLoadUtils.test.js +93 -81
  309. package/src/reducers/content/content.js +3 -18
  310. package/src/reducers/diff/diff.js +5 -1
  311. package/src/reducers/diff/diff.test.js +60 -4
  312. package/src/routes.js +4 -2
  313. package/src/server.jsx +45 -14
  314. package/src/start-client.jsx +9 -6
  315. package/src/start-server.js +9 -3
  316. package/test-setup-config.jsx +0 -2
  317. package/test-setup-globals-vitest.js +46 -0
  318. package/theme/themes/pastanaga/collections/table.overrides +9 -0
  319. package/theme/themes/pastanaga/extras/blocks.less +26 -0
  320. package/theme/themes/pastanaga/extras/contents.less +17 -5
  321. package/theme/themes/pastanaga/extras/main.less +32 -2
  322. package/tsconfig.declarations.json +12 -1
  323. package/tsconfig.json +5 -5
  324. package/types/components/manage/Blocks/Teaser/schema.d.ts +1 -0
  325. package/types/components/manage/ConditionalLink/ConditionalLink.d.ts +11 -15
  326. package/types/components/manage/Contents/__mocks__/index.vitest.d.ts +2 -0
  327. package/types/components/manage/Controlpanels/Users/RenderUsers.d.ts +18 -2
  328. package/types/components/manage/Controlpanels/Users/UsersControlpanel.d.ts +6 -2
  329. package/types/components/manage/Controlpanels/index.d.ts +2 -2
  330. package/types/components/manage/Form/__mocks__/index.vitest.d.ts +8 -0
  331. package/types/components/manage/MaybeWrap/MaybeWrap.d.ts +7 -5
  332. package/types/components/manage/Sidebar/SidebarPortal.d.ts +7 -15
  333. package/types/components/manage/UniversalLink/UniversalLink.d.ts +54 -20
  334. package/types/components/manage/Widgets/ImageWidget.d.ts +41 -1
  335. package/types/components/manage/Widgets/RecurrenceWidget/Utils.d.ts +12 -18
  336. package/types/components/manage/Widgets/__mocks__/index.vitest.d.ts +33 -0
  337. package/types/components/theme/FormattedDate/FormattedDate.stories.d.ts +1 -1
  338. package/types/components/theme/LanguageSelector/LanguageSelector.d.ts +3 -10
  339. package/types/helpers/Content/Content.d.ts +7 -0
  340. package/types/helpers/Content/withClientSideContent.d.ts +1 -0
  341. package/types/helpers/Extensions/withBlockSchemaEnhancer.d.ts +4 -5
  342. package/types/helpers/Helmet/Helmet.d.ts +1 -1
  343. package/types/helpers/LanguageMap/LanguageMap.d.ts +428 -4
  344. package/types/helpers/Loadable/__mocks__/Loadable.vitest.d.ts +3 -0
  345. package/types/helpers/MessageLabels/MessageLabels.d.ts +68 -62
  346. package/types/helpers/Url/Url.d.ts +14 -0
  347. package/types/helpers/Url/bulkFlattenToAppURL.d.ts +5 -0
  348. package/types/helpers/Utils/withSaveAsDraft.d.ts +1 -0
  349. package/types/middleware/api.d.ts +6 -9
  350. package/types/react-router-hash-link.d.ts +12 -0
  351. package/types/reducers/index.d.ts +1 -0
  352. package/types/routes.d.ts +4 -0
  353. package/types/server.d.ts +1 -1
  354. package/types/start-client.d.ts +0 -1
  355. package/vite-plugins/svg.mjs +81 -0
  356. package/vitest.config.mjs +77 -0
  357. package/package-why.json +0 -34
  358. package/src/actions/content/content.multilingual.test.js +0 -17
  359. package/src/components/manage/ConditionalLink/ConditionalLink.jsx +0 -27
  360. package/src/components/manage/ConditionalLink/ConditionalLink.test.jsx +0 -30
  361. package/src/components/manage/MaybeWrap/MaybeWrap.jsx +0 -9
  362. package/src/components/manage/Sidebar/SidebarPortal.jsx +0 -47
  363. package/src/components/manage/Sidebar/SidebarPortal.test.jsx +0 -26
  364. package/src/components/manage/UniversalLink/UniversalLink.jsx +0 -154
  365. package/src/components/manage/Widgets/FileWidget.test.jsx +0 -91
  366. package/src/components/theme/LanguageSelector/LanguageSelector.jsx +0 -77
  367. package/theme/themes/pastanaga/extras/utils.less +0 -63
@@ -4,7 +4,7 @@ import { Provider } from 'react-intl-redux';
4
4
  import configureStore from 'redux-mock-store';
5
5
  import { render } from '@testing-library/react';
6
6
  import { MemoryRouter } from 'react-router-dom';
7
- import UniversalLink from './UniversalLink';
7
+ import UniversalLink, { __test } from './UniversalLink';
8
8
  import config from '@plone/volto/registry';
9
9
 
10
10
  const mockStore = configureStore();
@@ -18,7 +18,7 @@ const store = mockStore({
18
18
  },
19
19
  });
20
20
 
21
- global.console.error = jest.fn();
21
+ global.console.error = vi.fn();
22
22
 
23
23
  describe('UniversalLink', () => {
24
24
  it('renders a UniversalLink component with internal link', () => {
@@ -39,7 +39,10 @@ describe('UniversalLink', () => {
39
39
  const component = renderer.create(
40
40
  <Provider store={store}>
41
41
  <MemoryRouter>
42
- <UniversalLink href="https://github.com/plone/volto">
42
+ <UniversalLink
43
+ href="https://github.com/plone/volto"
44
+ className="custom-link"
45
+ >
43
46
  <h1>Title</h1>
44
47
  </UniversalLink>
45
48
  </MemoryRouter>
@@ -213,18 +216,197 @@ describe('UniversalLink', () => {
213
216
  expect(json).toMatchSnapshot();
214
217
  expect(global.console.error).toHaveBeenCalled();
215
218
  });
216
- });
217
219
 
218
- it('renders a UniversalLink component when url ends with @@display-file', () => {
219
- const component = renderer.create(
220
- <Provider store={store}>
221
- <MemoryRouter>
222
- <UniversalLink href="http://localhost:3000/en/welcome-to-volto/@@display-file">
220
+ it('renders a UniversalLink component when url ends with @@display-file', () => {
221
+ const component = renderer.create(
222
+ <Provider store={store}>
223
+ <MemoryRouter>
224
+ <UniversalLink href="http://localhost:3000/en/welcome-to-volto/@@display-file">
225
+ <h1>Title</h1>
226
+ </UniversalLink>
227
+ </MemoryRouter>
228
+ </Provider>,
229
+ );
230
+ const json = component.toJSON();
231
+ expect(json).toMatchSnapshot();
232
+ });
233
+
234
+ test('only one UniversalLink re-renders when prop changes (stable references)', () => {
235
+ const renderCounter = vi.fn();
236
+ __test.renderCounter = renderCounter;
237
+
238
+ const itemA = { '@id': '/en/a' };
239
+ const itemB = { '@id': '/en/b' };
240
+ const itemC = { '@id': '/en/c' };
241
+
242
+ const Wrapper = ({ children }) => (
243
+ <Provider store={store}>
244
+ <MemoryRouter>{children}</MemoryRouter>
245
+ </Provider>
246
+ );
247
+
248
+ const { rerender } = render(
249
+ <>
250
+ <UniversalLink item={itemA} />
251
+ <UniversalLink item={itemB} />
252
+ <UniversalLink item={itemC} />
253
+ </>,
254
+ { wrapper: Wrapper },
255
+ );
256
+
257
+ // expect 3 renders
258
+ expect(renderCounter).toHaveBeenCalledTimes(3);
259
+
260
+ const updatedItemB = { '@id': '/en/b-updated' };
261
+
262
+ rerender(
263
+ <>
264
+ <UniversalLink item={itemA} />
265
+ <UniversalLink item={updatedItemB} />
266
+ <UniversalLink item={itemC} />
267
+ </>,
268
+ );
269
+
270
+ // expect 4 renders (only one UniversalLink re-renders)
271
+ expect(renderCounter).toHaveBeenCalledTimes(4);
272
+ });
273
+
274
+ test('only one UniversalLink re-renders when prop changes (with children - stable references)', () => {
275
+ const renderCounter = vi.fn();
276
+ __test.renderCounter = renderCounter;
277
+
278
+ const itemA = { '@id': '/en/a' };
279
+ const itemB = { '@id': '/en/b' };
280
+ const itemC = { '@id': '/en/c' };
281
+ const title = 'Title';
282
+
283
+ const Wrapper = ({ children }) => (
284
+ <Provider store={store}>
285
+ <MemoryRouter>{children}</MemoryRouter>
286
+ </Provider>
287
+ );
288
+
289
+ const { rerender } = render(
290
+ <>
291
+ <UniversalLink item={itemA}>{title}</UniversalLink>
292
+ <UniversalLink item={itemB}>{title}</UniversalLink>
293
+ <UniversalLink item={itemC}>{title}</UniversalLink>
294
+ </>,
295
+ { wrapper: Wrapper },
296
+ );
297
+
298
+ // expect 3 renders
299
+ expect(renderCounter).toHaveBeenCalledTimes(3);
300
+
301
+ const updatedItemB = { '@id': '/en/b-updated' };
302
+
303
+ rerender(
304
+ <>
305
+ <UniversalLink item={itemA}>{title}</UniversalLink>
306
+ <UniversalLink item={updatedItemB}>{title}</UniversalLink>
307
+ <UniversalLink item={itemC}>{title}</UniversalLink>
308
+ </>,
309
+ );
310
+
311
+ // expect 4 renders (only one UniversalLink re-renders)
312
+ expect(renderCounter).toHaveBeenCalledTimes(4);
313
+ });
314
+
315
+ test('[NEGATIVE TEST] UniversalLink re-renders all instances when children are inline JSX (React.memo ineffective)', () => {
316
+ // NEGATIVE TEST:
317
+ // This test demonstrates that React.memo does NOT prevent re-renders
318
+ // when props like `children` are passed as inline JSX.
319
+ // This is expected behavior due to unstable object references.
320
+ // Do NOT use inline props if render optimization is required.
321
+ const renderCounter = vi.fn();
322
+ __test.renderCounter = renderCounter;
323
+
324
+ const itemA = { '@id': '/en/a' };
325
+ const itemB = { '@id': '/en/b' };
326
+ const itemC = { '@id': '/en/c' };
327
+
328
+ const Wrapper = ({ children }) => (
329
+ <Provider store={store}>
330
+ <MemoryRouter>{children}</MemoryRouter>
331
+ </Provider>
332
+ );
333
+
334
+ const { rerender } = render(
335
+ <>
336
+ <UniversalLink item={itemA}>
337
+ <h1>Title</h1>
338
+ </UniversalLink>
339
+ <UniversalLink item={itemB}>
340
+ <h1>Title</h1>
341
+ </UniversalLink>
342
+ <UniversalLink item={itemC}>
343
+ <h1>Title</h1>
344
+ </UniversalLink>
345
+ </>,
346
+ { wrapper: Wrapper },
347
+ );
348
+
349
+ // expect 3 renders
350
+ expect(renderCounter).toHaveBeenCalledTimes(3);
351
+
352
+ const updatedItemB = { '@id': '/en/b-updated' };
353
+
354
+ rerender(
355
+ <>
356
+ <UniversalLink item={itemA}>
223
357
  <h1>Title</h1>
224
358
  </UniversalLink>
225
- </MemoryRouter>
226
- </Provider>,
227
- );
228
- const json = component.toJSON();
229
- expect(json).toMatchSnapshot();
359
+ <UniversalLink item={updatedItemB}>
360
+ <h1>Title</h1>
361
+ </UniversalLink>
362
+ <UniversalLink item={itemC}>
363
+ <h1>Title</h1>
364
+ </UniversalLink>
365
+ </>,
366
+ );
367
+
368
+ // expect 6 renders (React.memo does NOT prevent re-renders when props like `children` are passed as inline JSX.)
369
+ expect(renderCounter).toHaveBeenCalledTimes(6);
370
+ });
371
+
372
+ test('[NEGATIVE TEST] UniversalLink re-renders all instances when props are inline JSX (React.memo ineffective)', () => {
373
+ // NEGATIVE TEST:
374
+ // This test demonstrates that React.memo does NOT prevent re-renders
375
+ // when props like `item` are passed as inline object.
376
+ // This is expected behavior due to unstable object references.
377
+ // Do NOT use inline props if render optimization is required.
378
+ const renderCounter = vi.fn();
379
+ __test.renderCounter = renderCounter;
380
+
381
+ const title = 'Title';
382
+
383
+ const Wrapper = ({ children }) => (
384
+ <Provider store={store}>
385
+ <MemoryRouter>{children}</MemoryRouter>
386
+ </Provider>
387
+ );
388
+
389
+ const { rerender } = render(
390
+ <>
391
+ <UniversalLink item={{ '@id': '/en/a' }}>{title}</UniversalLink>
392
+ <UniversalLink item={{ '@id': '/en/b' }}>{title}</UniversalLink>
393
+ <UniversalLink item={{ '@id': '/en/c' }}>{title}</UniversalLink>
394
+ </>,
395
+ { wrapper: Wrapper },
396
+ );
397
+
398
+ // expect 3 renders
399
+ expect(renderCounter).toHaveBeenCalledTimes(3);
400
+
401
+ rerender(
402
+ <>
403
+ <UniversalLink item={{ '@id': '/en/a' }}>{title}</UniversalLink>
404
+ <UniversalLink item={{ '@id': '/en/b' }}>{title}</UniversalLink>
405
+ <UniversalLink item={{ '@id': '/en/c' }}>{title}</UniversalLink>
406
+ </>,
407
+ );
408
+
409
+ // expect 6 renders (React.memo does NOT prevent re-renders when props like `children` are passed as inline JSX.)
410
+ expect(renderCounter).toHaveBeenCalledTimes(6);
411
+ });
230
412
  });
@@ -0,0 +1,215 @@
1
+ import React from 'react';
2
+ import { HashLink as Link } from 'react-router-hash-link';
3
+ import { useSelector } from 'react-redux';
4
+ import {
5
+ flattenToAppURL,
6
+ isInternalURL,
7
+ URLUtils,
8
+ } from '@plone/volto/helpers/Url/Url';
9
+ import config from '@plone/volto/registry';
10
+ import cx from 'classnames';
11
+ import type { ObjectBrowserItem } from '@plone/types';
12
+
13
+ type BaseProps = {
14
+ openLinkInNewTab?: boolean;
15
+ download?: boolean;
16
+ children: React.ReactNode;
17
+ className?: string;
18
+ title?: string;
19
+ smooth?: boolean;
20
+ onClick?: (e: React.MouseEvent) => void;
21
+ onKeyDown?: (e: React.KeyboardEvent) => void;
22
+ };
23
+
24
+ type HrefOnly = {
25
+ href: string;
26
+ item?: never;
27
+ } & BaseProps;
28
+
29
+ type ItemOnly = {
30
+ href?: never;
31
+ item: Partial<ObjectBrowserItem> & { remoteUrl?: string };
32
+ } & BaseProps;
33
+
34
+ export type UniversalLinkProps = HrefOnly | ItemOnly;
35
+ export interface AppState {
36
+ content: {
37
+ data?: {
38
+ '@components'?: {
39
+ translations?: {
40
+ items?: { language: string; '@id': string }[];
41
+ };
42
+ };
43
+ };
44
+ };
45
+ navroot: {
46
+ data: {
47
+ navroot: {
48
+ id: string;
49
+ };
50
+ };
51
+ };
52
+ intl: {
53
+ locale: string;
54
+ };
55
+ userSession: {
56
+ token: string | null;
57
+ };
58
+ }
59
+
60
+ export const __test = {
61
+ renderCounter: () => {},
62
+ };
63
+
64
+ export function getUrl(
65
+ props: UniversalLinkProps,
66
+ token: string | null,
67
+ item: UniversalLinkProps['item'],
68
+ children: React.ReactNode,
69
+ ): string {
70
+ if ('href' in props && typeof props.href === 'string') {
71
+ return props.href;
72
+ }
73
+
74
+ if (!item || item['@id'] === '') return config.settings.publicURL;
75
+ if (!item['@id']) {
76
+ // eslint-disable-next-line no-console
77
+ console.error(
78
+ 'Invalid item passed to UniversalLink',
79
+ item,
80
+ props,
81
+ children,
82
+ );
83
+ return '#';
84
+ }
85
+
86
+ let url = flattenToAppURL(item['@id']);
87
+ const remoteUrl = item.remoteUrl || item.getRemoteUrl;
88
+
89
+ if (!token && remoteUrl) {
90
+ url = remoteUrl;
91
+ }
92
+
93
+ if (
94
+ !token &&
95
+ item['@type'] &&
96
+ config.settings.downloadableObjects.includes(item['@type'])
97
+ ) {
98
+ url = `${url}/@@download/file`;
99
+ }
100
+
101
+ if (
102
+ !token &&
103
+ item['@type'] &&
104
+ config.settings.viewableInBrowserObjects.includes(item['@type'])
105
+ ) {
106
+ url = `${url}/@@display-file/file`;
107
+ }
108
+
109
+ return url;
110
+ }
111
+
112
+ const UniversalLink = React.memo(
113
+ React.forwardRef<HTMLAnchorElement | HTMLDivElement, UniversalLinkProps>(
114
+ function UniversalLink(props, ref) {
115
+ const {
116
+ openLinkInNewTab,
117
+ download,
118
+ children,
119
+ className,
120
+ title,
121
+ smooth,
122
+ onClick,
123
+ onKeyDown,
124
+ item,
125
+ ...rest
126
+ } = props;
127
+ __test.renderCounter();
128
+
129
+ const token = useSelector<AppState, string | null>(
130
+ (state) => state.userSession?.token,
131
+ );
132
+
133
+ let url = getUrl(props, token, item, children);
134
+
135
+ const isExternal = !isInternalURL(url);
136
+
137
+ const isDownload =
138
+ (!isExternal && url.includes('@@download')) || download;
139
+ const isDisplayFile =
140
+ (!isExternal && url.includes('@@display-file')) || false;
141
+
142
+ const checkedURL = URLUtils.checkAndNormalizeUrl(url);
143
+
144
+ url = checkedURL.url;
145
+ let tag = (
146
+ <Link
147
+ to={flattenToAppURL(url)}
148
+ target={openLinkInNewTab ?? false ? '_blank' : undefined}
149
+ title={title}
150
+ className={className}
151
+ onClick={onClick}
152
+ smooth={smooth ?? config.settings.hashLinkSmoothScroll}
153
+ // @ts-ignore
154
+ ref={ref}
155
+ {...rest}
156
+ >
157
+ {children}
158
+ </Link>
159
+ );
160
+
161
+ if (isExternal) {
162
+ const isTelephoneOrMail = checkedURL.isMail || checkedURL.isTelephone;
163
+ const getClassName = cx({ external: !isTelephoneOrMail }, className);
164
+
165
+ tag = (
166
+ <a
167
+ href={url}
168
+ title={title}
169
+ target={
170
+ !isTelephoneOrMail && !(openLinkInNewTab === false)
171
+ ? '_blank'
172
+ : undefined
173
+ }
174
+ rel="noopener noreferrer"
175
+ {...rest}
176
+ className={getClassName}
177
+ ref={ref as React.Ref<HTMLAnchorElement>}
178
+ >
179
+ {children}
180
+ </a>
181
+ );
182
+ } else if (isDownload) {
183
+ tag = (
184
+ <a
185
+ href={flattenToAppURL(url)}
186
+ download
187
+ title={title}
188
+ {...rest}
189
+ className={className}
190
+ ref={ref as React.Ref<HTMLAnchorElement>}
191
+ >
192
+ {children}
193
+ </a>
194
+ );
195
+ } else if (isDisplayFile) {
196
+ tag = (
197
+ <a
198
+ title={title}
199
+ target="_blank"
200
+ rel="noopener noreferrer"
201
+ {...rest}
202
+ href={flattenToAppURL(url)}
203
+ className={className}
204
+ ref={ref as React.Ref<HTMLAnchorElement>}
205
+ >
206
+ {children}
207
+ </a>
208
+ );
209
+ }
210
+ return tag;
211
+ },
212
+ ),
213
+ );
214
+
215
+ export default UniversalLink;
@@ -8,11 +8,25 @@ import ArrayWidget from './ArrayWidget';
8
8
 
9
9
  const mockStore = configureStore();
10
10
 
11
- jest.mock('@plone/volto/helpers/Loadable/Loadable');
12
- beforeAll(
13
- async () =>
14
- await require('@plone/volto/helpers/Loadable/Loadable').__setLoadables(),
15
- );
11
+ vi.mock('@plone/volto/helpers/Loadable/Loadable', async () => {
12
+ return await import(
13
+ '@plone/volto/helpers/Loadable/__mocks__/Loadable.vitest.jsx'
14
+ );
15
+ });
16
+
17
+ // Mock react-sortable-hoc to prevent the container error
18
+ vi.mock('react-sortable-hoc', () => ({
19
+ ...vi.importActual('react-sortable-hoc'),
20
+ SortableContainer: (component) => component,
21
+ SortableElement: (component) => component,
22
+ }));
23
+
24
+ beforeAll(async () => {
25
+ const { __setLoadables } = await import(
26
+ '@plone/volto/helpers/Loadable/Loadable'
27
+ );
28
+ await __setLoadables();
29
+ });
16
30
 
17
31
  test('renders an array widget component', async () => {
18
32
  const store = mockStore({
@@ -27,6 +41,7 @@ test('renders an array widget component', async () => {
27
41
  },
28
42
  },
29
43
  });
44
+
30
45
  const component = renderer.create(
31
46
  <Provider store={store}>
32
47
  <ArrayWidget
@@ -38,6 +53,7 @@ test('renders an array widget component', async () => {
38
53
  />
39
54
  </Provider>,
40
55
  );
56
+
41
57
  await waitFor(() => {});
42
58
  expect(component.toJSON()).toMatchSnapshot();
43
59
  });
@@ -83,5 +99,6 @@ test("No 'No value' option when default value is 0", async () => {
83
99
  container.querySelector('.react-select__dropdown-indicator'),
84
100
  { button: 0 },
85
101
  );
102
+
86
103
  expect(container).toMatchSnapshot();
87
104
  });
@@ -7,11 +7,18 @@ import CheckboxGroupWidget from './CheckboxGroupWidget';
7
7
 
8
8
  const mockStore = configureStore();
9
9
 
10
- jest.mock('@plone/volto/helpers/Loadable/Loadable');
11
- beforeAll(
12
- async () =>
13
- await require('@plone/volto/helpers/Loadable/Loadable').__setLoadables(),
14
- );
10
+ vi.mock('@plone/volto/helpers/Loadable/Loadable', async () => {
11
+ return await import(
12
+ '@plone/volto/helpers/Loadable/__mocks__/Loadable.vitest.jsx'
13
+ );
14
+ });
15
+
16
+ beforeAll(async () => {
17
+ const { __setLoadables } = await import(
18
+ '@plone/volto/helpers/Loadable/Loadable'
19
+ );
20
+ await __setLoadables();
21
+ });
15
22
 
16
23
  test('renders a checkbox group widget component', async () => {
17
24
  const store = mockStore({
@@ -27,6 +27,10 @@ const messages = defineMessages({
27
27
  id: 'Time',
28
28
  defaultMessage: 'Time',
29
29
  },
30
+ clearDateTime: {
31
+ id: 'Clear date/time',
32
+ defaultMessage: 'Clear date and time',
33
+ },
30
34
  });
31
35
 
32
36
  const PrevIcon = () => (
@@ -207,6 +211,7 @@ const DatetimeWidgetComponent = (props) => {
207
211
  disabled={isDisabled || !datetime}
208
212
  onClick={onResetDates}
209
213
  className="item ui noborder button"
214
+ aria-label={intl.formatMessage(messages.clearDateTime)}
210
215
  >
211
216
  <Icon name={clearSVG} size="24px" className="close" />
212
217
  </button>
@@ -6,11 +6,18 @@ import { waitFor, render, screen } from '@testing-library/react';
6
6
 
7
7
  const mockStore = configureStore();
8
8
 
9
- jest.mock('@plone/volto/helpers/Loadable/Loadable');
10
- beforeAll(
11
- async () =>
12
- await require('@plone/volto/helpers/Loadable/Loadable').__setLoadables(),
13
- );
9
+ vi.mock('@plone/volto/helpers/Loadable/Loadable', async () => {
10
+ return await import(
11
+ '@plone/volto/helpers/Loadable/__mocks__/Loadable.vitest.jsx'
12
+ );
13
+ });
14
+
15
+ beforeAll(async () => {
16
+ const { __setLoadables } = await import(
17
+ '@plone/volto/helpers/Loadable/Loadable'
18
+ );
19
+ await __setLoadables();
20
+ });
14
21
 
15
22
  test('renders a datetime widget component', async () => {
16
23
  const store = mockStore({
@@ -19,6 +26,7 @@ test('renders a datetime widget component', async () => {
19
26
  messages: {},
20
27
  },
21
28
  });
29
+
22
30
  const isoDate = new Date('2019-10-21').toISOString();
23
31
  const { container } = render(
24
32
  <Provider store={store}>
@@ -28,20 +36,24 @@ test('renders a datetime widget component', async () => {
28
36
  fieldSet="default"
29
37
  onChange={() => {}}
30
38
  value={isoDate}
39
+ showTime={true}
31
40
  />
32
41
  </Provider>,
33
42
  );
43
+
34
44
  await waitFor(() => screen.getByText(/My field/));
45
+ await waitFor(() => screen.getByPlaceholderText('Time'));
35
46
  expect(container).toMatchSnapshot();
36
47
  });
37
48
 
38
- test('datetime widget converts UTC date and adapt to local datetime', async () => {
49
+ test('datetime widget converts UTC date and adapts to local datetime', async () => {
39
50
  const store = mockStore({
40
51
  intl: {
41
52
  locale: 'en',
42
53
  messages: {},
43
54
  },
44
55
  });
56
+
45
57
  const date = '2020-02-10T15:01:00.000Z';
46
58
  const { container } = render(
47
59
  <Provider store={store}>
@@ -50,9 +62,12 @@ test('datetime widget converts UTC date and adapt to local datetime', async () =
50
62
  title="My field"
51
63
  onChange={() => {}}
52
64
  value={date}
65
+ showTime={true}
53
66
  />
54
67
  </Provider>,
55
68
  );
69
+
56
70
  await waitFor(() => screen.getByText(/My field/));
71
+ await waitFor(() => screen.getByPlaceholderText('Time'));
57
72
  expect(container).toMatchSnapshot();
58
73
  });
@@ -15,7 +15,6 @@ import UniversalLink from '@plone/volto/components/manage/UniversalLink/Universa
15
15
  import FormFieldWrapper from '@plone/volto/components/manage/Widgets/FormFieldWrapper';
16
16
  import Image from '@plone/volto/components/theme/Image/Image';
17
17
  import loadable from '@loadable/component';
18
- import { flattenToAppURL } from '@plone/volto/helpers/Url/Url';
19
18
  import { validateFileUploadSize } from '@plone/volto/helpers/FormValidation/FormValidation';
20
19
  import { defineMessages, useIntl } from 'react-intl';
21
20
  import { toast } from 'react-toastify';
@@ -90,18 +89,25 @@ const FileWidget = (props) => {
90
89
  const [fileType, setFileType] = React.useState(false);
91
90
  const intl = useIntl();
92
91
 
92
+ const imgAttrs = React.useMemo(() => {
93
+ const data = {};
94
+ if (value?.download) {
95
+ data.item = {
96
+ '@id': value.download.substring(0, value.download.indexOf('/@@images')),
97
+ image: value,
98
+ };
99
+ } else if (value?.data) {
100
+ data.src = `data:${value['content-type']};${value.encoding},${value.data}`;
101
+ }
102
+ return data;
103
+ }, [value]);
104
+
93
105
  React.useEffect(() => {
94
106
  if (value && imageMimetypes.includes(value['content-type'])) {
95
107
  setFileType(true);
96
108
  }
97
109
  }, [value]);
98
110
 
99
- const imgsrc = value?.download
100
- ? `${flattenToAppURL(value?.download)}?id=${Date.now()}`
101
- : null || value?.data
102
- ? `data:${value['content-type']};${value.encoding},${value.data}`
103
- : null;
104
-
105
111
  /**
106
112
  * Drop handler
107
113
  * @method onDrop
@@ -175,7 +181,7 @@ const FileWidget = (props) => {
175
181
  <Image
176
182
  className="image-preview small ui image"
177
183
  id={`field-${id}-image`}
178
- src={imgsrc}
184
+ {...imgAttrs}
179
185
  />
180
186
  ) : (
181
187
  <div className="dropzone-placeholder">