@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,316 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { renderHook } from '@testing-library/react';
5
+
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import { useViewportMatch } from '@wordpress/compose';
10
+
11
+ // Mock WordPress dependencies before importing the hook
12
+ jest.mock( '@wordpress/compose', () => ( {
13
+ useViewportMatch: jest.fn(),
14
+ } ) );
15
+
16
+ /**
17
+ * Internal dependencies
18
+ */
19
+ import useBlockVisibility from '../use-block-visibility';
20
+
21
+ describe( 'useBlockVisibility', () => {
22
+ // Helper function to set up viewport matches
23
+ const setupViewport = ( { isMobileOrLarger, isMediumOrLarger } ) => {
24
+ if (
25
+ isMobileOrLarger !== undefined &&
26
+ isMediumOrLarger !== undefined
27
+ ) {
28
+ useViewportMatch
29
+ .mockReturnValueOnce( isMobileOrLarger )
30
+ .mockReturnValueOnce( isMediumOrLarger );
31
+ } else {
32
+ useViewportMatch.mockReturnValue(
33
+ isMobileOrLarger ?? isMediumOrLarger ?? true
34
+ );
35
+ }
36
+ };
37
+
38
+ beforeEach( () => {
39
+ // Reset all mocks before each test
40
+ jest.clearAllMocks();
41
+ // Enable experimental flag
42
+ window.__experimentalHideBlocksBasedOnScreenSize = true;
43
+ } );
44
+
45
+ afterEach( () => {
46
+ delete window.__experimentalHideBlocksBasedOnScreenSize;
47
+ } );
48
+
49
+ describe( 'Device type overrides', () => {
50
+ it( 'should return true when deviceType is Mobile and block is hidden on mobile', () => {
51
+ setupViewport( { isMobileOrLarger: true } );
52
+
53
+ const { result } = renderHook( () =>
54
+ useBlockVisibility( {
55
+ blockVisibility: { mobile: false },
56
+ deviceType: 'mobile',
57
+ } )
58
+ );
59
+
60
+ expect( result.current.isBlockCurrentlyHidden ).toBe( true );
61
+ } );
62
+
63
+ it( 'should return false when deviceType is Mobile and block is visible on mobile', () => {
64
+ setupViewport( { isMobileOrLarger: false } );
65
+
66
+ const { result } = renderHook( () =>
67
+ useBlockVisibility( {
68
+ blockVisibility: {
69
+ mobile: true,
70
+ tablet: false,
71
+ desktop: false,
72
+ },
73
+ deviceType: 'mobile',
74
+ } )
75
+ );
76
+
77
+ expect( result.current.isBlockCurrentlyHidden ).toBe( false );
78
+ } );
79
+
80
+ it( 'should return true when deviceType is Tablet and block is hidden on tablet', () => {
81
+ setupViewport( { isMobileOrLarger: false } );
82
+
83
+ const { result } = renderHook( () =>
84
+ useBlockVisibility( {
85
+ blockVisibility: { tablet: false },
86
+ deviceType: 'tablet',
87
+ } )
88
+ );
89
+
90
+ expect( result.current.isBlockCurrentlyHidden ).toBe( true );
91
+ } );
92
+
93
+ it( 'should use actual viewport detection when deviceType is Desktop', () => {
94
+ setupViewport( {
95
+ isMobileOrLarger: true,
96
+ isMediumOrLarger: true,
97
+ } );
98
+
99
+ const { result } = renderHook( () =>
100
+ useBlockVisibility( {
101
+ blockVisibility: { desktop: false },
102
+ deviceType: 'desktop',
103
+ } )
104
+ );
105
+
106
+ expect( result.current.isBlockCurrentlyHidden ).toBe( true );
107
+ } );
108
+ } );
109
+
110
+ describe( 'Viewport detection with Desktop deviceType', () => {
111
+ it( 'should return true when on mobile viewport and block is hidden on mobile', () => {
112
+ setupViewport( {
113
+ isMobileOrLarger: false,
114
+ isMediumOrLarger: false,
115
+ } );
116
+
117
+ const { result } = renderHook( () =>
118
+ useBlockVisibility( {
119
+ blockVisibility: { mobile: false },
120
+ deviceType: 'desktop',
121
+ } )
122
+ );
123
+
124
+ expect( result.current.isBlockCurrentlyHidden ).toBe( true );
125
+ } );
126
+
127
+ it( 'should return false when on mobile viewport and block is visible on mobile', () => {
128
+ setupViewport( {
129
+ isMobileOrLarger: false,
130
+ isMediumOrLarger: false,
131
+ } );
132
+
133
+ const { result } = renderHook( () =>
134
+ useBlockVisibility( {
135
+ blockVisibility: {
136
+ mobile: true,
137
+ tablet: false,
138
+ desktop: false,
139
+ },
140
+ deviceType: 'desktop',
141
+ } )
142
+ );
143
+
144
+ expect( result.current.isBlockCurrentlyHidden ).toBe( false );
145
+ } );
146
+
147
+ it( 'should return true when on tablet viewport and block is hidden on tablet', () => {
148
+ setupViewport( {
149
+ isMobileOrLarger: true,
150
+ isMediumOrLarger: false,
151
+ } );
152
+
153
+ const { result } = renderHook( () =>
154
+ useBlockVisibility( {
155
+ blockVisibility: { tablet: false },
156
+ deviceType: 'desktop',
157
+ } )
158
+ );
159
+
160
+ expect( result.current.isBlockCurrentlyHidden ).toBe( true );
161
+ } );
162
+
163
+ it( 'should return false when on tablet viewport and block is visible on tablet', () => {
164
+ setupViewport( {
165
+ isMobileOrLarger: true,
166
+ isMediumOrLarger: false,
167
+ } );
168
+
169
+ const { result } = renderHook( () =>
170
+ useBlockVisibility( {
171
+ blockVisibility: {
172
+ mobile: false,
173
+ tablet: true,
174
+ desktop: false,
175
+ },
176
+ deviceType: 'desktop',
177
+ } )
178
+ );
179
+
180
+ expect( result.current.isBlockCurrentlyHidden ).toBe( false );
181
+ } );
182
+
183
+ it( 'should return true when on desktop viewport and block is hidden on desktop', () => {
184
+ setupViewport( {
185
+ isMobileOrLarger: true,
186
+ isMediumOrLarger: true,
187
+ } );
188
+
189
+ const { result } = renderHook( () =>
190
+ useBlockVisibility( {
191
+ blockVisibility: { desktop: false },
192
+ deviceType: 'desktop',
193
+ } )
194
+ );
195
+
196
+ expect( result.current.isBlockCurrentlyHidden ).toBe( true );
197
+ } );
198
+
199
+ it( 'should return false when on desktop viewport and block is visible on desktop', () => {
200
+ setupViewport( {
201
+ isMobileOrLarger: true,
202
+ isMediumOrLarger: true,
203
+ } );
204
+
205
+ const { result } = renderHook( () =>
206
+ useBlockVisibility( {
207
+ blockVisibility: {
208
+ mobile: false,
209
+ tablet: false,
210
+ desktop: true,
211
+ },
212
+ deviceType: 'desktop',
213
+ } )
214
+ );
215
+
216
+ expect( result.current.isBlockCurrentlyHidden ).toBe( false );
217
+ } );
218
+ } );
219
+
220
+ describe( 'Block visibility (hidden everywhere)', () => {
221
+ it( 'should return true when blockVisibility is false', () => {
222
+ setupViewport( { isMobileOrLarger: true } );
223
+
224
+ const { result } = renderHook( () =>
225
+ useBlockVisibility( {
226
+ blockVisibility: false,
227
+ deviceType: 'desktop',
228
+ } )
229
+ );
230
+
231
+ expect( result.current.isBlockCurrentlyHidden ).toBe( true );
232
+ } );
233
+
234
+ it( 'should return false when blockVisibility is true and no viewport restrictions', () => {
235
+ setupViewport( { isMobileOrLarger: true } );
236
+
237
+ const { result } = renderHook( () =>
238
+ useBlockVisibility( {
239
+ blockVisibility: true,
240
+ deviceType: 'desktop',
241
+ } )
242
+ );
243
+
244
+ expect( result.current.isBlockCurrentlyHidden ).toBe( false );
245
+ } );
246
+
247
+ it( 'should return false when blockVisibility is undefined', () => {
248
+ setupViewport( { isMobileOrLarger: true } );
249
+
250
+ const { result } = renderHook( () =>
251
+ useBlockVisibility( {
252
+ blockVisibility: undefined,
253
+ deviceType: 'desktop',
254
+ } )
255
+ );
256
+
257
+ expect( result.current.isBlockCurrentlyHidden ).toBe( false );
258
+ } );
259
+
260
+ it( 'should return true when blockVisibility is false regardless of viewport settings', () => {
261
+ setupViewport( { isMobileOrLarger: true } );
262
+
263
+ const { result } = renderHook( () =>
264
+ useBlockVisibility( {
265
+ blockVisibility: false,
266
+ deviceType: 'desktop',
267
+ } )
268
+ );
269
+
270
+ expect( result.current.isBlockCurrentlyHidden ).toBe( true );
271
+ } );
272
+ } );
273
+
274
+ describe( 'Edge cases', () => {
275
+ it( 'should return false when no visibility settings are defined', () => {
276
+ setupViewport( { isMobileOrLarger: true } );
277
+
278
+ const { result } = renderHook( () =>
279
+ useBlockVisibility( {
280
+ blockVisibility: true,
281
+ deviceType: 'desktop',
282
+ } )
283
+ );
284
+
285
+ expect( result.current.isBlockCurrentlyHidden ).toBe( false );
286
+ } );
287
+
288
+ it( 'should return false when blockVisibility is undefined', () => {
289
+ setupViewport( { isMobileOrLarger: true } );
290
+
291
+ const { result } = renderHook( () =>
292
+ useBlockVisibility( {
293
+ blockVisibility: undefined,
294
+ deviceType: 'desktop',
295
+ } )
296
+ );
297
+
298
+ expect( result.current.isBlockCurrentlyHidden ).toBe( false );
299
+ } );
300
+
301
+ it( 'should default to desktop deviceType when not provided', () => {
302
+ setupViewport( {
303
+ isMobileOrLarger: true,
304
+ isMediumOrLarger: true,
305
+ } );
306
+
307
+ const { result } = renderHook( () =>
308
+ useBlockVisibility( {
309
+ blockVisibility: { desktop: false },
310
+ } )
311
+ );
312
+
313
+ expect( result.current.isBlockCurrentlyHidden ).toBe( true );
314
+ } );
315
+ } );
316
+ } );
@@ -0,0 +1,266 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import {
5
+ getViewportCheckboxState,
6
+ getHideEverywhereCheckboxState,
7
+ } from '../utils';
8
+
9
+ describe( 'block-visibility utils', () => {
10
+ describe( 'getViewportCheckboxState', () => {
11
+ it( 'should return false for empty or invalid input', () => {
12
+ expect( getViewportCheckboxState( [], 'mobile' ) ).toBe( false );
13
+ expect( getViewportCheckboxState( null, 'mobile' ) ).toBe( false );
14
+ expect( getViewportCheckboxState( undefined, 'mobile' ) ).toBe(
15
+ false
16
+ );
17
+ } );
18
+
19
+ it( 'should return false when no blocks are hidden for viewport', () => {
20
+ const blocks = [
21
+ {
22
+ attributes: {
23
+ metadata: {
24
+ blockVisibility: {},
25
+ },
26
+ },
27
+ },
28
+ {
29
+ attributes: {},
30
+ },
31
+ ];
32
+ expect( getViewportCheckboxState( blocks, 'mobile' ) ).toBe(
33
+ false
34
+ );
35
+ } );
36
+
37
+ it( 'should return false when all blocks are hidden everywhere (blockVisibility=false not handled)', () => {
38
+ const blocks = [
39
+ {
40
+ attributes: {
41
+ metadata: {
42
+ blockVisibility: false,
43
+ },
44
+ },
45
+ },
46
+ {
47
+ attributes: {
48
+ metadata: {
49
+ blockVisibility: false,
50
+ },
51
+ },
52
+ },
53
+ ];
54
+ // Note: isBlockHiddenForViewport doesn't check for blockVisibility === false,
55
+ // so it treats false as a non-object and returns false (not hidden)
56
+ expect( getViewportCheckboxState( blocks, 'mobile' ) ).toBe(
57
+ false
58
+ );
59
+ expect( getViewportCheckboxState( blocks, 'tablet' ) ).toBe(
60
+ false
61
+ );
62
+ expect( getViewportCheckboxState( blocks, 'desktop' ) ).toBe(
63
+ false
64
+ );
65
+ } );
66
+
67
+ it( 'should return null when some blocks are hidden for viewport', () => {
68
+ // Suppress console.log from getViewportCheckboxState
69
+ const consoleSpy = jest
70
+ .spyOn( console, 'log' )
71
+ .mockImplementation( () => {} );
72
+
73
+ const blocks = [
74
+ {
75
+ attributes: {
76
+ metadata: {
77
+ blockVisibility: {
78
+ mobile: false,
79
+ },
80
+ },
81
+ },
82
+ },
83
+ {
84
+ attributes: {
85
+ metadata: {
86
+ blockVisibility: {},
87
+ },
88
+ },
89
+ },
90
+ ];
91
+ expect( getViewportCheckboxState( blocks, 'mobile' ) ).toBe( null );
92
+
93
+ consoleSpy.mockRestore();
94
+ } );
95
+
96
+ it( 'should return false when some blocks have blockVisibility=false (not handled)', () => {
97
+ const blocks = [
98
+ {
99
+ attributes: {
100
+ metadata: {
101
+ blockVisibility: false,
102
+ },
103
+ },
104
+ },
105
+ {
106
+ attributes: {
107
+ metadata: {
108
+ blockVisibility: {},
109
+ },
110
+ },
111
+ },
112
+ ];
113
+ // Note: isBlockHiddenForViewport doesn't check for blockVisibility === false,
114
+ // so both blocks are treated as not hidden, resulting in false
115
+ expect( getViewportCheckboxState( blocks, 'mobile' ) ).toBe(
116
+ false
117
+ );
118
+ } );
119
+
120
+ it( 'should return false for invalid viewport', () => {
121
+ const block = {
122
+ attributes: {
123
+ metadata: {
124
+ blockVisibility: {
125
+ mobile: false,
126
+ },
127
+ },
128
+ },
129
+ };
130
+ expect( getViewportCheckboxState( [ block ], 'invalid' ) ).toBe(
131
+ false
132
+ );
133
+ } );
134
+
135
+ it( 'should return false when blockVisibility === true exists', () => {
136
+ // Test with blockVisibility=false (not handled by isBlockHiddenForViewport)
137
+ const blocks1 = [
138
+ {
139
+ attributes: {
140
+ metadata: {
141
+ blockVisibility: true,
142
+ },
143
+ },
144
+ },
145
+ {
146
+ attributes: {
147
+ metadata: {
148
+ blockVisibility: false,
149
+ },
150
+ },
151
+ },
152
+ ];
153
+ // First block is explicitly visible (true), second has blockVisibility=false
154
+ // which is not handled, so both are treated as not hidden
155
+ expect( getViewportCheckboxState( blocks1, 'mobile' ) ).toBe(
156
+ false
157
+ );
158
+
159
+ // Test with no metadata
160
+ const blocks2 = [
161
+ {
162
+ attributes: {
163
+ metadata: {
164
+ blockVisibility: true,
165
+ },
166
+ },
167
+ },
168
+ {
169
+ attributes: {},
170
+ },
171
+ ];
172
+ // Both blocks are not hidden (first is explicitly visible, second has no visibility set)
173
+ expect( getViewportCheckboxState( blocks2, 'mobile' ) ).toBe(
174
+ false
175
+ );
176
+ } );
177
+ } );
178
+
179
+ describe( 'getHideEverywhereCheckboxState', () => {
180
+ it( 'should return false for empty or invalid input', () => {
181
+ expect( getHideEverywhereCheckboxState( [] ) ).toBe( false );
182
+ expect( getHideEverywhereCheckboxState( null ) ).toBe( false );
183
+ expect( getHideEverywhereCheckboxState( undefined ) ).toBe( false );
184
+ } );
185
+
186
+ it( 'should return false when no blocks are hidden everywhere', () => {
187
+ const blocks = [
188
+ {
189
+ attributes: {
190
+ metadata: {
191
+ blockVisibility: {},
192
+ },
193
+ },
194
+ },
195
+ {
196
+ attributes: {},
197
+ },
198
+ ];
199
+ expect( getHideEverywhereCheckboxState( blocks ) ).toBe( false );
200
+ } );
201
+
202
+ it( 'should return true when all blocks are hidden everywhere', () => {
203
+ const blocks = [
204
+ {
205
+ attributes: {
206
+ metadata: {
207
+ blockVisibility: false,
208
+ },
209
+ },
210
+ },
211
+ {
212
+ attributes: {
213
+ metadata: {
214
+ blockVisibility: false,
215
+ },
216
+ },
217
+ },
218
+ ];
219
+ expect( getHideEverywhereCheckboxState( blocks ) ).toBe( true );
220
+ } );
221
+
222
+ it( 'should return null when some blocks are hidden everywhere', () => {
223
+ const blocks = [
224
+ {
225
+ attributes: {
226
+ metadata: {
227
+ blockVisibility: false,
228
+ },
229
+ },
230
+ },
231
+ {
232
+ attributes: {
233
+ metadata: {
234
+ blockVisibility: {},
235
+ },
236
+ },
237
+ },
238
+ ];
239
+ expect( getHideEverywhereCheckboxState( blocks ) ).toBe( null );
240
+ } );
241
+
242
+ it( 'should return false when blocks have viewport-specific visibility', () => {
243
+ const blocks = [
244
+ {
245
+ attributes: {
246
+ metadata: {
247
+ blockVisibility: {
248
+ mobile: false,
249
+ },
250
+ },
251
+ },
252
+ },
253
+ {
254
+ attributes: {
255
+ metadata: {
256
+ blockVisibility: {
257
+ tablet: false,
258
+ },
259
+ },
260
+ },
261
+ },
262
+ ];
263
+ expect( getHideEverywhereCheckboxState( blocks ) ).toBe( false );
264
+ } );
265
+ } );
266
+ } );
@@ -75,7 +75,7 @@ export default function BlockVisibilityToolbar( { clientIds } ) {
75
75
 
76
76
  return (
77
77
  <>
78
- <ToolbarGroup className="block-editor-block-lock-toolbar">
78
+ <ToolbarGroup>
79
79
  <ToolbarButton
80
80
  disabled={ ! canToggleBlockVisibility }
81
81
  icon={ hasHiddenBlock ? unseen : seen }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useViewportMatch } from '@wordpress/compose';
5
+ import { useMemo } from '@wordpress/element';
6
+
7
+ /**
8
+ * Internal dependencies
9
+ */
10
+ import { BLOCK_VISIBILITY_VIEWPORTS } from './constants';
11
+
12
+ /**
13
+ * Returns information about the current block visibility state.
14
+ *
15
+ * @param {Object} options Parameters to avoid extra store subscriptions.
16
+ * @param {Object|boolean} options.blockVisibility Block visibility metadata.
17
+ * @param {string} options.deviceType Current device type ('desktop', 'tablet', 'mobile').
18
+ * @return {Object} Object with `isBlockCurrentlyHidden` and `currentViewport` boolean properties.
19
+ */
20
+ export default function useBlockVisibility( options = {} ) {
21
+ const {
22
+ blockVisibility = undefined,
23
+ deviceType = BLOCK_VISIBILITY_VIEWPORTS.desktop.key,
24
+ } = options;
25
+
26
+ const isLargerThanMobile = useViewportMatch( 'mobile', '>=' ); // >= 480px
27
+ const isLargerThanTablet = useViewportMatch( 'medium', '>=' ); // >= 782px
28
+
29
+ /*
30
+ * Priority:
31
+ * 1. Device type override (Mobile/Tablet) - uses device type to determine viewport
32
+ * 2. Actual window size (Desktop mode) - uses viewport detection
33
+ */
34
+ const currentViewport = useMemo( () => {
35
+ if ( deviceType === BLOCK_VISIBILITY_VIEWPORTS.mobile.key ) {
36
+ return BLOCK_VISIBILITY_VIEWPORTS.mobile.key;
37
+ }
38
+ if ( deviceType === BLOCK_VISIBILITY_VIEWPORTS.tablet.key ) {
39
+ return BLOCK_VISIBILITY_VIEWPORTS.tablet.key;
40
+ }
41
+ if ( ! isLargerThanMobile ) {
42
+ return BLOCK_VISIBILITY_VIEWPORTS.mobile.key;
43
+ }
44
+ if ( isLargerThanMobile && ! isLargerThanTablet ) {
45
+ return BLOCK_VISIBILITY_VIEWPORTS.tablet.key;
46
+ }
47
+ return BLOCK_VISIBILITY_VIEWPORTS.desktop.key;
48
+ }, [ deviceType, isLargerThanMobile, isLargerThanTablet ] );
49
+
50
+ // Determine if block is currently hidden.
51
+ const isBlockCurrentlyHidden = useMemo( () => {
52
+ if ( blockVisibility === false ) {
53
+ return true;
54
+ }
55
+
56
+ if (
57
+ window.__experimentalHideBlocksBasedOnScreenSize &&
58
+ blockVisibility?.[ currentViewport ] === false
59
+ ) {
60
+ return true;
61
+ }
62
+
63
+ return false;
64
+ }, [ blockVisibility, currentViewport ] );
65
+
66
+ return {
67
+ isBlockCurrentlyHidden,
68
+ currentViewport,
69
+ };
70
+ }