@wordpress/block-editor 15.10.1-next.79a2f3cdd.0 → 15.10.1-next.v.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 (228) hide show
  1. package/build/components/block-bindings/attribute-control.cjs +1 -1
  2. package/build/components/block-bindings/attribute-control.cjs.map +1 -1
  3. package/build/components/block-bindings/source-fields-list.cjs +1 -1
  4. package/build/components/block-bindings/source-fields-list.cjs.map +1 -1
  5. package/build/components/block-edit/context.cjs +5 -5
  6. package/build/components/block-edit/context.cjs.map +1 -1
  7. package/build/components/block-list/block.cjs +24 -12
  8. package/build/components/block-list/block.cjs.map +3 -3
  9. package/build/components/block-list/use-block-props/index.cjs +8 -2
  10. package/build/components/block-list/use-block-props/index.cjs.map +2 -2
  11. package/build/components/block-tools/index.cjs +82 -70
  12. package/build/components/block-tools/index.cjs.map +2 -2
  13. package/build/components/block-visibility/block-visibility-info.cjs +0 -59
  14. package/build/components/block-visibility/block-visibility-info.cjs.map +3 -3
  15. package/build/components/block-visibility/constants.cjs +54 -0
  16. package/build/components/block-visibility/constants.cjs.map +7 -0
  17. package/build/components/block-visibility/index.cjs +15 -4
  18. package/build/components/block-visibility/index.cjs.map +3 -3
  19. package/build/components/block-visibility/modal.cjs +397 -0
  20. package/build/components/block-visibility/modal.cjs.map +7 -0
  21. package/build/components/block-visibility/toolbar.cjs +1 -1
  22. package/build/components/block-visibility/toolbar.cjs.map +2 -2
  23. package/build/components/block-visibility/use-block-visibility.cjs +65 -0
  24. package/build/components/block-visibility/use-block-visibility.cjs.map +7 -0
  25. package/build/components/block-visibility/utils.cjs +81 -0
  26. package/build/components/block-visibility/utils.cjs.map +7 -0
  27. package/build/components/block-visibility/viewport-menu-item.cjs +61 -0
  28. package/build/components/block-visibility/viewport-menu-item.cjs.map +7 -0
  29. package/build/components/block-visibility/viewport-toolbar.cjs +89 -0
  30. package/build/components/block-visibility/viewport-toolbar.cjs.map +7 -0
  31. package/build/components/collab/block-comment-icon-slot.cjs +1 -1
  32. package/build/components/collab/block-comment-icon-slot.cjs.map +1 -1
  33. package/build/components/collab/block-comment-icon-toolbar-slot.cjs +1 -1
  34. package/build/components/collab/block-comment-icon-toolbar-slot.cjs.map +1 -1
  35. package/build/components/inner-blocks/use-inner-block-template-sync.cjs +1 -1
  36. package/build/components/inner-blocks/use-inner-block-template-sync.cjs.map +1 -1
  37. package/build/components/inserter/menu.cjs +6 -2
  38. package/build/components/inserter/menu.cjs.map +2 -2
  39. package/build/components/inspector-controls/groups.cjs +1 -1
  40. package/build/components/inspector-controls/groups.cjs.map +1 -1
  41. package/build/components/inspector-controls-tabs/content-tab.cjs +1 -1
  42. package/build/components/inspector-controls-tabs/content-tab.cjs.map +2 -2
  43. package/build/components/list-view/block-select-button.cjs +2 -2
  44. package/build/components/list-view/block-select-button.cjs.map +2 -2
  45. package/build/components/list-view/block.cjs +39 -22
  46. package/build/components/list-view/block.cjs.map +2 -2
  47. package/build/components/list-view/index.cjs +11 -6
  48. package/build/components/list-view/index.cjs.map +2 -2
  49. package/build/components/list-view/utils.cjs +24 -17
  50. package/build/components/list-view/utils.cjs.map +2 -2
  51. package/build/components/rich-text/event-listeners/input-rules.cjs +13 -1
  52. package/build/components/rich-text/event-listeners/input-rules.cjs.map +2 -2
  53. package/build/components/rich-text/format-edit.cjs +1 -1
  54. package/build/components/rich-text/format-edit.cjs.map +1 -1
  55. package/build/components/rich-text/index.cjs +2 -2
  56. package/build/components/rich-text/index.cjs.map +2 -2
  57. package/build/components/url-input/index.cjs +2 -0
  58. package/build/components/url-input/index.cjs.map +2 -2
  59. package/build/components/use-block-commands/index.cjs +1 -1
  60. package/build/components/use-block-commands/index.cjs.map +2 -2
  61. package/build/components/writing-flow/utils.cjs +1 -1
  62. package/build/components/writing-flow/utils.cjs.map +1 -1
  63. package/build/hooks/block-fields/index.cjs +76 -167
  64. package/build/hooks/block-fields/index.cjs.map +2 -2
  65. package/build/hooks/block-fields/link/index.cjs +13 -23
  66. package/build/hooks/block-fields/link/index.cjs.map +2 -2
  67. package/build/hooks/block-fields/media/index.cjs +32 -58
  68. package/build/hooks/block-fields/media/index.cjs.map +2 -2
  69. package/build/hooks/block-fields/rich-text/index.cjs +1 -5
  70. package/build/hooks/block-fields/rich-text/index.cjs.map +2 -2
  71. package/build/hooks/cross-origin-isolation.cjs +102 -0
  72. package/build/hooks/cross-origin-isolation.cjs.map +7 -0
  73. package/build/hooks/fit-text.cjs +1 -1
  74. package/build/hooks/fit-text.cjs.map +1 -1
  75. package/build/hooks/index.cjs +1 -0
  76. package/build/hooks/index.cjs.map +2 -2
  77. package/build/layouts/flex.cjs +6 -2
  78. package/build/layouts/flex.cjs.map +2 -2
  79. package/build/store/private-keys.cjs +10 -10
  80. package/build/store/private-keys.cjs.map +1 -1
  81. package/build/store/private-selectors.cjs +33 -1
  82. package/build/store/private-selectors.cjs.map +3 -3
  83. package/build/store/reducer.cjs +1 -1
  84. package/build/store/reducer.cjs.map +1 -1
  85. package/build/store/selectors.cjs +7 -8
  86. package/build/store/selectors.cjs.map +2 -2
  87. package/build/store/utils.cjs +1 -1
  88. package/build/store/utils.cjs.map +1 -1
  89. package/build-module/components/block-bindings/attribute-control.mjs +1 -1
  90. package/build-module/components/block-bindings/attribute-control.mjs.map +1 -1
  91. package/build-module/components/block-bindings/source-fields-list.mjs +1 -1
  92. package/build-module/components/block-bindings/source-fields-list.mjs.map +1 -1
  93. package/build-module/components/block-edit/context.mjs +5 -5
  94. package/build-module/components/block-edit/context.mjs.map +1 -1
  95. package/build-module/components/block-list/block.mjs +24 -12
  96. package/build-module/components/block-list/block.mjs.map +3 -3
  97. package/build-module/components/block-list/use-block-props/index.mjs +8 -2
  98. package/build-module/components/block-list/use-block-props/index.mjs.map +2 -2
  99. package/build-module/components/block-tools/index.mjs +85 -73
  100. package/build-module/components/block-tools/index.mjs.map +2 -2
  101. package/build-module/components/block-visibility/block-visibility-info.mjs +0 -59
  102. package/build-module/components/block-visibility/block-visibility-info.mjs.map +3 -3
  103. package/build-module/components/block-visibility/constants.mjs +28 -0
  104. package/build-module/components/block-visibility/constants.mjs.map +7 -0
  105. package/build-module/components/block-visibility/index.mjs +13 -4
  106. package/build-module/components/block-visibility/index.mjs.map +2 -2
  107. package/build-module/components/block-visibility/modal.mjs +384 -0
  108. package/build-module/components/block-visibility/modal.mjs.map +7 -0
  109. package/build-module/components/block-visibility/toolbar.mjs +1 -1
  110. package/build-module/components/block-visibility/toolbar.mjs.map +2 -2
  111. package/build-module/components/block-visibility/use-block-visibility.mjs +44 -0
  112. package/build-module/components/block-visibility/use-block-visibility.mjs.map +7 -0
  113. package/build-module/components/block-visibility/utils.mjs +55 -0
  114. package/build-module/components/block-visibility/utils.mjs.map +7 -0
  115. package/build-module/components/block-visibility/viewport-menu-item.mjs +40 -0
  116. package/build-module/components/block-visibility/viewport-menu-item.mjs.map +7 -0
  117. package/build-module/components/block-visibility/viewport-toolbar.mjs +68 -0
  118. package/build-module/components/block-visibility/viewport-toolbar.mjs.map +7 -0
  119. package/build-module/components/collab/block-comment-icon-slot.mjs +1 -1
  120. package/build-module/components/collab/block-comment-icon-slot.mjs.map +1 -1
  121. package/build-module/components/collab/block-comment-icon-toolbar-slot.mjs +1 -1
  122. package/build-module/components/collab/block-comment-icon-toolbar-slot.mjs.map +1 -1
  123. package/build-module/components/inner-blocks/use-inner-block-template-sync.mjs +1 -1
  124. package/build-module/components/inner-blocks/use-inner-block-template-sync.mjs.map +1 -1
  125. package/build-module/components/inserter/menu.mjs +6 -2
  126. package/build-module/components/inserter/menu.mjs.map +2 -2
  127. package/build-module/components/inspector-controls/groups.mjs +1 -1
  128. package/build-module/components/inspector-controls/groups.mjs.map +1 -1
  129. package/build-module/components/inspector-controls-tabs/content-tab.mjs +1 -1
  130. package/build-module/components/inspector-controls-tabs/content-tab.mjs.map +2 -2
  131. package/build-module/components/list-view/block-select-button.mjs +2 -2
  132. package/build-module/components/list-view/block-select-button.mjs.map +2 -2
  133. package/build-module/components/list-view/block.mjs +39 -22
  134. package/build-module/components/list-view/block.mjs.map +2 -2
  135. package/build-module/components/list-view/index.mjs +11 -7
  136. package/build-module/components/list-view/index.mjs.map +2 -2
  137. package/build-module/components/list-view/utils.mjs +24 -17
  138. package/build-module/components/list-view/utils.mjs.map +2 -2
  139. package/build-module/components/rich-text/event-listeners/input-rules.mjs +13 -1
  140. package/build-module/components/rich-text/event-listeners/input-rules.mjs.map +2 -2
  141. package/build-module/components/rich-text/format-edit.mjs +1 -1
  142. package/build-module/components/rich-text/format-edit.mjs.map +1 -1
  143. package/build-module/components/rich-text/index.mjs +2 -2
  144. package/build-module/components/rich-text/index.mjs.map +2 -2
  145. package/build-module/components/url-input/index.mjs +2 -0
  146. package/build-module/components/url-input/index.mjs.map +2 -2
  147. package/build-module/components/use-block-commands/index.mjs +1 -1
  148. package/build-module/components/use-block-commands/index.mjs.map +2 -2
  149. package/build-module/components/writing-flow/utils.mjs +1 -1
  150. package/build-module/components/writing-flow/utils.mjs.map +1 -1
  151. package/build-module/hooks/block-fields/index.mjs +76 -167
  152. package/build-module/hooks/block-fields/index.mjs.map +2 -2
  153. package/build-module/hooks/block-fields/link/index.mjs +13 -23
  154. package/build-module/hooks/block-fields/link/index.mjs.map +2 -2
  155. package/build-module/hooks/block-fields/media/index.mjs +32 -58
  156. package/build-module/hooks/block-fields/media/index.mjs.map +2 -2
  157. package/build-module/hooks/block-fields/rich-text/index.mjs +1 -5
  158. package/build-module/hooks/block-fields/rich-text/index.mjs.map +2 -2
  159. package/build-module/hooks/cross-origin-isolation.mjs +100 -0
  160. package/build-module/hooks/cross-origin-isolation.mjs.map +7 -0
  161. package/build-module/hooks/fit-text.mjs +1 -1
  162. package/build-module/hooks/fit-text.mjs.map +1 -1
  163. package/build-module/hooks/index.mjs +1 -0
  164. package/build-module/hooks/index.mjs.map +2 -2
  165. package/build-module/layouts/flex.mjs +6 -2
  166. package/build-module/layouts/flex.mjs.map +2 -2
  167. package/build-module/store/private-keys.mjs +10 -10
  168. package/build-module/store/private-keys.mjs.map +1 -1
  169. package/build-module/store/private-selectors.mjs +34 -1
  170. package/build-module/store/private-selectors.mjs.map +2 -2
  171. package/build-module/store/reducer.mjs +1 -1
  172. package/build-module/store/reducer.mjs.map +1 -1
  173. package/build-module/store/selectors.mjs +7 -8
  174. package/build-module/store/selectors.mjs.map +2 -2
  175. package/build-module/store/utils.mjs +1 -1
  176. package/build-module/store/utils.mjs.map +1 -1
  177. package/build-style/content-rtl.css +4 -1
  178. package/build-style/content.css +4 -1
  179. package/build-style/style-rtl.css +54 -1
  180. package/build-style/style.css +54 -1
  181. package/package.json +39 -39
  182. package/src/components/block-bindings/attribute-control.js +1 -1
  183. package/src/components/block-bindings/source-fields-list.js +1 -1
  184. package/src/components/block-list/block.js +23 -9
  185. package/src/components/block-list/content.scss +4 -1
  186. package/src/components/block-list/use-block-props/index.js +10 -2
  187. package/src/components/block-toolbar/style.scss +0 -1
  188. package/src/components/block-tools/index.js +45 -33
  189. package/src/components/block-tools/style.scss +10 -0
  190. package/src/components/block-visibility/block-visibility-info.js +0 -1
  191. package/src/components/block-visibility/constants.js +33 -0
  192. package/src/components/block-visibility/index.js +21 -2
  193. package/src/components/block-visibility/modal.js +358 -0
  194. package/src/components/block-visibility/style.scss +58 -0
  195. package/src/components/block-visibility/test/use-block-visibility.js +316 -0
  196. package/src/components/block-visibility/test/utils.js +266 -0
  197. package/src/components/block-visibility/toolbar.js +1 -1
  198. package/src/components/block-visibility/use-block-visibility.js +70 -0
  199. package/src/components/block-visibility/utils.js +95 -0
  200. package/src/components/block-visibility/viewport-menu-item.js +42 -0
  201. package/src/components/block-visibility/viewport-toolbar.js +88 -0
  202. package/src/components/inner-blocks/use-inner-block-template-sync.js +1 -1
  203. package/src/components/inserter/menu.js +6 -2
  204. package/src/components/inspector-controls-tabs/content-tab.js +0 -1
  205. package/src/components/list-view/block-select-button.js +2 -2
  206. package/src/components/list-view/block.js +47 -25
  207. package/src/components/list-view/index.js +15 -11
  208. package/src/components/list-view/utils.js +31 -23
  209. package/src/components/rich-text/event-listeners/input-rules.js +17 -0
  210. package/src/components/rich-text/index.js +1 -1
  211. package/src/components/url-input/index.js +2 -0
  212. package/src/components/use-block-commands/index.js +4 -3
  213. package/src/hooks/block-fields/index.js +104 -225
  214. package/src/hooks/block-fields/link/index.js +13 -39
  215. package/src/hooks/block-fields/media/index.js +31 -90
  216. package/src/hooks/block-fields/rich-text/index.js +1 -5
  217. package/src/hooks/block-fields/styles.scss +2 -0
  218. package/src/hooks/cross-origin-isolation.js +143 -0
  219. package/src/hooks/fit-text.js +1 -1
  220. package/src/hooks/index.js +1 -0
  221. package/src/layouts/flex.js +8 -3
  222. package/src/layouts/test/flex.js +53 -0
  223. package/src/store/private-selectors.js +64 -1
  224. package/src/store/reducer.js +1 -1
  225. package/src/store/selectors.js +7 -9
  226. package/src/store/test/private-selectors.js +80 -0
  227. package/src/style.scss +1 -0
  228. package/src/components/block-visibility/styles.scss +0 -10
@@ -0,0 +1,143 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { addFilter } from '@wordpress/hooks';
5
+ import { createHigherOrderComponent } from '@wordpress/compose';
6
+
7
+ /**
8
+ * Adds crossorigin and credentialless attributes to elements as needed.
9
+ *
10
+ * @param {Element} el The element to modify.
11
+ */
12
+ function addCrossOriginAttributes( el ) {
13
+ // Add the crossorigin attribute if missing.
14
+ if ( ! el.hasAttribute( 'crossorigin' ) ) {
15
+ el.setAttribute( 'crossorigin', 'anonymous' );
16
+ }
17
+
18
+ // For iframes, add the credentialless attribute.
19
+ if ( el.nodeName === 'IFRAME' && ! el.hasAttribute( 'credentialless' ) ) {
20
+ // Do not modify the iframed editor canvas.
21
+ if ( el.getAttribute( 'src' )?.startsWith( 'blob:' ) ) {
22
+ return;
23
+ }
24
+
25
+ el.setAttribute( 'credentialless', '' );
26
+
27
+ // Reload the iframe to ensure the new attribute is taken into account.
28
+ const origSrc = el.getAttribute( 'src' ) || '';
29
+ el.setAttribute( 'src', '' );
30
+ el.setAttribute( 'src', origSrc );
31
+ }
32
+ }
33
+
34
+ // Only add the mutation observer if the site is cross-origin isolated.
35
+ if ( window.crossOriginIsolated ) {
36
+ /*
37
+ * Detects dynamically added DOM nodes that are missing the `crossorigin` attribute.
38
+ */
39
+ const observer = new window.MutationObserver( ( mutations ) => {
40
+ mutations.forEach( ( mutation ) => {
41
+ [ mutation.addedNodes, mutation.target ].forEach( ( value ) => {
42
+ const nodes =
43
+ value instanceof window.NodeList ? value : [ value ];
44
+ nodes.forEach( ( node ) => {
45
+ const el = node;
46
+
47
+ if ( ! el.querySelectorAll ) {
48
+ // Most likely a text node.
49
+ return;
50
+ }
51
+
52
+ el.querySelectorAll(
53
+ 'img,source,script,video,link,iframe'
54
+ ).forEach( ( v ) => {
55
+ addCrossOriginAttributes( v );
56
+ } );
57
+
58
+ if ( el.nodeName === 'IFRAME' ) {
59
+ const iframeNode = el;
60
+
61
+ /*
62
+ * Sandboxed iframes should not get modified. For example embedding a tweet served in a sandboxed
63
+ * iframe, the tweet itself would not be modified.
64
+ */
65
+ const isEmbedSandboxIframe =
66
+ iframeNode.classList.contains(
67
+ 'components-sandbox'
68
+ );
69
+
70
+ if ( ! isEmbedSandboxIframe ) {
71
+ iframeNode.addEventListener( 'load', () => {
72
+ if ( iframeNode.contentDocument ) {
73
+ observer.observe(
74
+ iframeNode.contentDocument,
75
+ {
76
+ childList: true,
77
+ attributes: true,
78
+ subtree: true,
79
+ }
80
+ );
81
+ }
82
+ } );
83
+ }
84
+ }
85
+
86
+ if (
87
+ [
88
+ 'IMG',
89
+ 'SOURCE',
90
+ 'SCRIPT',
91
+ 'VIDEO',
92
+ 'LINK',
93
+ 'IFRAME',
94
+ ].includes( el.nodeName )
95
+ ) {
96
+ addCrossOriginAttributes( el );
97
+ }
98
+ } );
99
+ } );
100
+ } );
101
+ } );
102
+
103
+ observer.observe( document.body, {
104
+ childList: true,
105
+ attributes: true,
106
+ subtree: true,
107
+ } );
108
+ }
109
+
110
+ // Only apply the embed preview filter when cross-origin isolated.
111
+ if ( window.crossOriginIsolated ) {
112
+ const supportsCredentialless =
113
+ 'credentialless' in window.HTMLIFrameElement.prototype;
114
+
115
+ const disableEmbedPreviews = createHigherOrderComponent(
116
+ ( BlockEdit ) => ( props ) => {
117
+ if ( 'core/embed' !== props.name ) {
118
+ return <BlockEdit { ...props } />;
119
+ }
120
+
121
+ // List of embeds that do not support a preview is from packages/block-library/src/embed/variations.js.
122
+ const previewable =
123
+ supportsCredentialless &&
124
+ ! [ 'facebook', 'smugmug' ].includes(
125
+ props.attributes.providerNameSlug
126
+ );
127
+
128
+ return (
129
+ <BlockEdit
130
+ { ...props }
131
+ attributes={ { ...props.attributes, previewable } }
132
+ />
133
+ );
134
+ },
135
+ 'withDisabledEmbedPreview'
136
+ );
137
+
138
+ addFilter(
139
+ 'editor.BlockEdit',
140
+ 'media-experiments/disable-embed-previews',
141
+ disableEmbedPreviews
142
+ );
143
+ }
@@ -13,7 +13,7 @@ import {
13
13
  import { createHigherOrderComponent } from '@wordpress/compose';
14
14
 
15
15
  const EMPTY_OBJECT = {};
16
- const MIN_FONT_SIZE_FOR_WARNING = 6;
16
+ const MIN_FONT_SIZE_FOR_WARNING = 12;
17
17
 
18
18
  /**
19
19
  * Internal dependencies
@@ -7,6 +7,7 @@ import {
7
7
  createBlockSaveFilter,
8
8
  } from './utils';
9
9
  import './compat';
10
+ import './cross-origin-isolation';
10
11
  import align from './align';
11
12
  import background from './background';
12
13
  import './lock';
@@ -71,8 +71,11 @@ export default {
71
71
  onChange,
72
72
  layoutBlockSupport = {},
73
73
  } ) {
74
- const { allowOrientation = true, allowJustification = true } =
75
- layoutBlockSupport;
74
+ const {
75
+ allowOrientation = true,
76
+ allowJustification = true,
77
+ allowWrap = true,
78
+ } = layoutBlockSupport;
76
79
  return (
77
80
  <>
78
81
  <Flex>
@@ -93,7 +96,9 @@ export default {
93
96
  </FlexItem>
94
97
  ) }
95
98
  </Flex>
96
- <FlexWrapControl layout={ layout } onChange={ onChange } />
99
+ { allowWrap && (
100
+ <FlexWrapControl layout={ layout } onChange={ onChange } />
101
+ ) }
97
102
  </>
98
103
  );
99
104
  },
@@ -1,8 +1,15 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { render, screen } from '@testing-library/react';
5
+
1
6
  /**
2
7
  * Internal dependencies
3
8
  */
4
9
  import flex from '../flex';
5
10
 
11
+ const FlexLayoutInspectorControls = flex.inspectorControls;
12
+
6
13
  describe( 'getLayoutStyle', () => {
7
14
  it( 'should return an empty string if no non-default params are provided', () => {
8
15
  const expected = '';
@@ -19,3 +26,49 @@ describe( 'getLayoutStyle', () => {
19
26
  expect( result ).toBe( expected );
20
27
  } );
21
28
  } );
29
+
30
+ describe( 'FlexLayoutInspectorControls', () => {
31
+ it( 'should render the wrap toggle by default', () => {
32
+ render(
33
+ <FlexLayoutInspectorControls layout={ {} } onChange={ jest.fn() } />
34
+ );
35
+
36
+ expect(
37
+ screen.getByRole( 'checkbox', {
38
+ name: 'Allow to wrap to multiple lines',
39
+ } )
40
+ ).toBeInTheDocument();
41
+ } );
42
+
43
+ it( 'should render the wrap toggle when allowWrap is true', () => {
44
+ render(
45
+ <FlexLayoutInspectorControls
46
+ layout={ {} }
47
+ onChange={ jest.fn() }
48
+ layoutBlockSupport={ { allowWrap: true } }
49
+ />
50
+ );
51
+
52
+ expect(
53
+ screen.getByRole( 'checkbox', {
54
+ name: 'Allow to wrap to multiple lines',
55
+ } )
56
+ ).toBeInTheDocument();
57
+ } );
58
+
59
+ it( 'should not render the wrap toggle when allowWrap is false', () => {
60
+ render(
61
+ <FlexLayoutInspectorControls
62
+ layout={ {} }
63
+ onChange={ jest.fn() }
64
+ layoutBlockSupport={ { allowWrap: false } }
65
+ />
66
+ );
67
+
68
+ expect(
69
+ screen.queryByRole( 'checkbox', {
70
+ name: 'Allow to wrap to multiple lines',
71
+ } )
72
+ ).not.toBeInTheDocument();
73
+ } );
74
+ } );
@@ -38,6 +38,10 @@ import {
38
38
  isIsolatedEditorKey,
39
39
  deviceTypeKey,
40
40
  } from './private-keys';
41
+ import {
42
+ BLOCK_VISIBILITY_VIEWPORT_ENTRIES,
43
+ BLOCK_VISIBILITY_VIEWPORTS,
44
+ } from '../components/block-visibility/constants';
41
45
 
42
46
  const { isContentBlock } = unlock( blocksPrivateApis );
43
47
 
@@ -730,7 +734,8 @@ export const isBlockHidden = ( state, clientId ) => {
730
734
  // Only apply when a device is explicitly selected.
731
735
  if ( typeof blockVisibility === 'object' && blockVisibility !== null ) {
732
736
  const settings = getSettings( state );
733
- const viewportType = settings[ deviceTypeKey ] ?? 'Desktop';
737
+ const viewportType =
738
+ settings[ deviceTypeKey ] ?? BLOCK_VISIBILITY_VIEWPORTS.desktop.key;
734
739
  const viewportKey = viewportType.toLowerCase();
735
740
  return blockVisibility?.[ viewportKey ] === false;
736
741
  }
@@ -738,6 +743,64 @@ export const isBlockHidden = ( state, clientId ) => {
738
743
  return false;
739
744
  };
740
745
 
746
+ /**
747
+ * Returns true if any of the provided blocks are hidden.
748
+ *
749
+ * @param {Object} state Global application state.
750
+ * @param {Array} clientIds Array of block client IDs to check.
751
+ * @return {boolean} Whether any block is hidden.
752
+ */
753
+ export const areBlocksHidden = ( state, clientIds ) => {
754
+ if ( ! clientIds || clientIds.length === 0 ) {
755
+ return false;
756
+ }
757
+ return clientIds.some( ( clientId ) => isBlockHidden( state, clientId ) );
758
+ };
759
+
760
+ /**
761
+ * Checks if at least one block in an array is hidden according to viewport visibility metadata.
762
+ *
763
+ * This is typically used to determine if the block visibility button should be shown in the toolbar.
764
+ * TODO: This is temporary for now. Later the UI will
765
+ * want to know where exactly the block is hidden, e.g., to display icons or other things.
766
+ *
767
+ * A block is considered hidden if:
768
+ * - Its `blockVisibility` metadata is `false` (hidden everywhere), or
769
+ * - Any viewport is set to `false`
770
+ *
771
+ * @param {Object} state Global application state.
772
+ * @param {Array} clientIds Array of block client IDs to check.
773
+ * @return {boolean} `true` if at least one block meets the visibility criteria, `false` otherwise.
774
+ */
775
+ export const areBlocksHiddenAnywhere = ( state, clientIds ) => {
776
+ if ( ! clientIds?.length ) {
777
+ return false;
778
+ }
779
+ return clientIds.some( ( clientId ) => {
780
+ if ( ! clientId ) {
781
+ return false;
782
+ }
783
+
784
+ const attributes = state.blocks.attributes.get( clientId );
785
+ const blockVisibility = attributes?.metadata?.blockVisibility;
786
+
787
+ // If explicitly hidden everywhere (false), return true.
788
+ if ( typeof blockVisibility === 'boolean' ) {
789
+ return blockVisibility === false;
790
+ }
791
+
792
+ // If not an object, block is not hidden in any viewport.
793
+ if ( 'object' !== typeof blockVisibility ) {
794
+ return false;
795
+ }
796
+
797
+ // Check viewport-specific visibility.
798
+ return BLOCK_VISIBILITY_VIEWPORT_ENTRIES.some(
799
+ ( [ , { key } ] ) => blockVisibility?.[ key ] === false
800
+ );
801
+ } );
802
+ };
803
+
741
804
  /**
742
805
  * Returns true if there is a spotlighted block.
743
806
  *
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import fastDeepEqual from 'fast-deep-equal/es6';
4
+ import fastDeepEqual from 'fast-deep-equal/es6/index.js';
5
5
 
6
6
  /**
7
7
  * WordPress dependencies
@@ -2154,24 +2154,22 @@ const buildBlockTypeItem =
2154
2154
  'inserter'
2155
2155
  );
2156
2156
  const blockVariations = getBlockVariations( blockType.name, 'block' );
2157
- // Combine inserter and block variations. Block-scope variations without
2158
- // inserter scope are searchable via slash commands but hidden from browse.
2159
- const inserterVariationNames = new Set(
2160
- inserterVariations.map( ( variation ) => variation.name )
2161
- );
2162
2157
  const allVariations = [
2163
2158
  ...inserterVariations,
2159
+ // Built-in heading level variations have block scope but allow
2160
+ // insertion via slash inserter.
2161
+ // See https://github.com/WordPress/gutenberg/issues/74233.
2164
2162
  ...blockVariations
2165
2163
  .filter(
2166
2164
  ( variation ) =>
2167
- ! inserterVariationNames.has( variation.name )
2165
+ blockType.name === 'core/heading' &&
2166
+ [ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6' ].includes(
2167
+ variation.name
2168
+ )
2168
2169
  )
2169
2170
  .map( ( variation ) => ( {
2170
2171
  ...variation,
2171
2172
  isSearchOnly: true,
2172
- // Block-scope `isDefault` is for the placeholder picker,
2173
- // not for the inserter, so don't carry it over.
2174
- isDefault: false,
2175
2173
  } ) ),
2176
2174
  ];
2177
2175
  return {
@@ -20,6 +20,7 @@ import {
20
20
  isRemoveLockedBlock,
21
21
  isLockedBlock,
22
22
  isBlockHidden,
23
+ areBlocksHiddenAnywhere,
23
24
  } from '../private-selectors';
24
25
  import { getBlockEditingMode } from '../selectors';
25
26
  import { deviceTypeKey } from '../private-keys';
@@ -1244,4 +1245,83 @@ describe( 'private selectors', () => {
1244
1245
  expect( result ).toBe( false );
1245
1246
  } );
1246
1247
  } );
1248
+
1249
+ describe( 'areBlocksHiddenAnywhere', () => {
1250
+ it( 'should return false when clientIds array is empty', () => {
1251
+ const state = {
1252
+ blocks: {
1253
+ attributes: new Map(),
1254
+ },
1255
+ };
1256
+ expect( areBlocksHiddenAnywhere( state, [] ) ).toBe( false );
1257
+ expect( areBlocksHiddenAnywhere( state, null ) ).toBe( false );
1258
+ expect( areBlocksHiddenAnywhere( state, undefined ) ).toBe( false );
1259
+ } );
1260
+
1261
+ it( 'should return false when no blocks are hidden', () => {
1262
+ const state = {
1263
+ blocks: {
1264
+ attributes: new Map( [
1265
+ [ 'block-1', { metadata: { blockVisibility: true } } ],
1266
+ [ 'block-2', { metadata: {} } ],
1267
+ ] ),
1268
+ },
1269
+ };
1270
+ expect(
1271
+ areBlocksHiddenAnywhere( state, [ 'block-1', 'block-2' ] )
1272
+ ).toBe( false );
1273
+ } );
1274
+
1275
+ it( 'should return true when a block is hidden everywhere', () => {
1276
+ const state = {
1277
+ blocks: {
1278
+ attributes: new Map( [
1279
+ [ 'block-1', { metadata: { blockVisibility: false } } ],
1280
+ [ 'block-2', { metadata: { blockVisibility: true } } ],
1281
+ ] ),
1282
+ },
1283
+ };
1284
+ expect(
1285
+ areBlocksHiddenAnywhere( state, [ 'block-1', 'block-2' ] )
1286
+ ).toBe( true );
1287
+ } );
1288
+
1289
+ it( 'should return true when a block is hidden in any viewport', () => {
1290
+ const state = {
1291
+ blocks: {
1292
+ attributes: new Map( [
1293
+ [
1294
+ 'block-1',
1295
+ {
1296
+ metadata: {
1297
+ blockVisibility: {
1298
+ mobile: false,
1299
+ tablet: true,
1300
+ },
1301
+ },
1302
+ },
1303
+ ],
1304
+ [ 'block-2', { metadata: { blockVisibility: true } } ],
1305
+ ] ),
1306
+ },
1307
+ };
1308
+ expect(
1309
+ areBlocksHiddenAnywhere( state, [ 'block-1', 'block-2' ] )
1310
+ ).toBe( true );
1311
+ } );
1312
+
1313
+ it( 'should return false when clientId is null or undefined', () => {
1314
+ const state = {
1315
+ blocks: {
1316
+ attributes: new Map( [
1317
+ [ 'block-1', { metadata: { blockVisibility: false } } ],
1318
+ ] ),
1319
+ },
1320
+ };
1321
+ expect( areBlocksHiddenAnywhere( state, [ null ] ) ).toBe( false );
1322
+ expect( areBlocksHiddenAnywhere( state, [ undefined ] ) ).toBe(
1323
+ false
1324
+ );
1325
+ } );
1326
+ } );
1247
1327
  } );
package/src/style.scss CHANGED
@@ -67,3 +67,4 @@
67
67
  @use "./components/block-toolbar/style.scss" as *;
68
68
  @use "./components/inserter/style.scss" as *;
69
69
  @use "./components/spacing-sizes-control/style.scss" as *;
70
+ @use "./components/block-visibility/style.scss" as *;
@@ -1,10 +0,0 @@
1
- @use "@wordpress/base-styles/variables" as *;
2
-
3
- .block-editor-block-visibility-info {
4
- padding-top: $grid-unit-05;
5
- padding-bottom: $grid-unit-05;
6
- margin: 0 $grid-unit-20 $grid-unit-20;
7
- display: flex;
8
- align-items: center;
9
- justify-content: start;
10
- }