@strapi/admin 4.14.0-beta.0 → 4.15.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (256) hide show
  1. package/admin/src/components/RBACProvider/index.js +1 -1
  2. package/admin/src/content-manager/components/BlocksEditor/BlocksInput/index.js +87 -0
  3. package/admin/src/content-manager/components/BlocksEditor/Toolbar/index.js +463 -0
  4. package/admin/src/content-manager/components/BlocksEditor/hooks/useBlocksStore.js +451 -0
  5. package/admin/src/content-manager/components/BlocksEditor/hooks/useModifiersStore.js +102 -0
  6. package/admin/src/content-manager/components/BlocksEditor/index.js +126 -0
  7. package/admin/src/content-manager/components/InputUID/index.js +92 -109
  8. package/admin/src/content-manager/components/Inputs/index.js +3 -1
  9. package/admin/src/content-manager/components/Inputs/utils/getInputType.js +2 -0
  10. package/admin/src/content-manager/components/RelationInput/RelationInput.js +59 -43
  11. package/admin/src/content-manager/hooks/useRelation/useRelation.js +85 -86
  12. package/admin/src/content-manager/pages/ListView/index.js +1 -0
  13. package/admin/src/content-manager/utils/schema.js +22 -0
  14. package/admin/src/index.js +7 -1
  15. package/admin/src/pages/MarketplacePage/components/EmptyNpmPackageSearch/index.js +1 -1
  16. package/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/index.js +0 -1
  17. package/admin/src/pages/MarketplacePage/components/NpmPackagesGrid/index.js +1 -1
  18. package/admin/src/translations/en.json +17 -0
  19. package/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/utils/getDisplayedFilters.js +1 -1
  20. package/ee/server/bootstrap.js +1 -1
  21. package/ee/server/content-types/workflow-stage/index.js +1 -1
  22. package/ee/server/controllers/admin.js +1 -1
  23. package/ee/server/controllers/user.js +1 -1
  24. package/ee/server/destroy.js +1 -1
  25. package/ee/server/register.js +1 -1
  26. package/ee/server/routes/utils.js +1 -1
  27. package/ee/server/services/audit-logs.js +1 -1
  28. package/ee/server/services/passport/sso.js +1 -1
  29. package/ee/server/services/passport.js +1 -1
  30. package/ee/server/services/seat-enforcement.js +1 -1
  31. package/ee/server/utils/sso-lock.js +1 -1
  32. package/ee/server/validation/role.js +1 -1
  33. package/ee/server/validation/user.js +1 -1
  34. package/package.json +21 -13
  35. package/server/controllers/admin.js +1 -1
  36. package/server/domain/permission/index.js +8 -1
  37. package/server/validation/permission.js +1 -1
  38. package/utils/plugins.js +7 -1
  39. package/build/0cd5f8915b265d5b1856.png +0 -0
  40. package/build/1049.bf5230e6.chunk.js +0 -1
  41. package/build/1227.4f48119b.chunk.js +0 -1
  42. package/build/1386.8c070d59.chunk.js +0 -7
  43. package/build/1727.b49f0713.chunk.js +0 -1
  44. package/build/19eb2dfcf2603eb55733.png +0 -0
  45. package/build/2225.73c9a224.chunk.js +0 -79
  46. package/build/2379.27c6ab54.chunk.js +0 -1
  47. package/build/2395.120256d6.chunk.js +0 -26
  48. package/build/2659.cb94f1e7.chunk.js +0 -105
  49. package/build/27d16aefee06412db90a.png +0 -0
  50. package/build/2801.fdd4d8a2.chunk.js +0 -1
  51. package/build/2950.216f2e89.chunk.js +0 -1
  52. package/build/3021.33ad47fb.chunk.js +0 -103
  53. package/build/3100.2ba4df95.chunk.js +0 -1
  54. package/build/311.cb0884bb.chunk.js +0 -1
  55. package/build/3483.f6b2439f.chunk.js +0 -1
  56. package/build/3911.488fbde3.chunk.js +0 -95
  57. package/build/4174.924ebd4c.chunk.js +0 -1
  58. package/build/4546.9710f321.chunk.js +0 -1
  59. package/build/502.d26ea06b.chunk.js +0 -1
  60. package/build/5158.c85f841a.chunk.js +0 -1
  61. package/build/6158.c3c13c20.chunk.js +0 -1
  62. package/build/6266.c652bdb1.chunk.js +0 -146
  63. package/build/6272.4017459a.chunk.js +0 -160
  64. package/build/6715.48e37308.chunk.js +0 -1
  65. package/build/6812.31979984.chunk.js +0 -26
  66. package/build/7030.b98dcedf.chunk.js +0 -1
  67. package/build/70674f63fc3904c20de0.svg +0 -7
  68. package/build/7464.d3d1414f.chunk.js +0 -1
  69. package/build/78.dcc6df5c.chunk.js +0 -1
  70. package/build/7897.cf22d5fe.chunk.js +0 -6
  71. package/build/7e9af4fb7e723fcebf1f.svg +0 -48
  72. package/build/8276.b55f4600.chunk.js +0 -26
  73. package/build/918.54414509.chunk.js +0 -1
  74. package/build/9d5d788027e86620c234.svg +0 -5
  75. package/build/Admin-authenticatedApp.a687d9c6.chunk.js +0 -112
  76. package/build/Admin_InternalErrorPage.18ba7fd6.chunk.js +0 -1
  77. package/build/Admin_homePage.86c8d4c9.chunk.js +0 -81
  78. package/build/Admin_marketplace.e75c9cf4.chunk.js +0 -55
  79. package/build/Admin_pluginsPage.d1afbf28.chunk.js +0 -6
  80. package/build/Admin_profilePage.079903a3.chunk.js +0 -13
  81. package/build/Admin_settingsPage.60a3e46e.chunk.js +0 -111
  82. package/build/Upload_ConfigureTheView.949535b8.chunk.js +0 -1
  83. package/build/admin-app.4654dc77.chunk.js +0 -36
  84. package/build/admin-edit-roles-page.6597d934.chunk.js +0 -267
  85. package/build/admin-edit-users.3014605e.chunk.js +0 -10
  86. package/build/admin-roles-list.ab6fcfb7.chunk.js +0 -22
  87. package/build/admin-users.81bf5f4d.chunk.js +0 -11
  88. package/build/api-tokens-create-page.f5a85725.chunk.js +0 -1
  89. package/build/api-tokens-edit-page.06a32cef.chunk.js +0 -1
  90. package/build/api-tokens-list-page.bb27d544.chunk.js +0 -16
  91. package/build/ar-json.74e40bc7.chunk.js +0 -1
  92. package/build/audit-logs-settings-page.4eb6cdf8.chunk.js +0 -1
  93. package/build/bb3108f7fd1e6179bde1.svg +0 -1
  94. package/build/bb4d0d527bdfb161bc5a.svg +0 -1
  95. package/build/ca-json.fc6001d3.chunk.js +0 -1
  96. package/build/content-manager.9187db78.chunk.js +0 -1097
  97. package/build/content-type-builder-list-view.b75fb938.chunk.js +0 -211
  98. package/build/content-type-builder-translation-ar-json.3e808e2f.chunk.js +0 -1
  99. package/build/content-type-builder-translation-cs-json.1ef9e106.chunk.js +0 -1
  100. package/build/content-type-builder-translation-de-json.63fcff7b.chunk.js +0 -1
  101. package/build/content-type-builder-translation-dk-json.fd626b67.chunk.js +0 -1
  102. package/build/content-type-builder-translation-en-json.ed29ff4d.chunk.js +0 -1
  103. package/build/content-type-builder-translation-es-json.a4a361a9.chunk.js +0 -1
  104. package/build/content-type-builder-translation-fr-json.499c3a46.chunk.js +0 -1
  105. package/build/content-type-builder-translation-id-json.65255f93.chunk.js +0 -1
  106. package/build/content-type-builder-translation-it-json.e268ab74.chunk.js +0 -1
  107. package/build/content-type-builder-translation-ja-json.9be0d5b2.chunk.js +0 -1
  108. package/build/content-type-builder-translation-ko-json.04cb309d.chunk.js +0 -1
  109. package/build/content-type-builder-translation-ms-json.f6b743b9.chunk.js +0 -1
  110. package/build/content-type-builder-translation-nl-json.997fe8cc.chunk.js +0 -1
  111. package/build/content-type-builder-translation-pl-json.634f638b.chunk.js +0 -1
  112. package/build/content-type-builder-translation-pt-BR-json.6a95dc71.chunk.js +0 -1
  113. package/build/content-type-builder-translation-pt-json.ddb44f8c.chunk.js +0 -1
  114. package/build/content-type-builder-translation-ru-json.3af65503.chunk.js +0 -1
  115. package/build/content-type-builder-translation-sk-json.c6078082.chunk.js +0 -1
  116. package/build/content-type-builder-translation-sv-json.a6df2462.chunk.js +0 -1
  117. package/build/content-type-builder-translation-th-json.122277cc.chunk.js +0 -1
  118. package/build/content-type-builder-translation-tr-json.41f44f77.chunk.js +0 -1
  119. package/build/content-type-builder-translation-uk-json.e1315acd.chunk.js +0 -1
  120. package/build/content-type-builder-translation-zh-Hans-json.6ff57db6.chunk.js +0 -1
  121. package/build/content-type-builder-translation-zh-json.3532b962.chunk.js +0 -1
  122. package/build/content-type-builder.5ff93edd.chunk.js +0 -170
  123. package/build/cs-json.4b44411c.chunk.js +0 -1
  124. package/build/de-json.e72545cf.chunk.js +0 -1
  125. package/build/dk-json.e77140ef.chunk.js +0 -1
  126. package/build/email-settings-page.07d417d5.chunk.js +0 -11
  127. package/build/email-translation-ar-json.88304564.chunk.js +0 -1
  128. package/build/email-translation-cs-json.6eaeec6a.chunk.js +0 -1
  129. package/build/email-translation-de-json.1b334230.chunk.js +0 -1
  130. package/build/email-translation-dk-json.85402492.chunk.js +0 -1
  131. package/build/email-translation-en-json.4211d4d0.chunk.js +0 -1
  132. package/build/email-translation-es-json.0b6b1006.chunk.js +0 -1
  133. package/build/email-translation-fr-json.78be2787.chunk.js +0 -1
  134. package/build/email-translation-id-json.c97239fe.chunk.js +0 -1
  135. package/build/email-translation-it-json.a2ed8c78.chunk.js +0 -1
  136. package/build/email-translation-ja-json.63eebd02.chunk.js +0 -1
  137. package/build/email-translation-ko-json.4de49b23.chunk.js +0 -1
  138. package/build/email-translation-ms-json.7390477e.chunk.js +0 -1
  139. package/build/email-translation-nl-json.377bdd9f.chunk.js +0 -1
  140. package/build/email-translation-pl-json.97d0db97.chunk.js +0 -1
  141. package/build/email-translation-pt-BR-json.81cca553.chunk.js +0 -1
  142. package/build/email-translation-pt-json.2a2a0643.chunk.js +0 -1
  143. package/build/email-translation-ru-json.6bce37dd.chunk.js +0 -1
  144. package/build/email-translation-sk-json.53da2fcd.chunk.js +0 -1
  145. package/build/email-translation-th-json.660fa9a8.chunk.js +0 -1
  146. package/build/email-translation-tr-json.e6c0f8fc.chunk.js +0 -1
  147. package/build/email-translation-uk-json.bd1fb6bf.chunk.js +0 -1
  148. package/build/email-translation-vi-json.9fb7e6d7.chunk.js +0 -1
  149. package/build/email-translation-zh-Hans-json.c6841563.chunk.js +0 -1
  150. package/build/email-translation-zh-json.7a2232ea.chunk.js +0 -1
  151. package/build/en-json.e12fd5fc.chunk.js +0 -1
  152. package/build/es-json.b1f2284b.chunk.js +0 -1
  153. package/build/eu-json.63d0a898.chunk.js +0 -1
  154. package/build/fr-json.33c6428b.chunk.js +0 -1
  155. package/build/gu-json.7efe8cc2.chunk.js +0 -1
  156. package/build/he-json.3cf0b48a.chunk.js +0 -1
  157. package/build/hi-json.0d633692.chunk.js +0 -1
  158. package/build/highlight.js.28a1547e.chunk.js +0 -85
  159. package/build/hu-json.c74b6a1e.chunk.js +0 -1
  160. package/build/i18n-settings-page.7107e28a.chunk.js +0 -9
  161. package/build/i18n-translation-de-json.362384a6.chunk.js +0 -1
  162. package/build/i18n-translation-dk-json.89401417.chunk.js +0 -1
  163. package/build/i18n-translation-en-json.1ec7becf.chunk.js +0 -1
  164. package/build/i18n-translation-es-json.87b494d1.chunk.js +0 -1
  165. package/build/i18n-translation-fr-json.57ddc77e.chunk.js +0 -1
  166. package/build/i18n-translation-ko-json.ef4f9471.chunk.js +0 -1
  167. package/build/i18n-translation-pl-json.dfac513d.chunk.js +0 -1
  168. package/build/i18n-translation-ru-json.a3dbc125.chunk.js +0 -1
  169. package/build/i18n-translation-tr-json.3bfc812f.chunk.js +0 -1
  170. package/build/i18n-translation-zh-Hans-json.757ce62d.chunk.js +0 -1
  171. package/build/i18n-translation-zh-json.bef2dc07.chunk.js +0 -1
  172. package/build/id-json.41e07c46.chunk.js +0 -1
  173. package/build/index.html +0 -1
  174. package/build/it-json.bfe27ed8.chunk.js +0 -1
  175. package/build/ja-json.e1959a1c.chunk.js +0 -1
  176. package/build/ko-json.ce5d6d94.chunk.js +0 -1
  177. package/build/main.da000219.js +0 -2860
  178. package/build/ml-json.940d7ace.chunk.js +0 -1
  179. package/build/ms-json.0eddffd9.chunk.js +0 -1
  180. package/build/nl-json.fe38f0fb.chunk.js +0 -1
  181. package/build/no-json.19a2dbfa.chunk.js +0 -1
  182. package/build/pl-json.d55e8e78.chunk.js +0 -1
  183. package/build/pt-BR-json.ae0a0d2e.chunk.js +0 -1
  184. package/build/pt-json.ee554a41.chunk.js +0 -1
  185. package/build/review-workflows-settings-create-view.5d8806b2.chunk.js +0 -1
  186. package/build/review-workflows-settings-edit-view.634903ed.chunk.js +0 -1
  187. package/build/review-workflows-settings-list-view.d138c3b5.chunk.js +0 -56
  188. package/build/ru-json.1c976644.chunk.js +0 -1
  189. package/build/runtime~main.9589b498.js +0 -2
  190. package/build/sa-json.2c03ef4e.chunk.js +0 -1
  191. package/build/sk-json.b41847e8.chunk.js +0 -1
  192. package/build/sso-settings-page.caa35f7b.chunk.js +0 -1
  193. package/build/sv-json.568cb7ae.chunk.js +0 -1
  194. package/build/th-json.5f659396.chunk.js +0 -1
  195. package/build/tr-json.c9f22432.chunk.js +0 -1
  196. package/build/transfer-tokens-create-page.6e7049ff.chunk.js +0 -1
  197. package/build/transfer-tokens-edit-page.449b4502.chunk.js +0 -1
  198. package/build/transfer-tokens-list-page.34caf827.chunk.js +0 -16
  199. package/build/uk-json.b7e38370.chunk.js +0 -1
  200. package/build/upload-settings.fede24b9.chunk.js +0 -14
  201. package/build/upload-translation-ca-json.57954414.chunk.js +0 -1
  202. package/build/upload-translation-de-json.420c943b.chunk.js +0 -1
  203. package/build/upload-translation-dk-json.bbb2fa05.chunk.js +0 -1
  204. package/build/upload-translation-en-json.8b7573ce.chunk.js +0 -1
  205. package/build/upload-translation-es-json.ba2eb03a.chunk.js +0 -1
  206. package/build/upload-translation-fr-json.baab9911.chunk.js +0 -1
  207. package/build/upload-translation-he-json.0a830937.chunk.js +0 -1
  208. package/build/upload-translation-it-json.e87d7966.chunk.js +0 -1
  209. package/build/upload-translation-ja-json.44b88e7a.chunk.js +0 -1
  210. package/build/upload-translation-ko-json.a52eab64.chunk.js +0 -1
  211. package/build/upload-translation-ms-json.74f6d746.chunk.js +0 -1
  212. package/build/upload-translation-pl-json.426f31c9.chunk.js +0 -1
  213. package/build/upload-translation-pt-BR-json.d1704f0b.chunk.js +0 -1
  214. package/build/upload-translation-pt-json.6b937fdf.chunk.js +0 -1
  215. package/build/upload-translation-ru-json.675f6b93.chunk.js +0 -1
  216. package/build/upload-translation-sk-json.483a18f6.chunk.js +0 -1
  217. package/build/upload-translation-th-json.98d35574.chunk.js +0 -1
  218. package/build/upload-translation-tr-json.74117e5c.chunk.js +0 -1
  219. package/build/upload-translation-uk-json.9950466a.chunk.js +0 -1
  220. package/build/upload-translation-zh-Hans-json.db163b6b.chunk.js +0 -1
  221. package/build/upload-translation-zh-json.e1dd6eb2.chunk.js +0 -1
  222. package/build/upload.a96e2452.chunk.js +0 -58
  223. package/build/users-advanced-settings-page.ac7968e7.chunk.js +0 -9
  224. package/build/users-email-settings-page.125a89e2.chunk.js +0 -9
  225. package/build/users-permissions-translation-ar-json.7d87d54d.chunk.js +0 -1
  226. package/build/users-permissions-translation-cs-json.7e23424a.chunk.js +0 -1
  227. package/build/users-permissions-translation-de-json.a6fb670f.chunk.js +0 -1
  228. package/build/users-permissions-translation-dk-json.60e50f48.chunk.js +0 -1
  229. package/build/users-permissions-translation-en-json.4b302272.chunk.js +0 -1
  230. package/build/users-permissions-translation-es-json.35007573.chunk.js +0 -1
  231. package/build/users-permissions-translation-fr-json.7e55bbbb.chunk.js +0 -1
  232. package/build/users-permissions-translation-id-json.a5a0fb59.chunk.js +0 -1
  233. package/build/users-permissions-translation-it-json.0705465d.chunk.js +0 -1
  234. package/build/users-permissions-translation-ja-json.891fe76e.chunk.js +0 -1
  235. package/build/users-permissions-translation-ko-json.357d7a33.chunk.js +0 -1
  236. package/build/users-permissions-translation-ms-json.c83f87c4.chunk.js +0 -1
  237. package/build/users-permissions-translation-nl-json.c9f92a3c.chunk.js +0 -1
  238. package/build/users-permissions-translation-pl-json.0a7287d1.chunk.js +0 -1
  239. package/build/users-permissions-translation-pt-BR-json.1b6d2920.chunk.js +0 -1
  240. package/build/users-permissions-translation-pt-json.a7eda429.chunk.js +0 -1
  241. package/build/users-permissions-translation-ru-json.8e883c67.chunk.js +0 -1
  242. package/build/users-permissions-translation-sk-json.7f37180f.chunk.js +0 -1
  243. package/build/users-permissions-translation-sv-json.17187818.chunk.js +0 -1
  244. package/build/users-permissions-translation-th-json.1e9c0247.chunk.js +0 -1
  245. package/build/users-permissions-translation-tr-json.2bd7ff98.chunk.js +0 -1
  246. package/build/users-permissions-translation-uk-json.6a0a1572.chunk.js +0 -1
  247. package/build/users-permissions-translation-vi-json.6722a8a2.chunk.js +0 -1
  248. package/build/users-permissions-translation-zh-Hans-json.8d82c809.chunk.js +0 -1
  249. package/build/users-permissions-translation-zh-json.7978eaa6.chunk.js +0 -1
  250. package/build/users-providers-settings-page.ce34951c.chunk.js +0 -14
  251. package/build/users-roles-settings-page.d415835a.chunk.js +0 -55
  252. package/build/vi-json.ee4c5537.chunk.js +0 -1
  253. package/build/webhook-edit-page.7498417e.chunk.js +0 -33
  254. package/build/webhook-list-page.1b085c7f.chunk.js +0 -63
  255. package/build/zh-Hans-json.97efd015.chunk.js +0 -1
  256. package/build/zh-json.bfc2e036.chunk.js +0 -1
@@ -0,0 +1,451 @@
1
+ import * as React from 'react';
2
+
3
+ import { Box, Typography, BaseLink } from '@strapi/design-system';
4
+ import {
5
+ Code,
6
+ Quote,
7
+ Picture,
8
+ Paragraph,
9
+ HeadingOne,
10
+ HeadingTwo,
11
+ HeadingThree,
12
+ HeadingFour,
13
+ HeadingFive,
14
+ HeadingSix,
15
+ } from '@strapi/icons';
16
+ import PropTypes from 'prop-types';
17
+ import { Editor, Path, Transforms } from 'slate';
18
+ import styled, { css } from 'styled-components';
19
+
20
+ const H1 = styled(Typography).attrs({ as: 'h1' })`
21
+ font-size: ${42 / 16}rem;
22
+ line-height: ${({ theme }) => theme.lineHeights[1]};
23
+ `;
24
+
25
+ const H2 = styled(Typography).attrs({ as: 'h2' })`
26
+ font-size: ${35 / 16}rem;
27
+ line-height: ${({ theme }) => theme.lineHeights[1]};
28
+ `;
29
+
30
+ const H3 = styled(Typography).attrs({ as: 'h3' })`
31
+ font-size: ${29 / 16}rem;
32
+ line-height: ${({ theme }) => theme.lineHeights[1]};
33
+ `;
34
+
35
+ const H4 = styled(Typography).attrs({ as: 'h4' })`
36
+ font-size: ${24 / 16}rem;
37
+ line-height: ${({ theme }) => theme.lineHeights[1]};
38
+ `;
39
+
40
+ const H5 = styled(Typography).attrs({ as: 'h5' })`
41
+ font-size: ${20 / 16}rem;
42
+ line-height: ${({ theme }) => theme.lineHeights[1]};
43
+ `;
44
+
45
+ const H6 = styled(Typography).attrs({ as: 'h6' })`
46
+ font-size: 1rem;
47
+ line-height: ${({ theme }) => theme.lineHeights[1]};
48
+ `;
49
+
50
+ const Heading = ({ attributes, children, element }) => {
51
+ switch (element.level) {
52
+ case 1:
53
+ return <H1 {...attributes}>{children}</H1>;
54
+ case 2:
55
+ return <H2 {...attributes}>{children}</H2>;
56
+ case 3:
57
+ return <H3 {...attributes}>{children}</H3>;
58
+ case 4:
59
+ return <H4 {...attributes}>{children}</H4>;
60
+ case 5:
61
+ return <H5 {...attributes}>{children}</H5>;
62
+ case 6:
63
+ return <H6 {...attributes}>{children}</H6>;
64
+ default: // do nothing
65
+ return null;
66
+ }
67
+ };
68
+
69
+ Heading.propTypes = {
70
+ attributes: PropTypes.object.isRequired,
71
+ children: PropTypes.node.isRequired,
72
+ element: PropTypes.shape({
73
+ level: PropTypes.oneOf([1, 2, 3, 4, 5, 6]).isRequired,
74
+ }).isRequired,
75
+ };
76
+
77
+ const CodeBlock = styled.pre.attrs({ role: 'code' })`
78
+ border-radius: ${({ theme }) => theme.borderRadius};
79
+ background-color: #32324d; // since the color is same between the themes
80
+ max-width: 100%;
81
+ overflow: auto;
82
+ padding: ${({ theme }) => theme.spaces[2]};
83
+ & > code {
84
+ color: #839496; // TODO: to confirm with design and get theme color
85
+ overflow: auto;
86
+ max-width: 100%;
87
+ padding: ${({ theme }) => theme.spaces[2]};
88
+ }
89
+ `;
90
+
91
+ const Blockquote = styled.blockquote.attrs({ role: 'blockquote' })`
92
+ margin: ${({ theme }) => `${theme.spaces[6]} 0`};
93
+ font-weight: ${({ theme }) => theme.fontWeights.regular};
94
+ border-left: ${({ theme }) => `${theme.spaces[1]} solid ${theme.colors.neutral150}`};
95
+ font-style: italic;
96
+ padding: ${({ theme }) => theme.spaces[2]} ${({ theme }) => theme.spaces[5]};
97
+ `;
98
+
99
+ const listStyle = css`
100
+ margin-block-start: ${({ theme }) => theme.spaces[4]};
101
+ margin-block-end: ${({ theme }) => theme.spaces[4]};
102
+ margin-inline-start: ${({ theme }) => theme.spaces[0]};
103
+ margin-inline-end: ${({ theme }) => theme.spaces[0]};
104
+ padding-inline-start: ${({ theme }) => theme.spaces[4]};
105
+
106
+ ol,
107
+ ul {
108
+ margin-block-start: ${({ theme }) => theme.spaces[0]};
109
+ margin-block-end: ${({ theme }) => theme.spaces[0]};
110
+ }
111
+ `;
112
+
113
+ const Orderedlist = styled.ol`
114
+ list-style-type: decimal;
115
+ ${listStyle}
116
+ `;
117
+
118
+ const Unorderedlist = styled.ul`
119
+ list-style-type: disc;
120
+ ${listStyle}
121
+ `;
122
+
123
+ const List = ({ attributes, children, element }) => {
124
+ if (element.format === 'ordered') return <Orderedlist {...attributes}>{children}</Orderedlist>;
125
+
126
+ return <Unorderedlist {...attributes}>{children}</Unorderedlist>;
127
+ };
128
+
129
+ List.propTypes = {
130
+ attributes: PropTypes.object.isRequired,
131
+ children: PropTypes.node.isRequired,
132
+ element: PropTypes.shape({
133
+ format: PropTypes.string.isRequired,
134
+ }).isRequired,
135
+ };
136
+
137
+ const Img = styled.img`
138
+ max-width: 100%;
139
+ `;
140
+
141
+ const Image = ({ attributes, children, element }) => {
142
+ if (!element.image) return null;
143
+ const { url, alternativeText, width, height } = element.image;
144
+
145
+ return (
146
+ <Box {...attributes}>
147
+ {children}
148
+ <Box contentEditable={false}>
149
+ <Img src={url} alt={alternativeText} width={width} height={height} />
150
+ </Box>
151
+ </Box>
152
+ );
153
+ };
154
+
155
+ Image.propTypes = {
156
+ attributes: PropTypes.object.isRequired,
157
+ children: PropTypes.node.isRequired,
158
+ element: PropTypes.shape({
159
+ image: PropTypes.shape({
160
+ url: PropTypes.string.isRequired,
161
+ alternativeText: PropTypes.string,
162
+ width: PropTypes.number,
163
+ height: PropTypes.number,
164
+ }),
165
+ }).isRequired,
166
+ };
167
+
168
+ /**
169
+ * Common handler for the enter key on ordered and unordered lists
170
+ * @param {import('slate').Editor} editor
171
+ */
172
+ const handleEnterKeyOnList = (editor) => {
173
+ // Check if the selected list item is empty
174
+ const [currentListItem, currentListItemPath] = Editor.above(editor, {
175
+ matchNode: (node) => node.type === 'list-item',
176
+ });
177
+ const isEmptyListItem =
178
+ currentListItem.children.length === 1 && currentListItem.children[0].text === '';
179
+
180
+ if (isEmptyListItem) {
181
+ // Delete the empty list item
182
+ Transforms.removeNodes(editor, { at: currentListItemPath });
183
+
184
+ // And create a new paragraph below the parent list
185
+ const listNodeEntry = Editor.above(editor, { match: (n) => n.type === 'list' });
186
+ const createdParagraphPath = Path.next(listNodeEntry[1]);
187
+ Transforms.insertNodes(
188
+ editor,
189
+ {
190
+ type: 'paragraph',
191
+ children: [{ type: 'text', text: '' }],
192
+ },
193
+ { at: createdParagraphPath }
194
+ );
195
+
196
+ // Move selection to the newly created paragraph
197
+ Transforms.select(editor, createdParagraphPath);
198
+ } else {
199
+ // Otherwise just create a new list item by splitting the current one
200
+ Transforms.splitNodes(editor, { always: true });
201
+ }
202
+ };
203
+
204
+ /**
205
+ * Manages a store of all the available blocks.
206
+ *
207
+ * @returns {{
208
+ * [key: string]: {
209
+ * renderElement: (props: Object) => JSX.Element,
210
+ * icon: React.ComponentType,
211
+ * label: {id: string, defaultMessage: string},
212
+ * value: Object,
213
+ * matchNode: (node: Object) => boolean,
214
+ * isInBlocksSelector: true,
215
+ * handleEnterKey: (editor: import('slate').Editor) => void,
216
+ * }
217
+ * }} an object containing rendering functions and metadata for different blocks, indexed by name.
218
+ */
219
+ export function useBlocksStore() {
220
+ return {
221
+ paragraph: {
222
+ renderElement: (props) => (
223
+ <Typography as="p" variant="omega" {...props.attributes}>
224
+ {props.children}
225
+ </Typography>
226
+ ),
227
+ icon: Paragraph,
228
+ label: {
229
+ id: 'components.Blocks.blocks.text',
230
+ defaultMessage: 'Text',
231
+ },
232
+ value: {
233
+ type: 'paragraph',
234
+ },
235
+ matchNode: (node) => node.type === 'paragraph',
236
+ isInBlocksSelector: true,
237
+ handleEnterKey(editor) {
238
+ /**
239
+ * Split the nodes where the cursor is. This will create a new paragraph with the content
240
+ * after the cursor, while retaining all the children, modifiers etc.
241
+ */
242
+ Transforms.splitNodes(editor, {
243
+ /**
244
+ * Makes sure we always create a new node,
245
+ * even if there's nothing to the right of the cursor in the node.
246
+ */
247
+ always: true,
248
+ });
249
+
250
+ /**
251
+ * Delete and recreate the node that was created at the right of the cursor.
252
+ * This is to avoid node pollution
253
+ * (e.g. keeping the level attribute when converting a heading to a paragraph).
254
+ * Select the parent of the selection because we want the full block, not the leaf.
255
+ * And copy its children to make sure we keep the modifiers.
256
+ */
257
+ const [createdNode] = Editor.parent(editor, editor.selection.anchor.path);
258
+ Transforms.removeNodes(editor, editor.selection);
259
+ Transforms.insertNodes(editor, {
260
+ type: 'paragraph',
261
+ children: createdNode.children,
262
+ });
263
+
264
+ /**
265
+ * The new selection will by default be at the end of the created node.
266
+ * Instead we manually move it to the start of the created node.
267
+ * Use slice(0, -1) to go 1 level higher in the tree,
268
+ * so we go to the start of the node and not the start of the leaf.
269
+ */
270
+ Transforms.select(editor, editor.start(editor.selection.anchor.path.slice(0, -1)));
271
+ },
272
+ },
273
+ 'heading-one': {
274
+ renderElement: (props) => <Heading {...props} />,
275
+ icon: HeadingOne,
276
+ label: {
277
+ id: 'components.Blocks.blocks.heading1',
278
+ defaultMessage: 'Heading 1',
279
+ },
280
+ value: {
281
+ type: 'heading',
282
+ level: 1,
283
+ },
284
+ matchNode: (node) => node.type === 'heading' && node.level === 1,
285
+ isInBlocksSelector: true,
286
+ },
287
+ 'heading-two': {
288
+ renderElement: (props) => <Heading {...props} />,
289
+ icon: HeadingTwo,
290
+ label: {
291
+ id: 'components.Blocks.blocks.heading2',
292
+ defaultMessage: 'Heading 2',
293
+ },
294
+ value: {
295
+ type: 'heading',
296
+ level: 2,
297
+ },
298
+ matchNode: (node) => node.type === 'heading' && node.level === 2,
299
+ isInBlocksSelector: true,
300
+ },
301
+ 'heading-three': {
302
+ renderElement: (props) => <Heading {...props} />,
303
+ icon: HeadingThree,
304
+ label: {
305
+ id: 'components.Blocks.blocks.heading3',
306
+ defaultMessage: 'Heading 3',
307
+ },
308
+ value: {
309
+ type: 'heading',
310
+ level: 3,
311
+ },
312
+ matchNode: (node) => node.type === 'heading' && node.level === 3,
313
+ isInBlocksSelector: true,
314
+ },
315
+ 'heading-four': {
316
+ renderElement: (props) => <Heading {...props} />,
317
+ icon: HeadingFour,
318
+ label: {
319
+ id: 'components.Blocks.blocks.heading4',
320
+ defaultMessage: 'Heading 4',
321
+ },
322
+ value: {
323
+ type: 'heading',
324
+ level: 4,
325
+ },
326
+ matchNode: (node) => node.type === 'heading' && node.level === 4,
327
+ isInBlocksSelector: true,
328
+ },
329
+ 'heading-five': {
330
+ renderElement: (props) => <Heading {...props} />,
331
+ icon: HeadingFive,
332
+ label: {
333
+ id: 'components.Blocks.blocks.heading5',
334
+ defaultMessage: 'Heading 5',
335
+ },
336
+ value: {
337
+ type: 'heading',
338
+ level: 5,
339
+ },
340
+ matchNode: (node) => node.type === 'heading' && node.level === 5,
341
+ isInBlocksSelector: true,
342
+ },
343
+ 'heading-six': {
344
+ renderElement: (props) => <Heading {...props} />,
345
+ icon: HeadingSix,
346
+ label: {
347
+ id: 'components.Blocks.blocks.heading6',
348
+ defaultMessage: 'Heading 6',
349
+ },
350
+ value: {
351
+ type: 'heading',
352
+ level: 6,
353
+ },
354
+ matchNode: (node) => node.type === 'heading' && node.level === 6,
355
+ isInBlocksSelector: true,
356
+ },
357
+ link: {
358
+ renderElement: (props) => (
359
+ <BaseLink href={props.element.url} {...props.attributes}>
360
+ {props.children}
361
+ </BaseLink>
362
+ ),
363
+ value: {
364
+ type: 'link',
365
+ },
366
+ matchNode: (node) => node.type === 'link',
367
+ isInBlocksSelector: false,
368
+ },
369
+ code: {
370
+ renderElement: (props) => (
371
+ <CodeBlock {...props.attributes}>
372
+ <code>{props.children}</code>
373
+ </CodeBlock>
374
+ ),
375
+ icon: Code,
376
+ label: {
377
+ id: 'components.Blocks.blocks.code',
378
+ defaultMessage: 'Code',
379
+ },
380
+ value: {
381
+ type: 'code',
382
+ },
383
+ matchNode: (node) => node.type === 'code',
384
+ isInBlocksSelector: true,
385
+ handleEnterKey(editor) {
386
+ // Insert a new line within the block
387
+ Transforms.insertText(editor, '\n');
388
+ },
389
+ },
390
+ quote: {
391
+ renderElement: (props) => <Blockquote {...props.attributes}>{props.children}</Blockquote>,
392
+ icon: Quote,
393
+ label: {
394
+ id: 'components.Blocks.blocks.quote',
395
+ defaultMessage: 'Quote',
396
+ },
397
+ value: {
398
+ type: 'quote',
399
+ },
400
+ matchNode: (node) => node.type === 'quote',
401
+ isInBlocksSelector: true,
402
+ },
403
+ 'list-ordered': {
404
+ renderElement: (props) => <List {...props} />,
405
+ value: {
406
+ type: 'list',
407
+ format: 'ordered',
408
+ },
409
+ matchNode: (node) => node.type === 'list' && node.format === 'ordered',
410
+ // TODO add icon and label and set isInBlocksEditor to true
411
+ isInBlocksSelector: false,
412
+ handleEnterKey: handleEnterKeyOnList,
413
+ },
414
+ 'list-unordered': {
415
+ renderElement: (props) => <List {...props} />,
416
+ value: {
417
+ type: 'list',
418
+ format: 'unordered',
419
+ },
420
+ matchNode: (node) => node.type === 'list' && node.format === 'unordered',
421
+ // TODO add icon and label and set isInBlocksEditor to true
422
+ isInBlocksSelector: false,
423
+ handleEnterKey: handleEnterKeyOnList,
424
+ },
425
+ 'list-item': {
426
+ renderElement: (props) => (
427
+ <Typography as="li" {...props.attributes}>
428
+ {props.children}
429
+ </Typography>
430
+ ),
431
+ value: {
432
+ type: 'list-item',
433
+ },
434
+ matchNode: (node) => node.type === 'list-item',
435
+ isInBlocksSelector: false,
436
+ },
437
+ image: {
438
+ renderElement: (props) => <Image {...props} />,
439
+ icon: Picture,
440
+ label: {
441
+ id: 'components.Blocks.blocks.image',
442
+ defaultMessage: 'Image',
443
+ },
444
+ value: {
445
+ type: 'image',
446
+ },
447
+ matchNode: (node) => node.type === 'image',
448
+ isInBlocksSelector: true,
449
+ },
450
+ };
451
+ }
@@ -0,0 +1,102 @@
1
+ import * as React from 'react';
2
+
3
+ import { Typography } from '@strapi/design-system';
4
+ import { Bold, Italic, Underline, StrikeThrough, Code } from '@strapi/icons';
5
+ import { Editor } from 'slate';
6
+ import { useSlate } from 'slate-react';
7
+ import styled from 'styled-components';
8
+
9
+ const BoldText = styled(Typography).attrs({ fontWeight: 'bold' })`
10
+ font-size: inherit;
11
+ `;
12
+
13
+ const ItalicText = styled(Typography)`
14
+ font-style: italic;
15
+ font-size: inherit;
16
+ `;
17
+
18
+ const UnderlineText = styled(Typography).attrs({ textDecoration: 'underline' })`
19
+ font-size: inherit;
20
+ `;
21
+
22
+ const StrikeThroughText = styled(Typography).attrs({ textDecoration: 'line-through' })`
23
+ font-size: inherit;
24
+ `;
25
+
26
+ const InlineCode = styled.code`
27
+ background-color: ${({ theme }) => theme.colors.neutral150};
28
+ border-radius: ${({ theme }) => theme.borderRadius};
29
+ padding: ${({ theme }) => `0 ${theme.spaces[2]}`};
30
+ font-family: 'SF Mono', SFMono-Regular, ui-monospace, 'DejaVu Sans Mono', Menlo, Consolas,
31
+ monospace;
32
+ `;
33
+
34
+ /**
35
+ * Manages a store of all the available modifiers.
36
+ *
37
+ * @returns {{
38
+ * [key: string]: {
39
+ * icon: IconComponent,
40
+ * label: {id: string, defaultMessage: string},
41
+ * checkIsActive: () => boolean,
42
+ * handleToggle: () => void,
43
+ * renderLeaf: (children: JSX.Element) => JSX.Element,
44
+ * }
45
+ * }} An object containing rendering functions and metadata for different text modifiers, indexed by name.
46
+ */
47
+ export function useModifiersStore() {
48
+ const editor = useSlate();
49
+ const modifiers = Editor.marks(editor);
50
+
51
+ const baseCheckIsActive = (name) => {
52
+ if (!modifiers) return false;
53
+
54
+ return Boolean(modifiers[name]);
55
+ };
56
+
57
+ const baseHandleToggle = (name) => {
58
+ if (modifiers[name]) {
59
+ Editor.removeMark(editor, name);
60
+ } else {
61
+ Editor.addMark(editor, name, true);
62
+ }
63
+ };
64
+
65
+ return {
66
+ bold: {
67
+ icon: Bold,
68
+ label: { id: 'components.Blocks.modifiers.bold', defaultMessage: 'Bold' },
69
+ checkIsActive: () => baseCheckIsActive('bold'),
70
+ handleToggle: () => baseHandleToggle('bold'),
71
+ renderLeaf: (children) => <BoldText>{children}</BoldText>,
72
+ },
73
+ italic: {
74
+ icon: Italic,
75
+ label: { id: 'components.Blocks.modifiers.italic', defaultMessage: 'Italic' },
76
+ checkIsActive: () => baseCheckIsActive('italic'),
77
+ handleToggle: () => baseHandleToggle('italic'),
78
+ renderLeaf: (children) => <ItalicText>{children}</ItalicText>,
79
+ },
80
+ underline: {
81
+ icon: Underline,
82
+ label: { id: 'components.Blocks.modifiers.underline', defaultMessage: 'Underline' },
83
+ checkIsActive: () => baseCheckIsActive('underline'),
84
+ handleToggle: () => baseHandleToggle('underline'),
85
+ renderLeaf: (children) => <UnderlineText>{children}</UnderlineText>,
86
+ },
87
+ strikethrough: {
88
+ icon: StrikeThrough,
89
+ label: { id: 'components.Blocks.modifiers.strikethrough', defaultMessage: 'Strikethrough' },
90
+ checkIsActive: () => baseCheckIsActive('strikethrough'),
91
+ handleToggle: () => baseHandleToggle('strikethrough'),
92
+ renderLeaf: (children) => <StrikeThroughText>{children}</StrikeThroughText>,
93
+ },
94
+ code: {
95
+ icon: Code,
96
+ label: { id: 'components.Blocks.modifiers.code', defaultMessage: 'Code' },
97
+ checkIsActive: () => baseCheckIsActive('code'),
98
+ handleToggle: () => baseHandleToggle('code'),
99
+ renderLeaf: (children) => <InlineCode>{children}</InlineCode>,
100
+ },
101
+ };
102
+ }
@@ -0,0 +1,126 @@
1
+ import * as React from 'react';
2
+
3
+ import { Box, Flex, Typography, InputWrapper, Divider } from '@strapi/design-system';
4
+ import PropTypes from 'prop-types';
5
+ import { useIntl } from 'react-intl';
6
+ import { createEditor } from 'slate';
7
+ import { withHistory } from 'slate-history';
8
+ import { Slate, withReact, ReactEditor } from 'slate-react';
9
+ import styled from 'styled-components';
10
+
11
+ import BlocksInput from './BlocksInput';
12
+ import { BlocksToolbar } from './Toolbar';
13
+
14
+ const TypographyAsterisk = styled(Typography)`
15
+ line-height: 0;
16
+ `;
17
+
18
+ const EditorDivider = styled(Divider)`
19
+ background: ${({ theme }) => theme.colors.neutral200};
20
+ `;
21
+
22
+ const Wrapper = styled(Box)`
23
+ width: 100%;
24
+ max-height: 512px;
25
+ overflow: auto;
26
+ padding: ${({ theme }) => `${theme.spaces[3]} ${theme.spaces[4]}`};
27
+ font-size: ${({ theme }) => theme.fontSizes[2]};
28
+ background-color: ${({ theme }) => theme.colors.neutral0};
29
+ color: ${({ theme }) => theme.colors.neutral800};
30
+ line-height: ${({ theme }) => theme.lineHeights[6]};
31
+ border-radius: ${({ theme }) => theme.borderRadius};
32
+ `;
33
+
34
+ const BlocksEditor = React.forwardRef(
35
+ ({ intlLabel, name, readOnly, required, error, value, onChange }, ref) => {
36
+ const { formatMessage } = useIntl();
37
+ const [editor] = React.useState(() => withReact(withHistory(createEditor())));
38
+
39
+ const label = intlLabel.id
40
+ ? formatMessage(
41
+ { id: intlLabel.id, defaultMessage: intlLabel.defaultMessage },
42
+ { ...intlLabel.values }
43
+ )
44
+ : name;
45
+
46
+ /** Editable is not able to hold the ref, https://github.com/ianstormtaylor/slate/issues/4082
47
+ * so with "useImperativeHandle" we can use ReactEditor methods to expose to the parent above
48
+ * also not passing forwarded ref here, gives console warning.
49
+ */
50
+ React.useImperativeHandle(
51
+ ref,
52
+ () => ({
53
+ focus() {
54
+ ReactEditor.focus(editor);
55
+ },
56
+ }),
57
+ [editor]
58
+ );
59
+
60
+ const handleSlateChange = (state) => {
61
+ const isAstChange = editor.operations.some((op) => op.type !== 'set_selection');
62
+
63
+ if (isAstChange) {
64
+ onChange({
65
+ target: { name, value: state, type: 'blocks' },
66
+ });
67
+ }
68
+ };
69
+
70
+ return (
71
+ <>
72
+ <Flex direction="column" alignItems="stretch" gap={1}>
73
+ <Flex gap={1}>
74
+ <Typography variant="pi" fontWeight="bold" textColor="neutral800">
75
+ {label}
76
+ {required && <TypographyAsterisk textColor="danger600">*</TypographyAsterisk>}
77
+ </Typography>
78
+ </Flex>
79
+ <Slate
80
+ editor={editor}
81
+ initialValue={value || [{ type: 'paragraph', children: [{ type: 'text', text: '' }] }]}
82
+ onChange={handleSlateChange}
83
+ >
84
+ <InputWrapper direction="column" alignItems="flex-start">
85
+ <BlocksToolbar />
86
+ <EditorDivider width="100%" />
87
+ <Wrapper>
88
+ <BlocksInput readOnly={readOnly} />
89
+ </Wrapper>
90
+ </InputWrapper>
91
+ </Slate>
92
+ </Flex>
93
+ {error && (
94
+ <Box paddingTop={1}>
95
+ <Typography variant="pi" textColor="danger600" data-strapi-field-error>
96
+ {error}
97
+ </Typography>
98
+ </Box>
99
+ )}
100
+ </>
101
+ );
102
+ }
103
+ );
104
+
105
+ BlocksEditor.defaultProps = {
106
+ required: false,
107
+ readOnly: false,
108
+ error: '',
109
+ value: null,
110
+ };
111
+
112
+ BlocksEditor.propTypes = {
113
+ intlLabel: PropTypes.shape({
114
+ id: PropTypes.string.isRequired,
115
+ defaultMessage: PropTypes.string.isRequired,
116
+ values: PropTypes.object,
117
+ }).isRequired,
118
+ name: PropTypes.string.isRequired,
119
+ required: PropTypes.bool,
120
+ readOnly: PropTypes.bool,
121
+ error: PropTypes.string,
122
+ onChange: PropTypes.func.isRequired,
123
+ value: PropTypes.array,
124
+ };
125
+
126
+ export default BlocksEditor;