@wordpress/block-editor 15.10.1-next.79a2f3cdd.0 → 15.10.1-next.ba3aee3a2.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 (97) hide show
  1. package/build/components/block-edit/context.cjs +5 -5
  2. package/build/components/block-edit/context.cjs.map +1 -1
  3. package/build/components/block-list/block.cjs +24 -12
  4. package/build/components/block-list/block.cjs.map +3 -3
  5. package/build/components/block-list/use-block-props/index.cjs +8 -2
  6. package/build/components/block-list/use-block-props/index.cjs.map +2 -2
  7. package/build/components/block-visibility/constants.cjs +49 -0
  8. package/build/components/block-visibility/constants.cjs.map +7 -0
  9. package/build/components/block-visibility/index.cjs +5 -2
  10. package/build/components/block-visibility/index.cjs.map +2 -2
  11. package/build/components/block-visibility/use-block-visibility.cjs +69 -0
  12. package/build/components/block-visibility/use-block-visibility.cjs.map +7 -0
  13. package/build/components/collab/block-comment-icon-slot.cjs +1 -1
  14. package/build/components/collab/block-comment-icon-slot.cjs.map +1 -1
  15. package/build/components/collab/block-comment-icon-toolbar-slot.cjs +1 -1
  16. package/build/components/collab/block-comment-icon-toolbar-slot.cjs.map +1 -1
  17. package/build/components/inspector-controls/groups.cjs +1 -1
  18. package/build/components/inspector-controls/groups.cjs.map +1 -1
  19. package/build/components/inspector-controls-tabs/content-tab.cjs +1 -1
  20. package/build/components/inspector-controls-tabs/content-tab.cjs.map +2 -2
  21. package/build/components/list-view/index.cjs +11 -6
  22. package/build/components/list-view/index.cjs.map +2 -2
  23. package/build/components/list-view/utils.cjs +24 -17
  24. package/build/components/list-view/utils.cjs.map +2 -2
  25. package/build/components/rich-text/event-listeners/input-rules.cjs +13 -1
  26. package/build/components/rich-text/event-listeners/input-rules.cjs.map +2 -2
  27. package/build/components/rich-text/format-edit.cjs +1 -1
  28. package/build/components/rich-text/format-edit.cjs.map +1 -1
  29. package/build/components/rich-text/index.cjs +1 -1
  30. package/build/components/rich-text/index.cjs.map +1 -1
  31. package/build/components/writing-flow/utils.cjs +1 -1
  32. package/build/components/writing-flow/utils.cjs.map +1 -1
  33. package/build/hooks/block-fields/index.cjs +1 -1
  34. package/build/hooks/block-fields/index.cjs.map +2 -2
  35. package/build/hooks/fit-text.cjs +1 -1
  36. package/build/hooks/fit-text.cjs.map +1 -1
  37. package/build/store/private-keys.cjs +10 -10
  38. package/build/store/private-keys.cjs.map +1 -1
  39. package/build/store/utils.cjs +1 -1
  40. package/build/store/utils.cjs.map +1 -1
  41. package/build-module/components/block-edit/context.mjs +5 -5
  42. package/build-module/components/block-edit/context.mjs.map +1 -1
  43. package/build-module/components/block-list/block.mjs +24 -12
  44. package/build-module/components/block-list/block.mjs.map +3 -3
  45. package/build-module/components/block-list/use-block-props/index.mjs +8 -2
  46. package/build-module/components/block-list/use-block-props/index.mjs.map +2 -2
  47. package/build-module/components/block-visibility/constants.mjs +24 -0
  48. package/build-module/components/block-visibility/constants.mjs.map +7 -0
  49. package/build-module/components/block-visibility/index.mjs +3 -1
  50. package/build-module/components/block-visibility/index.mjs.map +2 -2
  51. package/build-module/components/block-visibility/use-block-visibility.mjs +44 -0
  52. package/build-module/components/block-visibility/use-block-visibility.mjs.map +7 -0
  53. package/build-module/components/collab/block-comment-icon-slot.mjs +1 -1
  54. package/build-module/components/collab/block-comment-icon-slot.mjs.map +1 -1
  55. package/build-module/components/collab/block-comment-icon-toolbar-slot.mjs +1 -1
  56. package/build-module/components/collab/block-comment-icon-toolbar-slot.mjs.map +1 -1
  57. package/build-module/components/inspector-controls/groups.mjs +1 -1
  58. package/build-module/components/inspector-controls/groups.mjs.map +1 -1
  59. package/build-module/components/inspector-controls-tabs/content-tab.mjs +1 -1
  60. package/build-module/components/inspector-controls-tabs/content-tab.mjs.map +2 -2
  61. package/build-module/components/list-view/index.mjs +11 -7
  62. package/build-module/components/list-view/index.mjs.map +2 -2
  63. package/build-module/components/list-view/utils.mjs +24 -17
  64. package/build-module/components/list-view/utils.mjs.map +2 -2
  65. package/build-module/components/rich-text/event-listeners/input-rules.mjs +13 -1
  66. package/build-module/components/rich-text/event-listeners/input-rules.mjs.map +2 -2
  67. package/build-module/components/rich-text/format-edit.mjs +1 -1
  68. package/build-module/components/rich-text/format-edit.mjs.map +1 -1
  69. package/build-module/components/rich-text/index.mjs +1 -1
  70. package/build-module/components/rich-text/index.mjs.map +1 -1
  71. package/build-module/components/writing-flow/utils.mjs +1 -1
  72. package/build-module/components/writing-flow/utils.mjs.map +1 -1
  73. package/build-module/hooks/block-fields/index.mjs +1 -1
  74. package/build-module/hooks/block-fields/index.mjs.map +2 -2
  75. package/build-module/hooks/fit-text.mjs +1 -1
  76. package/build-module/hooks/fit-text.mjs.map +1 -1
  77. package/build-module/store/private-keys.mjs +10 -10
  78. package/build-module/store/private-keys.mjs.map +1 -1
  79. package/build-module/store/utils.mjs +1 -1
  80. package/build-module/store/utils.mjs.map +1 -1
  81. package/build-style/style-rtl.css +6 -1
  82. package/build-style/style.css +6 -1
  83. package/package.json +39 -39
  84. package/src/components/block-list/block.js +23 -9
  85. package/src/components/block-list/use-block-props/index.js +10 -2
  86. package/src/components/block-toolbar/style.scss +0 -1
  87. package/src/components/block-tools/style.scss +10 -0
  88. package/src/components/block-visibility/constants.js +29 -0
  89. package/src/components/block-visibility/index.js +1 -0
  90. package/src/components/block-visibility/test/use-block-visibility.js +360 -0
  91. package/src/components/block-visibility/use-block-visibility.js +73 -0
  92. package/src/components/inspector-controls-tabs/content-tab.js +0 -1
  93. package/src/components/list-view/index.js +15 -11
  94. package/src/components/list-view/utils.js +31 -23
  95. package/src/components/rich-text/event-listeners/input-rules.js +17 -0
  96. package/src/hooks/block-fields/index.js +0 -1
  97. package/src/hooks/fit-text.js +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/block-editor",
3
- "version": "15.10.1-next.79a2f3cdd.0",
3
+ "version": "15.10.1-next.ba3aee3a2.0",
4
4
  "description": "Generic block editor.",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -61,43 +61,43 @@
61
61
  ],
62
62
  "dependencies": {
63
63
  "@react-spring/web": "^9.4.5",
64
- "@wordpress/a11y": "^4.37.1-next.79a2f3cdd.0",
65
- "@wordpress/api-fetch": "^7.37.1-next.79a2f3cdd.0",
66
- "@wordpress/base-styles": "^6.13.2-next.79a2f3cdd.0",
67
- "@wordpress/blob": "^4.37.1-next.79a2f3cdd.0",
68
- "@wordpress/block-serialization-default-parser": "^5.37.1-next.79a2f3cdd.0",
69
- "@wordpress/blocks": "^15.10.1-next.79a2f3cdd.0",
70
- "@wordpress/commands": "^1.37.1-next.79a2f3cdd.0",
71
- "@wordpress/components": "^32.0.1-next.79a2f3cdd.0",
72
- "@wordpress/compose": "^7.37.1-next.79a2f3cdd.0",
73
- "@wordpress/data": "^10.37.1-next.79a2f3cdd.0",
74
- "@wordpress/dataviews": "^11.2.1-next.79a2f3cdd.0",
75
- "@wordpress/date": "^5.37.2-next.79a2f3cdd.0",
76
- "@wordpress/deprecated": "^4.37.1-next.79a2f3cdd.0",
77
- "@wordpress/dom": "^4.37.1-next.79a2f3cdd.0",
78
- "@wordpress/element": "^6.37.1-next.79a2f3cdd.0",
79
- "@wordpress/escape-html": "^3.37.1-next.79a2f3cdd.0",
80
- "@wordpress/global-styles-engine": "^1.4.1-next.79a2f3cdd.0",
81
- "@wordpress/hooks": "^4.37.1-next.79a2f3cdd.0",
82
- "@wordpress/html-entities": "^4.37.1-next.79a2f3cdd.0",
83
- "@wordpress/i18n": "^6.10.1-next.79a2f3cdd.0",
84
- "@wordpress/icons": "^11.4.1-next.79a2f3cdd.0",
85
- "@wordpress/image-cropper": "^1.1.1-next.79a2f3cdd.0",
86
- "@wordpress/interactivity": "^6.37.1-next.79a2f3cdd.0",
87
- "@wordpress/is-shallow-equal": "^5.37.1-next.79a2f3cdd.0",
88
- "@wordpress/keyboard-shortcuts": "^5.37.1-next.79a2f3cdd.0",
89
- "@wordpress/keycodes": "^4.38.1-next.79a2f3cdd.0",
90
- "@wordpress/notices": "^5.37.1-next.79a2f3cdd.0",
91
- "@wordpress/preferences": "^4.37.1-next.79a2f3cdd.0",
92
- "@wordpress/priority-queue": "^3.37.1-next.79a2f3cdd.0",
93
- "@wordpress/private-apis": "^1.37.1-next.79a2f3cdd.0",
94
- "@wordpress/rich-text": "^7.37.1-next.79a2f3cdd.0",
95
- "@wordpress/style-engine": "^2.37.1-next.79a2f3cdd.0",
96
- "@wordpress/token-list": "^3.37.1-next.79a2f3cdd.0",
97
- "@wordpress/upload-media": "^0.22.1-next.79a2f3cdd.0",
98
- "@wordpress/url": "^4.37.1-next.79a2f3cdd.0",
99
- "@wordpress/warning": "^3.37.1-next.79a2f3cdd.0",
100
- "@wordpress/wordcount": "^4.37.1-next.79a2f3cdd.0",
64
+ "@wordpress/a11y": "^4.37.1-next.ba3aee3a2.0",
65
+ "@wordpress/api-fetch": "^7.37.1-next.ba3aee3a2.0",
66
+ "@wordpress/base-styles": "^6.13.2-next.ba3aee3a2.0",
67
+ "@wordpress/blob": "^4.37.1-next.ba3aee3a2.0",
68
+ "@wordpress/block-serialization-default-parser": "^5.37.1-next.ba3aee3a2.0",
69
+ "@wordpress/blocks": "^15.10.1-next.ba3aee3a2.0",
70
+ "@wordpress/commands": "^1.37.1-next.ba3aee3a2.0",
71
+ "@wordpress/components": "^32.0.1-next.ba3aee3a2.0",
72
+ "@wordpress/compose": "^7.37.1-next.ba3aee3a2.0",
73
+ "@wordpress/data": "^10.37.1-next.ba3aee3a2.0",
74
+ "@wordpress/dataviews": "^11.2.1-next.ba3aee3a2.0",
75
+ "@wordpress/date": "^5.37.2-next.ba3aee3a2.0",
76
+ "@wordpress/deprecated": "^4.37.1-next.ba3aee3a2.0",
77
+ "@wordpress/dom": "^4.37.1-next.ba3aee3a2.0",
78
+ "@wordpress/element": "^6.37.1-next.ba3aee3a2.0",
79
+ "@wordpress/escape-html": "^3.37.1-next.ba3aee3a2.0",
80
+ "@wordpress/global-styles-engine": "^1.4.1-next.ba3aee3a2.0",
81
+ "@wordpress/hooks": "^4.37.1-next.ba3aee3a2.0",
82
+ "@wordpress/html-entities": "^4.37.1-next.ba3aee3a2.0",
83
+ "@wordpress/i18n": "^6.10.1-next.ba3aee3a2.0",
84
+ "@wordpress/icons": "^11.4.1-next.ba3aee3a2.0",
85
+ "@wordpress/image-cropper": "^1.1.1-next.ba3aee3a2.0",
86
+ "@wordpress/interactivity": "^6.37.2-next.ba3aee3a2.0",
87
+ "@wordpress/is-shallow-equal": "^5.37.1-next.ba3aee3a2.0",
88
+ "@wordpress/keyboard-shortcuts": "^5.37.1-next.ba3aee3a2.0",
89
+ "@wordpress/keycodes": "^4.38.1-next.ba3aee3a2.0",
90
+ "@wordpress/notices": "^5.37.1-next.ba3aee3a2.0",
91
+ "@wordpress/preferences": "^4.37.1-next.ba3aee3a2.0",
92
+ "@wordpress/priority-queue": "^3.37.1-next.ba3aee3a2.0",
93
+ "@wordpress/private-apis": "^1.37.1-next.ba3aee3a2.0",
94
+ "@wordpress/rich-text": "^7.37.1-next.ba3aee3a2.0",
95
+ "@wordpress/style-engine": "^2.37.1-next.ba3aee3a2.0",
96
+ "@wordpress/token-list": "^3.37.1-next.ba3aee3a2.0",
97
+ "@wordpress/upload-media": "^0.22.1-next.ba3aee3a2.0",
98
+ "@wordpress/url": "^4.37.1-next.ba3aee3a2.0",
99
+ "@wordpress/warning": "^3.37.1-next.ba3aee3a2.0",
100
+ "@wordpress/wordcount": "^4.37.1-next.ba3aee3a2.0",
101
101
  "change-case": "^4.1.2",
102
102
  "clsx": "^2.1.1",
103
103
  "colord": "^2.7.0",
@@ -124,5 +124,5 @@
124
124
  "publishConfig": {
125
125
  "access": "public"
126
126
  },
127
- "gitHead": "6a324496a37d9a333a11d4d7fe5fb93b8152a5ba"
127
+ "gitHead": "67d2e486fcd40c753591cf911ca0659132f519ca"
128
128
  }
@@ -38,8 +38,9 @@ import { useBlockProps } from './use-block-props';
38
38
  import { store as blockEditorStore } from '../../store';
39
39
  import { useLayout } from './layout';
40
40
  import { PrivateBlockContext } from './private-block-context';
41
-
41
+ import { useBlockVisibility } from '../block-visibility/';
42
42
  import { unlock } from '../../lock-unlock';
43
+ import { deviceTypeKey } from '../../store/private-keys';
43
44
 
44
45
  /**
45
46
  * Merges wrapper props with special handling for classNames and styles.
@@ -607,16 +608,17 @@ function BlockListBlockProvider( props ) {
607
608
  const attributes = getBlockAttributes( clientId );
608
609
  const { name: blockName, isValid } = blockWithoutAttributes;
609
610
  const blockType = getBlockType( blockName );
611
+ const settings = getSettings();
610
612
  const {
611
613
  supportsLayout,
612
614
  isPreviewMode,
613
615
  __experimentalBlockBindingsSupportedAttributes,
614
- } = getSettings();
615
- const { isBlockHidden: _isBlockHidden } = unlock(
616
- select( blockEditorStore )
617
- );
616
+ } = settings;
618
617
  const bindableAttributes =
619
618
  __experimentalBlockBindingsSupportedAttributes?.[ blockName ];
619
+ const blockVisibility = attributes?.metadata?.blockVisibility;
620
+ const deviceType =
621
+ settings?.[ deviceTypeKey ]?.toLowerCase() || 'desktop';
620
622
 
621
623
  const hasLightBlockWrapper = blockType?.apiVersion > 1;
622
624
  const previewContext = {
@@ -635,8 +637,9 @@ function BlockListBlockProvider( props ) {
635
637
  ? getBlockDefaultClassName( blockName )
636
638
  : undefined,
637
639
  blockTitle: blockType?.title,
638
- isBlockHidden: _isBlockHidden( clientId ),
639
640
  bindableAttributes,
641
+ blockVisibility,
642
+ deviceType,
640
643
  };
641
644
 
642
645
  // When in preview mode, we can avoid a lot of selection and
@@ -725,6 +728,8 @@ function BlockListBlockProvider( props ) {
725
728
  originalBlockClientId: isInvalid
726
729
  ? blocksWithSameName[ 0 ]
727
730
  : false,
731
+ blockVisibility,
732
+ deviceType,
728
733
  };
729
734
  },
730
735
  [ clientId, rootClientId ]
@@ -770,10 +775,17 @@ function BlockListBlockProvider( props ) {
770
775
  className,
771
776
  defaultClassName,
772
777
  originalBlockClientId,
773
- isBlockHidden,
774
778
  bindableAttributes,
779
+ blockVisibility,
780
+ deviceType,
775
781
  } = selectedProps;
776
782
 
783
+ // Use block visibility hook with data from existing useSelect to avoid extra subscription
784
+ const { isBlockCurrentlyHidden } = useBlockVisibility( {
785
+ blockVisibility,
786
+ deviceType,
787
+ } );
788
+
777
789
  // Users of the editor.BlockListBlock filter used to be able to
778
790
  // access the block prop.
779
791
  // Ideally these blocks would rely on the clientId prop only.
@@ -823,12 +835,14 @@ function BlockListBlockProvider( props ) {
823
835
  originalBlockClientId,
824
836
  themeSupportsLayout,
825
837
  canMove,
826
- isBlockHidden,
838
+ isBlockCurrentlyHidden,
827
839
  bindableAttributes,
840
+ blockVisibility,
841
+ deviceType,
828
842
  };
829
843
 
830
844
  if (
831
- isBlockHidden &&
845
+ isBlockCurrentlyHidden &&
832
846
  ! isSelected &&
833
847
  ! isMultiSelected &&
834
848
  ! hasChildSelected
@@ -30,6 +30,7 @@ import { useIntersectionObserver } from './use-intersection-observer';
30
30
  import { useScrollIntoView } from './use-scroll-into-view';
31
31
  import { useFlashEditableBlocks } from '../../use-flash-editable-blocks';
32
32
  import { useFirefoxDraggableCompatibility } from './use-firefox-draggable-compatibility';
33
+ import { useBlockVisibility } from '../../block-visibility/';
33
34
 
34
35
  /**
35
36
  * This hook is used to lightly mark an element as a block element. The element
@@ -102,7 +103,8 @@ export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) {
102
103
  isSectionBlock,
103
104
  isWithinSectionBlock,
104
105
  canMove,
105
- isBlockHidden,
106
+ blockVisibility,
107
+ deviceType,
106
108
  } = useContext( PrivateBlockContext );
107
109
 
108
110
  // translators: %s: Type of block (i.e. Text, Image etc)
@@ -138,6 +140,12 @@ export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) {
138
140
  }
139
141
  : {};
140
142
 
143
+ // Use block visibility hook with data from context to avoid extra subscription.
144
+ const { isBlockCurrentlyHidden } = useBlockVisibility( {
145
+ blockVisibility,
146
+ deviceType,
147
+ } );
148
+
141
149
  // Ensures it warns only inside the `edit` implementation for the block.
142
150
  if ( blockApiVersion < 2 && clientId === blockEditContext.clientId ) {
143
151
  warning(
@@ -185,7 +193,7 @@ export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) {
185
193
  'has-editable-outline': hasEditableOutline,
186
194
  'has-negative-margin': hasNegativeMargin,
187
195
  'is-editing-content-only-section': isEditingContentOnlySection,
188
- 'is-block-hidden': isBlockHidden,
196
+ 'is-block-hidden': isBlockCurrentlyHidden,
189
197
  },
190
198
  className,
191
199
  props.className,
@@ -141,7 +141,6 @@
141
141
  display: inline-flex;
142
142
  height: 2px;
143
143
  position: absolute;
144
- right: 0;
145
144
  top: $grid-unit-20 - $border-width;
146
145
  width: 2px;
147
146
  }
@@ -166,6 +166,11 @@
166
166
  content: "";
167
167
  }
168
168
 
169
+ // Hide the dot divider since the parent selector is visually separated.
170
+ &::after {
171
+ display: none;
172
+ }
173
+
169
174
  .block-editor-block-parent-selector__button {
170
175
  border: $border-width solid $gray-900;
171
176
  padding-right: 6px;
@@ -186,6 +191,11 @@
186
191
  position: relative;
187
192
  left: auto;
188
193
  margin-left: -$border-width;
194
+
195
+ // Show the dot divider since the parent selector is inline.
196
+ &::after {
197
+ display: inline-flex;
198
+ }
189
199
  }
190
200
 
191
201
  .block-editor-block-mover__move-button-container,
@@ -0,0 +1,29 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { __ } from '@wordpress/i18n';
5
+ import { desktop, tablet, mobile } from '@wordpress/icons';
6
+
7
+ /**
8
+ * The choices for the block visibility.
9
+ * Must match those in packages/editor/src/components/preview-dropdown/index.js.
10
+ *
11
+ * @todo create a single source of truth for the viewport types.
12
+ */
13
+ export const BLOCK_VISIBILITY_VIEWPORTS = {
14
+ desktop: {
15
+ label: __( 'Desktop' ),
16
+ icon: desktop,
17
+ value: 'desktop',
18
+ },
19
+ tablet: {
20
+ label: __( 'Tablet' ),
21
+ icon: tablet,
22
+ value: 'tablet',
23
+ },
24
+ mobile: {
25
+ label: __( 'Mobile' ),
26
+ icon: mobile,
27
+ value: 'mobile',
28
+ },
29
+ };
@@ -1,2 +1,3 @@
1
1
  export { default as BlockVisibilityMenuItem } from './menu-item';
2
2
  export { default as BlockVisibilityToolbar } from './toolbar';
3
+ export { useBlockVisibility } from './use-block-visibility';
@@ -0,0 +1,360 @@
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( 'Default values', () => {
275
+ it( 'should return false when no options are provided', () => {
276
+ setupViewport( {
277
+ isMobileOrLarger: true,
278
+ isMediumOrLarger: true,
279
+ } );
280
+
281
+ const { result } = renderHook( () => useBlockVisibility( {} ) );
282
+
283
+ expect( result.current.isBlockCurrentlyHidden ).toBe( false );
284
+ expect( result.current.currentViewport ).toBe( 'desktop' );
285
+ } );
286
+
287
+ it( 'should default to desktop deviceType when not provided', () => {
288
+ setupViewport( {
289
+ isMobileOrLarger: true,
290
+ isMediumOrLarger: true,
291
+ } );
292
+
293
+ const { result } = renderHook( () =>
294
+ useBlockVisibility( {
295
+ blockVisibility: { desktop: false },
296
+ } )
297
+ );
298
+
299
+ expect( result.current.isBlockCurrentlyHidden ).toBe( true );
300
+ expect( result.current.currentViewport ).toBe( 'desktop' );
301
+ } );
302
+
303
+ it( 'should default to undefined blockVisibility when not provided', () => {
304
+ setupViewport( {
305
+ isMobileOrLarger: true,
306
+ isMediumOrLarger: true,
307
+ } );
308
+
309
+ const { result } = renderHook( () =>
310
+ useBlockVisibility( {
311
+ deviceType: 'desktop',
312
+ } )
313
+ );
314
+
315
+ expect( result.current.isBlockCurrentlyHidden ).toBe( false );
316
+ } );
317
+ } );
318
+
319
+ describe( 'Edge cases', () => {
320
+ it( 'should return false when blockVisibility is an empty object', () => {
321
+ setupViewport( { isMobileOrLarger: true } );
322
+
323
+ const { result } = renderHook( () =>
324
+ useBlockVisibility( {
325
+ blockVisibility: {},
326
+ deviceType: 'desktop',
327
+ } )
328
+ );
329
+
330
+ expect( result.current.isBlockCurrentlyHidden ).toBe( false );
331
+ } );
332
+
333
+ it( 'should handle null blockVisibility', () => {
334
+ setupViewport( { isMobileOrLarger: true } );
335
+
336
+ const { result } = renderHook( () =>
337
+ useBlockVisibility( {
338
+ blockVisibility: null,
339
+ deviceType: 'desktop',
340
+ } )
341
+ );
342
+
343
+ expect( result.current.isBlockCurrentlyHidden ).toBe( false );
344
+ } );
345
+
346
+ it( 'should handle case-insensitive deviceType', () => {
347
+ setupViewport( { isMobileOrLarger: true } );
348
+
349
+ const { result } = renderHook( () =>
350
+ useBlockVisibility( {
351
+ blockVisibility: { mobile: false },
352
+ deviceType: 'MOBILE',
353
+ } )
354
+ );
355
+
356
+ // Should still work but viewport detection uses lowercase
357
+ expect( result.current.currentViewport ).toBe( 'desktop' );
358
+ } );
359
+ } );
360
+ } );