@strapi/content-manager 0.0.0-experimental.d1602f22dc638a4c3c5084965fd6126fff5e9d4f → 0.0.0-experimental.d2a56e52af31fcf0f0c582a5a2e58e310966e96b

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 (236) hide show
  1. package/dist/admin/chunks/{CardDragPreview-DwuraT0K.js → CardDragPreview-DwuraT0K.mjs} +1 -1
  2. package/dist/admin/chunks/CardDragPreview-DwuraT0K.mjs.map +1 -0
  3. package/dist/admin/chunks/{ComponentConfigurationPage-DXwOtpq1.js → ComponentConfigurationPage-CGn9IYeg.js} +6 -6
  4. package/dist/admin/chunks/{ComponentConfigurationPage-DXwOtpq1.js.map → ComponentConfigurationPage-CGn9IYeg.js.map} +1 -1
  5. package/dist/admin/chunks/{ComponentConfigurationPage-DhYZp4nN.js → ComponentConfigurationPage-DgYK4xW6.mjs} +9 -9
  6. package/dist/admin/chunks/ComponentConfigurationPage-DgYK4xW6.mjs.map +1 -0
  7. package/dist/admin/chunks/{ComponentIcon-BZcTc4rj.js → ComponentIcon-BZcTc4rj.mjs} +1 -1
  8. package/dist/admin/chunks/ComponentIcon-BZcTc4rj.mjs.map +1 -0
  9. package/dist/admin/chunks/{EditConfigurationPage-D0Ng758X.js → EditConfigurationPage-7w_-4jF4.js} +6 -6
  10. package/dist/admin/chunks/{EditConfigurationPage-D0Ng758X.js.map → EditConfigurationPage-7w_-4jF4.js.map} +1 -1
  11. package/dist/admin/chunks/{EditConfigurationPage-DDuPch5d.js → EditConfigurationPage-C05SwwH-.mjs} +9 -9
  12. package/dist/admin/chunks/EditConfigurationPage-C05SwwH-.mjs.map +1 -0
  13. package/dist/admin/chunks/EditViewPage-CVRJBOEv.mjs +318 -0
  14. package/dist/admin/chunks/EditViewPage-CVRJBOEv.mjs.map +1 -0
  15. package/dist/admin/chunks/EditViewPage-CuQfZJDf.js +341 -0
  16. package/dist/admin/chunks/EditViewPage-CuQfZJDf.js.map +1 -0
  17. package/dist/admin/chunks/{FieldTypeIcon-BY6MrVF4.js → FieldTypeIcon-BY6MrVF4.mjs} +1 -1
  18. package/dist/admin/chunks/FieldTypeIcon-BY6MrVF4.mjs.map +1 -0
  19. package/dist/admin/chunks/{Form-BEqiuSvQ.js → Form-BqNYRsCb.js} +5 -5
  20. package/dist/admin/chunks/{Form-BEqiuSvQ.js.map → Form-BqNYRsCb.js.map} +1 -1
  21. package/dist/admin/chunks/{Form-CZmB6JIg.js → Form-DaEnqAeV.mjs} +5 -5
  22. package/dist/admin/chunks/Form-DaEnqAeV.mjs.map +1 -0
  23. package/dist/admin/chunks/{History-CPYXgxkS.js → History-B7dGNfmx.mjs} +68 -15
  24. package/dist/admin/chunks/History-B7dGNfmx.mjs.map +1 -0
  25. package/dist/admin/chunks/{History-BlLKDZSw.js → History-CEoOna4w.js} +67 -14
  26. package/dist/admin/chunks/History-CEoOna4w.js.map +1 -0
  27. package/dist/admin/chunks/{Input-CLX3C5DI.js → Input-B3QUS9rv.mjs} +2273 -511
  28. package/dist/admin/chunks/Input-B3QUS9rv.mjs.map +1 -0
  29. package/dist/admin/chunks/{Input-DiR2Xfa7.js → Input-B8I0b9aD.js} +2284 -519
  30. package/dist/admin/chunks/Input-B8I0b9aD.js.map +1 -0
  31. package/dist/admin/chunks/{ListConfigurationPage-DdTp-HxB.js → ListConfigurationPage-BbjJweN-.js} +7 -7
  32. package/dist/admin/chunks/{ListConfigurationPage-DdTp-HxB.js.map → ListConfigurationPage-BbjJweN-.js.map} +1 -1
  33. package/dist/admin/chunks/{ListConfigurationPage-CNvotSqe.js → ListConfigurationPage-VtFQ5mOK.mjs} +8 -8
  34. package/dist/admin/chunks/ListConfigurationPage-VtFQ5mOK.mjs.map +1 -0
  35. package/dist/admin/chunks/{ListViewPage-MJNfQTp-.js → ListViewPage-Cg3zbT7Y.mjs} +5 -5
  36. package/dist/admin/chunks/ListViewPage-Cg3zbT7Y.mjs.map +1 -0
  37. package/dist/admin/chunks/{ListViewPage-BtXYjEYz.js → ListViewPage-CzUm2VJN.js} +8 -8
  38. package/dist/admin/chunks/{ListViewPage-BtXYjEYz.js.map → ListViewPage-CzUm2VJN.js.map} +1 -1
  39. package/dist/admin/chunks/{NoContentTypePage-CVvVpwj4.js → NoContentTypePage-FcLLn2Wt.js} +3 -2
  40. package/dist/admin/chunks/{NoContentTypePage-BJrZvYPY.js.map → NoContentTypePage-FcLLn2Wt.js.map} +1 -1
  41. package/dist/admin/chunks/{NoContentTypePage-BJrZvYPY.js → NoContentTypePage-NOf7Aq_E.mjs} +3 -2
  42. package/dist/admin/chunks/NoContentTypePage-NOf7Aq_E.mjs.map +1 -0
  43. package/dist/admin/chunks/{NoPermissionsPage-C5yWg70d.js → NoPermissionsPage-DmeyXtCk.js} +3 -2
  44. package/dist/admin/chunks/{NoPermissionsPage-BulvG4hB.js.map → NoPermissionsPage-DmeyXtCk.js.map} +1 -1
  45. package/dist/admin/chunks/{NoPermissionsPage-BulvG4hB.js → NoPermissionsPage-OVr9KG6L.mjs} +3 -2
  46. package/dist/admin/chunks/NoPermissionsPage-OVr9KG6L.mjs.map +1 -0
  47. package/dist/admin/chunks/Preview-BH9l1QXk.mjs +593 -0
  48. package/dist/admin/chunks/Preview-BH9l1QXk.mjs.map +1 -0
  49. package/dist/admin/chunks/Preview-BYKkpc11.js +615 -0
  50. package/dist/admin/chunks/Preview-BYKkpc11.js.map +1 -0
  51. package/dist/admin/chunks/{ar-DckYq_WK.js → ar-DckYq_WK.mjs} +1 -1
  52. package/dist/admin/chunks/ar-DckYq_WK.mjs.map +1 -0
  53. package/dist/admin/chunks/{ca-DviY7mRj.js → ca-DviY7mRj.mjs} +1 -1
  54. package/dist/admin/chunks/ca-DviY7mRj.mjs.map +1 -0
  55. package/dist/admin/chunks/{cs-C7OSYFQ7.js → cs-C7OSYFQ7.mjs} +1 -1
  56. package/dist/admin/chunks/cs-C7OSYFQ7.mjs.map +1 -0
  57. package/dist/admin/chunks/{de-5QRlDHyR.js → de-5QRlDHyR.mjs} +1 -1
  58. package/dist/admin/chunks/de-5QRlDHyR.mjs.map +1 -0
  59. package/dist/admin/chunks/{en-LfhocNG2.js → en-C2zEwS3-.mjs} +6 -1
  60. package/dist/admin/chunks/en-C2zEwS3-.mjs.map +1 -0
  61. package/dist/admin/chunks/{en-C1CjdAtC.js → en-G976DLsg.js} +6 -1
  62. package/dist/admin/chunks/{en-LfhocNG2.js.map → en-G976DLsg.js.map} +1 -1
  63. package/dist/admin/chunks/{es-DkoWSExG.js → es-DkoWSExG.mjs} +1 -1
  64. package/dist/admin/chunks/es-DkoWSExG.mjs.map +1 -0
  65. package/dist/admin/chunks/{eu-BG1xX7HK.js → eu-BG1xX7HK.mjs} +1 -1
  66. package/dist/admin/chunks/eu-BG1xX7HK.mjs.map +1 -0
  67. package/dist/admin/chunks/{fr-CFdRaRVj.js → fr-CFdRaRVj.mjs} +1 -1
  68. package/dist/admin/chunks/fr-CFdRaRVj.mjs.map +1 -0
  69. package/dist/admin/chunks/{gu-D5MMMXRs.js → gu-D5MMMXRs.mjs} +1 -1
  70. package/dist/admin/chunks/gu-D5MMMXRs.mjs.map +1 -0
  71. package/dist/admin/chunks/{hi-lp17SCjr.js → hi-lp17SCjr.mjs} +1 -1
  72. package/dist/admin/chunks/hi-lp17SCjr.mjs.map +1 -0
  73. package/dist/admin/chunks/{hooks-DMvik5y_.js → hooks-DMvik5y_.mjs} +1 -1
  74. package/dist/admin/chunks/hooks-DMvik5y_.mjs.map +1 -0
  75. package/dist/admin/chunks/{hu-CLka1U2C.js → hu-CLka1U2C.mjs} +1 -1
  76. package/dist/admin/chunks/hu-CLka1U2C.mjs.map +1 -0
  77. package/dist/admin/chunks/{id-USfY9m1g.js → id-USfY9m1g.mjs} +1 -1
  78. package/dist/admin/chunks/id-USfY9m1g.mjs.map +1 -0
  79. package/dist/admin/chunks/{index-BRlRBRLb.js → index-BE7PI9Wp.mjs} +273 -173
  80. package/dist/admin/chunks/index-BE7PI9Wp.mjs.map +1 -0
  81. package/dist/admin/chunks/{index-ZIwOPk6p.js → index-BwIhYBsG.js} +246 -142
  82. package/dist/admin/chunks/index-BwIhYBsG.js.map +1 -0
  83. package/dist/admin/chunks/{it-BAHrwmYS.js → it-BAHrwmYS.mjs} +1 -1
  84. package/dist/admin/chunks/it-BAHrwmYS.mjs.map +1 -0
  85. package/dist/admin/chunks/{ja-BWKmBJFT.js → ja-BWKmBJFT.mjs} +1 -1
  86. package/dist/admin/chunks/ja-BWKmBJFT.mjs.map +1 -0
  87. package/dist/admin/chunks/{ko-CgADGBNt.js → ko-CgADGBNt.mjs} +1 -1
  88. package/dist/admin/chunks/ko-CgADGBNt.mjs.map +1 -0
  89. package/dist/admin/chunks/{layout-B3-guCPG.js → layout-9zlUM9V3.mjs} +81 -7
  90. package/dist/admin/chunks/layout-9zlUM9V3.mjs.map +1 -0
  91. package/dist/admin/chunks/{layout-ameRNiAM.js → layout-Cr0HaJVS.js} +87 -13
  92. package/dist/admin/chunks/layout-Cr0HaJVS.js.map +1 -0
  93. package/dist/admin/chunks/{ml-CnhCfOn_.js → ml-CnhCfOn_.mjs} +1 -1
  94. package/dist/admin/chunks/ml-CnhCfOn_.mjs.map +1 -0
  95. package/dist/admin/chunks/{ms-Bh09NFff.js → ms-Bh09NFff.mjs} +1 -1
  96. package/dist/admin/chunks/ms-Bh09NFff.mjs.map +1 -0
  97. package/dist/admin/chunks/{nl-C8HYflTc.js → nl-C8HYflTc.mjs} +1 -1
  98. package/dist/admin/chunks/nl-C8HYflTc.mjs.map +1 -0
  99. package/dist/admin/chunks/{useDragAndDrop-gcqEJMnO.js → objects-BJTP843m.js} +73 -1
  100. package/dist/admin/chunks/objects-BJTP843m.js.map +1 -0
  101. package/dist/admin/chunks/{useDragAndDrop-HYwNDExe.js → objects-D2z-IJgu.mjs} +72 -2
  102. package/dist/admin/chunks/objects-D2z-IJgu.mjs.map +1 -0
  103. package/dist/admin/chunks/{pl-MFCZJZuZ.js → pl-MFCZJZuZ.mjs} +1 -1
  104. package/dist/admin/chunks/pl-MFCZJZuZ.mjs.map +1 -0
  105. package/dist/admin/chunks/{pt-BR-CcotyBGJ.js → pt-BR-CcotyBGJ.mjs} +1 -1
  106. package/dist/admin/chunks/pt-BR-CcotyBGJ.mjs.map +1 -0
  107. package/dist/admin/chunks/{pt-HbmgeiYO.js → pt-HbmgeiYO.mjs} +1 -1
  108. package/dist/admin/chunks/pt-HbmgeiYO.mjs.map +1 -0
  109. package/dist/admin/chunks/{ru-CB4BUyQp.js → ru-CB4BUyQp.mjs} +1 -1
  110. package/dist/admin/chunks/{ru-CB4BUyQp.js.map → ru-CB4BUyQp.mjs.map} +1 -1
  111. package/dist/admin/chunks/{sa-n_aPA-pU.js → sa-n_aPA-pU.mjs} +1 -1
  112. package/dist/admin/chunks/sa-n_aPA-pU.mjs.map +1 -0
  113. package/dist/admin/chunks/{sk-tn_BDjE2.js → sk-tn_BDjE2.mjs} +1 -1
  114. package/dist/admin/chunks/sk-tn_BDjE2.mjs.map +1 -0
  115. package/dist/admin/chunks/{sv-cq4ZrQRd.js → sv-cq4ZrQRd.mjs} +1 -1
  116. package/dist/admin/chunks/sv-cq4ZrQRd.mjs.map +1 -0
  117. package/dist/admin/chunks/{th-mUH7hEtc.js → th-mUH7hEtc.mjs} +1 -1
  118. package/dist/admin/chunks/th-mUH7hEtc.mjs.map +1 -0
  119. package/dist/admin/chunks/{tr-Yt38daxh.js → tr-Yt38daxh.mjs} +1 -1
  120. package/dist/admin/chunks/tr-Yt38daxh.mjs.map +1 -0
  121. package/dist/admin/chunks/uk-BtM6WnaE.mjs +313 -0
  122. package/dist/admin/chunks/uk-BtM6WnaE.mjs.map +1 -0
  123. package/dist/admin/chunks/uk-DB6OgySY.js +318 -0
  124. package/dist/admin/chunks/{en-C1CjdAtC.js.map → uk-DB6OgySY.js.map} +1 -1
  125. package/dist/admin/chunks/{relations-CmoFVrKj.js → usePrev-DgZBp9Oo.js} +18 -2
  126. package/dist/admin/chunks/usePrev-DgZBp9Oo.js.map +1 -0
  127. package/dist/admin/chunks/{relations-DYQAaXwZ.js → usePrev-PisKKvhT.mjs} +18 -4
  128. package/dist/admin/chunks/usePrev-PisKKvhT.mjs.map +1 -0
  129. package/dist/admin/chunks/{vi-CvBGlTjr.js → vi-CvBGlTjr.mjs} +1 -1
  130. package/dist/admin/chunks/vi-CvBGlTjr.mjs.map +1 -0
  131. package/dist/admin/chunks/{zh-BmF-sHaT.js → zh-BmF-sHaT.mjs} +1 -1
  132. package/dist/admin/chunks/zh-BmF-sHaT.mjs.map +1 -0
  133. package/dist/admin/chunks/{zh-Hans-CI0HKio3.js → zh-Hans-CI0HKio3.mjs} +1 -1
  134. package/dist/admin/chunks/{zh-Hans-CI0HKio3.js.map → zh-Hans-CI0HKio3.mjs.map} +1 -1
  135. package/dist/admin/index.js +2 -1
  136. package/dist/admin/index.js.map +1 -1
  137. package/dist/admin/index.mjs +2 -1
  138. package/dist/admin/index.mjs.map +1 -1
  139. package/dist/admin/src/components/InjectionZone.d.ts +7 -1
  140. package/dist/admin/src/content-manager.d.ts +4 -0
  141. package/dist/admin/src/features/DocumentContext.d.ts +53 -0
  142. package/dist/admin/src/features/DocumentRBAC.d.ts +3 -2
  143. package/dist/admin/src/hooks/useDocument.d.ts +2 -0
  144. package/dist/admin/src/hooks/useDocumentActions.d.ts +1 -0
  145. package/dist/admin/src/index.d.ts +1 -0
  146. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +2 -1
  147. package/dist/admin/src/pages/EditView/components/EditorToolbarObserver.d.ts +11 -0
  148. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/Code.d.ts +49 -0
  149. package/dist/admin/src/pages/EditView/components/FormInputs/Relations/RelationModal.d.ts +8 -0
  150. package/dist/admin/src/pages/EditView/components/FormInputs/{Relations.d.ts → Relations/Relations.d.ts} +8 -2
  151. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygNav.d.ts +1 -2
  152. package/dist/admin/src/pages/EditView/components/FormLayout.d.ts +9 -3
  153. package/dist/admin/src/pages/EditView/components/InputRenderer.d.ts +7 -4
  154. package/dist/admin/src/preview/components/PreviewHeader.d.ts +1 -2
  155. package/dist/admin/src/preview/pages/Preview.d.ts +2 -0
  156. package/dist/server/index.js +1 -1
  157. package/dist/server/index.js.map +1 -1
  158. package/dist/server/index.mjs +1 -1
  159. package/dist/server/index.mjs.map +1 -1
  160. package/package.json +8 -8
  161. package/dist/admin/chunks/CardDragPreview-DwuraT0K.js.map +0 -1
  162. package/dist/admin/chunks/ComponentConfigurationPage-DhYZp4nN.js.map +0 -1
  163. package/dist/admin/chunks/ComponentIcon-BZcTc4rj.js.map +0 -1
  164. package/dist/admin/chunks/EditConfigurationPage-DDuPch5d.js.map +0 -1
  165. package/dist/admin/chunks/EditViewPage-jCZnUuCR.js +0 -265
  166. package/dist/admin/chunks/EditViewPage-jCZnUuCR.js.map +0 -1
  167. package/dist/admin/chunks/EditViewPage-zSnDwLz3.js +0 -288
  168. package/dist/admin/chunks/EditViewPage-zSnDwLz3.js.map +0 -1
  169. package/dist/admin/chunks/FieldTypeIcon-BY6MrVF4.js.map +0 -1
  170. package/dist/admin/chunks/Form-CZmB6JIg.js.map +0 -1
  171. package/dist/admin/chunks/History-BlLKDZSw.js.map +0 -1
  172. package/dist/admin/chunks/History-CPYXgxkS.js.map +0 -1
  173. package/dist/admin/chunks/Input-CLX3C5DI.js.map +0 -1
  174. package/dist/admin/chunks/Input-DiR2Xfa7.js.map +0 -1
  175. package/dist/admin/chunks/ListConfigurationPage-CNvotSqe.js.map +0 -1
  176. package/dist/admin/chunks/ListViewPage-MJNfQTp-.js.map +0 -1
  177. package/dist/admin/chunks/NoContentTypePage-CVvVpwj4.js.map +0 -1
  178. package/dist/admin/chunks/NoPermissionsPage-C5yWg70d.js.map +0 -1
  179. package/dist/admin/chunks/Preview-DEuQgQg2.js +0 -482
  180. package/dist/admin/chunks/Preview-DEuQgQg2.js.map +0 -1
  181. package/dist/admin/chunks/Preview-H74FQ9Cq.js +0 -504
  182. package/dist/admin/chunks/Preview-H74FQ9Cq.js.map +0 -1
  183. package/dist/admin/chunks/Relations-C8jbZPVK.js +0 -827
  184. package/dist/admin/chunks/Relations-C8jbZPVK.js.map +0 -1
  185. package/dist/admin/chunks/Relations-mxOUS7TJ.js +0 -853
  186. package/dist/admin/chunks/Relations-mxOUS7TJ.js.map +0 -1
  187. package/dist/admin/chunks/ar-DckYq_WK.js.map +0 -1
  188. package/dist/admin/chunks/ca-DviY7mRj.js.map +0 -1
  189. package/dist/admin/chunks/cs-C7OSYFQ7.js.map +0 -1
  190. package/dist/admin/chunks/de-5QRlDHyR.js.map +0 -1
  191. package/dist/admin/chunks/es-DkoWSExG.js.map +0 -1
  192. package/dist/admin/chunks/eu-BG1xX7HK.js.map +0 -1
  193. package/dist/admin/chunks/fr-CFdRaRVj.js.map +0 -1
  194. package/dist/admin/chunks/gu-D5MMMXRs.js.map +0 -1
  195. package/dist/admin/chunks/hi-lp17SCjr.js.map +0 -1
  196. package/dist/admin/chunks/hooks-DMvik5y_.js.map +0 -1
  197. package/dist/admin/chunks/hu-CLka1U2C.js.map +0 -1
  198. package/dist/admin/chunks/id-USfY9m1g.js.map +0 -1
  199. package/dist/admin/chunks/index-BRlRBRLb.js.map +0 -1
  200. package/dist/admin/chunks/index-ZIwOPk6p.js.map +0 -1
  201. package/dist/admin/chunks/it-BAHrwmYS.js.map +0 -1
  202. package/dist/admin/chunks/ja-BWKmBJFT.js.map +0 -1
  203. package/dist/admin/chunks/ko-CgADGBNt.js.map +0 -1
  204. package/dist/admin/chunks/layout-B3-guCPG.js.map +0 -1
  205. package/dist/admin/chunks/layout-ameRNiAM.js.map +0 -1
  206. package/dist/admin/chunks/ml-CnhCfOn_.js.map +0 -1
  207. package/dist/admin/chunks/ms-Bh09NFff.js.map +0 -1
  208. package/dist/admin/chunks/nl-C8HYflTc.js.map +0 -1
  209. package/dist/admin/chunks/objects-C3EebVVe.js +0 -76
  210. package/dist/admin/chunks/objects-C3EebVVe.js.map +0 -1
  211. package/dist/admin/chunks/objects-wl73iEma.js +0 -73
  212. package/dist/admin/chunks/objects-wl73iEma.js.map +0 -1
  213. package/dist/admin/chunks/pl-MFCZJZuZ.js.map +0 -1
  214. package/dist/admin/chunks/pt-BR-CcotyBGJ.js.map +0 -1
  215. package/dist/admin/chunks/pt-HbmgeiYO.js.map +0 -1
  216. package/dist/admin/chunks/relations-CmoFVrKj.js.map +0 -1
  217. package/dist/admin/chunks/relations-DYQAaXwZ.js.map +0 -1
  218. package/dist/admin/chunks/sa-n_aPA-pU.js.map +0 -1
  219. package/dist/admin/chunks/sk-tn_BDjE2.js.map +0 -1
  220. package/dist/admin/chunks/sv-cq4ZrQRd.js.map +0 -1
  221. package/dist/admin/chunks/th-mUH7hEtc.js.map +0 -1
  222. package/dist/admin/chunks/tr-Yt38daxh.js.map +0 -1
  223. package/dist/admin/chunks/uk-B24MoTVg.js +0 -145
  224. package/dist/admin/chunks/uk-B24MoTVg.js.map +0 -1
  225. package/dist/admin/chunks/uk-Cpgmm7gE.js +0 -140
  226. package/dist/admin/chunks/uk-Cpgmm7gE.js.map +0 -1
  227. package/dist/admin/chunks/useDragAndDrop-HYwNDExe.js.map +0 -1
  228. package/dist/admin/chunks/useDragAndDrop-gcqEJMnO.js.map +0 -1
  229. package/dist/admin/chunks/usePrev-Bjw2dhmq.js +0 -18
  230. package/dist/admin/chunks/usePrev-Bjw2dhmq.js.map +0 -1
  231. package/dist/admin/chunks/usePrev-DIYl-IAL.js +0 -21
  232. package/dist/admin/chunks/usePrev-DIYl-IAL.js.map +0 -1
  233. package/dist/admin/chunks/vi-CvBGlTjr.js.map +0 -1
  234. package/dist/admin/chunks/zh-BmF-sHaT.js.map +0 -1
  235. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/utils/prismLanguages.d.ts +0 -0
  236. package/dist/admin/src/preview/components/PreviewContent.d.ts +0 -3
@@ -1,27 +1,75 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
- import { useState, useEffect, useCallback, memo } from 'react';
4
- import { useStrapiApp, createContext, useField, useForm, useNotification, useAPIErrorHandler, useQueryParams, useFocusInputField, InputRenderer as InputRenderer$1 } from '@strapi/admin/strapi-admin';
5
- import { Box, SingleSelect, SingleSelectOption, Typography, Flex, BaseLink, Button, Popover, Field, Tooltip, IconButton, useComposedRefs, Portal, FocusTrap, Divider, VisuallyHidden, Accordion, Menu, MenuItem, Grid as Grid$1, TextInput, IconButtonGroup, TextButton } from '@strapi/design-system';
6
- import { CodeBlock as CodeBlock$1, HeadingOne, HeadingTwo, HeadingThree, HeadingFour, HeadingFive, HeadingSix, Image as Image$1, NumberList, BulletList, Paragraph, Quotes, Link as Link$1, Drag, Collapse, Bold, Italic, Underline, StrikeThrough, Code, Expand, PlusCircle, Trash, More, EyeStriked, CheckCircle, WarningCircle, Loader, ArrowClockwise, Plus } from '@strapi/icons';
3
+ import { useState, useEffect, useCallback } from 'react';
4
+ import { useStrapiApp, useElementOnScreen, createContext, useField, useForm, useNotification, Form, ConfirmDialog, useRBAC, DescriptionComponentRenderer, useQueryParams, useFocusInputField, useAPIErrorHandler, InputRenderer as InputRenderer$1 } from '@strapi/admin/strapi-admin';
5
+ import { Box, SingleSelect, SingleSelectOption, Typography, Flex, Button, Popover, Field, Menu, IconButton, Tooltip, useComposedRefs, Portal, FocusTrap, Divider, VisuallyHidden, Accordion, MenuItem, Grid as Grid$1, TextInput, Modal, TextButton, Dialog, Loader, EmptyStateLayout, Link as Link$2, Combobox, ComboboxOption, IconButtonGroup } from '@strapi/design-system';
6
+ import { CodeBlock as CodeBlock$1, HeadingOne, HeadingTwo, HeadingThree, HeadingFour, HeadingFive, HeadingSix, Image as Image$1, NumberList, BulletList, Paragraph, Quotes, More, Link as Link$1, Drag, Collapse, Bold, Italic, Underline, StrikeThrough, Code, Expand, PlusCircle, Trash, EyeStriked, ArrowLeft, ArrowsOut, WarningCircle, ArrowClockwise, Cross, CheckCircle, Loader as Loader$1, Plus } from '@strapi/icons';
7
7
  import { useIntl } from 'react-intl';
8
- import { g as getTranslation, m as useDocLayout, c as useDoc, n as createDefaultForm, t as transformDocument, e as contentManagerApi, o as CLONE_PATH, d as buildValidParams, f as useDocumentRBAC, S as SINGLE_TYPES } from './index-BRlRBRLb.js';
8
+ import { g as getTranslation, c as useDocumentContext, d as useDocumentLayout, e as createDefaultForm, t as transformDocument, f as useLazyGetDocumentQuery, h as createYupSchema, P as PERMISSIONS, i as DocumentRBAC, j as DocumentActionButton, D as DocumentStatus, C as COLLECTION_TYPES, S as SINGLE_TYPES, k as buildValidParams, l as contentManagerApi, m as useDoc, n as CLONE_PATH, o as useDocumentRBAC } from './index-BE7PI9Wp.mjs';
9
9
  import { styled, css, keyframes } from 'styled-components';
10
10
  import { Editor as Editor$1, Transforms, Node, Element, Range, Path, Point, createEditor } from 'slate';
11
11
  import { withHistory } from 'slate-history';
12
12
  import { useFocused, useSelected, ReactEditor, Editable, Slate, useSlate, withReact } from 'slate-react';
13
13
  import * as Prism from 'prismjs';
14
14
  import 'prismjs/themes/prism-solarizedlight.css';
15
- import { p as prefixFileUrlWithBackendUrl, u as usePrev } from './usePrev-Bjw2dhmq.js';
16
- import { a as DIRECTIONS, u as useDragAndDrop, I as ItemTypes } from './useDragAndDrop-HYwNDExe.js';
15
+ import 'prismjs/components/prism-asmatmel';
16
+ import 'prismjs/components/prism-bash';
17
+ import 'prismjs/components/prism-basic';
18
+ import 'prismjs/components/prism-c';
19
+ import 'prismjs/components/prism-clojure';
20
+ import 'prismjs/components/prism-cobol';
21
+ import 'prismjs/components/prism-cpp';
22
+ import 'prismjs/components/prism-csharp';
23
+ import 'prismjs/components/prism-dart';
24
+ import 'prismjs/components/prism-docker';
25
+ import 'prismjs/components/prism-elixir';
26
+ import 'prismjs/components/prism-erlang';
27
+ import 'prismjs/components/prism-fortran';
28
+ import 'prismjs/components/prism-fsharp';
29
+ import 'prismjs/components/prism-go';
30
+ import 'prismjs/components/prism-graphql';
31
+ import 'prismjs/components/prism-groovy';
32
+ import 'prismjs/components/prism-haskell';
33
+ import 'prismjs/components/prism-haxe';
34
+ import 'prismjs/components/prism-ini';
35
+ import 'prismjs/components/prism-java';
36
+ import 'prismjs/components/prism-javascript';
37
+ import 'prismjs/components/prism-jsx';
38
+ import 'prismjs/components/prism-json';
39
+ import 'prismjs/components/prism-julia';
40
+ import 'prismjs/components/prism-kotlin';
41
+ import 'prismjs/components/prism-latex';
42
+ import 'prismjs/components/prism-lua';
43
+ import 'prismjs/components/prism-markdown';
44
+ import 'prismjs/components/prism-matlab';
45
+ import 'prismjs/components/prism-makefile';
46
+ import 'prismjs/components/prism-objectivec';
47
+ import 'prismjs/components/prism-perl';
48
+ import 'prismjs/components/prism-php';
49
+ import 'prismjs/components/prism-powershell';
50
+ import 'prismjs/components/prism-python';
51
+ import 'prismjs/components/prism-r';
52
+ import 'prismjs/components/prism-ruby';
53
+ import 'prismjs/components/prism-rust';
54
+ import 'prismjs/components/prism-sas';
55
+ import 'prismjs/components/prism-scala';
56
+ import 'prismjs/components/prism-scheme';
57
+ import 'prismjs/components/prism-sql';
58
+ import 'prismjs/components/prism-stata';
59
+ import 'prismjs/components/prism-swift';
60
+ import 'prismjs/components/prism-typescript';
61
+ import 'prismjs/components/prism-tsx';
62
+ import 'prismjs/components/prism-vbnet';
63
+ import 'prismjs/components/prism-yaml';
64
+ import { p as prefixFileUrlWithBackendUrl, u as useGetRelationsQuery, g as getRelationLabel, a as useDebounce, b as useLazySearchRelationsQuery, c as usePrev } from './usePrev-PisKKvhT.mjs';
65
+ import { D as DIRECTIONS, u as useDragAndDrop, I as ItemTypes, g as getIn, a as DROP_SENSITIVITY } from './objects-D2z-IJgu.mjs';
17
66
  import * as Toolbar from '@radix-ui/react-toolbar';
18
67
  import { getEmptyImage } from 'react-dnd-html5-backend';
19
- import { useMatch, useLocation } from 'react-router-dom';
20
- import { g as getIn } from './objects-wl73iEma.js';
21
- import { u as useComponent, C as ComponentProvider, M as MemoizedRelationsField } from './Relations-C8jbZPVK.js';
68
+ import { useNavigate, useLocation, useMatch } from 'react-router-dom';
22
69
  import pipe$1 from 'lodash/fp/pipe';
23
- import { C as ComponentIcon, a as COMPONENT_ICONS } from './ComponentIcon-BZcTc4rj.js';
24
- import { a as useDebounce } from './relations-DYQAaXwZ.js';
70
+ import { C as ComponentIcon, a as COMPONENT_ICONS } from './ComponentIcon-BZcTc4rj.mjs';
71
+ import { generateNKeysBetween } from 'fractional-indexing';
72
+ import { FixedSizeList } from 'react-window';
25
73
  import CodeMirror from 'codemirror5';
26
74
  import sanitizeHtml from 'sanitize-html';
27
75
  import { getLanguage, highlight, highlightAuto } from 'highlight.js';
@@ -410,11 +458,6 @@ const isText$2 = (node)=>{
410
458
  }
411
459
  };
412
460
 
413
- if (typeof window !== 'undefined' && !window.Prism) {
414
- window.Prism = Prism;
415
- }
416
- // NOTE: use dynamic requires to ensure they are run after Prism is set globally
417
- require('./utils/prismLanguages');
418
461
  const decorateCode = ([node, path])=>{
419
462
  const ranges = [];
420
463
  // make sure it is an Slate Element
@@ -987,7 +1030,7 @@ const isListNode$1 = (element)=>{
987
1030
  return element.type === 'list';
988
1031
  };
989
1032
 
990
- const StyledBaseLink = styled(BaseLink)`
1033
+ const StyledLink = styled(Box)`
991
1034
  text-decoration: none;
992
1035
  `;
993
1036
  const RemoveButton = styled(Button)`
@@ -1047,9 +1090,10 @@ const LinkContent = /*#__PURE__*/ React.forwardRef(({ link, children, attributes
1047
1090
  open: popoverOpen,
1048
1091
  children: [
1049
1092
  /*#__PURE__*/ jsx(Popover.Trigger, {
1050
- children: /*#__PURE__*/ jsx(StyledBaseLink, {
1093
+ children: /*#__PURE__*/ jsx(StyledLink, {
1051
1094
  ...attributes,
1052
1095
  ref: forwardedRef,
1096
+ tag: "a",
1053
1097
  href: link.url,
1054
1098
  onClick: ()=>setPopoverOpen(true),
1055
1099
  color: "primary600",
@@ -1653,13 +1697,103 @@ const quoteBlocks = {
1653
1697
  }
1654
1698
  };
1655
1699
 
1700
+ const ObservedToolbarComponent = ({ index, lastVisibleIndex, setLastVisibleIndex, rootRef, children })=>{
1701
+ const isVisible = index <= lastVisibleIndex;
1702
+ const containerRef = useElementOnScreen((isVisible)=>{
1703
+ /**
1704
+ * It's the MoreMenu's job to make an item not visible when there's not room for it.
1705
+ * But we need to react here to the element becoming visible again.
1706
+ */ if (isVisible) {
1707
+ setLastVisibleIndex((prev)=>Math.max(prev, index));
1708
+ }
1709
+ }, {
1710
+ threshold: 1,
1711
+ root: rootRef.current
1712
+ });
1713
+ return /*#__PURE__*/ jsx("div", {
1714
+ ref: containerRef,
1715
+ style: {
1716
+ /**
1717
+ * Use visibility so that the element occupies the space if requires even when there's not
1718
+ * enough room for it to be visible. The empty reserved space will be clipped by the
1719
+ * overflow:hidden rule on the parent, so it doesn't affect the UI.
1720
+ * This way we can keep observing its visiblity and react to browser resize events.
1721
+ */ visibility: isVisible ? 'visible' : 'hidden'
1722
+ },
1723
+ children: children
1724
+ });
1725
+ };
1726
+ const EditorToolbarObserver = ({ observedComponents, menuTriggerVariant = 'ghost' })=>{
1727
+ const { formatMessage } = useIntl();
1728
+ const toolbarRef = React.useRef(null);
1729
+ const [lastVisibleIndex, setLastVisibleIndex] = React.useState(observedComponents.length - 1);
1730
+ const hasHiddenItems = lastVisibleIndex < observedComponents.length - 1;
1731
+ const menuIndex = lastVisibleIndex + 1;
1732
+ const [open, setOpen] = React.useState(false);
1733
+ const isMenuOpenWithContent = open && hasHiddenItems;
1734
+ const menuTriggerRef = useElementOnScreen((isVisible)=>{
1735
+ // We only react to the menu becoming invisible. When that happens, we hide the last item.
1736
+ if (!isVisible) {
1737
+ /**
1738
+ * If there's no room for any item, the index can be -1.
1739
+ * This is intentional, in that case only the more menu will be visible.
1740
+ **/ setLastVisibleIndex((prev)=>prev - 1);
1741
+ // Maintain the menu state if it has content
1742
+ setOpen(isMenuOpenWithContent);
1743
+ }
1744
+ }, {
1745
+ threshold: 1,
1746
+ root: toolbarRef.current
1747
+ });
1748
+ return observedComponents.map((component, index)=>{
1749
+ return /*#__PURE__*/ jsx(ObservedToolbarComponent, {
1750
+ index: index,
1751
+ lastVisibleIndex: lastVisibleIndex,
1752
+ setLastVisibleIndex: setLastVisibleIndex,
1753
+ rootRef: toolbarRef,
1754
+ children: component.toolbar
1755
+ }, component.key);
1756
+ }).toSpliced(menuIndex, 0, /*#__PURE__*/ jsxs(Menu.Root, {
1757
+ defaultOpen: false,
1758
+ open: isMenuOpenWithContent,
1759
+ onOpenChange: setOpen,
1760
+ children: [
1761
+ /*#__PURE__*/ jsx(Menu.Trigger, {
1762
+ paddingLeft: 0,
1763
+ paddingRight: 0,
1764
+ ref: menuTriggerRef,
1765
+ variant: menuTriggerVariant,
1766
+ style: {
1767
+ visibility: hasHiddenItems ? 'visible' : 'hidden'
1768
+ },
1769
+ label: formatMessage({
1770
+ id: 'global.more',
1771
+ defaultMessage: 'More'
1772
+ }),
1773
+ tag: IconButton,
1774
+ icon: /*#__PURE__*/ jsx(More, {})
1775
+ }),
1776
+ /*#__PURE__*/ jsx(Menu.Content, {
1777
+ onCloseAutoFocus: (e)=>e.preventDefault(),
1778
+ maxHeight: "100%",
1779
+ minWidth: "256px",
1780
+ popoverPlacement: "bottom-end",
1781
+ zIndex: 2,
1782
+ children: observedComponents.slice(menuIndex).map((component)=>/*#__PURE__*/ jsx(React.Fragment, {
1783
+ children: component.menu
1784
+ }, component.key))
1785
+ })
1786
+ ]
1787
+ }, "more-menu"));
1788
+ };
1789
+
1656
1790
  const ToolbarWrapper = styled(Flex)`
1657
1791
  &[aria-disabled='true'] {
1658
1792
  cursor: not-allowed;
1659
1793
  background: ${({ theme })=>theme.colors.neutral150};
1660
1794
  }
1661
1795
  `;
1662
- const Separator = styled(Toolbar.Separator)`
1796
+ const ToolbarSeparator = styled(Toolbar.Separator)`
1663
1797
  background: ${({ theme })=>theme.colors.neutral150};
1664
1798
  width: 1px;
1665
1799
  height: 2.4rem;
@@ -1729,7 +1863,7 @@ const ToolbarButton = ({ icon: Icon, name, label, isActive, disabled, handleClic
1729
1863
  const labelMessage = formatMessage(label);
1730
1864
  const enabledColor = isActive ? 'primary600' : 'neutral600';
1731
1865
  return /*#__PURE__*/ jsx(Tooltip, {
1732
- description: labelMessage,
1866
+ label: labelMessage,
1733
1867
  children: /*#__PURE__*/ jsx(Toolbar.ToggleItem, {
1734
1868
  value: name,
1735
1869
  "data-state": isActive ? 'on' : 'off',
@@ -1921,8 +2055,9 @@ const BlockOption = ({ value, icon: Icon, label, blockSelected })=>{
1921
2055
  const isListNode = (node)=>{
1922
2056
  return Node.isNode(node) && !Editor$1.isEditor(node) && node.type === 'list';
1923
2057
  };
1924
- const ListButton = ({ block, format })=>{
2058
+ const ListButton = ({ block, format, location = 'toolbar' })=>{
1925
2059
  const { editor, disabled, blocks } = useBlocksEditorContext('ListButton');
2060
+ const { formatMessage } = useIntl();
1926
2061
  const isListActive = ()=>{
1927
2062
  if (!editor.selection) return false;
1928
2063
  // Get the parent list at selection anchor node
@@ -1998,6 +2133,18 @@ const ListButton = ({ block, format })=>{
1998
2133
  }
1999
2134
  }
2000
2135
  };
2136
+ if (location === 'menu') {
2137
+ const Icon = block.icon;
2138
+ return /*#__PURE__*/ jsxs(StyledMenuItem, {
2139
+ onSelect: ()=>toggleList(format),
2140
+ isActive: isListActive(),
2141
+ disabled: isListDisabled(),
2142
+ children: [
2143
+ /*#__PURE__*/ jsx(Icon, {}),
2144
+ formatMessage(block.label)
2145
+ ]
2146
+ });
2147
+ }
2001
2148
  return /*#__PURE__*/ jsx(ToolbarButton, {
2002
2149
  icon: block.icon,
2003
2150
  name: format,
@@ -2007,8 +2154,9 @@ const ListButton = ({ block, format })=>{
2007
2154
  handleClick: ()=>toggleList(format)
2008
2155
  });
2009
2156
  };
2010
- const LinkButton = ({ disabled })=>{
2157
+ const LinkButton = ({ disabled, location = 'toolbar' })=>{
2011
2158
  const { editor } = useBlocksEditorContext('LinkButton');
2159
+ const { formatMessage } = useIntl();
2012
2160
  const isLinkActive = ()=>{
2013
2161
  const { selection } = editor;
2014
2162
  if (!selection) return false;
@@ -2049,20 +2197,55 @@ const LinkButton = ({ disabled })=>{
2049
2197
  url: ''
2050
2198
  });
2051
2199
  };
2200
+ const label = {
2201
+ id: 'components.Blocks.link',
2202
+ defaultMessage: 'Link'
2203
+ };
2204
+ if (location === 'menu') {
2205
+ return /*#__PURE__*/ jsxs(StyledMenuItem, {
2206
+ onSelect: addLink,
2207
+ isActive: isLinkActive(),
2208
+ disabled: isLinkDisabled(),
2209
+ children: [
2210
+ /*#__PURE__*/ jsx(Link$1, {}),
2211
+ formatMessage(label)
2212
+ ]
2213
+ });
2214
+ }
2052
2215
  return /*#__PURE__*/ jsx(ToolbarButton, {
2053
2216
  icon: Link$1,
2054
2217
  name: "link",
2055
- label: {
2056
- id: 'components.Blocks.link',
2057
- defaultMessage: 'Link'
2058
- },
2218
+ label: label,
2059
2219
  isActive: isLinkActive(),
2060
2220
  handleClick: addLink,
2061
2221
  disabled: isLinkDisabled()
2062
2222
  });
2063
2223
  };
2224
+ const StyledMenuItem = styled(Menu.Item)`
2225
+ &:hover {
2226
+ background-color: ${({ theme })=>theme.colors.primary100};
2227
+ }
2228
+
2229
+ ${(props)=>props.isActive && css`
2230
+ font-weight: bold;
2231
+ background-color: ${({ theme })=>theme.colors.primary100};
2232
+ color: ${({ theme })=>theme.colors.primary600};
2233
+ font-weight: bold;
2234
+ `}
2235
+
2236
+ > span {
2237
+ display: inline-flex;
2238
+ gap: ${({ theme })=>theme.spaces[2]};
2239
+ align-items: center;
2240
+ }
2241
+
2242
+ svg {
2243
+ fill: ${({ theme, isActive })=>isActive ? theme.colors.primary600 : theme.colors.neutral600};
2244
+ }
2245
+ `;
2064
2246
  const BlocksToolbar = ()=>{
2065
2247
  const { editor, blocks, modifiers, disabled } = useBlocksEditorContext('BlocksToolbar');
2248
+ const { formatMessage } = useIntl();
2066
2249
  /**
2067
2250
  * The modifier buttons are disabled when an image is selected.
2068
2251
  */ const checkButtonDisabled = ()=>{
@@ -2083,6 +2266,94 @@ const BlocksToolbar = ()=>{
2083
2266
  return false;
2084
2267
  };
2085
2268
  const isButtonDisabled = checkButtonDisabled();
2269
+ /**
2270
+ * Observed components are ones that may or may not be visible in the toolbar, depending on the
2271
+ * available space. They provide two render props:
2272
+ * - renderInToolbar: for when we try to render the component in the toolbar (may be hidden)
2273
+ * - renderInMenu: for when the component didn't fit in the toolbar and is relegated
2274
+ * to the "more" menu
2275
+ */ const observedComponents = [
2276
+ ...Object.entries(modifiers).map(([name, modifier])=>{
2277
+ const Icon = modifier.icon;
2278
+ const isActive = modifier.checkIsActive(editor);
2279
+ const handleSelect = ()=>modifier.handleToggle(editor);
2280
+ return {
2281
+ toolbar: /*#__PURE__*/ jsx(ToolbarButton, {
2282
+ name: name,
2283
+ icon: modifier.icon,
2284
+ label: modifier.label,
2285
+ isActive: modifier.checkIsActive(editor),
2286
+ handleClick: handleSelect,
2287
+ disabled: isButtonDisabled
2288
+ }, name),
2289
+ menu: /*#__PURE__*/ jsxs(StyledMenuItem, {
2290
+ onSelect: handleSelect,
2291
+ isActive: isActive,
2292
+ children: [
2293
+ /*#__PURE__*/ jsx(Icon, {}),
2294
+ formatMessage(modifier.label)
2295
+ ]
2296
+ }),
2297
+ key: `modifier.${name}`
2298
+ };
2299
+ }),
2300
+ {
2301
+ toolbar: /*#__PURE__*/ jsx(LinkButton, {
2302
+ disabled: isButtonDisabled,
2303
+ location: "toolbar"
2304
+ }),
2305
+ menu: /*#__PURE__*/ jsx(LinkButton, {
2306
+ disabled: isButtonDisabled,
2307
+ location: "menu"
2308
+ }),
2309
+ key: 'block.link'
2310
+ },
2311
+ {
2312
+ // List buttons can only be rendered together when in the toolbar
2313
+ toolbar: /*#__PURE__*/ jsxs(Flex, {
2314
+ direction: "row",
2315
+ gap: 1,
2316
+ children: [
2317
+ /*#__PURE__*/ jsx(ToolbarSeparator, {}),
2318
+ /*#__PURE__*/ jsx(Toolbar.ToggleGroup, {
2319
+ type: "single",
2320
+ asChild: true,
2321
+ children: /*#__PURE__*/ jsxs(Flex, {
2322
+ gap: 1,
2323
+ children: [
2324
+ /*#__PURE__*/ jsx(ListButton, {
2325
+ block: blocks['list-unordered'],
2326
+ format: "unordered",
2327
+ location: "toolbar"
2328
+ }),
2329
+ /*#__PURE__*/ jsx(ListButton, {
2330
+ block: blocks['list-ordered'],
2331
+ format: "ordered",
2332
+ location: "toolbar"
2333
+ })
2334
+ ]
2335
+ })
2336
+ })
2337
+ ]
2338
+ }),
2339
+ menu: /*#__PURE__*/ jsxs(Fragment, {
2340
+ children: [
2341
+ /*#__PURE__*/ jsx(Menu.Separator, {}),
2342
+ /*#__PURE__*/ jsx(ListButton, {
2343
+ block: blocks['list-unordered'],
2344
+ format: "unordered",
2345
+ location: "menu"
2346
+ }),
2347
+ /*#__PURE__*/ jsx(ListButton, {
2348
+ block: blocks['list-ordered'],
2349
+ format: "ordered",
2350
+ location: "menu"
2351
+ })
2352
+ ]
2353
+ }),
2354
+ key: 'block.list'
2355
+ }
2356
+ ];
2086
2357
  return /*#__PURE__*/ jsx(Toolbar.Root, {
2087
2358
  "aria-disabled": disabled,
2088
2359
  asChild: true,
@@ -2092,43 +2363,18 @@ const BlocksToolbar = ()=>{
2092
2363
  width: "100%",
2093
2364
  children: [
2094
2365
  /*#__PURE__*/ jsx(BlocksDropdown, {}),
2095
- /*#__PURE__*/ jsx(Separator, {}),
2366
+ /*#__PURE__*/ jsx(ToolbarSeparator, {}),
2096
2367
  /*#__PURE__*/ jsx(Toolbar.ToggleGroup, {
2097
2368
  type: "multiple",
2098
2369
  asChild: true,
2099
- children: /*#__PURE__*/ jsxs(Flex, {
2100
- gap: 1,
2101
- children: [
2102
- Object.entries(modifiers).map(([name, modifier])=>/*#__PURE__*/ jsx(ToolbarButton, {
2103
- name: name,
2104
- icon: modifier.icon,
2105
- label: modifier.label,
2106
- isActive: modifier.checkIsActive(editor),
2107
- handleClick: ()=>modifier.handleToggle(editor),
2108
- disabled: isButtonDisabled
2109
- }, name)),
2110
- /*#__PURE__*/ jsx(LinkButton, {
2111
- disabled: isButtonDisabled
2112
- })
2113
- ]
2114
- })
2115
- }),
2116
- /*#__PURE__*/ jsx(Separator, {}),
2117
- /*#__PURE__*/ jsx(Toolbar.ToggleGroup, {
2118
- type: "single",
2119
- asChild: true,
2120
- children: /*#__PURE__*/ jsxs(Flex, {
2370
+ children: /*#__PURE__*/ jsx(Flex, {
2371
+ direction: "row",
2121
2372
  gap: 1,
2122
- children: [
2123
- /*#__PURE__*/ jsx(ListButton, {
2124
- block: blocks['list-unordered'],
2125
- format: "unordered"
2126
- }),
2127
- /*#__PURE__*/ jsx(ListButton, {
2128
- block: blocks['list-ordered'],
2129
- format: "ordered"
2130
- })
2131
- ]
2373
+ grow: 1,
2374
+ overflow: "hidden",
2375
+ children: /*#__PURE__*/ jsx(EditorToolbarObserver, {
2376
+ observedComponents: observedComponents
2377
+ })
2132
2378
  })
2133
2379
  })
2134
2380
  ]
@@ -3217,6 +3463,20 @@ const Initializer = ({ disabled, name, onClick })=>{
3217
3463
  });
3218
3464
  };
3219
3465
 
3466
+ /**
3467
+ * We use this component to wrap any individual component field in the Edit View,
3468
+ * this could be a component field in a dynamic zone, a component within a repeatable space,
3469
+ * or even nested components.
3470
+ *
3471
+ * We primarily need this to provide the component id to the components so that they can
3472
+ * correctly fetch their relations.
3473
+ */ const [ComponentProvider, useComponent] = createContext('ComponentContext', {
3474
+ id: undefined,
3475
+ level: -1,
3476
+ uid: undefined,
3477
+ type: undefined
3478
+ });
3479
+
3220
3480
  const AddComponentButton = ({ hasError, isDisabled, isOpen, children, onClick })=>{
3221
3481
  return /*#__PURE__*/ jsx(StyledButton, {
3222
3482
  type: "button",
@@ -3322,15 +3582,24 @@ const ComponentCategory = ({ category, components = [], variant = 'primary', onA
3322
3582
  const ResponsiveAccordionContent = styled(Accordion.Content)`
3323
3583
  container-type: inline-size;
3324
3584
  `;
3325
- const Grid = styled(Box)`
3326
- display: grid;
3327
- grid-template-columns: repeat(auto-fill, 100%);
3328
- grid-gap: ${({ theme })=>theme.spaces[1]};
3329
-
3330
- @container (min-width: ${()=>RESPONSIVE_CONTAINER_BREAKPOINTS.sm}) {
3331
- grid-template-columns: repeat(auto-fill, 14rem);
3332
- }
3333
- `;
3585
+ /**
3586
+ * TODO:
3587
+ * JSDOM cannot handle container queries.
3588
+ * This is a temporary workaround so that tests do not fail in the CI when jestdom throws an error
3589
+ * for failing to parse the stylesheet.
3590
+ */ const Grid = process.env.NODE_ENV !== 'test' ? styled(Box)`
3591
+ display: grid;
3592
+ grid-template-columns: repeat(auto-fill, 100%);
3593
+ grid-gap: 4px;
3594
+
3595
+ @container (min-width: ${()=>RESPONSIVE_CONTAINER_BREAKPOINTS.sm}) {
3596
+ grid-template-columns: repeat(auto-fill, 14rem);
3597
+ }
3598
+ ` : styled(Box)`
3599
+ display: grid;
3600
+ grid-template-columns: repeat(auto-fill, 100%);
3601
+ grid-gap: 4px;
3602
+ `;
3334
3603
  const ComponentBox = styled(Flex)`
3335
3604
  color: ${({ theme })=>theme.colors.neutral600};
3336
3605
  cursor: pointer;
@@ -3395,7 +3664,19 @@ const ComponentPicker = ({ dynamicComponentsByCategory = {}, isOpen, onClickAddC
3395
3664
  const DynamicComponent = ({ componentUid, disabled, index, name, onRemoveComponentClick, onMoveComponent, onGrabItem, onDropItem, onCancel, dynamicComponentsByCategory = {}, onAddComponent, children })=>{
3396
3665
  const { formatMessage } = useIntl();
3397
3666
  const formValues = useForm('DynamicComponent', (state)=>state.values);
3398
- const { edit: { components } } = useDocLayout();
3667
+ const documentMeta = useDocumentContext('DynamicComponent', (state)=>state.meta);
3668
+ const rootDocumentMeta = useDocumentContext('DynamicComponent', (state)=>state.rootDocumentMeta);
3669
+ const { edit: { components: rootComponents } } = useDocumentLayout(rootDocumentMeta.model);
3670
+ const { edit: { components: relatedComponents } } = useDocumentLayout(documentMeta.model);
3671
+ // Merge the root level components and related components
3672
+ const components = React.useMemo(()=>({
3673
+ ...rootComponents,
3674
+ ...relatedComponents
3675
+ }), [
3676
+ rootComponents,
3677
+ relatedComponents
3678
+ ]);
3679
+ const document = useDocumentContext('DynamicComponent', (state)=>state.document);
3399
3680
  const title = React.useMemo(()=>{
3400
3681
  const { mainField } = components[componentUid]?.settings ?? {
3401
3682
  mainField: 'id'
@@ -3627,9 +3908,11 @@ const DynamicComponent = ({ componentUid, disabled, index, name, onRemoveCompone
3627
3908
  alignItems: "stretch",
3628
3909
  children: children ? children({
3629
3910
  ...fieldWithTranslatedLabel,
3911
+ document,
3630
3912
  name: fieldName
3631
3913
  }) : /*#__PURE__*/ jsx(MemoizedInputRenderer, {
3632
3914
  ...fieldWithTranslatedLabel,
3915
+ document: document,
3633
3916
  name: fieldName
3634
3917
  })
3635
3918
  }, fieldName);
@@ -3747,7 +4030,8 @@ const DynamicZone = ({ attribute, disabled: disabledProp, hint, label, labelActi
3747
4030
  const { max = Infinity, min = -Infinity } = attribute ?? {};
3748
4031
  const [addComponentIsOpen, setAddComponentIsOpen] = React.useState(false);
3749
4032
  const [liveText, setLiveText] = React.useState('');
3750
- const { components, isLoading } = useDoc();
4033
+ const document = useDocumentContext('DynamicZone', (state)=>state.document);
4034
+ const { components, isLoading } = document;
3751
4035
  const disabled = disabledProp || isLoading;
3752
4036
  const { addFieldRow, removeFieldRow, moveFieldRow } = useForm('DynamicZone', ({ addFieldRow, removeFieldRow, moveFieldRow })=>({
3753
4037
  addFieldRow,
@@ -3980,153 +4264,1386 @@ const NotAllowedInput = ({ hint, label, required, name })=>{
3980
4264
  });
3981
4265
  };
3982
4266
 
3983
- const uidApi = contentManagerApi.injectEndpoints({
3984
- endpoints: (builder)=>({
3985
- getDefaultUID: builder.query({
3986
- query: ({ params, ...data })=>{
3987
- return {
3988
- url: '/content-manager/uid/generate',
3989
- method: 'POST',
3990
- data,
3991
- config: {
3992
- params
3993
- }
3994
- };
3995
- },
3996
- transformResponse: (response)=>response.data
3997
- }),
3998
- generateUID: builder.mutation({
3999
- query: ({ params, ...data })=>({
4000
- url: '/content-manager/uid/generate',
4001
- method: 'POST',
4002
- data,
4003
- config: {
4004
- params
4005
- }
4006
- }),
4007
- transformResponse: (response)=>response.data
4008
- }),
4009
- getAvailability: builder.query({
4010
- query: ({ params, ...data })=>({
4011
- url: '/content-manager/uid/check-availability',
4012
- method: 'POST',
4013
- data,
4014
- config: {
4015
- params
4016
- }
4017
- }),
4018
- providesTags: (_res, _error, params)=>[
4019
- {
4020
- type: 'UidAvailability',
4021
- id: params.contentTypeUID
4022
- }
4023
- ]
4024
- })
4025
- })
4267
+ function getCollectionType(url) {
4268
+ const regex = new RegExp(`(${COLLECTION_TYPES}|${SINGLE_TYPES})`);
4269
+ const match = url.match(regex);
4270
+ return match ? match[1] : undefined;
4271
+ }
4272
+ const CustomModalContent = styled(Modal.Content)`
4273
+ width: 90%;
4274
+ max-width: 100%;
4275
+ height: 90%;
4276
+ max-height: 100%;
4277
+ `;
4278
+ const [RelationModalProvider, useRelationModal] = createContext('RelationModal', {
4279
+ parentModified: false,
4280
+ depth: 0
4026
4281
  });
4027
- const { useGenerateUIDMutation, useGetDefaultUIDQuery, useGetAvailabilityQuery } = uidApi;
4028
-
4029
- /* -------------------------------------------------------------------------------------------------
4030
- * InputUID
4031
- * -----------------------------------------------------------------------------------------------*/ const UID_REGEX = /^[A-Za-z0-9-_.~]*$/;
4032
- const UIDInput = /*#__PURE__*/ React.forwardRef(({ hint, label, labelAction, name, required, ...props }, ref)=>{
4033
- const { model, id } = useDoc();
4034
- const allFormValues = useForm('InputUID', (form)=>form.values);
4035
- const [availability, setAvailability] = React.useState();
4036
- const [showRegenerate, setShowRegenerate] = React.useState(false);
4037
- const isCloning = useMatch(CLONE_PATH) !== null;
4038
- const field = useField(name);
4039
- const debouncedValue = useDebounce(field.value, 300);
4040
- const hasChanged = debouncedValue !== field.initialValue;
4041
- const { toggleNotification } = useNotification();
4042
- const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
4282
+ const RelationModalForm = ({ relation, triggerButtonLabel })=>{
4283
+ const navigate = useNavigate();
4284
+ const { pathname, search } = useLocation();
4043
4285
  const { formatMessage } = useIntl();
4044
- const [{ query }] = useQueryParams();
4045
- const params = React.useMemo(()=>buildValidParams(query), [
4046
- query
4047
- ]);
4048
- const { data: defaultGeneratedUID, isLoading: isGeneratingDefaultUID, error: apiError } = useGetDefaultUIDQuery({
4049
- contentTypeUID: model,
4050
- field: name,
4051
- data: {
4052
- id: id ?? '',
4053
- ...allFormValues
4054
- },
4055
- params
4056
- }, {
4057
- skip: field.value || !required
4058
- });
4059
- React.useEffect(()=>{
4060
- if (apiError) {
4061
- toggleNotification({
4062
- type: 'warning',
4063
- message: formatAPIError(apiError)
4064
- });
4286
+ const [triggerRefetchDocument] = useLazyGetDocumentQuery();
4287
+ const currentDocument = useDocumentContext('RelationModalForm', (state)=>state.document);
4288
+ const rootDocumentMeta = useDocumentContext('RelationModalForm', (state)=>state.rootDocumentMeta);
4289
+ const currentDocumentMeta = useDocumentContext('RelationModalForm', (state)=>state.meta);
4290
+ const changeDocument = useDocumentContext('RelationModalForm', (state)=>state.changeDocument);
4291
+ const documentHistory = useDocumentContext('RelationModalForm', (state)=>state.documentHistory);
4292
+ const setDocumentHistory = useDocumentContext('RelationModalForm', (state)=>state.setDocumentHistory);
4293
+ const [isConfirmationOpen, setIsConfirmationOpen] = React.useState(false);
4294
+ const [actionPosition, setActionPosition] = React.useState('cancel');
4295
+ const [isModalOpen, setIsModalOpen] = React.useState(false);
4296
+ // NOTE: Not sure about this relation modal context, maybe we should move this to DocumentContext?
4297
+ // Get parent modal context if it exists
4298
+ const parentContext = useRelationModal('RelationModalForm', (state)=>state);
4299
+ // Get depth of nested modals
4300
+ const depth = parentContext ? parentContext.depth + 1 : 0;
4301
+ // Check if this is a nested modal
4302
+ const isNested = depth > 0;
4303
+ const addDocumentToHistory = (document)=>setDocumentHistory((prev)=>[
4304
+ ...prev,
4305
+ document
4306
+ ]);
4307
+ const getPreviousDocument = ()=>{
4308
+ if (documentHistory.length === 0) return undefined;
4309
+ const lastDocument = documentHistory[documentHistory.length - 1];
4310
+ return lastDocument;
4311
+ };
4312
+ const removeLastDocumentFromHistory = ()=>{
4313
+ setDocumentHistory((prev)=>[
4314
+ ...prev
4315
+ ].slice(0, prev.length - 1));
4316
+ };
4317
+ const handleToggleModal = ()=>{
4318
+ if (isModalOpen) {
4319
+ setIsModalOpen(false);
4320
+ const document = {
4321
+ collectionType: rootDocumentMeta.collectionType,
4322
+ model: rootDocumentMeta.model,
4323
+ documentId: rootDocumentMeta.documentId
4324
+ };
4325
+ // Change back to the root document
4326
+ changeDocument(document);
4327
+ // Reset the document history
4328
+ setDocumentHistory([]);
4329
+ // Reset action position
4330
+ setActionPosition('cancel');
4331
+ // Read from cache or refetch root document
4332
+ triggerRefetchDocument(document, // Favor the cache
4333
+ true);
4334
+ } else {
4335
+ changeDocument(relation);
4336
+ setIsModalOpen(true);
4065
4337
  }
4066
- }, [
4067
- apiError,
4068
- formatAPIError,
4069
- toggleNotification
4070
- ]);
4071
- /**
4072
- * If the defaultGeneratedUID is available, then we set it as the value,
4073
- * but we also want to set it as the initialValue too.
4074
- */ React.useEffect(()=>{
4075
- if (defaultGeneratedUID && field.value === undefined) {
4076
- field.onChange(name, defaultGeneratedUID);
4338
+ };
4339
+ const getFullPageLink = ()=>{
4340
+ const isSingleType = currentDocumentMeta.collectionType === SINGLE_TYPES;
4341
+ const queryParams = currentDocumentMeta.params?.locale ? `?plugins[i18n][locale]=${currentDocumentMeta.params.locale}` : '';
4342
+ return `/content-manager/${currentDocumentMeta.collectionType}/${currentDocumentMeta.model}${isSingleType ? '' : '/' + currentDocumentMeta.documentId}${queryParams}`;
4343
+ };
4344
+ const handleRedirection = ()=>{
4345
+ const editViewUrl = `${pathname}${search}`;
4346
+ const isRootDocumentUrl = editViewUrl.includes(getFullPageLink());
4347
+ if (isRootDocumentUrl) {
4348
+ handleToggleModal();
4349
+ } else {
4350
+ navigate(getFullPageLink());
4077
4351
  }
4078
- }, [
4079
- defaultGeneratedUID,
4080
- field,
4081
- name
4082
- ]);
4083
- const [generateUID, { isLoading: isGeneratingUID }] = useGenerateUIDMutation();
4084
- const handleRegenerateClick = async ()=>{
4085
- try {
4086
- const res = await generateUID({
4087
- contentTypeUID: model,
4088
- field: name,
4089
- data: {
4090
- id: id ?? '',
4091
- ...allFormValues
4092
- },
4093
- params
4094
- });
4095
- if ('data' in res) {
4096
- field.onChange(name, res.data);
4097
- } else {
4098
- toggleNotification({
4099
- type: 'danger',
4100
- message: formatAPIError(res.error)
4101
- });
4352
+ };
4353
+ const handleConfirm = ()=>{
4354
+ if (actionPosition === 'navigate') {
4355
+ handleRedirection();
4356
+ } else if (actionPosition === 'back') {
4357
+ const previousRelation = getPreviousDocument();
4358
+ if (previousRelation) {
4359
+ removeLastDocumentFromHistory();
4360
+ changeDocument(previousRelation);
4102
4361
  }
4103
- } catch (err) {
4104
- toggleNotification({
4105
- type: 'danger',
4106
- message: formatMessage({
4107
- id: 'notification.error',
4108
- defaultMessage: 'An error occurred.'
4109
- })
4110
- });
4362
+ } else {
4363
+ // Add current relation to history before opening a new one in case we are opening a new one
4364
+ if (currentDocumentMeta && Object.keys(currentDocumentMeta).length > 0) {
4365
+ addDocumentToHistory(currentDocumentMeta);
4366
+ }
4367
+ handleToggleModal();
4111
4368
  }
4112
4369
  };
4113
- const { data: availabilityData, isLoading: isCheckingAvailability, error: availabilityError } = useGetAvailabilityQuery({
4114
- contentTypeUID: model,
4115
- field: name,
4116
- value: debouncedValue ? debouncedValue.trim() : '',
4117
- params
4118
- }, {
4119
- // Don't check availability if the value is empty or wasn't changed
4120
- skip: !Boolean((hasChanged || isCloning) && debouncedValue && UID_REGEX.test(debouncedValue.trim()))
4121
- });
4122
- React.useEffect(()=>{
4123
- if (availabilityError) {
4124
- toggleNotification({
4125
- type: 'warning',
4126
- message: formatAPIError(availabilityError)
4370
+ return /*#__PURE__*/ jsx(Form, {
4371
+ method: "PUT",
4372
+ initialValues: currentDocument.getInitialFormValues(),
4373
+ validate: (values, options)=>{
4374
+ const yupSchema = createYupSchema(currentDocument.schema?.attributes, currentDocument.components, {
4375
+ status: currentDocument.document?.status,
4376
+ ...options
4127
4377
  });
4128
- }
4129
- }, [
4378
+ return yupSchema.validate(values, {
4379
+ abortEarly: false
4380
+ });
4381
+ },
4382
+ children: ({ modified, isSubmitting, resetForm })=>{
4383
+ // We don't count the root document, so history starts after 1
4384
+ const hasHistory = documentHistory.length > 1;
4385
+ return /*#__PURE__*/ jsxs(RelationModalProvider, {
4386
+ parentModified: modified,
4387
+ depth: depth,
4388
+ children: [
4389
+ /*#__PURE__*/ jsxs(Modal.Root, {
4390
+ open: isModalOpen,
4391
+ onOpenChange: ()=>{
4392
+ if (isModalOpen) {
4393
+ if (modified && !isSubmitting) {
4394
+ setIsConfirmationOpen(true);
4395
+ } else {
4396
+ handleToggleModal();
4397
+ }
4398
+ }
4399
+ },
4400
+ children: [
4401
+ /*#__PURE__*/ jsx(Modal.Trigger, {
4402
+ children: /*#__PURE__*/ jsx(Tooltip, {
4403
+ description: triggerButtonLabel,
4404
+ children: /*#__PURE__*/ jsx(CustomTextButton, {
4405
+ onClick: ()=>{
4406
+ // Check if parent modal has unsaved changes
4407
+ if (isNested && parentContext.parentModified) {
4408
+ setIsConfirmationOpen(true);
4409
+ // Return early to avoid opening the modal
4410
+ return;
4411
+ } else {
4412
+ if (modified && !isSubmitting) {
4413
+ setIsConfirmationOpen(true);
4414
+ } else {
4415
+ // Add current relation to history before opening a new one
4416
+ if (currentDocumentMeta && Object.keys(currentDocumentMeta).length > 0) {
4417
+ addDocumentToHistory(currentDocumentMeta);
4418
+ }
4419
+ handleToggleModal();
4420
+ }
4421
+ if (!isModalOpen) {
4422
+ setIsModalOpen(true);
4423
+ }
4424
+ }
4425
+ },
4426
+ width: "100%",
4427
+ children: triggerButtonLabel
4428
+ })
4429
+ })
4430
+ }),
4431
+ /*#__PURE__*/ jsxs(CustomModalContent, {
4432
+ children: [
4433
+ /*#__PURE__*/ jsx(Modal.Header, {
4434
+ gap: 2,
4435
+ children: /*#__PURE__*/ jsx(Flex, {
4436
+ justifyContent: "space-between",
4437
+ alignItems: "center",
4438
+ width: "100%",
4439
+ children: /*#__PURE__*/ jsxs(Flex, {
4440
+ gap: 2,
4441
+ children: [
4442
+ /*#__PURE__*/ jsx(IconButton, {
4443
+ withTooltip: false,
4444
+ label: "Back",
4445
+ variant: "ghost",
4446
+ disabled: !hasHistory,
4447
+ onClick: ()=>{
4448
+ setActionPosition('back');
4449
+ if (modified && !isSubmitting) {
4450
+ setIsConfirmationOpen(true);
4451
+ } else {
4452
+ const previousRelation = getPreviousDocument();
4453
+ if (previousRelation) {
4454
+ removeLastDocumentFromHistory();
4455
+ changeDocument(previousRelation);
4456
+ }
4457
+ }
4458
+ },
4459
+ marginRight: 1,
4460
+ children: /*#__PURE__*/ jsx(ArrowLeft, {})
4461
+ }),
4462
+ /*#__PURE__*/ jsx(Typography, {
4463
+ tag: "span",
4464
+ fontWeight: 600,
4465
+ children: formatMessage({
4466
+ id: 'content-manager.components.RelationInputModal.modal-title',
4467
+ defaultMessage: 'Edit a relation'
4468
+ })
4469
+ })
4470
+ ]
4471
+ })
4472
+ })
4473
+ }),
4474
+ /*#__PURE__*/ jsx(RelationModalBody, {
4475
+ children: /*#__PURE__*/ jsx(IconButton, {
4476
+ onClick: ()=>{
4477
+ setActionPosition('navigate');
4478
+ if (modified && !isSubmitting) {
4479
+ setIsConfirmationOpen(true);
4480
+ } else {
4481
+ navigate(getFullPageLink());
4482
+ }
4483
+ },
4484
+ variant: "tertiary",
4485
+ label: formatMessage({
4486
+ id: 'content-manager.components.RelationInputModal.button-fullpage',
4487
+ defaultMessage: 'Go to entry'
4488
+ }),
4489
+ children: /*#__PURE__*/ jsx(ArrowsOut, {})
4490
+ })
4491
+ }),
4492
+ /*#__PURE__*/ jsx(Modal.Footer, {
4493
+ children: /*#__PURE__*/ jsx(Button, {
4494
+ onClick: ()=>{
4495
+ if (modified && !isSubmitting) {
4496
+ setIsConfirmationOpen(true);
4497
+ } else {
4498
+ handleToggleModal();
4499
+ }
4500
+ },
4501
+ variant: "tertiary",
4502
+ children: formatMessage({
4503
+ id: 'app.components.Button.cancel',
4504
+ defaultMessage: 'Cancel'
4505
+ })
4506
+ })
4507
+ })
4508
+ ]
4509
+ })
4510
+ ]
4511
+ }),
4512
+ /*#__PURE__*/ jsx(Dialog.Root, {
4513
+ open: isConfirmationOpen,
4514
+ onOpenChange: setIsConfirmationOpen,
4515
+ children: /*#__PURE__*/ jsx(ConfirmDialog, {
4516
+ onConfirm: ()=>{
4517
+ handleConfirm();
4518
+ setIsConfirmationOpen(false);
4519
+ resetForm();
4520
+ },
4521
+ onCancel: ()=>{
4522
+ setIsConfirmationOpen(false);
4523
+ },
4524
+ variant: "danger",
4525
+ children: formatMessage({
4526
+ id: 'content-manager.components.RelationInputModal.confirmation-message',
4527
+ defaultMessage: 'Some changes were not saved. Are you sure you want to close this relation? All changes that were not saved will be lost.'
4528
+ })
4529
+ })
4530
+ })
4531
+ ]
4532
+ });
4533
+ }
4534
+ });
4535
+ };
4536
+ const CustomTextButton = styled(TextButton)`
4537
+ & > span {
4538
+ font-size: ${({ theme })=>theme.fontSizes[2]};
4539
+ width: inherit;
4540
+ overflow: hidden;
4541
+ white-space: nowrap;
4542
+ text-overflow: ellipsis;
4543
+ }
4544
+ `;
4545
+ const RelationModalBody = ({ children })=>{
4546
+ const { formatMessage } = useIntl();
4547
+ const documentMeta = useDocumentContext('RelationModalBody', (state)=>state.meta);
4548
+ const documentResponse = useDocumentContext('RelationModalBody', (state)=>state.document);
4549
+ const onPreview = useDocumentContext('RelationModalBody', (state)=>state.onPreview);
4550
+ const documentLayoutResponse = useDocumentLayout(documentMeta.model);
4551
+ const plugins = useStrapiApp('RelationModalBody', (state)=>state.plugins);
4552
+ const initialValues = documentResponse.getInitialFormValues();
4553
+ const { permissions = [], isLoading: isLoadingPermissions, error } = useRBAC(PERMISSIONS.map((action)=>({
4554
+ action,
4555
+ subject: documentMeta.model
4556
+ })));
4557
+ const isLoading = isLoadingPermissions || documentLayoutResponse.isLoading || documentResponse.isLoading;
4558
+ if (isLoading && !documentResponse.document?.documentId) {
4559
+ return /*#__PURE__*/ jsx(Loader, {
4560
+ small: true,
4561
+ children: formatMessage({
4562
+ id: 'content-manager.ListViewTable.relation-loading',
4563
+ defaultMessage: 'Relations are loading'
4564
+ })
4565
+ });
4566
+ }
4567
+ if (error || !documentMeta.model || documentLayoutResponse.error || !documentResponse.document || !documentResponse.meta || !documentResponse.schema || !initialValues) {
4568
+ return /*#__PURE__*/ jsx(Flex, {
4569
+ alignItems: "center",
4570
+ height: "100%",
4571
+ justifyContent: "center",
4572
+ children: /*#__PURE__*/ jsx(EmptyStateLayout, {
4573
+ icon: /*#__PURE__*/ jsx(WarningCircle, {
4574
+ width: "16rem"
4575
+ }),
4576
+ content: formatMessage({
4577
+ id: 'anErrorOccurred',
4578
+ defaultMessage: 'Whoops! Something went wrong. Please, try again.'
4579
+ })
4580
+ })
4581
+ });
4582
+ }
4583
+ const documentTitle = documentResponse.getTitle(documentLayoutResponse.edit.settings.mainField);
4584
+ const hasDraftAndPublished = documentResponse.schema?.options?.draftAndPublish ?? false;
4585
+ const props = {
4586
+ activeTab: 'draft',
4587
+ collectionType: documentMeta.collectionType,
4588
+ model: documentMeta.model,
4589
+ documentId: documentMeta.documentId,
4590
+ document: documentResponse.document,
4591
+ meta: documentResponse.meta,
4592
+ onPreview
4593
+ };
4594
+ return /*#__PURE__*/ jsx(Modal.Body, {
4595
+ children: /*#__PURE__*/ jsxs(DocumentRBAC, {
4596
+ permissions: permissions,
4597
+ model: documentMeta.model,
4598
+ children: [
4599
+ /*#__PURE__*/ jsxs(Flex, {
4600
+ alignItems: "flex-start",
4601
+ direction: "column",
4602
+ gap: 2,
4603
+ children: [
4604
+ /*#__PURE__*/ jsxs(Flex, {
4605
+ width: "100%",
4606
+ justifyContent: "space-between",
4607
+ gap: 2,
4608
+ children: [
4609
+ /*#__PURE__*/ jsx(Typography, {
4610
+ tag: "h2",
4611
+ variant: "alpha",
4612
+ children: documentTitle
4613
+ }),
4614
+ /*#__PURE__*/ jsxs(Flex, {
4615
+ gap: 2,
4616
+ children: [
4617
+ children,
4618
+ /*#__PURE__*/ jsx(DescriptionComponentRenderer, {
4619
+ props: props,
4620
+ descriptions: plugins['content-manager'].apis.getDocumentActions('relation-modal'),
4621
+ children: (actions)=>{
4622
+ const filteredActions = actions.filter((action)=>{
4623
+ return [
4624
+ action.position
4625
+ ].flat().includes('relation-modal');
4626
+ });
4627
+ const [primaryAction, secondaryAction] = filteredActions;
4628
+ if (!primaryAction && !secondaryAction) return null;
4629
+ // Both actions are available when draft and publish enabled
4630
+ if (primaryAction && secondaryAction) {
4631
+ return /*#__PURE__*/ jsxs(Fragment, {
4632
+ children: [
4633
+ /*#__PURE__*/ jsx(DocumentActionButton, {
4634
+ ...secondaryAction,
4635
+ variant: secondaryAction.variant || 'secondary'
4636
+ }),
4637
+ /*#__PURE__*/ jsx(DocumentActionButton, {
4638
+ ...primaryAction,
4639
+ variant: primaryAction.variant || 'default'
4640
+ })
4641
+ ]
4642
+ });
4643
+ }
4644
+ // Otherwise we just have the save action
4645
+ return /*#__PURE__*/ jsx(DocumentActionButton, {
4646
+ ...primaryAction,
4647
+ variant: primaryAction.variant || 'secondary'
4648
+ });
4649
+ }
4650
+ })
4651
+ ]
4652
+ })
4653
+ ]
4654
+ }),
4655
+ hasDraftAndPublished ? /*#__PURE__*/ jsx(Box, {
4656
+ children: /*#__PURE__*/ jsx(DocumentStatus, {
4657
+ status: documentResponse.document?.status
4658
+ })
4659
+ }) : null
4660
+ ]
4661
+ }),
4662
+ /*#__PURE__*/ jsx(Flex, {
4663
+ flex: 1,
4664
+ overflow: "auto",
4665
+ alignItems: "stretch",
4666
+ paddingTop: 7,
4667
+ children: /*#__PURE__*/ jsx(Box, {
4668
+ overflow: "auto",
4669
+ flex: 1,
4670
+ children: /*#__PURE__*/ jsx(FormLayout, {
4671
+ layout: documentLayoutResponse.edit.layout,
4672
+ document: documentResponse,
4673
+ hasBackground: false
4674
+ })
4675
+ })
4676
+ })
4677
+ ]
4678
+ })
4679
+ });
4680
+ };
4681
+
4682
+ /**
4683
+ * Remove a relation, whether it's been already saved or not.
4684
+ * It's used both in RelationsList, where the "remove relation" button is, and in the input,
4685
+ * because we sometimes need to remove a previous relation when selecting a new one.
4686
+ */ function useHandleDisconnect(fieldName, consumerName) {
4687
+ const field = useField(fieldName);
4688
+ const removeFieldRow = useForm(consumerName, (state)=>state.removeFieldRow);
4689
+ const addFieldRow = useForm(consumerName, (state)=>state.addFieldRow);
4690
+ const handleDisconnect = (relation)=>{
4691
+ if (field.value && field.value.connect) {
4692
+ /**
4693
+ * A relation will exist in the `connect` array _if_ it has
4694
+ * been added without saving. In this case, we just remove it
4695
+ * from the connect array
4696
+ */ const indexOfRelationInConnectArray = field.value.connect.findIndex((rel)=>rel.id === relation.id);
4697
+ if (indexOfRelationInConnectArray >= 0) {
4698
+ removeFieldRow(`${fieldName}.connect`, indexOfRelationInConnectArray);
4699
+ return;
4700
+ }
4701
+ }
4702
+ addFieldRow(`${fieldName}.disconnect`, {
4703
+ id: relation.id,
4704
+ apiData: {
4705
+ id: relation.id,
4706
+ documentId: relation.documentId,
4707
+ locale: relation.locale
4708
+ }
4709
+ });
4710
+ };
4711
+ return handleDisconnect;
4712
+ }
4713
+ /* -------------------------------------------------------------------------------------------------
4714
+ * RelationsField
4715
+ * -----------------------------------------------------------------------------------------------*/ const RELATIONS_TO_DISPLAY = 5;
4716
+ const ONE_WAY_RELATIONS = [
4717
+ 'oneWay',
4718
+ 'oneToOne',
4719
+ 'manyToOne',
4720
+ 'oneToManyMorph',
4721
+ 'oneToOneMorph'
4722
+ ];
4723
+ /**
4724
+ * TODO: we get a rather ugly flash when we remove a single relation from the list leaving
4725
+ * no other relations when we press save. The initial relation re-renders, probably because
4726
+ * of the lag in the Form cleaning it's "disconnect" array, whilst our data has not been invalidated.
4727
+ *
4728
+ * Could we invalidate relation data on the document actions? Should we?
4729
+ */ /**
4730
+ * @internal
4731
+ * @description The relations field holds a lot of domain logic for handling relations which is rather complicated
4732
+ * At present we do not expose this to plugin developers, however, they are able to overwrite it themselves should
4733
+ * they wish to do so.
4734
+ */ const RelationsField = /*#__PURE__*/ React.forwardRef(({ disabled, label, ...props }, ref)=>{
4735
+ const currentDocumentMeta = useDocumentContext('RelationsField', (state)=>state.meta);
4736
+ const currentDocument = useDocumentContext('RelationsField', (state)=>state.document);
4737
+ const rootDocumentMeta = useDocumentContext('RelationsField', (state)=>state.rootDocumentMeta);
4738
+ const [currentPage, setCurrentPage] = React.useState(1);
4739
+ const isRootDocument = rootDocumentMeta.documentId === currentDocumentMeta.documentId;
4740
+ const documentMeta = isRootDocument ? rootDocumentMeta : currentDocumentMeta;
4741
+ // Use the documentId from the actual document, not the params (meta)
4742
+ const documentId = currentDocument.document?.documentId;
4743
+ const { formatMessage } = useIntl();
4744
+ const [{ query }] = useQueryParams();
4745
+ const params = documentMeta.params ?? buildValidParams(query);
4746
+ const isMorph = props.attribute.relation.toLowerCase().includes('morph');
4747
+ const isDisabled = isMorph || disabled;
4748
+ const { componentId, componentUID } = useComponent('RelationsField', ({ uid, id })=>({
4749
+ componentId: id,
4750
+ componentUID: uid
4751
+ }));
4752
+ const isSubmitting = useForm('RelationsList', (state)=>state.isSubmitting);
4753
+ React.useEffect(()=>{
4754
+ setCurrentPage(1);
4755
+ }, [
4756
+ isSubmitting
4757
+ ]);
4758
+ const component = componentUID && currentDocument.components[componentUID];
4759
+ /**
4760
+ * We'll always have a documentId in a created entry, so we look for a componentId first.
4761
+ * Same with `uid` and `documentModel`.
4762
+ */ const model = component ? component.uid : documentMeta.model;
4763
+ const id = component && componentId ? componentId.toString() : documentId;
4764
+ /**
4765
+ * The `name` prop is a complete path to the field, e.g. `field1.field2.field3`.
4766
+ * Where the above example would a nested field within two components, however
4767
+ * we only require the field on the component not the complete path since we query
4768
+ * individual components. Therefore we split the string and take the last item.
4769
+ */ const [targetField] = props.name.split('.').slice(-1);
4770
+ const schemaAttributes = component ? component.attributes ?? {} : currentDocument.schema?.attributes ?? {};
4771
+ /**
4772
+ * Confirm the target field is related to the current document.
4773
+ * Since relations can exist in a modal on top of the root document,
4774
+ * we need to ensure we are fetching relations for the correct document (root document vs related document),
4775
+ */ const isRelatedToCurrentDocument = Object.values(schemaAttributes).filter((attribute)=>attribute.type === 'relation' && 'target' in attribute && 'target' in props.attribute && attribute.target === props.attribute.target).length > 0;
4776
+ const { data, isLoading, isFetching } = useGetRelationsQuery({
4777
+ model,
4778
+ targetField,
4779
+ // below we don't run the query if there is no id.
4780
+ id,
4781
+ params: {
4782
+ ...params,
4783
+ pageSize: RELATIONS_TO_DISPLAY,
4784
+ page: currentPage
4785
+ }
4786
+ }, {
4787
+ refetchOnMountOrArgChange: true,
4788
+ skip: !id || !isRelatedToCurrentDocument,
4789
+ selectFromResult: (result)=>{
4790
+ return {
4791
+ ...result,
4792
+ data: {
4793
+ ...result.data,
4794
+ results: result.data?.results ? result.data.results : []
4795
+ }
4796
+ };
4797
+ }
4798
+ });
4799
+ const handleLoadMore = ()=>{
4800
+ setCurrentPage((prev)=>prev + 1);
4801
+ };
4802
+ const field = useField(props.name);
4803
+ const isFetchingMoreRelations = isLoading || isFetching;
4804
+ const realServerRelationsCount = 'pagination' in data && data.pagination ? data.pagination.total : 0;
4805
+ /**
4806
+ * Items that are already connected, but reordered would be in
4807
+ * this list, so to get an accurate figure, we remove them.
4808
+ */ const relationsConnected = (field.value?.connect ?? []).filter((rel)=>data.results.findIndex((relation)=>relation.id === rel.id) === -1).length ?? 0;
4809
+ const relationsDisconnected = field.value?.disconnect?.length ?? 0;
4810
+ const relationsCount = realServerRelationsCount + relationsConnected - relationsDisconnected;
4811
+ /**
4812
+ * This is it, the source of truth for reordering in conjunction with partial loading & updating
4813
+ * of relations. Relations on load are given __temp_key__ when fetched, because we don't want to
4814
+ * create brand new keys everytime the data updates, just keep adding them onto the newly loaded ones.
4815
+ */ const relations = React.useMemo(()=>{
4816
+ const ctx = {
4817
+ field: field.value,
4818
+ // @ts-expect-error – targetModel does exist on the attribute. But it's not typed.
4819
+ href: `../${COLLECTION_TYPES}/${props.attribute.targetModel}`,
4820
+ mainField: props.mainField
4821
+ };
4822
+ /**
4823
+ * Tidy up our data.
4824
+ */ const transformations = pipe$1(removeConnected(ctx), removeDisconnected(ctx), addLabelAndHref(ctx));
4825
+ const transformedRels = transformations([
4826
+ ...data.results
4827
+ ]);
4828
+ /**
4829
+ * THIS IS CRUCIAL. If you don't sort by the __temp_key__ which comes from fractional indexing
4830
+ * then the list will be in the wrong order.
4831
+ */ return [
4832
+ ...transformedRels,
4833
+ ...field.value?.connect ?? []
4834
+ ].sort((a, b)=>{
4835
+ if (a.__temp_key__ < b.__temp_key__) return -1;
4836
+ if (a.__temp_key__ > b.__temp_key__) return 1;
4837
+ return 0;
4838
+ });
4839
+ }, [
4840
+ data.results,
4841
+ field.value,
4842
+ // @ts-expect-error – targetModel does exist on the attribute. But it's not typed.
4843
+ props.attribute.targetModel,
4844
+ props.mainField
4845
+ ]);
4846
+ const handleDisconnect = useHandleDisconnect(props.name, 'RelationsField');
4847
+ const handleConnect = (relation)=>{
4848
+ const [lastItemInList] = relations.slice(-1);
4849
+ const item = {
4850
+ id: relation.id,
4851
+ apiData: {
4852
+ id: relation.id,
4853
+ documentId: relation.documentId,
4854
+ locale: relation.locale
4855
+ },
4856
+ status: relation.status,
4857
+ /**
4858
+ * If there's a last item, that's the first key we use to generate out next one.
4859
+ */ __temp_key__: generateNKeysBetween(lastItemInList?.__temp_key__ ?? null, null, 1)[0],
4860
+ // Fallback to `id` if there is no `mainField` value, which will overwrite the above `id` property with the exact same data.
4861
+ [props.mainField?.name ?? 'documentId']: relation[props.mainField?.name ?? 'documentId'],
4862
+ label: getRelationLabel(relation, props.mainField),
4863
+ // @ts-expect-error – targetModel does exist on the attribute, but it's not typed.
4864
+ href: `../${COLLECTION_TYPES}/${props.attribute.targetModel}/${relation.documentId}?${relation.locale ? `plugins[i18n][locale]=${relation.locale}` : ''}`
4865
+ };
4866
+ if (ONE_WAY_RELATIONS.includes(props.attribute.relation)) {
4867
+ // Remove any existing relation so they can be replaced with the new one
4868
+ field.value?.connect?.forEach(handleDisconnect);
4869
+ relations.forEach(handleDisconnect);
4870
+ field.onChange(`${props.name}.connect`, [
4871
+ item
4872
+ ]);
4873
+ } else {
4874
+ field.onChange(`${props.name}.connect`, [
4875
+ ...field.value?.connect ?? [],
4876
+ item
4877
+ ]);
4878
+ }
4879
+ };
4880
+ return /*#__PURE__*/ jsxs(Flex, {
4881
+ ref: ref,
4882
+ direction: "column",
4883
+ gap: 3,
4884
+ justifyContent: "space-between",
4885
+ alignItems: "stretch",
4886
+ wrap: "wrap",
4887
+ children: [
4888
+ /*#__PURE__*/ jsxs(StyledFlex, {
4889
+ direction: "column",
4890
+ alignItems: "start",
4891
+ gap: 2,
4892
+ width: "100%",
4893
+ children: [
4894
+ /*#__PURE__*/ jsx(RelationsInput, {
4895
+ disabled: isDisabled,
4896
+ // NOTE: we should not default to using the documentId if the component is being created (componentUID is undefined)
4897
+ id: componentUID && component ? componentId ? `${componentId}` : '' : documentId,
4898
+ label: `${label} ${relationsCount > 0 ? `(${relationsCount})` : ''}`,
4899
+ model: model,
4900
+ onChange: handleConnect,
4901
+ isRelatedToCurrentDocument: isRelatedToCurrentDocument,
4902
+ ...props
4903
+ }),
4904
+ 'pagination' in data && data.pagination && data.pagination.pageCount > data.pagination.page ? /*#__PURE__*/ jsx(TextButton, {
4905
+ disabled: isFetchingMoreRelations,
4906
+ onClick: handleLoadMore,
4907
+ loading: isFetchingMoreRelations,
4908
+ startIcon: /*#__PURE__*/ jsx(ArrowClockwise, {}),
4909
+ // prevent the label from line-wrapping
4910
+ shrink: 0,
4911
+ children: formatMessage({
4912
+ id: getTranslation('relation.loadMore'),
4913
+ defaultMessage: 'Load More'
4914
+ })
4915
+ }) : null
4916
+ ]
4917
+ }),
4918
+ /*#__PURE__*/ jsx(RelationsList, {
4919
+ data: relations,
4920
+ serverData: data.results,
4921
+ disabled: isDisabled,
4922
+ name: props.name,
4923
+ isLoading: isFetchingMoreRelations,
4924
+ relationType: props.attribute.relation,
4925
+ // @ts-expect-error – targetModel does exist on the attribute. But it's not typed.
4926
+ targetModel: props.attribute.targetModel
4927
+ })
4928
+ ]
4929
+ });
4930
+ });
4931
+ /**
4932
+ * TODO: this can be removed once we stop shipping Inputs with
4933
+ * labels wrapped round in DS@2.
4934
+ */ const StyledFlex = styled(Flex)`
4935
+ & > div {
4936
+ width: 100%;
4937
+ }
4938
+ `;
4939
+ /**
4940
+ * If it's in the connected array, it can get out of our data array,
4941
+ * we'll be putting it back in later and sorting it anyway.
4942
+ */ const removeConnected = ({ field })=>(relations)=>{
4943
+ return relations.filter((relation)=>{
4944
+ const connectedRelations = field?.connect ?? [];
4945
+ return connectedRelations.findIndex((rel)=>rel.id === relation.id) === -1;
4946
+ });
4947
+ };
4948
+ /**
4949
+ * @description Removes relations that are in the `disconnect` array of the field
4950
+ */ const removeDisconnected = ({ field })=>(relations)=>relations.filter((relation)=>{
4951
+ const disconnectedRelations = field?.disconnect ?? [];
4952
+ return disconnectedRelations.findIndex((rel)=>rel.id === relation.id) === -1;
4953
+ });
4954
+ /**
4955
+ * @description Adds a label and href to the relation object we use this to render
4956
+ * a better UI where we can link to the relation and display a human-readable label.
4957
+ */ const addLabelAndHref = ({ mainField, href })=>(relations)=>relations.map((relation)=>{
4958
+ return {
4959
+ ...relation,
4960
+ // Fallback to `id` if there is no `mainField` value, which will overwrite the above `documentId` property with the exact same data.
4961
+ [mainField?.name ?? 'documentId']: relation[mainField?.name ?? 'documentId'],
4962
+ label: getRelationLabel(relation, mainField),
4963
+ href: `${href}/${relation.documentId}?${relation.locale ? `plugins[i18n][locale]=${relation.locale}` : ''}`
4964
+ };
4965
+ });
4966
+ /**
4967
+ * @description Contains all the logic for the combobox that can search
4968
+ * for relations and then add them to the field's connect array.
4969
+ */ const RelationsInput = ({ hint, id, model, label, labelAction, name, mainField, placeholder, required, unique: _unique, 'aria-label': _ariaLabel, onChange, isRelatedToCurrentDocument, ...props })=>{
4970
+ const [textValue, setTextValue] = React.useState('');
4971
+ const [searchParams, setSearchParams] = React.useState({
4972
+ _q: '',
4973
+ page: 1
4974
+ });
4975
+ const { toggleNotification } = useNotification();
4976
+ const [{ query }] = useQueryParams();
4977
+ const currentDocumentMeta = useDocumentContext('RelationsInput', (state)=>state.meta);
4978
+ const rootDocumentMeta = useDocumentContext('RelationsInput', (state)=>state.rootDocumentMeta);
4979
+ const isRootDocument = rootDocumentMeta.documentId === currentDocumentMeta.documentId;
4980
+ const documentMeta = isRootDocument ? rootDocumentMeta : currentDocumentMeta;
4981
+ const { formatMessage } = useIntl();
4982
+ const fieldRef = useFocusInputField(name);
4983
+ const field = useField(name);
4984
+ const searchParamsDebounced = useDebounce(searchParams, 300);
4985
+ const [searchForTrigger, { data, isLoading }] = useLazySearchRelationsQuery();
4986
+ /**
4987
+ * Because we're using a lazy query, we need to trigger the search
4988
+ * when the component mounts and when the search params change.
4989
+ * We also need to trigger the search when the field value changes
4990
+ * so that we can filter out the relations that are already connected.
4991
+ */ React.useEffect(()=>{
4992
+ /**
4993
+ * The `name` prop is a complete path to the field, e.g. `field1.field2.field3`.
4994
+ * Where the above example would a nested field within two components, however
4995
+ * we only require the field on the component not the complete path since we query
4996
+ * individual components. Therefore we split the string and take the last item.
4997
+ */ const [targetField] = name.split('.').slice(-1);
4998
+ // Return early if there is no relation to the document
4999
+ if (!isRelatedToCurrentDocument) return;
5000
+ const params = documentMeta.params ?? buildValidParams(query);
5001
+ searchForTrigger({
5002
+ model,
5003
+ targetField,
5004
+ params: {
5005
+ ...params,
5006
+ id: id ?? '',
5007
+ pageSize: 10,
5008
+ idsToInclude: field.value?.disconnect?.map((rel)=>rel.id.toString()) ?? [],
5009
+ idsToOmit: field.value?.connect?.map((rel)=>rel.id.toString()) ?? [],
5010
+ ...searchParamsDebounced
5011
+ }
5012
+ });
5013
+ }, [
5014
+ field.value?.connect,
5015
+ field.value?.disconnect,
5016
+ id,
5017
+ model,
5018
+ name,
5019
+ query,
5020
+ searchForTrigger,
5021
+ searchParamsDebounced,
5022
+ isRelatedToCurrentDocument,
5023
+ documentMeta
5024
+ ]);
5025
+ const handleSearch = async (search)=>{
5026
+ setSearchParams((s)=>({
5027
+ ...s,
5028
+ _q: search,
5029
+ page: 1
5030
+ }));
5031
+ };
5032
+ const hasNextPage = data?.pagination ? data.pagination.page < data.pagination.pageCount : false;
5033
+ const options = data?.results ?? [];
5034
+ const handleChange = (relationId)=>{
5035
+ if (!relationId) {
5036
+ return;
5037
+ }
5038
+ const relation = options.find((opt)=>opt.id.toString() === relationId);
5039
+ if (!relation) {
5040
+ // This is very unlikely to happen, but it ensures we don't have any data for.
5041
+ console.error("You've tried to add a relation with an id that does not exist in the options you can see, this is likely a bug with Strapi. Please open an issue.");
5042
+ toggleNotification({
5043
+ message: formatMessage({
5044
+ id: getTranslation('relation.error-adding-relation'),
5045
+ defaultMessage: 'An error occurred while trying to add the relation.'
5046
+ }),
5047
+ type: 'danger'
5048
+ });
5049
+ return;
5050
+ }
5051
+ /**
5052
+ * You need to give this relation a correct _temp_key_ but
5053
+ * this component doesn't know about those ones, you can't rely
5054
+ * on the connect array because that doesn't hold items that haven't
5055
+ * moved. So use a callback to fill in the gaps when connecting.
5056
+ *
5057
+ */ onChange(relation);
5058
+ };
5059
+ const handleLoadMore = ()=>{
5060
+ if (!data || !data.pagination) {
5061
+ return;
5062
+ } else if (data.pagination.page < data.pagination.pageCount) {
5063
+ setSearchParams((s)=>({
5064
+ ...s,
5065
+ page: s.page + 1
5066
+ }));
5067
+ }
5068
+ };
5069
+ React.useLayoutEffect(()=>{
5070
+ setTextValue('');
5071
+ }, [
5072
+ field.value
5073
+ ]);
5074
+ return /*#__PURE__*/ jsxs(Field.Root, {
5075
+ error: field.error,
5076
+ hint: hint,
5077
+ name: name,
5078
+ required: required,
5079
+ children: [
5080
+ /*#__PURE__*/ jsx(Field.Label, {
5081
+ action: labelAction,
5082
+ children: label
5083
+ }),
5084
+ /*#__PURE__*/ jsx(Combobox, {
5085
+ ref: fieldRef,
5086
+ name: name,
5087
+ autocomplete: "list",
5088
+ placeholder: placeholder || formatMessage({
5089
+ id: getTranslation('relation.add'),
5090
+ defaultMessage: 'Add relation'
5091
+ }),
5092
+ hasMoreItems: hasNextPage,
5093
+ loading: isLoading,
5094
+ onOpenChange: ()=>{
5095
+ handleSearch(textValue ?? '');
5096
+ },
5097
+ noOptionsMessage: ()=>formatMessage({
5098
+ id: getTranslation('relation.notAvailable'),
5099
+ defaultMessage: 'No relations available'
5100
+ }),
5101
+ loadingMessage: formatMessage({
5102
+ id: getTranslation('relation.isLoading'),
5103
+ defaultMessage: 'Relations are loading'
5104
+ }),
5105
+ onLoadMore: handleLoadMore,
5106
+ textValue: textValue,
5107
+ onChange: handleChange,
5108
+ onTextValueChange: (text)=>{
5109
+ setTextValue(text);
5110
+ },
5111
+ onInputChange: (event)=>{
5112
+ handleSearch(event.currentTarget.value);
5113
+ },
5114
+ ...props,
5115
+ children: options.map((opt)=>{
5116
+ const textValue = getRelationLabel(opt, mainField);
5117
+ return /*#__PURE__*/ jsx(ComboboxOption, {
5118
+ value: opt.id.toString(),
5119
+ textValue: textValue,
5120
+ children: /*#__PURE__*/ jsxs(Flex, {
5121
+ gap: 2,
5122
+ justifyContent: "space-between",
5123
+ children: [
5124
+ /*#__PURE__*/ jsx(Typography, {
5125
+ ellipsis: true,
5126
+ children: textValue
5127
+ }),
5128
+ opt.status ? /*#__PURE__*/ jsx(DocumentStatus, {
5129
+ status: opt.status
5130
+ }) : null
5131
+ ]
5132
+ })
5133
+ }, opt.id);
5134
+ })
5135
+ }),
5136
+ /*#__PURE__*/ jsx(Field.Error, {}),
5137
+ /*#__PURE__*/ jsx(Field.Hint, {})
5138
+ ]
5139
+ });
5140
+ };
5141
+ /* -------------------------------------------------------------------------------------------------
5142
+ * RelationsList
5143
+ * -----------------------------------------------------------------------------------------------*/ const RELATION_ITEM_HEIGHT = 50;
5144
+ const RELATION_GUTTER = 4;
5145
+ const RelationsList = ({ data, serverData, disabled, name, isLoading, relationType, targetModel })=>{
5146
+ const ariaDescriptionId = React.useId();
5147
+ const { formatMessage } = useIntl();
5148
+ const listRef = React.useRef(null);
5149
+ const outerListRef = React.useRef(null);
5150
+ const [overflow, setOverflow] = React.useState();
5151
+ const [liveText, setLiveText] = React.useState('');
5152
+ const field = useField(name);
5153
+ React.useEffect(()=>{
5154
+ if (data.length <= RELATIONS_TO_DISPLAY) {
5155
+ return setOverflow(undefined);
5156
+ }
5157
+ const handleNativeScroll = (e)=>{
5158
+ const el = e.target;
5159
+ const parentScrollContainerHeight = el.parentNode.scrollHeight;
5160
+ const maxScrollBottom = el.scrollHeight - el.scrollTop;
5161
+ if (el.scrollTop === 0) {
5162
+ return setOverflow('bottom');
5163
+ }
5164
+ if (maxScrollBottom === parentScrollContainerHeight) {
5165
+ return setOverflow('top');
5166
+ }
5167
+ return setOverflow('top-bottom');
5168
+ };
5169
+ const outerListRefCurrent = outerListRef?.current;
5170
+ if (!isLoading && data.length > 0 && outerListRefCurrent) {
5171
+ outerListRef.current.addEventListener('scroll', handleNativeScroll);
5172
+ }
5173
+ return ()=>{
5174
+ if (outerListRefCurrent) {
5175
+ outerListRefCurrent.removeEventListener('scroll', handleNativeScroll);
5176
+ }
5177
+ };
5178
+ }, [
5179
+ isLoading,
5180
+ data.length
5181
+ ]);
5182
+ const getItemPos = (index)=>`${index + 1} of ${data.length}`;
5183
+ const handleMoveItem = (newIndex, oldIndex)=>{
5184
+ const item = data[oldIndex];
5185
+ setLiveText(formatMessage({
5186
+ id: getTranslation('dnd.reorder'),
5187
+ defaultMessage: '{item}, moved. New position in list: {position}.'
5188
+ }, {
5189
+ item: item.label ?? item.documentId,
5190
+ position: getItemPos(newIndex)
5191
+ }));
5192
+ /**
5193
+ * Splicing mutates the array, so we need to create a new array
5194
+ */ const newData = [
5195
+ ...data
5196
+ ];
5197
+ const currentRow = data[oldIndex];
5198
+ const startKey = oldIndex > newIndex ? newData[newIndex - 1]?.__temp_key__ : newData[newIndex]?.__temp_key__;
5199
+ const endKey = oldIndex > newIndex ? newData[newIndex]?.__temp_key__ : newData[newIndex + 1]?.__temp_key__;
5200
+ /**
5201
+ * We're moving the relation between two other relations, so
5202
+ * we need to generate a new key that keeps the order
5203
+ */ const [newKey] = generateNKeysBetween(startKey, endKey, 1);
5204
+ newData.splice(oldIndex, 1);
5205
+ newData.splice(newIndex, 0, {
5206
+ ...currentRow,
5207
+ __temp_key__: newKey
5208
+ });
5209
+ /**
5210
+ * Now we diff against the server to understand what's different so we
5211
+ * can keep the connect array nice and tidy. It also needs reversing because
5212
+ * we reverse the relations from the server in the first place.
5213
+ */ const connectedRelations = newData.reduce((acc, relation, currentIndex, array)=>{
5214
+ const relationOnServer = serverData.find((oldRelation)=>oldRelation.id === relation.id);
5215
+ const relationInFront = array[currentIndex + 1];
5216
+ if (!relationOnServer || relationOnServer.__temp_key__ !== relation.__temp_key__) {
5217
+ const position = relationInFront ? {
5218
+ before: relationInFront.documentId,
5219
+ locale: relationInFront.locale,
5220
+ status: 'publishedAt' in relationInFront && relationInFront.publishedAt ? 'published' : 'draft'
5221
+ } : {
5222
+ end: true
5223
+ };
5224
+ const relationWithPosition = {
5225
+ ...relation,
5226
+ ...{
5227
+ apiData: {
5228
+ id: relation.id,
5229
+ documentId: relation.documentId ?? relation.apiData?.documentId ?? '',
5230
+ locale: relation.locale || relation.apiData?.locale,
5231
+ position
5232
+ }
5233
+ }
5234
+ };
5235
+ return [
5236
+ ...acc,
5237
+ relationWithPosition
5238
+ ];
5239
+ }
5240
+ return acc;
5241
+ }, []).toReversed();
5242
+ field.onChange(`${name}.connect`, connectedRelations);
5243
+ };
5244
+ const handleGrabItem = (index)=>{
5245
+ const item = data[index];
5246
+ setLiveText(formatMessage({
5247
+ id: getTranslation('dnd.grab-item'),
5248
+ defaultMessage: `{item}, grabbed. Current position in list: {position}. Press up and down arrow to change position, Spacebar to drop, Escape to cancel.`
5249
+ }, {
5250
+ item: item.label ?? item.documentId,
5251
+ position: getItemPos(index)
5252
+ }));
5253
+ };
5254
+ const handleDropItem = (index)=>{
5255
+ const { href: _href, label, ...item } = data[index];
5256
+ setLiveText(formatMessage({
5257
+ id: getTranslation('dnd.drop-item'),
5258
+ defaultMessage: `{item}, dropped. Final position in list: {position}.`
5259
+ }, {
5260
+ item: label ?? item.documentId,
5261
+ position: getItemPos(index)
5262
+ }));
5263
+ };
5264
+ const handleCancel = (index)=>{
5265
+ const item = data[index];
5266
+ setLiveText(formatMessage({
5267
+ id: getTranslation('dnd.cancel-item'),
5268
+ defaultMessage: '{item}, dropped. Re-order cancelled.'
5269
+ }, {
5270
+ item: item.label ?? item.documentId
5271
+ }));
5272
+ };
5273
+ const handleDisconnect = useHandleDisconnect(name, 'RelationsList');
5274
+ /**
5275
+ * These relation types will only ever have one item
5276
+ * in their list, so you can't reorder a single item!
5277
+ */ const canReorder = !ONE_WAY_RELATIONS.includes(relationType);
5278
+ const dynamicListHeight = data.length > RELATIONS_TO_DISPLAY ? Math.min(data.length, RELATIONS_TO_DISPLAY) * (RELATION_ITEM_HEIGHT + RELATION_GUTTER) + RELATION_ITEM_HEIGHT / 2 : Math.min(data.length, RELATIONS_TO_DISPLAY) * (RELATION_ITEM_HEIGHT + RELATION_GUTTER);
5279
+ return /*#__PURE__*/ jsxs(ShadowBox, {
5280
+ $overflowDirection: overflow,
5281
+ children: [
5282
+ /*#__PURE__*/ jsx(VisuallyHidden, {
5283
+ id: ariaDescriptionId,
5284
+ children: formatMessage({
5285
+ id: getTranslation('dnd.instructions'),
5286
+ defaultMessage: `Press spacebar to grab and re-order`
5287
+ })
5288
+ }),
5289
+ /*#__PURE__*/ jsx(VisuallyHidden, {
5290
+ "aria-live": "assertive",
5291
+ children: liveText
5292
+ }),
5293
+ /*#__PURE__*/ jsx(FixedSizeList, {
5294
+ height: dynamicListHeight,
5295
+ ref: listRef,
5296
+ outerRef: outerListRef,
5297
+ itemCount: data.length,
5298
+ itemSize: RELATION_ITEM_HEIGHT + RELATION_GUTTER,
5299
+ itemData: {
5300
+ ariaDescribedBy: ariaDescriptionId,
5301
+ canDrag: canReorder,
5302
+ disabled,
5303
+ handleCancel,
5304
+ handleDropItem,
5305
+ handleGrabItem,
5306
+ handleMoveItem,
5307
+ name,
5308
+ handleDisconnect,
5309
+ relations: data,
5310
+ targetModel
5311
+ },
5312
+ itemKey: (index)=>data[index].id,
5313
+ innerElementType: "ol",
5314
+ children: ListItem
5315
+ })
5316
+ ]
5317
+ });
5318
+ };
5319
+ const ShadowBox = styled(Box)`
5320
+ position: relative;
5321
+ overflow: hidden;
5322
+ flex: 1;
5323
+
5324
+ &:before,
5325
+ &:after {
5326
+ position: absolute;
5327
+ width: 100%;
5328
+ height: 4px;
5329
+ z-index: 1;
5330
+ }
5331
+
5332
+ &:before {
5333
+ /* TODO: as for DS Table component we would need this to be handled by the DS theme */
5334
+ content: '';
5335
+ background: linear-gradient(rgba(3, 3, 5, 0.2) 0%, rgba(0, 0, 0, 0) 100%);
5336
+ top: 0;
5337
+ opacity: ${({ $overflowDirection })=>$overflowDirection === 'top-bottom' || $overflowDirection === 'top' ? 1 : 0};
5338
+ transition: opacity 0.2s ease-in-out;
5339
+ }
5340
+
5341
+ &:after {
5342
+ /* TODO: as for DS Table component we would need this to be handled by the DS theme */
5343
+ content: '';
5344
+ background: linear-gradient(0deg, rgba(3, 3, 5, 0.2) 0%, rgba(0, 0, 0, 0) 100%);
5345
+ bottom: 0;
5346
+ opacity: ${({ $overflowDirection })=>$overflowDirection === 'top-bottom' || $overflowDirection === 'bottom' ? 1 : 0};
5347
+ transition: opacity 0.2s ease-in-out;
5348
+ }
5349
+ `;
5350
+ const ListItem = ({ data, index, style })=>{
5351
+ const { ariaDescribedBy, canDrag = false, disabled = false, handleCancel, handleDisconnect, handleDropItem, handleGrabItem, handleMoveItem, name, relations, targetModel } = data;
5352
+ const { formatMessage } = useIntl();
5353
+ const { href, id, label, status, documentId, apiData, locale } = relations[index];
5354
+ const [{ handlerId, isDragging, handleKeyDown }, relationRef, dropRef, dragRef, dragPreviewRef] = useDragAndDrop(canDrag && !disabled, {
5355
+ type: `${ItemTypes.RELATION}_${name}`,
5356
+ index,
5357
+ item: {
5358
+ displayedValue: label,
5359
+ status,
5360
+ id: id,
5361
+ index
5362
+ },
5363
+ onMoveItem: handleMoveItem,
5364
+ onDropItem: handleDropItem,
5365
+ onGrabItem: handleGrabItem,
5366
+ onCancel: handleCancel,
5367
+ dropSensitivity: DROP_SENSITIVITY.REGULAR
5368
+ });
5369
+ const composedRefs = useComposedRefs(relationRef, dragRef);
5370
+ React.useEffect(()=>{
5371
+ dragPreviewRef(getEmptyImage());
5372
+ }, [
5373
+ dragPreviewRef
5374
+ ]);
5375
+ return /*#__PURE__*/ jsx(Box, {
5376
+ style: style,
5377
+ tag: "li",
5378
+ ref: dropRef,
5379
+ "aria-describedby": ariaDescribedBy,
5380
+ cursor: canDrag ? 'all-scroll' : 'default',
5381
+ children: isDragging ? /*#__PURE__*/ jsx(RelationItemPlaceholder, {}) : /*#__PURE__*/ jsxs(Flex, {
5382
+ paddingTop: 2,
5383
+ paddingBottom: 2,
5384
+ paddingLeft: canDrag ? 2 : 4,
5385
+ paddingRight: 4,
5386
+ hasRadius: true,
5387
+ borderColor: "neutral200",
5388
+ background: disabled ? 'neutral150' : 'neutral0',
5389
+ justifyContent: "space-between",
5390
+ ref: composedRefs,
5391
+ "data-handler-id": handlerId,
5392
+ children: [
5393
+ /*#__PURE__*/ jsxs(FlexWrapper, {
5394
+ gap: 1,
5395
+ children: [
5396
+ canDrag ? /*#__PURE__*/ jsx(IconButton, {
5397
+ tag: "div",
5398
+ role: "button",
5399
+ tabIndex: 0,
5400
+ withTooltip: false,
5401
+ label: formatMessage({
5402
+ id: getTranslation('components.RelationInput.icon-button-aria-label'),
5403
+ defaultMessage: 'Drag'
5404
+ }),
5405
+ variant: "ghost",
5406
+ onKeyDown: handleKeyDown,
5407
+ disabled: disabled,
5408
+ children: /*#__PURE__*/ jsx(Drag, {})
5409
+ }) : null,
5410
+ /*#__PURE__*/ jsxs(Flex, {
5411
+ width: "100%",
5412
+ minWidth: 0,
5413
+ justifyContent: "space-between",
5414
+ children: [
5415
+ /*#__PURE__*/ jsx(Box, {
5416
+ minWidth: 0,
5417
+ paddingTop: 1,
5418
+ paddingBottom: 1,
5419
+ paddingRight: 4,
5420
+ children: /*#__PURE__*/ jsx(RelationModalForm, {
5421
+ triggerButtonLabel: label,
5422
+ relation: {
5423
+ documentId: documentId ?? apiData?.documentId,
5424
+ model: targetModel,
5425
+ collectionType: getCollectionType(href),
5426
+ params: {
5427
+ locale: locale || apiData?.locale || null
5428
+ }
5429
+ }
5430
+ })
5431
+ }),
5432
+ status ? /*#__PURE__*/ jsx(DocumentStatus, {
5433
+ status: status
5434
+ }) : null
5435
+ ]
5436
+ })
5437
+ ]
5438
+ }),
5439
+ /*#__PURE__*/ jsx(Box, {
5440
+ paddingLeft: 4,
5441
+ children: /*#__PURE__*/ jsx(IconButton, {
5442
+ onClick: ()=>handleDisconnect(relations[index]),
5443
+ disabled: disabled,
5444
+ label: formatMessage({
5445
+ id: getTranslation('relation.disconnect'),
5446
+ defaultMessage: 'Remove'
5447
+ }),
5448
+ variant: "ghost",
5449
+ size: "S",
5450
+ children: /*#__PURE__*/ jsx(Cross, {})
5451
+ })
5452
+ })
5453
+ ]
5454
+ })
5455
+ });
5456
+ };
5457
+ const FlexWrapper = styled(Flex)`
5458
+ width: 100%;
5459
+ /* Used to prevent endAction to be pushed out of container */
5460
+ min-width: 0;
5461
+
5462
+ & > div[role='button'] {
5463
+ cursor: all-scroll;
5464
+ }
5465
+ `;
5466
+ const DisconnectButton = styled.button`
5467
+ svg path {
5468
+ fill: ${({ theme, disabled })=>disabled ? theme.colors.neutral600 : theme.colors.neutral500};
5469
+ }
5470
+
5471
+ &:hover svg path,
5472
+ &:focus svg path {
5473
+ fill: ${({ theme, disabled })=>!disabled && theme.colors.neutral600};
5474
+ }
5475
+ `;
5476
+ const LinkEllipsis = styled(Link$2)`
5477
+ display: block;
5478
+
5479
+ & > span {
5480
+ white-space: nowrap;
5481
+ overflow: hidden;
5482
+ text-overflow: ellipsis;
5483
+ display: block;
5484
+ }
5485
+ `;
5486
+ const RelationItemPlaceholder = ()=>/*#__PURE__*/ jsx(Box, {
5487
+ paddingTop: 2,
5488
+ paddingBottom: 2,
5489
+ paddingLeft: 4,
5490
+ paddingRight: 4,
5491
+ hasRadius: true,
5492
+ borderStyle: "dashed",
5493
+ borderColor: "primary600",
5494
+ borderWidth: "1px",
5495
+ background: "primary100",
5496
+ height: `calc(100% - ${RELATION_GUTTER}px)`
5497
+ });
5498
+ const MemoizedRelationsField = /*#__PURE__*/ React.memo(RelationsField);
5499
+
5500
+ const uidApi = contentManagerApi.injectEndpoints({
5501
+ endpoints: (builder)=>({
5502
+ getDefaultUID: builder.query({
5503
+ query: ({ params, ...data })=>{
5504
+ return {
5505
+ url: '/content-manager/uid/generate',
5506
+ method: 'POST',
5507
+ data,
5508
+ config: {
5509
+ params
5510
+ }
5511
+ };
5512
+ },
5513
+ transformResponse: (response)=>response.data
5514
+ }),
5515
+ generateUID: builder.mutation({
5516
+ query: ({ params, ...data })=>({
5517
+ url: '/content-manager/uid/generate',
5518
+ method: 'POST',
5519
+ data,
5520
+ config: {
5521
+ params
5522
+ }
5523
+ }),
5524
+ transformResponse: (response)=>response.data
5525
+ }),
5526
+ getAvailability: builder.query({
5527
+ query: ({ params, ...data })=>({
5528
+ url: '/content-manager/uid/check-availability',
5529
+ method: 'POST',
5530
+ data,
5531
+ config: {
5532
+ params
5533
+ }
5534
+ }),
5535
+ providesTags: (_res, _error, params)=>[
5536
+ {
5537
+ type: 'UidAvailability',
5538
+ id: params.contentTypeUID
5539
+ }
5540
+ ]
5541
+ })
5542
+ })
5543
+ });
5544
+ const { useGenerateUIDMutation, useGetDefaultUIDQuery, useGetAvailabilityQuery } = uidApi;
5545
+
5546
+ /* -------------------------------------------------------------------------------------------------
5547
+ * InputUID
5548
+ * -----------------------------------------------------------------------------------------------*/ const UID_REGEX = /^[A-Za-z0-9-_.~]*$/;
5549
+ const UIDInput = /*#__PURE__*/ React.forwardRef(({ hint, label, labelAction, name, required, ...props }, ref)=>{
5550
+ const { model, id } = useDoc();
5551
+ const allFormValues = useForm('InputUID', (form)=>form.values);
5552
+ const [availability, setAvailability] = React.useState();
5553
+ const [showRegenerate, setShowRegenerate] = React.useState(false);
5554
+ const isCloning = useMatch(CLONE_PATH) !== null;
5555
+ const field = useField(name);
5556
+ const debouncedValue = useDebounce(field.value, 300);
5557
+ const hasChanged = debouncedValue !== field.initialValue;
5558
+ const { toggleNotification } = useNotification();
5559
+ const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
5560
+ const { formatMessage } = useIntl();
5561
+ const [{ query }] = useQueryParams();
5562
+ const params = React.useMemo(()=>buildValidParams(query), [
5563
+ query
5564
+ ]);
5565
+ const { data: defaultGeneratedUID, isLoading: isGeneratingDefaultUID, error: apiError } = useGetDefaultUIDQuery({
5566
+ contentTypeUID: model,
5567
+ field: name,
5568
+ data: {
5569
+ id: id ?? '',
5570
+ ...allFormValues
5571
+ },
5572
+ params
5573
+ }, {
5574
+ skip: field.value || !required
5575
+ });
5576
+ React.useEffect(()=>{
5577
+ if (apiError) {
5578
+ toggleNotification({
5579
+ type: 'warning',
5580
+ message: formatAPIError(apiError)
5581
+ });
5582
+ }
5583
+ }, [
5584
+ apiError,
5585
+ formatAPIError,
5586
+ toggleNotification
5587
+ ]);
5588
+ /**
5589
+ * If the defaultGeneratedUID is available, then we set it as the value,
5590
+ * but we also want to set it as the initialValue too.
5591
+ */ React.useEffect(()=>{
5592
+ if (defaultGeneratedUID && field.value === undefined) {
5593
+ field.onChange(name, defaultGeneratedUID);
5594
+ }
5595
+ }, [
5596
+ defaultGeneratedUID,
5597
+ field,
5598
+ name
5599
+ ]);
5600
+ const [generateUID, { isLoading: isGeneratingUID }] = useGenerateUIDMutation();
5601
+ const handleRegenerateClick = async ()=>{
5602
+ try {
5603
+ const res = await generateUID({
5604
+ contentTypeUID: model,
5605
+ field: name,
5606
+ data: {
5607
+ id: id ?? '',
5608
+ ...allFormValues
5609
+ },
5610
+ params
5611
+ });
5612
+ if ('data' in res) {
5613
+ field.onChange(name, res.data);
5614
+ } else {
5615
+ toggleNotification({
5616
+ type: 'danger',
5617
+ message: formatAPIError(res.error)
5618
+ });
5619
+ }
5620
+ } catch (err) {
5621
+ toggleNotification({
5622
+ type: 'danger',
5623
+ message: formatMessage({
5624
+ id: 'notification.error',
5625
+ defaultMessage: 'An error occurred.'
5626
+ })
5627
+ });
5628
+ }
5629
+ };
5630
+ const { data: availabilityData, isLoading: isCheckingAvailability, error: availabilityError } = useGetAvailabilityQuery({
5631
+ contentTypeUID: model,
5632
+ field: name,
5633
+ value: debouncedValue ? debouncedValue.trim() : '',
5634
+ params
5635
+ }, {
5636
+ // Don't check availability if the value is empty or wasn't changed
5637
+ skip: !Boolean((hasChanged || isCloning) && debouncedValue && UID_REGEX.test(debouncedValue.trim()))
5638
+ });
5639
+ React.useEffect(()=>{
5640
+ if (availabilityError) {
5641
+ toggleNotification({
5642
+ type: 'warning',
5643
+ message: formatAPIError(availabilityError)
5644
+ });
5645
+ }
5646
+ }, [
4130
5647
  availabilityError,
4131
5648
  formatAPIError,
4132
5649
  toggleNotification
@@ -4221,7 +5738,7 @@ const UIDInput = /*#__PURE__*/ React.forwardRef(({ hint, label, labelAction, nam
4221
5738
  onMouseLeave: ()=>setShowRegenerate(false),
4222
5739
  children: isLoading ? /*#__PURE__*/ jsx(LoadingWrapper, {
4223
5740
  "data-testid": "loading-wrapper",
4224
- children: /*#__PURE__*/ jsx(Loader, {})
5741
+ children: /*#__PURE__*/ jsx(Loader$1, {})
4225
5742
  }) : /*#__PURE__*/ jsx(ArrowClockwise, {})
4226
5743
  })
4227
5744
  ]
@@ -5484,14 +7001,14 @@ const quoteAndCodeHandler = (editor, markdownType)=>{
5484
7001
  };
5485
7002
 
5486
7003
  // NAV BUTTONS
5487
- const MainButtons = styled(IconButtonGroup)`
7004
+ styled(IconButtonGroup)`
5488
7005
  margin-left: ${({ theme })=>theme.spaces[4]};
5489
7006
  `;
5490
- const MoreButton = styled(IconButton)`
7007
+ styled(IconButton)`
5491
7008
  margin: ${({ theme })=>`0 ${theme.spaces[2]}`};
5492
7009
  `;
5493
7010
  // NAV
5494
- const IconButtonGroupMargin = styled(IconButtonGroup)`
7011
+ styled(IconButtonGroup)`
5495
7012
  margin-right: ${({ theme })=>`${theme.spaces[2]}`};
5496
7013
  `;
5497
7014
  // FOOTER
@@ -5540,254 +7057,524 @@ const WysiwygFooter = ({ onToggleExpand })=>{
5540
7057
  defaultMessage: 'Expand'
5541
7058
  })
5542
7059
  }),
5543
- /*#__PURE__*/ jsx(Expand, {})
7060
+ /*#__PURE__*/ jsx(Expand, {})
7061
+ ]
7062
+ })
7063
+ })
7064
+ });
7065
+ };
7066
+
7067
+ /**
7068
+ * TODO: refactor this mess.
7069
+ */ const WysiwygNav = ({ disabled, editorRef, isPreviewMode, onToggleMediaLib, onTogglePreviewMode })=>{
7070
+ const { formatMessage } = useIntl();
7071
+ const isDisabled = disabled || isPreviewMode;
7072
+ const handleActionClick = (value, currentEditorRef)=>{
7073
+ switch(value){
7074
+ case 'Link':
7075
+ {
7076
+ markdownHandler(currentEditorRef, value);
7077
+ break;
7078
+ }
7079
+ case 'Code':
7080
+ case 'Quote':
7081
+ {
7082
+ quoteAndCodeHandler(currentEditorRef, value);
7083
+ break;
7084
+ }
7085
+ case 'Bold':
7086
+ case 'Italic':
7087
+ case 'Underline':
7088
+ case 'Strikethrough':
7089
+ {
7090
+ markdownHandler(currentEditorRef, value);
7091
+ break;
7092
+ }
7093
+ case 'BulletList':
7094
+ case 'NumberList':
7095
+ {
7096
+ listHandler(currentEditorRef, value);
7097
+ break;
7098
+ }
7099
+ case 'h1':
7100
+ case 'h2':
7101
+ case 'h3':
7102
+ case 'h4':
7103
+ case 'h5':
7104
+ case 'h6':
7105
+ {
7106
+ titleHandler(currentEditorRef, value);
7107
+ break;
7108
+ }
7109
+ }
7110
+ };
7111
+ const observedComponents = [
7112
+ {
7113
+ toolbar: /*#__PURE__*/ jsxs(IconButtonGroup, {
7114
+ children: [
7115
+ /*#__PURE__*/ jsx(IconButton, {
7116
+ disabled: isDisabled,
7117
+ onClick: ()=>handleActionClick('Bold', editorRef),
7118
+ label: formatMessage({
7119
+ id: 'components.Blocks.modifiers.bold',
7120
+ defaultMessage: 'Bold'
7121
+ }),
7122
+ name: formatMessage({
7123
+ id: 'components.Blocks.modifiers.bold',
7124
+ defaultMessage: 'Bold'
7125
+ }),
7126
+ children: /*#__PURE__*/ jsx(Bold, {})
7127
+ }),
7128
+ /*#__PURE__*/ jsx(IconButton, {
7129
+ disabled: isDisabled,
7130
+ onClick: ()=>handleActionClick('Italic', editorRef),
7131
+ label: formatMessage({
7132
+ id: 'components.Blocks.modifiers.italic',
7133
+ defaultMessage: 'Italic'
7134
+ }),
7135
+ name: formatMessage({
7136
+ id: 'components.Blocks.modifiers.italic',
7137
+ defaultMessage: 'Italic'
7138
+ }),
7139
+ children: /*#__PURE__*/ jsx(Italic, {})
7140
+ }),
7141
+ /*#__PURE__*/ jsx(IconButton, {
7142
+ disabled: isDisabled,
7143
+ onClick: ()=>handleActionClick('Underline', editorRef),
7144
+ label: formatMessage({
7145
+ id: 'components.Blocks.modifiers.underline',
7146
+ defaultMessage: 'Underline'
7147
+ }),
7148
+ name: formatMessage({
7149
+ id: 'components.Blocks.modifiers.underline',
7150
+ defaultMessage: 'Underline'
7151
+ }),
7152
+ children: /*#__PURE__*/ jsx(Underline, {})
7153
+ }),
7154
+ /*#__PURE__*/ jsx(IconButton, {
7155
+ disabled: isDisabled,
7156
+ onClick: ()=>handleActionClick('Strikethrough', editorRef),
7157
+ label: formatMessage({
7158
+ id: 'components.Blocks.modifiers.strikethrough',
7159
+ defaultMessage: 'Strikethrough'
7160
+ }),
7161
+ name: formatMessage({
7162
+ id: 'components.Blocks.modifiers.strikethrough',
7163
+ defaultMessage: 'Strikethrough'
7164
+ }),
7165
+ children: /*#__PURE__*/ jsx(StrikeThrough, {})
7166
+ })
7167
+ ]
7168
+ }),
7169
+ menu: /*#__PURE__*/ jsxs(Fragment, {
7170
+ children: [
7171
+ /*#__PURE__*/ jsx(Menu.Separator, {}),
7172
+ /*#__PURE__*/ jsx(Menu.Item, {
7173
+ onSelect: ()=>handleActionClick('Bold', editorRef),
7174
+ disabled: isDisabled,
7175
+ children: /*#__PURE__*/ jsxs(Flex, {
7176
+ tag: "span",
7177
+ gap: 2,
7178
+ children: [
7179
+ /*#__PURE__*/ jsx(Bold, {
7180
+ "aria-hidden": true,
7181
+ fill: "neutral600"
7182
+ }),
7183
+ formatMessage({
7184
+ id: 'components.Blocks.modifiers.bold',
7185
+ defaultMessage: 'Bold'
7186
+ })
7187
+ ]
7188
+ })
7189
+ }),
7190
+ /*#__PURE__*/ jsx(Menu.Item, {
7191
+ onSelect: ()=>handleActionClick('Italic', editorRef),
7192
+ disabled: isDisabled,
7193
+ children: /*#__PURE__*/ jsxs(Flex, {
7194
+ tag: "span",
7195
+ gap: 2,
7196
+ children: [
7197
+ /*#__PURE__*/ jsx(Italic, {
7198
+ "aria-hidden": true,
7199
+ fill: "neutral600"
7200
+ }),
7201
+ formatMessage({
7202
+ id: 'components.Blocks.modifiers.italic',
7203
+ defaultMessage: 'Italic'
7204
+ })
7205
+ ]
7206
+ })
7207
+ }),
7208
+ /*#__PURE__*/ jsx(Menu.Item, {
7209
+ onSelect: ()=>handleActionClick('Underline', editorRef),
7210
+ disabled: isDisabled,
7211
+ children: /*#__PURE__*/ jsxs(Flex, {
7212
+ tag: "span",
7213
+ gap: 2,
7214
+ children: [
7215
+ /*#__PURE__*/ jsx(Underline, {
7216
+ "aria-hidden": true,
7217
+ fill: "neutral600"
7218
+ }),
7219
+ formatMessage({
7220
+ id: 'components.Blocks.modifiers.underline',
7221
+ defaultMessage: 'Underline'
7222
+ })
7223
+ ]
7224
+ })
7225
+ }),
7226
+ /*#__PURE__*/ jsx(Menu.Item, {
7227
+ onSelect: ()=>handleActionClick('Strikethrough', editorRef),
7228
+ disabled: isDisabled,
7229
+ children: /*#__PURE__*/ jsxs(Flex, {
7230
+ tag: "span",
7231
+ gap: 2,
7232
+ children: [
7233
+ /*#__PURE__*/ jsx(StrikeThrough, {
7234
+ "aria-hidden": true,
7235
+ fill: "neutral600"
7236
+ }),
7237
+ formatMessage({
7238
+ id: 'components.Blocks.modifiers.strikethrough',
7239
+ defaultMessage: 'Strikethrough'
7240
+ })
7241
+ ]
7242
+ })
7243
+ })
5544
7244
  ]
5545
- })
5546
- })
5547
- });
5548
- };
5549
-
5550
- /**
5551
- * TODO: refactor this mess.
5552
- */ const WysiwygNav = ({ disabled, editorRef, isExpandMode, isPreviewMode, onActionClick, onToggleMediaLib, onTogglePreviewMode })=>{
5553
- const [visiblePopover, setVisiblePopover] = React.useState(false);
5554
- const { formatMessage } = useIntl();
5555
- const selectPlaceholder = formatMessage({
5556
- id: 'components.Wysiwyg.selectOptions.title',
5557
- defaultMessage: 'Add a title'
5558
- });
5559
- React.useRef(null);
5560
- const handleTogglePopover = ()=>{
5561
- setVisiblePopover((prev)=>!prev);
5562
- };
5563
- if (disabled || isPreviewMode) {
5564
- return /*#__PURE__*/ jsxs(Flex, {
5565
- padding: 2,
5566
- background: "neutral100",
5567
- justifyContent: "space-between",
5568
- borderRadius: `0.4rem 0.4rem 0 0`,
5569
- children: [
5570
- /*#__PURE__*/ jsxs(Flex, {
5571
- children: [
5572
- /*#__PURE__*/ jsx(Field.Root, {
5573
- children: /*#__PURE__*/ jsxs(SingleSelect, {
5574
- disabled: true,
5575
- placeholder: selectPlaceholder,
5576
- "aria-label": selectPlaceholder,
5577
- size: "S",
5578
- children: [
5579
- /*#__PURE__*/ jsx(SingleSelectOption, {
5580
- value: "h1",
5581
- children: "h1"
5582
- }),
5583
- /*#__PURE__*/ jsx(SingleSelectOption, {
5584
- value: "h2",
5585
- children: "h2"
5586
- }),
5587
- /*#__PURE__*/ jsx(SingleSelectOption, {
5588
- value: "h3",
5589
- children: "h3"
5590
- }),
5591
- /*#__PURE__*/ jsx(SingleSelectOption, {
5592
- value: "h4",
5593
- children: "h4"
5594
- }),
5595
- /*#__PURE__*/ jsx(SingleSelectOption, {
5596
- value: "h5",
5597
- children: "h5"
5598
- }),
5599
- /*#__PURE__*/ jsx(SingleSelectOption, {
5600
- value: "h6",
5601
- children: "h6"
5602
- })
5603
- ]
5604
- })
7245
+ }),
7246
+ key: 'formatting-group-1'
7247
+ },
7248
+ {
7249
+ toolbar: /*#__PURE__*/ jsxs(IconButtonGroup, {
7250
+ children: [
7251
+ /*#__PURE__*/ jsx(IconButton, {
7252
+ disabled: isDisabled,
7253
+ onClick: ()=>handleActionClick('BulletList', editorRef),
7254
+ label: formatMessage({
7255
+ id: 'components.Blocks.blocks.bulletList',
7256
+ defaultMessage: 'Bulleted list'
7257
+ }),
7258
+ name: formatMessage({
7259
+ id: 'components.Blocks.blocks.bulletList',
7260
+ defaultMessage: 'Bulleted list'
7261
+ }),
7262
+ children: /*#__PURE__*/ jsx(BulletList, {})
7263
+ }),
7264
+ /*#__PURE__*/ jsx(IconButton, {
7265
+ disabled: isDisabled,
7266
+ onClick: ()=>handleActionClick('NumberList', editorRef),
7267
+ label: formatMessage({
7268
+ id: 'components.Blocks.blocks.numberList',
7269
+ defaultMessage: 'Numbered list'
5605
7270
  }),
5606
- /*#__PURE__*/ jsxs(MainButtons, {
7271
+ name: formatMessage({
7272
+ id: 'components.Blocks.blocks.numberList',
7273
+ defaultMessage: 'Numbered list'
7274
+ }),
7275
+ children: /*#__PURE__*/ jsx(NumberList, {})
7276
+ })
7277
+ ]
7278
+ }),
7279
+ menu: /*#__PURE__*/ jsxs(Fragment, {
7280
+ children: [
7281
+ /*#__PURE__*/ jsx(Menu.Separator, {}),
7282
+ /*#__PURE__*/ jsx(Menu.Item, {
7283
+ onSelect: ()=>handleActionClick('BulletList', editorRef),
7284
+ disabled: isDisabled,
7285
+ children: /*#__PURE__*/ jsxs(Flex, {
7286
+ tag: "span",
7287
+ gap: 2,
5607
7288
  children: [
5608
- /*#__PURE__*/ jsx(IconButton, {
5609
- disabled: true,
5610
- label: "Bold",
5611
- name: "Bold",
5612
- children: /*#__PURE__*/ jsx(Bold, {})
7289
+ /*#__PURE__*/ jsx(BulletList, {
7290
+ "aria-hidden": true,
7291
+ fill: "neutral600"
5613
7292
  }),
5614
- /*#__PURE__*/ jsx(IconButton, {
5615
- disabled: true,
5616
- label: "Italic",
5617
- name: "Italic",
5618
- children: /*#__PURE__*/ jsx(Italic, {})
7293
+ formatMessage({
7294
+ id: 'components.Blocks.blocks.unorderedList',
7295
+ defaultMessage: 'Bulleted list'
7296
+ })
7297
+ ]
7298
+ })
7299
+ }),
7300
+ /*#__PURE__*/ jsx(Menu.Item, {
7301
+ onSelect: ()=>handleActionClick('NumberList', editorRef),
7302
+ disabled: isDisabled,
7303
+ children: /*#__PURE__*/ jsxs(Flex, {
7304
+ tag: "span",
7305
+ gap: 2,
7306
+ children: [
7307
+ /*#__PURE__*/ jsx(NumberList, {
7308
+ "aria-hidden": true,
7309
+ fill: "neutral600"
5619
7310
  }),
5620
- /*#__PURE__*/ jsx(IconButton, {
5621
- disabled: true,
5622
- label: "Underline",
5623
- name: "Underline",
5624
- children: /*#__PURE__*/ jsx(Underline, {})
7311
+ formatMessage({
7312
+ id: 'components.Blocks.blocks.orderedList',
7313
+ defaultMessage: 'Numbered list'
5625
7314
  })
5626
7315
  ]
5627
- }),
5628
- /*#__PURE__*/ jsx(MoreButton, {
5629
- disabled: true,
5630
- label: "More",
5631
- children: /*#__PURE__*/ jsx(More, {})
5632
7316
  })
5633
- ]
5634
- }),
5635
- !isExpandMode && /*#__PURE__*/ jsx(Button, {
5636
- onClick: onTogglePreviewMode,
5637
- variant: "tertiary",
5638
- children: formatMessage({
5639
- id: 'components.Wysiwyg.ToggleMode.markdown-mode',
5640
- defaultMessage: 'Markdown mode'
5641
7317
  })
5642
- })
5643
- ]
5644
- });
5645
- }
5646
- return /*#__PURE__*/ jsxs(Flex, {
5647
- padding: 2,
5648
- background: "neutral100",
5649
- justifyContent: "space-between",
5650
- borderRadius: `0.4rem 0.4rem 0 0`,
5651
- children: [
5652
- /*#__PURE__*/ jsxs(Flex, {
7318
+ ]
7319
+ }),
7320
+ key: 'formatting-group-2'
7321
+ },
7322
+ {
7323
+ toolbar: /*#__PURE__*/ jsxs(IconButtonGroup, {
7324
+ children: [
7325
+ /*#__PURE__*/ jsx(IconButton, {
7326
+ disabled: isDisabled,
7327
+ onClick: ()=>handleActionClick('Code', editorRef),
7328
+ label: formatMessage({
7329
+ id: 'components.Wysiwyg.blocks.code',
7330
+ defaultMessage: 'Code'
7331
+ }),
7332
+ name: formatMessage({
7333
+ id: 'components.Wysiwyg.blocks.code',
7334
+ defaultMessage: 'Code'
7335
+ }),
7336
+ children: /*#__PURE__*/ jsx(Code, {})
7337
+ }),
7338
+ /*#__PURE__*/ jsx(IconButton, {
7339
+ disabled: isDisabled,
7340
+ onClick: ()=>{
7341
+ onToggleMediaLib();
7342
+ },
7343
+ label: formatMessage({
7344
+ id: 'components.Blocks.blocks.image',
7345
+ defaultMessage: 'Image'
7346
+ }),
7347
+ name: formatMessage({
7348
+ id: 'components.Blocks.blocks.image',
7349
+ defaultMessage: 'Image'
7350
+ }),
7351
+ children: /*#__PURE__*/ jsx(Image$1, {})
7352
+ }),
7353
+ /*#__PURE__*/ jsx(IconButton, {
7354
+ disabled: isDisabled,
7355
+ onClick: ()=>handleActionClick('Link', editorRef),
7356
+ label: formatMessage({
7357
+ id: 'components.Blocks.popover.link',
7358
+ defaultMessage: 'Link'
7359
+ }),
7360
+ name: formatMessage({
7361
+ id: 'components.Blocks.popover.link',
7362
+ defaultMessage: 'Link'
7363
+ }),
7364
+ children: /*#__PURE__*/ jsx(Link$1, {})
7365
+ }),
7366
+ /*#__PURE__*/ jsx(IconButton, {
7367
+ disabled: isDisabled,
7368
+ onClick: ()=>handleActionClick('Quote', editorRef),
7369
+ label: formatMessage({
7370
+ id: 'components.Blocks.blocks.quote',
7371
+ defaultMessage: 'Quote'
7372
+ }),
7373
+ name: formatMessage({
7374
+ id: 'components.Blocks.blocks.quote',
7375
+ defaultMessage: 'Quote'
7376
+ }),
7377
+ children: /*#__PURE__*/ jsx(Quotes, {})
7378
+ })
7379
+ ]
7380
+ }),
7381
+ menu: /*#__PURE__*/ jsxs(Fragment, {
5653
7382
  children: [
5654
- /*#__PURE__*/ jsx(Field.Root, {
5655
- children: /*#__PURE__*/ jsxs(SingleSelect, {
5656
- placeholder: selectPlaceholder,
5657
- "aria-label": selectPlaceholder,
5658
- // @ts-expect-error DS v2 will only allow strings.
5659
- onChange: (value)=>onActionClick(value, editorRef),
5660
- size: "S",
7383
+ /*#__PURE__*/ jsx(Menu.Separator, {}),
7384
+ /*#__PURE__*/ jsx(Menu.Item, {
7385
+ onSelect: ()=>handleActionClick('Code', editorRef),
7386
+ disabled: isDisabled,
7387
+ children: /*#__PURE__*/ jsxs(Flex, {
7388
+ tag: "span",
7389
+ gap: 2,
5661
7390
  children: [
5662
- /*#__PURE__*/ jsx(SingleSelectOption, {
5663
- value: "h1",
5664
- children: "h1"
5665
- }),
5666
- /*#__PURE__*/ jsx(SingleSelectOption, {
5667
- value: "h2",
5668
- children: "h2"
7391
+ /*#__PURE__*/ jsx(Code, {
7392
+ "aria-hidden": true,
7393
+ fill: "neutral600"
5669
7394
  }),
5670
- /*#__PURE__*/ jsx(SingleSelectOption, {
5671
- value: "h3",
5672
- children: "h3"
7395
+ formatMessage({
7396
+ id: 'components.Wysiwyg.blocks.code',
7397
+ defaultMessage: 'Code'
7398
+ })
7399
+ ]
7400
+ })
7401
+ }),
7402
+ /*#__PURE__*/ jsx(Menu.Item, {
7403
+ startIcon: /*#__PURE__*/ jsx(Image$1, {}),
7404
+ onSelect: ()=>{
7405
+ onToggleMediaLib();
7406
+ },
7407
+ disabled: isDisabled,
7408
+ children: /*#__PURE__*/ jsxs(Flex, {
7409
+ tag: "span",
7410
+ gap: 2,
7411
+ children: [
7412
+ /*#__PURE__*/ jsx(Image$1, {
7413
+ "aria-hidden": true,
7414
+ fill: "neutral600"
5673
7415
  }),
5674
- /*#__PURE__*/ jsx(SingleSelectOption, {
5675
- value: "h4",
5676
- children: "h4"
7416
+ formatMessage({
7417
+ id: 'components.Blocks.blocks.image',
7418
+ defaultMessage: 'Image'
7419
+ })
7420
+ ]
7421
+ })
7422
+ }),
7423
+ /*#__PURE__*/ jsx(Menu.Item, {
7424
+ startIcon: /*#__PURE__*/ jsx(Link$1, {}),
7425
+ onSelect: ()=>handleActionClick('Link', editorRef),
7426
+ disabled: isDisabled,
7427
+ children: /*#__PURE__*/ jsxs(Flex, {
7428
+ tag: "span",
7429
+ gap: 2,
7430
+ children: [
7431
+ /*#__PURE__*/ jsx(Link$1, {
7432
+ "aria-hidden": true,
7433
+ fill: "neutral600"
5677
7434
  }),
5678
- /*#__PURE__*/ jsx(SingleSelectOption, {
5679
- value: "h5",
5680
- children: "h5"
7435
+ formatMessage({
7436
+ id: 'components.Blocks.popover.link',
7437
+ defaultMessage: 'Link'
7438
+ })
7439
+ ]
7440
+ })
7441
+ }),
7442
+ /*#__PURE__*/ jsx(Menu.Item, {
7443
+ onSelect: ()=>handleActionClick('Quote', editorRef),
7444
+ disabled: isDisabled,
7445
+ children: /*#__PURE__*/ jsxs(Flex, {
7446
+ tag: "span",
7447
+ gap: 2,
7448
+ children: [
7449
+ /*#__PURE__*/ jsx(Quotes, {
7450
+ "aria-hidden": true,
7451
+ fill: "neutral600"
5681
7452
  }),
5682
- /*#__PURE__*/ jsx(SingleSelectOption, {
5683
- value: "h6",
5684
- children: "h6"
7453
+ formatMessage({
7454
+ id: 'components.Blocks.blocks.quote',
7455
+ defaultMessage: 'Quote'
5685
7456
  })
5686
7457
  ]
5687
7458
  })
7459
+ })
7460
+ ]
7461
+ }),
7462
+ key: 'formatting-group-3'
7463
+ }
7464
+ ];
7465
+ return /*#__PURE__*/ jsxs(Flex, {
7466
+ padding: 2,
7467
+ background: "neutral100",
7468
+ justifyContent: "space-between",
7469
+ borderRadius: "0.4rem 0.4rem 0 0",
7470
+ width: "100%",
7471
+ gap: 4,
7472
+ children: [
7473
+ /*#__PURE__*/ jsx(Field.Root, {
7474
+ children: /*#__PURE__*/ jsxs(SingleSelect, {
7475
+ disabled: isDisabled,
7476
+ placeholder: formatMessage({
7477
+ id: 'components.Wysiwyg.selectOptions.title',
7478
+ defaultMessage: 'Headings'
5688
7479
  }),
5689
- /*#__PURE__*/ jsxs(MainButtons, {
5690
- children: [
5691
- /*#__PURE__*/ jsx(IconButton, {
5692
- onClick: ()=>onActionClick('Bold', editorRef),
5693
- label: "Bold",
5694
- name: "Bold",
5695
- children: /*#__PURE__*/ jsx(Bold, {})
7480
+ "aria-label": formatMessage({
7481
+ id: 'components.Wysiwyg.selectOptions.title',
7482
+ defaultMessage: 'Headings'
7483
+ }),
7484
+ // @ts-expect-error – DS v2 will only allow strings.
7485
+ onChange: (value)=>handleActionClick(value, editorRef),
7486
+ size: "S",
7487
+ children: [
7488
+ /*#__PURE__*/ jsx(SingleSelectOption, {
7489
+ value: "h1",
7490
+ startIcon: /*#__PURE__*/ jsx(HeadingOne, {
7491
+ fill: "neutral600"
5696
7492
  }),
5697
- /*#__PURE__*/ jsx(IconButton, {
5698
- onClick: ()=>onActionClick('Italic', editorRef),
5699
- label: "Italic",
5700
- name: "Italic",
5701
- children: /*#__PURE__*/ jsx(Italic, {})
7493
+ children: formatMessage({
7494
+ id: 'components.Wysiwyg.selectOptions.H1',
7495
+ defaultMessage: 'Heading 1'
7496
+ })
7497
+ }),
7498
+ /*#__PURE__*/ jsx(SingleSelectOption, {
7499
+ value: "h2",
7500
+ startIcon: /*#__PURE__*/ jsx(HeadingTwo, {
7501
+ fill: "neutral600"
5702
7502
  }),
5703
- /*#__PURE__*/ jsx(IconButton, {
5704
- onClick: ()=>onActionClick('Underline', editorRef),
5705
- label: "Underline",
5706
- name: "Underline",
5707
- children: /*#__PURE__*/ jsx(Underline, {})
7503
+ children: formatMessage({
7504
+ id: 'components.Wysiwyg.selectOptions.H2',
7505
+ defaultMessage: 'Heading 2'
5708
7506
  })
5709
- ]
5710
- }),
5711
- /*#__PURE__*/ jsxs(Popover.Root, {
5712
- children: [
5713
- /*#__PURE__*/ jsx(Popover.Trigger, {
5714
- children: /*#__PURE__*/ jsx(MoreButton, {
5715
- label: "More",
5716
- children: /*#__PURE__*/ jsx(More, {})
5717
- })
7507
+ }),
7508
+ /*#__PURE__*/ jsx(SingleSelectOption, {
7509
+ value: "h3",
7510
+ startIcon: /*#__PURE__*/ jsx(HeadingThree, {
7511
+ fill: "neutral600"
5718
7512
  }),
5719
- /*#__PURE__*/ jsx(Popover.Content, {
5720
- sideOffset: 12,
5721
- children: /*#__PURE__*/ jsxs(Flex, {
5722
- padding: 2,
5723
- children: [
5724
- /*#__PURE__*/ jsxs(IconButtonGroupMargin, {
5725
- children: [
5726
- /*#__PURE__*/ jsx(IconButton, {
5727
- onClick: ()=>onActionClick('Strikethrough', editorRef, handleTogglePopover),
5728
- label: "Strikethrough",
5729
- name: "Strikethrough",
5730
- children: /*#__PURE__*/ jsx(StrikeThrough, {})
5731
- }),
5732
- /*#__PURE__*/ jsx(IconButton, {
5733
- onClick: ()=>onActionClick('BulletList', editorRef, handleTogglePopover),
5734
- label: "BulletList",
5735
- name: "BulletList",
5736
- children: /*#__PURE__*/ jsx(BulletList, {})
5737
- }),
5738
- /*#__PURE__*/ jsx(IconButton, {
5739
- onClick: ()=>onActionClick('NumberList', editorRef, handleTogglePopover),
5740
- label: "NumberList",
5741
- name: "NumberList",
5742
- children: /*#__PURE__*/ jsx(NumberList, {})
5743
- })
5744
- ]
5745
- }),
5746
- /*#__PURE__*/ jsxs(IconButtonGroup, {
5747
- children: [
5748
- /*#__PURE__*/ jsx(IconButton, {
5749
- onClick: ()=>onActionClick('Code', editorRef, handleTogglePopover),
5750
- label: "Code",
5751
- name: "Code",
5752
- children: /*#__PURE__*/ jsx(Code, {})
5753
- }),
5754
- /*#__PURE__*/ jsx(IconButton, {
5755
- onClick: ()=>{
5756
- handleTogglePopover();
5757
- onToggleMediaLib();
5758
- },
5759
- label: "Image",
5760
- name: "Image",
5761
- children: /*#__PURE__*/ jsx(Image$1, {})
5762
- }),
5763
- /*#__PURE__*/ jsx(IconButton, {
5764
- onClick: ()=>onActionClick('Link', editorRef, handleTogglePopover),
5765
- label: "Link",
5766
- name: "Link",
5767
- children: /*#__PURE__*/ jsx(Link$1, {})
5768
- }),
5769
- /*#__PURE__*/ jsx(IconButton, {
5770
- onClick: ()=>onActionClick('Quote', editorRef, handleTogglePopover),
5771
- label: "Quote",
5772
- name: "Quote",
5773
- children: /*#__PURE__*/ jsx(Quotes, {})
5774
- })
5775
- ]
5776
- })
5777
- ]
5778
- })
7513
+ children: formatMessage({
7514
+ id: 'components.Wysiwyg.selectOptions.H3',
7515
+ defaultMessage: 'Heading 3'
5779
7516
  })
5780
- ]
7517
+ }),
7518
+ /*#__PURE__*/ jsx(SingleSelectOption, {
7519
+ value: "h4",
7520
+ startIcon: /*#__PURE__*/ jsx(HeadingFour, {
7521
+ fill: "neutral600"
7522
+ }),
7523
+ children: formatMessage({
7524
+ id: 'components.Wysiwyg.selectOptions.H4',
7525
+ defaultMessage: 'Heading 4'
7526
+ })
7527
+ }),
7528
+ /*#__PURE__*/ jsx(SingleSelectOption, {
7529
+ value: "h5",
7530
+ startIcon: /*#__PURE__*/ jsx(HeadingFive, {
7531
+ fill: "neutral600"
7532
+ }),
7533
+ children: formatMessage({
7534
+ id: 'components.Wysiwyg.selectOptions.H5',
7535
+ defaultMessage: 'Heading 5'
7536
+ })
7537
+ }),
7538
+ /*#__PURE__*/ jsx(SingleSelectOption, {
7539
+ value: "h6",
7540
+ startIcon: /*#__PURE__*/ jsx(HeadingSix, {
7541
+ fill: "neutral600"
7542
+ }),
7543
+ children: formatMessage({
7544
+ id: 'components.Wysiwyg.selectOptions.H6',
7545
+ defaultMessage: 'Heading 6'
7546
+ })
7547
+ })
7548
+ ]
7549
+ })
7550
+ }),
7551
+ /*#__PURE__*/ jsxs(Flex, {
7552
+ width: "100%",
7553
+ justifyContent: "space-between",
7554
+ overflow: "hidden",
7555
+ children: [
7556
+ /*#__PURE__*/ jsx(Flex, {
7557
+ gap: 2,
7558
+ overflow: "hidden",
7559
+ width: "100%",
7560
+ children: /*#__PURE__*/ jsx(EditorToolbarObserver, {
7561
+ menuTriggerVariant: "tertiary",
7562
+ observedComponents: observedComponents
7563
+ })
7564
+ }),
7565
+ onTogglePreviewMode && /*#__PURE__*/ jsx(Button, {
7566
+ onClick: onTogglePreviewMode,
7567
+ variant: "tertiary",
7568
+ minWidth: "132px",
7569
+ children: isPreviewMode ? formatMessage({
7570
+ id: 'components.Wysiwyg.ToggleMode.markdown-mode',
7571
+ defaultMessage: 'Markdown mode'
7572
+ }) : formatMessage({
7573
+ id: 'components.Wysiwyg.ToggleMode.preview-mode',
7574
+ defaultMessage: 'Preview mode'
7575
+ })
5781
7576
  })
5782
7577
  ]
5783
- }),
5784
- onTogglePreviewMode && /*#__PURE__*/ jsx(Button, {
5785
- onClick: onTogglePreviewMode,
5786
- variant: "tertiary",
5787
- children: formatMessage({
5788
- id: 'components.Wysiwyg.ToggleMode.preview-mode',
5789
- defaultMessage: 'Preview mode'
5790
- })
5791
7578
  })
5792
7579
  ]
5793
7580
  });
@@ -5808,48 +7595,6 @@ const Wysiwyg = /*#__PURE__*/ React.forwardRef(({ hint, disabled, label, name, p
5808
7595
  setIsPreviewMode(false);
5809
7596
  setIsExpandMode((prev)=>!prev);
5810
7597
  };
5811
- const handleActionClick = (value, currentEditorRef, togglePopover)=>{
5812
- switch(value){
5813
- case 'Link':
5814
- case 'Strikethrough':
5815
- {
5816
- markdownHandler(currentEditorRef, value);
5817
- togglePopover?.();
5818
- break;
5819
- }
5820
- case 'Code':
5821
- case 'Quote':
5822
- {
5823
- quoteAndCodeHandler(currentEditorRef, value);
5824
- togglePopover?.();
5825
- break;
5826
- }
5827
- case 'Bold':
5828
- case 'Italic':
5829
- case 'Underline':
5830
- {
5831
- markdownHandler(currentEditorRef, value);
5832
- break;
5833
- }
5834
- case 'BulletList':
5835
- case 'NumberList':
5836
- {
5837
- listHandler(currentEditorRef, value);
5838
- togglePopover?.();
5839
- break;
5840
- }
5841
- case 'h1':
5842
- case 'h2':
5843
- case 'h3':
5844
- case 'h4':
5845
- case 'h5':
5846
- case 'h6':
5847
- {
5848
- titleHandler(currentEditorRef, value);
5849
- break;
5850
- }
5851
- }
5852
- };
5853
7598
  const handleSelectAssets = (files)=>{
5854
7599
  const formattedFiles = files.map((f)=>({
5855
7600
  alt: f.alternativeText || f.name,
@@ -5884,7 +7629,6 @@ const Wysiwyg = /*#__PURE__*/ React.forwardRef(({ hint, disabled, label, name, p
5884
7629
  isExpandMode: isExpandMode,
5885
7630
  editorRef: editorRef,
5886
7631
  isPreviewMode: isPreviewMode,
5887
- onActionClick: handleActionClick,
5888
7632
  onToggleMediaLib: handleToggleMediaLib,
5889
7633
  onTogglePreviewMode: isExpandMode ? undefined : handleTogglePreviewMode,
5890
7634
  disabled: disabled
@@ -5928,17 +7672,25 @@ const MemoizedWysiwyg = /*#__PURE__*/ React.memo(Wysiwyg);
5928
7672
  * specifically to be used in the EditView of the content-manager this understands
5929
7673
  * the complete EditFieldLayout and will handle RBAC conditions and rendering CM specific
5930
7674
  * components such as Blocks / Relations.
5931
- */ const InputRenderer = ({ visible, hint: providedHint, ...props })=>{
5932
- const { id, document, collectionType } = useDoc();
5933
- const isFormDisabled = useForm('InputRenderer', (state)=>state.disabled);
7675
+ */ const InputRenderer = ({ visible, hint: providedHint, document, ...props })=>{
7676
+ const { model: rootModel } = useDoc();
7677
+ const rootDocumentMeta = useDocumentContext('DynamicComponent', (state)=>state.rootDocumentMeta);
7678
+ const { edit: { components: rootComponents } } = useDocumentLayout(rootDocumentMeta.model);
7679
+ const { edit: { components: relatedComponents } } = useDocumentLayout(document.schema?.uid ?? rootModel);
7680
+ const components = {
7681
+ ...rootComponents,
7682
+ ...relatedComponents
7683
+ };
7684
+ const collectionType = document.schema?.kind === 'collectionType' ? 'collection-types' : 'single-types';
5934
7685
  const isInDynamicZone = useDynamicZone('isInDynamicZone', (state)=>state.isInDynamicZone);
7686
+ const isFormDisabled = useForm('InputRenderer', (state)=>state.disabled);
5935
7687
  const canCreateFields = useDocumentRBAC('InputRenderer', (rbac)=>rbac.canCreateFields);
5936
7688
  const canReadFields = useDocumentRBAC('InputRenderer', (rbac)=>rbac.canReadFields);
5937
7689
  const canUpdateFields = useDocumentRBAC('InputRenderer', (rbac)=>rbac.canUpdateFields);
5938
7690
  const canUserAction = useDocumentRBAC('InputRenderer', (rbac)=>rbac.canUserAction);
5939
- let idToCheck = id;
7691
+ let idToCheck = document.document?.documentId;
5940
7692
  if (collectionType === SINGLE_TYPES) {
5941
- idToCheck = document?.documentId;
7693
+ idToCheck = document?.document?.documentId;
5942
7694
  }
5943
7695
  const editableFields = idToCheck ? canUpdateFields : canCreateFields;
5944
7696
  const readableFields = idToCheck ? canReadFields : canCreateFields;
@@ -5952,7 +7704,6 @@ const MemoizedWysiwyg = /*#__PURE__*/ React.memo(Wysiwyg);
5952
7704
  props.attribute.customField
5953
7705
  ] : undefined);
5954
7706
  const hint = useFieldHint(providedHint, props.attribute);
5955
- const { edit: { components } } = useDocLayout();
5956
7707
  // We pass field in case of Custom Fields to keep backward compatibility
5957
7708
  const field = useField(props.name);
5958
7709
  if (!visible) {
@@ -6126,7 +7877,7 @@ const getMinMax = (attribute)=>{
6126
7877
  };
6127
7878
  }
6128
7879
  };
6129
- const MemoizedInputRenderer = /*#__PURE__*/ memo(InputRenderer);
7880
+ const MemoizedInputRenderer = /*#__PURE__*/ React.memo(InputRenderer);
6130
7881
 
6131
7882
  const RESPONSIVE_CONTAINER_BREAKPOINTS = {
6132
7883
  sm: '27.5rem'
@@ -6134,16 +7885,22 @@ const RESPONSIVE_CONTAINER_BREAKPOINTS = {
6134
7885
  const ResponsiveGridRoot = styled(Grid$1.Root)`
6135
7886
  container-type: inline-size;
6136
7887
  `;
6137
- const ResponsiveGridItem = styled(Grid$1.Item)`
6138
- grid-column: span 12;
6139
-
6140
- @container (min-width: ${RESPONSIVE_CONTAINER_BREAKPOINTS.sm}) {
6141
- ${({ col })=>col && `grid-column: span ${col};`}
6142
- }
6143
- `;
6144
- const FormLayout = ({ layout })=>{
7888
+ const ResponsiveGridItem = /**
7889
+ * TODO:
7890
+ * JSDOM cannot handle container queries.
7891
+ * This is a temporary workaround so that tests do not fail in the CI when jestdom throws an error
7892
+ * for failing to parse the stylesheet.
7893
+ */ process.env.NODE_ENV !== 'test' ? styled(Grid$1.Item)`
7894
+ grid-column: span 12;
7895
+ @container (min-width: ${RESPONSIVE_CONTAINER_BREAKPOINTS.sm}) {
7896
+ ${({ col })=>col && `grid-column: span ${col};`}
7897
+ }
7898
+ ` : styled(Grid$1.Item)`
7899
+ grid-column: span 12;
7900
+ `;
7901
+ const FormLayout = ({ layout, document, hasBackground = true })=>{
6145
7902
  const { formatMessage } = useIntl();
6146
- const { model } = useDoc();
7903
+ const model = document.schema?.modelName;
6147
7904
  return /*#__PURE__*/ jsx(Flex, {
6148
7905
  direction: "column",
6149
7906
  alignItems: "stretch",
@@ -6168,20 +7925,20 @@ const FormLayout = ({ layout })=>{
6168
7925
  direction: "column",
6169
7926
  alignItems: "stretch",
6170
7927
  children: /*#__PURE__*/ jsx(MemoizedInputRenderer, {
6171
- ...fieldWithTranslatedLabel
7928
+ ...fieldWithTranslatedLabel,
7929
+ document: document
6172
7930
  })
6173
7931
  })
6174
7932
  }, field.name);
6175
7933
  }
6176
7934
  return /*#__PURE__*/ jsx(Box, {
6177
- hasRadius: true,
6178
- background: "neutral0",
6179
- shadow: "tableShadow",
6180
- paddingLeft: 6,
6181
- paddingRight: 6,
6182
- paddingTop: 6,
6183
- paddingBottom: 6,
6184
- borderColor: "neutral150",
7935
+ ...hasBackground && {
7936
+ padding: 6,
7937
+ borderColor: 'neutral150',
7938
+ background: 'neutral0',
7939
+ hasRadius: true,
7940
+ shadow: 'tableShadow'
7941
+ },
6185
7942
  children: /*#__PURE__*/ jsx(Flex, {
6186
7943
  direction: "column",
6187
7944
  alignItems: "stretch",
@@ -6203,7 +7960,8 @@ const FormLayout = ({ layout })=>{
6203
7960
  direction: "column",
6204
7961
  alignItems: "stretch",
6205
7962
  children: /*#__PURE__*/ jsx(MemoizedInputRenderer, {
6206
- ...fieldWithTranslatedLabel
7963
+ ...fieldWithTranslatedLabel,
7964
+ document: document
6207
7965
  })
6208
7966
  }, field.name);
6209
7967
  })
@@ -6219,6 +7977,7 @@ const NonRepeatableComponent = ({ attribute, name, children, layout })=>{
6219
7977
  const { value } = useField(name);
6220
7978
  const level = useComponent('NonRepeatableComponent', (state)=>state.level);
6221
7979
  const isNested = level > 0;
7980
+ const currentDocument = useDocumentContext('NonRepeatableComponent', (state)=>state.document);
6222
7981
  return /*#__PURE__*/ jsx(ComponentProvider, {
6223
7982
  id: value?.id,
6224
7983
  uid: attribute.component,
@@ -6259,7 +8018,8 @@ const NonRepeatableComponent = ({ attribute, name, children, layout })=>{
6259
8018
  children: children({
6260
8019
  ...field,
6261
8020
  label: translatedLabel,
6262
- name: completeFieldName
8021
+ name: completeFieldName,
8022
+ document: currentDocument
6263
8023
  })
6264
8024
  }, completeFieldName);
6265
8025
  })
@@ -6277,7 +8037,8 @@ const RepeatableComponent = ({ attribute, disabled, name, mainField, children, l
6277
8037
  const search = React.useMemo(()=>new URLSearchParams(searchString), [
6278
8038
  searchString
6279
8039
  ]);
6280
- const { components } = useDoc();
8040
+ const currentDocument = useDocumentContext('RepeatableComponent', (state)=>state.document);
8041
+ const components = currentDocument.components;
6281
8042
  const { value = [], error, rawError } = useField(name);
6282
8043
  const addFieldRow = useForm('RepeatableComponent', (state)=>state.addFieldRow);
6283
8044
  const moveFieldRow = useForm('RepeatableComponent', (state)=>state.moveFieldRow);
@@ -6480,7 +8241,8 @@ const RepeatableComponent = ({ attribute, disabled, name, mainField, children, l
6480
8241
  children: children({
6481
8242
  ...field,
6482
8243
  label: translatedLabel,
6483
- name: completeFieldName
8244
+ name: completeFieldName,
8245
+ document: currentDocument
6484
8246
  })
6485
8247
  }, completeFieldName);
6486
8248
  })
@@ -6642,7 +8404,7 @@ const ComponentInput = ({ label, required, name, attribute, disabled, labelActio
6642
8404
  const { formatMessage } = useIntl();
6643
8405
  const field = useField(name);
6644
8406
  const showResetComponent = !attribute.repeatable && field.value && !disabled;
6645
- const { components } = useDoc();
8407
+ const components = useDocumentContext('ComponentInput', (state)=>state.document.components);
6646
8408
  const handleInitialisationClick = ()=>{
6647
8409
  const schema = components[attribute.component];
6648
8410
  const form = createDefaultForm(schema, components);
@@ -6707,5 +8469,5 @@ const ComponentInput = ({ label, required, name, attribute, disabled, labelActio
6707
8469
  };
6708
8470
  const MemoizedComponentInput = /*#__PURE__*/ React.memo(ComponentInput);
6709
8471
 
6710
- export { DynamicZone as D, FormLayout as F, MemoizedUIDInput as M, NotAllowedInput as N, useDynamicZone as a, useFieldHint as b, MemoizedWysiwyg as c, MemoizedComponentInput as d, MemoizedBlocksInput as e, useLazyComponents as u };
6711
- //# sourceMappingURL=Input-CLX3C5DI.js.map
8472
+ export { DisconnectButton as D, FlexWrapper as F, LinkEllipsis as L, MemoizedUIDInput as M, NotAllowedInput as N, FormLayout as a, useDynamicZone as b, useFieldHint as c, MemoizedWysiwyg as d, DynamicZone as e, MemoizedComponentInput as f, MemoizedBlocksInput as g, useLazyComponents as u };
8473
+ //# sourceMappingURL=Input-B3QUS9rv.mjs.map