@wordpress/block-editor 8.5.0 → 8.5.1

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 (71) hide show
  1. package/build/components/block-content-overlay/index.js +13 -4
  2. package/build/components/block-content-overlay/index.js.map +1 -1
  3. package/build/components/block-lock/index.js +8 -0
  4. package/build/components/block-lock/index.js.map +1 -1
  5. package/build/components/block-lock/menu-item.js +5 -20
  6. package/build/components/block-lock/menu-item.js.map +1 -1
  7. package/build/components/block-lock/modal.js +33 -12
  8. package/build/components/block-lock/modal.js.map +1 -1
  9. package/build/components/block-lock/toolbar.js +7 -20
  10. package/build/components/block-lock/toolbar.js.map +1 -1
  11. package/build/components/block-lock/use-block-lock.js +53 -0
  12. package/build/components/block-lock/use-block-lock.js.map +1 -0
  13. package/build/components/block-pattern-setup/index.js +37 -22
  14. package/build/components/block-pattern-setup/index.js.map +1 -1
  15. package/build/components/block-pattern-setup/setup-toolbar.js +1 -1
  16. package/build/components/block-pattern-setup/setup-toolbar.js.map +1 -1
  17. package/build/components/block-preview/auto.js +6 -3
  18. package/build/components/block-preview/auto.js.map +1 -1
  19. package/build/components/block-preview/index.js +4 -2
  20. package/build/components/block-preview/index.js.map +1 -1
  21. package/build/components/block-switcher/index.js +7 -2
  22. package/build/components/block-switcher/index.js.map +1 -1
  23. package/build/components/list-view/block-select-button.js +4 -10
  24. package/build/components/list-view/block-select-button.js.map +1 -1
  25. package/build/store/selectors.js +26 -2
  26. package/build/store/selectors.js.map +1 -1
  27. package/build-module/components/block-content-overlay/index.js +13 -4
  28. package/build-module/components/block-content-overlay/index.js.map +1 -1
  29. package/build-module/components/block-lock/index.js +1 -0
  30. package/build-module/components/block-lock/index.js.map +1 -1
  31. package/build-module/components/block-lock/menu-item.js +4 -18
  32. package/build-module/components/block-lock/menu-item.js.map +1 -1
  33. package/build-module/components/block-lock/modal.js +31 -12
  34. package/build-module/components/block-lock/modal.js.map +1 -1
  35. package/build-module/components/block-lock/toolbar.js +6 -18
  36. package/build-module/components/block-lock/toolbar.js.map +1 -1
  37. package/build-module/components/block-lock/use-block-lock.js +44 -0
  38. package/build-module/components/block-lock/use-block-lock.js.map +1 -0
  39. package/build-module/components/block-pattern-setup/index.js +39 -24
  40. package/build-module/components/block-pattern-setup/index.js.map +1 -1
  41. package/build-module/components/block-pattern-setup/setup-toolbar.js +1 -1
  42. package/build-module/components/block-pattern-setup/setup-toolbar.js.map +1 -1
  43. package/build-module/components/block-preview/auto.js +6 -3
  44. package/build-module/components/block-preview/auto.js.map +1 -1
  45. package/build-module/components/block-preview/index.js +4 -2
  46. package/build-module/components/block-preview/index.js.map +1 -1
  47. package/build-module/components/block-switcher/index.js +7 -2
  48. package/build-module/components/block-switcher/index.js.map +1 -1
  49. package/build-module/components/list-view/block-select-button.js +4 -9
  50. package/build-module/components/list-view/block-select-button.js.map +1 -1
  51. package/build-module/store/selectors.js +24 -2
  52. package/build-module/store/selectors.js.map +1 -1
  53. package/build-style/style-rtl.css +34 -25
  54. package/build-style/style.css +34 -25
  55. package/package.json +3 -3
  56. package/src/components/block-content-overlay/index.js +19 -2
  57. package/src/components/block-lock/index.js +1 -0
  58. package/src/components/block-lock/menu-item.js +3 -23
  59. package/src/components/block-lock/modal.js +37 -13
  60. package/src/components/block-lock/toolbar.js +4 -21
  61. package/src/components/block-lock/use-block-lock.js +49 -0
  62. package/src/components/block-pattern-setup/index.js +84 -59
  63. package/src/components/block-pattern-setup/setup-toolbar.js +3 -1
  64. package/src/components/block-pattern-setup/style.scss +32 -26
  65. package/src/components/block-preview/auto.js +10 -1
  66. package/src/components/block-preview/index.js +2 -0
  67. package/src/components/block-switcher/index.js +13 -1
  68. package/src/components/block-switcher/style.scss +7 -3
  69. package/src/components/block-switcher/test/__snapshots__/index.js.snap +15 -13
  70. package/src/components/list-view/block-select-button.js +2 -10
  71. package/src/store/selectors.js +22 -2
@@ -11,7 +11,7 @@ import {
11
11
  } from '@wordpress/components';
12
12
 
13
13
  import { useState } from '@wordpress/element';
14
- import { useInstanceId } from '@wordpress/compose';
14
+ import { useInstanceId, useResizeObserver } from '@wordpress/compose';
15
15
  import { __ } from '@wordpress/i18n';
16
16
 
17
17
  /**
@@ -28,6 +28,7 @@ const SetupContent = ( {
28
28
  activeSlide,
29
29
  patterns,
30
30
  onBlockPatternSelect,
31
+ height,
31
32
  } ) => {
32
33
  const composite = useCompositeState();
33
34
  const containerClass = 'block-editor-block-pattern-setup__container';
@@ -38,41 +39,52 @@ const SetupContent = ( {
38
39
  [ activeSlide + 1, 'next-slide' ],
39
40
  ] );
40
41
  return (
41
- <div className={ containerClass }>
42
- <ul className="carousel-container">
43
- { patterns.map( ( pattern, index ) => (
44
- <BlockPatternSlide
45
- className={ slideClass.get( index ) || '' }
46
- key={ pattern.name }
47
- pattern={ pattern }
48
- />
49
- ) ) }
50
- </ul>
42
+ <div
43
+ className="block-editor-block-pattern-setup__carousel"
44
+ style={ { height } }
45
+ >
46
+ <div className={ containerClass }>
47
+ <ul className="carousel-container">
48
+ { patterns.map( ( pattern, index ) => (
49
+ <BlockPatternSlide
50
+ className={ slideClass.get( index ) || '' }
51
+ key={ pattern.name }
52
+ pattern={ pattern }
53
+ minHeight={ height }
54
+ />
55
+ ) ) }
56
+ </ul>
57
+ </div>
51
58
  </div>
52
59
  );
53
60
  }
54
61
  return (
55
- <Composite
56
- { ...composite }
57
- role="listbox"
58
- className={ containerClass }
59
- aria-label={ __( 'Patterns list' ) }
62
+ <div
63
+ style={ { height } }
64
+ className="block-editor-block-pattern-setup__grid"
60
65
  >
61
- { patterns.map( ( pattern ) => (
62
- <BlockPattern
63
- key={ pattern.name }
64
- pattern={ pattern }
65
- onSelect={ onBlockPatternSelect }
66
- composite={ composite }
67
- />
68
- ) ) }
69
- </Composite>
66
+ <Composite
67
+ { ...composite }
68
+ role="listbox"
69
+ className={ containerClass }
70
+ aria-label={ __( 'Patterns list' ) }
71
+ >
72
+ { patterns.map( ( pattern ) => (
73
+ <BlockPattern
74
+ key={ pattern.name }
75
+ pattern={ pattern }
76
+ onSelect={ onBlockPatternSelect }
77
+ composite={ composite }
78
+ />
79
+ ) ) }
80
+ </Composite>
81
+ </div>
70
82
  );
71
83
  };
72
84
 
73
85
  function BlockPattern( { pattern, onSelect, composite } ) {
74
86
  const baseClassName = 'block-editor-block-pattern-setup-list';
75
- const { blocks, title, description, viewportWidth = 700 } = pattern;
87
+ const { blocks, description, viewportWidth = 700 } = pattern;
76
88
  const descriptionId = useInstanceId(
77
89
  BlockPattern,
78
90
  `${ baseClassName }__item-description`
@@ -94,9 +106,6 @@ function BlockPattern( { pattern, onSelect, composite } ) {
94
106
  blocks={ blocks }
95
107
  viewportWidth={ viewportWidth }
96
108
  />
97
- <div className={ `${ baseClassName }__item-title` }>
98
- { title }
99
- </div>
100
109
  </CompositeItem>
101
110
  { !! description && (
102
111
  <VisuallyHidden id={ descriptionId }>
@@ -107,7 +116,7 @@ function BlockPattern( { pattern, onSelect, composite } ) {
107
116
  );
108
117
  }
109
118
 
110
- function BlockPatternSlide( { className, pattern } ) {
119
+ function BlockPatternSlide( { className, pattern, minHeight } ) {
111
120
  const { blocks, title, description } = pattern;
112
121
  const descriptionId = useInstanceId(
113
122
  BlockPatternSlide,
@@ -119,7 +128,10 @@ function BlockPatternSlide( { className, pattern } ) {
119
128
  aria-label={ title }
120
129
  aria-describedby={ description ? descriptionId : undefined }
121
130
  >
122
- <BlockPreview blocks={ blocks } __experimentalLive />
131
+ <BlockPreview
132
+ blocks={ blocks }
133
+ __experimentalMinHeight={ minHeight }
134
+ />
123
135
  { !! description && (
124
136
  <VisuallyHidden id={ descriptionId }>
125
137
  { description }
@@ -141,6 +153,10 @@ const BlockPatternSetup = ( {
141
153
  const [ showBlank, setShowBlank ] = useState( false );
142
154
  const { replaceBlock } = useDispatch( blockEditorStore );
143
155
  const patterns = usePatternsSetup( clientId, blockName, filterPatternsFn );
156
+ const [
157
+ contentResizeListener,
158
+ { height: contentHeight },
159
+ ] = useResizeObserver();
144
160
 
145
161
  if ( ! patterns?.length || showBlank ) {
146
162
  return startBlankComponent;
@@ -152,35 +168,44 @@ const BlockPatternSetup = ( {
152
168
  };
153
169
  const onPatternSelectCallback =
154
170
  onBlockPatternSelect || onBlockPatternSelectDefault;
171
+ const onStartBlank = startBlankComponent
172
+ ? () => {
173
+ setShowBlank( true );
174
+ }
175
+ : undefined;
155
176
  return (
156
- <div
157
- className={ `block-editor-block-pattern-setup view-mode-${ viewMode }` }
158
- >
159
- <SetupToolbar
160
- viewMode={ viewMode }
161
- setViewMode={ setViewMode }
162
- activeSlide={ activeSlide }
163
- totalSlides={ patterns.length }
164
- handleNext={ () => {
165
- setActiveSlide( ( active ) => active + 1 );
166
- } }
167
- handlePrevious={ () => {
168
- setActiveSlide( ( active ) => active - 1 );
169
- } }
170
- onBlockPatternSelect={ () => {
171
- onPatternSelectCallback( patterns[ activeSlide ].blocks );
172
- } }
173
- onStartBlank={ () => {
174
- setShowBlank( true );
175
- } }
176
- />
177
- <SetupContent
178
- viewMode={ viewMode }
179
- activeSlide={ activeSlide }
180
- patterns={ patterns }
181
- onBlockPatternSelect={ onPatternSelectCallback }
182
- />
183
- </div>
177
+ <>
178
+ { contentResizeListener }
179
+ <div
180
+ className={ `block-editor-block-pattern-setup view-mode-${ viewMode }` }
181
+ >
182
+ <SetupContent
183
+ viewMode={ viewMode }
184
+ activeSlide={ activeSlide }
185
+ patterns={ patterns }
186
+ onBlockPatternSelect={ onPatternSelectCallback }
187
+ height={ contentHeight - 2 * 60 }
188
+ />
189
+ <SetupToolbar
190
+ viewMode={ viewMode }
191
+ setViewMode={ setViewMode }
192
+ activeSlide={ activeSlide }
193
+ totalSlides={ patterns.length }
194
+ handleNext={ () => {
195
+ setActiveSlide( ( active ) => active + 1 );
196
+ } }
197
+ handlePrevious={ () => {
198
+ setActiveSlide( ( active ) => active - 1 );
199
+ } }
200
+ onBlockPatternSelect={ () => {
201
+ onPatternSelectCallback(
202
+ patterns[ activeSlide ].blocks
203
+ );
204
+ } }
205
+ onStartBlank={ onStartBlank }
206
+ />
207
+ </div>
208
+ </>
184
209
  );
185
210
  };
186
211
 
@@ -17,7 +17,9 @@ import { VIEWMODES } from './constants';
17
17
 
18
18
  const Actions = ( { onStartBlank, onBlockPatternSelect } ) => (
19
19
  <div className="block-editor-block-pattern-setup__actions">
20
- <Button onClick={ onStartBlank }>{ __( 'Start blank' ) }</Button>
20
+ { onStartBlank && (
21
+ <Button onClick={ onStartBlank }>{ __( 'Start blank' ) }</Button>
22
+ ) }
21
23
  <Button variant="primary" onClick={ onBlockPatternSelect }>
22
24
  { __( 'Choose' ) }
23
25
  </Button>
@@ -5,8 +5,6 @@
5
5
  align-items: flex-start;
6
6
  width: 100%;
7
7
  border-radius: $radius-block-ui;
8
- box-shadow: inset 0 0 0 $border-width $gray-900;
9
- outline: 1px solid transparent; // Shown for Windows 10 High Contrast mode.
10
8
 
11
9
  // TODO change to check parent.
12
10
  &.view-mode-grid {
@@ -15,37 +13,41 @@
15
13
  }
16
14
 
17
15
  .block-editor-block-pattern-setup__container {
18
- display: grid;
19
- grid-template-columns: 1fr 1fr;
20
- grid-gap: $grid-unit-20;
21
- padding: $grid-unit-20;
22
- max-height: 550px;
23
- overflow: auto;
24
- margin: 0 $border-width $border-width $border-width;
25
- width: calc(100% - #{ $border-width * 2 });
26
- background: $white;
16
+ column-gap: $grid-unit-30;
17
+ display: block;
18
+ width: 100%;
19
+ padding: $grid-unit-40;
20
+ column-count: 2;
21
+
22
+ @include break-huge() {
23
+ column-count: 3;
24
+ }
27
25
 
28
26
  .block-editor-block-preview__container,
29
27
  div[role="button"] {
30
28
  cursor: pointer;
31
29
  }
32
30
 
33
- .block-editor-block-pattern-setup-list__item-title {
34
- padding: $grid-unit-05;
35
- font-size: $helptext-font-size;
36
- text-align: center;
37
- }
31
+ .block-editor-block-pattern-setup-list__list-item {
32
+ break-inside: avoid-column;
33
+ margin-bottom: $grid-unit-30;
34
+
35
+ .block-editor-block-preview__container {
36
+ min-height: 100px;
37
+ border-radius: $radius-block-ui;
38
+ border: $border-width solid $gray-300;
39
+ }
38
40
 
39
- .block-editor-block-preview__container {
40
- border-radius: $radius-block-ui;
41
- border: $border-width solid $gray-300;
41
+ .block-editor-block-preview__content {
42
+ width: 100%;
43
+ }
42
44
  }
43
45
  }
44
46
  }
45
47
 
46
48
  .block-editor-block-pattern-setup__toolbar {
49
+ height: $header-height;
47
50
  box-sizing: border-box;
48
- position: relative;
49
51
  padding: $grid-unit-20;
50
52
  width: 100%;
51
53
  text-align: left;
@@ -54,13 +56,12 @@
54
56
  // Block UI appearance.
55
57
  border-radius: $radius-block-ui $radius-block-ui 0 0;
56
58
  background-color: $white;
57
- box-shadow: inset 0 0 0 $border-width $gray-900;
58
- outline: 1px solid transparent; // Shown for Windows 10 High Contrast mode.
59
-
60
59
  display: flex;
61
60
  flex-direction: row;
62
61
  align-items: center;
63
62
  justify-content: space-between;
63
+ border-top: 1px solid $gray-300;
64
+ align-self: flex-end;
64
65
 
65
66
  .block-editor-block-pattern-setup__display-controls {
66
67
  display: flex;
@@ -93,13 +94,12 @@
93
94
  box-sizing: border-box;
94
95
  }
95
96
  .pattern-slide {
96
- opacity: 0;
97
97
  position: absolute;
98
98
  top: 0;
99
99
  width: 100%;
100
100
  margin: auto;
101
- padding: $grid-unit-20;
102
- transition: transform 0.5s, opacity 0.5s, z-index 0.5s;
101
+ padding: 0;
102
+ transition: transform 0.5s, z-index 0.5s;
103
103
  z-index: z-index(".block-editor-block-pattern-setup .pattern-slide");
104
104
 
105
105
  &.active-slide {
@@ -125,3 +125,9 @@
125
125
  }
126
126
  }
127
127
  }
128
+
129
+ .block-editor-block-pattern-setup__carousel,
130
+ .block-editor-block-pattern-setup__grid {
131
+ width: 100%;
132
+ overflow-y: auto;
133
+ }
@@ -19,7 +19,11 @@ let MemoizedBlockList;
19
19
 
20
20
  const MAX_HEIGHT = 2000;
21
21
 
22
- function AutoBlockPreview( { viewportWidth, __experimentalPadding } ) {
22
+ function AutoBlockPreview( {
23
+ viewportWidth,
24
+ __experimentalPadding,
25
+ __experimentalMinHeight,
26
+ } ) {
23
27
  const [
24
28
  containerResizeListener,
25
29
  { width: containerWidth },
@@ -68,6 +72,7 @@ function AutoBlockPreview( { viewportWidth, __experimentalPadding } ) {
68
72
  contentHeight > MAX_HEIGHT
69
73
  ? MAX_HEIGHT * scale
70
74
  : undefined,
75
+ minHeight: __experimentalMinHeight,
71
76
  } }
72
77
  >
73
78
  <Iframe
@@ -98,6 +103,10 @@ function AutoBlockPreview( { viewportWidth, __experimentalPadding } ) {
98
103
  // This is a catch-all max-height for patterns.
99
104
  // See: https://github.com/WordPress/gutenberg/pull/38175.
100
105
  maxHeight: MAX_HEIGHT,
106
+ minHeight:
107
+ scale < 1 && __experimentalMinHeight
108
+ ? __experimentalMinHeight / scale
109
+ : __experimentalMinHeight,
101
110
  } }
102
111
  >
103
112
  { contentResizeListener }
@@ -29,6 +29,7 @@ export function BlockPreview( {
29
29
  viewportWidth = 1200,
30
30
  __experimentalLive = false,
31
31
  __experimentalOnClick,
32
+ __experimentalMinHeight,
32
33
  } ) {
33
34
  const originalSettings = useSelect(
34
35
  ( select ) => select( blockEditorStore ).getSettings(),
@@ -51,6 +52,7 @@ export function BlockPreview( {
51
52
  <AutoHeightBlockPreview
52
53
  viewportWidth={ viewportWidth }
53
54
  __experimentalPadding={ __experimentalPadding }
55
+ __experimentalMinHeight={ __experimentalMinHeight }
54
56
  />
55
57
  ) }
56
58
  </BlockEditorProvider>
@@ -108,7 +108,19 @@ export const BlockSwitcherDropdownMenu = ( { clientIds, blocks } ) => {
108
108
  disabled
109
109
  className="block-editor-block-switcher__no-switcher-icon"
110
110
  title={ blockTitle }
111
- icon={ <BlockIcon icon={ icon } showColors /> }
111
+ icon={
112
+ <>
113
+ <BlockIcon icon={ icon } showColors />
114
+ { ( isReusable || isTemplate ) && (
115
+ <span className="block-editor-block-switcher__toggle-text">
116
+ <BlockTitle
117
+ clientId={ clientIds }
118
+ maximumLength={ 35 }
119
+ />
120
+ </span>
121
+ ) }
122
+ </>
123
+ }
112
124
  />
113
125
  </ToolbarGroup>
114
126
  );
@@ -46,11 +46,15 @@
46
46
  }
47
47
 
48
48
  .components-button.block-editor-block-switcher__no-switcher-icon {
49
- width: $block-toolbar-height;
49
+ display: flex;
50
+ // The `!important` is used to vastly simplify the overriding of an inherited selector.
51
+ // Can be removed if we refactor .block-editor-block-toolbar .components-toolbar-group .components-button.has-icon.has-icon
52
+ padding: ($grid-unit-15 * 0.5) $grid-unit-15 !important;
50
53
 
51
- .block-editor-blocks-icon {
54
+ .block-editor-block-icon {
52
55
  margin-right: auto;
53
56
  margin-left: auto;
57
+ min-width: $icon-size !important;
54
58
  }
55
59
  }
56
60
 
@@ -172,7 +176,7 @@
172
176
  // The block switcher in the contextual toolbar should be bigger.
173
177
  .block-editor-block-contextual-toolbar {
174
178
  .components-button.block-editor-block-switcher__no-switcher-icon {
175
- width: $grid-unit-60;
179
+ min-width: $button-size;
176
180
  }
177
181
 
178
182
  .components-button.block-editor-block-switcher__no-switcher-icon,
@@ -6,19 +6,21 @@ exports[`BlockSwitcherDropdownMenu should render disabled block switcher with mu
6
6
  className="block-editor-block-switcher__no-switcher-icon"
7
7
  disabled={true}
8
8
  icon={
9
- <Memo(BlockIcon)
10
- icon={
11
- <SVG
12
- viewBox="0 0 24 24"
13
- xmlns="http://www.w3.org/2000/svg"
14
- >
15
- <Path
16
- d="M20.2 8v11c0 .7-.6 1.2-1.2 1.2H6v1.5h13c1.5 0 2.7-1.2 2.7-2.8V8zM18 16.4V4.6c0-.9-.7-1.6-1.6-1.6H4.6C3.7 3 3 3.7 3 4.6v11.8c0 .9.7 1.6 1.6 1.6h11.8c.9 0 1.6-.7 1.6-1.6zm-13.5 0V4.6c0-.1.1-.1.1-.1h11.8c.1 0 .1.1.1.1v11.8c0 .1-.1.1-.1.1H4.6l-.1-.1z"
17
- />
18
- </SVG>
19
- }
20
- showColors={true}
21
- />
9
+ <React.Fragment>
10
+ <Memo(BlockIcon)
11
+ icon={
12
+ <SVG
13
+ viewBox="0 0 24 24"
14
+ xmlns="http://www.w3.org/2000/svg"
15
+ >
16
+ <Path
17
+ d="M20.2 8v11c0 .7-.6 1.2-1.2 1.2H6v1.5h13c1.5 0 2.7-1.2 2.7-2.8V8zM18 16.4V4.6c0-.9-.7-1.6-1.6-1.6H4.6C3.7 3 3 3.7 3 4.6v11.8c0 .9.7 1.6 1.6 1.6h11.8c.9 0 1.6-.7 1.6-1.6zm-13.5 0V4.6c0-.1.1-.1.1-.1h11.8c.1 0 .1.1.1.1v11.8c0 .1-.1.1-.1.1H4.6l-.1-.1z"
18
+ />
19
+ </SVG>
20
+ }
21
+ showColors={true}
22
+ />
23
+ </React.Fragment>
22
24
  }
23
25
  />
24
26
  </ToolbarGroup>
@@ -8,7 +8,6 @@ import classnames from 'classnames';
8
8
  */
9
9
  import { Button } from '@wordpress/components';
10
10
  import { forwardRef } from '@wordpress/element';
11
- import { useSelect } from '@wordpress/data';
12
11
  import { Icon, lock } from '@wordpress/icons';
13
12
  import { SPACE, ENTER } from '@wordpress/keycodes';
14
13
 
@@ -19,7 +18,7 @@ import BlockIcon from '../block-icon';
19
18
  import useBlockDisplayInformation from '../use-block-display-information';
20
19
  import BlockTitle from '../block-title';
21
20
  import ListViewExpander from './expander';
22
- import { store as blockEditorStore } from '../../store';
21
+ import { useBlockLock } from '../block-lock';
23
22
 
24
23
  function ListViewBlockSelectButton(
25
24
  {
@@ -36,14 +35,7 @@ function ListViewBlockSelectButton(
36
35
  ref
37
36
  ) {
38
37
  const blockInformation = useBlockDisplayInformation( clientId );
39
- const isLocked = useSelect(
40
- ( select ) => {
41
- const { canMoveBlock, canRemoveBlock } = select( blockEditorStore );
42
-
43
- return ! canMoveBlock( clientId ) || ! canRemoveBlock( clientId );
44
- },
45
- [ clientId ]
46
- );
38
+ const { isLocked } = useBlockLock( clientId );
47
39
 
48
40
  // The `href` attribute triggers the browser's native HTML drag operations.
49
41
  // When the link is dragged, the element's outerHTML is set in DataTransfer object as text/html.
@@ -1504,7 +1504,7 @@ export function canRemoveBlock( state, clientId, rootClientId = null ) {
1504
1504
 
1505
1505
  const { lock } = attributes;
1506
1506
  const parentIsLocked = !! getTemplateLock( state, rootClientId );
1507
- // If we don't have a lock on the blockType level, we differ to the parent templateLock.
1507
+ // If we don't have a lock on the blockType level, we defer to the parent templateLock.
1508
1508
  if ( lock === undefined || lock?.remove === undefined ) {
1509
1509
  return ! parentIsLocked;
1510
1510
  }
@@ -1545,7 +1545,7 @@ export function canMoveBlock( state, clientId, rootClientId = null ) {
1545
1545
 
1546
1546
  const { lock } = attributes;
1547
1547
  const parentIsLocked = getTemplateLock( state, rootClientId ) === 'all';
1548
- // If we don't have a lock on the blockType level, we differ to the parent templateLock.
1548
+ // If we don't have a lock on the blockType level, we defer to the parent templateLock.
1549
1549
  if ( lock === undefined || lock?.move === undefined ) {
1550
1550
  return ! parentIsLocked;
1551
1551
  }
@@ -1569,6 +1569,26 @@ export function canMoveBlocks( state, clientIds, rootClientId = null ) {
1569
1569
  );
1570
1570
  }
1571
1571
 
1572
+ /**
1573
+ * Determines if the given block is allowed to be edited.
1574
+ *
1575
+ * @param {Object} state Editor state.
1576
+ * @param {string} clientId The block client Id.
1577
+ *
1578
+ * @return {boolean} Whether the given block is allowed to be edited.
1579
+ */
1580
+ export function canEditBlock( state, clientId ) {
1581
+ const attributes = getBlockAttributes( state, clientId );
1582
+ if ( attributes === null ) {
1583
+ return true;
1584
+ }
1585
+
1586
+ const { lock } = attributes;
1587
+
1588
+ // When the edit is true, we cannot edit the block.
1589
+ return ! lock?.edit;
1590
+ }
1591
+
1572
1592
  /**
1573
1593
  * Determines if the given block type can be locked/unlocked by a user.
1574
1594
  *