@strapi/content-manager 0.0.0-experimental.3d525b3d2d44b055469a7694f6aaecfe7145b9e6 → 0.0.0-experimental.3e198200d32a65f20bd375086da6b1501e469c51

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 (238) 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-D4UH2BN4.js → ComponentConfigurationPage-DDybTE9k.js} +6 -6
  4. package/dist/admin/chunks/{ComponentConfigurationPage-D4UH2BN4.js.map → ComponentConfigurationPage-DDybTE9k.js.map} +1 -1
  5. package/dist/admin/chunks/{ComponentConfigurationPage-BSCYuG9k.js → ComponentConfigurationPage-Dtpjt9kW.mjs} +9 -9
  6. package/dist/admin/chunks/ComponentConfigurationPage-Dtpjt9kW.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-DAwy6frt.js → EditConfigurationPage-DAbUlQVr.mjs} +9 -9
  10. package/dist/admin/chunks/EditConfigurationPage-DAbUlQVr.mjs.map +1 -0
  11. package/dist/admin/chunks/{EditConfigurationPage-C6jesdjb.js → EditConfigurationPage-D_otE6ca.js} +6 -6
  12. package/dist/admin/chunks/{EditConfigurationPage-C6jesdjb.js.map → EditConfigurationPage-D_otE6ca.js.map} +1 -1
  13. package/dist/admin/chunks/EditViewPage-CILYfIn8.mjs +318 -0
  14. package/dist/admin/chunks/EditViewPage-CILYfIn8.mjs.map +1 -0
  15. package/dist/admin/chunks/EditViewPage-Cd7iCrfo.js +341 -0
  16. package/dist/admin/chunks/EditViewPage-Cd7iCrfo.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-Bwz2xTe9.js → Form-CER6uyhc.mjs} +5 -5
  20. package/dist/admin/chunks/Form-CER6uyhc.mjs.map +1 -0
  21. package/dist/admin/chunks/{Form-CzUHBbLw.js → Form-D6ROqMO7.js} +5 -5
  22. package/dist/admin/chunks/{Form-CzUHBbLw.js.map → Form-D6ROqMO7.js.map} +1 -1
  23. package/dist/admin/chunks/{History-5wpSVAu9.js → History-CORGJtti.mjs} +68 -15
  24. package/dist/admin/chunks/History-CORGJtti.mjs.map +1 -0
  25. package/dist/admin/chunks/{History-Dax5KiyG.js → History-DECiFmYO.js} +67 -14
  26. package/dist/admin/chunks/History-DECiFmYO.js.map +1 -0
  27. package/dist/admin/chunks/{Input-Dr7YL5Sv.js → Input-D3aI7eJe.js} +2201 -478
  28. package/dist/admin/chunks/Input-D3aI7eJe.js.map +1 -0
  29. package/dist/admin/chunks/{Input-Csrk7S5E.js → Input-hScqTWvW.mjs} +2276 -557
  30. package/dist/admin/chunks/Input-hScqTWvW.mjs.map +1 -0
  31. package/dist/admin/chunks/{ListConfigurationPage-Bp1dKd-U.js → ListConfigurationPage-Bgya7skT.mjs} +8 -8
  32. package/dist/admin/chunks/ListConfigurationPage-Bgya7skT.mjs.map +1 -0
  33. package/dist/admin/chunks/{ListConfigurationPage-oFwCMRWP.js → ListConfigurationPage-BiKI9-fH.js} +7 -7
  34. package/dist/admin/chunks/{ListConfigurationPage-oFwCMRWP.js.map → ListConfigurationPage-BiKI9-fH.js.map} +1 -1
  35. package/dist/admin/chunks/{ListViewPage-DfHXfD_c.js → ListViewPage-B3Frxm6y.mjs} +5 -5
  36. package/dist/admin/chunks/ListViewPage-B3Frxm6y.mjs.map +1 -0
  37. package/dist/admin/chunks/{ListViewPage-CkPfXiex.js → ListViewPage-BfFRaMK8.js} +8 -8
  38. package/dist/admin/chunks/{ListViewPage-CkPfXiex.js.map → ListViewPage-BfFRaMK8.js.map} +1 -1
  39. package/dist/admin/chunks/{NoContentTypePage-BLWccskh.js → NoContentTypePage-B2rBgAB9.mjs} +3 -2
  40. package/dist/admin/chunks/NoContentTypePage-B2rBgAB9.mjs.map +1 -0
  41. package/dist/admin/chunks/{NoContentTypePage-BgTBqH4R.js → NoContentTypePage-C-WQTH0F.js} +3 -2
  42. package/dist/admin/chunks/{NoContentTypePage-BLWccskh.js.map → NoContentTypePage-C-WQTH0F.js.map} +1 -1
  43. package/dist/admin/chunks/{NoPermissionsPage-CGC__b-5.js → NoPermissionsPage-BNXoY-4Q.mjs} +3 -2
  44. package/dist/admin/chunks/NoPermissionsPage-BNXoY-4Q.mjs.map +1 -0
  45. package/dist/admin/chunks/{NoPermissionsPage-CUnJ9nZ8.js → NoPermissionsPage-D0T5uTtv.js} +3 -2
  46. package/dist/admin/chunks/{NoPermissionsPage-CGC__b-5.js.map → NoPermissionsPage-D0T5uTtv.js.map} +1 -1
  47. package/dist/admin/chunks/Preview-BvCbqXQY.js +617 -0
  48. package/dist/admin/chunks/Preview-BvCbqXQY.js.map +1 -0
  49. package/dist/admin/chunks/Preview-D4L4y24d.mjs +595 -0
  50. package/dist/admin/chunks/Preview-D4L4y24d.mjs.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-BhFoy2kH.js → index-CB_ymrXf.js} +261 -144
  80. package/dist/admin/chunks/index-CB_ymrXf.js.map +1 -0
  81. package/dist/admin/chunks/{index-2cT6u68c.js → index-DsOgMEE-.mjs} +287 -174
  82. package/dist/admin/chunks/index-DsOgMEE-.mjs.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-CsDX52Zb.js → layout-C8AQHDvk.mjs} +81 -7
  90. package/dist/admin/chunks/layout-C8AQHDvk.mjs.map +1 -0
  91. package/dist/admin/chunks/{layout-CDvvkRib.js → layout-DGlrPEkC.js} +87 -13
  92. package/dist/admin/chunks/layout-DGlrPEkC.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-LR7_V8ZN.js → usePrev-BJk2lXYH.mjs} +18 -4
  126. package/dist/admin/chunks/usePrev-BJk2lXYH.mjs.map +1 -0
  127. package/dist/admin/chunks/{relations--SHAQ-Ch.js → usePrev-BXNyqdUp.js} +18 -2
  128. package/dist/admin/chunks/usePrev-BXNyqdUp.js.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-DEAhqI3x.mjs} +3 -2
  134. package/dist/admin/chunks/{zh-Hans-JVK9x7xr.js.map → zh-Hans-DEAhqI3x.mjs.map} +1 -1
  135. package/dist/admin/chunks/{zh-Hans-JVK9x7xr.js → zh-Hans-Djj7eGpO.js} +3 -2
  136. package/dist/admin/chunks/{zh-Hans-CI0HKio3.js.map → zh-Hans-Djj7eGpO.js.map} +1 -1
  137. package/dist/admin/index.js +2 -1
  138. package/dist/admin/index.js.map +1 -1
  139. package/dist/admin/index.mjs +2 -1
  140. package/dist/admin/index.mjs.map +1 -1
  141. package/dist/admin/src/components/InjectionZone.d.ts +7 -1
  142. package/dist/admin/src/content-manager.d.ts +6 -0
  143. package/dist/admin/src/features/DocumentContext.d.ts +53 -0
  144. package/dist/admin/src/features/DocumentRBAC.d.ts +3 -2
  145. package/dist/admin/src/hooks/useDocument.d.ts +2 -0
  146. package/dist/admin/src/hooks/useDocumentActions.d.ts +2 -1
  147. package/dist/admin/src/index.d.ts +1 -0
  148. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +2 -1
  149. package/dist/admin/src/pages/EditView/components/EditorToolbarObserver.d.ts +11 -0
  150. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/Code.d.ts +49 -1
  151. package/dist/admin/src/pages/EditView/components/FormInputs/Relations/RelationModal.d.ts +8 -0
  152. package/dist/admin/src/pages/EditView/components/FormInputs/{Relations.d.ts → Relations/Relations.d.ts} +8 -2
  153. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygNav.d.ts +1 -2
  154. package/dist/admin/src/pages/EditView/components/FormLayout.d.ts +9 -3
  155. package/dist/admin/src/pages/EditView/components/InputRenderer.d.ts +7 -4
  156. package/dist/admin/src/preview/components/PreviewHeader.d.ts +1 -2
  157. package/dist/admin/src/preview/pages/Preview.d.ts +2 -0
  158. package/dist/server/index.js +1 -1
  159. package/dist/server/index.js.map +1 -1
  160. package/dist/server/index.mjs +1 -1
  161. package/dist/server/index.mjs.map +1 -1
  162. package/package.json +9 -9
  163. package/dist/admin/chunks/CardDragPreview-DwuraT0K.js.map +0 -1
  164. package/dist/admin/chunks/ComponentConfigurationPage-BSCYuG9k.js.map +0 -1
  165. package/dist/admin/chunks/ComponentIcon-BZcTc4rj.js.map +0 -1
  166. package/dist/admin/chunks/EditConfigurationPage-DAwy6frt.js.map +0 -1
  167. package/dist/admin/chunks/EditViewPage-BZuZJr0N.js +0 -265
  168. package/dist/admin/chunks/EditViewPage-BZuZJr0N.js.map +0 -1
  169. package/dist/admin/chunks/EditViewPage-D8FDB8_y.js +0 -288
  170. package/dist/admin/chunks/EditViewPage-D8FDB8_y.js.map +0 -1
  171. package/dist/admin/chunks/FieldTypeIcon-BY6MrVF4.js.map +0 -1
  172. package/dist/admin/chunks/Form-Bwz2xTe9.js.map +0 -1
  173. package/dist/admin/chunks/History-5wpSVAu9.js.map +0 -1
  174. package/dist/admin/chunks/History-Dax5KiyG.js.map +0 -1
  175. package/dist/admin/chunks/Input-Csrk7S5E.js.map +0 -1
  176. package/dist/admin/chunks/Input-Dr7YL5Sv.js.map +0 -1
  177. package/dist/admin/chunks/ListConfigurationPage-Bp1dKd-U.js.map +0 -1
  178. package/dist/admin/chunks/ListViewPage-DfHXfD_c.js.map +0 -1
  179. package/dist/admin/chunks/NoContentTypePage-BgTBqH4R.js.map +0 -1
  180. package/dist/admin/chunks/NoPermissionsPage-CUnJ9nZ8.js.map +0 -1
  181. package/dist/admin/chunks/Preview-DKUCY7o_.js +0 -504
  182. package/dist/admin/chunks/Preview-DKUCY7o_.js.map +0 -1
  183. package/dist/admin/chunks/Preview-uBnW2CsI.js +0 -482
  184. package/dist/admin/chunks/Preview-uBnW2CsI.js.map +0 -1
  185. package/dist/admin/chunks/Relations-BgtVC-3t.js +0 -827
  186. package/dist/admin/chunks/Relations-BgtVC-3t.js.map +0 -1
  187. package/dist/admin/chunks/Relations-CzrnshXy.js +0 -853
  188. package/dist/admin/chunks/Relations-CzrnshXy.js.map +0 -1
  189. package/dist/admin/chunks/ar-DckYq_WK.js.map +0 -1
  190. package/dist/admin/chunks/ca-DviY7mRj.js.map +0 -1
  191. package/dist/admin/chunks/cs-C7OSYFQ7.js.map +0 -1
  192. package/dist/admin/chunks/de-5QRlDHyR.js.map +0 -1
  193. package/dist/admin/chunks/es-DkoWSExG.js.map +0 -1
  194. package/dist/admin/chunks/eu-BG1xX7HK.js.map +0 -1
  195. package/dist/admin/chunks/fr-CFdRaRVj.js.map +0 -1
  196. package/dist/admin/chunks/gu-D5MMMXRs.js.map +0 -1
  197. package/dist/admin/chunks/hi-lp17SCjr.js.map +0 -1
  198. package/dist/admin/chunks/hooks-DMvik5y_.js.map +0 -1
  199. package/dist/admin/chunks/hu-CLka1U2C.js.map +0 -1
  200. package/dist/admin/chunks/id-USfY9m1g.js.map +0 -1
  201. package/dist/admin/chunks/index-2cT6u68c.js.map +0 -1
  202. package/dist/admin/chunks/index-BhFoy2kH.js.map +0 -1
  203. package/dist/admin/chunks/it-BAHrwmYS.js.map +0 -1
  204. package/dist/admin/chunks/ja-BWKmBJFT.js.map +0 -1
  205. package/dist/admin/chunks/ko-CgADGBNt.js.map +0 -1
  206. package/dist/admin/chunks/layout-CDvvkRib.js.map +0 -1
  207. package/dist/admin/chunks/layout-CsDX52Zb.js.map +0 -1
  208. package/dist/admin/chunks/ml-CnhCfOn_.js.map +0 -1
  209. package/dist/admin/chunks/ms-Bh09NFff.js.map +0 -1
  210. package/dist/admin/chunks/nl-C8HYflTc.js.map +0 -1
  211. package/dist/admin/chunks/objects-C3EebVVe.js +0 -76
  212. package/dist/admin/chunks/objects-C3EebVVe.js.map +0 -1
  213. package/dist/admin/chunks/objects-wl73iEma.js +0 -73
  214. package/dist/admin/chunks/objects-wl73iEma.js.map +0 -1
  215. package/dist/admin/chunks/pl-MFCZJZuZ.js.map +0 -1
  216. package/dist/admin/chunks/pt-BR-CcotyBGJ.js.map +0 -1
  217. package/dist/admin/chunks/pt-HbmgeiYO.js.map +0 -1
  218. package/dist/admin/chunks/relations--SHAQ-Ch.js.map +0 -1
  219. package/dist/admin/chunks/relations-LR7_V8ZN.js.map +0 -1
  220. package/dist/admin/chunks/sa-n_aPA-pU.js.map +0 -1
  221. package/dist/admin/chunks/sk-tn_BDjE2.js.map +0 -1
  222. package/dist/admin/chunks/sv-cq4ZrQRd.js.map +0 -1
  223. package/dist/admin/chunks/th-mUH7hEtc.js.map +0 -1
  224. package/dist/admin/chunks/tr-Yt38daxh.js.map +0 -1
  225. package/dist/admin/chunks/uk-B24MoTVg.js +0 -145
  226. package/dist/admin/chunks/uk-B24MoTVg.js.map +0 -1
  227. package/dist/admin/chunks/uk-Cpgmm7gE.js +0 -140
  228. package/dist/admin/chunks/uk-Cpgmm7gE.js.map +0 -1
  229. package/dist/admin/chunks/useDragAndDrop-HYwNDExe.js.map +0 -1
  230. package/dist/admin/chunks/useDragAndDrop-gcqEJMnO.js.map +0 -1
  231. package/dist/admin/chunks/usePrev-Bjw2dhmq.js +0 -18
  232. package/dist/admin/chunks/usePrev-Bjw2dhmq.js.map +0 -1
  233. package/dist/admin/chunks/usePrev-DIYl-IAL.js +0 -21
  234. package/dist/admin/chunks/usePrev-DIYl-IAL.js.map +0 -1
  235. package/dist/admin/chunks/vi-CvBGlTjr.js.map +0 -1
  236. package/dist/admin/chunks/zh-BmF-sHaT.js.map +0 -1
  237. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/utils/prismLanguages.d.ts +0 -0
  238. 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-2cT6u68c.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-DsOgMEE-.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
- import Prism from 'prismjs';
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-BJk2lXYH.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-BgtVC-3t.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-LR7_V8ZN.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,56 +458,6 @@ const isText$2 = (node)=>{
410
458
  }
411
459
  };
412
460
 
413
- require('prismjs/components/prism-asmatmel');
414
- require('prismjs/components/prism-bash');
415
- require('prismjs/components/prism-basic');
416
- require('prismjs/components/prism-c');
417
- require('prismjs/components/prism-clojure');
418
- require('prismjs/components/prism-cobol');
419
- require('prismjs/components/prism-cpp');
420
- require('prismjs/components/prism-csharp');
421
- require('prismjs/components/prism-dart');
422
- require('prismjs/components/prism-docker');
423
- require('prismjs/components/prism-elixir');
424
- require('prismjs/components/prism-erlang');
425
- require('prismjs/components/prism-fortran');
426
- require('prismjs/components/prism-fsharp');
427
- require('prismjs/components/prism-go');
428
- require('prismjs/components/prism-graphql');
429
- require('prismjs/components/prism-groovy');
430
- require('prismjs/components/prism-haskell');
431
- require('prismjs/components/prism-haxe');
432
- require('prismjs/components/prism-ini');
433
- require('prismjs/components/prism-java');
434
- require('prismjs/components/prism-javascript');
435
- require('prismjs/components/prism-jsx');
436
- require('prismjs/components/prism-json');
437
- require('prismjs/components/prism-julia');
438
- require('prismjs/components/prism-kotlin');
439
- require('prismjs/components/prism-latex');
440
- require('prismjs/components/prism-lua');
441
- require('prismjs/components/prism-markdown');
442
- require('prismjs/components/prism-matlab');
443
- require('prismjs/components/prism-makefile');
444
- require('prismjs/components/prism-objectivec');
445
- require('prismjs/components/prism-perl');
446
- require('prismjs/components/prism-php');
447
- require('prismjs/components/prism-powershell');
448
- require('prismjs/components/prism-python');
449
- require('prismjs/components/prism-r');
450
- require('prismjs/components/prism-ruby');
451
- require('prismjs/components/prism-rust');
452
- require('prismjs/components/prism-sas');
453
- require('prismjs/components/prism-scala');
454
- require('prismjs/components/prism-scheme');
455
- require('prismjs/components/prism-sql');
456
- require('prismjs/components/prism-stata');
457
- require('prismjs/components/prism-swift');
458
- require('prismjs/components/prism-typescript');
459
- require('prismjs/components/prism-tsx');
460
- require('prismjs/components/prism-vbnet');
461
- require('prismjs/components/prism-yaml');
462
-
463
461
  const decorateCode = ([node, path])=>{
464
462
  const ranges = [];
465
463
  // make sure it is an Slate Element
@@ -1032,7 +1030,7 @@ const isListNode$1 = (element)=>{
1032
1030
  return element.type === 'list';
1033
1031
  };
1034
1032
 
1035
- const StyledBaseLink = styled(BaseLink)`
1033
+ const StyledLink = styled(Box)`
1036
1034
  text-decoration: none;
1037
1035
  `;
1038
1036
  const RemoveButton = styled(Button)`
@@ -1092,9 +1090,10 @@ const LinkContent = /*#__PURE__*/ React.forwardRef(({ link, children, attributes
1092
1090
  open: popoverOpen,
1093
1091
  children: [
1094
1092
  /*#__PURE__*/ jsx(Popover.Trigger, {
1095
- children: /*#__PURE__*/ jsx(StyledBaseLink, {
1093
+ children: /*#__PURE__*/ jsx(StyledLink, {
1096
1094
  ...attributes,
1097
1095
  ref: forwardedRef,
1096
+ tag: "a",
1098
1097
  href: link.url,
1099
1098
  onClick: ()=>setPopoverOpen(true),
1100
1099
  color: "primary600",
@@ -1698,13 +1697,103 @@ const quoteBlocks = {
1698
1697
  }
1699
1698
  };
1700
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
+
1701
1790
  const ToolbarWrapper = styled(Flex)`
1702
1791
  &[aria-disabled='true'] {
1703
1792
  cursor: not-allowed;
1704
1793
  background: ${({ theme })=>theme.colors.neutral150};
1705
1794
  }
1706
1795
  `;
1707
- const Separator = styled(Toolbar.Separator)`
1796
+ const ToolbarSeparator = styled(Toolbar.Separator)`
1708
1797
  background: ${({ theme })=>theme.colors.neutral150};
1709
1798
  width: 1px;
1710
1799
  height: 2.4rem;
@@ -1774,7 +1863,7 @@ const ToolbarButton = ({ icon: Icon, name, label, isActive, disabled, handleClic
1774
1863
  const labelMessage = formatMessage(label);
1775
1864
  const enabledColor = isActive ? 'primary600' : 'neutral600';
1776
1865
  return /*#__PURE__*/ jsx(Tooltip, {
1777
- description: labelMessage,
1866
+ label: labelMessage,
1778
1867
  children: /*#__PURE__*/ jsx(Toolbar.ToggleItem, {
1779
1868
  value: name,
1780
1869
  "data-state": isActive ? 'on' : 'off',
@@ -1966,8 +2055,9 @@ const BlockOption = ({ value, icon: Icon, label, blockSelected })=>{
1966
2055
  const isListNode = (node)=>{
1967
2056
  return Node.isNode(node) && !Editor$1.isEditor(node) && node.type === 'list';
1968
2057
  };
1969
- const ListButton = ({ block, format })=>{
2058
+ const ListButton = ({ block, format, location = 'toolbar' })=>{
1970
2059
  const { editor, disabled, blocks } = useBlocksEditorContext('ListButton');
2060
+ const { formatMessage } = useIntl();
1971
2061
  const isListActive = ()=>{
1972
2062
  if (!editor.selection) return false;
1973
2063
  // Get the parent list at selection anchor node
@@ -2043,6 +2133,18 @@ const ListButton = ({ block, format })=>{
2043
2133
  }
2044
2134
  }
2045
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
+ }
2046
2148
  return /*#__PURE__*/ jsx(ToolbarButton, {
2047
2149
  icon: block.icon,
2048
2150
  name: format,
@@ -2052,8 +2154,9 @@ const ListButton = ({ block, format })=>{
2052
2154
  handleClick: ()=>toggleList(format)
2053
2155
  });
2054
2156
  };
2055
- const LinkButton = ({ disabled })=>{
2157
+ const LinkButton = ({ disabled, location = 'toolbar' })=>{
2056
2158
  const { editor } = useBlocksEditorContext('LinkButton');
2159
+ const { formatMessage } = useIntl();
2057
2160
  const isLinkActive = ()=>{
2058
2161
  const { selection } = editor;
2059
2162
  if (!selection) return false;
@@ -2094,20 +2197,55 @@ const LinkButton = ({ disabled })=>{
2094
2197
  url: ''
2095
2198
  });
2096
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
+ }
2097
2215
  return /*#__PURE__*/ jsx(ToolbarButton, {
2098
2216
  icon: Link$1,
2099
2217
  name: "link",
2100
- label: {
2101
- id: 'components.Blocks.link',
2102
- defaultMessage: 'Link'
2103
- },
2218
+ label: label,
2104
2219
  isActive: isLinkActive(),
2105
2220
  handleClick: addLink,
2106
2221
  disabled: isLinkDisabled()
2107
2222
  });
2108
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
+ `;
2109
2246
  const BlocksToolbar = ()=>{
2110
2247
  const { editor, blocks, modifiers, disabled } = useBlocksEditorContext('BlocksToolbar');
2248
+ const { formatMessage } = useIntl();
2111
2249
  /**
2112
2250
  * The modifier buttons are disabled when an image is selected.
2113
2251
  */ const checkButtonDisabled = ()=>{
@@ -2128,6 +2266,94 @@ const BlocksToolbar = ()=>{
2128
2266
  return false;
2129
2267
  };
2130
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
+ ];
2131
2357
  return /*#__PURE__*/ jsx(Toolbar.Root, {
2132
2358
  "aria-disabled": disabled,
2133
2359
  asChild: true,
@@ -2137,43 +2363,18 @@ const BlocksToolbar = ()=>{
2137
2363
  width: "100%",
2138
2364
  children: [
2139
2365
  /*#__PURE__*/ jsx(BlocksDropdown, {}),
2140
- /*#__PURE__*/ jsx(Separator, {}),
2366
+ /*#__PURE__*/ jsx(ToolbarSeparator, {}),
2141
2367
  /*#__PURE__*/ jsx(Toolbar.ToggleGroup, {
2142
2368
  type: "multiple",
2143
2369
  asChild: true,
2144
- children: /*#__PURE__*/ jsxs(Flex, {
2145
- gap: 1,
2146
- children: [
2147
- Object.entries(modifiers).map(([name, modifier])=>/*#__PURE__*/ jsx(ToolbarButton, {
2148
- name: name,
2149
- icon: modifier.icon,
2150
- label: modifier.label,
2151
- isActive: modifier.checkIsActive(editor),
2152
- handleClick: ()=>modifier.handleToggle(editor),
2153
- disabled: isButtonDisabled
2154
- }, name)),
2155
- /*#__PURE__*/ jsx(LinkButton, {
2156
- disabled: isButtonDisabled
2157
- })
2158
- ]
2159
- })
2160
- }),
2161
- /*#__PURE__*/ jsx(Separator, {}),
2162
- /*#__PURE__*/ jsx(Toolbar.ToggleGroup, {
2163
- type: "single",
2164
- asChild: true,
2165
- children: /*#__PURE__*/ jsxs(Flex, {
2370
+ children: /*#__PURE__*/ jsx(Flex, {
2371
+ direction: "row",
2166
2372
  gap: 1,
2167
- children: [
2168
- /*#__PURE__*/ jsx(ListButton, {
2169
- block: blocks['list-unordered'],
2170
- format: "unordered"
2171
- }),
2172
- /*#__PURE__*/ jsx(ListButton, {
2173
- block: blocks['list-ordered'],
2174
- format: "ordered"
2175
- })
2176
- ]
2373
+ grow: 1,
2374
+ overflow: "hidden",
2375
+ children: /*#__PURE__*/ jsx(EditorToolbarObserver, {
2376
+ observedComponents: observedComponents
2377
+ })
2177
2378
  })
2178
2379
  })
2179
2380
  ]
@@ -3262,6 +3463,20 @@ const Initializer = ({ disabled, name, onClick })=>{
3262
3463
  });
3263
3464
  };
3264
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
+
3265
3480
  const AddComponentButton = ({ hasError, isDisabled, isOpen, children, onClick })=>{
3266
3481
  return /*#__PURE__*/ jsx(StyledButton, {
3267
3482
  type: "button",
@@ -3367,15 +3582,24 @@ const ComponentCategory = ({ category, components = [], variant = 'primary', onA
3367
3582
  const ResponsiveAccordionContent = styled(Accordion.Content)`
3368
3583
  container-type: inline-size;
3369
3584
  `;
3370
- const Grid = styled(Box)`
3371
- display: grid;
3372
- grid-template-columns: repeat(auto-fill, 100%);
3373
- grid-gap: ${({ theme })=>theme.spaces[1]};
3374
-
3375
- @container (min-width: ${()=>RESPONSIVE_CONTAINER_BREAKPOINTS.sm}) {
3376
- grid-template-columns: repeat(auto-fill, 14rem);
3377
- }
3378
- `;
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
+ `;
3379
3603
  const ComponentBox = styled(Flex)`
3380
3604
  color: ${({ theme })=>theme.colors.neutral600};
3381
3605
  cursor: pointer;
@@ -3440,7 +3664,19 @@ const ComponentPicker = ({ dynamicComponentsByCategory = {}, isOpen, onClickAddC
3440
3664
  const DynamicComponent = ({ componentUid, disabled, index, name, onRemoveComponentClick, onMoveComponent, onGrabItem, onDropItem, onCancel, dynamicComponentsByCategory = {}, onAddComponent, children })=>{
3441
3665
  const { formatMessage } = useIntl();
3442
3666
  const formValues = useForm('DynamicComponent', (state)=>state.values);
3443
- 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);
3444
3680
  const title = React.useMemo(()=>{
3445
3681
  const { mainField } = components[componentUid]?.settings ?? {
3446
3682
  mainField: 'id'
@@ -3672,9 +3908,11 @@ const DynamicComponent = ({ componentUid, disabled, index, name, onRemoveCompone
3672
3908
  alignItems: "stretch",
3673
3909
  children: children ? children({
3674
3910
  ...fieldWithTranslatedLabel,
3911
+ document,
3675
3912
  name: fieldName
3676
3913
  }) : /*#__PURE__*/ jsx(MemoizedInputRenderer, {
3677
3914
  ...fieldWithTranslatedLabel,
3915
+ document: document,
3678
3916
  name: fieldName
3679
3917
  })
3680
3918
  }, fieldName);
@@ -3792,7 +4030,8 @@ const DynamicZone = ({ attribute, disabled: disabledProp, hint, label, labelActi
3792
4030
  const { max = Infinity, min = -Infinity } = attribute ?? {};
3793
4031
  const [addComponentIsOpen, setAddComponentIsOpen] = React.useState(false);
3794
4032
  const [liveText, setLiveText] = React.useState('');
3795
- const { components, isLoading } = useDoc();
4033
+ const document = useDocumentContext('DynamicZone', (state)=>state.document);
4034
+ const { components, isLoading } = document;
3796
4035
  const disabled = disabledProp || isLoading;
3797
4036
  const { addFieldRow, removeFieldRow, moveFieldRow } = useForm('DynamicZone', ({ addFieldRow, removeFieldRow, moveFieldRow })=>({
3798
4037
  addFieldRow,
@@ -4025,153 +4264,1388 @@ const NotAllowedInput = ({ hint, label, required, name })=>{
4025
4264
  });
4026
4265
  };
4027
4266
 
4028
- const uidApi = contentManagerApi.injectEndpoints({
4029
- endpoints: (builder)=>({
4030
- getDefaultUID: builder.query({
4031
- query: ({ params, ...data })=>{
4032
- return {
4033
- url: '/content-manager/uid/generate',
4034
- method: 'POST',
4035
- data,
4036
- config: {
4037
- params
4038
- }
4039
- };
4040
- },
4041
- transformResponse: (response)=>response.data
4042
- }),
4043
- generateUID: builder.mutation({
4044
- query: ({ params, ...data })=>({
4045
- url: '/content-manager/uid/generate',
4046
- method: 'POST',
4047
- data,
4048
- config: {
4049
- params
4050
- }
4051
- }),
4052
- transformResponse: (response)=>response.data
4053
- }),
4054
- getAvailability: builder.query({
4055
- query: ({ params, ...data })=>({
4056
- url: '/content-manager/uid/check-availability',
4057
- method: 'POST',
4058
- data,
4059
- config: {
4060
- params
4061
- }
4062
- }),
4063
- providesTags: (_res, _error, params)=>[
4064
- {
4065
- type: 'UidAvailability',
4066
- id: params.contentTypeUID
4067
- }
4068
- ]
4069
- })
4070
- })
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
4071
4281
  });
4072
- const { useGenerateUIDMutation, useGetDefaultUIDQuery, useGetAvailabilityQuery } = uidApi;
4073
-
4074
- /* -------------------------------------------------------------------------------------------------
4075
- * InputUID
4076
- * -----------------------------------------------------------------------------------------------*/ const UID_REGEX = /^[A-Za-z0-9-_.~]*$/;
4077
- const UIDInput = /*#__PURE__*/ React.forwardRef(({ hint, label, labelAction, name, required, ...props }, ref)=>{
4078
- const { model, id } = useDoc();
4079
- const allFormValues = useForm('InputUID', (form)=>form.values);
4080
- const [availability, setAvailability] = React.useState();
4081
- const [showRegenerate, setShowRegenerate] = React.useState(false);
4082
- const isCloning = useMatch(CLONE_PATH) !== null;
4083
- const field = useField(name);
4084
- const debouncedValue = useDebounce(field.value, 300);
4085
- const hasChanged = debouncedValue !== field.initialValue;
4086
- const { toggleNotification } = useNotification();
4087
- const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
4282
+ const RelationModalForm = ({ relation, triggerButtonLabel })=>{
4283
+ const navigate = useNavigate();
4284
+ const { pathname, search } = useLocation();
4088
4285
  const { formatMessage } = useIntl();
4089
- const [{ query }] = useQueryParams();
4090
- const params = React.useMemo(()=>buildValidParams(query), [
4091
- query
4092
- ]);
4093
- const { data: defaultGeneratedUID, isLoading: isGeneratingDefaultUID, error: apiError } = useGetDefaultUIDQuery({
4094
- contentTypeUID: model,
4095
- field: name,
4096
- data: {
4097
- id: id ?? '',
4098
- ...allFormValues
4099
- },
4100
- params
4101
- }, {
4102
- skip: field.value || !required
4103
- });
4104
- React.useEffect(()=>{
4105
- if (apiError) {
4106
- toggleNotification({
4107
- type: 'warning',
4108
- message: formatAPIError(apiError)
4109
- });
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);
4110
4337
  }
4111
- }, [
4112
- apiError,
4113
- formatAPIError,
4114
- toggleNotification
4115
- ]);
4116
- /**
4117
- * If the defaultGeneratedUID is available, then we set it as the value,
4118
- * but we also want to set it as the initialValue too.
4119
- */ React.useEffect(()=>{
4120
- if (defaultGeneratedUID && field.value === undefined) {
4121
- 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());
4122
4351
  }
4123
- }, [
4124
- defaultGeneratedUID,
4125
- field,
4126
- name
4127
- ]);
4128
- const [generateUID, { isLoading: isGeneratingUID }] = useGenerateUIDMutation();
4129
- const handleRegenerateClick = async ()=>{
4130
- try {
4131
- const res = await generateUID({
4132
- contentTypeUID: model,
4133
- field: name,
4134
- data: {
4135
- id: id ?? '',
4136
- ...allFormValues
4137
- },
4138
- params
4139
- });
4140
- if ('data' in res) {
4141
- field.onChange(name, res.data);
4142
- } else {
4143
- toggleNotification({
4144
- type: 'danger',
4145
- message: formatAPIError(res.error)
4146
- });
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);
4147
4361
  }
4148
- } catch (err) {
4149
- toggleNotification({
4150
- type: 'danger',
4151
- message: formatMessage({
4152
- id: 'notification.error',
4153
- defaultMessage: 'An error occurred.'
4154
- })
4155
- });
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();
4156
4368
  }
4157
4369
  };
4158
- const { data: availabilityData, isLoading: isCheckingAvailability, error: availabilityError } = useGetAvailabilityQuery({
4159
- contentTypeUID: model,
4160
- field: name,
4161
- value: debouncedValue ? debouncedValue.trim() : '',
4162
- params
4163
- }, {
4164
- // Don't check availability if the value is empty or wasn't changed
4165
- skip: !Boolean((hasChanged || isCloning) && debouncedValue && UID_REGEX.test(debouncedValue.trim()))
4166
- });
4167
- React.useEffect(()=>{
4168
- if (availabilityError) {
4169
- toggleNotification({
4170
- type: 'warning',
4171
- 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
4172
4377
  });
4173
- }
4174
- }, [
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
+ fromRelationModal: true,
4594
+ fromPreview: onPreview !== undefined
4595
+ };
4596
+ return /*#__PURE__*/ jsx(Modal.Body, {
4597
+ children: /*#__PURE__*/ jsxs(DocumentRBAC, {
4598
+ permissions: permissions,
4599
+ model: documentMeta.model,
4600
+ children: [
4601
+ /*#__PURE__*/ jsxs(Flex, {
4602
+ alignItems: "flex-start",
4603
+ direction: "column",
4604
+ gap: 2,
4605
+ children: [
4606
+ /*#__PURE__*/ jsxs(Flex, {
4607
+ width: "100%",
4608
+ justifyContent: "space-between",
4609
+ gap: 2,
4610
+ children: [
4611
+ /*#__PURE__*/ jsx(Typography, {
4612
+ tag: "h2",
4613
+ variant: "alpha",
4614
+ children: documentTitle
4615
+ }),
4616
+ /*#__PURE__*/ jsxs(Flex, {
4617
+ gap: 2,
4618
+ children: [
4619
+ children,
4620
+ /*#__PURE__*/ jsx(DescriptionComponentRenderer, {
4621
+ props: props,
4622
+ descriptions: plugins['content-manager'].apis.getDocumentActions('relation-modal'),
4623
+ children: (actions)=>{
4624
+ const filteredActions = actions.filter((action)=>{
4625
+ return [
4626
+ action.position
4627
+ ].flat().includes('relation-modal');
4628
+ });
4629
+ const [primaryAction, secondaryAction] = filteredActions;
4630
+ if (!primaryAction && !secondaryAction) return null;
4631
+ // Both actions are available when draft and publish enabled
4632
+ if (primaryAction && secondaryAction) {
4633
+ return /*#__PURE__*/ jsxs(Fragment, {
4634
+ children: [
4635
+ /*#__PURE__*/ jsx(DocumentActionButton, {
4636
+ ...secondaryAction,
4637
+ variant: secondaryAction.variant || 'secondary'
4638
+ }),
4639
+ /*#__PURE__*/ jsx(DocumentActionButton, {
4640
+ ...primaryAction,
4641
+ variant: primaryAction.variant || 'default'
4642
+ })
4643
+ ]
4644
+ });
4645
+ }
4646
+ // Otherwise we just have the save action
4647
+ return /*#__PURE__*/ jsx(DocumentActionButton, {
4648
+ ...primaryAction,
4649
+ variant: primaryAction.variant || 'secondary'
4650
+ });
4651
+ }
4652
+ })
4653
+ ]
4654
+ })
4655
+ ]
4656
+ }),
4657
+ hasDraftAndPublished ? /*#__PURE__*/ jsx(Box, {
4658
+ children: /*#__PURE__*/ jsx(DocumentStatus, {
4659
+ status: documentResponse.document?.status
4660
+ })
4661
+ }) : null
4662
+ ]
4663
+ }),
4664
+ /*#__PURE__*/ jsx(Flex, {
4665
+ flex: 1,
4666
+ overflow: "auto",
4667
+ alignItems: "stretch",
4668
+ paddingTop: 7,
4669
+ children: /*#__PURE__*/ jsx(Box, {
4670
+ overflow: "auto",
4671
+ flex: 1,
4672
+ children: /*#__PURE__*/ jsx(FormLayout, {
4673
+ layout: documentLayoutResponse.edit.layout,
4674
+ document: documentResponse,
4675
+ hasBackground: false
4676
+ })
4677
+ })
4678
+ })
4679
+ ]
4680
+ })
4681
+ });
4682
+ };
4683
+
4684
+ /**
4685
+ * Remove a relation, whether it's been already saved or not.
4686
+ * It's used both in RelationsList, where the "remove relation" button is, and in the input,
4687
+ * because we sometimes need to remove a previous relation when selecting a new one.
4688
+ */ function useHandleDisconnect(fieldName, consumerName) {
4689
+ const field = useField(fieldName);
4690
+ const removeFieldRow = useForm(consumerName, (state)=>state.removeFieldRow);
4691
+ const addFieldRow = useForm(consumerName, (state)=>state.addFieldRow);
4692
+ const handleDisconnect = (relation)=>{
4693
+ if (field.value && field.value.connect) {
4694
+ /**
4695
+ * A relation will exist in the `connect` array _if_ it has
4696
+ * been added without saving. In this case, we just remove it
4697
+ * from the connect array
4698
+ */ const indexOfRelationInConnectArray = field.value.connect.findIndex((rel)=>rel.id === relation.id);
4699
+ if (indexOfRelationInConnectArray >= 0) {
4700
+ removeFieldRow(`${fieldName}.connect`, indexOfRelationInConnectArray);
4701
+ return;
4702
+ }
4703
+ }
4704
+ addFieldRow(`${fieldName}.disconnect`, {
4705
+ id: relation.id,
4706
+ apiData: {
4707
+ id: relation.id,
4708
+ documentId: relation.documentId,
4709
+ locale: relation.locale
4710
+ }
4711
+ });
4712
+ };
4713
+ return handleDisconnect;
4714
+ }
4715
+ /* -------------------------------------------------------------------------------------------------
4716
+ * RelationsField
4717
+ * -----------------------------------------------------------------------------------------------*/ const RELATIONS_TO_DISPLAY = 5;
4718
+ const ONE_WAY_RELATIONS = [
4719
+ 'oneWay',
4720
+ 'oneToOne',
4721
+ 'manyToOne',
4722
+ 'oneToManyMorph',
4723
+ 'oneToOneMorph'
4724
+ ];
4725
+ /**
4726
+ * TODO: we get a rather ugly flash when we remove a single relation from the list leaving
4727
+ * no other relations when we press save. The initial relation re-renders, probably because
4728
+ * of the lag in the Form cleaning it's "disconnect" array, whilst our data has not been invalidated.
4729
+ *
4730
+ * Could we invalidate relation data on the document actions? Should we?
4731
+ */ /**
4732
+ * @internal
4733
+ * @description The relations field holds a lot of domain logic for handling relations which is rather complicated
4734
+ * At present we do not expose this to plugin developers, however, they are able to overwrite it themselves should
4735
+ * they wish to do so.
4736
+ */ const RelationsField = /*#__PURE__*/ React.forwardRef(({ disabled, label, ...props }, ref)=>{
4737
+ const currentDocumentMeta = useDocumentContext('RelationsField', (state)=>state.meta);
4738
+ const currentDocument = useDocumentContext('RelationsField', (state)=>state.document);
4739
+ const rootDocumentMeta = useDocumentContext('RelationsField', (state)=>state.rootDocumentMeta);
4740
+ const [currentPage, setCurrentPage] = React.useState(1);
4741
+ const isRootDocument = rootDocumentMeta.documentId === currentDocumentMeta.documentId;
4742
+ const documentMeta = isRootDocument ? rootDocumentMeta : currentDocumentMeta;
4743
+ // Use the documentId from the actual document, not the params (meta)
4744
+ const documentId = currentDocument.document?.documentId;
4745
+ const { formatMessage } = useIntl();
4746
+ const [{ query }] = useQueryParams();
4747
+ const params = documentMeta.params ?? buildValidParams(query);
4748
+ const isMorph = props.attribute.relation.toLowerCase().includes('morph');
4749
+ const isDisabled = isMorph || disabled;
4750
+ const { componentId, componentUID } = useComponent('RelationsField', ({ uid, id })=>({
4751
+ componentId: id,
4752
+ componentUID: uid
4753
+ }));
4754
+ const isSubmitting = useForm('RelationsList', (state)=>state.isSubmitting);
4755
+ React.useEffect(()=>{
4756
+ setCurrentPage(1);
4757
+ }, [
4758
+ isSubmitting
4759
+ ]);
4760
+ const component = componentUID && currentDocument.components[componentUID];
4761
+ /**
4762
+ * We'll always have a documentId in a created entry, so we look for a componentId first.
4763
+ * Same with `uid` and `documentModel`.
4764
+ */ const model = component ? component.uid : documentMeta.model;
4765
+ const id = component && componentId ? componentId.toString() : documentId;
4766
+ /**
4767
+ * The `name` prop is a complete path to the field, e.g. `field1.field2.field3`.
4768
+ * Where the above example would a nested field within two components, however
4769
+ * we only require the field on the component not the complete path since we query
4770
+ * individual components. Therefore we split the string and take the last item.
4771
+ */ const [targetField] = props.name.split('.').slice(-1);
4772
+ const schemaAttributes = component ? component.attributes ?? {} : currentDocument.schema?.attributes ?? {};
4773
+ /**
4774
+ * Confirm the target field is related to the current document.
4775
+ * Since relations can exist in a modal on top of the root document,
4776
+ * we need to ensure we are fetching relations for the correct document (root document vs related document),
4777
+ */ const isRelatedToCurrentDocument = Object.values(schemaAttributes).filter((attribute)=>attribute.type === 'relation' && 'target' in attribute && 'target' in props.attribute && attribute.target === props.attribute.target).length > 0;
4778
+ const { data, isLoading, isFetching } = useGetRelationsQuery({
4779
+ model,
4780
+ targetField,
4781
+ // below we don't run the query if there is no id.
4782
+ id,
4783
+ params: {
4784
+ ...params,
4785
+ pageSize: RELATIONS_TO_DISPLAY,
4786
+ page: currentPage
4787
+ }
4788
+ }, {
4789
+ refetchOnMountOrArgChange: true,
4790
+ skip: !id || !isRelatedToCurrentDocument,
4791
+ selectFromResult: (result)=>{
4792
+ return {
4793
+ ...result,
4794
+ data: {
4795
+ ...result.data,
4796
+ results: result.data?.results ? result.data.results : []
4797
+ }
4798
+ };
4799
+ }
4800
+ });
4801
+ const handleLoadMore = ()=>{
4802
+ setCurrentPage((prev)=>prev + 1);
4803
+ };
4804
+ const field = useField(props.name);
4805
+ const isFetchingMoreRelations = isLoading || isFetching;
4806
+ const realServerRelationsCount = 'pagination' in data && data.pagination ? data.pagination.total : 0;
4807
+ /**
4808
+ * Items that are already connected, but reordered would be in
4809
+ * this list, so to get an accurate figure, we remove them.
4810
+ */ const relationsConnected = (field.value?.connect ?? []).filter((rel)=>data.results.findIndex((relation)=>relation.id === rel.id) === -1).length ?? 0;
4811
+ const relationsDisconnected = field.value?.disconnect?.length ?? 0;
4812
+ const relationsCount = realServerRelationsCount + relationsConnected - relationsDisconnected;
4813
+ /**
4814
+ * This is it, the source of truth for reordering in conjunction with partial loading & updating
4815
+ * of relations. Relations on load are given __temp_key__ when fetched, because we don't want to
4816
+ * create brand new keys everytime the data updates, just keep adding them onto the newly loaded ones.
4817
+ */ const relations = React.useMemo(()=>{
4818
+ const ctx = {
4819
+ field: field.value,
4820
+ // @ts-expect-error – targetModel does exist on the attribute. But it's not typed.
4821
+ href: `../${COLLECTION_TYPES}/${props.attribute.targetModel}`,
4822
+ mainField: props.mainField
4823
+ };
4824
+ /**
4825
+ * Tidy up our data.
4826
+ */ const transformations = pipe$1(removeConnected(ctx), removeDisconnected(ctx), addLabelAndHref(ctx));
4827
+ const transformedRels = transformations([
4828
+ ...data.results
4829
+ ]);
4830
+ /**
4831
+ * THIS IS CRUCIAL. If you don't sort by the __temp_key__ which comes from fractional indexing
4832
+ * then the list will be in the wrong order.
4833
+ */ return [
4834
+ ...transformedRels,
4835
+ ...field.value?.connect ?? []
4836
+ ].sort((a, b)=>{
4837
+ if (a.__temp_key__ < b.__temp_key__) return -1;
4838
+ if (a.__temp_key__ > b.__temp_key__) return 1;
4839
+ return 0;
4840
+ });
4841
+ }, [
4842
+ data.results,
4843
+ field.value,
4844
+ // @ts-expect-error – targetModel does exist on the attribute. But it's not typed.
4845
+ props.attribute.targetModel,
4846
+ props.mainField
4847
+ ]);
4848
+ const handleDisconnect = useHandleDisconnect(props.name, 'RelationsField');
4849
+ const handleConnect = (relation)=>{
4850
+ const [lastItemInList] = relations.slice(-1);
4851
+ const item = {
4852
+ id: relation.id,
4853
+ apiData: {
4854
+ id: relation.id,
4855
+ documentId: relation.documentId,
4856
+ locale: relation.locale
4857
+ },
4858
+ status: relation.status,
4859
+ /**
4860
+ * If there's a last item, that's the first key we use to generate out next one.
4861
+ */ __temp_key__: generateNKeysBetween(lastItemInList?.__temp_key__ ?? null, null, 1)[0],
4862
+ // Fallback to `id` if there is no `mainField` value, which will overwrite the above `id` property with the exact same data.
4863
+ [props.mainField?.name ?? 'documentId']: relation[props.mainField?.name ?? 'documentId'],
4864
+ label: getRelationLabel(relation, props.mainField),
4865
+ // @ts-expect-error – targetModel does exist on the attribute, but it's not typed.
4866
+ href: `../${COLLECTION_TYPES}/${props.attribute.targetModel}/${relation.documentId}?${relation.locale ? `plugins[i18n][locale]=${relation.locale}` : ''}`
4867
+ };
4868
+ if (ONE_WAY_RELATIONS.includes(props.attribute.relation)) {
4869
+ // Remove any existing relation so they can be replaced with the new one
4870
+ field.value?.connect?.forEach(handleDisconnect);
4871
+ relations.forEach(handleDisconnect);
4872
+ field.onChange(`${props.name}.connect`, [
4873
+ item
4874
+ ]);
4875
+ } else {
4876
+ field.onChange(`${props.name}.connect`, [
4877
+ ...field.value?.connect ?? [],
4878
+ item
4879
+ ]);
4880
+ }
4881
+ };
4882
+ return /*#__PURE__*/ jsxs(Flex, {
4883
+ ref: ref,
4884
+ direction: "column",
4885
+ gap: 3,
4886
+ justifyContent: "space-between",
4887
+ alignItems: "stretch",
4888
+ wrap: "wrap",
4889
+ children: [
4890
+ /*#__PURE__*/ jsxs(StyledFlex, {
4891
+ direction: "column",
4892
+ alignItems: "start",
4893
+ gap: 2,
4894
+ width: "100%",
4895
+ children: [
4896
+ /*#__PURE__*/ jsx(RelationsInput, {
4897
+ disabled: isDisabled,
4898
+ // NOTE: we should not default to using the documentId if the component is being created (componentUID is undefined)
4899
+ id: componentUID && component ? componentId ? `${componentId}` : '' : documentId,
4900
+ label: `${label} ${relationsCount > 0 ? `(${relationsCount})` : ''}`,
4901
+ model: model,
4902
+ onChange: handleConnect,
4903
+ isRelatedToCurrentDocument: isRelatedToCurrentDocument,
4904
+ ...props
4905
+ }),
4906
+ 'pagination' in data && data.pagination && data.pagination.pageCount > data.pagination.page ? /*#__PURE__*/ jsx(TextButton, {
4907
+ disabled: isFetchingMoreRelations,
4908
+ onClick: handleLoadMore,
4909
+ loading: isFetchingMoreRelations,
4910
+ startIcon: /*#__PURE__*/ jsx(ArrowClockwise, {}),
4911
+ // prevent the label from line-wrapping
4912
+ shrink: 0,
4913
+ children: formatMessage({
4914
+ id: getTranslation('relation.loadMore'),
4915
+ defaultMessage: 'Load More'
4916
+ })
4917
+ }) : null
4918
+ ]
4919
+ }),
4920
+ /*#__PURE__*/ jsx(RelationsList, {
4921
+ data: relations,
4922
+ serverData: data.results,
4923
+ disabled: isDisabled,
4924
+ name: props.name,
4925
+ isLoading: isFetchingMoreRelations,
4926
+ relationType: props.attribute.relation,
4927
+ // @ts-expect-error – targetModel does exist on the attribute. But it's not typed.
4928
+ targetModel: props.attribute.targetModel
4929
+ })
4930
+ ]
4931
+ });
4932
+ });
4933
+ /**
4934
+ * TODO: this can be removed once we stop shipping Inputs with
4935
+ * labels wrapped round in DS@2.
4936
+ */ const StyledFlex = styled(Flex)`
4937
+ & > div {
4938
+ width: 100%;
4939
+ }
4940
+ `;
4941
+ /**
4942
+ * If it's in the connected array, it can get out of our data array,
4943
+ * we'll be putting it back in later and sorting it anyway.
4944
+ */ const removeConnected = ({ field })=>(relations)=>{
4945
+ return relations.filter((relation)=>{
4946
+ const connectedRelations = field?.connect ?? [];
4947
+ return connectedRelations.findIndex((rel)=>rel.id === relation.id) === -1;
4948
+ });
4949
+ };
4950
+ /**
4951
+ * @description Removes relations that are in the `disconnect` array of the field
4952
+ */ const removeDisconnected = ({ field })=>(relations)=>relations.filter((relation)=>{
4953
+ const disconnectedRelations = field?.disconnect ?? [];
4954
+ return disconnectedRelations.findIndex((rel)=>rel.id === relation.id) === -1;
4955
+ });
4956
+ /**
4957
+ * @description Adds a label and href to the relation object we use this to render
4958
+ * a better UI where we can link to the relation and display a human-readable label.
4959
+ */ const addLabelAndHref = ({ mainField, href })=>(relations)=>relations.map((relation)=>{
4960
+ return {
4961
+ ...relation,
4962
+ // Fallback to `id` if there is no `mainField` value, which will overwrite the above `documentId` property with the exact same data.
4963
+ [mainField?.name ?? 'documentId']: relation[mainField?.name ?? 'documentId'],
4964
+ label: getRelationLabel(relation, mainField),
4965
+ href: `${href}/${relation.documentId}?${relation.locale ? `plugins[i18n][locale]=${relation.locale}` : ''}`
4966
+ };
4967
+ });
4968
+ /**
4969
+ * @description Contains all the logic for the combobox that can search
4970
+ * for relations and then add them to the field's connect array.
4971
+ */ const RelationsInput = ({ hint, id, model, label, labelAction, name, mainField, placeholder, required, unique: _unique, 'aria-label': _ariaLabel, onChange, isRelatedToCurrentDocument, ...props })=>{
4972
+ const [textValue, setTextValue] = React.useState('');
4973
+ const [searchParams, setSearchParams] = React.useState({
4974
+ _q: '',
4975
+ page: 1
4976
+ });
4977
+ const { toggleNotification } = useNotification();
4978
+ const [{ query }] = useQueryParams();
4979
+ const currentDocumentMeta = useDocumentContext('RelationsInput', (state)=>state.meta);
4980
+ const rootDocumentMeta = useDocumentContext('RelationsInput', (state)=>state.rootDocumentMeta);
4981
+ const isRootDocument = rootDocumentMeta.documentId === currentDocumentMeta.documentId;
4982
+ const documentMeta = isRootDocument ? rootDocumentMeta : currentDocumentMeta;
4983
+ const { formatMessage } = useIntl();
4984
+ const fieldRef = useFocusInputField(name);
4985
+ const field = useField(name);
4986
+ const searchParamsDebounced = useDebounce(searchParams, 300);
4987
+ const [searchForTrigger, { data, isLoading }] = useLazySearchRelationsQuery();
4988
+ /**
4989
+ * Because we're using a lazy query, we need to trigger the search
4990
+ * when the component mounts and when the search params change.
4991
+ * We also need to trigger the search when the field value changes
4992
+ * so that we can filter out the relations that are already connected.
4993
+ */ React.useEffect(()=>{
4994
+ /**
4995
+ * The `name` prop is a complete path to the field, e.g. `field1.field2.field3`.
4996
+ * Where the above example would a nested field within two components, however
4997
+ * we only require the field on the component not the complete path since we query
4998
+ * individual components. Therefore we split the string and take the last item.
4999
+ */ const [targetField] = name.split('.').slice(-1);
5000
+ // Return early if there is no relation to the document
5001
+ if (!isRelatedToCurrentDocument) return;
5002
+ const params = documentMeta.params ?? buildValidParams(query);
5003
+ searchForTrigger({
5004
+ model,
5005
+ targetField,
5006
+ params: {
5007
+ ...params,
5008
+ id: id ?? '',
5009
+ pageSize: 10,
5010
+ idsToInclude: field.value?.disconnect?.map((rel)=>rel.id.toString()) ?? [],
5011
+ idsToOmit: field.value?.connect?.map((rel)=>rel.id.toString()) ?? [],
5012
+ ...searchParamsDebounced
5013
+ }
5014
+ });
5015
+ }, [
5016
+ field.value?.connect,
5017
+ field.value?.disconnect,
5018
+ id,
5019
+ model,
5020
+ name,
5021
+ query,
5022
+ searchForTrigger,
5023
+ searchParamsDebounced,
5024
+ isRelatedToCurrentDocument,
5025
+ documentMeta
5026
+ ]);
5027
+ const handleSearch = async (search)=>{
5028
+ setSearchParams((s)=>({
5029
+ ...s,
5030
+ _q: search,
5031
+ page: 1
5032
+ }));
5033
+ };
5034
+ const hasNextPage = data?.pagination ? data.pagination.page < data.pagination.pageCount : false;
5035
+ const options = data?.results ?? [];
5036
+ const handleChange = (relationId)=>{
5037
+ if (!relationId) {
5038
+ return;
5039
+ }
5040
+ const relation = options.find((opt)=>opt.id.toString() === relationId);
5041
+ if (!relation) {
5042
+ // This is very unlikely to happen, but it ensures we don't have any data for.
5043
+ 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.");
5044
+ toggleNotification({
5045
+ message: formatMessage({
5046
+ id: getTranslation('relation.error-adding-relation'),
5047
+ defaultMessage: 'An error occurred while trying to add the relation.'
5048
+ }),
5049
+ type: 'danger'
5050
+ });
5051
+ return;
5052
+ }
5053
+ /**
5054
+ * You need to give this relation a correct _temp_key_ but
5055
+ * this component doesn't know about those ones, you can't rely
5056
+ * on the connect array because that doesn't hold items that haven't
5057
+ * moved. So use a callback to fill in the gaps when connecting.
5058
+ *
5059
+ */ onChange(relation);
5060
+ };
5061
+ const handleLoadMore = ()=>{
5062
+ if (!data || !data.pagination) {
5063
+ return;
5064
+ } else if (data.pagination.page < data.pagination.pageCount) {
5065
+ setSearchParams((s)=>({
5066
+ ...s,
5067
+ page: s.page + 1
5068
+ }));
5069
+ }
5070
+ };
5071
+ React.useLayoutEffect(()=>{
5072
+ setTextValue('');
5073
+ }, [
5074
+ field.value
5075
+ ]);
5076
+ return /*#__PURE__*/ jsxs(Field.Root, {
5077
+ error: field.error,
5078
+ hint: hint,
5079
+ name: name,
5080
+ required: required,
5081
+ children: [
5082
+ /*#__PURE__*/ jsx(Field.Label, {
5083
+ action: labelAction,
5084
+ children: label
5085
+ }),
5086
+ /*#__PURE__*/ jsx(Combobox, {
5087
+ ref: fieldRef,
5088
+ name: name,
5089
+ autocomplete: "list",
5090
+ placeholder: placeholder || formatMessage({
5091
+ id: getTranslation('relation.add'),
5092
+ defaultMessage: 'Add relation'
5093
+ }),
5094
+ hasMoreItems: hasNextPage,
5095
+ loading: isLoading,
5096
+ onOpenChange: ()=>{
5097
+ handleSearch(textValue ?? '');
5098
+ },
5099
+ noOptionsMessage: ()=>formatMessage({
5100
+ id: getTranslation('relation.notAvailable'),
5101
+ defaultMessage: 'No relations available'
5102
+ }),
5103
+ loadingMessage: formatMessage({
5104
+ id: getTranslation('relation.isLoading'),
5105
+ defaultMessage: 'Relations are loading'
5106
+ }),
5107
+ onLoadMore: handleLoadMore,
5108
+ textValue: textValue,
5109
+ onChange: handleChange,
5110
+ onTextValueChange: (text)=>{
5111
+ setTextValue(text);
5112
+ },
5113
+ onInputChange: (event)=>{
5114
+ handleSearch(event.currentTarget.value);
5115
+ },
5116
+ ...props,
5117
+ children: options.map((opt)=>{
5118
+ const textValue = getRelationLabel(opt, mainField);
5119
+ return /*#__PURE__*/ jsx(ComboboxOption, {
5120
+ value: opt.id.toString(),
5121
+ textValue: textValue,
5122
+ children: /*#__PURE__*/ jsxs(Flex, {
5123
+ gap: 2,
5124
+ justifyContent: "space-between",
5125
+ children: [
5126
+ /*#__PURE__*/ jsx(Typography, {
5127
+ ellipsis: true,
5128
+ children: textValue
5129
+ }),
5130
+ opt.status ? /*#__PURE__*/ jsx(DocumentStatus, {
5131
+ status: opt.status
5132
+ }) : null
5133
+ ]
5134
+ })
5135
+ }, opt.id);
5136
+ })
5137
+ }),
5138
+ /*#__PURE__*/ jsx(Field.Error, {}),
5139
+ /*#__PURE__*/ jsx(Field.Hint, {})
5140
+ ]
5141
+ });
5142
+ };
5143
+ /* -------------------------------------------------------------------------------------------------
5144
+ * RelationsList
5145
+ * -----------------------------------------------------------------------------------------------*/ const RELATION_ITEM_HEIGHT = 50;
5146
+ const RELATION_GUTTER = 4;
5147
+ const RelationsList = ({ data, serverData, disabled, name, isLoading, relationType, targetModel })=>{
5148
+ const ariaDescriptionId = React.useId();
5149
+ const { formatMessage } = useIntl();
5150
+ const listRef = React.useRef(null);
5151
+ const outerListRef = React.useRef(null);
5152
+ const [overflow, setOverflow] = React.useState();
5153
+ const [liveText, setLiveText] = React.useState('');
5154
+ const field = useField(name);
5155
+ React.useEffect(()=>{
5156
+ if (data.length <= RELATIONS_TO_DISPLAY) {
5157
+ return setOverflow(undefined);
5158
+ }
5159
+ const handleNativeScroll = (e)=>{
5160
+ const el = e.target;
5161
+ const parentScrollContainerHeight = el.parentNode.scrollHeight;
5162
+ const maxScrollBottom = el.scrollHeight - el.scrollTop;
5163
+ if (el.scrollTop === 0) {
5164
+ return setOverflow('bottom');
5165
+ }
5166
+ if (maxScrollBottom === parentScrollContainerHeight) {
5167
+ return setOverflow('top');
5168
+ }
5169
+ return setOverflow('top-bottom');
5170
+ };
5171
+ const outerListRefCurrent = outerListRef?.current;
5172
+ if (!isLoading && data.length > 0 && outerListRefCurrent) {
5173
+ outerListRef.current.addEventListener('scroll', handleNativeScroll);
5174
+ }
5175
+ return ()=>{
5176
+ if (outerListRefCurrent) {
5177
+ outerListRefCurrent.removeEventListener('scroll', handleNativeScroll);
5178
+ }
5179
+ };
5180
+ }, [
5181
+ isLoading,
5182
+ data.length
5183
+ ]);
5184
+ const getItemPos = (index)=>`${index + 1} of ${data.length}`;
5185
+ const handleMoveItem = (newIndex, oldIndex)=>{
5186
+ const item = data[oldIndex];
5187
+ setLiveText(formatMessage({
5188
+ id: getTranslation('dnd.reorder'),
5189
+ defaultMessage: '{item}, moved. New position in list: {position}.'
5190
+ }, {
5191
+ item: item.label ?? item.documentId,
5192
+ position: getItemPos(newIndex)
5193
+ }));
5194
+ /**
5195
+ * Splicing mutates the array, so we need to create a new array
5196
+ */ const newData = [
5197
+ ...data
5198
+ ];
5199
+ const currentRow = data[oldIndex];
5200
+ const startKey = oldIndex > newIndex ? newData[newIndex - 1]?.__temp_key__ : newData[newIndex]?.__temp_key__;
5201
+ const endKey = oldIndex > newIndex ? newData[newIndex]?.__temp_key__ : newData[newIndex + 1]?.__temp_key__;
5202
+ /**
5203
+ * We're moving the relation between two other relations, so
5204
+ * we need to generate a new key that keeps the order
5205
+ */ const [newKey] = generateNKeysBetween(startKey, endKey, 1);
5206
+ newData.splice(oldIndex, 1);
5207
+ newData.splice(newIndex, 0, {
5208
+ ...currentRow,
5209
+ __temp_key__: newKey
5210
+ });
5211
+ /**
5212
+ * Now we diff against the server to understand what's different so we
5213
+ * can keep the connect array nice and tidy. It also needs reversing because
5214
+ * we reverse the relations from the server in the first place.
5215
+ */ const connectedRelations = newData.reduce((acc, relation, currentIndex, array)=>{
5216
+ const relationOnServer = serverData.find((oldRelation)=>oldRelation.id === relation.id);
5217
+ const relationInFront = array[currentIndex + 1];
5218
+ if (!relationOnServer || relationOnServer.__temp_key__ !== relation.__temp_key__) {
5219
+ const position = relationInFront ? {
5220
+ before: relationInFront.documentId,
5221
+ locale: relationInFront.locale,
5222
+ status: 'publishedAt' in relationInFront && relationInFront.publishedAt ? 'published' : 'draft'
5223
+ } : {
5224
+ end: true
5225
+ };
5226
+ const relationWithPosition = {
5227
+ ...relation,
5228
+ ...{
5229
+ apiData: {
5230
+ id: relation.id,
5231
+ documentId: relation.documentId ?? relation.apiData?.documentId ?? '',
5232
+ locale: relation.locale || relation.apiData?.locale,
5233
+ position
5234
+ }
5235
+ }
5236
+ };
5237
+ return [
5238
+ ...acc,
5239
+ relationWithPosition
5240
+ ];
5241
+ }
5242
+ return acc;
5243
+ }, []).toReversed();
5244
+ field.onChange(`${name}.connect`, connectedRelations);
5245
+ };
5246
+ const handleGrabItem = (index)=>{
5247
+ const item = data[index];
5248
+ setLiveText(formatMessage({
5249
+ id: getTranslation('dnd.grab-item'),
5250
+ defaultMessage: `{item}, grabbed. Current position in list: {position}. Press up and down arrow to change position, Spacebar to drop, Escape to cancel.`
5251
+ }, {
5252
+ item: item.label ?? item.documentId,
5253
+ position: getItemPos(index)
5254
+ }));
5255
+ };
5256
+ const handleDropItem = (index)=>{
5257
+ const { href: _href, label, ...item } = data[index];
5258
+ setLiveText(formatMessage({
5259
+ id: getTranslation('dnd.drop-item'),
5260
+ defaultMessage: `{item}, dropped. Final position in list: {position}.`
5261
+ }, {
5262
+ item: label ?? item.documentId,
5263
+ position: getItemPos(index)
5264
+ }));
5265
+ };
5266
+ const handleCancel = (index)=>{
5267
+ const item = data[index];
5268
+ setLiveText(formatMessage({
5269
+ id: getTranslation('dnd.cancel-item'),
5270
+ defaultMessage: '{item}, dropped. Re-order cancelled.'
5271
+ }, {
5272
+ item: item.label ?? item.documentId
5273
+ }));
5274
+ };
5275
+ const handleDisconnect = useHandleDisconnect(name, 'RelationsList');
5276
+ /**
5277
+ * These relation types will only ever have one item
5278
+ * in their list, so you can't reorder a single item!
5279
+ */ const canReorder = !ONE_WAY_RELATIONS.includes(relationType);
5280
+ 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);
5281
+ return /*#__PURE__*/ jsxs(ShadowBox, {
5282
+ $overflowDirection: overflow,
5283
+ children: [
5284
+ /*#__PURE__*/ jsx(VisuallyHidden, {
5285
+ id: ariaDescriptionId,
5286
+ children: formatMessage({
5287
+ id: getTranslation('dnd.instructions'),
5288
+ defaultMessage: `Press spacebar to grab and re-order`
5289
+ })
5290
+ }),
5291
+ /*#__PURE__*/ jsx(VisuallyHidden, {
5292
+ "aria-live": "assertive",
5293
+ children: liveText
5294
+ }),
5295
+ /*#__PURE__*/ jsx(FixedSizeList, {
5296
+ height: dynamicListHeight,
5297
+ ref: listRef,
5298
+ outerRef: outerListRef,
5299
+ itemCount: data.length,
5300
+ itemSize: RELATION_ITEM_HEIGHT + RELATION_GUTTER,
5301
+ itemData: {
5302
+ ariaDescribedBy: ariaDescriptionId,
5303
+ canDrag: canReorder,
5304
+ disabled,
5305
+ handleCancel,
5306
+ handleDropItem,
5307
+ handleGrabItem,
5308
+ handleMoveItem,
5309
+ name,
5310
+ handleDisconnect,
5311
+ relations: data,
5312
+ targetModel
5313
+ },
5314
+ itemKey: (index)=>data[index].id,
5315
+ innerElementType: "ol",
5316
+ children: ListItem
5317
+ })
5318
+ ]
5319
+ });
5320
+ };
5321
+ const ShadowBox = styled(Box)`
5322
+ position: relative;
5323
+ overflow: hidden;
5324
+ flex: 1;
5325
+
5326
+ &:before,
5327
+ &:after {
5328
+ position: absolute;
5329
+ width: 100%;
5330
+ height: 4px;
5331
+ z-index: 1;
5332
+ }
5333
+
5334
+ &:before {
5335
+ /* TODO: as for DS Table component we would need this to be handled by the DS theme */
5336
+ content: '';
5337
+ background: linear-gradient(rgba(3, 3, 5, 0.2) 0%, rgba(0, 0, 0, 0) 100%);
5338
+ top: 0;
5339
+ opacity: ${({ $overflowDirection })=>$overflowDirection === 'top-bottom' || $overflowDirection === 'top' ? 1 : 0};
5340
+ transition: opacity 0.2s ease-in-out;
5341
+ }
5342
+
5343
+ &:after {
5344
+ /* TODO: as for DS Table component we would need this to be handled by the DS theme */
5345
+ content: '';
5346
+ background: linear-gradient(0deg, rgba(3, 3, 5, 0.2) 0%, rgba(0, 0, 0, 0) 100%);
5347
+ bottom: 0;
5348
+ opacity: ${({ $overflowDirection })=>$overflowDirection === 'top-bottom' || $overflowDirection === 'bottom' ? 1 : 0};
5349
+ transition: opacity 0.2s ease-in-out;
5350
+ }
5351
+ `;
5352
+ const ListItem = ({ data, index, style })=>{
5353
+ const { ariaDescribedBy, canDrag = false, disabled = false, handleCancel, handleDisconnect, handleDropItem, handleGrabItem, handleMoveItem, name, relations, targetModel } = data;
5354
+ const { formatMessage } = useIntl();
5355
+ const { href, id, label, status, documentId, apiData, locale } = relations[index];
5356
+ const [{ handlerId, isDragging, handleKeyDown }, relationRef, dropRef, dragRef, dragPreviewRef] = useDragAndDrop(canDrag && !disabled, {
5357
+ type: `${ItemTypes.RELATION}_${name}`,
5358
+ index,
5359
+ item: {
5360
+ displayedValue: label,
5361
+ status,
5362
+ id: id,
5363
+ index
5364
+ },
5365
+ onMoveItem: handleMoveItem,
5366
+ onDropItem: handleDropItem,
5367
+ onGrabItem: handleGrabItem,
5368
+ onCancel: handleCancel,
5369
+ dropSensitivity: DROP_SENSITIVITY.REGULAR
5370
+ });
5371
+ const composedRefs = useComposedRefs(relationRef, dragRef);
5372
+ React.useEffect(()=>{
5373
+ dragPreviewRef(getEmptyImage());
5374
+ }, [
5375
+ dragPreviewRef
5376
+ ]);
5377
+ return /*#__PURE__*/ jsx(Box, {
5378
+ style: style,
5379
+ tag: "li",
5380
+ ref: dropRef,
5381
+ "aria-describedby": ariaDescribedBy,
5382
+ cursor: canDrag ? 'all-scroll' : 'default',
5383
+ children: isDragging ? /*#__PURE__*/ jsx(RelationItemPlaceholder, {}) : /*#__PURE__*/ jsxs(Flex, {
5384
+ paddingTop: 2,
5385
+ paddingBottom: 2,
5386
+ paddingLeft: canDrag ? 2 : 4,
5387
+ paddingRight: 4,
5388
+ hasRadius: true,
5389
+ borderColor: "neutral200",
5390
+ background: disabled ? 'neutral150' : 'neutral0',
5391
+ justifyContent: "space-between",
5392
+ ref: composedRefs,
5393
+ "data-handler-id": handlerId,
5394
+ children: [
5395
+ /*#__PURE__*/ jsxs(FlexWrapper, {
5396
+ gap: 1,
5397
+ children: [
5398
+ canDrag ? /*#__PURE__*/ jsx(IconButton, {
5399
+ tag: "div",
5400
+ role: "button",
5401
+ tabIndex: 0,
5402
+ withTooltip: false,
5403
+ label: formatMessage({
5404
+ id: getTranslation('components.RelationInput.icon-button-aria-label'),
5405
+ defaultMessage: 'Drag'
5406
+ }),
5407
+ variant: "ghost",
5408
+ onKeyDown: handleKeyDown,
5409
+ disabled: disabled,
5410
+ children: /*#__PURE__*/ jsx(Drag, {})
5411
+ }) : null,
5412
+ /*#__PURE__*/ jsxs(Flex, {
5413
+ width: "100%",
5414
+ minWidth: 0,
5415
+ justifyContent: "space-between",
5416
+ children: [
5417
+ /*#__PURE__*/ jsx(Box, {
5418
+ minWidth: 0,
5419
+ paddingTop: 1,
5420
+ paddingBottom: 1,
5421
+ paddingRight: 4,
5422
+ children: /*#__PURE__*/ jsx(RelationModalForm, {
5423
+ triggerButtonLabel: label,
5424
+ relation: {
5425
+ documentId: documentId ?? apiData?.documentId,
5426
+ model: targetModel,
5427
+ collectionType: getCollectionType(href),
5428
+ params: {
5429
+ locale: locale || apiData?.locale || null
5430
+ }
5431
+ }
5432
+ })
5433
+ }),
5434
+ status ? /*#__PURE__*/ jsx(DocumentStatus, {
5435
+ status: status
5436
+ }) : null
5437
+ ]
5438
+ })
5439
+ ]
5440
+ }),
5441
+ /*#__PURE__*/ jsx(Box, {
5442
+ paddingLeft: 4,
5443
+ children: /*#__PURE__*/ jsx(IconButton, {
5444
+ onClick: ()=>handleDisconnect(relations[index]),
5445
+ disabled: disabled,
5446
+ label: formatMessage({
5447
+ id: getTranslation('relation.disconnect'),
5448
+ defaultMessage: 'Remove'
5449
+ }),
5450
+ variant: "ghost",
5451
+ size: "S",
5452
+ children: /*#__PURE__*/ jsx(Cross, {})
5453
+ })
5454
+ })
5455
+ ]
5456
+ })
5457
+ });
5458
+ };
5459
+ const FlexWrapper = styled(Flex)`
5460
+ width: 100%;
5461
+ /* Used to prevent endAction to be pushed out of container */
5462
+ min-width: 0;
5463
+
5464
+ & > div[role='button'] {
5465
+ cursor: all-scroll;
5466
+ }
5467
+ `;
5468
+ const DisconnectButton = styled.button`
5469
+ svg path {
5470
+ fill: ${({ theme, disabled })=>disabled ? theme.colors.neutral600 : theme.colors.neutral500};
5471
+ }
5472
+
5473
+ &:hover svg path,
5474
+ &:focus svg path {
5475
+ fill: ${({ theme, disabled })=>!disabled && theme.colors.neutral600};
5476
+ }
5477
+ `;
5478
+ const LinkEllipsis = styled(Link$2)`
5479
+ display: block;
5480
+
5481
+ & > span {
5482
+ white-space: nowrap;
5483
+ overflow: hidden;
5484
+ text-overflow: ellipsis;
5485
+ display: block;
5486
+ }
5487
+ `;
5488
+ const RelationItemPlaceholder = ()=>/*#__PURE__*/ jsx(Box, {
5489
+ paddingTop: 2,
5490
+ paddingBottom: 2,
5491
+ paddingLeft: 4,
5492
+ paddingRight: 4,
5493
+ hasRadius: true,
5494
+ borderStyle: "dashed",
5495
+ borderColor: "primary600",
5496
+ borderWidth: "1px",
5497
+ background: "primary100",
5498
+ height: `calc(100% - ${RELATION_GUTTER}px)`
5499
+ });
5500
+ const MemoizedRelationsField = /*#__PURE__*/ React.memo(RelationsField);
5501
+
5502
+ const uidApi = contentManagerApi.injectEndpoints({
5503
+ endpoints: (builder)=>({
5504
+ getDefaultUID: builder.query({
5505
+ query: ({ params, ...data })=>{
5506
+ return {
5507
+ url: '/content-manager/uid/generate',
5508
+ method: 'POST',
5509
+ data,
5510
+ config: {
5511
+ params
5512
+ }
5513
+ };
5514
+ },
5515
+ transformResponse: (response)=>response.data
5516
+ }),
5517
+ generateUID: builder.mutation({
5518
+ query: ({ params, ...data })=>({
5519
+ url: '/content-manager/uid/generate',
5520
+ method: 'POST',
5521
+ data,
5522
+ config: {
5523
+ params
5524
+ }
5525
+ }),
5526
+ transformResponse: (response)=>response.data
5527
+ }),
5528
+ getAvailability: builder.query({
5529
+ query: ({ params, ...data })=>({
5530
+ url: '/content-manager/uid/check-availability',
5531
+ method: 'POST',
5532
+ data,
5533
+ config: {
5534
+ params
5535
+ }
5536
+ }),
5537
+ providesTags: (_res, _error, params)=>[
5538
+ {
5539
+ type: 'UidAvailability',
5540
+ id: params.contentTypeUID
5541
+ }
5542
+ ]
5543
+ })
5544
+ })
5545
+ });
5546
+ const { useGenerateUIDMutation, useGetDefaultUIDQuery, useGetAvailabilityQuery } = uidApi;
5547
+
5548
+ /* -------------------------------------------------------------------------------------------------
5549
+ * InputUID
5550
+ * -----------------------------------------------------------------------------------------------*/ const UID_REGEX = /^[A-Za-z0-9-_.~]*$/;
5551
+ const UIDInput = /*#__PURE__*/ React.forwardRef(({ hint, label, labelAction, name, required, ...props }, ref)=>{
5552
+ const { model, id } = useDoc();
5553
+ const allFormValues = useForm('InputUID', (form)=>form.values);
5554
+ const [availability, setAvailability] = React.useState();
5555
+ const [showRegenerate, setShowRegenerate] = React.useState(false);
5556
+ const isCloning = useMatch(CLONE_PATH) !== null;
5557
+ const field = useField(name);
5558
+ const debouncedValue = useDebounce(field.value, 300);
5559
+ const hasChanged = debouncedValue !== field.initialValue;
5560
+ const { toggleNotification } = useNotification();
5561
+ const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
5562
+ const { formatMessage } = useIntl();
5563
+ const [{ query }] = useQueryParams();
5564
+ const params = React.useMemo(()=>buildValidParams(query), [
5565
+ query
5566
+ ]);
5567
+ const { data: defaultGeneratedUID, isLoading: isGeneratingDefaultUID, error: apiError } = useGetDefaultUIDQuery({
5568
+ contentTypeUID: model,
5569
+ field: name,
5570
+ data: {
5571
+ id: id ?? '',
5572
+ ...allFormValues
5573
+ },
5574
+ params
5575
+ }, {
5576
+ skip: field.value || !required
5577
+ });
5578
+ React.useEffect(()=>{
5579
+ if (apiError) {
5580
+ toggleNotification({
5581
+ type: 'warning',
5582
+ message: formatAPIError(apiError)
5583
+ });
5584
+ }
5585
+ }, [
5586
+ apiError,
5587
+ formatAPIError,
5588
+ toggleNotification
5589
+ ]);
5590
+ /**
5591
+ * If the defaultGeneratedUID is available, then we set it as the value,
5592
+ * but we also want to set it as the initialValue too.
5593
+ */ React.useEffect(()=>{
5594
+ if (defaultGeneratedUID && field.value === undefined) {
5595
+ field.onChange(name, defaultGeneratedUID);
5596
+ }
5597
+ }, [
5598
+ defaultGeneratedUID,
5599
+ field,
5600
+ name
5601
+ ]);
5602
+ const [generateUID, { isLoading: isGeneratingUID }] = useGenerateUIDMutation();
5603
+ const handleRegenerateClick = async ()=>{
5604
+ try {
5605
+ const res = await generateUID({
5606
+ contentTypeUID: model,
5607
+ field: name,
5608
+ data: {
5609
+ id: id ?? '',
5610
+ ...allFormValues
5611
+ },
5612
+ params
5613
+ });
5614
+ if ('data' in res) {
5615
+ field.onChange(name, res.data);
5616
+ } else {
5617
+ toggleNotification({
5618
+ type: 'danger',
5619
+ message: formatAPIError(res.error)
5620
+ });
5621
+ }
5622
+ } catch (err) {
5623
+ toggleNotification({
5624
+ type: 'danger',
5625
+ message: formatMessage({
5626
+ id: 'notification.error',
5627
+ defaultMessage: 'An error occurred.'
5628
+ })
5629
+ });
5630
+ }
5631
+ };
5632
+ const { data: availabilityData, isLoading: isCheckingAvailability, error: availabilityError } = useGetAvailabilityQuery({
5633
+ contentTypeUID: model,
5634
+ field: name,
5635
+ value: debouncedValue ? debouncedValue.trim() : '',
5636
+ params
5637
+ }, {
5638
+ // Don't check availability if the value is empty or wasn't changed
5639
+ skip: !Boolean((hasChanged || isCloning) && debouncedValue && UID_REGEX.test(debouncedValue.trim()))
5640
+ });
5641
+ React.useEffect(()=>{
5642
+ if (availabilityError) {
5643
+ toggleNotification({
5644
+ type: 'warning',
5645
+ message: formatAPIError(availabilityError)
5646
+ });
5647
+ }
5648
+ }, [
4175
5649
  availabilityError,
4176
5650
  formatAPIError,
4177
5651
  toggleNotification
@@ -4266,7 +5740,7 @@ const UIDInput = /*#__PURE__*/ React.forwardRef(({ hint, label, labelAction, nam
4266
5740
  onMouseLeave: ()=>setShowRegenerate(false),
4267
5741
  children: isLoading ? /*#__PURE__*/ jsx(LoadingWrapper, {
4268
5742
  "data-testid": "loading-wrapper",
4269
- children: /*#__PURE__*/ jsx(Loader, {})
5743
+ children: /*#__PURE__*/ jsx(Loader$1, {})
4270
5744
  }) : /*#__PURE__*/ jsx(ArrowClockwise, {})
4271
5745
  })
4272
5746
  ]
@@ -5529,14 +7003,14 @@ const quoteAndCodeHandler = (editor, markdownType)=>{
5529
7003
  };
5530
7004
 
5531
7005
  // NAV BUTTONS
5532
- const MainButtons = styled(IconButtonGroup)`
7006
+ styled(IconButtonGroup)`
5533
7007
  margin-left: ${({ theme })=>theme.spaces[4]};
5534
7008
  `;
5535
- const MoreButton = styled(IconButton)`
7009
+ styled(IconButton)`
5536
7010
  margin: ${({ theme })=>`0 ${theme.spaces[2]}`};
5537
7011
  `;
5538
7012
  // NAV
5539
- const IconButtonGroupMargin = styled(IconButtonGroup)`
7013
+ styled(IconButtonGroup)`
5540
7014
  margin-right: ${({ theme })=>`${theme.spaces[2]}`};
5541
7015
  `;
5542
7016
  // FOOTER
@@ -5585,254 +7059,524 @@ const WysiwygFooter = ({ onToggleExpand })=>{
5585
7059
  defaultMessage: 'Expand'
5586
7060
  })
5587
7061
  }),
5588
- /*#__PURE__*/ jsx(Expand, {})
7062
+ /*#__PURE__*/ jsx(Expand, {})
7063
+ ]
7064
+ })
7065
+ })
7066
+ });
7067
+ };
7068
+
7069
+ /**
7070
+ * TODO: refactor this mess.
7071
+ */ const WysiwygNav = ({ disabled, editorRef, isPreviewMode, onToggleMediaLib, onTogglePreviewMode })=>{
7072
+ const { formatMessage } = useIntl();
7073
+ const isDisabled = disabled || isPreviewMode;
7074
+ const handleActionClick = (value, currentEditorRef)=>{
7075
+ switch(value){
7076
+ case 'Link':
7077
+ {
7078
+ markdownHandler(currentEditorRef, value);
7079
+ break;
7080
+ }
7081
+ case 'Code':
7082
+ case 'Quote':
7083
+ {
7084
+ quoteAndCodeHandler(currentEditorRef, value);
7085
+ break;
7086
+ }
7087
+ case 'Bold':
7088
+ case 'Italic':
7089
+ case 'Underline':
7090
+ case 'Strikethrough':
7091
+ {
7092
+ markdownHandler(currentEditorRef, value);
7093
+ break;
7094
+ }
7095
+ case 'BulletList':
7096
+ case 'NumberList':
7097
+ {
7098
+ listHandler(currentEditorRef, value);
7099
+ break;
7100
+ }
7101
+ case 'h1':
7102
+ case 'h2':
7103
+ case 'h3':
7104
+ case 'h4':
7105
+ case 'h5':
7106
+ case 'h6':
7107
+ {
7108
+ titleHandler(currentEditorRef, value);
7109
+ break;
7110
+ }
7111
+ }
7112
+ };
7113
+ const observedComponents = [
7114
+ {
7115
+ toolbar: /*#__PURE__*/ jsxs(IconButtonGroup, {
7116
+ children: [
7117
+ /*#__PURE__*/ jsx(IconButton, {
7118
+ disabled: isDisabled,
7119
+ onClick: ()=>handleActionClick('Bold', editorRef),
7120
+ label: formatMessage({
7121
+ id: 'components.Blocks.modifiers.bold',
7122
+ defaultMessage: 'Bold'
7123
+ }),
7124
+ name: formatMessage({
7125
+ id: 'components.Blocks.modifiers.bold',
7126
+ defaultMessage: 'Bold'
7127
+ }),
7128
+ children: /*#__PURE__*/ jsx(Bold, {})
7129
+ }),
7130
+ /*#__PURE__*/ jsx(IconButton, {
7131
+ disabled: isDisabled,
7132
+ onClick: ()=>handleActionClick('Italic', editorRef),
7133
+ label: formatMessage({
7134
+ id: 'components.Blocks.modifiers.italic',
7135
+ defaultMessage: 'Italic'
7136
+ }),
7137
+ name: formatMessage({
7138
+ id: 'components.Blocks.modifiers.italic',
7139
+ defaultMessage: 'Italic'
7140
+ }),
7141
+ children: /*#__PURE__*/ jsx(Italic, {})
7142
+ }),
7143
+ /*#__PURE__*/ jsx(IconButton, {
7144
+ disabled: isDisabled,
7145
+ onClick: ()=>handleActionClick('Underline', editorRef),
7146
+ label: formatMessage({
7147
+ id: 'components.Blocks.modifiers.underline',
7148
+ defaultMessage: 'Underline'
7149
+ }),
7150
+ name: formatMessage({
7151
+ id: 'components.Blocks.modifiers.underline',
7152
+ defaultMessage: 'Underline'
7153
+ }),
7154
+ children: /*#__PURE__*/ jsx(Underline, {})
7155
+ }),
7156
+ /*#__PURE__*/ jsx(IconButton, {
7157
+ disabled: isDisabled,
7158
+ onClick: ()=>handleActionClick('Strikethrough', editorRef),
7159
+ label: formatMessage({
7160
+ id: 'components.Blocks.modifiers.strikethrough',
7161
+ defaultMessage: 'Strikethrough'
7162
+ }),
7163
+ name: formatMessage({
7164
+ id: 'components.Blocks.modifiers.strikethrough',
7165
+ defaultMessage: 'Strikethrough'
7166
+ }),
7167
+ children: /*#__PURE__*/ jsx(StrikeThrough, {})
7168
+ })
7169
+ ]
7170
+ }),
7171
+ menu: /*#__PURE__*/ jsxs(Fragment, {
7172
+ children: [
7173
+ /*#__PURE__*/ jsx(Menu.Separator, {}),
7174
+ /*#__PURE__*/ jsx(Menu.Item, {
7175
+ onSelect: ()=>handleActionClick('Bold', editorRef),
7176
+ disabled: isDisabled,
7177
+ children: /*#__PURE__*/ jsxs(Flex, {
7178
+ tag: "span",
7179
+ gap: 2,
7180
+ children: [
7181
+ /*#__PURE__*/ jsx(Bold, {
7182
+ "aria-hidden": true,
7183
+ fill: "neutral600"
7184
+ }),
7185
+ formatMessage({
7186
+ id: 'components.Blocks.modifiers.bold',
7187
+ defaultMessage: 'Bold'
7188
+ })
7189
+ ]
7190
+ })
7191
+ }),
7192
+ /*#__PURE__*/ jsx(Menu.Item, {
7193
+ onSelect: ()=>handleActionClick('Italic', editorRef),
7194
+ disabled: isDisabled,
7195
+ children: /*#__PURE__*/ jsxs(Flex, {
7196
+ tag: "span",
7197
+ gap: 2,
7198
+ children: [
7199
+ /*#__PURE__*/ jsx(Italic, {
7200
+ "aria-hidden": true,
7201
+ fill: "neutral600"
7202
+ }),
7203
+ formatMessage({
7204
+ id: 'components.Blocks.modifiers.italic',
7205
+ defaultMessage: 'Italic'
7206
+ })
7207
+ ]
7208
+ })
7209
+ }),
7210
+ /*#__PURE__*/ jsx(Menu.Item, {
7211
+ onSelect: ()=>handleActionClick('Underline', editorRef),
7212
+ disabled: isDisabled,
7213
+ children: /*#__PURE__*/ jsxs(Flex, {
7214
+ tag: "span",
7215
+ gap: 2,
7216
+ children: [
7217
+ /*#__PURE__*/ jsx(Underline, {
7218
+ "aria-hidden": true,
7219
+ fill: "neutral600"
7220
+ }),
7221
+ formatMessage({
7222
+ id: 'components.Blocks.modifiers.underline',
7223
+ defaultMessage: 'Underline'
7224
+ })
7225
+ ]
7226
+ })
7227
+ }),
7228
+ /*#__PURE__*/ jsx(Menu.Item, {
7229
+ onSelect: ()=>handleActionClick('Strikethrough', editorRef),
7230
+ disabled: isDisabled,
7231
+ children: /*#__PURE__*/ jsxs(Flex, {
7232
+ tag: "span",
7233
+ gap: 2,
7234
+ children: [
7235
+ /*#__PURE__*/ jsx(StrikeThrough, {
7236
+ "aria-hidden": true,
7237
+ fill: "neutral600"
7238
+ }),
7239
+ formatMessage({
7240
+ id: 'components.Blocks.modifiers.strikethrough',
7241
+ defaultMessage: 'Strikethrough'
7242
+ })
7243
+ ]
7244
+ })
7245
+ })
5589
7246
  ]
5590
- })
5591
- })
5592
- });
5593
- };
5594
-
5595
- /**
5596
- * TODO: refactor this mess.
5597
- */ const WysiwygNav = ({ disabled, editorRef, isExpandMode, isPreviewMode, onActionClick, onToggleMediaLib, onTogglePreviewMode })=>{
5598
- const [visiblePopover, setVisiblePopover] = React.useState(false);
5599
- const { formatMessage } = useIntl();
5600
- const selectPlaceholder = formatMessage({
5601
- id: 'components.Wysiwyg.selectOptions.title',
5602
- defaultMessage: 'Add a title'
5603
- });
5604
- React.useRef(null);
5605
- const handleTogglePopover = ()=>{
5606
- setVisiblePopover((prev)=>!prev);
5607
- };
5608
- if (disabled || isPreviewMode) {
5609
- return /*#__PURE__*/ jsxs(Flex, {
5610
- padding: 2,
5611
- background: "neutral100",
5612
- justifyContent: "space-between",
5613
- borderRadius: `0.4rem 0.4rem 0 0`,
5614
- children: [
5615
- /*#__PURE__*/ jsxs(Flex, {
5616
- children: [
5617
- /*#__PURE__*/ jsx(Field.Root, {
5618
- children: /*#__PURE__*/ jsxs(SingleSelect, {
5619
- disabled: true,
5620
- placeholder: selectPlaceholder,
5621
- "aria-label": selectPlaceholder,
5622
- size: "S",
5623
- children: [
5624
- /*#__PURE__*/ jsx(SingleSelectOption, {
5625
- value: "h1",
5626
- children: "h1"
5627
- }),
5628
- /*#__PURE__*/ jsx(SingleSelectOption, {
5629
- value: "h2",
5630
- children: "h2"
5631
- }),
5632
- /*#__PURE__*/ jsx(SingleSelectOption, {
5633
- value: "h3",
5634
- children: "h3"
5635
- }),
5636
- /*#__PURE__*/ jsx(SingleSelectOption, {
5637
- value: "h4",
5638
- children: "h4"
5639
- }),
5640
- /*#__PURE__*/ jsx(SingleSelectOption, {
5641
- value: "h5",
5642
- children: "h5"
5643
- }),
5644
- /*#__PURE__*/ jsx(SingleSelectOption, {
5645
- value: "h6",
5646
- children: "h6"
5647
- })
5648
- ]
5649
- })
7247
+ }),
7248
+ key: 'formatting-group-1'
7249
+ },
7250
+ {
7251
+ toolbar: /*#__PURE__*/ jsxs(IconButtonGroup, {
7252
+ children: [
7253
+ /*#__PURE__*/ jsx(IconButton, {
7254
+ disabled: isDisabled,
7255
+ onClick: ()=>handleActionClick('BulletList', editorRef),
7256
+ label: formatMessage({
7257
+ id: 'components.Blocks.blocks.bulletList',
7258
+ defaultMessage: 'Bulleted list'
7259
+ }),
7260
+ name: formatMessage({
7261
+ id: 'components.Blocks.blocks.bulletList',
7262
+ defaultMessage: 'Bulleted list'
7263
+ }),
7264
+ children: /*#__PURE__*/ jsx(BulletList, {})
7265
+ }),
7266
+ /*#__PURE__*/ jsx(IconButton, {
7267
+ disabled: isDisabled,
7268
+ onClick: ()=>handleActionClick('NumberList', editorRef),
7269
+ label: formatMessage({
7270
+ id: 'components.Blocks.blocks.numberList',
7271
+ defaultMessage: 'Numbered list'
5650
7272
  }),
5651
- /*#__PURE__*/ jsxs(MainButtons, {
7273
+ name: formatMessage({
7274
+ id: 'components.Blocks.blocks.numberList',
7275
+ defaultMessage: 'Numbered list'
7276
+ }),
7277
+ children: /*#__PURE__*/ jsx(NumberList, {})
7278
+ })
7279
+ ]
7280
+ }),
7281
+ menu: /*#__PURE__*/ jsxs(Fragment, {
7282
+ children: [
7283
+ /*#__PURE__*/ jsx(Menu.Separator, {}),
7284
+ /*#__PURE__*/ jsx(Menu.Item, {
7285
+ onSelect: ()=>handleActionClick('BulletList', editorRef),
7286
+ disabled: isDisabled,
7287
+ children: /*#__PURE__*/ jsxs(Flex, {
7288
+ tag: "span",
7289
+ gap: 2,
5652
7290
  children: [
5653
- /*#__PURE__*/ jsx(IconButton, {
5654
- disabled: true,
5655
- label: "Bold",
5656
- name: "Bold",
5657
- children: /*#__PURE__*/ jsx(Bold, {})
7291
+ /*#__PURE__*/ jsx(BulletList, {
7292
+ "aria-hidden": true,
7293
+ fill: "neutral600"
5658
7294
  }),
5659
- /*#__PURE__*/ jsx(IconButton, {
5660
- disabled: true,
5661
- label: "Italic",
5662
- name: "Italic",
5663
- children: /*#__PURE__*/ jsx(Italic, {})
7295
+ formatMessage({
7296
+ id: 'components.Blocks.blocks.unorderedList',
7297
+ defaultMessage: 'Bulleted list'
7298
+ })
7299
+ ]
7300
+ })
7301
+ }),
7302
+ /*#__PURE__*/ jsx(Menu.Item, {
7303
+ onSelect: ()=>handleActionClick('NumberList', editorRef),
7304
+ disabled: isDisabled,
7305
+ children: /*#__PURE__*/ jsxs(Flex, {
7306
+ tag: "span",
7307
+ gap: 2,
7308
+ children: [
7309
+ /*#__PURE__*/ jsx(NumberList, {
7310
+ "aria-hidden": true,
7311
+ fill: "neutral600"
5664
7312
  }),
5665
- /*#__PURE__*/ jsx(IconButton, {
5666
- disabled: true,
5667
- label: "Underline",
5668
- name: "Underline",
5669
- children: /*#__PURE__*/ jsx(Underline, {})
7313
+ formatMessage({
7314
+ id: 'components.Blocks.blocks.orderedList',
7315
+ defaultMessage: 'Numbered list'
5670
7316
  })
5671
7317
  ]
5672
- }),
5673
- /*#__PURE__*/ jsx(MoreButton, {
5674
- disabled: true,
5675
- label: "More",
5676
- children: /*#__PURE__*/ jsx(More, {})
5677
7318
  })
5678
- ]
5679
- }),
5680
- !isExpandMode && /*#__PURE__*/ jsx(Button, {
5681
- onClick: onTogglePreviewMode,
5682
- variant: "tertiary",
5683
- children: formatMessage({
5684
- id: 'components.Wysiwyg.ToggleMode.markdown-mode',
5685
- defaultMessage: 'Markdown mode'
5686
7319
  })
5687
- })
5688
- ]
5689
- });
5690
- }
5691
- return /*#__PURE__*/ jsxs(Flex, {
5692
- padding: 2,
5693
- background: "neutral100",
5694
- justifyContent: "space-between",
5695
- borderRadius: `0.4rem 0.4rem 0 0`,
5696
- children: [
5697
- /*#__PURE__*/ jsxs(Flex, {
7320
+ ]
7321
+ }),
7322
+ key: 'formatting-group-2'
7323
+ },
7324
+ {
7325
+ toolbar: /*#__PURE__*/ jsxs(IconButtonGroup, {
7326
+ children: [
7327
+ /*#__PURE__*/ jsx(IconButton, {
7328
+ disabled: isDisabled,
7329
+ onClick: ()=>handleActionClick('Code', editorRef),
7330
+ label: formatMessage({
7331
+ id: 'components.Wysiwyg.blocks.code',
7332
+ defaultMessage: 'Code'
7333
+ }),
7334
+ name: formatMessage({
7335
+ id: 'components.Wysiwyg.blocks.code',
7336
+ defaultMessage: 'Code'
7337
+ }),
7338
+ children: /*#__PURE__*/ jsx(Code, {})
7339
+ }),
7340
+ /*#__PURE__*/ jsx(IconButton, {
7341
+ disabled: isDisabled,
7342
+ onClick: ()=>{
7343
+ onToggleMediaLib();
7344
+ },
7345
+ label: formatMessage({
7346
+ id: 'components.Blocks.blocks.image',
7347
+ defaultMessage: 'Image'
7348
+ }),
7349
+ name: formatMessage({
7350
+ id: 'components.Blocks.blocks.image',
7351
+ defaultMessage: 'Image'
7352
+ }),
7353
+ children: /*#__PURE__*/ jsx(Image$1, {})
7354
+ }),
7355
+ /*#__PURE__*/ jsx(IconButton, {
7356
+ disabled: isDisabled,
7357
+ onClick: ()=>handleActionClick('Link', editorRef),
7358
+ label: formatMessage({
7359
+ id: 'components.Blocks.popover.link',
7360
+ defaultMessage: 'Link'
7361
+ }),
7362
+ name: formatMessage({
7363
+ id: 'components.Blocks.popover.link',
7364
+ defaultMessage: 'Link'
7365
+ }),
7366
+ children: /*#__PURE__*/ jsx(Link$1, {})
7367
+ }),
7368
+ /*#__PURE__*/ jsx(IconButton, {
7369
+ disabled: isDisabled,
7370
+ onClick: ()=>handleActionClick('Quote', editorRef),
7371
+ label: formatMessage({
7372
+ id: 'components.Blocks.blocks.quote',
7373
+ defaultMessage: 'Quote'
7374
+ }),
7375
+ name: formatMessage({
7376
+ id: 'components.Blocks.blocks.quote',
7377
+ defaultMessage: 'Quote'
7378
+ }),
7379
+ children: /*#__PURE__*/ jsx(Quotes, {})
7380
+ })
7381
+ ]
7382
+ }),
7383
+ menu: /*#__PURE__*/ jsxs(Fragment, {
5698
7384
  children: [
5699
- /*#__PURE__*/ jsx(Field.Root, {
5700
- children: /*#__PURE__*/ jsxs(SingleSelect, {
5701
- placeholder: selectPlaceholder,
5702
- "aria-label": selectPlaceholder,
5703
- // @ts-expect-error DS v2 will only allow strings.
5704
- onChange: (value)=>onActionClick(value, editorRef),
5705
- size: "S",
7385
+ /*#__PURE__*/ jsx(Menu.Separator, {}),
7386
+ /*#__PURE__*/ jsx(Menu.Item, {
7387
+ onSelect: ()=>handleActionClick('Code', editorRef),
7388
+ disabled: isDisabled,
7389
+ children: /*#__PURE__*/ jsxs(Flex, {
7390
+ tag: "span",
7391
+ gap: 2,
5706
7392
  children: [
5707
- /*#__PURE__*/ jsx(SingleSelectOption, {
5708
- value: "h1",
5709
- children: "h1"
5710
- }),
5711
- /*#__PURE__*/ jsx(SingleSelectOption, {
5712
- value: "h2",
5713
- children: "h2"
7393
+ /*#__PURE__*/ jsx(Code, {
7394
+ "aria-hidden": true,
7395
+ fill: "neutral600"
5714
7396
  }),
5715
- /*#__PURE__*/ jsx(SingleSelectOption, {
5716
- value: "h3",
5717
- children: "h3"
7397
+ formatMessage({
7398
+ id: 'components.Wysiwyg.blocks.code',
7399
+ defaultMessage: 'Code'
7400
+ })
7401
+ ]
7402
+ })
7403
+ }),
7404
+ /*#__PURE__*/ jsx(Menu.Item, {
7405
+ startIcon: /*#__PURE__*/ jsx(Image$1, {}),
7406
+ onSelect: ()=>{
7407
+ onToggleMediaLib();
7408
+ },
7409
+ disabled: isDisabled,
7410
+ children: /*#__PURE__*/ jsxs(Flex, {
7411
+ tag: "span",
7412
+ gap: 2,
7413
+ children: [
7414
+ /*#__PURE__*/ jsx(Image$1, {
7415
+ "aria-hidden": true,
7416
+ fill: "neutral600"
5718
7417
  }),
5719
- /*#__PURE__*/ jsx(SingleSelectOption, {
5720
- value: "h4",
5721
- children: "h4"
7418
+ formatMessage({
7419
+ id: 'components.Blocks.blocks.image',
7420
+ defaultMessage: 'Image'
7421
+ })
7422
+ ]
7423
+ })
7424
+ }),
7425
+ /*#__PURE__*/ jsx(Menu.Item, {
7426
+ startIcon: /*#__PURE__*/ jsx(Link$1, {}),
7427
+ onSelect: ()=>handleActionClick('Link', editorRef),
7428
+ disabled: isDisabled,
7429
+ children: /*#__PURE__*/ jsxs(Flex, {
7430
+ tag: "span",
7431
+ gap: 2,
7432
+ children: [
7433
+ /*#__PURE__*/ jsx(Link$1, {
7434
+ "aria-hidden": true,
7435
+ fill: "neutral600"
5722
7436
  }),
5723
- /*#__PURE__*/ jsx(SingleSelectOption, {
5724
- value: "h5",
5725
- children: "h5"
7437
+ formatMessage({
7438
+ id: 'components.Blocks.popover.link',
7439
+ defaultMessage: 'Link'
7440
+ })
7441
+ ]
7442
+ })
7443
+ }),
7444
+ /*#__PURE__*/ jsx(Menu.Item, {
7445
+ onSelect: ()=>handleActionClick('Quote', editorRef),
7446
+ disabled: isDisabled,
7447
+ children: /*#__PURE__*/ jsxs(Flex, {
7448
+ tag: "span",
7449
+ gap: 2,
7450
+ children: [
7451
+ /*#__PURE__*/ jsx(Quotes, {
7452
+ "aria-hidden": true,
7453
+ fill: "neutral600"
5726
7454
  }),
5727
- /*#__PURE__*/ jsx(SingleSelectOption, {
5728
- value: "h6",
5729
- children: "h6"
7455
+ formatMessage({
7456
+ id: 'components.Blocks.blocks.quote',
7457
+ defaultMessage: 'Quote'
5730
7458
  })
5731
7459
  ]
5732
7460
  })
7461
+ })
7462
+ ]
7463
+ }),
7464
+ key: 'formatting-group-3'
7465
+ }
7466
+ ];
7467
+ return /*#__PURE__*/ jsxs(Flex, {
7468
+ padding: 2,
7469
+ background: "neutral100",
7470
+ justifyContent: "space-between",
7471
+ borderRadius: "0.4rem 0.4rem 0 0",
7472
+ width: "100%",
7473
+ gap: 4,
7474
+ children: [
7475
+ /*#__PURE__*/ jsx(Field.Root, {
7476
+ children: /*#__PURE__*/ jsxs(SingleSelect, {
7477
+ disabled: isDisabled,
7478
+ placeholder: formatMessage({
7479
+ id: 'components.Wysiwyg.selectOptions.title',
7480
+ defaultMessage: 'Headings'
5733
7481
  }),
5734
- /*#__PURE__*/ jsxs(MainButtons, {
5735
- children: [
5736
- /*#__PURE__*/ jsx(IconButton, {
5737
- onClick: ()=>onActionClick('Bold', editorRef),
5738
- label: "Bold",
5739
- name: "Bold",
5740
- children: /*#__PURE__*/ jsx(Bold, {})
7482
+ "aria-label": formatMessage({
7483
+ id: 'components.Wysiwyg.selectOptions.title',
7484
+ defaultMessage: 'Headings'
7485
+ }),
7486
+ // @ts-expect-error – DS v2 will only allow strings.
7487
+ onChange: (value)=>handleActionClick(value, editorRef),
7488
+ size: "S",
7489
+ children: [
7490
+ /*#__PURE__*/ jsx(SingleSelectOption, {
7491
+ value: "h1",
7492
+ startIcon: /*#__PURE__*/ jsx(HeadingOne, {
7493
+ fill: "neutral600"
5741
7494
  }),
5742
- /*#__PURE__*/ jsx(IconButton, {
5743
- onClick: ()=>onActionClick('Italic', editorRef),
5744
- label: "Italic",
5745
- name: "Italic",
5746
- children: /*#__PURE__*/ jsx(Italic, {})
7495
+ children: formatMessage({
7496
+ id: 'components.Wysiwyg.selectOptions.H1',
7497
+ defaultMessage: 'Heading 1'
7498
+ })
7499
+ }),
7500
+ /*#__PURE__*/ jsx(SingleSelectOption, {
7501
+ value: "h2",
7502
+ startIcon: /*#__PURE__*/ jsx(HeadingTwo, {
7503
+ fill: "neutral600"
5747
7504
  }),
5748
- /*#__PURE__*/ jsx(IconButton, {
5749
- onClick: ()=>onActionClick('Underline', editorRef),
5750
- label: "Underline",
5751
- name: "Underline",
5752
- children: /*#__PURE__*/ jsx(Underline, {})
7505
+ children: formatMessage({
7506
+ id: 'components.Wysiwyg.selectOptions.H2',
7507
+ defaultMessage: 'Heading 2'
5753
7508
  })
5754
- ]
5755
- }),
5756
- /*#__PURE__*/ jsxs(Popover.Root, {
5757
- children: [
5758
- /*#__PURE__*/ jsx(Popover.Trigger, {
5759
- children: /*#__PURE__*/ jsx(MoreButton, {
5760
- label: "More",
5761
- children: /*#__PURE__*/ jsx(More, {})
5762
- })
7509
+ }),
7510
+ /*#__PURE__*/ jsx(SingleSelectOption, {
7511
+ value: "h3",
7512
+ startIcon: /*#__PURE__*/ jsx(HeadingThree, {
7513
+ fill: "neutral600"
5763
7514
  }),
5764
- /*#__PURE__*/ jsx(Popover.Content, {
5765
- sideOffset: 12,
5766
- children: /*#__PURE__*/ jsxs(Flex, {
5767
- padding: 2,
5768
- children: [
5769
- /*#__PURE__*/ jsxs(IconButtonGroupMargin, {
5770
- children: [
5771
- /*#__PURE__*/ jsx(IconButton, {
5772
- onClick: ()=>onActionClick('Strikethrough', editorRef, handleTogglePopover),
5773
- label: "Strikethrough",
5774
- name: "Strikethrough",
5775
- children: /*#__PURE__*/ jsx(StrikeThrough, {})
5776
- }),
5777
- /*#__PURE__*/ jsx(IconButton, {
5778
- onClick: ()=>onActionClick('BulletList', editorRef, handleTogglePopover),
5779
- label: "BulletList",
5780
- name: "BulletList",
5781
- children: /*#__PURE__*/ jsx(BulletList, {})
5782
- }),
5783
- /*#__PURE__*/ jsx(IconButton, {
5784
- onClick: ()=>onActionClick('NumberList', editorRef, handleTogglePopover),
5785
- label: "NumberList",
5786
- name: "NumberList",
5787
- children: /*#__PURE__*/ jsx(NumberList, {})
5788
- })
5789
- ]
5790
- }),
5791
- /*#__PURE__*/ jsxs(IconButtonGroup, {
5792
- children: [
5793
- /*#__PURE__*/ jsx(IconButton, {
5794
- onClick: ()=>onActionClick('Code', editorRef, handleTogglePopover),
5795
- label: "Code",
5796
- name: "Code",
5797
- children: /*#__PURE__*/ jsx(Code, {})
5798
- }),
5799
- /*#__PURE__*/ jsx(IconButton, {
5800
- onClick: ()=>{
5801
- handleTogglePopover();
5802
- onToggleMediaLib();
5803
- },
5804
- label: "Image",
5805
- name: "Image",
5806
- children: /*#__PURE__*/ jsx(Image$1, {})
5807
- }),
5808
- /*#__PURE__*/ jsx(IconButton, {
5809
- onClick: ()=>onActionClick('Link', editorRef, handleTogglePopover),
5810
- label: "Link",
5811
- name: "Link",
5812
- children: /*#__PURE__*/ jsx(Link$1, {})
5813
- }),
5814
- /*#__PURE__*/ jsx(IconButton, {
5815
- onClick: ()=>onActionClick('Quote', editorRef, handleTogglePopover),
5816
- label: "Quote",
5817
- name: "Quote",
5818
- children: /*#__PURE__*/ jsx(Quotes, {})
5819
- })
5820
- ]
5821
- })
5822
- ]
5823
- })
7515
+ children: formatMessage({
7516
+ id: 'components.Wysiwyg.selectOptions.H3',
7517
+ defaultMessage: 'Heading 3'
5824
7518
  })
5825
- ]
7519
+ }),
7520
+ /*#__PURE__*/ jsx(SingleSelectOption, {
7521
+ value: "h4",
7522
+ startIcon: /*#__PURE__*/ jsx(HeadingFour, {
7523
+ fill: "neutral600"
7524
+ }),
7525
+ children: formatMessage({
7526
+ id: 'components.Wysiwyg.selectOptions.H4',
7527
+ defaultMessage: 'Heading 4'
7528
+ })
7529
+ }),
7530
+ /*#__PURE__*/ jsx(SingleSelectOption, {
7531
+ value: "h5",
7532
+ startIcon: /*#__PURE__*/ jsx(HeadingFive, {
7533
+ fill: "neutral600"
7534
+ }),
7535
+ children: formatMessage({
7536
+ id: 'components.Wysiwyg.selectOptions.H5',
7537
+ defaultMessage: 'Heading 5'
7538
+ })
7539
+ }),
7540
+ /*#__PURE__*/ jsx(SingleSelectOption, {
7541
+ value: "h6",
7542
+ startIcon: /*#__PURE__*/ jsx(HeadingSix, {
7543
+ fill: "neutral600"
7544
+ }),
7545
+ children: formatMessage({
7546
+ id: 'components.Wysiwyg.selectOptions.H6',
7547
+ defaultMessage: 'Heading 6'
7548
+ })
7549
+ })
7550
+ ]
7551
+ })
7552
+ }),
7553
+ /*#__PURE__*/ jsxs(Flex, {
7554
+ width: "100%",
7555
+ justifyContent: "space-between",
7556
+ overflow: "hidden",
7557
+ children: [
7558
+ /*#__PURE__*/ jsx(Flex, {
7559
+ gap: 2,
7560
+ overflow: "hidden",
7561
+ width: "100%",
7562
+ children: /*#__PURE__*/ jsx(EditorToolbarObserver, {
7563
+ menuTriggerVariant: "tertiary",
7564
+ observedComponents: observedComponents
7565
+ })
7566
+ }),
7567
+ onTogglePreviewMode && /*#__PURE__*/ jsx(Button, {
7568
+ onClick: onTogglePreviewMode,
7569
+ variant: "tertiary",
7570
+ minWidth: "132px",
7571
+ children: isPreviewMode ? formatMessage({
7572
+ id: 'components.Wysiwyg.ToggleMode.markdown-mode',
7573
+ defaultMessage: 'Markdown mode'
7574
+ }) : formatMessage({
7575
+ id: 'components.Wysiwyg.ToggleMode.preview-mode',
7576
+ defaultMessage: 'Preview mode'
7577
+ })
5826
7578
  })
5827
7579
  ]
5828
- }),
5829
- onTogglePreviewMode && /*#__PURE__*/ jsx(Button, {
5830
- onClick: onTogglePreviewMode,
5831
- variant: "tertiary",
5832
- children: formatMessage({
5833
- id: 'components.Wysiwyg.ToggleMode.preview-mode',
5834
- defaultMessage: 'Preview mode'
5835
- })
5836
7580
  })
5837
7581
  ]
5838
7582
  });
@@ -5853,48 +7597,6 @@ const Wysiwyg = /*#__PURE__*/ React.forwardRef(({ hint, disabled, label, name, p
5853
7597
  setIsPreviewMode(false);
5854
7598
  setIsExpandMode((prev)=>!prev);
5855
7599
  };
5856
- const handleActionClick = (value, currentEditorRef, togglePopover)=>{
5857
- switch(value){
5858
- case 'Link':
5859
- case 'Strikethrough':
5860
- {
5861
- markdownHandler(currentEditorRef, value);
5862
- togglePopover?.();
5863
- break;
5864
- }
5865
- case 'Code':
5866
- case 'Quote':
5867
- {
5868
- quoteAndCodeHandler(currentEditorRef, value);
5869
- togglePopover?.();
5870
- break;
5871
- }
5872
- case 'Bold':
5873
- case 'Italic':
5874
- case 'Underline':
5875
- {
5876
- markdownHandler(currentEditorRef, value);
5877
- break;
5878
- }
5879
- case 'BulletList':
5880
- case 'NumberList':
5881
- {
5882
- listHandler(currentEditorRef, value);
5883
- togglePopover?.();
5884
- break;
5885
- }
5886
- case 'h1':
5887
- case 'h2':
5888
- case 'h3':
5889
- case 'h4':
5890
- case 'h5':
5891
- case 'h6':
5892
- {
5893
- titleHandler(currentEditorRef, value);
5894
- break;
5895
- }
5896
- }
5897
- };
5898
7600
  const handleSelectAssets = (files)=>{
5899
7601
  const formattedFiles = files.map((f)=>({
5900
7602
  alt: f.alternativeText || f.name,
@@ -5929,7 +7631,6 @@ const Wysiwyg = /*#__PURE__*/ React.forwardRef(({ hint, disabled, label, name, p
5929
7631
  isExpandMode: isExpandMode,
5930
7632
  editorRef: editorRef,
5931
7633
  isPreviewMode: isPreviewMode,
5932
- onActionClick: handleActionClick,
5933
7634
  onToggleMediaLib: handleToggleMediaLib,
5934
7635
  onTogglePreviewMode: isExpandMode ? undefined : handleTogglePreviewMode,
5935
7636
  disabled: disabled
@@ -5973,17 +7674,25 @@ const MemoizedWysiwyg = /*#__PURE__*/ React.memo(Wysiwyg);
5973
7674
  * specifically to be used in the EditView of the content-manager this understands
5974
7675
  * the complete EditFieldLayout and will handle RBAC conditions and rendering CM specific
5975
7676
  * components such as Blocks / Relations.
5976
- */ const InputRenderer = ({ visible, hint: providedHint, ...props })=>{
5977
- const { id, document, collectionType } = useDoc();
5978
- const isFormDisabled = useForm('InputRenderer', (state)=>state.disabled);
7677
+ */ const InputRenderer = ({ visible, hint: providedHint, document, ...props })=>{
7678
+ const { model: rootModel } = useDoc();
7679
+ const rootDocumentMeta = useDocumentContext('DynamicComponent', (state)=>state.rootDocumentMeta);
7680
+ const { edit: { components: rootComponents } } = useDocumentLayout(rootDocumentMeta.model);
7681
+ const { edit: { components: relatedComponents } } = useDocumentLayout(document.schema?.uid ?? rootModel);
7682
+ const components = {
7683
+ ...rootComponents,
7684
+ ...relatedComponents
7685
+ };
7686
+ const collectionType = document.schema?.kind === 'collectionType' ? 'collection-types' : 'single-types';
5979
7687
  const isInDynamicZone = useDynamicZone('isInDynamicZone', (state)=>state.isInDynamicZone);
7688
+ const isFormDisabled = useForm('InputRenderer', (state)=>state.disabled);
5980
7689
  const canCreateFields = useDocumentRBAC('InputRenderer', (rbac)=>rbac.canCreateFields);
5981
7690
  const canReadFields = useDocumentRBAC('InputRenderer', (rbac)=>rbac.canReadFields);
5982
7691
  const canUpdateFields = useDocumentRBAC('InputRenderer', (rbac)=>rbac.canUpdateFields);
5983
7692
  const canUserAction = useDocumentRBAC('InputRenderer', (rbac)=>rbac.canUserAction);
5984
- let idToCheck = id;
7693
+ let idToCheck = document.document?.documentId;
5985
7694
  if (collectionType === SINGLE_TYPES) {
5986
- idToCheck = document?.documentId;
7695
+ idToCheck = document?.document?.documentId;
5987
7696
  }
5988
7697
  const editableFields = idToCheck ? canUpdateFields : canCreateFields;
5989
7698
  const readableFields = idToCheck ? canReadFields : canCreateFields;
@@ -5997,7 +7706,6 @@ const MemoizedWysiwyg = /*#__PURE__*/ React.memo(Wysiwyg);
5997
7706
  props.attribute.customField
5998
7707
  ] : undefined);
5999
7708
  const hint = useFieldHint(providedHint, props.attribute);
6000
- const { edit: { components } } = useDocLayout();
6001
7709
  // We pass field in case of Custom Fields to keep backward compatibility
6002
7710
  const field = useField(props.name);
6003
7711
  if (!visible) {
@@ -6171,7 +7879,7 @@ const getMinMax = (attribute)=>{
6171
7879
  };
6172
7880
  }
6173
7881
  };
6174
- const MemoizedInputRenderer = /*#__PURE__*/ memo(InputRenderer);
7882
+ const MemoizedInputRenderer = /*#__PURE__*/ React.memo(InputRenderer);
6175
7883
 
6176
7884
  const RESPONSIVE_CONTAINER_BREAKPOINTS = {
6177
7885
  sm: '27.5rem'
@@ -6179,16 +7887,22 @@ const RESPONSIVE_CONTAINER_BREAKPOINTS = {
6179
7887
  const ResponsiveGridRoot = styled(Grid$1.Root)`
6180
7888
  container-type: inline-size;
6181
7889
  `;
6182
- const ResponsiveGridItem = styled(Grid$1.Item)`
6183
- grid-column: span 12;
6184
-
6185
- @container (min-width: ${RESPONSIVE_CONTAINER_BREAKPOINTS.sm}) {
6186
- ${({ col })=>col && `grid-column: span ${col};`}
6187
- }
6188
- `;
6189
- const FormLayout = ({ layout })=>{
7890
+ const ResponsiveGridItem = /**
7891
+ * TODO:
7892
+ * JSDOM cannot handle container queries.
7893
+ * This is a temporary workaround so that tests do not fail in the CI when jestdom throws an error
7894
+ * for failing to parse the stylesheet.
7895
+ */ process.env.NODE_ENV !== 'test' ? styled(Grid$1.Item)`
7896
+ grid-column: span 12;
7897
+ @container (min-width: ${RESPONSIVE_CONTAINER_BREAKPOINTS.sm}) {
7898
+ ${({ col })=>col && `grid-column: span ${col};`}
7899
+ }
7900
+ ` : styled(Grid$1.Item)`
7901
+ grid-column: span 12;
7902
+ `;
7903
+ const FormLayout = ({ layout, document, hasBackground = true })=>{
6190
7904
  const { formatMessage } = useIntl();
6191
- const { model } = useDoc();
7905
+ const model = document.schema?.modelName;
6192
7906
  return /*#__PURE__*/ jsx(Flex, {
6193
7907
  direction: "column",
6194
7908
  alignItems: "stretch",
@@ -6213,20 +7927,20 @@ const FormLayout = ({ layout })=>{
6213
7927
  direction: "column",
6214
7928
  alignItems: "stretch",
6215
7929
  children: /*#__PURE__*/ jsx(MemoizedInputRenderer, {
6216
- ...fieldWithTranslatedLabel
7930
+ ...fieldWithTranslatedLabel,
7931
+ document: document
6217
7932
  })
6218
7933
  })
6219
7934
  }, field.name);
6220
7935
  }
6221
7936
  return /*#__PURE__*/ jsx(Box, {
6222
- hasRadius: true,
6223
- background: "neutral0",
6224
- shadow: "tableShadow",
6225
- paddingLeft: 6,
6226
- paddingRight: 6,
6227
- paddingTop: 6,
6228
- paddingBottom: 6,
6229
- borderColor: "neutral150",
7937
+ ...hasBackground && {
7938
+ padding: 6,
7939
+ borderColor: 'neutral150',
7940
+ background: 'neutral0',
7941
+ hasRadius: true,
7942
+ shadow: 'tableShadow'
7943
+ },
6230
7944
  children: /*#__PURE__*/ jsx(Flex, {
6231
7945
  direction: "column",
6232
7946
  alignItems: "stretch",
@@ -6248,7 +7962,8 @@ const FormLayout = ({ layout })=>{
6248
7962
  direction: "column",
6249
7963
  alignItems: "stretch",
6250
7964
  children: /*#__PURE__*/ jsx(MemoizedInputRenderer, {
6251
- ...fieldWithTranslatedLabel
7965
+ ...fieldWithTranslatedLabel,
7966
+ document: document
6252
7967
  })
6253
7968
  }, field.name);
6254
7969
  })
@@ -6264,6 +7979,7 @@ const NonRepeatableComponent = ({ attribute, name, children, layout })=>{
6264
7979
  const { value } = useField(name);
6265
7980
  const level = useComponent('NonRepeatableComponent', (state)=>state.level);
6266
7981
  const isNested = level > 0;
7982
+ const currentDocument = useDocumentContext('NonRepeatableComponent', (state)=>state.document);
6267
7983
  return /*#__PURE__*/ jsx(ComponentProvider, {
6268
7984
  id: value?.id,
6269
7985
  uid: attribute.component,
@@ -6304,7 +8020,8 @@ const NonRepeatableComponent = ({ attribute, name, children, layout })=>{
6304
8020
  children: children({
6305
8021
  ...field,
6306
8022
  label: translatedLabel,
6307
- name: completeFieldName
8023
+ name: completeFieldName,
8024
+ document: currentDocument
6308
8025
  })
6309
8026
  }, completeFieldName);
6310
8027
  })
@@ -6322,7 +8039,8 @@ const RepeatableComponent = ({ attribute, disabled, name, mainField, children, l
6322
8039
  const search = React.useMemo(()=>new URLSearchParams(searchString), [
6323
8040
  searchString
6324
8041
  ]);
6325
- const { components } = useDoc();
8042
+ const currentDocument = useDocumentContext('RepeatableComponent', (state)=>state.document);
8043
+ const components = currentDocument.components;
6326
8044
  const { value = [], error, rawError } = useField(name);
6327
8045
  const addFieldRow = useForm('RepeatableComponent', (state)=>state.addFieldRow);
6328
8046
  const moveFieldRow = useForm('RepeatableComponent', (state)=>state.moveFieldRow);
@@ -6525,7 +8243,8 @@ const RepeatableComponent = ({ attribute, disabled, name, mainField, children, l
6525
8243
  children: children({
6526
8244
  ...field,
6527
8245
  label: translatedLabel,
6528
- name: completeFieldName
8246
+ name: completeFieldName,
8247
+ document: currentDocument
6529
8248
  })
6530
8249
  }, completeFieldName);
6531
8250
  })
@@ -6687,7 +8406,7 @@ const ComponentInput = ({ label, required, name, attribute, disabled, labelActio
6687
8406
  const { formatMessage } = useIntl();
6688
8407
  const field = useField(name);
6689
8408
  const showResetComponent = !attribute.repeatable && field.value && !disabled;
6690
- const { components } = useDoc();
8409
+ const components = useDocumentContext('ComponentInput', (state)=>state.document.components);
6691
8410
  const handleInitialisationClick = ()=>{
6692
8411
  const schema = components[attribute.component];
6693
8412
  const form = createDefaultForm(schema, components);
@@ -6752,5 +8471,5 @@ const ComponentInput = ({ label, required, name, attribute, disabled, labelActio
6752
8471
  };
6753
8472
  const MemoizedComponentInput = /*#__PURE__*/ React.memo(ComponentInput);
6754
8473
 
6755
- 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 };
6756
- //# sourceMappingURL=Input-Csrk7S5E.js.map
8474
+ 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 };
8475
+ //# sourceMappingURL=Input-hScqTWvW.mjs.map