@wordpress/block-library 9.33.2 → 9.34.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 +2 -0
- package/build/accordion-heading/block.json +1 -1
- package/build/accordion-item/block.json +1 -1
- package/build/breadcrumbs/block.json +3 -4
- package/build/breadcrumbs/edit.js +43 -77
- package/build/breadcrumbs/edit.js.map +2 -2
- package/build/categories/edit.js +8 -4
- package/build/categories/edit.js.map +2 -2
- package/build/latest-comments/block.json +4 -3
- package/build/latest-comments/deprecated.js +56 -0
- package/build/latest-comments/deprecated.js.map +7 -0
- package/build/latest-comments/edit.js +16 -10
- package/build/latest-comments/edit.js.map +2 -2
- package/build/latest-comments/index.js +3 -1
- package/build/latest-comments/index.js.map +3 -3
- package/build/math/deprecated.js +54 -0
- package/build/math/deprecated.js.map +7 -0
- package/build/math/index.js +3 -1
- package/build/math/index.js.map +3 -3
- package/build/math/save.js +2 -3
- package/build/math/save.js.map +2 -2
- package/build/navigation/edit/menu-inspector-controls.js +1 -1
- package/build/navigation/edit/menu-inspector-controls.js.map +2 -2
- package/build/navigation-link/edit.js +1 -1
- package/build/navigation-link/edit.js.map +2 -2
- package/build/navigation-link/link-ui/page-creator.js +20 -0
- package/build/navigation-link/link-ui/page-creator.js.map +3 -3
- package/build/navigation-link/shared/controls.js +36 -16
- package/build/navigation-link/shared/controls.js.map +2 -2
- package/build/navigation-link/shared/use-entity-binding.js +1 -1
- package/build/navigation-link/shared/use-entity-binding.js.map +2 -2
- package/build/navigation-submenu/edit.js +1 -1
- package/build/navigation-submenu/edit.js.map +2 -2
- package/build-module/accordion-heading/block.json +1 -1
- package/build-module/accordion-item/block.json +1 -1
- package/build-module/breadcrumbs/block.json +3 -4
- package/build-module/breadcrumbs/edit.js +44 -78
- package/build-module/breadcrumbs/edit.js.map +2 -2
- package/build-module/categories/edit.js +8 -4
- package/build-module/categories/edit.js.map +2 -2
- package/build-module/latest-comments/block.json +4 -3
- package/build-module/latest-comments/deprecated.js +36 -0
- package/build-module/latest-comments/deprecated.js.map +7 -0
- package/build-module/latest-comments/edit.js +17 -10
- package/build-module/latest-comments/edit.js.map +2 -2
- package/build-module/latest-comments/index.js +3 -1
- package/build-module/latest-comments/index.js.map +2 -2
- package/build-module/math/deprecated.js +34 -0
- package/build-module/math/deprecated.js.map +7 -0
- package/build-module/math/index.js +3 -1
- package/build-module/math/index.js.map +2 -2
- package/build-module/math/save.js +2 -3
- package/build-module/math/save.js.map +2 -2
- package/build-module/navigation/edit/menu-inspector-controls.js +1 -1
- package/build-module/navigation/edit/menu-inspector-controls.js.map +2 -2
- package/build-module/navigation-link/edit.js +1 -1
- package/build-module/navigation-link/edit.js.map +2 -2
- package/build-module/navigation-link/link-ui/page-creator.js +21 -1
- package/build-module/navigation-link/link-ui/page-creator.js.map +2 -2
- package/build-module/navigation-link/shared/controls.js +37 -17
- package/build-module/navigation-link/shared/controls.js.map +2 -2
- package/build-module/navigation-link/shared/use-entity-binding.js +1 -1
- package/build-module/navigation-link/shared/use-entity-binding.js.map +2 -2
- package/build-module/navigation-submenu/edit.js +1 -1
- package/build-module/navigation-submenu/edit.js.map +2 -2
- package/build-style/editor-rtl.css +2 -2
- package/build-style/editor.css +2 -2
- package/build-style/math/style-rtl.css +4 -0
- package/build-style/math/style.css +4 -0
- package/build-style/navigation-link/editor-rtl.css +1 -1
- package/build-style/navigation-link/editor.css +1 -1
- package/build-style/style-rtl.css +5 -0
- package/build-style/style.css +5 -0
- package/build-style/video/editor-rtl.css +1 -1
- package/build-style/video/editor.css +1 -1
- package/package.json +37 -37
- package/src/accordion-heading/block.json +1 -1
- package/src/accordion-item/block.json +1 -1
- package/src/breadcrumbs/block.json +3 -4
- package/src/breadcrumbs/edit.js +96 -132
- package/src/breadcrumbs/index.php +203 -50
- package/src/categories/edit.js +10 -6
- package/src/categories/index.php +1 -1
- package/src/latest-comments/block.json +4 -3
- package/src/latest-comments/deprecated.js +37 -0
- package/src/latest-comments/edit.js +17 -10
- package/src/latest-comments/index.js +2 -0
- package/src/latest-comments/index.php +11 -2
- package/src/math/deprecated.js +44 -0
- package/src/math/index.js +2 -0
- package/src/math/save.js +6 -5
- package/src/math/style.scss +4 -0
- package/src/navigation/edit/menu-inspector-controls.js +1 -1
- package/src/navigation-link/edit.js +1 -1
- package/src/navigation-link/editor.scss +1 -1
- package/src/navigation-link/link-ui/page-creator.js +25 -2
- package/src/navigation-link/shared/controls.js +58 -18
- package/src/navigation-link/shared/test/controls.js +14 -9
- package/src/navigation-link/shared/use-entity-binding.js +1 -1
- package/src/navigation-submenu/edit.js +1 -1
- package/src/style.scss +1 -0
- package/src/video/editor.scss +1 -1
|
@@ -11,7 +11,7 @@ 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';
|
|
@@ -72,9 +72,20 @@ export function Controls( { attributes, setAttributes, clientId } ) {
|
|
|
72
72
|
const { label, url, description, rel, opensInNewTab } = attributes;
|
|
73
73
|
const lastURLRef = useRef( url );
|
|
74
74
|
const dropdownMenuProps = useToolsPanelDropdownMenuProps();
|
|
75
|
+
const urlInputRef = useRef();
|
|
76
|
+
const shouldFocusURLInputRef = useRef( false );
|
|
75
77
|
const inputId = useInstanceId( Controls, 'link-input' );
|
|
76
78
|
const helpTextId = `${ inputId }__help`;
|
|
77
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
|
+
|
|
78
89
|
// Use the entity binding hook internally
|
|
79
90
|
const { hasUrlBinding, clearBinding } = useEntityBinding( {
|
|
80
91
|
clientId,
|
|
@@ -84,7 +95,7 @@ export function Controls( { attributes, setAttributes, clientId } ) {
|
|
|
84
95
|
// Get direct store dispatch to bypass setBoundAttributes wrapper
|
|
85
96
|
const { updateBlockAttributes } = useDispatch( blockEditorStore );
|
|
86
97
|
|
|
87
|
-
const
|
|
98
|
+
const unsyncBoundLink = () => {
|
|
88
99
|
// Clear the binding first
|
|
89
100
|
clearBinding();
|
|
90
101
|
|
|
@@ -93,9 +104,23 @@ export function Controls( { attributes, setAttributes, clientId } ) {
|
|
|
93
104
|
// setAttributes is actually setBoundAttributes, a wrapper function that
|
|
94
105
|
// processes attributes through the binding system.
|
|
95
106
|
// See: packages/block-editor/src/components/block-edit/edit.js
|
|
96
|
-
updateBlockAttributes( clientId, {
|
|
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
|
+
} );
|
|
97
111
|
};
|
|
98
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
|
+
|
|
99
124
|
return (
|
|
100
125
|
<ToolsPanel
|
|
101
126
|
label={ __( 'Settings' ) }
|
|
@@ -135,22 +160,25 @@ export function Controls( { attributes, setAttributes, clientId } ) {
|
|
|
135
160
|
isShownByDefault
|
|
136
161
|
>
|
|
137
162
|
<InputControl
|
|
163
|
+
ref={ urlInputRef }
|
|
138
164
|
__nextHasNoMarginBottom
|
|
139
165
|
__next40pxDefaultSize
|
|
140
166
|
id={ inputId }
|
|
141
167
|
label={ __( 'Link' ) }
|
|
142
|
-
value={
|
|
143
|
-
onChange={ ( urlValue ) => {
|
|
144
|
-
if ( hasUrlBinding ) {
|
|
145
|
-
return; // Prevent editing when URL is bound
|
|
146
|
-
}
|
|
147
|
-
setAttributes( {
|
|
148
|
-
url: encodeURI( safeDecodeURI( urlValue ) ),
|
|
149
|
-
} );
|
|
150
|
-
} }
|
|
168
|
+
value={ inputValue ? safeDecodeURI( inputValue ) : '' }
|
|
151
169
|
autoComplete="off"
|
|
152
170
|
type="url"
|
|
153
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
|
+
} }
|
|
154
182
|
onFocus={ () => {
|
|
155
183
|
if ( hasUrlBinding ) {
|
|
156
184
|
return;
|
|
@@ -161,12 +189,19 @@ export function Controls( { attributes, setAttributes, clientId } ) {
|
|
|
161
189
|
if ( hasUrlBinding ) {
|
|
162
190
|
return;
|
|
163
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
|
+
|
|
164
200
|
// Defer the updateAttributes call to ensure entity connection isn't severed by accident.
|
|
165
|
-
updateAttributes(
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
);
|
|
201
|
+
updateAttributes( { url: finalValue }, setAttributes, {
|
|
202
|
+
...attributes,
|
|
203
|
+
url: lastURLRef.current,
|
|
204
|
+
} );
|
|
170
205
|
} }
|
|
171
206
|
help={
|
|
172
207
|
hasUrlBinding && (
|
|
@@ -180,7 +215,12 @@ export function Controls( { attributes, setAttributes, clientId } ) {
|
|
|
180
215
|
hasUrlBinding && (
|
|
181
216
|
<Button
|
|
182
217
|
icon={ unlinkIcon }
|
|
183
|
-
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
|
+
} }
|
|
184
224
|
aria-describedby={ helpTextId }
|
|
185
225
|
showTooltip
|
|
186
226
|
label={ __( 'Unsync and edit' ) }
|
|
@@ -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,
|
|
@@ -69,7 +69,7 @@ export function useEntityBinding( { clientId, attributes } ) {
|
|
|
69
69
|
if ( hasUrlBinding ) {
|
|
70
70
|
updateBlockBindings( { url: undefined } );
|
|
71
71
|
}
|
|
72
|
-
}, [ updateBlockBindings, hasUrlBinding
|
|
72
|
+
}, [ updateBlockBindings, hasUrlBinding ] );
|
|
73
73
|
|
|
74
74
|
const createBinding = useCallback(
|
|
75
75
|
( updatedAttributes ) => {
|
package/src/style.scss
CHANGED
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
@use "./latest-posts/style.scss" as *;
|
|
33
33
|
@use "./list/style.scss" as *;
|
|
34
34
|
@use "./loginout/style.scss" as *;
|
|
35
|
+
@use "./math/style.scss" as *;
|
|
35
36
|
@use "./media-text/style.scss" as *;
|
|
36
37
|
@use "./navigation/style.scss" as *;
|
|
37
38
|
@use "./navigation-link/style.scss" as *;
|