@wordpress/block-editor 8.5.1 → 8.5.4

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 (100) hide show
  1. package/build/components/block-alignment-control/ui.js +1 -1
  2. package/build/components/block-alignment-control/ui.js.map +1 -1
  3. package/build/components/block-content-overlay/index.js +4 -13
  4. package/build/components/block-content-overlay/index.js.map +1 -1
  5. package/build/components/block-lock/menu-item.js +1 -1
  6. package/build/components/block-lock/menu-item.js.map +1 -1
  7. package/build/components/block-lock/modal.js +5 -35
  8. package/build/components/block-lock/modal.js.map +1 -1
  9. package/build/components/block-lock/toolbar.js +1 -2
  10. package/build/components/block-lock/toolbar.js.map +1 -1
  11. package/build/components/block-lock/use-block-lock.js +4 -10
  12. package/build/components/block-lock/use-block-lock.js.map +1 -1
  13. package/build/components/copy-handler/index.js +44 -9
  14. package/build/components/copy-handler/index.js.map +1 -1
  15. package/build/components/inserter/index.js +21 -7
  16. package/build/components/inserter/index.js.map +1 -1
  17. package/build/components/inserter/quick-inserter.js +4 -5
  18. package/build/components/inserter/quick-inserter.js.map +1 -1
  19. package/build/components/link-control/index.js +6 -7
  20. package/build/components/link-control/index.js.map +1 -1
  21. package/build/components/list-view/block.js +13 -2
  22. package/build/components/list-view/block.js.map +1 -1
  23. package/build/components/writing-flow/use-click-selection.js +1 -3
  24. package/build/components/writing-flow/use-click-selection.js.map +1 -1
  25. package/build/components/writing-flow/use-selection-observer.js +49 -8
  26. package/build/components/writing-flow/use-selection-observer.js.map +1 -1
  27. package/build/hooks/duotone.js +66 -16
  28. package/build/hooks/duotone.js.map +1 -1
  29. package/build/hooks/index.js +7 -1
  30. package/build/hooks/index.js.map +1 -1
  31. package/build/index.js +7 -0
  32. package/build/index.js.map +1 -1
  33. package/build/store/actions.js +22 -29
  34. package/build/store/actions.js.map +1 -1
  35. package/build/store/selectors.js +96 -25
  36. package/build/store/selectors.js.map +1 -1
  37. package/build/store/utils.js +27 -0
  38. package/build/store/utils.js.map +1 -0
  39. package/build-module/components/block-alignment-control/ui.js +2 -2
  40. package/build-module/components/block-alignment-control/ui.js.map +1 -1
  41. package/build-module/components/block-content-overlay/index.js +4 -13
  42. package/build-module/components/block-content-overlay/index.js.map +1 -1
  43. package/build-module/components/block-lock/menu-item.js +1 -1
  44. package/build-module/components/block-lock/menu-item.js.map +1 -1
  45. package/build-module/components/block-lock/modal.js +6 -35
  46. package/build-module/components/block-lock/modal.js.map +1 -1
  47. package/build-module/components/block-lock/toolbar.js +1 -2
  48. package/build-module/components/block-lock/toolbar.js.map +1 -1
  49. package/build-module/components/block-lock/use-block-lock.js +4 -10
  50. package/build-module/components/block-lock/use-block-lock.js.map +1 -1
  51. package/build-module/components/copy-handler/index.js +44 -9
  52. package/build-module/components/copy-handler/index.js.map +1 -1
  53. package/build-module/components/inserter/index.js +21 -7
  54. package/build-module/components/inserter/index.js.map +1 -1
  55. package/build-module/components/inserter/quick-inserter.js +4 -5
  56. package/build-module/components/inserter/quick-inserter.js.map +1 -1
  57. package/build-module/components/link-control/index.js +6 -7
  58. package/build-module/components/link-control/index.js.map +1 -1
  59. package/build-module/components/list-view/block.js +13 -2
  60. package/build-module/components/list-view/block.js.map +1 -1
  61. package/build-module/components/writing-flow/use-click-selection.js +1 -3
  62. package/build-module/components/writing-flow/use-click-selection.js.map +1 -1
  63. package/build-module/components/writing-flow/use-selection-observer.js +49 -8
  64. package/build-module/components/writing-flow/use-selection-observer.js.map +1 -1
  65. package/build-module/hooks/duotone.js +63 -16
  66. package/build-module/hooks/duotone.js.map +1 -1
  67. package/build-module/hooks/index.js +1 -0
  68. package/build-module/hooks/index.js.map +1 -1
  69. package/build-module/index.js +1 -1
  70. package/build-module/index.js.map +1 -1
  71. package/build-module/store/actions.js +5 -14
  72. package/build-module/store/actions.js.map +1 -1
  73. package/build-module/store/selectors.js +88 -22
  74. package/build-module/store/selectors.js.map +1 -1
  75. package/build-module/store/utils.js +20 -0
  76. package/build-module/store/utils.js.map +1 -0
  77. package/build-style/style-rtl.css +1 -3
  78. package/build-style/style.css +1 -3
  79. package/package.json +28 -28
  80. package/src/components/block-alignment-control/ui.js +2 -2
  81. package/src/components/block-content-overlay/index.js +2 -19
  82. package/src/components/block-content-overlay/style.scss +0 -1
  83. package/src/components/block-lock/menu-item.js +1 -1
  84. package/src/components/block-lock/modal.js +3 -42
  85. package/src/components/block-lock/style.scss +1 -2
  86. package/src/components/block-lock/toolbar.js +2 -2
  87. package/src/components/block-lock/use-block-lock.js +5 -12
  88. package/src/components/copy-handler/index.js +52 -10
  89. package/src/components/inserter/index.js +20 -0
  90. package/src/components/inserter/quick-inserter.js +3 -11
  91. package/src/components/link-control/index.js +5 -5
  92. package/src/components/list-view/block.js +16 -7
  93. package/src/components/writing-flow/use-click-selection.js +1 -4
  94. package/src/components/writing-flow/use-selection-observer.js +55 -10
  95. package/src/hooks/duotone.js +98 -62
  96. package/src/hooks/index.js +1 -0
  97. package/src/index.js +1 -0
  98. package/src/store/actions.js +5 -13
  99. package/src/store/selectors.js +126 -20
  100. package/src/store/utils.js +19 -0
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Helper function that maps attribute definition properties to the
3
+ * ones used by RichText utils like `create, toHTMLString, etc..`.
4
+ *
5
+ * @param {Object} attributeDefinition A block's attribute definition object.
6
+ * @return {Object} The mapped object.
7
+ */
8
+ export function mapRichTextSettings(attributeDefinition) {
9
+ const {
10
+ multiline: multilineTag,
11
+ __unstableMultilineWrapperTags: multilineWrapperTags,
12
+ __unstablePreserveWhiteSpace: preserveWhiteSpace
13
+ } = attributeDefinition;
14
+ return {
15
+ multilineTag,
16
+ multilineWrapperTags,
17
+ preserveWhiteSpace
18
+ };
19
+ }
20
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["@wordpress/block-editor/src/store/utils.js"],"names":["mapRichTextSettings","attributeDefinition","multiline","multilineTag","__unstableMultilineWrapperTags","multilineWrapperTags","__unstablePreserveWhiteSpace","preserveWhiteSpace"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASA,mBAAT,CAA8BC,mBAA9B,EAAoD;AAC1D,QAAM;AACLC,IAAAA,SAAS,EAAEC,YADN;AAELC,IAAAA,8BAA8B,EAAEC,oBAF3B;AAGLC,IAAAA,4BAA4B,EAAEC;AAHzB,MAIFN,mBAJJ;AAKA,SAAO;AACNE,IAAAA,YADM;AAENE,IAAAA,oBAFM;AAGNE,IAAAA;AAHM,GAAP;AAKA","sourcesContent":["/**\n * Helper function that maps attribute definition properties to the\n * ones used by RichText utils like `create, toHTMLString, etc..`.\n *\n * @param {Object} attributeDefinition A block's attribute definition object.\n * @return {Object} The mapped object.\n */\nexport function mapRichTextSettings( attributeDefinition ) {\n\tconst {\n\t\tmultiline: multilineTag,\n\t\t__unstableMultilineWrapperTags: multilineWrapperTags,\n\t\t__unstablePreserveWhiteSpace: preserveWhiteSpace,\n\t} = attributeDefinition;\n\treturn {\n\t\tmultilineTag,\n\t\tmultilineWrapperTags,\n\t\tpreserveWhiteSpace,\n\t};\n}\n"]}
@@ -855,8 +855,7 @@
855
855
  padding-right: 0 !important;
856
856
  }
857
857
  .block-editor-block-lock-toolbar .components-button.has-icon:focus::before {
858
- right: 0 !important;
859
- left: 12px !important;
858
+ left: 8px !important;
860
859
  }
861
860
 
862
861
  .block-editor-block-breadcrumb {
@@ -1019,7 +1018,6 @@
1019
1018
  border: none;
1020
1019
  border-radius: 2px;
1021
1020
  z-index: 10;
1022
- pointer-events: none;
1023
1021
  }
1024
1022
  .block-editor-block-content-overlay:hover:not(.is-dragging-blocks).overlay-active::before, .block-editor-block-content-overlay.parent-highlighted.overlay-active::before {
1025
1023
  background: rgba(var(--wp-admin-theme-color--rgb), 0.1);
@@ -855,8 +855,7 @@
855
855
  padding-left: 0 !important;
856
856
  }
857
857
  .block-editor-block-lock-toolbar .components-button.has-icon:focus::before {
858
- left: 0 !important;
859
- right: 12px !important;
858
+ right: 8px !important;
860
859
  }
861
860
 
862
861
  .block-editor-block-breadcrumb {
@@ -1019,7 +1018,6 @@
1019
1018
  border: none;
1020
1019
  border-radius: 2px;
1021
1020
  z-index: 10;
1022
- pointer-events: none;
1023
1021
  }
1024
1022
  .block-editor-block-content-overlay:hover:not(.is-dragging-blocks).overlay-active::before, .block-editor-block-content-overlay.parent-highlighted.overlay-active::before {
1025
1023
  background: rgba(var(--wp-admin-theme-color--rgb), 0.1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/block-editor",
3
- "version": "8.5.1",
3
+ "version": "8.5.4",
4
4
  "description": "Generic block editor.",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -33,32 +33,32 @@
33
33
  "dependencies": {
34
34
  "@babel/runtime": "^7.16.0",
35
35
  "@react-spring/web": "^9.2.4",
36
- "@wordpress/a11y": "^3.6.0",
37
- "@wordpress/api-fetch": "^6.3.0",
38
- "@wordpress/blob": "^3.6.0",
39
- "@wordpress/blocks": "^11.5.1",
40
- "@wordpress/components": "^19.8.0",
41
- "@wordpress/compose": "^5.4.0",
42
- "@wordpress/data": "^6.6.0",
43
- "@wordpress/date": "^4.6.0",
44
- "@wordpress/deprecated": "^3.6.0",
45
- "@wordpress/dom": "^3.6.0",
46
- "@wordpress/element": "^4.4.0",
47
- "@wordpress/hooks": "^3.6.0",
48
- "@wordpress/html-entities": "^3.6.0",
49
- "@wordpress/i18n": "^4.6.0",
50
- "@wordpress/icons": "^8.2.0",
51
- "@wordpress/is-shallow-equal": "^4.6.0",
52
- "@wordpress/keyboard-shortcuts": "^3.4.0",
53
- "@wordpress/keycodes": "^3.6.0",
54
- "@wordpress/notices": "^3.6.0",
55
- "@wordpress/rich-text": "^5.4.0",
56
- "@wordpress/shortcode": "^3.6.0",
57
- "@wordpress/style-engine": "^0.5.0",
58
- "@wordpress/token-list": "^2.6.0",
59
- "@wordpress/url": "^3.7.0",
60
- "@wordpress/warning": "^2.6.0",
61
- "@wordpress/wordcount": "^3.6.0",
36
+ "@wordpress/a11y": "^3.6.1",
37
+ "@wordpress/api-fetch": "^6.3.1",
38
+ "@wordpress/blob": "^3.6.1",
39
+ "@wordpress/blocks": "^11.5.3",
40
+ "@wordpress/components": "^19.8.3",
41
+ "@wordpress/compose": "^5.4.1",
42
+ "@wordpress/data": "^6.6.1",
43
+ "@wordpress/date": "^4.6.1",
44
+ "@wordpress/deprecated": "^3.6.1",
45
+ "@wordpress/dom": "^3.6.1",
46
+ "@wordpress/element": "^4.4.1",
47
+ "@wordpress/hooks": "^3.6.1",
48
+ "@wordpress/html-entities": "^3.6.1",
49
+ "@wordpress/i18n": "^4.6.1",
50
+ "@wordpress/icons": "^8.2.2",
51
+ "@wordpress/is-shallow-equal": "^4.6.1",
52
+ "@wordpress/keyboard-shortcuts": "^3.4.1",
53
+ "@wordpress/keycodes": "^3.6.1",
54
+ "@wordpress/notices": "^3.6.1",
55
+ "@wordpress/rich-text": "^5.4.2",
56
+ "@wordpress/shortcode": "^3.6.1",
57
+ "@wordpress/style-engine": "^0.5.1",
58
+ "@wordpress/token-list": "^2.6.1",
59
+ "@wordpress/url": "^3.7.1",
60
+ "@wordpress/warning": "^2.6.1",
61
+ "@wordpress/wordcount": "^3.6.1",
62
62
  "classnames": "^2.3.1",
63
63
  "colord": "^2.7.0",
64
64
  "diff": "^4.0.2",
@@ -77,5 +77,5 @@
77
77
  "publishConfig": {
78
78
  "access": "public"
79
79
  },
80
- "gitHead": "9c15c669843d53c5ca6024a4c486d01d819d123f"
80
+ "gitHead": "1fdd4758150247d6b690051aed18fa27c15f3a32"
81
81
  }
@@ -6,7 +6,7 @@ import classNames from 'classnames';
6
6
  /**
7
7
  * WordPress dependencies
8
8
  */
9
- import { __ } from '@wordpress/i18n';
9
+ import { __, _x } from '@wordpress/i18n';
10
10
  import {
11
11
  ToolbarDropdownMenu,
12
12
  ToolbarGroup,
@@ -31,7 +31,7 @@ import useAvailableAlignments from './use-available-alignments';
31
31
  const BLOCK_ALIGNMENTS_CONTROLS = {
32
32
  none: {
33
33
  icon: alignNone,
34
- title: __( 'None' ),
34
+ title: _x( 'None', 'Alignment option' ),
35
35
  },
36
36
  left: {
37
37
  icon: positionLeft,
@@ -25,7 +25,6 @@ export default function BlockContentOverlay( {
25
25
  const [ isHovered, setIsHovered ] = useState( false );
26
26
 
27
27
  const {
28
- canEdit,
29
28
  isParentSelected,
30
29
  hasChildSelected,
31
30
  isDraggingBlocks,
@@ -37,10 +36,8 @@ export default function BlockContentOverlay( {
37
36
  hasSelectedInnerBlock,
38
37
  isDraggingBlocks: _isDraggingBlocks,
39
38
  isBlockHighlighted,
40
- canEditBlock,
41
39
  } = select( blockEditorStore );
42
40
  return {
43
- canEdit: canEditBlock( clientId ),
44
41
  isParentSelected: isBlockSelected( clientId ),
45
42
  hasChildSelected: hasSelectedInnerBlock( clientId, true ),
46
43
  isDraggingBlocks: _isDraggingBlocks(),
@@ -62,12 +59,6 @@ export default function BlockContentOverlay( {
62
59
  );
63
60
 
64
61
  useEffect( () => {
65
- // The overlay is always active when editing is locked.
66
- if ( ! canEdit ) {
67
- setIsOverlayActive( true );
68
- return;
69
- }
70
-
71
62
  // Reenable when blocks are not in use.
72
63
  if ( ! isParentSelected && ! hasChildSelected && ! isOverlayActive ) {
73
64
  setIsOverlayActive( true );
@@ -84,13 +75,7 @@ export default function BlockContentOverlay( {
84
75
  if ( hasChildSelected && isOverlayActive ) {
85
76
  setIsOverlayActive( false );
86
77
  }
87
- }, [
88
- isParentSelected,
89
- hasChildSelected,
90
- isOverlayActive,
91
- isHovered,
92
- canEdit,
93
- ] );
78
+ }, [ isParentSelected, hasChildSelected, isOverlayActive, isHovered ] );
94
79
 
95
80
  // Disabled because the overlay div doesn't actually have a role or functionality
96
81
  // as far as the a11y is concerned. We're just catching the first click so that
@@ -103,9 +88,7 @@ export default function BlockContentOverlay( {
103
88
  onMouseEnter={ () => setIsHovered( true ) }
104
89
  onMouseLeave={ () => setIsHovered( false ) }
105
90
  onMouseUp={
106
- isOverlayActive && canEdit
107
- ? () => setIsOverlayActive( false )
108
- : undefined
91
+ isOverlayActive ? () => setIsOverlayActive( false ) : undefined
109
92
  }
110
93
  >
111
94
  { wrapperProps?.children }
@@ -10,7 +10,6 @@
10
10
  border: none;
11
11
  border-radius: $radius-block-ui;
12
12
  z-index: z-index(".block-editor-block-content-overlay__overlay");
13
- pointer-events: none;
14
13
  }
15
14
 
16
15
  &:hover:not(.is-dragging-blocks).overlay-active::before,
@@ -13,7 +13,7 @@ import useBlockLock from './use-block-lock';
13
13
  import BlockLockModal from './modal';
14
14
 
15
15
  export default function BlockLockMenuItem( { clientId } ) {
16
- const { canLock, isLocked } = useBlockLock( clientId, true );
16
+ const { canLock, isLocked } = useBlockLock( clientId );
17
17
 
18
18
  const [ isModalOpen, toggleModal ] = useReducer(
19
19
  ( isActive ) => ! isActive,
@@ -13,8 +13,7 @@ import {
13
13
  } from '@wordpress/components';
14
14
  import { lock as lockIcon, unlock as unlockIcon } from '@wordpress/icons';
15
15
  import { useInstanceId } from '@wordpress/compose';
16
- import { useDispatch, useSelect } from '@wordpress/data';
17
- import { isReusableBlock, getBlockType } from '@wordpress/blocks';
16
+ import { useDispatch } from '@wordpress/data';
18
17
 
19
18
  /**
20
19
  * Internal dependencies
@@ -25,18 +24,7 @@ import { store as blockEditorStore } from '../../store';
25
24
 
26
25
  export default function BlockLockModal( { clientId, onClose } ) {
27
26
  const [ lock, setLock ] = useState( { move: false, remove: false } );
28
- const { canEdit, canMove, canRemove } = useBlockLock( clientId, true );
29
- const { isReusable } = useSelect(
30
- ( select ) => {
31
- const { getBlockName } = select( blockEditorStore );
32
- const blockName = getBlockName( clientId );
33
-
34
- return {
35
- isReusable: isReusableBlock( getBlockType( blockName ) ),
36
- };
37
- },
38
- [ clientId ]
39
- );
27
+ const { canMove, canRemove } = useBlockLock( clientId );
40
28
  const { updateBlockAttributes } = useDispatch( blockEditorStore );
41
29
  const blockInformation = useBlockDisplayInformation( clientId );
42
30
  const instanceId = useInstanceId(
@@ -48,9 +36,8 @@ export default function BlockLockModal( { clientId, onClose } ) {
48
36
  setLock( {
49
37
  move: ! canMove,
50
38
  remove: ! canRemove,
51
- ...( isReusable ? { edit: ! canEdit } : {} ),
52
39
  } );
53
- }, [ canEdit, canMove, canRemove, isReusable ] );
40
+ }, [ canMove, canRemove ] );
54
41
 
55
42
  const isAllChecked = Object.values( lock ).every( Boolean );
56
43
  const isMixed = Object.values( lock ).some( Boolean ) && ! isAllChecked;
@@ -94,36 +81,10 @@ export default function BlockLockModal( { clientId, onClose } ) {
94
81
  setLock( {
95
82
  move: newValue,
96
83
  remove: newValue,
97
- ...( isReusable ? { edit: newValue } : {} ),
98
84
  } )
99
85
  }
100
86
  />
101
87
  <ul className="block-editor-block-lock-modal__checklist">
102
- { isReusable && (
103
- <li className="block-editor-block-lock-modal__checklist-item">
104
- <CheckboxControl
105
- label={
106
- <>
107
- { __( 'Restrict editing' ) }
108
- <Icon
109
- icon={
110
- lock.edit
111
- ? lockIcon
112
- : unlockIcon
113
- }
114
- />
115
- </>
116
- }
117
- checked={ !! lock.edit }
118
- onChange={ ( edit ) =>
119
- setLock( ( prevLock ) => ( {
120
- ...prevLock,
121
- edit,
122
- } ) )
123
- }
124
- />
125
- </li>
126
- ) }
127
88
  <li className="block-editor-block-lock-modal__checklist-item">
128
89
  <CheckboxControl
129
90
  label={
@@ -63,8 +63,7 @@
63
63
  padding-left: 0 !important;
64
64
 
65
65
  &:focus::before {
66
- left: 0 !important;
67
- right: $grid-unit-15 !important;
66
+ right: $grid-unit-10 !important;
68
67
  }
69
68
  }
70
69
  }
@@ -15,7 +15,7 @@ import useBlockDisplayInformation from '../use-block-display-information';
15
15
 
16
16
  export default function BlockLockToolbar( { clientId } ) {
17
17
  const blockInformation = useBlockDisplayInformation( clientId );
18
- const { canEdit, canMove, canRemove, canLock } = useBlockLock( clientId );
18
+ const { canMove, canRemove, canLock } = useBlockLock( clientId );
19
19
 
20
20
  const [ isModalOpen, toggleModal ] = useReducer(
21
21
  ( isActive ) => ! isActive,
@@ -26,7 +26,7 @@ export default function BlockLockToolbar( { clientId } ) {
26
26
  return null;
27
27
  }
28
28
 
29
- if ( canEdit && canMove && canRemove ) {
29
+ if ( canMove && canRemove ) {
30
30
  return null;
31
31
  }
32
32
 
@@ -11,39 +11,32 @@ import { store as blockEditorStore } from '../../store';
11
11
  /**
12
12
  * Return details about the block lock status.
13
13
  *
14
- * @param {string} clientId The block client Id.
15
- * @param {boolean} checkParent Optional. The status is derived from the parent `templateLock`
16
- * when the current block's lock state isn't defined.
14
+ * @param {string} clientId The block client Id.
17
15
  *
18
16
  * @return {Object} Block lock status
19
17
  */
20
- export default function useBlockLock( clientId, checkParent = false ) {
18
+ export default function useBlockLock( clientId ) {
21
19
  return useSelect(
22
20
  ( select ) => {
23
21
  const {
24
- canEditBlock,
25
22
  canMoveBlock,
26
23
  canRemoveBlock,
27
24
  canLockBlockType,
28
25
  getBlockName,
29
26
  getBlockRootClientId,
30
27
  } = select( blockEditorStore );
31
- const rootClientId = checkParent
32
- ? getBlockRootClientId( clientId )
33
- : null;
28
+ const rootClientId = getBlockRootClientId( clientId );
34
29
 
35
- const canEdit = canEditBlock( clientId );
36
30
  const canMove = canMoveBlock( clientId, rootClientId );
37
31
  const canRemove = canRemoveBlock( clientId, rootClientId );
38
32
 
39
33
  return {
40
- canEdit,
41
34
  canMove,
42
35
  canRemove,
43
36
  canLock: canLockBlockType( getBlockName( clientId ) ),
44
- isLocked: ! canEdit || ! canMove || ! canRemove,
37
+ isLocked: ! canMove || ! canRemove,
45
38
  };
46
39
  },
47
- [ clientId, checkParent ]
40
+ [ clientId ]
48
41
  );
49
42
  }
@@ -78,10 +78,18 @@ export function useClipboardHandler() {
78
78
  getSelectedBlockClientIds,
79
79
  hasMultiSelection,
80
80
  getSettings,
81
+ __unstableIsFullySelected,
82
+ __unstableIsSelectionCollapsed,
83
+ __unstableIsSelectionMergeable,
84
+ __unstableGetSelectedBlocksWithPartialSelection,
81
85
  } = useSelect( blockEditorStore );
82
- const { flashBlock, removeBlocks, replaceBlocks } = useDispatch(
83
- blockEditorStore
84
- );
86
+ const {
87
+ flashBlock,
88
+ removeBlocks,
89
+ replaceBlocks,
90
+ __unstableDeleteSelection,
91
+ __unstableExpandSelection,
92
+ } = useDispatch( blockEditorStore );
85
93
  const notifyCopy = useNotifyCopy();
86
94
 
87
95
  return useRefEffect( ( node ) => {
@@ -116,20 +124,54 @@ export function useClipboardHandler() {
116
124
  const eventDefaultPrevented = event.defaultPrevented;
117
125
  event.preventDefault();
118
126
 
127
+ const isSelectionMergeable = __unstableIsSelectionMergeable();
128
+ const shouldHandleWholeBlocks =
129
+ __unstableIsSelectionCollapsed() || __unstableIsFullySelected();
130
+ const expandSelectionIsNeeded =
131
+ ! shouldHandleWholeBlocks && ! isSelectionMergeable;
119
132
  if ( event.type === 'copy' || event.type === 'cut' ) {
120
133
  if ( selectedBlockClientIds.length === 1 ) {
121
134
  flashBlock( selectedBlockClientIds[ 0 ] );
122
135
  }
123
- notifyCopy( event.type, selectedBlockClientIds );
124
- const blocks = getBlocksByClientId( selectedBlockClientIds );
125
- const serialized = serialize( blocks );
126
-
127
- event.clipboardData.setData( 'text/plain', serialized );
128
- event.clipboardData.setData( 'text/html', serialized );
136
+ // If we have a partial selection that is not mergeable, just
137
+ // expand the selection to the whole blocks.
138
+ if ( expandSelectionIsNeeded ) {
139
+ __unstableExpandSelection();
140
+ } else {
141
+ notifyCopy( event.type, selectedBlockClientIds );
142
+ let blocks;
143
+ // Check if we have partial selection.
144
+ if ( shouldHandleWholeBlocks ) {
145
+ blocks = getBlocksByClientId( selectedBlockClientIds );
146
+ } else {
147
+ const [
148
+ head,
149
+ tail,
150
+ ] = __unstableGetSelectedBlocksWithPartialSelection();
151
+ const inBetweenBlocks = getBlocksByClientId(
152
+ selectedBlockClientIds.slice(
153
+ 1,
154
+ selectedBlockClientIds.length - 1
155
+ )
156
+ );
157
+ blocks = [ head, ...inBetweenBlocks, tail ];
158
+ }
159
+ const serialized = serialize( blocks );
160
+
161
+ event.clipboardData.setData( 'text/plain', serialized );
162
+ event.clipboardData.setData( 'text/html', serialized );
163
+ }
129
164
  }
130
165
 
131
166
  if ( event.type === 'cut' ) {
132
- removeBlocks( selectedBlockClientIds );
167
+ // We need to also check if at the start we needed to
168
+ // expand the selection, as in this point we might have
169
+ // programmatically fully selected the blocks above.
170
+ if ( shouldHandleWholeBlocks && ! expandSelectionIsNeeded ) {
171
+ removeBlocks( selectedBlockClientIds );
172
+ } else {
173
+ __unstableDeleteSelection();
174
+ }
133
175
  } else if ( event.type === 'paste' ) {
134
176
  if ( eventDefaultPrevented ) {
135
177
  // This was likely already handled in rich-text/use-paste-handler.js.
@@ -30,6 +30,7 @@ const defaultRenderToggle = ( {
30
30
  blockTitle,
31
31
  hasSingleBlockType,
32
32
  toggleProps = {},
33
+ prioritizePatterns,
33
34
  } ) => {
34
35
  let label;
35
36
  if ( hasSingleBlockType ) {
@@ -38,6 +39,8 @@ const defaultRenderToggle = ( {
38
39
  _x( 'Add %s', 'directly add the only allowed block' ),
39
40
  blockTitle
40
41
  );
42
+ } else if ( prioritizePatterns ) {
43
+ label = __( 'Add pattern' );
41
44
  } else {
42
45
  label = _x( 'Add block', 'Generic label for block inserter button' );
43
46
  }
@@ -106,6 +109,7 @@ class Inserter extends Component {
106
109
  toggleProps,
107
110
  hasItems,
108
111
  renderToggle = defaultRenderToggle,
112
+ prioritizePatterns,
109
113
  } = this.props;
110
114
 
111
115
  return renderToggle( {
@@ -116,6 +120,7 @@ class Inserter extends Component {
116
120
  hasSingleBlockType,
117
121
  directInsertBlock,
118
122
  toggleProps,
123
+ prioritizePatterns,
119
124
  } );
120
125
  }
121
126
 
@@ -138,6 +143,7 @@ class Inserter extends Component {
138
143
  // This prop is experimental to give some time for the quick inserter to mature
139
144
  // Feel free to make them stable after a few releases.
140
145
  __experimentalIsQuick: isQuick,
146
+ prioritizePatterns,
141
147
  } = this.props;
142
148
 
143
149
  if ( isQuick ) {
@@ -149,6 +155,7 @@ class Inserter extends Component {
149
155
  rootClientId={ rootClientId }
150
156
  clientId={ clientId }
151
157
  isAppender={ isAppender }
158
+ prioritizePatterns={ prioritizePatterns }
152
159
  />
153
160
  );
154
161
  }
@@ -206,7 +213,11 @@ export default compose( [
206
213
  hasInserterItems,
207
214
  __experimentalGetAllowedBlocks,
208
215
  __experimentalGetDirectInsertBlock,
216
+ getBlockIndex,
217
+ getBlockCount,
218
+ getSettings,
209
219
  } = select( blockEditorStore );
220
+
210
221
  const { getBlockVariations } = select( blocksStore );
211
222
 
212
223
  rootClientId =
@@ -218,6 +229,10 @@ export default compose( [
218
229
  rootClientId
219
230
  );
220
231
 
232
+ const index = getBlockIndex( clientId );
233
+ const blockCount = getBlockCount();
234
+ const settings = getSettings();
235
+
221
236
  const hasSingleBlockType =
222
237
  size( allowedBlocks ) === 1 &&
223
238
  size(
@@ -236,6 +251,11 @@ export default compose( [
236
251
  allowedBlockType,
237
252
  directInsertBlock,
238
253
  rootClientId,
254
+ prioritizePatterns:
255
+ settings.__experimentalPreferPatternsOnRoot &&
256
+ ! rootClientId &&
257
+ index > 0 &&
258
+ ( index < blockCount || blockCount === 0 ),
239
259
  };
240
260
  } ),
241
261
  withDispatch( ( dispatch, ownProps, { select } ) => {
@@ -30,6 +30,7 @@ export default function QuickInserter( {
30
30
  rootClientId,
31
31
  clientId,
32
32
  isAppender,
33
+ prioritizePatterns,
33
34
  } ) {
34
35
  const [ filterValue, setFilterValue ] = useState( '' );
35
36
  const [ destinationRootClientId, onInsertBlocks ] = useInsertionPoint( {
@@ -48,11 +49,7 @@ export default function QuickInserter( {
48
49
  destinationRootClientId
49
50
  );
50
51
 
51
- const {
52
- setInserterIsOpened,
53
- insertionIndex,
54
- prioritizePatterns,
55
- } = useSelect(
52
+ const { setInserterIsOpened, insertionIndex } = useSelect(
56
53
  ( select ) => {
57
54
  const { getSettings, getBlockIndex, getBlockCount } = select(
58
55
  blockEditorStore
@@ -63,15 +60,10 @@ export default function QuickInserter( {
63
60
 
64
61
  return {
65
62
  setInserterIsOpened: settings.__experimentalSetIsInserterOpened,
66
- prioritizePatterns:
67
- settings.__experimentalPreferPatternsOnRoot &&
68
- ! rootClientId &&
69
- index > 0 &&
70
- ( index < blockCount || blockCount === 0 ),
71
63
  insertionIndex: index === -1 ? blockCount : index,
72
64
  };
73
65
  },
74
- [ clientId, rootClientId ]
66
+ [ clientId ]
75
67
  );
76
68
 
77
69
  const showPatterns =
@@ -148,6 +148,10 @@ function LinkControl( {
148
148
 
149
149
  const currentInputIsEmpty = ! currentInputValue?.trim()?.length;
150
150
 
151
+ const { createPage, isCreatingPage, errorMessage } = useCreatePage(
152
+ createSuggestion
153
+ );
154
+
151
155
  useEffect( () => {
152
156
  if (
153
157
  forceIsEditingLink !== undefined &&
@@ -185,7 +189,7 @@ function LinkControl( {
185
189
  nextFocusTarget.focus();
186
190
 
187
191
  isEndingEditWithFocus.current = false;
188
- }, [ isEditingLink ] );
192
+ }, [ isEditingLink, isCreatingPage ] );
189
193
 
190
194
  useEffect( () => {
191
195
  /**
@@ -217,10 +221,6 @@ function LinkControl( {
217
221
  setIsEditingLink( false );
218
222
  }
219
223
 
220
- const { createPage, isCreatingPage, errorMessage } = useCreatePage(
221
- createSuggestion
222
- );
223
-
224
224
  const handleSelectSuggestion = ( updatedValue ) => {
225
225
  onChange( {
226
226
  ...updatedValue,
@@ -36,6 +36,7 @@ import { useListViewContext } from './context';
36
36
  import { getBlockPositionDescription } from './utils';
37
37
  import { store as blockEditorStore } from '../../store';
38
38
  import useBlockDisplayInformation from '../use-block-display-information';
39
+ import { useBlockLock } from '../block-lock';
39
40
 
40
41
  function ListViewBlock( {
41
42
  block,
@@ -65,6 +66,7 @@ function ListViewBlock( {
65
66
  const { toggleBlockHighlight } = useDispatch( blockEditorStore );
66
67
 
67
68
  const blockInformation = useBlockDisplayInformation( clientId );
69
+ const { isLocked } = useBlockLock( clientId );
68
70
  const instanceId = useInstanceId( ListViewBlock );
69
71
  const descriptionId = `list-view-block-select-button__${ instanceId }`;
70
72
  const blockPositionDescription = getBlockPositionDescription(
@@ -73,13 +75,20 @@ function ListViewBlock( {
73
75
  level
74
76
  );
75
77
 
76
- const blockAriaLabel = blockInformation
77
- ? sprintf(
78
- // translators: %s: The title of the block. This string indicates a link to select the block.
79
- __( '%s link' ),
80
- blockInformation.title
81
- )
82
- : __( 'Link' );
78
+ let blockAriaLabel = __( 'Link' );
79
+ if ( blockInformation ) {
80
+ blockAriaLabel = isLocked
81
+ ? sprintf(
82
+ // translators: %s: The title of the block. This string indicates a link to select the locked block.
83
+ __( '%s link (locked)' ),
84
+ blockInformation.title
85
+ )
86
+ : sprintf(
87
+ // translators: %s: The title of the block. This string indicates a link to select the block.
88
+ __( '%s link' ),
89
+ blockInformation.title
90
+ );
91
+ }
83
92
 
84
93
  const settingsAriaLabel = blockInformation
85
94
  ? sprintf(