@wordpress/block-editor 15.14.1-next.v.202603102151.0 → 15.15.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 (112) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/components/block-bindings/attribute-control.cjs +5 -2
  3. package/build/components/block-bindings/attribute-control.cjs.map +2 -2
  4. package/build/components/block-inspector/edit-contents.cjs +5 -4
  5. package/build/components/block-inspector/edit-contents.cjs.map +2 -2
  6. package/build/components/block-list/block.cjs +9 -1
  7. package/build/components/block-list/block.cjs.map +2 -2
  8. package/build/components/block-list/use-block-props/index.cjs +10 -1
  9. package/build/components/block-list/use-block-props/index.cjs.map +2 -2
  10. package/build/components/block-styles/index.cjs +7 -1
  11. package/build/components/block-styles/index.cjs.map +3 -3
  12. package/build/components/block-variation-transforms/index.cjs +11 -5
  13. package/build/components/block-variation-transforms/index.cjs.map +2 -2
  14. package/build/components/block-visibility/use-block-visibility.cjs +4 -3
  15. package/build/components/block-visibility/use-block-visibility.cjs.map +2 -2
  16. package/build/components/global-styles/color-panel.cjs +1 -1
  17. package/build/components/global-styles/color-panel.cjs.map +2 -2
  18. package/build/components/global-styles/filters-panel.cjs.map +2 -2
  19. package/build/components/global-styles/index.cjs +3 -0
  20. package/build/components/global-styles/index.cjs.map +2 -2
  21. package/build/components/global-styles/state-control.cjs +81 -0
  22. package/build/components/global-styles/state-control.cjs.map +7 -0
  23. package/build/components/iframe/index.cjs +1 -3
  24. package/build/components/iframe/index.cjs.map +2 -2
  25. package/build/components/iframe/use-scale-canvas.cjs +0 -1
  26. package/build/components/iframe/use-scale-canvas.cjs.map +2 -2
  27. package/build/components/provider/index.cjs +1 -1
  28. package/build/components/provider/index.cjs.map +2 -2
  29. package/build/components/provider/use-media-upload-settings.cjs +1 -0
  30. package/build/components/provider/use-media-upload-settings.cjs.map +2 -2
  31. package/build/hooks/block-fields/media/index.cjs +140 -101
  32. package/build/hooks/block-fields/media/index.cjs.map +3 -3
  33. package/build/private-apis.cjs +1 -0
  34. package/build/private-apis.cjs.map +2 -2
  35. package/build/store/private-keys.cjs +3 -0
  36. package/build/store/private-keys.cjs.map +2 -2
  37. package/build/store/private-selectors.cjs +2 -1
  38. package/build/store/private-selectors.cjs.map +2 -2
  39. package/build/store/reducer.cjs +3 -4
  40. package/build/store/reducer.cjs.map +2 -2
  41. package/build/store/selectors.cjs +4 -4
  42. package/build/store/selectors.cjs.map +2 -2
  43. package/build-module/components/block-bindings/attribute-control.mjs +5 -2
  44. package/build-module/components/block-bindings/attribute-control.mjs.map +2 -2
  45. package/build-module/components/block-inspector/edit-contents.mjs +5 -4
  46. package/build-module/components/block-inspector/edit-contents.mjs.map +2 -2
  47. package/build-module/components/block-list/block.mjs +10 -2
  48. package/build-module/components/block-list/block.mjs.map +2 -2
  49. package/build-module/components/block-list/use-block-props/index.mjs +11 -2
  50. package/build-module/components/block-list/use-block-props/index.mjs.map +2 -2
  51. package/build-module/components/block-styles/index.mjs +7 -1
  52. package/build-module/components/block-styles/index.mjs.map +2 -2
  53. package/build-module/components/block-variation-transforms/index.mjs +11 -5
  54. package/build-module/components/block-variation-transforms/index.mjs.map +2 -2
  55. package/build-module/components/block-visibility/use-block-visibility.mjs +4 -3
  56. package/build-module/components/block-visibility/use-block-visibility.mjs.map +2 -2
  57. package/build-module/components/global-styles/color-panel.mjs +1 -1
  58. package/build-module/components/global-styles/color-panel.mjs.map +2 -2
  59. package/build-module/components/global-styles/filters-panel.mjs.map +2 -2
  60. package/build-module/components/global-styles/index.mjs +2 -0
  61. package/build-module/components/global-styles/index.mjs.map +2 -2
  62. package/build-module/components/global-styles/state-control.mjs +60 -0
  63. package/build-module/components/global-styles/state-control.mjs.map +7 -0
  64. package/build-module/components/iframe/index.mjs +2 -9
  65. package/build-module/components/iframe/index.mjs.map +2 -2
  66. package/build-module/components/iframe/use-scale-canvas.mjs +0 -1
  67. package/build-module/components/iframe/use-scale-canvas.mjs.map +2 -2
  68. package/build-module/components/provider/index.mjs +1 -1
  69. package/build-module/components/provider/index.mjs.map +2 -2
  70. package/build-module/components/provider/use-media-upload-settings.mjs +1 -0
  71. package/build-module/components/provider/use-media-upload-settings.mjs.map +2 -2
  72. package/build-module/hooks/block-fields/media/index.mjs +142 -102
  73. package/build-module/hooks/block-fields/media/index.mjs.map +2 -2
  74. package/build-module/private-apis.mjs +2 -0
  75. package/build-module/private-apis.mjs.map +2 -2
  76. package/build-module/store/private-keys.mjs +2 -0
  77. package/build-module/store/private-keys.mjs.map +2 -2
  78. package/build-module/store/private-selectors.mjs +2 -1
  79. package/build-module/store/private-selectors.mjs.map +2 -2
  80. package/build-module/store/reducer.mjs +3 -4
  81. package/build-module/store/reducer.mjs.map +2 -2
  82. package/build-module/store/selectors.mjs +4 -4
  83. package/build-module/store/selectors.mjs.map +2 -2
  84. package/build-style/content-rtl.css +2 -0
  85. package/build-style/content.css +2 -0
  86. package/build-style/style-rtl.css +30 -3
  87. package/build-style/style.css +30 -3
  88. package/package.json +39 -39
  89. package/src/components/block-bindings/attribute-control.js +8 -3
  90. package/src/components/block-inspector/edit-contents.js +5 -3
  91. package/src/components/block-list/block.js +10 -1
  92. package/src/components/block-list/use-block-props/index.js +11 -1
  93. package/src/components/block-styles/index.js +7 -1
  94. package/src/components/block-variation-transforms/index.js +41 -36
  95. package/src/components/block-visibility/use-block-visibility.js +4 -2
  96. package/src/components/global-styles/color-panel.js +3 -1
  97. package/src/components/global-styles/filters-panel.js +2 -0
  98. package/src/components/global-styles/index.js +1 -0
  99. package/src/components/global-styles/state-control.js +75 -0
  100. package/src/components/iframe/index.js +2 -12
  101. package/src/components/iframe/use-scale-canvas.js +0 -1
  102. package/src/components/link-control/style.scss +4 -2
  103. package/src/components/provider/index.js +2 -1
  104. package/src/components/provider/use-media-upload-settings.js +1 -0
  105. package/src/components/url-popover/style.scss +4 -2
  106. package/src/hooks/block-fields/media/index.js +143 -99
  107. package/src/hooks/block-fields/media/styles.scss +31 -3
  108. package/src/private-apis.js +2 -0
  109. package/src/store/private-keys.js +1 -0
  110. package/src/store/private-selectors.js +4 -1
  111. package/src/store/reducer.js +12 -6
  112. package/src/store/selectors.js +13 -6
@@ -199,6 +199,7 @@ _::-webkit-full-page-media, _:future, :root [data-has-multi-selection=true] .blo
199
199
  outline-style: solid;
200
200
  outline-width: calc(1 * var(--wp-admin-border-width-focus) / var(--wp-block-editor-iframe-zoom-out-scale, 1));
201
201
  outline-offset: calc(1 * -1 * var(--wp-admin-border-width-focus) / var(--wp-block-editor-iframe-zoom-out-scale, 1));
202
+ box-shadow: inset 0 0 0 calc(var(--wp-admin-border-width-focus, 2px) + 1px) #fff, 0 0 0 1px #fff, 0 1px 1px rgba(0, 0, 0, 0.03), 0 1px 2px rgba(0, 0, 0, 0.02), 0 3px 3px rgba(0, 0, 0, 0.02), 0 4px 4px rgba(0, 0, 0, 0.01);
202
203
  z-index: 1;
203
204
  }
204
205
  .block-editor-block-list__layout .block-editor-block-list__block.is-block-hidden {
@@ -293,6 +294,7 @@ _::-webkit-full-page-media, _:future, :root [data-has-multi-selection=true] .blo
293
294
  outline-style: solid;
294
295
  outline-width: calc(1 * var(--wp-admin-border-width-focus) / var(--wp-block-editor-iframe-zoom-out-scale, 1));
295
296
  outline-offset: calc(1 * -1 * var(--wp-admin-border-width-focus) / var(--wp-block-editor-iframe-zoom-out-scale, 1));
297
+ box-shadow: inset 0 0 0 calc(var(--wp-admin-border-width-focus, 2px) + 1px) #fff, 0 0 0 1px #fff, 0 1px 1px rgba(0, 0, 0, 0.03), 0 1px 2px rgba(0, 0, 0, 0.02), 0 3px 3px rgba(0, 0, 0, 0.02), 0 4px 4px rgba(0, 0, 0, 0.01);
296
298
  }
297
299
 
298
300
  .is-outline-mode .block-editor-block-list__block:not(.remove-outline).wp-block-template-part.is-hovered::after, .is-outline-mode .block-editor-block-list__block:not(.remove-outline).wp-block-template-part.is-selected::after, .is-outline-mode .block-editor-block-list__block:not(.remove-outline).wp-block-template-part.is-highlighted::after,
@@ -199,6 +199,7 @@ _::-webkit-full-page-media, _:future, :root [data-has-multi-selection=true] .blo
199
199
  outline-style: solid;
200
200
  outline-width: calc(1 * var(--wp-admin-border-width-focus) / var(--wp-block-editor-iframe-zoom-out-scale, 1));
201
201
  outline-offset: calc(1 * -1 * var(--wp-admin-border-width-focus) / var(--wp-block-editor-iframe-zoom-out-scale, 1));
202
+ box-shadow: inset 0 0 0 calc(var(--wp-admin-border-width-focus, 2px) + 1px) #fff, 0 0 0 1px #fff, 0 1px 1px rgba(0, 0, 0, 0.03), 0 1px 2px rgba(0, 0, 0, 0.02), 0 3px 3px rgba(0, 0, 0, 0.02), 0 4px 4px rgba(0, 0, 0, 0.01);
202
203
  z-index: 1;
203
204
  }
204
205
  .block-editor-block-list__layout .block-editor-block-list__block.is-block-hidden {
@@ -293,6 +294,7 @@ _::-webkit-full-page-media, _:future, :root [data-has-multi-selection=true] .blo
293
294
  outline-style: solid;
294
295
  outline-width: calc(1 * var(--wp-admin-border-width-focus) / var(--wp-block-editor-iframe-zoom-out-scale, 1));
295
296
  outline-offset: calc(1 * -1 * var(--wp-admin-border-width-focus) / var(--wp-block-editor-iframe-zoom-out-scale, 1));
297
+ box-shadow: inset 0 0 0 calc(var(--wp-admin-border-width-focus, 2px) + 1px) #fff, 0 0 0 1px #fff, 0 1px 1px rgba(0, 0, 0, 0.03), 0 1px 2px rgba(0, 0, 0, 0.02), 0 3px 3px rgba(0, 0, 0, 0.02), 0 4px 4px rgba(0, 0, 0, 0.01);
296
298
  }
297
299
 
298
300
  .is-outline-mode .block-editor-block-list__block:not(.remove-outline).wp-block-template-part.is-hovered::after, .is-outline-mode .block-editor-block-list__block:not(.remove-outline).wp-block-template-part.is-selected::after, .is-outline-mode .block-editor-block-list__block:not(.remove-outline).wp-block-template-part.is-highlighted::after,
@@ -3432,7 +3432,7 @@ iframe[name=editor-canvas] {
3432
3432
  .block-editor-content-only-controls__media {
3433
3433
  width: 100%;
3434
3434
  box-shadow: inset 0 0 0 1px #ccc;
3435
- padding: 8px;
3435
+ padding-left: 32px;
3436
3436
  }
3437
3437
  .block-editor-content-only-controls__media:focus:not(:disabled) {
3438
3438
  box-shadow: 0 0 0 currentColor inset, 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);
@@ -3464,10 +3464,11 @@ iframe[name=editor-canvas] {
3464
3464
  }
3465
3465
 
3466
3466
  .block-editor-content-only-controls__media-thumbnail {
3467
- width: 24px;
3468
- height: 24px;
3467
+ width: 20px;
3468
+ height: 20px;
3469
3469
  border-radius: 2px;
3470
3470
  align-self: center;
3471
+ overflow: hidden;
3471
3472
  }
3472
3473
  .block-editor-content-only-controls__media-thumbnail img {
3473
3474
  width: 100% !important;
@@ -3475,6 +3476,32 @@ iframe[name=editor-canvas] {
3475
3476
  object-fit: cover;
3476
3477
  }
3477
3478
 
3479
+ .block-editor-content-only-controls {
3480
+ position: relative;
3481
+ }
3482
+
3483
+ .block-editor-content-only-controls__media-reset {
3484
+ position: absolute;
3485
+ left: 0;
3486
+ top: 8px;
3487
+ margin: auto 8px auto;
3488
+ opacity: 0;
3489
+ border-radius: 2px;
3490
+ }
3491
+ @media not (prefers-reduced-motion) {
3492
+ .block-editor-content-only-controls__media-reset {
3493
+ transition: opacity 0.1s ease-in-out;
3494
+ }
3495
+ }
3496
+ .block-editor-content-only-controls:hover .block-editor-content-only-controls__media-reset, .block-editor-content-only-controls__media-reset:focus, .block-editor-content-only-controls__media-reset:hover {
3497
+ opacity: 1;
3498
+ }
3499
+ @media (hover: none) {
3500
+ .block-editor-content-only-controls__media-reset {
3501
+ opacity: 1;
3502
+ }
3503
+ }
3504
+
3478
3505
  .block-editor-content-only-controls__rich-text {
3479
3506
  width: 100%;
3480
3507
  margin: 0;
@@ -3434,7 +3434,7 @@ iframe[name=editor-canvas] {
3434
3434
  .block-editor-content-only-controls__media {
3435
3435
  width: 100%;
3436
3436
  box-shadow: inset 0 0 0 1px #ccc;
3437
- padding: 8px;
3437
+ padding-right: 32px;
3438
3438
  }
3439
3439
  .block-editor-content-only-controls__media:focus:not(:disabled) {
3440
3440
  box-shadow: 0 0 0 currentColor inset, 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);
@@ -3466,10 +3466,11 @@ iframe[name=editor-canvas] {
3466
3466
  }
3467
3467
 
3468
3468
  .block-editor-content-only-controls__media-thumbnail {
3469
- width: 24px;
3470
- height: 24px;
3469
+ width: 20px;
3470
+ height: 20px;
3471
3471
  border-radius: 2px;
3472
3472
  align-self: center;
3473
+ overflow: hidden;
3473
3474
  }
3474
3475
  .block-editor-content-only-controls__media-thumbnail img {
3475
3476
  width: 100% !important;
@@ -3477,6 +3478,32 @@ iframe[name=editor-canvas] {
3477
3478
  object-fit: cover;
3478
3479
  }
3479
3480
 
3481
+ .block-editor-content-only-controls {
3482
+ position: relative;
3483
+ }
3484
+
3485
+ .block-editor-content-only-controls__media-reset {
3486
+ position: absolute;
3487
+ right: 0;
3488
+ top: 8px;
3489
+ margin: auto 8px auto;
3490
+ opacity: 0;
3491
+ border-radius: 2px;
3492
+ }
3493
+ @media not (prefers-reduced-motion) {
3494
+ .block-editor-content-only-controls__media-reset {
3495
+ transition: opacity 0.1s ease-in-out;
3496
+ }
3497
+ }
3498
+ .block-editor-content-only-controls:hover .block-editor-content-only-controls__media-reset, .block-editor-content-only-controls__media-reset:focus, .block-editor-content-only-controls__media-reset:hover {
3499
+ opacity: 1;
3500
+ }
3501
+ @media (hover: none) {
3502
+ .block-editor-content-only-controls__media-reset {
3503
+ opacity: 1;
3504
+ }
3505
+ }
3506
+
3480
3507
  .block-editor-content-only-controls__rich-text {
3481
3508
  width: 100%;
3482
3509
  margin: 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/block-editor",
3
- "version": "15.14.1-next.v.202603102151.0+59e17f9ec",
3
+ "version": "15.15.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.41.1-next.v.202603102151.0+59e17f9ec",
65
- "@wordpress/api-fetch": "^7.41.1-next.v.202603102151.0+59e17f9ec",
66
- "@wordpress/base-styles": "^6.17.1-next.v.202603102151.0+59e17f9ec",
67
- "@wordpress/blob": "^4.41.1-next.v.202603102151.0+59e17f9ec",
68
- "@wordpress/block-serialization-default-parser": "^5.41.1-next.v.202603102151.0+59e17f9ec",
69
- "@wordpress/blocks": "^15.14.1-next.v.202603102151.0+59e17f9ec",
70
- "@wordpress/commands": "^1.41.1-next.v.202603102151.0+59e17f9ec",
71
- "@wordpress/components": "^32.4.1-next.v.202603102151.0+59e17f9ec",
72
- "@wordpress/compose": "^7.41.1-next.v.202603102151.0+59e17f9ec",
73
- "@wordpress/data": "^10.41.1-next.v.202603102151.0+59e17f9ec",
74
- "@wordpress/dataviews": "^13.1.1-next.v.202603102151.0+59e17f9ec",
75
- "@wordpress/date": "^5.41.1-next.v.202603102151.0+59e17f9ec",
76
- "@wordpress/deprecated": "^4.41.1-next.v.202603102151.0+59e17f9ec",
77
- "@wordpress/dom": "^4.41.1-next.v.202603102151.0+59e17f9ec",
78
- "@wordpress/element": "^6.41.1-next.v.202603102151.0+59e17f9ec",
79
- "@wordpress/escape-html": "^3.41.1-next.v.202603102151.0+59e17f9ec",
80
- "@wordpress/global-styles-engine": "^1.8.1-next.v.202603102151.0+59e17f9ec",
81
- "@wordpress/hooks": "^4.41.1-next.v.202603102151.0+59e17f9ec",
82
- "@wordpress/html-entities": "^4.41.1-next.v.202603102151.0+59e17f9ec",
83
- "@wordpress/i18n": "^6.14.1-next.v.202603102151.0+59e17f9ec",
84
- "@wordpress/icons": "^12.0.1-next.v.202603102151.0+59e17f9ec",
85
- "@wordpress/image-cropper": "^1.5.1-next.v.202603102151.0+59e17f9ec",
86
- "@wordpress/interactivity": "^6.41.2-next.v.202603102151.0+59e17f9ec",
87
- "@wordpress/is-shallow-equal": "^5.41.1-next.v.202603102151.0+59e17f9ec",
88
- "@wordpress/keyboard-shortcuts": "^5.41.1-next.v.202603102151.0+59e17f9ec",
89
- "@wordpress/keycodes": "^4.41.1-next.v.202603102151.0+59e17f9ec",
90
- "@wordpress/notices": "^5.41.1-next.v.202603102151.0+59e17f9ec",
91
- "@wordpress/preferences": "^4.41.1-next.v.202603102151.0+59e17f9ec",
92
- "@wordpress/priority-queue": "^3.41.1-next.v.202603102151.0+59e17f9ec",
93
- "@wordpress/private-apis": "^1.41.1-next.v.202603102151.0+59e17f9ec",
94
- "@wordpress/rich-text": "^7.41.1-next.v.202603102151.0+59e17f9ec",
95
- "@wordpress/style-engine": "^2.41.1-next.v.202603102151.0+59e17f9ec",
96
- "@wordpress/token-list": "^3.41.1-next.v.202603102151.0+59e17f9ec",
97
- "@wordpress/upload-media": "^0.26.1-next.v.202603102151.0+59e17f9ec",
98
- "@wordpress/url": "^4.41.1-next.v.202603102151.0+59e17f9ec",
99
- "@wordpress/warning": "^3.41.1-next.v.202603102151.0+59e17f9ec",
100
- "@wordpress/wordcount": "^4.41.1-next.v.202603102151.0+59e17f9ec",
64
+ "@wordpress/a11y": "^4.42.0",
65
+ "@wordpress/api-fetch": "^7.42.0",
66
+ "@wordpress/base-styles": "^6.18.0",
67
+ "@wordpress/blob": "^4.42.0",
68
+ "@wordpress/block-serialization-default-parser": "^5.42.0",
69
+ "@wordpress/blocks": "^15.15.0",
70
+ "@wordpress/commands": "^1.42.0",
71
+ "@wordpress/components": "^32.4.0",
72
+ "@wordpress/compose": "^7.42.0",
73
+ "@wordpress/data": "^10.42.0",
74
+ "@wordpress/dataviews": "^13.1.0",
75
+ "@wordpress/date": "^5.42.0",
76
+ "@wordpress/deprecated": "^4.42.0",
77
+ "@wordpress/dom": "^4.42.0",
78
+ "@wordpress/element": "^6.42.0",
79
+ "@wordpress/escape-html": "^3.42.0",
80
+ "@wordpress/global-styles-engine": "^1.9.0",
81
+ "@wordpress/hooks": "^4.42.0",
82
+ "@wordpress/html-entities": "^4.42.0",
83
+ "@wordpress/i18n": "^6.15.0",
84
+ "@wordpress/icons": "^12.0.0",
85
+ "@wordpress/image-cropper": "^1.6.0",
86
+ "@wordpress/interactivity": "^6.42.0",
87
+ "@wordpress/is-shallow-equal": "^5.42.0",
88
+ "@wordpress/keyboard-shortcuts": "^5.42.0",
89
+ "@wordpress/keycodes": "^4.42.0",
90
+ "@wordpress/notices": "^5.42.0",
91
+ "@wordpress/preferences": "^4.42.0",
92
+ "@wordpress/priority-queue": "^3.42.0",
93
+ "@wordpress/private-apis": "^1.42.0",
94
+ "@wordpress/rich-text": "^7.42.0",
95
+ "@wordpress/style-engine": "^2.42.0",
96
+ "@wordpress/token-list": "^3.42.0",
97
+ "@wordpress/upload-media": "^0.27.0",
98
+ "@wordpress/url": "^4.42.0",
99
+ "@wordpress/warning": "^3.42.0",
100
+ "@wordpress/wordcount": "^4.42.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": "86db21e727d89e8f0dbba9300d2f97fd22b08693"
127
+ "gitHead": "c20787b1778ae64c2db65643b1c236309d68e6ba"
128
128
  }
@@ -50,10 +50,15 @@ export default function BlockBindingsAttributeControl( {
50
50
  getBlockType,
51
51
  } = unlock( select( blocksStore ) );
52
52
 
53
- const _attributeType =
54
- getBlockType( blockName ).attributes?.[ attribute ]?.type;
53
+ const _attribute =
54
+ getBlockType( blockName ).attributes?.[ attribute ];
55
+
56
+ if ( _attribute?.enum ) {
57
+ return {};
58
+ }
59
+
55
60
  const attributeType =
56
- _attributeType === 'rich-text' ? 'string' : _attributeType;
61
+ _attribute?.type === 'rich-text' ? 'string' : _attribute?.type;
57
62
 
58
63
  const sourceFields = {};
59
64
  Object.entries( getAllBlockBindingsSources() ).forEach(
@@ -92,19 +92,21 @@ export default function EditContents( { clientId } ) {
92
92
  stopEditingContentOnlySection,
93
93
  } = useContentOnlySectionEdit( clientId );
94
94
 
95
- const { block, onNavigateToEntityRecord } = useSelect(
95
+ const { block, onNavigateToEntityRecord, canEdit } = useSelect(
96
96
  ( select ) => {
97
- const { getBlock, getSettings } = select( blockEditorStore );
97
+ const { getBlock, getSettings, canEditBlock } =
98
+ select( blockEditorStore );
98
99
  return {
99
100
  block: getBlock( clientId ),
100
101
  onNavigateToEntityRecord:
101
102
  getSettings().onNavigateToEntityRecord,
103
+ canEdit: canEditBlock( clientId ),
102
104
  };
103
105
  },
104
106
  [ clientId ]
105
107
  );
106
108
 
107
- if ( ! isWithinSection && ! isWithinEditedSection ) {
109
+ if ( ! canEdit || ( ! isWithinSection && ! isWithinEditedSection ) ) {
108
110
  return null;
109
111
  }
110
112
 
@@ -23,7 +23,7 @@ import {
23
23
  } from '@wordpress/blocks';
24
24
  import { withFilters } from '@wordpress/components';
25
25
  import { withDispatch, useSelect } from '@wordpress/data';
26
- import { compose } from '@wordpress/compose';
26
+ import { compose, useRefEffect } from '@wordpress/compose';
27
27
  import { safeHTML } from '@wordpress/dom';
28
28
 
29
29
  /**
@@ -741,10 +741,19 @@ function BlockListBlockProvider( props ) {
741
741
  [ clientId, rootClientId ]
742
742
  );
743
743
 
744
+ const defaultViewRef = useRefEffect( ( element ) => {
745
+ if ( element ) {
746
+ const { ownerDocument } = element;
747
+ const { defaultView } = ownerDocument;
748
+ defaultViewRef.current = defaultView;
749
+ }
750
+ }, [] );
751
+
744
752
  // Use block visibility hook with data from existing useSelect to avoid extra subscription
745
753
  const { isBlockCurrentlyHidden } = useBlockVisibility( {
746
754
  blockVisibility: selectedProps?.blockVisibility,
747
755
  deviceType: selectedProps?.deviceType,
756
+ view: defaultViewRef.current,
748
757
  } );
749
758
 
750
759
  // Users of the editor.BlockListBlock filter used to be able to
@@ -9,7 +9,7 @@ import clsx from 'clsx';
9
9
  import { useContext } from '@wordpress/element';
10
10
  import { __, sprintf } from '@wordpress/i18n';
11
11
  import { __unstableGetBlockProps as getBlockProps } from '@wordpress/blocks';
12
- import { useMergeRefs, useDisabled } from '@wordpress/compose';
12
+ import { useMergeRefs, useDisabled, useRefEffect } from '@wordpress/compose';
13
13
  import warning from '@wordpress/warning';
14
14
 
15
15
  /**
@@ -107,6 +107,14 @@ export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) {
107
107
  deviceType,
108
108
  } = useContext( PrivateBlockContext );
109
109
 
110
+ const defaultViewRef = useRefEffect( ( element ) => {
111
+ if ( element ) {
112
+ const { ownerDocument } = element;
113
+ const { defaultView } = ownerDocument;
114
+ defaultViewRef.current = defaultView;
115
+ }
116
+ }, [] );
117
+
110
118
  // translators: %s: Type of block (i.e. Text, Image etc)
111
119
  const blockLabel = sprintf( __( 'Block: %s' ), blockTitle );
112
120
  const htmlSuffix = mode === 'html' && ! __unstableIsHtml ? '-visual' : '';
@@ -114,6 +122,7 @@ export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) {
114
122
  const isHoverEnabled = ! isWithinSectionBlock;
115
123
  const mergedRefs = useMergeRefs( [
116
124
  props.ref,
125
+ defaultViewRef,
117
126
  useFocusFirstElement( { clientId, initialPosition } ),
118
127
  useBlockRefProvider( clientId ),
119
128
  useFocusHandler( clientId ),
@@ -144,6 +153,7 @@ export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) {
144
153
  const { isBlockCurrentlyHidden } = useBlockVisibility( {
145
154
  blockVisibility,
146
155
  deviceType,
156
+ view: defaultViewRef.current,
147
157
  } );
148
158
 
149
159
  // Ensures it warns only inside the `edit` implementation for the block.
@@ -7,6 +7,7 @@ import clsx from 'clsx';
7
7
  * WordPress dependencies
8
8
  */
9
9
  import { useState, useMemo } from '@wordpress/element';
10
+ import { useSelect } from '@wordpress/data';
10
11
  import { debounce } from '@wordpress/compose';
11
12
  import {
12
13
  Button,
@@ -23,11 +24,16 @@ import PreviewBlockPopover from '../block-switcher/preview-block-popover';
23
24
  import useStylesForBlocks from './use-styles-for-block';
24
25
  import { useToolsPanelDropdownMenuProps } from '../global-styles/utils';
25
26
  import { getDefaultStyle, replaceActiveStyle } from './utils';
27
+ import { store as blockEditorStore } from '../../store';
26
28
 
27
29
  const noop = () => {};
28
30
 
29
31
  // Block Styles component for the Settings Sidebar.
30
32
  function BlockStyles( { clientId, onSwitch = noop, onHoverClassName = noop } ) {
33
+ const canEdit = useSelect(
34
+ ( select ) => select( blockEditorStore ).canEditBlock( clientId ),
35
+ [ clientId ]
36
+ );
31
37
  const {
32
38
  onSelect,
33
39
  stylesToRender,
@@ -62,7 +68,7 @@ function BlockStyles( { clientId, onSwitch = noop, onHoverClassName = noop } ) {
62
68
  ];
63
69
  }, [ hoveredStyle, genericPreviewBlock, className, activeStyle ] );
64
70
 
65
- if ( ! stylesToRender || stylesToRender.length === 0 ) {
71
+ if ( ! canEdit || ! stylesToRender || stylesToRender.length === 0 ) {
66
72
  return null;
67
73
  }
68
74
 
@@ -146,41 +146,46 @@ function VariationsToggleGroupControl( {
146
146
 
147
147
  function __experimentalBlockVariationTransforms( { blockClientId } ) {
148
148
  const { updateBlockAttributes } = useDispatch( blockEditorStore );
149
- const { activeBlockVariation, variations, isContentOnly, isSection } =
150
- useSelect(
151
- ( select ) => {
152
- const { getActiveBlockVariation, getBlockVariations } =
153
- select( blocksStore );
154
-
155
- const {
156
- getBlockName,
157
- getBlockAttributes,
158
- getBlockEditingMode,
159
- isSectionBlock,
160
- } = unlock( select( blockEditorStore ) );
161
-
162
- const name = blockClientId && getBlockName( blockClientId );
163
-
164
- const { hasContentRoleAttribute } = unlock(
165
- select( blocksStore )
166
- );
167
- const isContentBlock = hasContentRoleAttribute( name );
168
-
169
- return {
170
- activeBlockVariation: getActiveBlockVariation(
171
- name,
172
- getBlockAttributes( blockClientId ),
173
- 'transform'
174
- ),
175
- variations: name && getBlockVariations( name, 'transform' ),
176
- isContentOnly:
177
- getBlockEditingMode( blockClientId ) ===
178
- 'contentOnly' && ! isContentBlock,
179
- isSection: isSectionBlock( blockClientId ),
180
- };
181
- },
182
- [ blockClientId ]
183
- );
149
+ const {
150
+ activeBlockVariation,
151
+ variations,
152
+ canEdit,
153
+ isContentOnly,
154
+ isSection,
155
+ } = useSelect(
156
+ ( select ) => {
157
+ const { getActiveBlockVariation, getBlockVariations } =
158
+ select( blocksStore );
159
+
160
+ const {
161
+ getBlockName,
162
+ getBlockAttributes,
163
+ getBlockEditingMode,
164
+ isSectionBlock,
165
+ } = unlock( select( blockEditorStore ) );
166
+ const { canEditBlock } = select( blockEditorStore );
167
+
168
+ const name = blockClientId && getBlockName( blockClientId );
169
+
170
+ const { hasContentRoleAttribute } = unlock( select( blocksStore ) );
171
+ const isContentBlock = hasContentRoleAttribute( name );
172
+
173
+ return {
174
+ activeBlockVariation: getActiveBlockVariation(
175
+ name,
176
+ getBlockAttributes( blockClientId ),
177
+ 'transform'
178
+ ),
179
+ variations: name && getBlockVariations( name, 'transform' ),
180
+ canEdit: canEditBlock( blockClientId ),
181
+ isContentOnly:
182
+ getBlockEditingMode( blockClientId ) === 'contentOnly' &&
183
+ ! isContentBlock,
184
+ isSection: isSectionBlock( blockClientId ),
185
+ };
186
+ },
187
+ [ blockClientId ]
188
+ );
184
189
 
185
190
  const selectedValue = activeBlockVariation?.name;
186
191
 
@@ -205,7 +210,7 @@ function __experimentalBlockVariationTransforms( { blockClientId } ) {
205
210
  } );
206
211
  };
207
212
 
208
- if ( ! variations?.length || isContentOnly || isSection ) {
213
+ if ( ! variations?.length || ! canEdit || isContentOnly || isSection ) {
209
214
  return null;
210
215
  }
211
216
 
@@ -14,16 +14,18 @@ import { BLOCK_VISIBILITY_VIEWPORTS } from './constants';
14
14
  * @param {Object} options Parameters to avoid extra store subscriptions.
15
15
  * @param {Object|boolean} options.blockVisibility Block visibility metadata.
16
16
  * @param {string} options.deviceType Current device type ('desktop', 'tablet', 'mobile').
17
+ * @param {Window?} options.view Window instance in which to perform viewport matching
17
18
  * @return {Object} Object with `isBlockCurrentlyHidden` (boolean) and `currentViewport` (string) properties.
18
19
  */
19
20
  export default function useBlockVisibility( options = {} ) {
20
21
  const {
21
22
  blockVisibility = undefined,
22
23
  deviceType = BLOCK_VISIBILITY_VIEWPORTS.desktop.key,
24
+ view = window,
23
25
  } = options;
24
26
 
25
- const isLargerThanMobile = useViewportMatch( 'mobile', '>=' ); // >= 480px
26
- const isLargerThanTablet = useViewportMatch( 'medium', '>=' ); // >= 782px
27
+ const isLargerThanMobile = useViewportMatch( 'mobile', '>=', view ); // >= 480px
28
+ const isLargerThanTablet = useViewportMatch( 'medium', '>=', view ); // >= 782px
27
29
 
28
30
  /*
29
31
  * Priority:
@@ -10,6 +10,8 @@ import {
10
10
  __experimentalToolsPanel as ToolsPanel,
11
11
  __experimentalToolsPanelItem as ToolsPanelItem,
12
12
  __experimentalHStack as HStack,
13
+ // TODO: Replace this ZStack with ad hoc CSS.
14
+ // eslint-disable-next-line @wordpress/use-recommended-components
13
15
  __experimentalZStack as ZStack,
14
16
  __experimentalDropdownContentWrapper as DropdownContentWrapper,
15
17
  ColorIndicator,
@@ -22,6 +24,7 @@ import {
22
24
  import { useCallback, useRef } from '@wordpress/element';
23
25
  import { __ } from '@wordpress/i18n';
24
26
  import { getValueFromVariable } from '@wordpress/global-styles-engine';
27
+ import { reset as resetIcon } from '@wordpress/icons';
25
28
 
26
29
  /**
27
30
  * Internal dependencies
@@ -31,7 +34,6 @@ import { useColorsPerOrigin, useGradientsPerOrigin } from './hooks';
31
34
  import { useToolsPanelDropdownMenuProps } from './utils';
32
35
  import { setImmutably } from '../../utils/object';
33
36
  import { unlock } from '../../lock-unlock';
34
- import { reset as resetIcon } from '@wordpress/icons';
35
37
 
36
38
  export function useHasColorPanel( settings ) {
37
39
  const hasTextPanel = useHasTextPanel( settings );
@@ -10,6 +10,8 @@ import {
10
10
  __experimentalToolsPanel as ToolsPanel,
11
11
  __experimentalToolsPanelItem as ToolsPanelItem,
12
12
  __experimentalHStack as HStack,
13
+ // TODO: Replace this ZStack with ad hoc CSS.
14
+ // eslint-disable-next-line @wordpress/use-recommended-components
13
15
  __experimentalZStack as ZStack,
14
16
  __experimentalDropdownContentWrapper as DropdownContentWrapper,
15
17
  MenuGroup,
@@ -23,3 +23,4 @@ export {
23
23
  default as BackgroundPanel,
24
24
  useHasBackgroundPanel,
25
25
  } from './background-panel';
26
+ export { default as StateControl } from './state-control';
@@ -0,0 +1,75 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { __, sprintf } from '@wordpress/i18n';
5
+ import { check, chevronDown } from '@wordpress/icons';
6
+ import { DropdownMenu, MenuGroup, MenuItem } from '@wordpress/components';
7
+
8
+ /**
9
+ * State control for managing block state styles (hover, focus, etc.).
10
+ * Displays a dropdown menu to select between different states.
11
+ *
12
+ * @param {Object} props Component props.
13
+ * @param {Array} props.states Array of available states with value and label.
14
+ * @param {string} props.value Currently selected state value.
15
+ * @param {Function} props.onChange Callback when selection changes.
16
+ * @return {Element|null} State control component.
17
+ */
18
+ export default function StateControl( {
19
+ states = [],
20
+ value = 'default',
21
+ onChange,
22
+ } ) {
23
+ if ( ! states || states.length === 0 ) {
24
+ return null;
25
+ }
26
+
27
+ const stateOptions = [
28
+ { label: __( 'Default' ), value: 'default' },
29
+ ...states.map( ( state ) => ( {
30
+ label: state.label,
31
+ value: state.value,
32
+ } ) ),
33
+ ];
34
+
35
+ const getCurrentStateLabel = () => {
36
+ const currentOption = stateOptions.find(
37
+ ( option ) => option.value === value
38
+ );
39
+ return currentOption?.label || __( 'Default' );
40
+ };
41
+
42
+ return (
43
+ <DropdownMenu
44
+ icon={ chevronDown }
45
+ label={ sprintf(
46
+ /* translators: %s: Current state (e.g. "Hover", "Focus") */
47
+ __( 'State: %s' ),
48
+ getCurrentStateLabel()
49
+ ) }
50
+ text={ getCurrentStateLabel() }
51
+ toggleProps={ {
52
+ size: 'compact',
53
+ variant: 'tertiary',
54
+ iconPosition: 'right',
55
+ } }
56
+ >
57
+ { ( { onClose } ) => (
58
+ <MenuGroup label={ __( 'State' ) }>
59
+ { stateOptions.map( ( option ) => (
60
+ <MenuItem
61
+ key={ option.value }
62
+ onClick={ () => {
63
+ onChange( option.value );
64
+ onClose();
65
+ } }
66
+ icon={ value === option.value ? check : null }
67
+ >
68
+ { option.label }
69
+ </MenuItem>
70
+ ) ) }
71
+ </MenuGroup>
72
+ ) }
73
+ </DropdownMenu>
74
+ );
75
+ }