@wordpress/block-library 9.33.1-next.ff1cebbba.0 → 9.33.2-next.36001005c.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.
- package/CHANGELOG.md +1 -1
- package/README.md +1 -1
- package/build/breadcrumbs/block.json +8 -2
- package/build/breadcrumbs/edit.js +113 -12
- package/build/breadcrumbs/edit.js.map +2 -2
- package/build/buttons/transforms.js +7 -7
- package/build/buttons/transforms.js.map +2 -2
- package/build/code/transforms.js +19 -15
- package/build/code/transforms.js.map +2 -2
- package/build/heading/index.js +1 -3
- package/build/heading/index.js.map +3 -3
- package/build/heading/transforms.js +22 -20
- package/build/heading/transforms.js.map +2 -2
- package/build/index.js +5 -3
- package/build/index.js.map +2 -2
- package/build/math/block.json +21 -0
- package/build/math/edit.js +132 -0
- package/build/math/edit.js.map +7 -0
- package/build/math/index.js +63 -0
- package/build/math/index.js.map +7 -0
- package/build/math/init.js +35 -0
- package/build/math/init.js.map +7 -0
- package/build/math/save.js +40 -0
- package/build/math/save.js.map +7 -0
- package/build/navigation/edit/menu-inspector-controls.js +2 -2
- package/build/navigation/edit/menu-inspector-controls.js.map +2 -2
- package/build/navigation-link/edit.js +5 -2
- package/build/navigation-link/edit.js.map +2 -2
- package/build/navigation-link/link-ui/index.js +1 -1
- package/build/navigation-link/link-ui/index.js.map +2 -2
- package/build/navigation-link/shared/controls.js +39 -16
- package/build/navigation-link/shared/controls.js.map +3 -3
- package/build/navigation-link/shared/index.js +2 -0
- package/build/navigation-link/shared/index.js.map +2 -2
- package/build/navigation-link/shared/update-attributes.js +3 -1
- package/build/navigation-link/shared/update-attributes.js.map +2 -2
- package/build/navigation-link/shared/use-entity-binding.js +46 -13
- package/build/navigation-link/shared/use-entity-binding.js.map +2 -2
- package/build/navigation-submenu/edit.js +5 -2
- package/build/navigation-submenu/edit.js.map +2 -2
- package/build/page-list/use-convert-to-navigation-links.js +6 -1
- package/build/page-list/use-convert-to-navigation-links.js.map +2 -2
- package/build/paragraph/index.js +1 -3
- package/build/paragraph/index.js.map +3 -3
- package/build/post-date/deprecated.js +98 -2
- package/build/post-date/deprecated.js.map +2 -2
- package/build/post-date/edit.js +1 -1
- package/build/post-date/edit.js.map +1 -1
- package/build/post-date/variations.js +4 -4
- package/build/post-date/variations.js.map +2 -2
- package/build/term-template/block.json +0 -1
- package/build/term-template/edit.js +4 -1
- package/build/term-template/edit.js.map +2 -2
- package/build/terms-query/block.json +0 -1
- package/build/utils/get-transformed-attributes.js +82 -0
- package/build/utils/get-transformed-attributes.js.map +7 -0
- package/build-module/breadcrumbs/block.json +8 -2
- package/build-module/breadcrumbs/edit.js +117 -14
- package/build-module/breadcrumbs/edit.js.map +2 -2
- package/build-module/buttons/transforms.js +7 -7
- package/build-module/buttons/transforms.js.map +2 -2
- package/build-module/code/transforms.js +19 -15
- package/build-module/code/transforms.js.map +2 -2
- package/build-module/heading/index.js +1 -3
- package/build-module/heading/index.js.map +2 -2
- package/build-module/heading/transforms.js +22 -20
- package/build-module/heading/transforms.js.map +2 -2
- package/build-module/index.js +5 -3
- package/build-module/index.js.map +2 -2
- package/build-module/math/block.json +21 -0
- package/build-module/math/edit.js +110 -0
- package/build-module/math/edit.js.map +7 -0
- package/build-module/math/index.js +26 -0
- package/build-module/math/index.js.map +7 -0
- package/build-module/math/init.js +8 -0
- package/build-module/math/init.js.map +7 -0
- package/build-module/math/save.js +20 -0
- package/build-module/math/save.js.map +7 -0
- package/build-module/navigation/edit/menu-inspector-controls.js +2 -2
- package/build-module/navigation/edit/menu-inspector-controls.js.map +2 -2
- package/build-module/navigation-link/edit.js +5 -2
- package/build-module/navigation-link/edit.js.map +2 -2
- package/build-module/navigation-link/link-ui/index.js +1 -1
- package/build-module/navigation-link/link-ui/index.js.map +2 -2
- package/build-module/navigation-link/shared/controls.js +40 -17
- package/build-module/navigation-link/shared/controls.js.map +2 -2
- package/build-module/navigation-link/shared/index.js +5 -1
- package/build-module/navigation-link/shared/index.js.map +2 -2
- package/build-module/navigation-link/shared/update-attributes.js +3 -1
- package/build-module/navigation-link/shared/update-attributes.js.map +2 -2
- package/build-module/navigation-link/shared/use-entity-binding.js +45 -13
- package/build-module/navigation-link/shared/use-entity-binding.js.map +2 -2
- package/build-module/navigation-submenu/edit.js +5 -2
- package/build-module/navigation-submenu/edit.js.map +2 -2
- package/build-module/page-list/use-convert-to-navigation-links.js +6 -1
- package/build-module/page-list/use-convert-to-navigation-links.js.map +2 -2
- package/build-module/paragraph/index.js +1 -3
- package/build-module/paragraph/index.js.map +2 -2
- package/build-module/post-date/deprecated.js +98 -2
- package/build-module/post-date/deprecated.js.map +2 -2
- package/build-module/post-date/edit.js +1 -1
- package/build-module/post-date/edit.js.map +1 -1
- package/build-module/post-date/variations.js +4 -4
- package/build-module/post-date/variations.js.map +2 -2
- package/build-module/term-template/block.json +0 -1
- package/build-module/term-template/edit.js +4 -1
- package/build-module/term-template/edit.js.map +2 -2
- package/build-module/terms-query/block.json +0 -1
- package/build-module/utils/get-transformed-attributes.js +58 -0
- package/build-module/utils/get-transformed-attributes.js.map +7 -0
- package/build-style/editor-rtl.css +2 -2
- package/build-style/editor.css +2 -2
- package/build-style/navigation-link/editor-rtl.css +1 -1
- package/build-style/navigation-link/editor.css +1 -1
- package/build-style/video/editor-rtl.css +1 -1
- package/build-style/video/editor.css +1 -1
- package/package.json +61 -36
- package/src/breadcrumbs/block.json +8 -2
- package/src/breadcrumbs/edit.js +163 -18
- package/src/breadcrumbs/index.php +118 -16
- package/src/buttons/transforms.js +6 -6
- package/src/code/transforms.js +16 -14
- package/src/heading/index.js +0 -2
- package/src/heading/transforms.js +25 -24
- package/src/index.js +5 -3
- package/src/math/block.json +21 -0
- package/src/math/edit.js +123 -0
- package/src/math/index.js +31 -0
- package/src/math/init.js +4 -0
- package/src/math/save.js +20 -0
- package/src/navigation/edit/menu-inspector-controls.js +7 -6
- package/src/navigation-link/edit.js +5 -2
- package/src/navigation-link/editor.scss +1 -1
- package/src/navigation-link/index.php +4 -18
- package/src/navigation-link/link-ui/index.js +4 -2
- package/src/navigation-link/shared/controls.js +69 -20
- package/src/navigation-link/shared/index.js +4 -1
- package/src/navigation-link/shared/test/controls.js +14 -9
- package/src/navigation-link/shared/test/update-attributes.test.js +8 -0
- package/src/navigation-link/shared/test/use-entity-binding.js +132 -17
- package/src/navigation-link/shared/update-attributes.js +1 -0
- package/src/navigation-link/shared/use-entity-binding.js +74 -19
- package/src/navigation-submenu/edit.js +5 -2
- package/src/navigation-submenu/index.php +3 -17
- package/src/page-list/test/{convert-to-links-modal.js → convert-to-navigation-links.js} +67 -0
- package/src/page-list/use-convert-to-navigation-links.js +11 -1
- package/src/paragraph/index.js +0 -2
- package/src/post-date/deprecated.js +104 -2
- package/src/post-date/edit.js +1 -1
- package/src/post-date/index.php +3 -3
- package/src/post-date/variations.js +5 -4
- package/src/term-template/block.json +0 -1
- package/src/term-template/edit.js +4 -1
- package/src/term-template/index.php +4 -6
- package/src/terms-query/block.json +0 -1
- package/src/utils/get-transformed-attributes.js +98 -0
- package/src/video/editor.scss +1 -1
- package/tsconfig.json +1 -0
- package/build/heading/variations.js +0 -48
- package/build/heading/variations.js.map +0 -7
- package/build/paragraph/variations.js +0 -48
- package/build/paragraph/variations.js.map +0 -7
- package/build/utils/get-transformed-metadata.js +0 -65
- package/build/utils/get-transformed-metadata.js.map +0 -7
- package/build-module/heading/variations.js +0 -28
- package/build-module/heading/variations.js.map +0 -7
- package/build-module/paragraph/variations.js +0 -28
- package/build-module/paragraph/variations.js.map +0 -7
- package/build-module/utils/get-transformed-metadata.js +0 -41
- package/build-module/utils/get-transformed-metadata.js.map +0 -7
- package/src/heading/variations.js +0 -29
- package/src/paragraph/variations.js +0 -29
- package/src/utils/get-transformed-metadata.js +0 -69
|
@@ -202,20 +202,6 @@ function render_block_core_navigation_link( $attributes, $content, $block ) {
|
|
|
202
202
|
return '';
|
|
203
203
|
}
|
|
204
204
|
|
|
205
|
-
// Resolve URL binding if present
|
|
206
|
-
$url = $attributes['url'] ?? '';
|
|
207
|
-
if ( isset( $attributes['metadata']['bindings']['url']['source'] ) ) {
|
|
208
|
-
$binding = $attributes['metadata']['bindings']['url'];
|
|
209
|
-
$source = get_block_bindings_source( $binding['source'] );
|
|
210
|
-
if ( $source ) {
|
|
211
|
-
$source_args = $binding['args'] ?? array();
|
|
212
|
-
$resolved_url = $source->get_value( $source_args, $block, 'url' );
|
|
213
|
-
if ( $resolved_url ) {
|
|
214
|
-
$url = $resolved_url;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
205
|
$font_sizes = block_core_navigation_link_build_css_font_sizes( $block->context );
|
|
220
206
|
$classes = array_merge(
|
|
221
207
|
$font_sizes['css_classes']
|
|
@@ -227,9 +213,9 @@ function render_block_core_navigation_link( $attributes, $content, $block ) {
|
|
|
227
213
|
$kind = empty( $attributes['kind'] ) ? 'post_type' : str_replace( '-', '_', $attributes['kind'] );
|
|
228
214
|
$is_active = ! empty( $attributes['id'] ) && get_queried_object_id() === (int) $attributes['id'] && ! empty( get_queried_object()->$kind );
|
|
229
215
|
|
|
230
|
-
if ( is_post_type_archive() && ! empty( $url ) ) {
|
|
216
|
+
if ( is_post_type_archive() && ! empty( $attributes['url'] ) ) {
|
|
231
217
|
$queried_archive_link = get_post_type_archive_link( get_queried_object()->name );
|
|
232
|
-
if ( $url === $queried_archive_link ) {
|
|
218
|
+
if ( $attributes['url'] === $queried_archive_link ) {
|
|
233
219
|
$is_active = true;
|
|
234
220
|
}
|
|
235
221
|
}
|
|
@@ -245,8 +231,8 @@ function render_block_core_navigation_link( $attributes, $content, $block ) {
|
|
|
245
231
|
'<a class="wp-block-navigation-item__content" ';
|
|
246
232
|
|
|
247
233
|
// Start appending HTML attributes to anchor tag.
|
|
248
|
-
if (
|
|
249
|
-
$html .= ' href="' . esc_url( block_core_navigation_link_maybe_urldecode( $url ) ) . '"';
|
|
234
|
+
if ( isset( $attributes['url'] ) ) {
|
|
235
|
+
$html .= ' href="' . esc_url( block_core_navigation_link_maybe_urldecode( $attributes['url'] ) ) . '"';
|
|
250
236
|
}
|
|
251
237
|
|
|
252
238
|
if ( $is_active ) {
|
|
@@ -78,10 +78,12 @@ function UnforwardedLinkUI( props, ref ) {
|
|
|
78
78
|
name: postType,
|
|
79
79
|
} );
|
|
80
80
|
|
|
81
|
-
// Check if there's a URL binding with the
|
|
81
|
+
// Check if there's a URL binding with the new binding sources
|
|
82
82
|
// Only enable handleEntities when there's actually a binding present
|
|
83
83
|
const hasUrlBinding =
|
|
84
|
-
metadata?.bindings?.url?.source === 'core/
|
|
84
|
+
( metadata?.bindings?.url?.source === 'core/post-data' ||
|
|
85
|
+
metadata?.bindings?.url?.source === 'core/term-data' ) &&
|
|
86
|
+
!! id;
|
|
85
87
|
|
|
86
88
|
// Memoize link value to avoid overriding the LinkControl's internal state.
|
|
87
89
|
// This is a temporary fix. See https://github.com/WordPress/gutenberg/issues/50976#issuecomment-1568226407.
|
|
@@ -11,11 +11,13 @@ import {
|
|
|
11
11
|
TextareaControl,
|
|
12
12
|
} from '@wordpress/components';
|
|
13
13
|
import { __, sprintf } from '@wordpress/i18n';
|
|
14
|
-
import { useRef } from '@wordpress/element';
|
|
14
|
+
import { useRef, useEffect, useState } from '@wordpress/element';
|
|
15
15
|
import { useInstanceId } from '@wordpress/compose';
|
|
16
16
|
import { safeDecodeURI } from '@wordpress/url';
|
|
17
17
|
import { __unstableStripHTML as stripHTML } from '@wordpress/dom';
|
|
18
18
|
import { linkOff as unlinkIcon } from '@wordpress/icons';
|
|
19
|
+
import { useDispatch } from '@wordpress/data';
|
|
20
|
+
import { store as blockEditorStore } from '@wordpress/block-editor';
|
|
19
21
|
|
|
20
22
|
/**
|
|
21
23
|
* Internal dependencies
|
|
@@ -70,23 +72,55 @@ export function Controls( { attributes, setAttributes, clientId } ) {
|
|
|
70
72
|
const { label, url, description, rel, opensInNewTab } = attributes;
|
|
71
73
|
const lastURLRef = useRef( url );
|
|
72
74
|
const dropdownMenuProps = useToolsPanelDropdownMenuProps();
|
|
75
|
+
const urlInputRef = useRef();
|
|
76
|
+
const shouldFocusURLInputRef = useRef( false );
|
|
73
77
|
const inputId = useInstanceId( Controls, 'link-input' );
|
|
74
78
|
const helpTextId = `${ inputId }__help`;
|
|
75
79
|
|
|
80
|
+
// Local state to control the input value
|
|
81
|
+
const [ inputValue, setInputValue ] = useState( url );
|
|
82
|
+
|
|
83
|
+
// Sync local state when url prop changes (e.g., from undo/redo or external updates)
|
|
84
|
+
useEffect( () => {
|
|
85
|
+
setInputValue( url );
|
|
86
|
+
lastURLRef.current = url;
|
|
87
|
+
}, [ url ] );
|
|
88
|
+
|
|
76
89
|
// Use the entity binding hook internally
|
|
77
90
|
const { hasUrlBinding, clearBinding } = useEntityBinding( {
|
|
78
91
|
clientId,
|
|
79
92
|
attributes,
|
|
80
93
|
} );
|
|
81
94
|
|
|
82
|
-
|
|
83
|
-
|
|
95
|
+
// Get direct store dispatch to bypass setBoundAttributes wrapper
|
|
96
|
+
const { updateBlockAttributes } = useDispatch( blockEditorStore );
|
|
97
|
+
|
|
98
|
+
const unsyncBoundLink = () => {
|
|
99
|
+
// Clear the binding first
|
|
84
100
|
clearBinding();
|
|
85
101
|
|
|
86
|
-
//
|
|
87
|
-
|
|
102
|
+
// Use direct store dispatch to bypass block bindings safeguards
|
|
103
|
+
// which prevent updates to bound attributes when calling setAttributes.
|
|
104
|
+
// setAttributes is actually setBoundAttributes, a wrapper function that
|
|
105
|
+
// processes attributes through the binding system.
|
|
106
|
+
// See: packages/block-editor/src/components/block-edit/edit.js
|
|
107
|
+
updateBlockAttributes( clientId, {
|
|
108
|
+
url: lastURLRef.current, // set the lastURLRef as the new editable value so we avoid bugs from empty link states
|
|
109
|
+
id: undefined,
|
|
110
|
+
} );
|
|
88
111
|
};
|
|
89
112
|
|
|
113
|
+
useEffect( () => {
|
|
114
|
+
// Checking for ! hasUrlBinding is a defensive check, as we would
|
|
115
|
+
// only want to focus the input if the url is not bound to an entity.
|
|
116
|
+
if ( ! hasUrlBinding && shouldFocusURLInputRef.current ) {
|
|
117
|
+
// focuses and highlights the url input value, giving the user
|
|
118
|
+
// the ability to delete the value quickly or edit it.
|
|
119
|
+
urlInputRef.current?.select();
|
|
120
|
+
}
|
|
121
|
+
shouldFocusURLInputRef.current = false;
|
|
122
|
+
}, [ hasUrlBinding ] );
|
|
123
|
+
|
|
90
124
|
return (
|
|
91
125
|
<ToolsPanel
|
|
92
126
|
label={ __( 'Settings' ) }
|
|
@@ -126,22 +160,25 @@ export function Controls( { attributes, setAttributes, clientId } ) {
|
|
|
126
160
|
isShownByDefault
|
|
127
161
|
>
|
|
128
162
|
<InputControl
|
|
163
|
+
ref={ urlInputRef }
|
|
129
164
|
__nextHasNoMarginBottom
|
|
130
165
|
__next40pxDefaultSize
|
|
131
166
|
id={ inputId }
|
|
132
167
|
label={ __( 'Link' ) }
|
|
133
|
-
value={
|
|
134
|
-
onChange={ ( urlValue ) => {
|
|
135
|
-
if ( hasUrlBinding ) {
|
|
136
|
-
return; // Prevent editing when URL is bound
|
|
137
|
-
}
|
|
138
|
-
setAttributes( {
|
|
139
|
-
url: encodeURI( safeDecodeURI( urlValue ) ),
|
|
140
|
-
} );
|
|
141
|
-
} }
|
|
168
|
+
value={ inputValue ? safeDecodeURI( inputValue ) : '' }
|
|
142
169
|
autoComplete="off"
|
|
143
170
|
type="url"
|
|
144
171
|
disabled={ hasUrlBinding }
|
|
172
|
+
onChange={ ( newValue ) => {
|
|
173
|
+
if ( hasUrlBinding ) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Defer updating the url attribute until onBlur to prevent the canvas from
|
|
178
|
+
// treating a temporary empty value as a committed value, which replaces the
|
|
179
|
+
// label with placeholder text.
|
|
180
|
+
setInputValue( newValue );
|
|
181
|
+
} }
|
|
145
182
|
onFocus={ () => {
|
|
146
183
|
if ( hasUrlBinding ) {
|
|
147
184
|
return;
|
|
@@ -152,12 +189,19 @@ export function Controls( { attributes, setAttributes, clientId } ) {
|
|
|
152
189
|
if ( hasUrlBinding ) {
|
|
153
190
|
return;
|
|
154
191
|
}
|
|
192
|
+
|
|
193
|
+
const finalValue = ! inputValue
|
|
194
|
+
? lastURLRef.current
|
|
195
|
+
: inputValue;
|
|
196
|
+
|
|
197
|
+
// Update local state immediately so input reflects the reverted value if the value was cleared
|
|
198
|
+
setInputValue( finalValue );
|
|
199
|
+
|
|
155
200
|
// Defer the updateAttributes call to ensure entity connection isn't severed by accident.
|
|
156
|
-
updateAttributes(
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
);
|
|
201
|
+
updateAttributes( { url: finalValue }, setAttributes, {
|
|
202
|
+
...attributes,
|
|
203
|
+
url: lastURLRef.current,
|
|
204
|
+
} );
|
|
161
205
|
} }
|
|
162
206
|
help={
|
|
163
207
|
hasUrlBinding && (
|
|
@@ -171,7 +215,12 @@ export function Controls( { attributes, setAttributes, clientId } ) {
|
|
|
171
215
|
hasUrlBinding && (
|
|
172
216
|
<Button
|
|
173
217
|
icon={ unlinkIcon }
|
|
174
|
-
onClick={
|
|
218
|
+
onClick={ () => {
|
|
219
|
+
unsyncBoundLink();
|
|
220
|
+
// Focus management to send focus to the URL input
|
|
221
|
+
// on next render after disabled state is removed.
|
|
222
|
+
shouldFocusURLInputRef.current = true;
|
|
223
|
+
} }
|
|
175
224
|
aria-describedby={ helpTextId }
|
|
176
225
|
showTooltip
|
|
177
226
|
label={ __( 'Unsync and edit' ) }
|
|
@@ -7,5 +7,8 @@
|
|
|
7
7
|
|
|
8
8
|
export { Controls } from './controls';
|
|
9
9
|
export { updateAttributes } from './update-attributes';
|
|
10
|
-
export {
|
|
10
|
+
export {
|
|
11
|
+
useEntityBinding,
|
|
12
|
+
buildNavigationLinkEntityBinding,
|
|
13
|
+
} from './use-entity-binding';
|
|
11
14
|
export { LinkUI } from '../link-ui';
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* External dependencies
|
|
7
7
|
*/
|
|
8
8
|
import { render, screen, fireEvent } from '@testing-library/react';
|
|
9
|
+
import userEvent from '@testing-library/user-event';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Internal dependencies
|
|
@@ -95,18 +96,22 @@ describe( 'Controls', () => {
|
|
|
95
96
|
expect( urlInput.value ).toBe( 'https://example.com/test page' );
|
|
96
97
|
} );
|
|
97
98
|
|
|
98
|
-
it( '
|
|
99
|
+
it( 'calls updateAttributes with new URL on blur', async () => {
|
|
100
|
+
const user = userEvent.setup();
|
|
99
101
|
render( <Controls { ...defaultProps } /> );
|
|
100
102
|
|
|
101
103
|
const urlInput = screen.getByLabelText( 'Link' );
|
|
102
104
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
105
|
+
await user.click( urlInput );
|
|
106
|
+
await user.clear( urlInput );
|
|
107
|
+
await user.type( urlInput, 'https://example.com/test page' );
|
|
108
|
+
await user.tab();
|
|
106
109
|
|
|
107
|
-
expect(
|
|
108
|
-
url: 'https://example.com/test
|
|
109
|
-
|
|
110
|
+
expect( mockUpdateAttributes ).toHaveBeenCalledWith(
|
|
111
|
+
{ url: 'https://example.com/test page' },
|
|
112
|
+
defaultProps.setAttributes,
|
|
113
|
+
{ ...defaultProps.attributes, url: 'https://example.com' }
|
|
114
|
+
);
|
|
110
115
|
} );
|
|
111
116
|
|
|
112
117
|
it( 'calls updateAttributes on URL blur', () => {
|
|
@@ -143,11 +148,11 @@ describe( 'Controls', () => {
|
|
|
143
148
|
target: { value: 'https://new.com' },
|
|
144
149
|
} );
|
|
145
150
|
|
|
146
|
-
// Blur should call updateAttributes with the
|
|
151
|
+
// Blur should call updateAttributes with the new URL value from the input
|
|
147
152
|
fireEvent.blur( urlInput );
|
|
148
153
|
|
|
149
154
|
expect( mockUpdateAttributes ).toHaveBeenCalledWith(
|
|
150
|
-
{ url: 'https://
|
|
155
|
+
{ url: 'https://new.com' }, // New URL from input value
|
|
151
156
|
defaultProps.setAttributes,
|
|
152
157
|
{
|
|
153
158
|
...propsWithDifferentUrl.attributes,
|
|
@@ -1153,6 +1153,7 @@ describe( 'updateAttributes', () => {
|
|
|
1153
1153
|
|
|
1154
1154
|
expect( result ).toEqual( {
|
|
1155
1155
|
isEntityLink: true,
|
|
1156
|
+
attributes: expect.any( Object ),
|
|
1156
1157
|
} );
|
|
1157
1158
|
} );
|
|
1158
1159
|
|
|
@@ -1173,6 +1174,7 @@ describe( 'updateAttributes', () => {
|
|
|
1173
1174
|
|
|
1174
1175
|
expect( result ).toEqual( {
|
|
1175
1176
|
isEntityLink: false,
|
|
1177
|
+
attributes: expect.any( Object ),
|
|
1176
1178
|
} );
|
|
1177
1179
|
} );
|
|
1178
1180
|
|
|
@@ -1190,6 +1192,7 @@ describe( 'updateAttributes', () => {
|
|
|
1190
1192
|
|
|
1191
1193
|
expect( result ).toEqual( {
|
|
1192
1194
|
isEntityLink: false,
|
|
1195
|
+
attributes: expect.any( Object ),
|
|
1193
1196
|
} );
|
|
1194
1197
|
} );
|
|
1195
1198
|
|
|
@@ -1215,6 +1218,7 @@ describe( 'updateAttributes', () => {
|
|
|
1215
1218
|
// Should return false because the link was severed and converted to custom
|
|
1216
1219
|
expect( result ).toEqual( {
|
|
1217
1220
|
isEntityLink: false,
|
|
1221
|
+
attributes: expect.any( Object ),
|
|
1218
1222
|
} );
|
|
1219
1223
|
} );
|
|
1220
1224
|
|
|
@@ -1240,6 +1244,7 @@ describe( 'updateAttributes', () => {
|
|
|
1240
1244
|
// Should return true because entity link is preserved
|
|
1241
1245
|
expect( result ).toEqual( {
|
|
1242
1246
|
isEntityLink: true,
|
|
1247
|
+
attributes: expect.any( Object ),
|
|
1243
1248
|
} );
|
|
1244
1249
|
} );
|
|
1245
1250
|
|
|
@@ -1260,6 +1265,7 @@ describe( 'updateAttributes', () => {
|
|
|
1260
1265
|
// mailto links have kind: 'custom', so isEntityLink should be false
|
|
1261
1266
|
expect( result ).toEqual( {
|
|
1262
1267
|
isEntityLink: false,
|
|
1268
|
+
attributes: expect.any( Object ),
|
|
1263
1269
|
} );
|
|
1264
1270
|
} );
|
|
1265
1271
|
|
|
@@ -1280,6 +1286,7 @@ describe( 'updateAttributes', () => {
|
|
|
1280
1286
|
// tel links have kind: 'custom', so isEntityLink should be false
|
|
1281
1287
|
expect( result ).toEqual( {
|
|
1282
1288
|
isEntityLink: false,
|
|
1289
|
+
attributes: expect.any( Object ),
|
|
1283
1290
|
} );
|
|
1284
1291
|
} );
|
|
1285
1292
|
|
|
@@ -1300,6 +1307,7 @@ describe( 'updateAttributes', () => {
|
|
|
1300
1307
|
|
|
1301
1308
|
expect( result ).toEqual( {
|
|
1302
1309
|
isEntityLink: true,
|
|
1310
|
+
attributes: expect.any( Object ),
|
|
1303
1311
|
} );
|
|
1304
1312
|
} );
|
|
1305
1313
|
} );
|
|
@@ -10,7 +10,10 @@ import { renderHook, act } from '@testing-library/react';
|
|
|
10
10
|
/**
|
|
11
11
|
* Internal dependencies
|
|
12
12
|
*/
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
useEntityBinding,
|
|
15
|
+
buildNavigationLinkEntityBinding,
|
|
16
|
+
} from '../use-entity-binding';
|
|
14
17
|
|
|
15
18
|
// Mock the entire @wordpress/block-editor module
|
|
16
19
|
jest.mock( '@wordpress/block-editor', () => ( {
|
|
@@ -49,17 +52,18 @@ describe( 'useEntityBinding', () => {
|
|
|
49
52
|
expect( result.current.hasUrlBinding ).toBe( false );
|
|
50
53
|
} );
|
|
51
54
|
|
|
52
|
-
it( 'should return true when core/
|
|
55
|
+
it( 'should return true when core/post-data binding exists with id for post-type', () => {
|
|
53
56
|
const attributes = {
|
|
54
57
|
metadata: {
|
|
55
58
|
bindings: {
|
|
56
59
|
url: {
|
|
57
|
-
source: 'core/
|
|
58
|
-
args: {
|
|
60
|
+
source: 'core/post-data',
|
|
61
|
+
args: { field: 'link' },
|
|
59
62
|
},
|
|
60
63
|
},
|
|
61
64
|
},
|
|
62
65
|
id: 123,
|
|
66
|
+
kind: 'post-type',
|
|
63
67
|
};
|
|
64
68
|
|
|
65
69
|
const { result } = renderHook( () =>
|
|
@@ -72,17 +76,42 @@ describe( 'useEntityBinding', () => {
|
|
|
72
76
|
expect( result.current.hasUrlBinding ).toBe( true );
|
|
73
77
|
} );
|
|
74
78
|
|
|
75
|
-
it( 'should return
|
|
79
|
+
it( 'should return true when core/term-data binding exists with id for taxonomy', () => {
|
|
80
|
+
const attributes = {
|
|
81
|
+
metadata: {
|
|
82
|
+
bindings: {
|
|
83
|
+
url: {
|
|
84
|
+
source: 'core/term-data',
|
|
85
|
+
args: { field: 'link' },
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
id: 123,
|
|
90
|
+
kind: 'taxonomy',
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const { result } = renderHook( () =>
|
|
94
|
+
useEntityBinding( {
|
|
95
|
+
clientId: 'test-client-id',
|
|
96
|
+
attributes,
|
|
97
|
+
} )
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
expect( result.current.hasUrlBinding ).toBe( true );
|
|
101
|
+
} );
|
|
102
|
+
|
|
103
|
+
it( 'should return false when source is not core/post-data or core/term-data', () => {
|
|
76
104
|
const attributes = {
|
|
77
105
|
metadata: {
|
|
78
106
|
bindings: {
|
|
79
107
|
url: {
|
|
80
108
|
source: 'some-other-source',
|
|
81
|
-
args: {
|
|
109
|
+
args: { field: 'url' },
|
|
82
110
|
},
|
|
83
111
|
},
|
|
84
112
|
},
|
|
85
113
|
id: 123,
|
|
114
|
+
kind: 'post-type',
|
|
86
115
|
};
|
|
87
116
|
|
|
88
117
|
const { result } = renderHook( () =>
|
|
@@ -95,17 +124,18 @@ describe( 'useEntityBinding', () => {
|
|
|
95
124
|
expect( result.current.hasUrlBinding ).toBe( false );
|
|
96
125
|
} );
|
|
97
126
|
|
|
98
|
-
it( 'should return false when core/
|
|
127
|
+
it( 'should return false when core/post-data binding exists but no id', () => {
|
|
99
128
|
const attributes = {
|
|
100
129
|
metadata: {
|
|
101
130
|
bindings: {
|
|
102
131
|
url: {
|
|
103
|
-
source: 'core/
|
|
104
|
-
args: {
|
|
132
|
+
source: 'core/post-data',
|
|
133
|
+
args: { field: 'link' },
|
|
105
134
|
},
|
|
106
135
|
},
|
|
107
136
|
},
|
|
108
137
|
id: null,
|
|
138
|
+
kind: 'post-type',
|
|
109
139
|
};
|
|
110
140
|
|
|
111
141
|
const { result } = renderHook( () =>
|
|
@@ -147,12 +177,13 @@ describe( 'useEntityBinding', () => {
|
|
|
147
177
|
metadata: {
|
|
148
178
|
bindings: {
|
|
149
179
|
url: {
|
|
150
|
-
source: 'core/
|
|
151
|
-
args: {
|
|
180
|
+
source: 'core/post-data',
|
|
181
|
+
args: { field: 'link' },
|
|
152
182
|
},
|
|
153
183
|
},
|
|
154
184
|
},
|
|
155
185
|
id: 123,
|
|
186
|
+
kind: 'post-type',
|
|
156
187
|
};
|
|
157
188
|
|
|
158
189
|
const { result } = renderHook( () =>
|
|
@@ -171,7 +202,7 @@ describe( 'useEntityBinding', () => {
|
|
|
171
202
|
} );
|
|
172
203
|
} );
|
|
173
204
|
|
|
174
|
-
it( 'should NOT
|
|
205
|
+
it( 'should NOT call updateBlockBindings when clearBinding is called and no binding exists', () => {
|
|
175
206
|
const attributes = {
|
|
176
207
|
metadata: {},
|
|
177
208
|
id: null,
|
|
@@ -191,7 +222,7 @@ describe( 'useEntityBinding', () => {
|
|
|
191
222
|
expect( mockUpdateBlockBindings ).not.toHaveBeenCalled();
|
|
192
223
|
} );
|
|
193
224
|
|
|
194
|
-
it( 'should
|
|
225
|
+
it( 'should call updateBlockBindings when clearBinding is called and binding exists even with null source', () => {
|
|
195
226
|
const attributes = {
|
|
196
227
|
metadata: {
|
|
197
228
|
bindings: {
|
|
@@ -215,13 +246,16 @@ describe( 'useEntityBinding', () => {
|
|
|
215
246
|
result.current.clearBinding();
|
|
216
247
|
} );
|
|
217
248
|
|
|
218
|
-
expect( mockUpdateBlockBindings ).
|
|
249
|
+
expect( mockUpdateBlockBindings ).toHaveBeenCalledWith( {
|
|
250
|
+
url: undefined,
|
|
251
|
+
} );
|
|
219
252
|
} );
|
|
220
253
|
|
|
221
|
-
it( 'should create binding when createBinding is called', () => {
|
|
254
|
+
it( 'should create core/post-data binding when createBinding is called for post-type', () => {
|
|
222
255
|
const attributes = {
|
|
223
256
|
metadata: {},
|
|
224
257
|
id: null,
|
|
258
|
+
kind: 'post-type',
|
|
225
259
|
};
|
|
226
260
|
|
|
227
261
|
const { result } = renderHook( () =>
|
|
@@ -237,11 +271,92 @@ describe( 'useEntityBinding', () => {
|
|
|
237
271
|
|
|
238
272
|
expect( mockUpdateBlockBindings ).toHaveBeenCalledWith( {
|
|
239
273
|
url: {
|
|
240
|
-
source: 'core/
|
|
274
|
+
source: 'core/post-data',
|
|
241
275
|
args: {
|
|
242
|
-
|
|
276
|
+
field: 'link',
|
|
243
277
|
},
|
|
244
278
|
},
|
|
245
279
|
} );
|
|
246
280
|
} );
|
|
281
|
+
|
|
282
|
+
describe( 'buildNavigationLinkEntityBinding', () => {
|
|
283
|
+
it( 'returns correct binding for post-type', () => {
|
|
284
|
+
const binding = buildNavigationLinkEntityBinding( 'post-type' );
|
|
285
|
+
expect( binding ).toEqual( {
|
|
286
|
+
url: {
|
|
287
|
+
source: 'core/post-data',
|
|
288
|
+
args: { field: 'link' },
|
|
289
|
+
},
|
|
290
|
+
} );
|
|
291
|
+
} );
|
|
292
|
+
|
|
293
|
+
it( 'returns correct binding for taxonomy', () => {
|
|
294
|
+
const binding = buildNavigationLinkEntityBinding( 'taxonomy' );
|
|
295
|
+
expect( binding ).toEqual( {
|
|
296
|
+
url: {
|
|
297
|
+
source: 'core/term-data',
|
|
298
|
+
args: { field: 'link' },
|
|
299
|
+
},
|
|
300
|
+
} );
|
|
301
|
+
} );
|
|
302
|
+
|
|
303
|
+
it( 'throws error when called without parameter', () => {
|
|
304
|
+
expect( () => {
|
|
305
|
+
buildNavigationLinkEntityBinding();
|
|
306
|
+
} ).toThrow(
|
|
307
|
+
'buildNavigationLinkEntityBinding requires a kind parameter'
|
|
308
|
+
);
|
|
309
|
+
} );
|
|
310
|
+
|
|
311
|
+
it( 'throws error for invalid kind', () => {
|
|
312
|
+
expect( () => {
|
|
313
|
+
buildNavigationLinkEntityBinding( 'invalid-kind' );
|
|
314
|
+
} ).toThrow( 'Invalid kind "invalid-kind"' );
|
|
315
|
+
} );
|
|
316
|
+
|
|
317
|
+
it( 'throws error for null kind', () => {
|
|
318
|
+
expect( () => {
|
|
319
|
+
buildNavigationLinkEntityBinding( null );
|
|
320
|
+
} ).toThrow( 'Invalid kind "null"' );
|
|
321
|
+
} );
|
|
322
|
+
|
|
323
|
+
it( 'throws error for empty string', () => {
|
|
324
|
+
expect( () => {
|
|
325
|
+
buildNavigationLinkEntityBinding( '' );
|
|
326
|
+
} ).toThrow( 'Invalid kind ""' );
|
|
327
|
+
} );
|
|
328
|
+
|
|
329
|
+
it( 'handles invalid kind gracefully in createBinding', () => {
|
|
330
|
+
const consoleSpy = jest
|
|
331
|
+
.spyOn( console, 'warn' )
|
|
332
|
+
.mockImplementation();
|
|
333
|
+
|
|
334
|
+
const attributes = {
|
|
335
|
+
metadata: {},
|
|
336
|
+
id: null,
|
|
337
|
+
kind: 'invalid-kind',
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
const { result } = renderHook( () =>
|
|
341
|
+
useEntityBinding( {
|
|
342
|
+
clientId: 'test-client-id',
|
|
343
|
+
attributes,
|
|
344
|
+
} )
|
|
345
|
+
);
|
|
346
|
+
|
|
347
|
+
act( () => {
|
|
348
|
+
result.current.createBinding();
|
|
349
|
+
} );
|
|
350
|
+
|
|
351
|
+
expect( consoleSpy ).toHaveBeenCalledWith(
|
|
352
|
+
'Failed to create entity binding:',
|
|
353
|
+
expect.stringContaining( 'Invalid kind "invalid-kind"' )
|
|
354
|
+
);
|
|
355
|
+
|
|
356
|
+
// Should not call updateBlockBindings when validation fails
|
|
357
|
+
expect( mockUpdateBlockBindings ).not.toHaveBeenCalled();
|
|
358
|
+
|
|
359
|
+
consoleSpy.mockRestore();
|
|
360
|
+
} );
|
|
361
|
+
} );
|
|
247
362
|
} );
|