@wordpress/block-editor 15.9.0 → 15.9.1-next.6deb34194.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 (144) hide show
  1. package/README.md +12 -0
  2. package/build/components/block-alignment-matrix-control/index.js +1 -8
  3. package/build/components/block-alignment-matrix-control/index.js.map +2 -2
  4. package/build/components/block-bindings/attribute-control.js +172 -0
  5. package/build/components/block-bindings/attribute-control.js.map +7 -0
  6. package/build/components/block-bindings/index.js +47 -0
  7. package/build/components/block-bindings/index.js.map +7 -0
  8. package/build/components/block-bindings/source-fields-list.js +135 -0
  9. package/build/components/block-bindings/source-fields-list.js.map +7 -0
  10. package/build/components/block-bindings/use-block-bindings-utils.js +66 -0
  11. package/build/components/block-bindings/use-block-bindings-utils.js.map +7 -0
  12. package/build/components/block-edit/edit.js +1 -3
  13. package/build/components/block-edit/edit.js.map +2 -2
  14. package/build/components/block-styles/preview-panel.js +3 -5
  15. package/build/components/block-styles/preview-panel.js.map +2 -2
  16. package/build/components/block-styles/use-styles-for-block.js +2 -2
  17. package/build/components/block-styles/use-styles-for-block.js.map +2 -2
  18. package/build/components/block-toolbar/index.js +1 -8
  19. package/build/components/block-toolbar/index.js.map +3 -3
  20. package/build/components/content-only-controls/index.js +2 -25
  21. package/build/components/content-only-controls/index.js.map +2 -2
  22. package/build/components/content-only-controls/link/index.js +3 -3
  23. package/build/components/content-only-controls/link/index.js.map +2 -2
  24. package/build/components/content-only-controls/media/index.js +3 -3
  25. package/build/components/content-only-controls/media/index.js.map +2 -2
  26. package/build/components/content-only-controls/rich-text/index.js +3 -2
  27. package/build/components/content-only-controls/rich-text/index.js.map +2 -2
  28. package/build/components/dimensions-tool/width-height-tool.js +4 -16
  29. package/build/components/dimensions-tool/width-height-tool.js.map +3 -3
  30. package/build/components/image-editor/cropper.js +3 -34
  31. package/build/components/image-editor/cropper.js.map +3 -3
  32. package/build/components/image-editor/index.js +9 -3
  33. package/build/components/image-editor/index.js.map +2 -2
  34. package/build/components/image-editor/use-transform-image.js +62 -32
  35. package/build/components/image-editor/use-transform-image.js.map +2 -2
  36. package/build/components/image-editor/zoom-dropdown.js +2 -2
  37. package/build/components/image-editor/zoom-dropdown.js.map +2 -2
  38. package/build/components/index.js +10 -3
  39. package/build/components/index.js.map +2 -2
  40. package/build/components/inserter-draggable-blocks/index.js +8 -4
  41. package/build/components/inserter-draggable-blocks/index.js.map +2 -2
  42. package/build/components/inspector-controls-tabs/content-tab.js +3 -2
  43. package/build/components/inspector-controls-tabs/content-tab.js.map +2 -2
  44. package/build/components/tool-selector/index.js +46 -0
  45. package/build/components/tool-selector/index.js.map +7 -0
  46. package/build/hooks/block-bindings.js +22 -260
  47. package/build/hooks/block-bindings.js.map +3 -3
  48. package/build/layouts/grid.js +23 -28
  49. package/build/layouts/grid.js.map +2 -2
  50. package/build/utils/block-bindings.js +2 -44
  51. package/build/utils/block-bindings.js.map +3 -3
  52. package/build/utils/index.js +2 -5
  53. package/build/utils/index.js.map +2 -2
  54. package/build-module/components/block-alignment-matrix-control/index.js +1 -8
  55. package/build-module/components/block-alignment-matrix-control/index.js.map +2 -2
  56. package/build-module/components/block-bindings/attribute-control.js +150 -0
  57. package/build-module/components/block-bindings/attribute-control.js.map +7 -0
  58. package/build-module/components/block-bindings/index.js +10 -0
  59. package/build-module/components/block-bindings/index.js.map +7 -0
  60. package/build-module/components/block-bindings/source-fields-list.js +104 -0
  61. package/build-module/components/block-bindings/source-fields-list.js.map +7 -0
  62. package/build-module/components/block-bindings/use-block-bindings-utils.js +45 -0
  63. package/build-module/components/block-bindings/use-block-bindings-utils.js.map +7 -0
  64. package/build-module/components/block-edit/edit.js +1 -3
  65. package/build-module/components/block-edit/edit.js.map +2 -2
  66. package/build-module/components/block-styles/preview-panel.js +3 -5
  67. package/build-module/components/block-styles/preview-panel.js.map +2 -2
  68. package/build-module/components/block-styles/use-styles-for-block.js +2 -2
  69. package/build-module/components/block-styles/use-styles-for-block.js.map +2 -2
  70. package/build-module/components/block-toolbar/index.js +1 -8
  71. package/build-module/components/block-toolbar/index.js.map +2 -2
  72. package/build-module/components/content-only-controls/index.js +2 -25
  73. package/build-module/components/content-only-controls/index.js.map +2 -2
  74. package/build-module/components/content-only-controls/link/index.js +3 -3
  75. package/build-module/components/content-only-controls/link/index.js.map +2 -2
  76. package/build-module/components/content-only-controls/media/index.js +3 -3
  77. package/build-module/components/content-only-controls/media/index.js.map +2 -2
  78. package/build-module/components/content-only-controls/rich-text/index.js +3 -2
  79. package/build-module/components/content-only-controls/rich-text/index.js.map +2 -2
  80. package/build-module/components/dimensions-tool/width-height-tool.js +4 -6
  81. package/build-module/components/dimensions-tool/width-height-tool.js.map +2 -2
  82. package/build-module/components/image-editor/cropper.js +3 -34
  83. package/build-module/components/image-editor/cropper.js.map +2 -2
  84. package/build-module/components/image-editor/index.js +9 -3
  85. package/build-module/components/image-editor/index.js.map +2 -2
  86. package/build-module/components/image-editor/use-transform-image.js +63 -33
  87. package/build-module/components/image-editor/use-transform-image.js.map +2 -2
  88. package/build-module/components/image-editor/zoom-dropdown.js +2 -2
  89. package/build-module/components/image-editor/zoom-dropdown.js.map +2 -2
  90. package/build-module/components/index.js +74 -66
  91. package/build-module/components/index.js.map +2 -2
  92. package/build-module/components/inserter-draggable-blocks/index.js +8 -4
  93. package/build-module/components/inserter-draggable-blocks/index.js.map +2 -2
  94. package/build-module/components/inspector-controls-tabs/content-tab.js +3 -2
  95. package/build-module/components/inspector-controls-tabs/content-tab.js.map +2 -2
  96. package/build-module/components/tool-selector/index.js +15 -0
  97. package/build-module/components/tool-selector/index.js.map +7 -0
  98. package/build-module/hooks/block-bindings.js +27 -270
  99. package/build-module/hooks/block-bindings.js.map +2 -2
  100. package/build-module/layouts/grid.js +23 -28
  101. package/build-module/layouts/grid.js.map +2 -2
  102. package/build-module/utils/block-bindings.js +1 -42
  103. package/build-module/utils/block-bindings.js.map +2 -2
  104. package/build-module/utils/index.js +1 -3
  105. package/build-module/utils/index.js.map +2 -2
  106. package/build-style/style-rtl.css +6 -6
  107. package/build-style/style.css +6 -6
  108. package/package.json +39 -40
  109. package/src/components/block-alignment-matrix-control/index.js +1 -5
  110. package/src/components/block-bindings/attribute-control.js +174 -0
  111. package/src/components/block-bindings/index.js +6 -0
  112. package/src/components/block-bindings/source-fields-list.js +130 -0
  113. package/src/components/block-bindings/use-block-bindings-utils.js +156 -0
  114. package/src/components/block-edit/edit.js +1 -3
  115. package/src/components/block-styles/preview-panel.js +3 -5
  116. package/src/components/block-styles/use-styles-for-block.js +2 -2
  117. package/src/components/block-toolbar/index.js +1 -6
  118. package/src/components/block-toolbar/style.scss +6 -6
  119. package/src/components/content-only-controls/index.js +2 -27
  120. package/src/components/content-only-controls/link/index.js +3 -3
  121. package/src/components/content-only-controls/media/index.js +3 -3
  122. package/src/components/content-only-controls/rich-text/index.js +3 -2
  123. package/src/components/dimensions-tool/width-height-tool.js +6 -13
  124. package/src/components/image-editor/cropper.js +3 -32
  125. package/src/components/image-editor/index.js +34 -29
  126. package/src/components/image-editor/use-transform-image.js +80 -34
  127. package/src/components/image-editor/zoom-dropdown.js +2 -2
  128. package/src/components/index.js +9 -1
  129. package/src/components/inserter/style.scss +1 -1
  130. package/src/components/inserter-draggable-blocks/index.js +19 -8
  131. package/src/components/inspector-controls-tabs/content-tab.js +6 -2
  132. package/src/components/tool-selector/index.js +19 -0
  133. package/src/hooks/block-bindings.js +27 -347
  134. package/src/layouts/grid.js +40 -72
  135. package/src/layouts/test/grid.js +14 -0
  136. package/src/utils/block-bindings.js +0 -157
  137. package/src/utils/index.js +0 -1
  138. package/tsconfig.json +1 -0
  139. package/build/components/block-toolbar/block-name-context.js +0 -30
  140. package/build/components/block-toolbar/block-name-context.js.map +0 -7
  141. package/build-module/components/block-toolbar/block-name-context.js +0 -9
  142. package/build-module/components/block-toolbar/block-name-context.js.map +0 -7
  143. package/src/components/block-toolbar/block-name-context.js +0 -9
  144. /package/src/{utils → components/block-bindings}/test/use-block-bindings-utils.js +0 -0
@@ -0,0 +1,174 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import fastDeepEqual from 'fast-deep-equal/es6';
5
+
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import { __ } from '@wordpress/i18n';
10
+ import {
11
+ getBlockBindingsSource,
12
+ store as blocksStore,
13
+ } from '@wordpress/blocks';
14
+ import {
15
+ __experimentalItem as Item,
16
+ __experimentalText as Text,
17
+ __experimentalToolsPanelItem as ToolsPanelItem,
18
+ __experimentalVStack as VStack,
19
+ privateApis as componentsPrivateApis,
20
+ } from '@wordpress/components';
21
+ import { useSelect } from '@wordpress/data';
22
+ import { useContext } from '@wordpress/element';
23
+ import { useViewportMatch } from '@wordpress/compose';
24
+
25
+ /**
26
+ * Internal dependencies
27
+ */
28
+ import BlockContext from '../block-context';
29
+ import BlockBindingsSourceFieldsList from './source-fields-list';
30
+ import useBlockBindingsUtils from './use-block-bindings-utils';
31
+ import { unlock } from '../../lock-unlock';
32
+ import { store as blockEditorStore } from '../../store';
33
+
34
+ const { Menu } = unlock( componentsPrivateApis );
35
+
36
+ export default function BlockBindingsAttributeControl( {
37
+ attribute,
38
+ binding,
39
+ blockName,
40
+ } ) {
41
+ const { updateBlockBindings } = useBlockBindingsUtils();
42
+ const isMobile = useViewportMatch( 'medium', '<' );
43
+
44
+ const blockContext = useContext( BlockContext );
45
+ const compatibleFields = useSelect(
46
+ ( select ) => {
47
+ const {
48
+ getAllBlockBindingsSources,
49
+ getBlockBindingsSourceFieldsList,
50
+ getBlockType,
51
+ } = unlock( select( blocksStore ) );
52
+
53
+ const _attributeType =
54
+ getBlockType( blockName ).attributes?.[ attribute ]?.type;
55
+ const attributeType =
56
+ _attributeType === 'rich-text' ? 'string' : _attributeType;
57
+
58
+ const sourceFields = {};
59
+ Object.entries( getAllBlockBindingsSources() ).forEach(
60
+ ( [ sourceName, source ] ) => {
61
+ const fieldsList = getBlockBindingsSourceFieldsList(
62
+ source,
63
+ blockContext
64
+ );
65
+ if ( ! fieldsList?.length ) {
66
+ return;
67
+ }
68
+ const compatibleFieldsList = fieldsList.filter(
69
+ ( field ) => field.type === attributeType
70
+ );
71
+ if ( compatibleFieldsList.length ) {
72
+ sourceFields[ sourceName ] = compatibleFieldsList;
73
+ }
74
+ }
75
+ );
76
+ return sourceFields;
77
+ },
78
+ [ attribute, blockName, blockContext ]
79
+ );
80
+
81
+ const { canUpdateBlockBindings } = useSelect( ( select ) => ( {
82
+ canUpdateBlockBindings:
83
+ select( blockEditorStore ).getSettings().canUpdateBlockBindings,
84
+ } ) );
85
+
86
+ const hasCompatibleFields = Object.keys( compatibleFields ).length > 0;
87
+
88
+ // Lock the UI when the user can't update bindings or there are no fields to connect to.
89
+ const isAttributeReadOnly =
90
+ ! canUpdateBlockBindings || ! hasCompatibleFields;
91
+
92
+ const { source: boundSourceName, args } = binding || {};
93
+ const source = getBlockBindingsSource( boundSourceName );
94
+
95
+ let displayText;
96
+ let isValid = true;
97
+
98
+ if ( binding === undefined ) {
99
+ if ( ! hasCompatibleFields ) {
100
+ displayText = __( 'No sources available' );
101
+ } else {
102
+ displayText = __( 'Not connected' );
103
+ }
104
+ isValid = true;
105
+ } else if ( ! source ) {
106
+ // If there's a binding but the source is not found, it's invalid.
107
+ isValid = false;
108
+ displayText = __( 'Source not registered' );
109
+ } else {
110
+ displayText =
111
+ compatibleFields?.[ boundSourceName ]?.find( ( field ) =>
112
+ fastDeepEqual( field.args, args )
113
+ )?.label ||
114
+ source?.label ||
115
+ boundSourceName;
116
+ }
117
+
118
+ return (
119
+ <ToolsPanelItem
120
+ hasValue={ () => !! binding }
121
+ label={ attribute }
122
+ onDeselect={
123
+ !! hasCompatibleFields &&
124
+ ( () => {
125
+ updateBlockBindings( {
126
+ [ attribute ]: undefined,
127
+ } );
128
+ } )
129
+ }
130
+ >
131
+ <Menu placement={ isMobile ? 'bottom-start' : 'left-start' }>
132
+ <Menu.TriggerButton
133
+ render={ <Item /> }
134
+ disabled={ ! hasCompatibleFields }
135
+ >
136
+ <VStack
137
+ className="block-editor-bindings__item"
138
+ spacing={ 0 }
139
+ >
140
+ <Text truncate>{ attribute }</Text>
141
+ <Text
142
+ truncate
143
+ variant={ isValid ? 'muted' : undefined }
144
+ isDestructive={ ! isValid }
145
+ >
146
+ { displayText }
147
+ </Text>
148
+ </VStack>
149
+ </Menu.TriggerButton>
150
+ { ! isAttributeReadOnly && (
151
+ <Menu.Popover gutter={ isMobile ? 8 : 36 }>
152
+ <Menu
153
+ placement={
154
+ isMobile ? 'bottom-start' : 'left-start'
155
+ }
156
+ >
157
+ { Object.entries( compatibleFields ).map(
158
+ ( [ sourceKey, fields ] ) => (
159
+ <BlockBindingsSourceFieldsList
160
+ key={ sourceKey }
161
+ args={ binding?.args }
162
+ attribute={ attribute }
163
+ sourceKey={ sourceKey }
164
+ fields={ fields }
165
+ />
166
+ )
167
+ ) }
168
+ </Menu>
169
+ </Menu.Popover>
170
+ ) }
171
+ </Menu>
172
+ </ToolsPanelItem>
173
+ );
174
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ export { default as BlockBindingsAttributeControl } from './attribute-control';
5
+ export { default as BlockBindingsSourceFieldsList } from './source-fields-list';
6
+ export { default as useBlockBindingsUtils } from './use-block-bindings-utils';
@@ -0,0 +1,130 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import fastDeepEqual from 'fast-deep-equal/es6';
5
+
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import { getBlockBindingsSource } from '@wordpress/blocks';
10
+ import { privateApis as componentsPrivateApis } from '@wordpress/components';
11
+ import { useSelect } from '@wordpress/data';
12
+ import { useContext, useMemo } from '@wordpress/element';
13
+ import { useViewportMatch } from '@wordpress/compose';
14
+
15
+ /**
16
+ * Internal dependencies
17
+ */
18
+ import useBlockBindingsUtils from './use-block-bindings-utils';
19
+ import { unlock } from '../../lock-unlock';
20
+ import BlockContext from '../block-context';
21
+
22
+ const { Menu } = unlock( componentsPrivateApis );
23
+
24
+ function BlockBindingsSourceFieldsListItem( {
25
+ args,
26
+ attribute,
27
+ field,
28
+ source,
29
+ sourceKey,
30
+ } ) {
31
+ const itemBindings = useMemo(
32
+ () => ( {
33
+ source: sourceKey,
34
+ args: field.args || {
35
+ key: field.key,
36
+ },
37
+ } ),
38
+ [ field.args, field.key, sourceKey ]
39
+ );
40
+
41
+ const blockContext = useContext( BlockContext );
42
+ const values = useSelect(
43
+ ( select ) =>
44
+ source.getValues( {
45
+ select,
46
+ context: blockContext,
47
+ bindings: {
48
+ [ attribute ]: itemBindings,
49
+ },
50
+ } ),
51
+ [ attribute, blockContext, itemBindings, source ]
52
+ );
53
+ const { updateBlockBindings } = useBlockBindingsUtils();
54
+
55
+ return (
56
+ <Menu.CheckboxItem
57
+ onChange={ () => {
58
+ const isCurrentlySelected =
59
+ fastDeepEqual( args, field.args ) ??
60
+ // Deprecate key dependency in 7.0.
61
+ field.key === args?.key;
62
+
63
+ if ( isCurrentlySelected ) {
64
+ // Unset if the same field is selected again.
65
+ updateBlockBindings( {
66
+ [ attribute ]: undefined,
67
+ } );
68
+ } else {
69
+ updateBlockBindings( {
70
+ [ attribute ]: itemBindings,
71
+ } );
72
+ }
73
+ } }
74
+ name={ attribute + '-binding' }
75
+ value={ values[ attribute ] }
76
+ checked={
77
+ fastDeepEqual( args, field.args ) ??
78
+ // Deprecate key dependency in 7.0.
79
+ field.key === args?.key
80
+ }
81
+ >
82
+ <Menu.ItemLabel>{ field.label }</Menu.ItemLabel>
83
+ <Menu.ItemHelpText>{ values[ attribute ] }</Menu.ItemHelpText>
84
+ </Menu.CheckboxItem>
85
+ );
86
+ }
87
+
88
+ export default function BlockBindingsSourceFieldsList( {
89
+ args,
90
+ attribute,
91
+ sourceKey,
92
+ fields,
93
+ } ) {
94
+ const isMobile = useViewportMatch( 'medium', '<' );
95
+
96
+ // Only render source if it has compatible fields.
97
+ if ( ! fields || fields.length === 0 ) {
98
+ return null;
99
+ }
100
+
101
+ const source = getBlockBindingsSource( sourceKey );
102
+
103
+ return (
104
+ <Menu
105
+ key={ sourceKey }
106
+ placement={ isMobile ? 'bottom-start' : 'left-start' }
107
+ >
108
+ <Menu.SubmenuTriggerItem>
109
+ <Menu.ItemLabel>{ source.label }</Menu.ItemLabel>
110
+ </Menu.SubmenuTriggerItem>
111
+ <Menu.Popover gutter={ 8 }>
112
+ <Menu.Group>
113
+ { fields.map( ( field ) => (
114
+ <BlockBindingsSourceFieldsListItem
115
+ key={
116
+ sourceKey + JSON.stringify( field.args ) ||
117
+ field.key
118
+ }
119
+ args={ args }
120
+ attribute={ attribute }
121
+ field={ field }
122
+ source={ source }
123
+ sourceKey={ sourceKey }
124
+ />
125
+ ) ) }
126
+ </Menu.Group>
127
+ </Menu.Popover>
128
+ </Menu>
129
+ );
130
+ }
@@ -0,0 +1,156 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useDispatch, useRegistry } from '@wordpress/data';
5
+
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import { store as blockEditorStore } from '../../store';
10
+ import { useBlockEditContext } from '../block-edit';
11
+
12
+ /**
13
+ * Checks if the given object is empty.
14
+ *
15
+ * @param {?Object} object The object to check.
16
+ *
17
+ * @return {boolean} Whether the object is empty.
18
+ */
19
+ function isObjectEmpty( object ) {
20
+ return ! object || Object.keys( object ).length === 0;
21
+ }
22
+
23
+ /**
24
+ * Contains utils to update the block `bindings` metadata.
25
+ *
26
+ * @typedef {Object} WPBlockBindingsUtils
27
+ *
28
+ * @property {Function} updateBlockBindings Updates the value of the bindings connected to block attributes.
29
+ * @property {Function} removeAllBlockBindings Removes the bindings property of the `metadata` attribute.
30
+ */
31
+
32
+ /**
33
+ * Retrieves the existing utils needed to update the block `bindings` metadata.
34
+ * They can be used to create, modify, or remove connections from the existing block attributes.
35
+ *
36
+ * It contains the following utils:
37
+ * - `updateBlockBindings`: Updates the value of the bindings connected to block attributes. It can be used to remove a specific binding by setting the value to `undefined`.
38
+ * - `removeAllBlockBindings`: Removes the bindings property of the `metadata` attribute.
39
+ *
40
+ * @since 6.7.0 Introduced in WordPress core.
41
+ *
42
+ * @param {?string} clientId Optional block client ID. If not set, it will use the current block client ID from the context.
43
+ *
44
+ * @return {?WPBlockBindingsUtils} Object containing the block bindings utils.
45
+ *
46
+ * @example
47
+ * ```js
48
+ * import { useBlockBindingsUtils } from '@wordpress/block-editor'
49
+ * const { updateBlockBindings, removeAllBlockBindings } = useBlockBindingsUtils();
50
+ *
51
+ * // Update url and alt attributes.
52
+ * updateBlockBindings( {
53
+ * url: {
54
+ * source: 'core/post-meta',
55
+ * args: {
56
+ * key: 'url_custom_field',
57
+ * },
58
+ * },
59
+ * alt: {
60
+ * source: 'core/post-meta',
61
+ * args: {
62
+ * key: 'text_custom_field',
63
+ * },
64
+ * },
65
+ * } );
66
+ *
67
+ * // Remove binding from url attribute.
68
+ * updateBlockBindings( { url: undefined } );
69
+ *
70
+ * // Remove bindings from all attributes.
71
+ * removeAllBlockBindings();
72
+ * ```
73
+ */
74
+ export default function useBlockBindingsUtils( clientId ) {
75
+ const { clientId: contextClientId } = useBlockEditContext();
76
+ const blockClientId = clientId || contextClientId;
77
+ const { updateBlockAttributes } = useDispatch( blockEditorStore );
78
+ const { getBlockAttributes } = useRegistry().select( blockEditorStore );
79
+
80
+ /**
81
+ * Updates the value of the bindings connected to block attributes.
82
+ * It removes the binding when the new value is `undefined`.
83
+ *
84
+ * @param {Object} bindings Bindings including the attributes to update and the new object.
85
+ * @param {string} bindings.source The source name to connect to.
86
+ * @param {Object} [bindings.args] Object containing the arguments needed by the source.
87
+ *
88
+ * @example
89
+ * ```js
90
+ * import { useBlockBindingsUtils } from '@wordpress/block-editor'
91
+ *
92
+ * const { updateBlockBindings } = useBlockBindingsUtils();
93
+ * updateBlockBindings( {
94
+ * url: {
95
+ * source: 'core/post-meta',
96
+ * args: {
97
+ * key: 'url_custom_field',
98
+ * },
99
+ * },
100
+ * alt: {
101
+ * source: 'core/post-meta',
102
+ * args: {
103
+ * key: 'text_custom_field',
104
+ * },
105
+ * }
106
+ * } );
107
+ * ```
108
+ */
109
+ const updateBlockBindings = ( bindings ) => {
110
+ const { metadata: { bindings: currentBindings, ...metadata } = {} } =
111
+ getBlockAttributes( blockClientId );
112
+ const newBindings = { ...currentBindings };
113
+
114
+ Object.entries( bindings ).forEach( ( [ attribute, binding ] ) => {
115
+ if ( ! binding && newBindings[ attribute ] ) {
116
+ delete newBindings[ attribute ];
117
+ return;
118
+ }
119
+ newBindings[ attribute ] = binding;
120
+ } );
121
+
122
+ const newMetadata = {
123
+ ...metadata,
124
+ bindings: newBindings,
125
+ };
126
+
127
+ if ( isObjectEmpty( newMetadata.bindings ) ) {
128
+ delete newMetadata.bindings;
129
+ }
130
+
131
+ updateBlockAttributes( blockClientId, {
132
+ metadata: isObjectEmpty( newMetadata ) ? undefined : newMetadata,
133
+ } );
134
+ };
135
+
136
+ /**
137
+ * Removes the bindings property of the `metadata` attribute.
138
+ *
139
+ * @example
140
+ * ```js
141
+ * import { useBlockBindingsUtils } from '@wordpress/block-editor'
142
+ *
143
+ * const { removeAllBlockBindings } = useBlockBindingsUtils();
144
+ * removeAllBlockBindings();
145
+ * ```
146
+ */
147
+ const removeAllBlockBindings = () => {
148
+ const { metadata: { bindings, ...metadata } = {} } =
149
+ getBlockAttributes( blockClientId );
150
+ updateBlockAttributes( blockClientId, {
151
+ metadata: isObjectEmpty( metadata ) ? undefined : metadata,
152
+ } );
153
+ };
154
+
155
+ return { updateBlockBindings, removeAllBlockBindings };
156
+ }
@@ -100,10 +100,10 @@ const EditWithGeneratedProps = ( props ) => {
100
100
  ),
101
101
  };
102
102
  }, [
103
- name,
104
103
  blockType?.usesContext,
105
104
  blockContext,
106
105
  attributes?.metadata?.bindings,
106
+ bindableAttributes,
107
107
  registeredSources,
108
108
  ] );
109
109
 
@@ -180,7 +180,6 @@ const EditWithGeneratedProps = ( props ) => {
180
180
  blockBindings,
181
181
  clientId,
182
182
  context,
183
- name,
184
183
  registeredSources,
185
184
  ]
186
185
  );
@@ -262,7 +261,6 @@ const EditWithGeneratedProps = ( props ) => {
262
261
  hasPatternOverrides,
263
262
  setAttributes,
264
263
  registeredSources,
265
- name,
266
264
  registry,
267
265
  ]
268
266
  );
@@ -1,7 +1,6 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { getBlockType } from '@wordpress/blocks';
5
4
  import { useMemo } from '@wordpress/element';
6
5
 
7
6
  /**
@@ -16,11 +15,10 @@ export default function BlockStylesPreviewPanel( {
16
15
  className,
17
16
  activeStyle,
18
17
  } ) {
19
- const example = getBlockType( genericPreviewBlock.name )?.example;
20
18
  const styleClassName = replaceActiveStyle( className, activeStyle, style );
21
19
  const previewBlocks = useMemo( () => {
22
20
  return {
23
- ...genericPreviewBlock,
21
+ name: genericPreviewBlock.name,
24
22
  title: style.label || style.name,
25
23
  description: style.description,
26
24
  initialAttributes: {
@@ -29,9 +27,9 @@ export default function BlockStylesPreviewPanel( {
29
27
  styleClassName +
30
28
  ' block-editor-block-styles__block-preview-container',
31
29
  },
32
- example,
30
+ example: genericPreviewBlock,
33
31
  };
34
- }, [ genericPreviewBlock, styleClassName ] );
32
+ }, [ genericPreviewBlock, style, styleClassName ] );
35
33
 
36
34
  return <InserterPreviewPanel item={ previewBlocks } />;
37
35
  }
@@ -37,7 +37,7 @@ function useGenericPreviewBlock( block, type ) {
37
37
  if ( block ) {
38
38
  return cloneBlock( block );
39
39
  }
40
- }, [ type?.example ? block?.name : block, type ] );
40
+ }, [ block, type?.example, type?.name ] );
41
41
  }
42
42
 
43
43
  /**
@@ -63,7 +63,7 @@ export default function useStylesForBlocks( { clientId, onSwitch } ) {
63
63
  const { getBlockStyles } = select( blocksStore );
64
64
 
65
65
  return {
66
- block,
66
+ block: ! blockType?.example ? block : null,
67
67
  blockType,
68
68
  styles: getBlockStyles( block.name ),
69
69
  className: block.attributes.className || '',
@@ -32,7 +32,6 @@ import { BlockGroupToolbar } from '../convert-to-group-buttons';
32
32
  import BlockEditVisuallyButton from '../block-edit-visually-button';
33
33
  import { useShowHoveredOrFocusedGestures } from './utils';
34
34
  import { store as blockEditorStore } from '../../store';
35
- import __unstableBlockNameContext from './block-name-context';
36
35
  import NavigableToolbar from '../navigable-toolbar';
37
36
  import { useHasBlockToolbar } from './use-has-block-toolbar';
38
37
  import ChangeDesign from './change-design';
@@ -265,11 +264,7 @@ export function PrivateBlockToolbar( {
265
264
  group="other"
266
265
  className="block-editor-block-toolbar__slot"
267
266
  />
268
- <__unstableBlockNameContext.Provider
269
- value={ blockType?.name }
270
- >
271
- <__unstableBlockToolbarLastItem.Slot />
272
- </__unstableBlockNameContext.Provider>
267
+ <__unstableBlockToolbarLastItem.Slot />
273
268
  </>
274
269
  ) }
275
270
  <BlockEditVisuallyButton clientIds={ blockClientIds } />
@@ -193,6 +193,12 @@
193
193
  font-size: $helptext-font-size;
194
194
  }
195
195
  }
196
+
197
+ .block-editor-block-icon {
198
+ width: 0 !important;
199
+ height: 0 !important;
200
+ min-width: 0 !important;
201
+ }
196
202
  }
197
203
 
198
204
  // Padding overrides.
@@ -201,12 +207,6 @@
201
207
  padding-right: 6px;
202
208
  }
203
209
 
204
- .block-editor-block-icon {
205
- width: 0 !important;
206
- height: 0 !important;
207
- min-width: 0 !important;
208
- }
209
-
210
210
  // Parent selector overrides
211
211
  .block-editor-block-parent-selector .block-editor-block-parent-selector__button {
212
212
  border-top-right-radius: 0;
@@ -295,19 +295,13 @@ function BlockFields( { clientId } ) {
295
295
  field.Edit = createConfiguredControl( {
296
296
  control: fieldDef.type,
297
297
  clientId,
298
- updateBlockAttributes,
299
298
  fieldDef,
300
299
  } );
301
300
  }
302
301
 
303
302
  return field;
304
303
  } );
305
- }, [
306
- blockTypeFields,
307
- blockType?.attributes,
308
- clientId,
309
- updateBlockAttributes,
310
- ] );
304
+ }, [ blockTypeFields, blockType?.attributes, clientId ] );
311
305
 
312
306
  const handleToggleField = ( fieldId ) => {
313
307
  setForm( ( prev ) => {
@@ -351,26 +345,7 @@ function BlockFields( { clientId } ) {
351
345
  fields={ dataFormFields }
352
346
  form={ form }
353
347
  onChange={ ( changes ) => {
354
- // Map field values to block attributes using field.setValue
355
- const mappedChanges = {};
356
- Object.entries( changes ).forEach(
357
- ( [ fieldId, fieldValue ] ) => {
358
- const field = dataFormFields.find(
359
- ( f ) => f.id === fieldId
360
- );
361
- if ( field && field.setValue ) {
362
- const updates = field.setValue( {
363
- item: attributes,
364
- value: fieldValue,
365
- } );
366
- Object.assign( mappedChanges, updates );
367
- } else {
368
- // For fields without setValue, use the value directly
369
- mappedChanges[ fieldId ] = fieldValue;
370
- }
371
- }
372
- );
373
- updateBlockAttributes( clientId, mappedChanges );
348
+ updateBlockAttributes( clientId, changes );
374
349
  } }
375
350
  />
376
351
  </div>
@@ -67,15 +67,15 @@ export function getUpdatedLinkAttributes( {
67
67
  };
68
68
  }
69
69
 
70
- export default function Link( { data, field, config = {} } ) {
70
+ export default function Link( { data, field, onChange, config = {} } ) {
71
71
  const [ isLinkControlOpen, setIsLinkControlOpen ] = useState( false );
72
72
  const { popoverProps } = useInspectorPopoverPlacement( {
73
73
  isControl: true,
74
74
  } );
75
- const { clientId, updateBlockAttributes, fieldDef } = config;
75
+ const { fieldDef } = config;
76
76
  const updateAttributes = ( newValue ) => {
77
77
  const mappedChanges = field.setValue( { item: data, value: newValue } );
78
- updateBlockAttributes( clientId, mappedChanges );
78
+ onChange( mappedChanges );
79
79
  };
80
80
 
81
81
  const value = field.getValue( { item: data } );
@@ -83,19 +83,19 @@ function MediaThumbnail( { data, field, attachment } ) {
83
83
  return <Icon icon={ mediaIcon } size={ 24 } />;
84
84
  }
85
85
 
86
- export default function Media( { data, field, config = {} } ) {
86
+ export default function Media( { data, field, onChange, config = {} } ) {
87
87
  const { popoverProps } = useInspectorPopoverPlacement( {
88
88
  isControl: true,
89
89
  } );
90
90
  const value = field.getValue( { item: data } );
91
91
  const { allowedTypes = [], multiple = false } = field.config || {};
92
- const { clientId, updateBlockAttributes, fieldDef } = config;
92
+ const { fieldDef } = config;
93
93
  const updateAttributes = ( newFieldValue ) => {
94
94
  const mappedChanges = field.setValue( {
95
95
  item: data,
96
96
  value: newFieldValue,
97
97
  } );
98
- updateBlockAttributes( clientId, mappedChanges );
98
+ onChange( mappedChanges );
99
99
  };
100
100
 
101
101
  // Check if featured image is supported by checking if it's in the mapping