@wordpress/editor 14.33.3 → 14.34.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 (301) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/components/collab-sidebar/comment-author-info.js +26 -14
  3. package/build/components/collab-sidebar/comment-author-info.js.map +2 -2
  4. package/build/components/document-bar/index.js +16 -3
  5. package/build/components/document-bar/index.js.map +2 -2
  6. package/build/components/editor/index.js +23 -4
  7. package/build/components/editor/index.js.map +3 -3
  8. package/build/components/editor-interface/index.js +15 -10
  9. package/build/components/editor-interface/index.js.map +3 -3
  10. package/build/components/entities-saved-states/entity-type-list.js +19 -15
  11. package/build/components/entities-saved-states/entity-type-list.js.map +3 -3
  12. package/build/components/global-styles/block-link.js +70 -0
  13. package/build/components/global-styles/block-link.js.map +7 -0
  14. package/build/components/global-styles/header.js +54 -0
  15. package/build/components/global-styles/header.js.map +7 -0
  16. package/build/components/global-styles/hooks.js +176 -0
  17. package/build/components/global-styles/hooks.js.map +7 -0
  18. package/build/components/global-styles/index.js +138 -0
  19. package/build/components/global-styles/index.js.map +7 -0
  20. package/build/components/global-styles/menu.js +95 -0
  21. package/build/components/global-styles/menu.js.map +7 -0
  22. package/build/components/global-styles-provider/index.js +3 -49
  23. package/build/components/global-styles-provider/index.js.map +3 -3
  24. package/build/components/global-styles-renderer/index.js +55 -0
  25. package/build/components/global-styles-renderer/index.js.map +7 -0
  26. package/build/components/global-styles-sidebar/default-sidebar.js +66 -0
  27. package/build/components/global-styles-sidebar/default-sidebar.js.map +7 -0
  28. package/build/components/global-styles-sidebar/index.js +182 -0
  29. package/build/components/global-styles-sidebar/index.js.map +7 -0
  30. package/build/components/global-styles-sidebar/welcome-guide-image.js +37 -0
  31. package/build/components/global-styles-sidebar/welcome-guide-image.js.map +7 -0
  32. package/build/components/global-styles-sidebar/welcome-guide.js +143 -0
  33. package/build/components/global-styles-sidebar/welcome-guide.js.map +7 -0
  34. package/build/components/header/index.js +12 -9
  35. package/build/components/header/index.js.map +2 -2
  36. package/build/components/post-featured-image/index.js +32 -1
  37. package/build/components/post-featured-image/index.js.map +3 -3
  38. package/build/components/provider/index.js +0 -2
  39. package/build/components/provider/index.js.map +3 -3
  40. package/build/components/style-book/categories.js +86 -0
  41. package/build/components/style-book/categories.js.map +7 -0
  42. package/build/components/style-book/color-examples.js +64 -0
  43. package/build/components/style-book/color-examples.js.map +7 -0
  44. package/build/components/style-book/constants.js +319 -0
  45. package/build/components/style-book/constants.js.map +7 -0
  46. package/build/components/style-book/duotone-examples.js +68 -0
  47. package/build/components/style-book/duotone-examples.js.map +7 -0
  48. package/build/components/style-book/examples.js +237 -0
  49. package/build/components/style-book/examples.js.map +7 -0
  50. package/build/components/style-book/index.js +627 -0
  51. package/build/components/style-book/index.js.map +7 -0
  52. package/build/components/style-book/types.js +17 -0
  53. package/build/components/style-book/types.js.map +7 -0
  54. package/build/components/styles-canvas/index.js +138 -0
  55. package/build/components/styles-canvas/index.js.map +7 -0
  56. package/build/components/styles-canvas/revisions.js +121 -0
  57. package/build/components/styles-canvas/revisions.js.map +7 -0
  58. package/build/components/styles-canvas/style-book.js +68 -0
  59. package/build/components/styles-canvas/style-book.js.map +7 -0
  60. package/build/components/visual-editor/index.js +4 -3
  61. package/build/components/visual-editor/index.js.map +2 -2
  62. package/build/dataviews/fields/content-preview/content-preview-view.js.map +2 -2
  63. package/build/hooks/index.js +1 -0
  64. package/build/hooks/index.js.map +2 -2
  65. package/build/hooks/media-upload.js +15 -4
  66. package/build/hooks/media-upload.js.map +3 -3
  67. package/build/hooks/push-changes-to-global-styles/index.js +322 -0
  68. package/build/hooks/push-changes-to-global-styles/index.js.map +7 -0
  69. package/build/hooks/use-global-styles-output.js +74 -0
  70. package/build/hooks/use-global-styles-output.js.map +7 -0
  71. package/build/private-apis.js +10 -5
  72. package/build/private-apis.js.map +3 -3
  73. package/build/store/private-actions.js +23 -0
  74. package/build/store/private-actions.js.map +2 -2
  75. package/build/store/private-selectors.js +10 -0
  76. package/build/store/private-selectors.js.map +2 -2
  77. package/build/store/reducer.js +24 -0
  78. package/build/store/reducer.js.map +2 -2
  79. package/build/{components/editor-interface/content-slot-fill.js → utils/set-nested-value.js} +24 -10
  80. package/build/utils/set-nested-value.js.map +7 -0
  81. package/build-module/components/collab-sidebar/comment-author-info.js +26 -14
  82. package/build-module/components/collab-sidebar/comment-author-info.js.map +2 -2
  83. package/build-module/components/document-bar/index.js +16 -3
  84. package/build-module/components/document-bar/index.js.map +2 -2
  85. package/build-module/components/editor/index.js +23 -4
  86. package/build-module/components/editor/index.js.map +2 -2
  87. package/build-module/components/editor-interface/index.js +15 -10
  88. package/build-module/components/editor-interface/index.js.map +2 -2
  89. package/build-module/components/entities-saved-states/entity-type-list.js +18 -14
  90. package/build-module/components/entities-saved-states/entity-type-list.js.map +2 -2
  91. package/build-module/components/global-styles/block-link.js +46 -0
  92. package/build-module/components/global-styles/block-link.js.map +7 -0
  93. package/build-module/components/global-styles/header.js +41 -0
  94. package/build-module/components/global-styles/header.js.map +7 -0
  95. package/build-module/components/global-styles/hooks.js +154 -0
  96. package/build-module/components/global-styles/hooks.js.map +7 -0
  97. package/build-module/components/global-styles/index.js +112 -0
  98. package/build-module/components/global-styles/index.js.map +7 -0
  99. package/build-module/components/global-styles/menu.js +71 -0
  100. package/build-module/components/global-styles/menu.js.map +7 -0
  101. package/build-module/components/global-styles-provider/index.js +3 -37
  102. package/build-module/components/global-styles-provider/index.js.map +2 -2
  103. package/build-module/components/global-styles-renderer/index.js +31 -0
  104. package/build-module/components/global-styles-renderer/index.js.map +7 -0
  105. package/build-module/components/global-styles-sidebar/default-sidebar.js +49 -0
  106. package/build-module/components/global-styles-sidebar/default-sidebar.js.map +7 -0
  107. package/build-module/components/global-styles-sidebar/index.js +152 -0
  108. package/build-module/components/global-styles-sidebar/index.js.map +7 -0
  109. package/build-module/components/global-styles-sidebar/welcome-guide-image.js +17 -0
  110. package/build-module/components/global-styles-sidebar/welcome-guide-image.js.map +7 -0
  111. package/build-module/components/global-styles-sidebar/welcome-guide.js +113 -0
  112. package/build-module/components/global-styles-sidebar/welcome-guide.js.map +7 -0
  113. package/build-module/components/header/index.js +12 -9
  114. package/build-module/components/header/index.js.map +2 -2
  115. package/build-module/components/post-featured-image/index.js +35 -3
  116. package/build-module/components/post-featured-image/index.js.map +2 -2
  117. package/build-module/components/provider/index.js +0 -2
  118. package/build-module/components/provider/index.js.map +2 -2
  119. package/build-module/components/style-book/categories.js +64 -0
  120. package/build-module/components/style-book/categories.js.map +7 -0
  121. package/build-module/components/style-book/color-examples.js +37 -0
  122. package/build-module/components/style-book/color-examples.js.map +7 -0
  123. package/build-module/components/style-book/constants.js +290 -0
  124. package/build-module/components/style-book/constants.js.map +7 -0
  125. package/build-module/components/style-book/duotone-examples.js +48 -0
  126. package/build-module/components/style-book/duotone-examples.js.map +7 -0
  127. package/build-module/components/style-book/examples.js +208 -0
  128. package/build-module/components/style-book/examples.js.map +7 -0
  129. package/build-module/components/style-book/index.js +618 -0
  130. package/build-module/components/style-book/index.js.map +7 -0
  131. package/build-module/components/style-book/types.js +1 -0
  132. package/build-module/components/style-book/types.js.map +7 -0
  133. package/build-module/components/styles-canvas/index.js +104 -0
  134. package/build-module/components/styles-canvas/index.js.map +7 -0
  135. package/build-module/components/styles-canvas/revisions.js +107 -0
  136. package/build-module/components/styles-canvas/revisions.js.map +7 -0
  137. package/build-module/components/styles-canvas/style-book.js +38 -0
  138. package/build-module/components/styles-canvas/style-book.js.map +7 -0
  139. package/build-module/components/visual-editor/index.js +4 -3
  140. package/build-module/components/visual-editor/index.js.map +2 -2
  141. package/build-module/dataviews/fields/content-preview/content-preview-view.js.map +2 -2
  142. package/build-module/hooks/index.js +1 -0
  143. package/build-module/hooks/index.js.map +2 -2
  144. package/build-module/hooks/media-upload.js +19 -5
  145. package/build-module/hooks/media-upload.js.map +2 -2
  146. package/build-module/hooks/push-changes-to-global-styles/index.js +309 -0
  147. package/build-module/hooks/push-changes-to-global-styles/index.js.map +7 -0
  148. package/build-module/hooks/use-global-styles-output.js +49 -0
  149. package/build-module/hooks/use-global-styles-output.js.map +7 -0
  150. package/build-module/private-apis.js +10 -8
  151. package/build-module/private-apis.js.map +2 -2
  152. package/build-module/store/private-actions.js +20 -0
  153. package/build-module/store/private-actions.js.map +2 -2
  154. package/build-module/store/private-selectors.js +8 -0
  155. package/build-module/store/private-selectors.js.map +2 -2
  156. package/build-module/store/reducer.js +22 -0
  157. package/build-module/store/reducer.js.map +2 -2
  158. package/build-module/utils/set-nested-value.js +23 -0
  159. package/build-module/utils/set-nested-value.js.map +7 -0
  160. package/build-style/style-rtl.css +3017 -11
  161. package/build-style/style.css +3018 -11
  162. package/build-types/components/collab-sidebar/comment-author-info.d.ts +5 -16
  163. package/build-types/components/collab-sidebar/comment-author-info.d.ts.map +1 -1
  164. package/build-types/components/document-bar/index.d.ts +2 -2
  165. package/build-types/components/document-bar/index.d.ts.map +1 -1
  166. package/build-types/components/editor/index.d.ts.map +1 -1
  167. package/build-types/components/editor-interface/index.d.ts +1 -3
  168. package/build-types/components/editor-interface/index.d.ts.map +1 -1
  169. package/build-types/components/entities-saved-states/entity-type-list.d.ts.map +1 -1
  170. package/build-types/components/global-styles/block-link.d.ts +12 -0
  171. package/build-types/components/global-styles/block-link.d.ts.map +1 -0
  172. package/build-types/components/global-styles/header.d.ts +7 -0
  173. package/build-types/components/global-styles/header.d.ts.map +1 -0
  174. package/build-types/components/global-styles/hooks.d.ts +24 -0
  175. package/build-types/components/global-styles/hooks.d.ts.map +1 -0
  176. package/build-types/components/global-styles/index.d.ts +6 -0
  177. package/build-types/components/global-styles/index.d.ts.map +1 -0
  178. package/build-types/components/global-styles/menu.d.ts +13 -0
  179. package/build-types/components/global-styles/menu.d.ts.map +1 -0
  180. package/build-types/components/global-styles-provider/index.d.ts +1 -5
  181. package/build-types/components/global-styles-provider/index.d.ts.map +1 -1
  182. package/build-types/components/global-styles-renderer/index.d.ts +4 -0
  183. package/build-types/components/global-styles-renderer/index.d.ts.map +1 -0
  184. package/build-types/components/global-styles-sidebar/default-sidebar.d.ts +13 -0
  185. package/build-types/components/global-styles-sidebar/default-sidebar.d.ts.map +1 -0
  186. package/build-types/components/global-styles-sidebar/index.d.ts +2 -0
  187. package/build-types/components/global-styles-sidebar/index.d.ts.map +1 -0
  188. package/build-types/components/global-styles-sidebar/welcome-guide-image.d.ts +5 -0
  189. package/build-types/components/global-styles-sidebar/welcome-guide-image.d.ts.map +1 -0
  190. package/build-types/components/global-styles-sidebar/welcome-guide.d.ts +2 -0
  191. package/build-types/components/global-styles-sidebar/welcome-guide.d.ts.map +1 -0
  192. package/build-types/components/header/index.d.ts +1 -3
  193. package/build-types/components/header/index.d.ts.map +1 -1
  194. package/build-types/components/provider/index.d.ts.map +1 -1
  195. package/build-types/components/style-book/categories.d.ts +18 -0
  196. package/build-types/components/style-book/categories.d.ts.map +1 -0
  197. package/build-types/components/style-book/color-examples.d.ts +7 -0
  198. package/build-types/components/style-book/color-examples.d.ts.map +1 -0
  199. package/build-types/components/style-book/constants.d.ts +11 -0
  200. package/build-types/components/style-book/constants.d.ts.map +1 -0
  201. package/build-types/components/style-book/duotone-examples.d.ts +9 -0
  202. package/build-types/components/style-book/duotone-examples.d.ts.map +1 -0
  203. package/build-types/components/style-book/examples.d.ts +12 -0
  204. package/build-types/components/style-book/examples.d.ts.map +1 -0
  205. package/build-types/components/style-book/index.d.ts +31 -0
  206. package/build-types/components/style-book/index.d.ts.map +1 -0
  207. package/build-types/components/style-book/types.d.ts +72 -0
  208. package/build-types/components/style-book/types.d.ts.map +1 -0
  209. package/build-types/components/styles-canvas/index.d.ts +16 -0
  210. package/build-types/components/styles-canvas/index.d.ts.map +1 -0
  211. package/build-types/components/styles-canvas/revisions.d.ts +5 -0
  212. package/build-types/components/styles-canvas/revisions.d.ts.map +1 -0
  213. package/build-types/components/styles-canvas/style-book.d.ts +6 -0
  214. package/build-types/components/styles-canvas/style-book.d.ts.map +1 -0
  215. package/build-types/components/visual-editor/index.d.ts +1 -2
  216. package/build-types/components/visual-editor/index.d.ts.map +1 -1
  217. package/build-types/dataviews/fields/content-preview/content-preview-view.d.ts.map +1 -1
  218. package/build-types/hooks/push-changes-to-global-styles/index.d.ts +2 -0
  219. package/build-types/hooks/push-changes-to-global-styles/index.d.ts.map +1 -0
  220. package/build-types/hooks/use-global-styles-output.d.ts +18 -0
  221. package/build-types/hooks/use-global-styles-output.d.ts.map +1 -0
  222. package/build-types/private-apis.d.ts.map +1 -1
  223. package/build-types/store/private-actions.d.ts +20 -0
  224. package/build-types/store/private-actions.d.ts.map +1 -1
  225. package/build-types/store/private-selectors.d.ts +14 -0
  226. package/build-types/store/private-selectors.d.ts.map +1 -1
  227. package/build-types/store/reducer.d.ts +20 -0
  228. package/build-types/store/reducer.d.ts.map +1 -1
  229. package/build-types/utils/set-nested-value.d.ts +20 -0
  230. package/build-types/utils/set-nested-value.d.ts.map +1 -0
  231. package/package.json +40 -40
  232. package/src/components/collab-sidebar/comment-author-info.js +32 -25
  233. package/src/components/collab-sidebar/style.scss +1 -1
  234. package/src/components/document-bar/index.js +18 -3
  235. package/src/components/editor/index.js +25 -1
  236. package/src/components/editor-help/style.scss +1 -1
  237. package/src/components/editor-interface/index.js +40 -39
  238. package/src/components/entities-saved-states/entity-type-list.js +19 -17
  239. package/src/components/global-styles/block-link.js +65 -0
  240. package/src/components/global-styles/header.js +48 -0
  241. package/src/components/global-styles/hooks.js +216 -0
  242. package/src/components/global-styles/index.js +125 -0
  243. package/src/components/global-styles/menu.js +101 -0
  244. package/src/components/global-styles/style.scss +11 -0
  245. package/src/components/global-styles-provider/index.js +3 -45
  246. package/src/components/global-styles-renderer/index.js +39 -0
  247. package/src/components/global-styles-sidebar/default-sidebar.js +46 -0
  248. package/src/components/global-styles-sidebar/index.js +177 -0
  249. package/src/components/global-styles-sidebar/style.scss +119 -0
  250. package/src/components/global-styles-sidebar/welcome-guide-image.js +11 -0
  251. package/src/components/global-styles-sidebar/welcome-guide.js +136 -0
  252. package/src/components/header/index.js +11 -6
  253. package/src/components/post-featured-image/index.js +44 -1
  254. package/src/components/post-last-revision/style.scss +1 -1
  255. package/src/components/post-panel-row/style.scss +1 -0
  256. package/src/components/post-publish-panel/style.scss +1 -1
  257. package/src/components/post-publish-panel/test/__snapshots__/index.js.snap +2 -2
  258. package/src/components/provider/index.js +0 -2
  259. package/src/components/style-book/categories.ts +97 -0
  260. package/src/components/style-book/color-examples.tsx +56 -0
  261. package/src/components/style-book/constants.ts +308 -0
  262. package/src/components/style-book/duotone-examples.tsx +56 -0
  263. package/src/components/style-book/examples.tsx +273 -0
  264. package/src/components/style-book/index.js +794 -0
  265. package/src/components/style-book/style.scss +44 -0
  266. package/src/components/style-book/test/categories.js +166 -0
  267. package/src/components/style-book/types.ts +80 -0
  268. package/src/components/styles-canvas/index.js +126 -0
  269. package/src/components/styles-canvas/revisions.js +144 -0
  270. package/src/components/styles-canvas/style-book.js +57 -0
  271. package/src/components/styles-canvas/style.scss +40 -0
  272. package/src/components/visual-editor/index.js +2 -1
  273. package/src/dataviews/fields/content-preview/content-preview-view.tsx +2 -0
  274. package/src/hooks/index.js +1 -0
  275. package/src/hooks/media-upload.js +25 -5
  276. package/src/hooks/push-changes-to-global-styles/index.js +391 -0
  277. package/src/hooks/push-changes-to-global-styles/style.scss +4 -0
  278. package/src/hooks/use-global-styles-output.js +76 -0
  279. package/src/private-apis.js +10 -8
  280. package/src/store/private-actions.js +37 -0
  281. package/src/store/private-selectors.js +20 -0
  282. package/src/store/reducer.js +36 -0
  283. package/src/style.scss +7 -1
  284. package/src/utils/set-nested-value.js +39 -0
  285. package/tsconfig.json +3 -0
  286. package/tsconfig.tsbuildinfo +1 -1
  287. package/build/components/block-settings-menu/content-only-settings-menu.js +0 -186
  288. package/build/components/block-settings-menu/content-only-settings-menu.js.map +0 -7
  289. package/build/components/editor-interface/content-slot-fill.js.map +0 -7
  290. package/build-module/components/block-settings-menu/content-only-settings-menu.js +0 -161
  291. package/build-module/components/block-settings-menu/content-only-settings-menu.js.map +0 -7
  292. package/build-module/components/editor-interface/content-slot-fill.js +0 -9
  293. package/build-module/components/editor-interface/content-slot-fill.js.map +0 -7
  294. package/build-types/components/block-settings-menu/content-only-settings-menu.d.ts +0 -2
  295. package/build-types/components/block-settings-menu/content-only-settings-menu.d.ts.map +0 -1
  296. package/build-types/components/editor-interface/content-slot-fill.d.ts +0 -14
  297. package/build-types/components/editor-interface/content-slot-fill.d.ts.map +0 -1
  298. package/src/components/block-settings-menu/content-only-settings-menu.js +0 -185
  299. package/src/components/block-settings-menu/content-only-settings-menu.native.js +0 -4
  300. package/src/components/block-settings-menu/style.scss +0 -6
  301. package/src/components/editor-interface/content-slot-fill.js +0 -10
@@ -0,0 +1,794 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import clsx from 'clsx';
5
+
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import {
10
+ Disabled,
11
+ Composite,
12
+ privateApis as componentsPrivateApis,
13
+ } from '@wordpress/components';
14
+ import { __, _x, sprintf } from '@wordpress/i18n';
15
+ import {
16
+ BlockList,
17
+ privateApis as blockEditorPrivateApis,
18
+ store as blockEditorStore,
19
+ useSettings,
20
+ BlockEditorProvider,
21
+ __unstableEditorStyles as EditorStyles,
22
+ __unstableIframe as Iframe,
23
+ __experimentalUseMultipleOriginColorsAndGradients as useMultipleOriginColorsAndGradients,
24
+ } from '@wordpress/block-editor';
25
+ import { useSelect, dispatch } from '@wordpress/data';
26
+ import { mergeGlobalStyles } from '@wordpress/global-styles-engine';
27
+ import {
28
+ useMemo,
29
+ useState,
30
+ memo,
31
+ useRef,
32
+ useLayoutEffect,
33
+ useEffect,
34
+ forwardRef,
35
+ } from '@wordpress/element';
36
+ import { ENTER, SPACE } from '@wordpress/keycodes';
37
+ import { uploadMedia } from '@wordpress/media-utils';
38
+ import { store as coreStore } from '@wordpress/core-data';
39
+
40
+ /**
41
+ * Internal dependencies
42
+ */
43
+ import { unlock } from '../../lock-unlock';
44
+ import { STYLE_BOOK_IFRAME_STYLES } from './constants';
45
+ import {
46
+ getExamplesByCategory,
47
+ getTopLevelStyleBookCategories,
48
+ } from './categories';
49
+ import { getExamples } from './examples';
50
+ import { GlobalStylesRenderer } from '../global-styles-renderer';
51
+ import {
52
+ STYLE_BOOK_COLOR_GROUPS,
53
+ STYLE_BOOK_PREVIEW_CATEGORIES,
54
+ } from '../style-book/constants';
55
+ import { useGlobalStylesOutputWithConfig } from '../../hooks/use-global-styles-output';
56
+ import { useStyle, useGlobalStyles } from '../global-styles';
57
+ import { store as editorStore } from '../../store';
58
+
59
+ const { ExperimentalBlockEditorProvider } = unlock( blockEditorPrivateApis );
60
+ const { Tabs } = unlock( componentsPrivateApis );
61
+
62
+ function isObjectEmpty( object ) {
63
+ return ! object || Object.keys( object ).length === 0;
64
+ }
65
+
66
+ /**
67
+ * Scrolls to a section within an iframe.
68
+ *
69
+ * @param {string} anchorId The id of the element to scroll to.
70
+ * @param {HTMLIFrameElement} iframe The target iframe.
71
+ */
72
+ const scrollToSection = ( anchorId, iframe ) => {
73
+ if ( ! anchorId || ! iframe || ! iframe?.contentDocument ) {
74
+ return;
75
+ }
76
+
77
+ const element =
78
+ anchorId === 'top'
79
+ ? iframe.contentDocument.body
80
+ : iframe.contentDocument.getElementById( anchorId );
81
+ if ( element ) {
82
+ element.scrollIntoView( {
83
+ behavior: 'smooth',
84
+ } );
85
+ }
86
+ };
87
+
88
+ /**
89
+ * Parses a Block Editor navigation path to build a style book navigation path.
90
+ * The object can be extended to include a category, representing a style book tab/section.
91
+ *
92
+ * @param {string} path An internal Block Editor navigation path.
93
+ * @return {null|{block: string}} An object containing the example to navigate to.
94
+ */
95
+ const getStyleBookNavigationFromPath = ( path ) => {
96
+ if ( path && typeof path === 'string' ) {
97
+ if (
98
+ path === '/' ||
99
+ path.startsWith( '/typography' ) ||
100
+ path.startsWith( '/colors' ) ||
101
+ path.startsWith( '/blocks' )
102
+ ) {
103
+ return {
104
+ top: true,
105
+ };
106
+ }
107
+ }
108
+ return null;
109
+ };
110
+
111
+ /**
112
+ * Retrieves colors, gradients, and duotone filters from Global Styles.
113
+ * The inclusion of default (Core) palettes is controlled by the relevant
114
+ * theme.json property e.g. defaultPalette, defaultGradients, defaultDuotone.
115
+ *
116
+ * @return {Object} Object containing properties for each type of palette.
117
+ */
118
+ function useMultiOriginPalettes() {
119
+ const { colors, gradients } = useMultipleOriginColorsAndGradients();
120
+
121
+ // Add duotone filters to the palettes data.
122
+ const [
123
+ shouldDisplayDefaultDuotones,
124
+ customDuotones,
125
+ themeDuotones,
126
+ defaultDuotones,
127
+ ] = useSettings(
128
+ 'color.defaultDuotone',
129
+ 'color.duotone.custom',
130
+ 'color.duotone.theme',
131
+ 'color.duotone.default'
132
+ );
133
+
134
+ const palettes = useMemo( () => {
135
+ const result = { colors, gradients, duotones: [] };
136
+
137
+ if ( themeDuotones && themeDuotones.length ) {
138
+ result.duotones.push( {
139
+ name: _x(
140
+ 'Theme',
141
+ 'Indicates these duotone filters come from the theme.'
142
+ ),
143
+ slug: 'theme',
144
+ duotones: themeDuotones,
145
+ } );
146
+ }
147
+
148
+ if (
149
+ shouldDisplayDefaultDuotones &&
150
+ defaultDuotones &&
151
+ defaultDuotones.length
152
+ ) {
153
+ result.duotones.push( {
154
+ name: _x(
155
+ 'Default',
156
+ 'Indicates these duotone filters come from WordPress.'
157
+ ),
158
+ slug: 'default',
159
+ duotones: defaultDuotones,
160
+ } );
161
+ }
162
+ if ( customDuotones && customDuotones.length ) {
163
+ result.duotones.push( {
164
+ name: _x(
165
+ 'Custom',
166
+ 'Indicates these doutone filters are created by the user.'
167
+ ),
168
+ slug: 'custom',
169
+ duotones: customDuotones,
170
+ } );
171
+ }
172
+
173
+ return result;
174
+ }, [
175
+ colors,
176
+ gradients,
177
+ customDuotones,
178
+ themeDuotones,
179
+ defaultDuotones,
180
+ shouldDisplayDefaultDuotones,
181
+ ] );
182
+
183
+ return palettes;
184
+ }
185
+
186
+ /**
187
+ * Get deduped examples for single page stylebook.
188
+ * @param {Array} examples Array of examples.
189
+ * @return {Array} Deduped examples.
190
+ */
191
+ export function getExamplesForSinglePageUse( examples ) {
192
+ const examplesForSinglePageUse = [];
193
+ const overviewCategoryExamples = getExamplesByCategory(
194
+ { slug: 'overview' },
195
+ examples
196
+ );
197
+ examplesForSinglePageUse.push( ...overviewCategoryExamples.examples );
198
+ const otherExamples = examples.filter( ( example ) => {
199
+ return (
200
+ example.category !== 'overview' &&
201
+ ! overviewCategoryExamples.examples.find(
202
+ ( overviewExample ) => overviewExample.name === example.name
203
+ )
204
+ );
205
+ } );
206
+ examplesForSinglePageUse.push( ...otherExamples );
207
+
208
+ return examplesForSinglePageUse;
209
+ }
210
+
211
+ /**
212
+ * Applies a block variation to each example by updating its attributes.
213
+ *
214
+ * @param {Array} examples Array of examples
215
+ * @param {string} variation Block variation name.
216
+ * @return {Array} Updated examples with variation applied.
217
+ */
218
+ function applyBlockVariationsToExamples( examples, variation ) {
219
+ if ( ! variation ) {
220
+ return examples;
221
+ }
222
+ return examples.map( ( example ) => {
223
+ return {
224
+ ...example,
225
+ variation,
226
+ blocks: Array.isArray( example.blocks )
227
+ ? example.blocks.map( ( block ) => ( {
228
+ ...block,
229
+ attributes: {
230
+ ...block.attributes,
231
+ style: undefined,
232
+ className: `is-style-${ variation }`,
233
+ },
234
+ } ) )
235
+ : {
236
+ ...example.blocks,
237
+ attributes: {
238
+ ...example.blocks.attributes,
239
+ style: undefined,
240
+ className: `is-style-${ variation }`,
241
+ },
242
+ },
243
+ };
244
+ } );
245
+ }
246
+
247
+ function StyleBook(
248
+ {
249
+ isSelected,
250
+ onClick,
251
+ onSelect,
252
+ showTabs = true,
253
+ userConfig = {},
254
+ path = '',
255
+ },
256
+ ref
257
+ ) {
258
+ const textColor = useStyle( 'color.text' );
259
+ const backgroundColor = useStyle( 'color.background' );
260
+ const colors = useMultiOriginPalettes();
261
+ const examples = useMemo( () => getExamples( colors ), [ colors ] );
262
+ const tabs = useMemo(
263
+ () =>
264
+ getTopLevelStyleBookCategories().filter( ( category ) =>
265
+ examples.some(
266
+ ( example ) => example.category === category.slug
267
+ )
268
+ ),
269
+ [ examples ]
270
+ );
271
+
272
+ const examplesForSinglePageUse = getExamplesForSinglePageUse( examples );
273
+
274
+ const { base: baseConfig } = useGlobalStyles();
275
+ const goTo = getStyleBookNavigationFromPath( path );
276
+
277
+ const mergedConfig = useMemo( () => {
278
+ if ( ! isObjectEmpty( userConfig ) && ! isObjectEmpty( baseConfig ) ) {
279
+ return mergeGlobalStyles( baseConfig, userConfig );
280
+ }
281
+ return {};
282
+ }, [ baseConfig, userConfig ] );
283
+
284
+ const originalSettings = useSelect(
285
+ ( select ) => select( blockEditorStore ).getSettings(),
286
+ []
287
+ );
288
+ const [ globalStyles ] = useGlobalStylesOutputWithConfig( mergedConfig );
289
+
290
+ const settings = useMemo(
291
+ () => ( {
292
+ ...originalSettings,
293
+ styles:
294
+ ! isObjectEmpty( globalStyles ) && ! isObjectEmpty( userConfig )
295
+ ? globalStyles
296
+ : originalSettings.styles,
297
+ isPreviewMode: true,
298
+ } ),
299
+ [ globalStyles, originalSettings, userConfig ]
300
+ );
301
+
302
+ return (
303
+ <div
304
+ ref={ ref }
305
+ className={ clsx( 'editor-style-book', {
306
+ 'is-button': !! onClick,
307
+ } ) }
308
+ style={ {
309
+ color: textColor,
310
+ background: backgroundColor,
311
+ } }
312
+ >
313
+ { showTabs ? (
314
+ <Tabs>
315
+ <div className="editor-style-book__tablist-container">
316
+ <Tabs.TabList>
317
+ { tabs.map( ( tab ) => (
318
+ <Tabs.Tab tabId={ tab.slug } key={ tab.slug }>
319
+ { tab.title }
320
+ </Tabs.Tab>
321
+ ) ) }
322
+ </Tabs.TabList>
323
+ </div>
324
+ { tabs.map( ( tab ) => {
325
+ const categoryDefinition = tab.slug
326
+ ? getTopLevelStyleBookCategories().find(
327
+ ( _category ) => _category.slug === tab.slug
328
+ )
329
+ : null;
330
+ const filteredExamples = categoryDefinition
331
+ ? getExamplesByCategory(
332
+ categoryDefinition,
333
+ examples
334
+ )
335
+ : { examples };
336
+ return (
337
+ <Tabs.TabPanel
338
+ key={ tab.slug }
339
+ tabId={ tab.slug }
340
+ focusable={ false }
341
+ className="editor-style-book__tabpanel"
342
+ >
343
+ <StyleBookBody
344
+ category={ tab.slug }
345
+ examples={ filteredExamples }
346
+ isSelected={ isSelected }
347
+ onSelect={ onSelect }
348
+ settings={ settings }
349
+ title={ tab.title }
350
+ goTo={ goTo }
351
+ />
352
+ </Tabs.TabPanel>
353
+ );
354
+ } ) }
355
+ </Tabs>
356
+ ) : (
357
+ <StyleBookBody
358
+ examples={ { examples: examplesForSinglePageUse } }
359
+ isSelected={ isSelected }
360
+ onClick={ onClick }
361
+ onSelect={ onSelect }
362
+ settings={ settings }
363
+ goTo={ goTo }
364
+ />
365
+ ) }
366
+ </div>
367
+ );
368
+ }
369
+
370
+ /**
371
+ * Style Book Preview component renders the stylebook without the Editor dependency.
372
+ *
373
+ * @param {Object} props Component props.
374
+ * @param {string} props.path Current path in global styles.
375
+ * @param {Function} props.onPathChange Callback when the path changes.
376
+ * @param {Object} props.userConfig User configuration.
377
+ * @param {boolean} props.isStatic Whether the stylebook is static or clickable.
378
+ * @return {Object} Style Book Preview component.
379
+ */
380
+ export const StyleBookPreview = ( {
381
+ userConfig = {},
382
+ isStatic = false,
383
+ path,
384
+ onPathChange,
385
+ } ) => {
386
+ const editorSettings = useSelect(
387
+ ( select ) => select( editorStore ).getEditorSettings(),
388
+ []
389
+ );
390
+
391
+ const canUserUploadMedia = useSelect(
392
+ ( select ) =>
393
+ select( coreStore ).canUser( 'create', {
394
+ kind: 'postType',
395
+ name: 'attachment',
396
+ } ),
397
+ []
398
+ );
399
+
400
+ // Update block editor settings because useMultipleOriginColorsAndGradients fetch colours from there.
401
+ useEffect( () => {
402
+ dispatch( blockEditorStore ).updateSettings( {
403
+ ...editorSettings,
404
+ mediaUpload: canUserUploadMedia ? uploadMedia : undefined,
405
+ } );
406
+ }, [ editorSettings, canUserUploadMedia ] );
407
+
408
+ const [ internalPath, setInternalPath ] = useState( '/' );
409
+ const section = path ?? internalPath;
410
+ const onChangeSection = onPathChange ?? setInternalPath;
411
+
412
+ const isSelected = ( blockName ) => {
413
+ // Match '/blocks/core%2Fbutton' and
414
+ // '/blocks/core%2Fbutton/typography', but not
415
+ // '/blocks/core%2Fbuttons'.
416
+ return (
417
+ section === `/blocks/${ encodeURIComponent( blockName ) }` ||
418
+ section.startsWith(
419
+ `/blocks/${ encodeURIComponent( blockName ) }/`
420
+ )
421
+ );
422
+ };
423
+
424
+ const onSelect = ( blockName, isBlockVariation = false ) => {
425
+ if (
426
+ STYLE_BOOK_COLOR_GROUPS.find(
427
+ ( group ) => group.slug === blockName
428
+ )
429
+ ) {
430
+ // Go to color palettes Global Styles.
431
+ onChangeSection( '/colors/palette' );
432
+ return;
433
+ }
434
+ if ( blockName === 'typography' ) {
435
+ // Go to typography Global Styles.
436
+ onChangeSection( '/typography' );
437
+ return;
438
+ }
439
+
440
+ if ( isBlockVariation ) {
441
+ return;
442
+ }
443
+
444
+ // Now go to the selected block.
445
+ onChangeSection( `/blocks/${ encodeURIComponent( blockName ) }` );
446
+ };
447
+
448
+ const colors = useMultiOriginPalettes();
449
+ const examples = getExamples( colors );
450
+ const examplesForSinglePageUse = getExamplesForSinglePageUse( examples );
451
+
452
+ let previewCategory = null;
453
+ let blockVariation = null;
454
+ if ( section.includes( '/colors' ) ) {
455
+ previewCategory = 'colors';
456
+ } else if ( section.includes( '/typography' ) ) {
457
+ previewCategory = 'text';
458
+ } else if ( section.includes( '/blocks' ) ) {
459
+ previewCategory = 'blocks';
460
+ let blockName = decodeURIComponent( section ).split( '/blocks/' )[ 1 ];
461
+
462
+ // The blockName can contain variations, if so, extract the variation.
463
+ if ( blockName?.includes( '/variations' ) ) {
464
+ [ blockName, blockVariation ] = blockName.split( '/variations/' );
465
+ }
466
+
467
+ if (
468
+ blockName &&
469
+ examples.find( ( example ) => example.name === blockName )
470
+ ) {
471
+ previewCategory = blockName;
472
+ }
473
+ } else if ( ! isStatic ) {
474
+ previewCategory = 'overview';
475
+ }
476
+ const categoryDefinition = STYLE_BOOK_PREVIEW_CATEGORIES.find(
477
+ ( category ) => category.slug === previewCategory
478
+ );
479
+
480
+ const filteredExamples = useMemo( () => {
481
+ // If there's no category definition there may be a single block.
482
+ if ( ! categoryDefinition ) {
483
+ return {
484
+ examples: [
485
+ examples.find(
486
+ ( example ) => example.name === previewCategory
487
+ ),
488
+ ],
489
+ };
490
+ }
491
+
492
+ return getExamplesByCategory( categoryDefinition, examples );
493
+ }, [ categoryDefinition, examples, previewCategory ] );
494
+
495
+ const displayedExamples = useMemo( () => {
496
+ // If there's no preview category, show all examples.
497
+ if ( ! previewCategory ) {
498
+ return { examples: examplesForSinglePageUse };
499
+ }
500
+
501
+ if ( blockVariation ) {
502
+ return {
503
+ examples: applyBlockVariationsToExamples(
504
+ filteredExamples.examples,
505
+ blockVariation
506
+ ),
507
+ };
508
+ }
509
+
510
+ return filteredExamples;
511
+ }, [
512
+ previewCategory,
513
+ examplesForSinglePageUse,
514
+ blockVariation,
515
+ filteredExamples,
516
+ ] );
517
+
518
+ const { base: baseConfig } = useGlobalStyles();
519
+ const goTo = getStyleBookNavigationFromPath( section );
520
+
521
+ const mergedConfig = useMemo( () => {
522
+ if ( ! isObjectEmpty( userConfig ) && ! isObjectEmpty( baseConfig ) ) {
523
+ return mergeGlobalStyles( baseConfig, userConfig );
524
+ }
525
+ return {};
526
+ }, [ baseConfig, userConfig ] );
527
+
528
+ const [ globalStyles ] = useGlobalStylesOutputWithConfig( mergedConfig );
529
+
530
+ const settings = useMemo(
531
+ () => ( {
532
+ ...editorSettings,
533
+ styles:
534
+ ! isObjectEmpty( globalStyles ) && ! isObjectEmpty( userConfig )
535
+ ? globalStyles
536
+ : editorSettings.styles,
537
+ isPreviewMode: true,
538
+ } ),
539
+ [ globalStyles, editorSettings, userConfig ]
540
+ );
541
+
542
+ return (
543
+ <div className="editor-style-book">
544
+ <BlockEditorProvider settings={ settings }>
545
+ <GlobalStylesRenderer disableRootPadding />
546
+ <StyleBookBody
547
+ examples={ displayedExamples }
548
+ settings={ settings }
549
+ goTo={ goTo }
550
+ isSelected={ ! isStatic ? isSelected : null }
551
+ onSelect={ ! isStatic ? onSelect : null }
552
+ />
553
+ </BlockEditorProvider>
554
+ </div>
555
+ );
556
+ };
557
+
558
+ export const StyleBookBody = ( {
559
+ examples,
560
+ isSelected,
561
+ onClick,
562
+ onSelect,
563
+ settings,
564
+ title,
565
+ goTo,
566
+ } ) => {
567
+ const [ isFocused, setIsFocused ] = useState( false );
568
+ const [ hasIframeLoaded, setHasIframeLoaded ] = useState( false );
569
+ const iframeRef = useRef( null );
570
+ // The presence of an `onClick` prop indicates that the Style Book is being used as a button.
571
+ // In this case, add additional props to the iframe to make it behave like a button.
572
+ const buttonModeProps = {
573
+ role: 'button',
574
+ onFocus: () => setIsFocused( true ),
575
+ onBlur: () => setIsFocused( false ),
576
+ onKeyDown: ( event ) => {
577
+ if ( event.defaultPrevented ) {
578
+ return;
579
+ }
580
+ const { keyCode } = event;
581
+ if ( onClick && ( keyCode === ENTER || keyCode === SPACE ) ) {
582
+ event.preventDefault();
583
+ onClick( event );
584
+ }
585
+ },
586
+ onClick: ( event ) => {
587
+ if ( event.defaultPrevented ) {
588
+ return;
589
+ }
590
+ if ( onClick ) {
591
+ event.preventDefault();
592
+ onClick( event );
593
+ }
594
+ },
595
+ readonly: true,
596
+ };
597
+
598
+ const handleLoad = () => setHasIframeLoaded( true );
599
+ useLayoutEffect( () => {
600
+ if ( hasIframeLoaded && iframeRef?.current ) {
601
+ if ( goTo?.top ) {
602
+ scrollToSection( 'top', iframeRef?.current );
603
+ }
604
+ }
605
+ }, [ iframeRef?.current, goTo, scrollToSection, hasIframeLoaded ] );
606
+
607
+ return (
608
+ <Iframe
609
+ onLoad={ handleLoad }
610
+ ref={ iframeRef }
611
+ className={ clsx( 'editor-style-book__iframe', {
612
+ 'is-focused': isFocused && !! onClick,
613
+ 'is-button': !! onClick,
614
+ } ) }
615
+ name="style-book-canvas"
616
+ tabIndex={ 0 }
617
+ { ...( onClick ? buttonModeProps : {} ) }
618
+ >
619
+ <EditorStyles styles={ settings.styles } />
620
+ <style>
621
+ { STYLE_BOOK_IFRAME_STYLES }
622
+ { !! onClick &&
623
+ 'body { cursor: pointer; } body * { pointer-events: none; }' }
624
+ </style>
625
+ <Examples
626
+ className="editor-style-book__examples"
627
+ filteredExamples={ examples }
628
+ label={
629
+ title
630
+ ? sprintf(
631
+ // translators: %s: Category of blocks, e.g. Text.
632
+ __( 'Examples of blocks in the %s category' ),
633
+ title
634
+ )
635
+ : __( 'Examples of blocks' )
636
+ }
637
+ isSelected={ isSelected }
638
+ onSelect={ onSelect }
639
+ key={ title }
640
+ />
641
+ </Iframe>
642
+ );
643
+ };
644
+
645
+ const Examples = memo(
646
+ ( { className, filteredExamples, label, isSelected, onSelect } ) => {
647
+ return (
648
+ <Composite
649
+ orientation="vertical"
650
+ className={ className }
651
+ aria-label={ label }
652
+ role="grid"
653
+ >
654
+ { !! filteredExamples?.examples?.length &&
655
+ filteredExamples.examples.map( ( example ) => (
656
+ <Example
657
+ key={ example.name }
658
+ id={ `example-${ example.name }` }
659
+ title={ example.title }
660
+ content={ example.content }
661
+ blocks={ example.blocks }
662
+ isSelected={ isSelected?.( example.name ) }
663
+ onClick={
664
+ !! onSelect
665
+ ? () =>
666
+ onSelect(
667
+ example.name,
668
+ !! example.variation
669
+ )
670
+ : null
671
+ }
672
+ />
673
+ ) ) }
674
+ { !! filteredExamples?.subcategories?.length &&
675
+ filteredExamples.subcategories.map( ( subcategory ) => (
676
+ <Composite.Group
677
+ className="editor-style-book__subcategory"
678
+ key={ `subcategory-${ subcategory.slug }` }
679
+ >
680
+ <Composite.GroupLabel>
681
+ <h2 className="editor-style-book__subcategory-title">
682
+ { subcategory.title }
683
+ </h2>
684
+ </Composite.GroupLabel>
685
+ <Subcategory
686
+ examples={ subcategory.examples }
687
+ isSelected={ isSelected }
688
+ onSelect={ onSelect }
689
+ />
690
+ </Composite.Group>
691
+ ) ) }
692
+ </Composite>
693
+ );
694
+ }
695
+ );
696
+
697
+ const Subcategory = ( { examples, isSelected, onSelect } ) => {
698
+ return (
699
+ !! examples?.length &&
700
+ examples.map( ( example ) => (
701
+ <Example
702
+ key={ example.name }
703
+ id={ `example-${ example.name }` }
704
+ title={ example.title }
705
+ content={ example.content }
706
+ blocks={ example.blocks }
707
+ isSelected={ isSelected?.( example.name ) }
708
+ onClick={ !! onSelect ? () => onSelect( example.name ) : null }
709
+ />
710
+ ) )
711
+ );
712
+ };
713
+
714
+ const disabledExamples = [ 'example-duotones' ];
715
+
716
+ const Example = ( { id, title, blocks, isSelected, onClick, content } ) => {
717
+ const originalSettings = useSelect(
718
+ ( select ) => select( blockEditorStore ).getSettings(),
719
+ []
720
+ );
721
+ const settings = useMemo(
722
+ () => ( {
723
+ ...originalSettings,
724
+ focusMode: false, // Disable "Spotlight mode".
725
+ isPreviewMode: true,
726
+ } ),
727
+ [ originalSettings ]
728
+ );
729
+
730
+ // Cache the list of blocks to avoid additional processing when the component is re-rendered.
731
+ const renderedBlocks = useMemo(
732
+ () => ( Array.isArray( blocks ) ? blocks : [ blocks ] ),
733
+ [ blocks ]
734
+ );
735
+
736
+ const disabledProps =
737
+ disabledExamples.includes( id ) || ! onClick
738
+ ? {
739
+ disabled: true,
740
+ accessibleWhenDisabled: !! onClick,
741
+ }
742
+ : {};
743
+
744
+ return (
745
+ <div role="row">
746
+ <div role="gridcell">
747
+ <Composite.Item
748
+ className={ clsx( 'editor-style-book__example', {
749
+ 'is-selected': isSelected,
750
+ 'is-disabled-example': !! disabledProps?.disabled,
751
+ } ) }
752
+ id={ id }
753
+ aria-label={
754
+ !! onClick
755
+ ? sprintf(
756
+ // translators: %s: Title of a block, e.g. Heading.
757
+ __( 'Open %s styles in Styles panel' ),
758
+ title
759
+ )
760
+ : undefined
761
+ }
762
+ render={ <div /> }
763
+ role={ !! onClick ? 'button' : null }
764
+ onClick={ onClick }
765
+ { ...disabledProps }
766
+ >
767
+ <span className="editor-style-book__example-title">
768
+ { title }
769
+ </span>
770
+ <div
771
+ className="editor-style-book__example-preview"
772
+ aria-hidden
773
+ >
774
+ <Disabled className="editor-style-book__example-preview__content">
775
+ { content ? (
776
+ content
777
+ ) : (
778
+ <ExperimentalBlockEditorProvider
779
+ value={ renderedBlocks }
780
+ settings={ settings }
781
+ >
782
+ <EditorStyles />
783
+ <BlockList renderAppender={ false } />
784
+ </ExperimentalBlockEditorProvider>
785
+ ) }
786
+ </Disabled>
787
+ </div>
788
+ </Composite.Item>
789
+ </div>
790
+ </div>
791
+ );
792
+ };
793
+
794
+ export default forwardRef( StyleBook );