@wordpress/block-library 8.10.0 → 8.11.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 (278) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/block/edit.native.js +17 -10
  3. package/build/block/edit.native.js.map +1 -1
  4. package/build/code/index.js +1 -0
  5. package/build/code/index.js.map +1 -1
  6. package/build/column/index.js +1 -1
  7. package/build/columns/transforms.js +1 -5
  8. package/build/columns/transforms.js.map +1 -1
  9. package/build/cover/edit/resizable-cover-popover.js +3 -3
  10. package/build/cover/edit/resizable-cover-popover.js.map +1 -1
  11. package/build/file/interactivity.js +19 -0
  12. package/build/file/interactivity.js.map +1 -0
  13. package/build/file/{utils.js → utils/index.js} +1 -1
  14. package/build/file/utils/index.js.map +1 -0
  15. package/build/freeform/modal.js +20 -17
  16. package/build/freeform/modal.js.map +1 -1
  17. package/build/gallery/v1/edit.js +1 -7
  18. package/build/gallery/v1/edit.js.map +1 -1
  19. package/build/gallery/v1/gallery-image.native.js +1 -3
  20. package/build/gallery/v1/gallery-image.native.js.map +1 -1
  21. package/build/group/transforms.js +0 -5
  22. package/build/group/transforms.js.map +1 -1
  23. package/build/image/deprecated.js +2 -4
  24. package/build/image/deprecated.js.map +1 -1
  25. package/build/image/edit.js +13 -11
  26. package/build/image/edit.js.map +1 -1
  27. package/build/image/image.js +7 -12
  28. package/build/image/image.js.map +1 -1
  29. package/build/image/index.js +3 -0
  30. package/build/image/index.js.map +1 -1
  31. package/build/image/interactivity.js +102 -0
  32. package/build/image/interactivity.js.map +1 -0
  33. package/build/image/save.js +2 -4
  34. package/build/image/save.js.map +1 -1
  35. package/build/image/utils.js +10 -18
  36. package/build/image/utils.js.map +1 -1
  37. package/build/latest-posts/edit.native.js +1 -3
  38. package/build/latest-posts/edit.native.js.map +1 -1
  39. package/build/list/edit.js +1 -1
  40. package/build/list/edit.js.map +1 -1
  41. package/build/list-item/edit.native.js +1 -1
  42. package/build/list-item/edit.native.js.map +1 -1
  43. package/build/list-item/transforms.js +4 -1
  44. package/build/list-item/transforms.js.map +1 -1
  45. package/build/media-text/deprecated.js +4 -6
  46. package/build/media-text/deprecated.js.map +1 -1
  47. package/build/media-text/edit.js +13 -11
  48. package/build/media-text/edit.js.map +1 -1
  49. package/build/media-text/media-container.js +3 -3
  50. package/build/media-text/media-container.js.map +1 -1
  51. package/build/media-text/save.js +1 -3
  52. package/build/media-text/save.js.map +1 -1
  53. package/build/navigation/constants.js +3 -1
  54. package/build/navigation/constants.js.map +1 -1
  55. package/build/navigation/edit/inner-blocks.js +1 -0
  56. package/build/navigation/edit/inner-blocks.js.map +1 -1
  57. package/build/navigation/edit/leaf-more-menu.js +148 -0
  58. package/build/navigation/edit/leaf-more-menu.js.map +1 -0
  59. package/build/navigation/edit/menu-inspector-controls.js +53 -8
  60. package/build/navigation/edit/menu-inspector-controls.js.map +1 -1
  61. package/build/navigation/edit/navigation-menu-delete-control.js +6 -6
  62. package/build/navigation/edit/navigation-menu-delete-control.js.map +1 -1
  63. package/build/navigation/edit/unsaved-inner-blocks.js +8 -19
  64. package/build/navigation/edit/unsaved-inner-blocks.js.map +1 -1
  65. package/build/navigation/interactivity.js +24 -6
  66. package/build/navigation/interactivity.js.map +1 -1
  67. package/build/navigation-link/edit.js +6 -4
  68. package/build/navigation-link/edit.js.map +1 -1
  69. package/build/navigation-link/update-attributes.js +5 -5
  70. package/build/navigation-link/update-attributes.js.map +1 -1
  71. package/build/navigation-submenu/edit.js +6 -4
  72. package/build/navigation-submenu/edit.js.map +1 -1
  73. package/build/pattern/edit.js +42 -8
  74. package/build/pattern/edit.js.map +1 -1
  75. package/build/pattern/index.js +12 -5
  76. package/build/pattern/index.js.map +1 -1
  77. package/build/pattern/v1/edit.js +57 -0
  78. package/build/pattern/v1/edit.js.map +1 -0
  79. package/build/post-title/edit.js +10 -3
  80. package/build/post-title/edit.js.map +1 -1
  81. package/build/quote/transforms.js +9 -12
  82. package/build/quote/transforms.js.map +1 -1
  83. package/build/social-link/edit.js +21 -4
  84. package/build/social-link/edit.js.map +1 -1
  85. package/build/template-part/edit/index.js +1 -7
  86. package/build/template-part/edit/index.js.map +1 -1
  87. package/build/template-part/edit/utils/hooks.js +2 -2
  88. package/build/template-part/edit/utils/hooks.js.map +1 -1
  89. package/build/utils/interactivity/directives.js +50 -22
  90. package/build/utils/interactivity/directives.js.map +1 -1
  91. package/build/utils/interactivity/hooks.js +76 -12
  92. package/build/utils/interactivity/hooks.js.map +1 -1
  93. package/build/utils/interactivity/portals.js +108 -0
  94. package/build/utils/interactivity/portals.js.map +1 -0
  95. package/build-module/block/edit.native.js +7 -1
  96. package/build-module/block/edit.native.js.map +1 -1
  97. package/build-module/code/index.js +1 -0
  98. package/build-module/code/index.js.map +1 -1
  99. package/build-module/column/index.js +1 -1
  100. package/build-module/columns/transforms.js +1 -5
  101. package/build-module/columns/transforms.js.map +1 -1
  102. package/build-module/cover/edit/resizable-cover-popover.js +3 -3
  103. package/build-module/cover/edit/resizable-cover-popover.js.map +1 -1
  104. package/build-module/file/interactivity.js +15 -0
  105. package/build-module/file/interactivity.js.map +1 -0
  106. package/build-module/file/{utils.js → utils/index.js} +1 -1
  107. package/build-module/file/utils/index.js.map +1 -0
  108. package/build-module/freeform/modal.js +19 -18
  109. package/build-module/freeform/modal.js.map +1 -1
  110. package/build-module/gallery/v1/edit.js +1 -6
  111. package/build-module/gallery/v1/edit.js.map +1 -1
  112. package/build-module/gallery/v1/gallery-image.native.js +1 -2
  113. package/build-module/gallery/v1/gallery-image.native.js.map +1 -1
  114. package/build-module/group/transforms.js +0 -5
  115. package/build-module/group/transforms.js.map +1 -1
  116. package/build-module/image/deprecated.js +2 -3
  117. package/build-module/image/deprecated.js.map +1 -1
  118. package/build-module/image/edit.js +12 -11
  119. package/build-module/image/edit.js.map +1 -1
  120. package/build-module/image/image.js +7 -11
  121. package/build-module/image/image.js.map +1 -1
  122. package/build-module/image/index.js +3 -0
  123. package/build-module/image/index.js.map +1 -1
  124. package/build-module/image/interactivity.js +99 -0
  125. package/build-module/image/interactivity.js.map +1 -0
  126. package/build-module/image/save.js +2 -3
  127. package/build-module/image/save.js.map +1 -1
  128. package/build-module/image/utils.js +10 -17
  129. package/build-module/image/utils.js.map +1 -1
  130. package/build-module/latest-posts/edit.native.js +1 -2
  131. package/build-module/latest-posts/edit.native.js.map +1 -1
  132. package/build-module/list/edit.js +1 -1
  133. package/build-module/list/edit.js.map +1 -1
  134. package/build-module/list-item/edit.native.js +1 -1
  135. package/build-module/list-item/edit.native.js.map +1 -1
  136. package/build-module/list-item/transforms.js +5 -2
  137. package/build-module/list-item/transforms.js.map +1 -1
  138. package/build-module/media-text/deprecated.js +4 -5
  139. package/build-module/media-text/deprecated.js.map +1 -1
  140. package/build-module/media-text/edit.js +13 -12
  141. package/build-module/media-text/edit.js.map +1 -1
  142. package/build-module/media-text/media-container.js +3 -3
  143. package/build-module/media-text/media-container.js.map +1 -1
  144. package/build-module/media-text/save.js +1 -2
  145. package/build-module/media-text/save.js.map +1 -1
  146. package/build-module/navigation/constants.js +1 -0
  147. package/build-module/navigation/constants.js.map +1 -1
  148. package/build-module/navigation/edit/inner-blocks.js +2 -1
  149. package/build-module/navigation/edit/inner-blocks.js.map +1 -1
  150. package/build-module/navigation/edit/leaf-more-menu.js +132 -0
  151. package/build-module/navigation/edit/leaf-more-menu.js.map +1 -0
  152. package/build-module/navigation/edit/menu-inspector-controls.js +52 -9
  153. package/build-module/navigation/edit/menu-inspector-controls.js.map +1 -1
  154. package/build-module/navigation/edit/navigation-menu-delete-control.js +7 -7
  155. package/build-module/navigation/edit/navigation-menu-delete-control.js.map +1 -1
  156. package/build-module/navigation/edit/unsaved-inner-blocks.js +8 -16
  157. package/build-module/navigation/edit/unsaved-inner-blocks.js.map +1 -1
  158. package/build-module/navigation/interactivity.js +24 -6
  159. package/build-module/navigation/interactivity.js.map +1 -1
  160. package/build-module/navigation-link/edit.js +6 -4
  161. package/build-module/navigation-link/edit.js.map +1 -1
  162. package/build-module/navigation-link/update-attributes.js +4 -4
  163. package/build-module/navigation-link/update-attributes.js.map +1 -1
  164. package/build-module/navigation-submenu/edit.js +6 -4
  165. package/build-module/navigation-submenu/edit.js.map +1 -1
  166. package/build-module/pattern/edit.js +42 -9
  167. package/build-module/pattern/edit.js.map +1 -1
  168. package/build-module/pattern/index.js +12 -3
  169. package/build-module/pattern/index.js.map +1 -1
  170. package/build-module/pattern/v1/edit.js +48 -0
  171. package/build-module/pattern/v1/edit.js.map +1 -0
  172. package/build-module/post-title/edit.js +10 -3
  173. package/build-module/post-title/edit.js.map +1 -1
  174. package/build-module/quote/transforms.js +9 -12
  175. package/build-module/quote/transforms.js.map +1 -1
  176. package/build-module/social-link/edit.js +20 -5
  177. package/build-module/social-link/edit.js.map +1 -1
  178. package/build-module/template-part/edit/index.js +1 -6
  179. package/build-module/template-part/edit/index.js.map +1 -1
  180. package/build-module/template-part/edit/utils/hooks.js +1 -1
  181. package/build-module/template-part/edit/utils/hooks.js.map +1 -1
  182. package/build-module/utils/interactivity/directives.js +49 -22
  183. package/build-module/utils/interactivity/directives.js.map +1 -1
  184. package/build-module/utils/interactivity/hooks.js +77 -13
  185. package/build-module/utils/interactivity/hooks.js.map +1 -1
  186. package/build-module/utils/interactivity/portals.js +100 -0
  187. package/build-module/utils/interactivity/portals.js.map +1 -0
  188. package/build-style/common-rtl.css +1 -1
  189. package/build-style/common.css +1 -1
  190. package/build-style/cover/style-rtl.css +1 -2
  191. package/build-style/cover/style.css +1 -2
  192. package/build-style/editor-rtl.css +68 -0
  193. package/build-style/editor.css +68 -0
  194. package/build-style/file/editor-rtl.css +3 -0
  195. package/build-style/file/editor.css +3 -0
  196. package/build-style/freeform/editor-rtl.css +29 -0
  197. package/build-style/freeform/editor.css +29 -0
  198. package/build-style/gallery/style-rtl.css +2 -4
  199. package/build-style/gallery/style.css +2 -4
  200. package/build-style/image/style-rtl.css +98 -0
  201. package/build-style/image/style.css +98 -0
  202. package/build-style/navigation/editor-rtl.css +36 -0
  203. package/build-style/navigation/editor.css +36 -0
  204. package/build-style/post-comments-form/style-rtl.css +1 -1
  205. package/build-style/post-comments-form/style.css +1 -1
  206. package/build-style/style-rtl.css +103 -9
  207. package/build-style/style.css +103 -9
  208. package/build-style/video/style-rtl.css +1 -2
  209. package/build-style/video/style.css +1 -2
  210. package/package.json +32 -32
  211. package/src/block/edit.native.js +18 -4
  212. package/src/buttons/test/edit.native.js +0 -9
  213. package/src/code/block.json +1 -0
  214. package/src/column/block.json +1 -1
  215. package/src/columns/test/__snapshots__/transforms.native.js.snap +1 -1
  216. package/src/columns/test/transforms.native.js +3 -5
  217. package/src/columns/transforms.js +2 -8
  218. package/src/comments/index.php +1 -6
  219. package/src/cover/edit/resizable-cover-popover.js +2 -1
  220. package/src/file/editor.scss +4 -0
  221. package/src/file/interactivity.js +15 -0
  222. package/src/freeform/editor.scss +45 -0
  223. package/src/freeform/modal.js +22 -19
  224. package/src/gallery/v1/edit.js +1 -6
  225. package/src/gallery/v1/gallery-image.native.js +1 -2
  226. package/src/group/test/__snapshots__/transforms.native.js.snap +1 -1
  227. package/src/group/test/transforms.native.js +3 -5
  228. package/src/group/transforms.js +0 -7
  229. package/src/image/block.json +3 -0
  230. package/src/image/deprecated.js +2 -3
  231. package/src/image/edit.js +18 -18
  232. package/src/image/image.js +8 -11
  233. package/src/image/index.php +75 -2
  234. package/src/image/interactivity.js +113 -0
  235. package/src/image/save.js +4 -3
  236. package/src/image/style.scss +113 -0
  237. package/src/image/utils.js +11 -18
  238. package/src/latest-posts/edit.native.js +1 -4
  239. package/src/list/edit.js +1 -1
  240. package/src/list/test/edit.native.js +80 -1
  241. package/src/list-item/edit.native.js +1 -1
  242. package/src/list-item/transforms.js +4 -2
  243. package/src/media-text/deprecated.js +4 -5
  244. package/src/media-text/edit.js +12 -10
  245. package/src/media-text/media-container.js +3 -3
  246. package/src/media-text/save.js +1 -2
  247. package/src/navigation/constants.js +5 -0
  248. package/src/navigation/edit/inner-blocks.js +6 -1
  249. package/src/navigation/edit/leaf-more-menu.js +170 -0
  250. package/src/navigation/edit/menu-inspector-controls.js +78 -10
  251. package/src/navigation/edit/navigation-menu-delete-control.js +29 -29
  252. package/src/navigation/edit/unsaved-inner-blocks.js +11 -24
  253. package/src/navigation/editor.scss +10 -0
  254. package/src/navigation/index.php +4 -1
  255. package/src/navigation/interactivity.js +9 -2
  256. package/src/navigation-link/edit.js +8 -2
  257. package/src/navigation-link/update-attributes.js +2 -2
  258. package/src/navigation-submenu/edit.js +8 -2
  259. package/src/pattern/block.json +4 -0
  260. package/src/pattern/edit.js +53 -16
  261. package/src/pattern/index.js +5 -4
  262. package/src/pattern/index.php +14 -1
  263. package/src/pattern/v1/edit.js +57 -0
  264. package/src/post-comments-form/style.scss +3 -1
  265. package/src/post-title/edit.js +50 -44
  266. package/src/quote/test/__snapshots__/transforms.native.js.snap +1 -1
  267. package/src/quote/test/transforms.native.js +3 -5
  268. package/src/quote/transforms.js +9 -13
  269. package/src/social-link/edit.js +51 -26
  270. package/src/template-part/edit/index.js +4 -6
  271. package/src/template-part/edit/utils/hooks.js +1 -1
  272. package/src/template-part/index.php +2 -2
  273. package/src/utils/interactivity/directives.js +27 -6
  274. package/src/utils/interactivity/hooks.js +83 -14
  275. package/src/utils/interactivity/portals.js +98 -0
  276. package/build/file/utils.js.map +0 -1
  277. package/build-module/file/utils.js.map +0 -1
  278. /package/src/file/{utils.js → utils/index.js} +0 -0
@@ -35,6 +35,10 @@
35
35
 
36
36
  a {
37
37
  min-width: 1em;
38
+
39
+ &:not(.wp-block-file__button) {
40
+ display: inline-block;
41
+ }
38
42
  }
39
43
 
40
44
  .wp-block-file__button-richtext-wrapper {
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import { store } from '../utils/interactivity';
5
+ import { browserSupportsPdfs as hasPdfPreview } from './utils';
6
+
7
+ store( {
8
+ selectors: {
9
+ core: {
10
+ file: {
11
+ hasPdfPreview,
12
+ },
13
+ },
14
+ },
15
+ } );
@@ -374,3 +374,48 @@ div[data-type="core/freeform"] {
374
374
  display: block;
375
375
  }
376
376
  }
377
+
378
+ .block-editor-freeform-modal {
379
+ .components-modal__frame {
380
+ // On large screens, make the TinyMCE edit area grow to take all the
381
+ // available height so that the Cancel/Save buttons are always into the
382
+ // view. On smaller screens, the modal content is scrollable.
383
+ @include break-large() {
384
+ // On medium and large screens, the modal component sets a max-height.
385
+ // We want the modal to be as tall as possible also when the content is short.
386
+ height: 9999rem;
387
+
388
+ .components-modal__header + div {
389
+ height: 100%;
390
+ }
391
+
392
+ .mce-tinymce {
393
+ height: calc(100% - #{$button-size} - #{$grid-unit-20});
394
+ }
395
+
396
+ .mce-container-body {
397
+ height: 100%;
398
+ display: flex;
399
+ flex-direction: column;
400
+ }
401
+
402
+ .mce-edit-area {
403
+ flex-grow: 1;
404
+ display: flex;
405
+ flex-direction: column;
406
+
407
+ iframe {
408
+ flex-grow: 1;
409
+ // Override the height TinyMCE sets via JavaScript so that it
410
+ // can shrink to a smaller height. The actual height is
411
+ // determined by Flexbox.
412
+ height: 10px !important;
413
+ }
414
+ }
415
+ }
416
+ }
417
+
418
+ &__actions {
419
+ margin-top: $grid-unit-20;
420
+ }
421
+ }
@@ -7,6 +7,8 @@ import {
7
7
  ToolbarButton,
8
8
  Modal,
9
9
  Button,
10
+ Flex,
11
+ FlexItem,
10
12
  } from '@wordpress/components';
11
13
  import { useEffect, useState, RawHTML } from '@wordpress/element';
12
14
  import { __ } from '@wordpress/i18n';
@@ -27,7 +29,6 @@ function ClassicEdit( props ) {
27
29
  window.wp.oldEditor.initialize( props.id, {
28
30
  tinymce: {
29
31
  ...settings,
30
- height: 500,
31
32
  setup( editor ) {
32
33
  editor.on( 'init', () => {
33
34
  const doc = editor.getDoc();
@@ -58,35 +59,38 @@ export default function ModalEdit( props ) {
58
59
  } = props;
59
60
  const [ isOpen, setOpen ] = useState( false );
60
61
  const id = `editor-${ clientId }`;
61
- const label = __( 'Classic Edit' );
62
+
63
+ const onClose = () => ( content ? setOpen( false ) : onReplace( [] ) );
62
64
 
63
65
  return (
64
66
  <>
65
67
  <BlockControls>
66
68
  <ToolbarGroup>
67
69
  <ToolbarButton onClick={ () => setOpen( true ) }>
68
- { label }
70
+ { __( 'Edit' ) }
69
71
  </ToolbarButton>
70
72
  </ToolbarGroup>
71
73
  </BlockControls>
72
74
  { content && <RawHTML>{ content }</RawHTML> }
73
75
  { ( isOpen || ! content ) && (
74
- <Modal title={ label } __experimentalHideHeader={ true }>
75
- <h2
76
- style={ {
77
- display: 'flex',
78
- justifyContent: 'space-between',
79
- } }
76
+ <Modal
77
+ title={ __( 'Classic Editor' ) }
78
+ onRequestClose={ onClose }
79
+ shouldCloseOnClickOutside={ false }
80
+ overlayClassName="block-editor-freeform-modal"
81
+ >
82
+ <ClassicEdit id={ id } defaultValue={ content } />
83
+ <Flex
84
+ className="block-editor-freeform-modal__actions"
85
+ justify="flex-end"
86
+ expanded={ false }
80
87
  >
81
- <div>{ label }</div>
82
- <div>
83
- <Button
84
- onClick={ () =>
85
- content ? setOpen( false ) : onReplace( [] )
86
- }
87
- >
88
+ <FlexItem>
89
+ <Button variant="tertiary" onClick={ onClose }>
88
90
  { __( 'Cancel' ) }
89
91
  </Button>
92
+ </FlexItem>
93
+ <FlexItem>
90
94
  <Button
91
95
  variant="primary"
92
96
  onClick={ () => {
@@ -101,9 +105,8 @@ export default function ModalEdit( props ) {
101
105
  >
102
106
  { __( 'Save' ) }
103
107
  </Button>
104
- </div>
105
- </h2>
106
- <ClassicEdit id={ id } defaultValue={ content } />
108
+ </FlexItem>
109
+ </Flex>
107
110
  </Modal>
108
111
  ) }
109
112
  </>
@@ -1,8 +1,3 @@
1
- /**
2
- * External dependencies
3
- */
4
- import { isEmpty } from 'lodash';
5
-
6
1
  /**
7
2
  * WordPress dependencies
8
3
  */
@@ -385,7 +380,7 @@ function GalleryEdit( props ) {
385
380
  }
386
381
 
387
382
  const imageSizeOptions = getImagesSizeOptions();
388
- const shouldShowSizeOptions = hasImages && ! isEmpty( imageSizeOptions );
383
+ const shouldShowSizeOptions = hasImages && imageSizeOptions.length > 0;
389
384
 
390
385
  return (
391
386
  <>
@@ -7,7 +7,6 @@ import {
7
7
  ScrollView,
8
8
  TouchableWithoutFeedback,
9
9
  } from 'react-native';
10
- import { isEmpty } from 'lodash';
11
10
 
12
11
  /**
13
12
  * WordPress dependencies
@@ -334,7 +333,7 @@ class GalleryImage extends Component {
334
333
  accessibilityLabelImageContainer() {
335
334
  const { caption, 'aria-label': ariaLabel } = this.props;
336
335
 
337
- return isEmpty( caption )
336
+ return ! caption
338
337
  ? ariaLabel
339
338
  : ariaLabel +
340
339
  '. ' +
@@ -20,7 +20,7 @@ exports[`Group block transforms to Columns block 1`] = `
20
20
  <!-- /wp:columns -->"
21
21
  `;
22
22
 
23
- exports[`Group block transforms unwraps content 1`] = `
23
+ exports[`Group block transforms ungroups block 1`] = `
24
24
  "<!-- wp:paragraph -->
25
25
  <p>One.</p>
26
26
  <!-- /wp:paragraph -->
@@ -44,14 +44,13 @@ describe( `${ block } block transforms`, () => {
44
44
  expect( getEditorHtml() ).toMatchSnapshot();
45
45
  } );
46
46
 
47
- it( 'unwraps content', async () => {
47
+ it( 'ungroups block', async () => {
48
48
  const screen = await initializeEditor( { initialHtml } );
49
49
  const { getByText } = screen;
50
50
  fireEvent.press( getBlock( screen, block ) );
51
51
 
52
52
  await openBlockActionsMenu( screen );
53
- fireEvent.press( getByText( 'Transform block…' ) );
54
- fireEvent.press( getByText( 'Unwrap' ) );
53
+ fireEvent.press( getByText( 'Ungroup' ) );
55
54
 
56
55
  // The first block created is the content of the Paragraph block.
57
56
  const paragraph = getBlock( screen, 'Paragraph', 0 );
@@ -67,8 +66,7 @@ describe( `${ block } block transforms`, () => {
67
66
  const screen = await initializeEditor( { initialHtml } );
68
67
  const transformOptions = await getBlockTransformOptions(
69
68
  screen,
70
- block,
71
- { canUnwrap: true }
69
+ block
72
70
  );
73
71
  expect( transformOptions ).toHaveLength( blockTransforms.length );
74
72
  } );
@@ -48,13 +48,6 @@ const transforms = {
48
48
  },
49
49
  },
50
50
  ],
51
- to: [
52
- {
53
- type: 'block',
54
- blocks: [ '*' ],
55
- transform: ( attributes, innerBlocks ) => innerBlocks,
56
- },
57
- ],
58
51
  };
59
52
 
60
53
  export default transforms;
@@ -80,6 +80,9 @@
80
80
  "source": "attribute",
81
81
  "selector": "figure > a",
82
82
  "attribute": "target"
83
+ },
84
+ "behaviors": {
85
+ "type": "object"
83
86
  }
84
87
  },
85
88
  "supports": {
@@ -2,7 +2,6 @@
2
2
  * External dependencies
3
3
  */
4
4
  import classnames from 'classnames';
5
- import { isEmpty } from 'lodash';
6
5
 
7
6
  /**
8
7
  * WordPress dependencies
@@ -122,7 +121,7 @@ const deprecated = [
122
121
  title,
123
122
  } = attributes;
124
123
 
125
- const newRel = isEmpty( rel ) ? undefined : rel;
124
+ const newRel = ! rel ? undefined : rel;
126
125
 
127
126
  const classes = classnames( {
128
127
  [ `align${ align }` ]: align,
@@ -202,7 +201,7 @@ const deprecated = [
202
201
  title,
203
202
  } = attributes;
204
203
 
205
- const newRel = isEmpty( rel ) ? undefined : rel;
204
+ const newRel = ! rel ? undefined : rel;
206
205
 
207
206
  const classes = classnames( {
208
207
  [ `align${ align }` ]: align,
package/src/image/edit.js CHANGED
@@ -2,7 +2,6 @@
2
2
  * External dependencies
3
3
  */
4
4
  import classnames from 'classnames';
5
- import { isEmpty } from 'lodash';
6
5
 
7
6
  /**
8
7
  * WordPress dependencies
@@ -18,6 +17,7 @@ import {
18
17
  useBlockProps,
19
18
  store as blockEditorStore,
20
19
  __experimentalUseBorderProps as useBorderProps,
20
+ privateApis as blockEditorPrivateApis,
21
21
  } from '@wordpress/block-editor';
22
22
  import { useEffect, useRef, useState } from '@wordpress/element';
23
23
  import { __ } from '@wordpress/i18n';
@@ -28,6 +28,7 @@ import { store as noticesStore } from '@wordpress/notices';
28
28
  * Internal dependencies
29
29
  */
30
30
  import Image from './image';
31
+ import { unlock } from '../private-apis';
31
32
 
32
33
  /**
33
34
  * Module constants
@@ -40,6 +41,8 @@ import {
40
41
  ALLOWED_MEDIA_TYPES,
41
42
  } from './constants';
42
43
 
44
+ const { useBlockEditingMode } = unlock( blockEditorPrivateApis );
45
+
43
46
  export const pickRelevantMediaFiles = ( image, size ) => {
44
47
  const imageProps = Object.fromEntries(
45
48
  Object.entries( image ?? {} ).filter( ( [ key ] ) =>
@@ -125,20 +128,15 @@ export function ImageEdit( {
125
128
  }, [ caption ] );
126
129
 
127
130
  const ref = useRef();
128
- const { imageDefaultSize, mediaUpload, isContentLocked } = useSelect(
129
- ( select ) => {
130
- const { getSettings, __unstableGetContentLockingParent } =
131
- select( blockEditorStore );
132
- const settings = getSettings();
133
- return {
134
- imageDefaultSize: settings.imageDefaultSize,
135
- mediaUpload: settings.mediaUpload,
136
- isContentLocked:
137
- !! __unstableGetContentLockingParent( clientId ),
138
- };
139
- },
140
- []
141
- );
131
+ const { imageDefaultSize, mediaUpload } = useSelect( ( select ) => {
132
+ const { getSettings } = select( blockEditorStore );
133
+ const settings = getSettings();
134
+ return {
135
+ imageDefaultSize: settings.imageDefaultSize,
136
+ mediaUpload: settings.mediaUpload,
137
+ };
138
+ }, [] );
139
+ const blockEditingMode = useBlockEditingMode();
142
140
 
143
141
  const { createErrorNotice } = useDispatch( noticesStore );
144
142
  function onUploadError( message ) {
@@ -320,7 +318,9 @@ export function ImageEdit( {
320
318
  'is-resized': !! width || !! height,
321
319
  [ `size-${ sizeSlug }` ]: sizeSlug,
322
320
  'has-custom-border':
323
- !! borderProps.className || ! isEmpty( borderProps.style ),
321
+ !! borderProps.className ||
322
+ ( borderProps.style &&
323
+ Object.keys( borderProps.style ).length > 0 ),
324
324
  } );
325
325
 
326
326
  const blockProps = useBlockProps( {
@@ -365,10 +365,10 @@ export function ImageEdit( {
365
365
  containerRef={ ref }
366
366
  context={ context }
367
367
  clientId={ clientId }
368
- isContentLocked={ isContentLocked }
368
+ blockEditingMode={ blockEditingMode }
369
369
  />
370
370
  ) }
371
- { ! url && ! isContentLocked && (
371
+ { ! url && blockEditingMode === 'default' && (
372
372
  <BlockControls group="block">
373
373
  <BlockAlignmentControl
374
374
  value={ align }
@@ -1,8 +1,3 @@
1
- /**
2
- * External dependencies
3
- */
4
- import { isEmpty } from 'lodash';
5
-
6
1
  /**
7
2
  * WordPress dependencies
8
3
  */
@@ -79,7 +74,7 @@ export default function Image( {
79
74
  containerRef,
80
75
  context,
81
76
  clientId,
82
- isContentLocked,
77
+ blockEditingMode,
83
78
  } ) {
84
79
  const {
85
80
  url = '',
@@ -122,7 +117,7 @@ export default function Image( {
122
117
  ),
123
118
  };
124
119
  },
125
- [ id, isSelected, clientId ]
120
+ [ id, isSelected ]
126
121
  );
127
122
  const { canInsertCover, imageEditing, imageSizes, maxWidth, mediaUpload } =
128
123
  useSelect(
@@ -161,9 +156,10 @@ export default function Image( {
161
156
  const [ isEditingImage, setIsEditingImage ] = useState( false );
162
157
  const [ externalBlob, setExternalBlob ] = useState();
163
158
  const clientWidth = useClientWidth( containerRef, [ align ] );
159
+ const hasNonContentControls = blockEditingMode === 'default';
164
160
  const isResizable =
165
161
  allowResize &&
166
- ! isContentLocked &&
162
+ hasNonContentControls &&
167
163
  ! ( isWideAligned && isLargeViewport );
168
164
  const imageSizeOptions = imageSizes
169
165
  .filter(
@@ -332,13 +328,13 @@ export default function Image( {
332
328
  const controls = (
333
329
  <>
334
330
  <BlockControls group="block">
335
- { ! isContentLocked && (
331
+ { hasNonContentControls && (
336
332
  <BlockAlignmentControl
337
333
  value={ align }
338
334
  onChange={ updateAlignment }
339
335
  />
340
336
  ) }
341
- { ! isContentLocked && (
337
+ { hasNonContentControls && (
342
338
  <ToolbarButton
343
339
  onClick={ () => {
344
340
  setShowCaption( ! showCaption );
@@ -480,7 +476,8 @@ export default function Image( {
480
476
  const borderProps = useBorderProps( attributes );
481
477
  const isRounded = attributes.className?.includes( 'is-style-rounded' );
482
478
  const hasCustomBorder =
483
- !! borderProps.className || ! isEmpty( borderProps.style );
479
+ !! borderProps.className ||
480
+ ( borderProps.style && Object.keys( borderProps.style ).length > 0 );
484
481
 
485
482
  let img = (
486
483
  // Disable reason: Image itself is not meant to be interactive, but
@@ -14,6 +14,7 @@
14
14
  * @return string Returns the block content with the data-id attribute added.
15
15
  */
16
16
  function render_block_core_image( $attributes, $content ) {
17
+
17
18
  $processor = new WP_HTML_Tag_Processor( $content );
18
19
  $processor->next_tag( 'img' );
19
20
 
@@ -27,16 +28,88 @@ function render_block_core_image( $attributes, $content ) {
27
28
  // which now wraps Image Blocks within innerBlocks.
28
29
  // The data-id attribute is added in a core/gallery `render_block_data` hook.
29
30
  $processor->set_attribute( 'data-id', $attributes['data-id'] );
31
+ }
32
+
33
+ $link_destination = isset( $attributes['linkDestination'] ) ? $attributes['linkDestination'] : 'none';
34
+
35
+ // Get the lightbox setting from the block attributes.
36
+ if ( isset( $attributes['behaviors']['lightbox'] ) ) {
37
+ $lightbox = $attributes['behaviors']['lightbox'];
38
+ // If the lightbox setting is not set in the block attributes, get it from the theme.json file.
39
+ } else {
40
+ $theme_data = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data()->get_data();
41
+ if ( isset( $theme_data['behaviors']['blocks']['core/image']['lightbox'] ) ) {
42
+ $lightbox = $theme_data['behaviors']['blocks']['core/image']['lightbox'];
43
+ } else {
44
+ $lightbox = false;
45
+ }
46
+ }
47
+
48
+ $experiments = get_option( 'gutenberg-experiments' );
49
+
50
+ if ( ! empty( $experiments['gutenberg-interactivity-api-core-blocks'] ) && 'none' === $link_destination && $lightbox ) {
51
+
52
+ $aria_label = 'Open image lightbox';
53
+ if ( $processor->get_attribute( 'alt' ) ) {
54
+ $aria_label .= ' : ' . $processor->get_attribute( 'alt' );
55
+ }
30
56
  $content = $processor->get_updated_html();
57
+
58
+ // Wrap the image in the body content with a button.
59
+ $img = null;
60
+ preg_match( '/<img[^>]+>/', $content, $img );
61
+ $button = '<div class="img-container">
62
+ <button aria-haspopup="dialog" aria-label="' . $aria_label . '" data-wp-on.click="actions.core.image.showLightbox"></button>'
63
+ . $img[0] .
64
+ '</div>';
65
+ $body_content = preg_replace( '/<img[^>]+>/', $button, $content );
66
+
67
+ // For the modal, set an ID on the image to be used for an aria-labelledby attribute.
68
+ $modal_content = new WP_HTML_Tag_Processor( $content );
69
+ $modal_content->next_tag( 'img' );
70
+ $image_lightbox_id = $modal_content->get_attribute( 'class' ) . '-lightbox';
71
+ $modal_content->set_attribute( 'id', $image_lightbox_id );
72
+ $modal_content = $modal_content->get_updated_html();
73
+
74
+ $background_color = wp_get_global_styles( array( 'color', 'background' ) );
75
+ $close_button_icon = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="30" height="30" aria-hidden="true" focusable="false"><path d="M13 11.8l6.1-6.3-1-1-6.1 6.2-6.1-6.2-1 1 6.1 6.3-6.5 6.7 1 1 6.5-6.6 6.5 6.6 1-1z"></path></svg>';
76
+
77
+ return
78
+ <<<HTML
79
+ <div class="wp-lightbox-container"
80
+ data-wp-island
81
+ data-wp-context='{ "core": { "image": { "initialized": false, "lightboxEnabled": false } } }'>
82
+ $body_content
83
+ <div data-wp-body="" class="wp-lightbox-overlay"
84
+ data-wp-bind.role="selectors.core.image.roleAttribute"
85
+ aria-labelledby="$image_lightbox_id"
86
+ data-wp-class.initialized="context.core.image.initialized"
87
+ data-wp-class.active="context.core.image.lightboxEnabled"
88
+ data-wp-bind.aria-hidden="!context.core.image.lightboxEnabled"
89
+ data-wp-bind.aria-modal="context.core.image.lightboxEnabled"
90
+ data-wp-effect="effects.core.image.initLightbox"
91
+ data-wp-on.keydown="actions.core.image.handleKeydown"
92
+ data-wp-on.mousewheel="actions.core.image.hideLightbox"
93
+ data-wp-on.click="actions.core.image.hideLightbox"
94
+ >
95
+ <button aria-label="Close lightbox" class="close-button" data-wp-on.click="actions.core.image.hideLightbox">
96
+ $close_button_icon
97
+ </button>
98
+ $modal_content
99
+ <div class="scrim" style="background-color: $background_color"></div>
100
+ </div>
101
+ </div>
102
+ HTML;
31
103
  }
32
- return $content;
33
- }
34
104
 
105
+ return $processor->get_updated_html();
106
+ }
35
107
 
36
108
  /**
37
109
  * Registers the `core/image` block on server.
38
110
  */
39
111
  function register_block_core_image() {
112
+
40
113
  register_block_type_from_metadata(
41
114
  __DIR__ . '/image',
42
115
  array(
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import { store } from '../utils/interactivity';
5
+
6
+ const focusableSelectors = [
7
+ 'a[href]',
8
+ 'area[href]',
9
+ 'input:not([disabled]):not([type="hidden"]):not([aria-hidden])',
10
+ 'select:not([disabled]):not([aria-hidden])',
11
+ 'textarea:not([disabled]):not([aria-hidden])',
12
+ 'button:not([disabled]):not([aria-hidden])',
13
+ 'iframe',
14
+ 'object',
15
+ 'embed',
16
+ '[contenteditable]',
17
+ '[tabindex]:not([tabindex^="-"])',
18
+ ];
19
+
20
+ store( {
21
+ actions: {
22
+ core: {
23
+ image: {
24
+ showLightbox: ( { context } ) => {
25
+ context.core.image.initialized = true;
26
+ context.core.image.lightboxEnabled = true;
27
+ context.core.image.lastFocusedElement =
28
+ window.document.activeElement;
29
+ context.core.image.scrollPosition = window.scrollY;
30
+ document.documentElement.classList.add(
31
+ 'has-lightbox-open'
32
+ );
33
+ },
34
+ hideLightbox: async ( { context, event } ) => {
35
+ if ( context.core.image.lightboxEnabled ) {
36
+ // If scrolling, wait a moment before closing the lightbox.
37
+ if (
38
+ event.type === 'mousewheel' &&
39
+ Math.abs(
40
+ window.scrollY -
41
+ context.core.image.scrollPosition
42
+ ) < 5
43
+ ) {
44
+ return;
45
+ }
46
+ document.documentElement.classList.remove(
47
+ 'has-lightbox-open'
48
+ );
49
+
50
+ context.core.image.lightboxEnabled = false;
51
+ context.core.image.lastFocusedElement.focus();
52
+ }
53
+ },
54
+ handleKeydown: ( { context, actions, event } ) => {
55
+ if ( context.core.image.lightboxEnabled ) {
56
+ if ( event.key === 'Tab' || event.keyCode === 9 ) {
57
+ // If shift + tab it change the direction
58
+ if (
59
+ event.shiftKey &&
60
+ window.document.activeElement ===
61
+ context.core.image.firstFocusableElement
62
+ ) {
63
+ event.preventDefault();
64
+ context.core.image.lastFocusableElement.focus();
65
+ } else if (
66
+ ! event.shiftKey &&
67
+ window.document.activeElement ===
68
+ context.core.image.lastFocusableElement
69
+ ) {
70
+ event.preventDefault();
71
+ context.core.image.firstFocusableElement.focus();
72
+ }
73
+ }
74
+
75
+ if ( event.key === 'Escape' || event.keyCode === 27 ) {
76
+ actions.core.image.hideLightbox( {
77
+ context,
78
+ event,
79
+ } );
80
+ }
81
+ }
82
+ },
83
+ },
84
+ },
85
+ },
86
+ selectors: {
87
+ core: {
88
+ image: {
89
+ roleAttribute: ( { context } ) => {
90
+ return context.core.image.lightboxEnabled ? 'dialog' : '';
91
+ },
92
+ },
93
+ },
94
+ },
95
+ effects: {
96
+ core: {
97
+ image: {
98
+ initLightbox: async ( { context, ref } ) => {
99
+ if ( context.core.image.lightboxEnabled ) {
100
+ const focusableElements =
101
+ ref.querySelectorAll( focusableSelectors );
102
+ context.core.image.firstFocusableElement =
103
+ focusableElements[ 0 ];
104
+ context.core.image.lastFocusableElement =
105
+ focusableElements[ focusableElements.length - 1 ];
106
+
107
+ ref.querySelector( '.close-button' ).focus();
108
+ }
109
+ },
110
+ },
111
+ },
112
+ },
113
+ } );
package/src/image/save.js CHANGED
@@ -2,7 +2,6 @@
2
2
  * External dependencies
3
3
  */
4
4
  import classnames from 'classnames';
5
- import { isEmpty } from 'lodash';
6
5
 
7
6
  /**
8
7
  * WordPress dependencies
@@ -31,7 +30,7 @@ export default function save( { attributes } ) {
31
30
  title,
32
31
  } = attributes;
33
32
 
34
- const newRel = isEmpty( rel ) ? undefined : rel;
33
+ const newRel = ! rel ? undefined : rel;
35
34
  const borderProps = getBorderClassesAndStyles( attributes );
36
35
 
37
36
  const classes = classnames( {
@@ -39,7 +38,9 @@ export default function save( { attributes } ) {
39
38
  [ `size-${ sizeSlug }` ]: sizeSlug,
40
39
  'is-resized': width || height,
41
40
  'has-custom-border':
42
- !! borderProps.className || ! isEmpty( borderProps.style ),
41
+ !! borderProps.className ||
42
+ ( borderProps.style &&
43
+ Object.keys( borderProps.style ).length > 0 ),
43
44
  } );
44
45
 
45
46
  const imageClasses = classnames( borderProps.className, {