@wordpress/block-editor 12.19.4 → 12.19.5

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 (90) hide show
  1. package/build/components/block-actions/index.js +45 -32
  2. package/build/components/block-actions/index.js.map +1 -1
  3. package/build/components/block-bindings-toolbar-indicator/index.js +25 -0
  4. package/build/components/block-bindings-toolbar-indicator/index.js.map +1 -0
  5. package/build/components/block-list/use-block-props/index.js +8 -1
  6. package/build/components/block-list/use-block-props/index.js.map +1 -1
  7. package/build/components/block-list/use-block-props/use-selected-block-event-handlers.js +3 -3
  8. package/build/components/block-list/use-block-props/use-selected-block-event-handlers.js.map +1 -1
  9. package/build/components/block-settings-menu/block-settings-dropdown.js +12 -10
  10. package/build/components/block-settings-menu/block-settings-dropdown.js.map +1 -1
  11. package/build/components/block-toolbar/index.js +14 -5
  12. package/build/components/block-toolbar/index.js.map +1 -1
  13. package/build/components/list-view/block-select-button.js +10 -2
  14. package/build/components/list-view/block-select-button.js.map +1 -1
  15. package/build/components/list-view/use-clipboard-handler.js +2 -1
  16. package/build/components/list-view/use-clipboard-handler.js.map +1 -1
  17. package/build/components/rich-text/index.js +1 -1
  18. package/build/components/rich-text/index.js.map +1 -1
  19. package/build/components/url-popover/index.js +3 -3
  20. package/build/components/url-popover/index.js.map +1 -1
  21. package/build/components/writing-flow/use-clipboard-handler.js +2 -1
  22. package/build/components/writing-flow/use-clipboard-handler.js.map +1 -1
  23. package/build/components/writing-flow/utils.js +23 -6
  24. package/build/components/writing-flow/utils.js.map +1 -1
  25. package/build/hooks/block-hooks.js +26 -2
  26. package/build/hooks/block-hooks.js.map +1 -1
  27. package/build/hooks/use-bindings-attributes.js +171 -46
  28. package/build/hooks/use-bindings-attributes.js.map +1 -1
  29. package/build/private-apis.js +2 -0
  30. package/build/private-apis.js.map +1 -1
  31. package/build/store/actions.js +40 -6
  32. package/build/store/actions.js.map +1 -1
  33. package/build-module/components/block-actions/index.js +45 -32
  34. package/build-module/components/block-actions/index.js.map +1 -1
  35. package/build-module/components/block-bindings-toolbar-indicator/index.js +18 -0
  36. package/build-module/components/block-bindings-toolbar-indicator/index.js.map +1 -0
  37. package/build-module/components/block-list/use-block-props/index.js +9 -2
  38. package/build-module/components/block-list/use-block-props/index.js.map +1 -1
  39. package/build-module/components/block-list/use-block-props/use-selected-block-event-handlers.js +3 -3
  40. package/build-module/components/block-list/use-block-props/use-selected-block-event-handlers.js.map +1 -1
  41. package/build-module/components/block-settings-menu/block-settings-dropdown.js +12 -10
  42. package/build-module/components/block-settings-menu/block-settings-dropdown.js.map +1 -1
  43. package/build-module/components/block-toolbar/index.js +14 -5
  44. package/build-module/components/block-toolbar/index.js.map +1 -1
  45. package/build-module/components/list-view/block-select-button.js +11 -3
  46. package/build-module/components/list-view/block-select-button.js.map +1 -1
  47. package/build-module/components/list-view/use-clipboard-handler.js +3 -2
  48. package/build-module/components/list-view/use-clipboard-handler.js.map +1 -1
  49. package/build-module/components/rich-text/index.js +2 -2
  50. package/build-module/components/rich-text/index.js.map +1 -1
  51. package/build-module/components/url-popover/index.js +3 -3
  52. package/build-module/components/url-popover/index.js.map +1 -1
  53. package/build-module/components/writing-flow/use-clipboard-handler.js +3 -2
  54. package/build-module/components/writing-flow/use-clipboard-handler.js.map +1 -1
  55. package/build-module/components/writing-flow/utils.js +22 -7
  56. package/build-module/components/writing-flow/utils.js.map +1 -1
  57. package/build-module/hooks/block-hooks.js +26 -2
  58. package/build-module/hooks/block-hooks.js.map +1 -1
  59. package/build-module/hooks/use-bindings-attributes.js +171 -46
  60. package/build-module/hooks/use-bindings-attributes.js.map +1 -1
  61. package/build-module/private-apis.js +2 -0
  62. package/build-module/private-apis.js.map +1 -1
  63. package/build-module/store/actions.js +40 -6
  64. package/build-module/store/actions.js.map +1 -1
  65. package/build-style/content-rtl.css +1 -0
  66. package/build-style/content.css +1 -0
  67. package/build-style/default-editor-styles-rtl.css +1 -0
  68. package/build-style/default-editor-styles.css +1 -0
  69. package/build-style/style-rtl.css +23 -0
  70. package/build-style/style.css +23 -0
  71. package/package.json +8 -8
  72. package/src/components/block-actions/index.js +57 -47
  73. package/src/components/block-bindings-toolbar-indicator/index.js +20 -0
  74. package/src/components/block-bindings-toolbar-indicator/style.scss +14 -0
  75. package/src/components/block-list/use-block-props/index.js +12 -2
  76. package/src/components/block-list/use-block-props/use-selected-block-event-handlers.js +3 -7
  77. package/src/components/block-settings-menu/block-settings-dropdown.js +12 -9
  78. package/src/components/block-toolbar/index.js +14 -4
  79. package/src/components/list-view/block-select-button.js +16 -2
  80. package/src/components/list-view/style.scss +8 -0
  81. package/src/components/list-view/use-clipboard-handler.js +3 -2
  82. package/src/components/rich-text/index.js +2 -2
  83. package/src/components/url-popover/index.js +5 -5
  84. package/src/components/writing-flow/use-clipboard-handler.js +3 -2
  85. package/src/components/writing-flow/utils.js +31 -16
  86. package/src/hooks/block-hooks.js +36 -3
  87. package/src/hooks/use-bindings-attributes.js +214 -62
  88. package/src/private-apis.js +2 -0
  89. package/src/store/actions.js +54 -14
  90. package/src/style.scss +1 -0
@@ -97,6 +97,7 @@
97
97
  --wp-admin-border-width-focus: 2px;
98
98
  --wp-block-synced-color: #7a00df;
99
99
  --wp-block-synced-color--rgb: 122, 0, 223;
100
+ --wp-bound-block-color: #9747ff;
100
101
  }
101
102
  @media (min-resolution: 192dpi) {
102
103
  :root {
@@ -122,6 +123,20 @@
122
123
  margin-top: 0;
123
124
  }
124
125
 
126
+ .block-editor-block-bindings-toolbar-indicator {
127
+ display: inline-flex;
128
+ align-items: center;
129
+ height: 48px;
130
+ padding: 6px;
131
+ }
132
+ .block-editor-block-bindings-toolbar-indicator svg g {
133
+ stroke: var(--wp-bound-block-color);
134
+ fill: transparent;
135
+ stroke-width: 1.5;
136
+ stroke-linecap: round;
137
+ stroke-linejoin: round;
138
+ }
139
+
125
140
  iframe[name=editor-canvas] {
126
141
  width: 100%;
127
142
  height: 100%;
@@ -2670,6 +2685,14 @@ iframe[name=editor-canvas].has-editor-padding {
2670
2685
  display: none;
2671
2686
  }
2672
2687
 
2688
+ .block-editor-list-view-block-select-button__bindings svg g {
2689
+ stroke: var(--wp-bound-block-color);
2690
+ fill: transparent;
2691
+ stroke-width: 1.5;
2692
+ stroke-linecap: round;
2693
+ stroke-linejoin: round;
2694
+ }
2695
+
2673
2696
  .modal-open .block-editor-media-replace-flow__options {
2674
2697
  display: none;
2675
2698
  }
@@ -97,6 +97,7 @@
97
97
  --wp-admin-border-width-focus: 2px;
98
98
  --wp-block-synced-color: #7a00df;
99
99
  --wp-block-synced-color--rgb: 122, 0, 223;
100
+ --wp-bound-block-color: #9747ff;
100
101
  }
101
102
  @media (min-resolution: 192dpi) {
102
103
  :root {
@@ -122,6 +123,20 @@
122
123
  margin-top: 0;
123
124
  }
124
125
 
126
+ .block-editor-block-bindings-toolbar-indicator {
127
+ display: inline-flex;
128
+ align-items: center;
129
+ height: 48px;
130
+ padding: 6px;
131
+ }
132
+ .block-editor-block-bindings-toolbar-indicator svg g {
133
+ stroke: var(--wp-bound-block-color);
134
+ fill: transparent;
135
+ stroke-width: 1.5;
136
+ stroke-linecap: round;
137
+ stroke-linejoin: round;
138
+ }
139
+
125
140
  iframe[name=editor-canvas] {
126
141
  width: 100%;
127
142
  height: 100%;
@@ -2671,6 +2686,14 @@ iframe[name=editor-canvas].has-editor-padding {
2671
2686
  display: none;
2672
2687
  }
2673
2688
 
2689
+ .block-editor-list-view-block-select-button__bindings svg g {
2690
+ stroke: var(--wp-bound-block-color);
2691
+ fill: transparent;
2692
+ stroke-width: 1.5;
2693
+ stroke-linecap: round;
2694
+ stroke-linejoin: round;
2695
+ }
2696
+
2674
2697
  .modal-open .block-editor-media-replace-flow__options {
2675
2698
  display: none;
2676
2699
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/block-editor",
3
- "version": "12.19.4",
3
+ "version": "12.19.5",
4
4
  "description": "Generic block editor.",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -38,9 +38,9 @@
38
38
  "@wordpress/a11y": "^3.51.1",
39
39
  "@wordpress/api-fetch": "^6.48.1",
40
40
  "@wordpress/blob": "^3.51.1",
41
- "@wordpress/blocks": "^12.28.4",
42
- "@wordpress/commands": "^0.22.3",
43
- "@wordpress/components": "^26.0.3",
41
+ "@wordpress/blocks": "^12.28.5",
42
+ "@wordpress/commands": "^0.22.4",
43
+ "@wordpress/components": "^26.0.4",
44
44
  "@wordpress/compose": "^6.28.1",
45
45
  "@wordpress/data": "^9.21.1",
46
46
  "@wordpress/date": "^4.51.1",
@@ -51,14 +51,14 @@
51
51
  "@wordpress/hooks": "^3.51.1",
52
52
  "@wordpress/html-entities": "^3.51.1",
53
53
  "@wordpress/i18n": "^4.51.1",
54
- "@wordpress/icons": "^9.42.2",
54
+ "@wordpress/icons": "^9.42.3",
55
55
  "@wordpress/is-shallow-equal": "^4.51.1",
56
56
  "@wordpress/keyboard-shortcuts": "^4.28.1",
57
57
  "@wordpress/keycodes": "^3.51.1",
58
58
  "@wordpress/notices": "^4.19.1",
59
- "@wordpress/preferences": "^3.28.3",
59
+ "@wordpress/preferences": "^3.28.4",
60
60
  "@wordpress/private-apis": "^0.33.1",
61
- "@wordpress/rich-text": "^6.28.2",
61
+ "@wordpress/rich-text": "^6.28.3",
62
62
  "@wordpress/style-engine": "^1.34.1",
63
63
  "@wordpress/token-list": "^2.51.1",
64
64
  "@wordpress/url": "^3.52.1",
@@ -87,5 +87,5 @@
87
87
  "publishConfig": {
88
88
  "access": "public"
89
89
  },
90
- "gitHead": "864c1c553cb284def3bd5c907998da45f5c143ea"
90
+ "gitHead": "4927ea437069f9aed12f696df294a79bd8e12fd5"
91
91
  }
@@ -20,42 +20,55 @@ export default function BlockActions( {
20
20
  children,
21
21
  __experimentalUpdateSelection: updateSelection,
22
22
  } ) {
23
- const {
24
- canInsertBlockType,
25
- getBlockRootClientId,
26
- getBlocksByClientId,
27
- canMoveBlocks,
28
- canRemoveBlocks,
29
- } = useSelect( blockEditorStore );
30
23
  const { getDefaultBlockName, getGroupingBlockName } =
31
24
  useSelect( blocksStore );
32
-
33
- const blocks = getBlocksByClientId( clientIds );
34
- const rootClientId = getBlockRootClientId( clientIds[ 0 ] );
35
-
36
- const canCopyStyles = blocks.every( ( block ) => {
37
- return (
38
- !! block &&
39
- ( hasBlockSupport( block.name, 'color' ) ||
40
- hasBlockSupport( block.name, 'typography' ) )
41
- );
42
- } );
43
-
44
- const canDuplicate = blocks.every( ( block ) => {
45
- return (
46
- !! block &&
47
- hasBlockSupport( block.name, 'multiple', true ) &&
48
- canInsertBlockType( block.name, rootClientId )
49
- );
50
- } );
51
-
52
- const canInsertDefaultBlock = canInsertBlockType(
53
- getDefaultBlockName(),
54
- rootClientId
25
+ const selected = useSelect(
26
+ ( select ) => {
27
+ const {
28
+ canInsertBlockType,
29
+ getBlockRootClientId,
30
+ getBlocksByClientId,
31
+ getDirectInsertBlock,
32
+ canMoveBlocks,
33
+ canRemoveBlocks,
34
+ } = select( blockEditorStore );
35
+
36
+ const blocks = getBlocksByClientId( clientIds );
37
+ const rootClientId = getBlockRootClientId( clientIds[ 0 ] );
38
+ const canInsertDefaultBlock = canInsertBlockType(
39
+ getDefaultBlockName(),
40
+ rootClientId
41
+ );
42
+ const directInsertBlock = rootClientId
43
+ ? getDirectInsertBlock( rootClientId )
44
+ : null;
45
+
46
+ return {
47
+ canMove: canMoveBlocks( clientIds, rootClientId ),
48
+ canRemove: canRemoveBlocks( clientIds, rootClientId ),
49
+ canInsertBlock: canInsertDefaultBlock || !! directInsertBlock,
50
+ canCopyStyles: blocks.every( ( block ) => {
51
+ return (
52
+ !! block &&
53
+ ( hasBlockSupport( block.name, 'color' ) ||
54
+ hasBlockSupport( block.name, 'typography' ) )
55
+ );
56
+ } ),
57
+ canDuplicate: blocks.every( ( block ) => {
58
+ return (
59
+ !! block &&
60
+ hasBlockSupport( block.name, 'multiple', true ) &&
61
+ canInsertBlockType( block.name, rootClientId )
62
+ );
63
+ } ),
64
+ };
65
+ },
66
+ [ clientIds, getDefaultBlockName ]
55
67
  );
68
+ const { getBlocksByClientId, getBlocks } = useSelect( blockEditorStore );
56
69
 
57
- const canMove = canMoveBlocks( clientIds, rootClientId );
58
- const canRemove = canRemoveBlocks( clientIds, rootClientId );
70
+ const { canMove, canRemove, canInsertBlock, canCopyStyles, canDuplicate } =
71
+ selected;
59
72
 
60
73
  const {
61
74
  removeBlocks,
@@ -75,11 +88,9 @@ export default function BlockActions( {
75
88
  return children( {
76
89
  canCopyStyles,
77
90
  canDuplicate,
78
- canInsertDefaultBlock,
91
+ canInsertBlock,
79
92
  canMove,
80
93
  canRemove,
81
- rootClientId,
82
- blocks,
83
94
  onDuplicate() {
84
95
  return duplicateBlocks( clientIds, updateSelection );
85
96
  },
@@ -104,14 +115,17 @@ export default function BlockActions( {
104
115
  setBlockMovingClientId( clientIds[ 0 ] );
105
116
  },
106
117
  onGroup() {
107
- if ( ! blocks.length ) {
118
+ if ( ! clientIds.length ) {
108
119
  return;
109
120
  }
110
121
 
111
122
  const groupingBlockName = getGroupingBlockName();
112
123
 
113
124
  // Activate the `transform` on `core/group` which does the conversion.
114
- const newBlocks = switchToBlockType( blocks, groupingBlockName );
125
+ const newBlocks = switchToBlockType(
126
+ getBlocksByClientId( clientIds ),
127
+ groupingBlockName
128
+ );
115
129
 
116
130
  if ( ! newBlocks ) {
117
131
  return;
@@ -119,12 +133,11 @@ export default function BlockActions( {
119
133
  replaceBlocks( clientIds, newBlocks );
120
134
  },
121
135
  onUngroup() {
122
- if ( ! blocks.length ) {
136
+ if ( ! clientIds.length ) {
123
137
  return;
124
138
  }
125
139
 
126
- const innerBlocks = blocks[ 0 ].innerBlocks;
127
-
140
+ const innerBlocks = getBlocks( clientIds[ 0 ] );
128
141
  if ( ! innerBlocks.length ) {
129
142
  return;
130
143
  }
@@ -132,16 +145,13 @@ export default function BlockActions( {
132
145
  replaceBlocks( clientIds, innerBlocks );
133
146
  },
134
147
  onCopy() {
135
- const selectedBlockClientIds = blocks.map(
136
- ( { clientId } ) => clientId
137
- );
138
- if ( blocks.length === 1 ) {
139
- flashBlock( selectedBlockClientIds[ 0 ] );
148
+ if ( clientIds.length === 1 ) {
149
+ flashBlock( clientIds[ 0 ] );
140
150
  }
141
- notifyCopy( 'copy', selectedBlockClientIds );
151
+ notifyCopy( 'copy', clientIds );
142
152
  },
143
153
  async onPasteStyles() {
144
- await pasteStyles( blocks );
154
+ await pasteStyles( getBlocksByClientId( clientIds ) );
145
155
  },
146
156
  } );
147
157
  }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { ToolbarItem, ToolbarGroup, Icon } from '@wordpress/components';
5
+ import { connection } from '@wordpress/icons';
6
+ import { _x } from '@wordpress/i18n';
7
+
8
+ export default function BlockBindingsToolbarIndicator() {
9
+ return (
10
+ <ToolbarGroup>
11
+ <ToolbarItem
12
+ as={ 'div' }
13
+ aria-label={ _x( 'Connected', 'block toolbar button label' ) }
14
+ className="block-editor-block-bindings-toolbar-indicator"
15
+ >
16
+ <Icon icon={ connection } size={ 24 } />
17
+ </ToolbarItem>
18
+ </ToolbarGroup>
19
+ );
20
+ }
@@ -0,0 +1,14 @@
1
+ .block-editor-block-bindings-toolbar-indicator {
2
+ display: inline-flex;
3
+ align-items: center;
4
+ height: 48px;
5
+ padding: 6px;
6
+
7
+ svg g {
8
+ stroke: var(--wp-bound-block-color);
9
+ fill: transparent;
10
+ stroke-width: 1.5;
11
+ stroke-linecap: round;
12
+ stroke-linejoin: round;
13
+ }
14
+ }
@@ -19,13 +19,17 @@ import useMovingAnimation from '../../use-moving-animation';
19
19
  import { PrivateBlockContext } from '../private-block-context';
20
20
  import { useFocusFirstElement } from './use-focus-first-element';
21
21
  import { useIsHovered } from './use-is-hovered';
22
- import { useBlockEditContext } from '../../block-edit/context';
22
+ import {
23
+ blockBindingsKey,
24
+ useBlockEditContext,
25
+ } from '../../block-edit/context';
23
26
  import { useFocusHandler } from './use-focus-handler';
24
27
  import { useEventHandlers } from './use-selected-block-event-handlers';
25
28
  import { useNavModeExit } from './use-nav-mode-exit';
26
29
  import { useBlockRefProvider } from './use-block-refs';
27
30
  import { useIntersectionObserver } from './use-intersection-observer';
28
31
  import { useFlashEditableBlocks } from '../../use-flash-editable-blocks';
32
+ import { canBindBlock } from '../../../hooks/use-bindings-attributes';
29
33
 
30
34
  /**
31
35
  * This hook is used to lightly mark an element as a block element. The element
@@ -123,6 +127,12 @@ export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) {
123
127
  ] );
124
128
 
125
129
  const blockEditContext = useBlockEditContext();
130
+ const hasBlockBindings = !! blockEditContext[ blockBindingsKey ];
131
+ const bindingsStyle =
132
+ hasBlockBindings && canBindBlock( name )
133
+ ? { '--wp-admin-theme-color': 'var(--wp-bound-block-color)' }
134
+ : {};
135
+
126
136
  // Ensures it warns only inside the `edit` implementation for the block.
127
137
  if ( blockApiVersion < 2 && clientId === blockEditContext.clientId ) {
128
138
  warning(
@@ -168,7 +178,7 @@ export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) {
168
178
  wrapperProps.className,
169
179
  defaultClassName
170
180
  ),
171
- style: { ...wrapperProps.style, ...props.style },
181
+ style: { ...wrapperProps.style, ...props.style, ...bindingsStyle },
172
182
  };
173
183
  }
174
184
 
@@ -22,7 +22,7 @@ import { store as blockEditorStore } from '../../../store';
22
22
  export function useEventHandlers( { clientId, isSelected } ) {
23
23
  const { getBlockRootClientId, getBlockIndex } =
24
24
  useSelect( blockEditorStore );
25
- const { insertDefaultBlock, removeBlock } = useDispatch( blockEditorStore );
25
+ const { insertAfterBlock, removeBlock } = useDispatch( blockEditorStore );
26
26
 
27
27
  return useRefEffect(
28
28
  ( node ) => {
@@ -57,11 +57,7 @@ export function useEventHandlers( { clientId, isSelected } ) {
57
57
  event.preventDefault();
58
58
 
59
59
  if ( keyCode === ENTER ) {
60
- insertDefaultBlock(
61
- {},
62
- getBlockRootClientId( clientId ),
63
- getBlockIndex( clientId ) + 1
64
- );
60
+ insertAfterBlock( clientId );
65
61
  } else {
66
62
  removeBlock( clientId );
67
63
  }
@@ -90,7 +86,7 @@ export function useEventHandlers( { clientId, isSelected } ) {
90
86
  isSelected,
91
87
  getBlockRootClientId,
92
88
  getBlockIndex,
93
- insertDefaultBlock,
89
+ insertAfterBlock,
94
90
  removeBlock,
95
91
  ]
96
92
  );
@@ -39,8 +39,12 @@ const POPOVER_PROPS = {
39
39
  placement: 'bottom-start',
40
40
  };
41
41
 
42
- function CopyMenuItem( { blocks, onCopy, label } ) {
43
- const ref = useCopyToClipboard( () => serialize( blocks ), onCopy );
42
+ function CopyMenuItem( { clientIds, onCopy, label } ) {
43
+ const { getBlocksByClientId } = useSelect( blockEditorStore );
44
+ const ref = useCopyToClipboard(
45
+ () => serialize( getBlocksByClientId( clientIds ) ),
46
+ onCopy
47
+ );
44
48
  const copyMenuItemLabel = label ? label : __( 'Copy' );
45
49
  return <MenuItem ref={ ref }>{ copyMenuItemLabel }</MenuItem>;
46
50
  }
@@ -239,7 +243,7 @@ export function BlockSettingsDropdown( {
239
243
  { ( {
240
244
  canCopyStyles,
241
245
  canDuplicate,
242
- canInsertDefaultBlock,
246
+ canInsertBlock,
243
247
  canMove,
244
248
  canRemove,
245
249
  onDuplicate,
@@ -249,7 +253,6 @@ export function BlockSettingsDropdown( {
249
253
  onCopy,
250
254
  onPasteStyles,
251
255
  onMoveTo,
252
- blocks,
253
256
  } ) => (
254
257
  <DropdownMenu
255
258
  icon={ moreVertical }
@@ -286,7 +289,7 @@ export function BlockSettingsDropdown( {
286
289
  'core/block-editor/insert-after',
287
290
  event
288
291
  ) &&
289
- canInsertDefaultBlock
292
+ canInsertBlock
290
293
  ) {
291
294
  event.preventDefault();
292
295
  setOpenedBlockSettingsMenu( undefined );
@@ -296,7 +299,7 @@ export function BlockSettingsDropdown( {
296
299
  'core/block-editor/insert-before',
297
300
  event
298
301
  ) &&
299
- canInsertDefaultBlock
302
+ canInsertBlock
300
303
  ) {
301
304
  event.preventDefault();
302
305
  setOpenedBlockSettingsMenu( undefined );
@@ -327,7 +330,7 @@ export function BlockSettingsDropdown( {
327
330
  />
328
331
  ) }
329
332
  <CopyMenuItem
330
- blocks={ blocks }
333
+ clientIds={ clientIds }
331
334
  onCopy={ onCopy }
332
335
  />
333
336
  { canDuplicate && (
@@ -342,7 +345,7 @@ export function BlockSettingsDropdown( {
342
345
  { __( 'Duplicate' ) }
343
346
  </MenuItem>
344
347
  ) }
345
- { canInsertDefaultBlock && (
348
+ { canInsertBlock && (
346
349
  <>
347
350
  <MenuItem
348
351
  onClick={ pipe(
@@ -368,7 +371,7 @@ export function BlockSettingsDropdown( {
368
371
  { canCopyStyles && (
369
372
  <MenuGroup>
370
373
  <CopyMenuItem
371
- blocks={ blocks }
374
+ clientIds={ clientIds }
372
375
  onCopy={ onCopy }
373
376
  label={ __( 'Copy styles' ) }
374
377
  />
@@ -35,6 +35,8 @@ import { store as blockEditorStore } from '../../store';
35
35
  import __unstableBlockNameContext from './block-name-context';
36
36
  import NavigableToolbar from '../navigable-toolbar';
37
37
  import { useHasAnyBlockControls } from '../block-controls/use-has-block-controls';
38
+ import BlockBindingsIndicator from '../block-bindings-toolbar-indicator';
39
+ import { canBindBlock } from '../../hooks/use-bindings-attributes';
38
40
 
39
41
  /**
40
42
  * Renders the block toolbar.
@@ -60,8 +62,10 @@ export function PrivateBlockToolbar( {
60
62
  blockClientIds,
61
63
  isDefaultEditingMode,
62
64
  blockType,
65
+ blockName,
63
66
  shouldShowVisualToolbar,
64
67
  showParentSelector,
68
+ isUsingBindings,
65
69
  } = useSelect( ( select ) => {
66
70
  const {
67
71
  getBlockName,
@@ -71,6 +75,7 @@ export function PrivateBlockToolbar( {
71
75
  isBlockValid,
72
76
  getBlockRootClientId,
73
77
  getBlockEditingMode,
78
+ getBlockAttributes,
74
79
  } = select( blockEditorStore );
75
80
  const selectedBlockClientIds = getSelectedBlockClientIds();
76
81
  const selectedBlockClientId = selectedBlockClientIds[ 0 ];
@@ -81,20 +86,21 @@ export function PrivateBlockToolbar( {
81
86
  const parentBlockType = getBlockType( parentBlockName );
82
87
  const _isDefaultEditingMode =
83
88
  getBlockEditingMode( selectedBlockClientId ) === 'default';
89
+ const _blockName = getBlockName( selectedBlockClientId );
84
90
  const isValid = selectedBlockClientIds.every( ( id ) =>
85
91
  isBlockValid( id )
86
92
  );
87
93
  const isVisual = selectedBlockClientIds.every(
88
94
  ( id ) => getBlockMode( id ) === 'visual'
89
95
  );
96
+ const _isUsingBindings = !! getBlockAttributes( selectedBlockClientId )
97
+ ?.metadata?.bindings;
90
98
  return {
91
99
  blockClientId: selectedBlockClientId,
92
100
  blockClientIds: selectedBlockClientIds,
93
101
  isDefaultEditingMode: _isDefaultEditingMode,
94
- blockType:
95
- selectedBlockClientId &&
96
- getBlockType( getBlockName( selectedBlockClientId ) ),
97
-
102
+ blockName: _blockName,
103
+ blockType: selectedBlockClientId && getBlockType( _blockName ),
98
104
  shouldShowVisualToolbar: isValid && isVisual,
99
105
  rootClientId: blockRootClientId,
100
106
  showParentSelector:
@@ -107,6 +113,7 @@ export function PrivateBlockToolbar( {
107
113
  ) &&
108
114
  selectedBlockClientIds.length === 1 &&
109
115
  _isDefaultEditingMode,
116
+ isUsingBindings: _isUsingBindings,
110
117
  };
111
118
  }, [] );
112
119
 
@@ -165,6 +172,9 @@ export function PrivateBlockToolbar( {
165
172
  { ! isMultiToolbar &&
166
173
  isLargeViewport &&
167
174
  isDefaultEditingMode && <BlockParentSelector /> }
175
+ { isUsingBindings && canBindBlock( blockName ) && (
176
+ <BlockBindingsIndicator />
177
+ ) }
168
178
  { ( shouldShowVisualToolbar || isMultiToolbar ) &&
169
179
  isDefaultEditingMode && (
170
180
  <div
@@ -14,7 +14,12 @@ import {
14
14
  Tooltip,
15
15
  } from '@wordpress/components';
16
16
  import { forwardRef } from '@wordpress/element';
17
- import { Icon, lockSmall as lock, pinSmall } from '@wordpress/icons';
17
+ import {
18
+ Icon,
19
+ connection,
20
+ lockSmall as lock,
21
+ pinSmall,
22
+ } from '@wordpress/icons';
18
23
  import { SPACE, ENTER, BACKSPACE, DELETE } from '@wordpress/keycodes';
19
24
  import { useSelect, useDispatch } from '@wordpress/data';
20
25
  import { __unstableUseShortcutEventMatch as useShortcutEventMatch } from '@wordpress/keyboard-shortcuts';
@@ -32,11 +37,12 @@ import { useBlockLock } from '../block-lock';
32
37
  import { store as blockEditorStore } from '../../store';
33
38
  import useListViewImages from './use-list-view-images';
34
39
  import { useListViewContext } from './context';
40
+ import { canBindBlock } from '../../hooks/use-bindings-attributes';
35
41
 
36
42
  function ListViewBlockSelectButton(
37
43
  {
38
44
  className,
39
- block: { clientId },
45
+ block: { clientId, name: blockName },
40
46
  onClick,
41
47
  onContextMenu,
42
48
  onMouseDown,
@@ -66,6 +72,7 @@ function ListViewBlockSelectButton(
66
72
  getBlockRootClientId,
67
73
  getBlockOrder,
68
74
  getBlocksByClientId,
75
+ getBlockAttributes,
69
76
  canRemoveBlocks,
70
77
  } = useSelect( blockEditorStore );
71
78
  const { duplicateBlocks, multiSelect, removeBlocks } =
@@ -75,6 +82,8 @@ function ListViewBlockSelectButton(
75
82
  const images = useListViewImages( { clientId, isExpanded } );
76
83
  const { rootClientId } = useListViewContext();
77
84
 
85
+ const isConnected = getBlockAttributes( clientId )?.metadata?.bindings;
86
+
78
87
  const positionLabel = blockInformation?.positionLabel
79
88
  ? sprintf(
80
89
  // translators: 1: Position of selected block, e.g. "Sticky" or "Fixed".
@@ -278,6 +287,11 @@ function ListViewBlockSelectButton(
278
287
  </Truncate>
279
288
  </span>
280
289
  ) }
290
+ { isConnected && canBindBlock( blockName ) && (
291
+ <span className="block-editor-list-view-block-select-button__bindings">
292
+ <Icon icon={ connection } />
293
+ </span>
294
+ ) }
281
295
  { positionLabel && isSticky && (
282
296
  <Tooltip text={ positionLabel }>
283
297
  <Icon icon={ pinSmall } />
@@ -557,3 +557,11 @@ $block-navigation-max-indent: 8;
557
557
  .list-view-appender__description {
558
558
  display: none;
559
559
  }
560
+
561
+ .block-editor-list-view-block-select-button__bindings svg g {
562
+ stroke: var(--wp-bound-block-color);
563
+ fill: transparent;
564
+ stroke-width: 1.5;
565
+ stroke-linecap: round;
566
+ stroke-linejoin: round;
567
+ }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { useDispatch, useSelect } from '@wordpress/data';
4
+ import { useDispatch, useRegistry, useSelect } from '@wordpress/data';
5
5
  import { useRefEffect } from '@wordpress/compose';
6
6
 
7
7
  /**
@@ -15,6 +15,7 @@ import { getPasteBlocks, setClipboardBlocks } from '../writing-flow/utils';
15
15
  // This hook borrows from useClipboardHandler in ../writing-flow/use-clipboard-handler.js
16
16
  // and adds behaviour for the list view, while skipping partial selection.
17
17
  export default function useClipboardHandler( { selectBlock } ) {
18
+ const registry = useRegistry();
18
19
  const {
19
20
  getBlockOrder,
20
21
  getBlockRootClientId,
@@ -106,7 +107,7 @@ export default function useClipboardHandler( { selectBlock } ) {
106
107
 
107
108
  notifyCopy( event.type, selectedBlockClientIds );
108
109
  const blocks = getBlocksByClientId( selectedBlockClientIds );
109
- setClipboardBlocks( event, blocks );
110
+ setClipboardBlocks( event, blocks, registry );
110
111
  }
111
112
 
112
113
  if ( event.type === 'cut' ) {
@@ -47,7 +47,7 @@ import { getAllowedFormats } from './utils';
47
47
  import { Content } from './content';
48
48
  import { withDeprecations } from './with-deprecations';
49
49
  import { unlock } from '../../lock-unlock';
50
- import { BLOCK_BINDINGS_ALLOWED_BLOCKS } from '../../hooks/use-bindings-attributes';
50
+ import { canBindBlock } from '../../hooks/use-bindings-attributes';
51
51
 
52
52
  export const keyboardShortcutContext = createContext();
53
53
  export const inputEventContext = createContext();
@@ -161,7 +161,7 @@ export function RichTextWrapper(
161
161
  ( select ) => {
162
162
  // Disable Rich Text editing if block bindings specify that.
163
163
  let _disableBoundBlocks = false;
164
- if ( blockBindings && blockName in BLOCK_BINDINGS_ALLOWED_BLOCKS ) {
164
+ if ( blockBindings && canBindBlock( blockName ) ) {
165
165
  const blockTypeAttributes =
166
166
  getBlockType( blockName ).attributes;
167
167
  const { getBlockBindingsSource } = unlock(
@@ -92,12 +92,12 @@ const URLPopover = forwardRef(
92
92
  />
93
93
  ) }
94
94
  </div>
95
- { showSettings && (
96
- <div className="block-editor-url-popover__row block-editor-url-popover__settings">
97
- { renderSettings() }
98
- </div>
99
- ) }
100
95
  </div>
96
+ { showSettings && (
97
+ <div className="block-editor-url-popover__settings">
98
+ { renderSettings() }
99
+ </div>
100
+ ) }
101
101
  { additionalControls && ! showSettings && (
102
102
  <div className="block-editor-url-popover__additional-controls">
103
103
  { additionalControls }