diff --git a/packages/block-editor/src/components/link-control/index.js b/packages/block-editor/src/components/link-control/index.js
index 4803b9a0efebc4..41455c4ecf9704 100644
--- a/packages/block-editor/src/components/link-control/index.js
+++ b/packages/block-editor/src/components/link-control/index.js
@@ -292,7 +292,8 @@ function LinkControl( {
const shownUnlinkControl =
onRemove && value && ! isEditingLink && ! isCreatingPage;
- const showSettings = !! settings?.length;
+ const showSettings = !! settings?.length && isEditingLink && hasLinkValue;
+ const showActions = isEditingLink && hasLinkValue;
// Only show text control once a URL value has been committed
// and it isn't just empty whitespace.
@@ -322,6 +323,18 @@ function LinkControl( {
'has-text-control': showTextControl,
} ) }
>
+ { showTextControl && (
+
+ ) }
- { showTextControl && (
-
- ) }
{ errorMessage && (
) }
- { isEditing && (
+ { showSettings && (
- { showSettings && (
+ { ! currentInputIsEmpty && (
) }
+
+ ) }
-
-
-
-
+ { showActions && (
+
+
+
) }
diff --git a/packages/block-editor/src/components/link-control/search-input.js b/packages/block-editor/src/components/link-control/search-input.js
index 4e30daaa96524b..d6023b9220d630 100644
--- a/packages/block-editor/src/components/link-control/search-input.js
+++ b/packages/block-editor/src/components/link-control/search-input.js
@@ -46,7 +46,7 @@ const LinkControlSearchInput = forwardRef(
suggestionsQuery = {},
withURLSuggestion = true,
createSuggestionButtonText,
- useLabel = false,
+ hideLabelFromVision = false,
},
ref
) => {
@@ -120,7 +120,7 @@ const LinkControlSearchInput = forwardRef(
};
const inputClasses = classnames( className, {
- 'has-no-label': ! useLabel,
+ // 'has-no-label': ! hideLabelFromVision,
} );
return (
@@ -128,7 +128,8 @@ const LinkControlSearchInput = forwardRef(
setSettingsOpen( ! settingsOpen ) }
- icon={ settingsIcon }
- label={ __( 'Link Settings' ) }
+ icon={ isRTL() ? chevronLeftSmall : chevronRightSmall }
aria-controls={ settingsDrawerId }
- />
+ >
+ { _x( 'Advanced', 'Additional link settings' ) }
+
{ settingsOpen && (
.components-base-control__field {
- display: flex;
- align-items: center;
- }
-
- .components-base-control__label {
- margin-right: $grid-unit-20;
- margin-bottom: 0;
- min-width: 29px; // align with search results.
- }
-
input[type="text"],
// Specificity overide of URLInput defaults.
&.block-editor-url-input input[type="text"].block-editor-url-input__input {
@include input-control;
- width: calc(100% - #{$grid-unit-20 * 2});
display: block;
- padding: 11px $grid-unit-20;
+ border: 1px solid $gray-600;
+ border-radius: $radius-block-ui;
+ height: $button-size-next-default-40px; // components do not properly support unstable-large yet.
margin: 0;
+ padding: $grid-unit-10 $grid-unit-20;
position: relative;
- border: 1px solid $gray-300;
- border-radius: $radius-block-ui;
+ width: 100%;
}
}
@@ -94,12 +83,12 @@ $preview-image-height: 140px;
flex-direction: row-reverse; // put "Cancel" on the left but retain DOM order.
justify-content: flex-start;
gap: $grid-unit-10;
+ padding: $grid-unit-10;
order: 20;
}
.block-editor-link-control__search-results-wrapper {
position: relative;
- margin-top: -$grid-unit-20 + 1px;
&::before,
&::after {
@@ -440,36 +429,7 @@ $preview-image-height: 140px;
display: flex; // allow for ordering.
flex-direction: column;
flex-basis: 100%; // occupy full width.
- margin-top: $grid-unit-20;
- padding-top: $grid-unit-20;
position: relative;
-
- &::after {
- content: "";
- display: block;
- height: 1px;
- background-color: $gray-300;
- position: absolute;
- left: -$grid-unit-20;
- right: -$grid-unit-20;
- top: 0;
- }
-}
-
-.block-editor-link-control__tools {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- justify-content: space-between;
- margin: 0;
- padding: $grid-unit-20;
-
- // To hide the horizontal scrollbar on toggle.
- // Margin and padding are needed to prevent cutoff of the toggle button focus outline.
- // See: https://github.com/WordPress/gutenberg/pull/47986
- margin-top: calc(var(--wp-admin-border-width-focus) * -1);
- padding-top: var(--wp-admin-border-width-focus);
- overflow: hidden;
}
.block-editor-link-control__unlink {
@@ -477,17 +437,10 @@ $preview-image-height: 140px;
padding-right: $grid-unit-20;
}
-.block-editor-link-control__settings {
- flex: 1;
- margin: 0;
-
- .is-alternate & {
- border-top: $border-width solid $gray-900;
- }
-}
-
.block-editor-link-control__setting {
margin-bottom: $grid-unit-20;
+ flex: 1;
+ padding: $grid-unit-10 0 $grid-unit-10 $grid-unit-30;
// Cancel left margin inherited from WP Admin Forms CSS.
input {
@@ -499,6 +452,31 @@ $preview-image-height: 140px;
}
}
+.block-editor-link-control__tools {
+ padding: $grid-unit-10 $grid-unit-10 0 $grid-unit-10;
+ margin-top: #{$grid-unit-20 * -1};
+
+ .components-button.block-editor-link-control__drawer-toggle {
+ padding-left: 0;
+ gap: 0;
+
+ // Point downwards when open (same as list view expander)
+ &[aria-expanded="true"] svg {
+ visibility: visible;
+ transition: transform 0.1s ease;
+ transform: rotate(90deg);
+ @include reduce-motion("transition");
+ }
+ // Point rightwards when closed (same as list view expander)
+ &[aria-expanded="false"] svg {
+ visibility: visible;
+ transform: rotate(0deg);
+ transition: transform 0.1s ease;
+ @include reduce-motion("transition");
+ }
+ }
+}
+
.block-editor-link-control .block-editor-link-control__search-input .components-spinner {
display: block;
diff --git a/packages/block-editor/src/components/link-control/test/index.js b/packages/block-editor/src/components/link-control/test/index.js
index e5084844946be5..20b72363391ee1 100644
--- a/packages/block-editor/src/components/link-control/test/index.js
+++ b/packages/block-editor/src/components/link-control/test/index.js
@@ -138,7 +138,7 @@ describe( 'Basic rendering', () => {
render( );
// Search Input UI.
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
expect( searchInput ).toBeVisible();
} );
@@ -147,7 +147,7 @@ describe( 'Basic rendering', () => {
render( );
// Search Input UI.
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
expect( searchInput ).toBeVisible();
// Make sure we use the ARIA 1.0 pattern with aria-owns.
@@ -170,7 +170,7 @@ describe( 'Basic rendering', () => {
render( );
// Search Input UI.
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
// Simulate searching for a term.
await user.type( searchInput, 'Hello' );
@@ -283,7 +283,7 @@ describe( 'Basic rendering', () => {
render( );
// Search Input UI.
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
// Simulate searching for a term.
await user.type( searchInput, searchTerm );
@@ -296,7 +296,7 @@ describe( 'Basic rendering', () => {
render( );
expect(
- screen.queryByRole( 'combobox', { name: 'URL' } )
+ screen.queryByRole( 'combobox', { name: 'Link' } )
).not.toBeInTheDocument();
} );
@@ -309,7 +309,7 @@ describe( 'Basic rendering', () => {
);
expect(
- screen.getByRole( 'combobox', { name: 'URL' } )
+ screen.getByRole( 'combobox', { name: 'Link' } )
).toBeVisible();
} );
@@ -327,7 +327,7 @@ describe( 'Basic rendering', () => {
await user.click( editButton );
expect(
- screen.getByRole( 'combobox', { name: 'URL' } )
+ screen.getByRole( 'combobox', { name: 'Link' } )
).toBeVisible();
// If passed `forceIsEditingLink` of `false` while editing, should
@@ -340,7 +340,7 @@ describe( 'Basic rendering', () => {
);
expect(
- screen.queryByRole( 'combobox', { name: 'URL' } )
+ screen.queryByRole( 'combobox', { name: 'Link' } )
).not.toBeInTheDocument();
} );
@@ -424,7 +424,7 @@ describe( 'Searching for a link', () => {
render( );
// Search Input UI.
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
// Simulate searching for a term.
await user.type( searchInput, searchTerm );
@@ -448,7 +448,9 @@ describe( 'Searching for a link', () => {
render( );
// Search Input UI.
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
+ const searchInput = screen.getByRole( 'combobox', {
+ name: 'Link',
+ } );
// Simulate searching for a term.
await user.type( searchInput, searchTerm );
@@ -497,7 +499,9 @@ describe( 'Searching for a link', () => {
render( );
// Search Input UI.
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
+ const searchInput = screen.getByRole( 'combobox', {
+ name: 'Link',
+ } );
// Simulate searching for a term.
await user.type( searchInput, searchTerm );
@@ -528,7 +532,7 @@ describe( 'Searching for a link', () => {
render( );
// Search Input UI.
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
// Simulate searching for a term.
await user.type( searchInput, searchTerm );
@@ -571,7 +575,7 @@ describe( 'Searching for a link', () => {
render( );
// Search Input UI.
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
// Simulate searching for a term.
await user.type( searchInput, 'anything' );
@@ -582,12 +586,43 @@ describe( 'Searching for a link', () => {
expect( mockFetchSearchSuggestions ).not.toHaveBeenCalled();
} );
+ it( 'should not display a URL suggestion when input is not likely to be a URL.', async () => {
+ const searchTerm = 'unlikelytobeaURL';
+ const user = userEvent.setup();
+ render( );
+
+ // Search Input UI.
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
+
+ // Simulate searching for a term.
+ await user.type( searchInput, searchTerm );
+
+ const searchResultElements = within(
+ await screen.findByRole( 'listbox', {
+ name: /Search results for.*/,
+ } )
+ ).getAllByRole( 'option' );
+
+ const lastSearchResultItem =
+ searchResultElements[ searchResultElements.length - 1 ];
+
+ // We should see a search result for each of the expect search suggestions.
+ expect( searchResultElements ).toHaveLength(
+ fauxEntitySuggestions.length
+ );
+
+ // The URL search suggestion should not exist.
+ expect( lastSearchResultItem ).not.toHaveTextContent(
+ 'Press ENTER to add this link'
+ );
+ } );
+
it( 'should not display a URL suggestion as a default fallback when noURLSuggestion is passed.', async () => {
const user = userEvent.setup();
render( );
// Search Input UI.
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
// Simulate searching for a term.
await user.type( searchInput, 'couldbeurlorentitysearchterm' );
@@ -617,7 +652,9 @@ describe( 'Manual link entry', () => {
render( );
// Search Input UI.
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
+ const searchInput = screen.getByRole( 'combobox', {
+ name: 'Link',
+ } );
// Simulate searching for a term.
await user.type( searchInput, searchTerm );
@@ -653,19 +690,9 @@ describe( 'Manual link entry', () => {
// Search Input UI.
const searchInput = screen.getByRole( 'combobox', {
- name: 'URL',
- } );
-
- let submitButton = screen.getByRole( 'button', {
- name: 'Save',
+ name: 'Link',
} );
- expect( submitButton ).toHaveAttribute(
- 'aria-disabled',
- 'true'
- );
- expect( submitButton ).toBeVisible();
-
if ( searchString.length ) {
// Simulate searching for a term.
await user.type( searchInput, searchString );
@@ -677,102 +704,74 @@ describe( 'Manual link entry', () => {
// Attempt to submit the empty search value in the input.
await user.keyboard( '[Enter]' );
- submitButton = screen.getByRole( 'button', {
- name: 'Save',
- } );
-
- // Verify the UI hasn't allowed submission.
+ // Verify the UI hasn't allowed submission because
+ // the search input is still visible.
expect( searchInput ).toBeVisible();
- expect( submitButton ).toHaveAttribute(
- 'aria-disabled',
- 'true'
- );
- expect( submitButton ).toBeVisible();
}
);
it.each( testTable )(
- 'should not allow creation of links %s via the UI "submit" button',
+ 'should not allow editing of links to a new link %s via the UI "submit" button',
async ( _desc, searchString ) => {
const user = userEvent.setup();
- render( );
+ render(
+
+ );
// Search Input UI.
const searchInput = screen.getByRole( 'combobox', {
- name: 'URL',
+ name: 'Link',
} );
- let submitButton = screen.queryByRole( 'button', {
- name: 'Save',
- } );
+ // Remove the existing link.
+ await user.clear( searchInput );
- expect( submitButton ).toHaveAttribute(
- 'aria-disabled',
- 'true'
- );
- expect( submitButton ).toBeVisible();
-
- // Simulate searching for a term.
if ( searchString.length ) {
- // Simulate searching for a term.
await user.type( searchInput, searchString );
} else {
// Simulate clearing the search term.
await user.clear( searchInput );
}
- // Attempt to submit the empty search value in the input.
- await user.click( submitButton );
-
- submitButton = screen.queryByRole( 'button', {
+ const submitButton = screen.queryByRole( 'button', {
name: 'Save',
} );
- // Verify the UI hasn't allowed submission.
- expect( searchInput ).toBeVisible();
+ // debug the UI state
+ // screen.debug();
+
+ // Verify the submission UI is disabled.
+ expect( submitButton ).toBeVisible();
expect( submitButton ).toHaveAttribute(
'aria-disabled',
'true'
);
- expect( submitButton ).toBeVisible();
+
+ // Attempt to submit the empty search value in the input.
+ await user.click( submitButton );
+
+ // Verify the UI hasn't allowed submission because
+ // the search input is still visible.
+ expect( searchInput ).toBeVisible();
}
);
} );
describe( 'Handling cancellation', () => {
- it( 'should allow cancellation of the link creation process and reset any entered values', async () => {
- const user = userEvent.setup();
+ it( 'should not show cancellation button during link creation', async () => {
const mockOnRemove = jest.fn();
- const mockOnCancel = jest.fn();
render( );
- // Search Input UI.
- const searchInput = screen.getByRole( 'combobox', {
- name: 'URL',
- } );
-
const cancelButton = screen.queryByRole( 'button', {
name: 'Cancel',
} );
- expect( cancelButton ).toBeEnabled();
- expect( cancelButton ).toBeVisible();
-
- // Simulate adding a link for a term.
- await user.type( searchInput, 'https://www.wordpress.org' );
-
- // Attempt to submit the empty search value in the input.
- await user.click( cancelButton );
-
- // Verify the consumer can handle the cancellation.
- expect( mockOnRemove ).toHaveBeenCalled();
-
- // Ensure optional callback is not called.
- expect( mockOnCancel ).not.toHaveBeenCalled();
-
- expect( searchInput ).toHaveValue( '' );
+ expect( cancelButton ).not.toBeInTheDocument();
} );
it( 'should allow cancellation of the link editing process and reset any entered values', async () => {
@@ -809,7 +808,7 @@ describe( 'Manual link entry', () => {
await toggleSettingsDrawer( user );
let searchInput = screen.getByRole( 'combobox', {
- name: 'URL',
+ name: 'Link',
} );
let textInput = screen.getByRole( 'textbox', {
@@ -844,7 +843,7 @@ describe( 'Manual link entry', () => {
// Re-query the inputs as they have been replaced.
searchInput = screen.getByRole( 'combobox', {
- name: 'URL',
+ name: 'Link',
} );
textInput = screen.getByRole( 'textbox', {
@@ -860,7 +859,13 @@ describe( 'Manual link entry', () => {
const user = userEvent.setup();
const mockOnCancel = jest.fn();
- render( );
+ render(
+
+ );
const cancelButton = screen.queryByRole( 'button', {
name: 'Cancel',
@@ -886,7 +891,7 @@ describe( 'Manual link entry', () => {
// Search Input UI.
const searchInput = screen.getByRole( 'combobox', {
- name: 'URL',
+ name: 'Link',
} );
// Simulate searching for a term.
@@ -922,7 +927,7 @@ describe( 'Default search suggestions', () => {
// Verify input has no value has default suggestions should only show
// when this does not have a value.
// Search Input UI.
- expect( screen.getByRole( 'combobox', { name: 'URL' } ) ).toHaveValue(
+ expect( screen.getByRole( 'combobox', { name: 'Link' } ) ).toHaveValue(
''
);
@@ -951,7 +956,7 @@ describe( 'Default search suggestions', () => {
} );
await user.click( currentLinkBtn );
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
// Search input is set to the URL value.
expect( searchInput ).toHaveValue( initialValue.url );
@@ -973,7 +978,7 @@ describe( 'Default search suggestions', () => {
render( );
// Search Input UI.
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
// Simulate searching for a term.
await user.type( searchInput, searchTerm );
@@ -1011,7 +1016,7 @@ describe( 'Default search suggestions', () => {
render( );
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
const searchResultsField = screen.queryByRole( 'listbox', {
name: 'Suggestions',
@@ -1069,7 +1074,9 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
render( );
// Search Input UI.
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
+ const searchInput = screen.getByRole( 'combobox', {
+ name: 'Link',
+ } );
// Simulate searching for a term.
await user.type( searchInput, entityNameText );
@@ -1136,7 +1143,7 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
render( );
// Search Input UI.
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
// Simulate searching for a term.
await user.type( searchInput, 'Some new page to create' );
@@ -1185,7 +1192,7 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
render( );
// Search Input UI.
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
// Simulate searching for a term.
await user.type( searchInput, entityNameText );
@@ -1228,7 +1235,7 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
render( );
// Search Input UI.
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
// Simulate searching for a term.
await user.type( searchInput, entityNameText );
@@ -1252,7 +1259,7 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
// Search Input UI.
const searchInput = screen.getByRole( 'combobox', {
- name: 'URL',
+ name: 'Link',
} );
const searchResultsField = screen.queryByRole( 'listbox' );
@@ -1272,7 +1279,9 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
);
// Search Input UI.
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
+ const searchInput = screen.getByRole( 'combobox', {
+ name: 'Link',
+ } );
const searchResultsField = screen.queryByRole( 'listbox' );
@@ -1295,7 +1304,7 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
// Search Input UI.
const searchInput = screen.getByRole( 'combobox', {
- name: 'URL',
+ name: 'Link',
} );
// Simulate searching for a term.
@@ -1329,7 +1338,7 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
render( );
// Search Input UI.
- searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
+ searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
// Simulate searching for a term.
await user.type( searchInput, searchText );
@@ -1344,7 +1353,7 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
await user.click( createButton );
- searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
+ searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
const errorNotice = screen.getAllByText(
'API response returned invalid entity.'
@@ -1417,7 +1426,7 @@ describe( 'Selecting links', () => {
// Simulate searching for a term.
await user.click( currentLinkBtn );
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
currentLinkUI = screen.queryByLabelText( 'Currently selected' );
// We should be back to showing the search input.
@@ -1458,7 +1467,7 @@ describe( 'Selecting links', () => {
// Search Input UI.
const searchInput = screen.getByRole( 'combobox', {
- name: 'URL',
+ name: 'Link',
} );
// Simulate searching for a term.
@@ -1520,7 +1529,7 @@ describe( 'Selecting links', () => {
// Search Input UI.
const searchInput = screen.getByRole( 'combobox', {
- name: 'URL',
+ name: 'Link',
} );
// Simulate searching for a term.
@@ -1609,7 +1618,9 @@ describe( 'Selecting links', () => {
).toBeVisible();
// Search Input UI.
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
+ const searchInput = screen.getByRole( 'combobox', {
+ name: 'Link',
+ } );
// Step down into the search results, highlighting the first result item.
triggerArrowDown( searchInput );
@@ -1665,7 +1676,9 @@ describe( 'Selecting links', () => {
render( );
// focus the search input
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
+ const searchInput = screen.getByRole( 'combobox', {
+ name: 'Link',
+ } );
fireEvent.focus( searchInput );
@@ -1707,10 +1720,7 @@ describe( 'Addition Settings UI', () => {
render( );
- const settingsToggle = screen.queryByRole( 'button', {
- name: 'Link Settings',
- ariaControls: 'link-settings-1',
- } );
+ const settingsToggle = getSettingsDrawerToggle();
expect( settingsToggle ).not.toBeInTheDocument();
} );
@@ -1727,10 +1737,7 @@ describe( 'Addition Settings UI', () => {
const user = userEvent.setup();
- const settingsToggle = screen.queryByRole( 'button', {
- name: 'Link Settings',
- ariaControls: 'link-settings-1',
- } );
+ const settingsToggle = getSettingsDrawerToggle();
expect( settingsToggle ).toHaveAttribute( 'aria-expanded', 'false' );
@@ -1891,7 +1898,7 @@ describe( 'Post types', () => {
render( );
// Search Input UI.
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
// Simulate searching for a term.
await user.type( searchInput, searchTerm );
@@ -1918,7 +1925,9 @@ describe( 'Post types', () => {
render( );
// Search Input UI.
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
+ const searchInput = screen.getByRole( 'combobox', {
+ name: 'Link',
+ } );
// Simulate searching for a term.
await user.type( searchInput, searchTerm );
@@ -2376,10 +2385,14 @@ describe( 'Controlling link title text', () => {
} );
} );
-async function toggleSettingsDrawer( user ) {
- const settingsToggle = screen.queryByRole( 'button', {
- name: 'Link Settings',
+function getSettingsDrawerToggle() {
+ return screen.queryByRole( 'button', {
+ name: 'Advanced',
} );
+}
+
+async function toggleSettingsDrawer( user ) {
+ const settingsToggle = getSettingsDrawerToggle();
await user.click( settingsToggle );
}
diff --git a/packages/block-editor/src/components/media-replace-flow/test/index.js b/packages/block-editor/src/components/media-replace-flow/test/index.js
index 2be7e7372260df..cef747ce6be639 100644
--- a/packages/block-editor/src/components/media-replace-flow/test/index.js
+++ b/packages/block-editor/src/components/media-replace-flow/test/index.js
@@ -128,7 +128,7 @@ describe( 'General media replace flow', () => {
);
const mediaURLInput = screen.getByRole( 'combobox', {
- name: 'URL',
+ name: 'Link',
expanded: false,
} );
diff --git a/packages/block-editor/src/components/url-input/index.js b/packages/block-editor/src/components/url-input/index.js
index eb448f79d1b3f5..1451397ce68e5f 100644
--- a/packages/block-editor/src/components/url-input/index.js
+++ b/packages/block-editor/src/components/url-input/index.js
@@ -434,6 +434,7 @@ class URLInput extends Component {
placeholder = __( 'Paste URL or type to search' ),
__experimentalRenderControl: renderControl,
value = '',
+ hideLabelFromVision = false,
} = this.props;
const {
@@ -452,6 +453,7 @@ class URLInput extends Component {
className: classnames( 'block-editor-url-input', className, {
'is-full-width': isFullWidth,
} ),
+ hideLabelFromVision,
};
const inputProps = {
diff --git a/packages/e2e-tests/specs/editor/various/links.test.js b/packages/e2e-tests/specs/editor/various/links.test.js
index 3be80f786fbc28..719d00afe076bb 100644
--- a/packages/e2e-tests/specs/editor/various/links.test.js
+++ b/packages/e2e-tests/specs/editor/various/links.test.js
@@ -105,7 +105,8 @@ describe( 'Links', () => {
await waitForURLFieldAutoFocus();
const urlInputValue = await page.evaluate(
- () => document.querySelector( '[aria-label="URL"]' ).value
+ () =>
+ document.querySelector( '.block-editor-url-input__input' ).value
);
expect( urlInputValue ).toBe( '' );
@@ -496,7 +497,7 @@ describe( 'Links', () => {
await pressKeyWithModifier( 'primary', 'K' );
const [ settingsToggle ] = await page.$x(
- '//button[contains(@aria-label, "Link Settings")]'
+ '//button[contains(text(), "Advanced")]'
);
await settingsToggle.click();
@@ -528,7 +529,7 @@ describe( 'Links', () => {
await waitForURLFieldAutoFocus();
- await page.keyboard.press( 'Tab' );
+ await pressKeyWithModifier( 'shift', 'Tab' );
// Tabbing should land us in the text input.
const { isTextInput, textValue } = await page.evaluate( () => {
@@ -585,8 +586,10 @@ describe( 'Links', () => {
await editButton.click();
- // Tabbing forward should land us in the "Text" input.
- await page.keyboard.press( 'Tab' );
+ await waitForURLFieldAutoFocus();
+
+ // Tabbing backward should land us in the "Text" input.
+ await pressKeyWithModifier( 'shift', 'Tab' );
const textInputValue = await page.evaluate(
() => document.activeElement.value
@@ -614,8 +617,9 @@ describe( 'Links', () => {
);
await editButton.click();
- // tab forward to the text input.
- await page.keyboard.press( 'Tab' );
+ await waitForURLFieldAutoFocus();
+
+ await pressKeyWithModifier( 'shift', 'Tab' );
const textInputValue = await page.evaluate(
() => document.activeElement.value
@@ -661,7 +665,7 @@ describe( 'Links', () => {
await waitForURLFieldAutoFocus();
const [ settingsToggle ] = await page.$x(
- '//button[contains(@aria-label, "Link Settings")]'
+ '//button[contains(text(), "Advanced")]'
);
await settingsToggle.click();
@@ -679,7 +683,7 @@ describe( 'Links', () => {
await pressKeyWithModifier( 'shift', 'ArrowRight' );
// Move back to the text input.
- await pressKeyTimes( 'Tab', 2 );
+ await pressKeyTimes( 'Tab', 1 );
// Tabbing back should land us in the text input.
const textInputValue = await page.evaluate(
@@ -879,8 +883,11 @@ describe( 'Links', () => {
await waitForURLFieldAutoFocus();
- // Move to Link Text field.
- await page.keyboard.press( 'Tab' );
+ // Move to "Text" field.
+ await pressKeyWithModifier( 'shift', 'Tab' );
+
+ // Delete existing value from "Text" field
+ await page.keyboard.press( 'Delete' );
// Change text to "z"
await page.keyboard.type( 'z' );
diff --git a/test/e2e/specs/editor/blocks/buttons.spec.js b/test/e2e/specs/editor/blocks/buttons.spec.js
index 8eacb7e2bed2e9..d6bdcb167f9ac9 100644
--- a/test/e2e/specs/editor/blocks/buttons.spec.js
+++ b/test/e2e/specs/editor/blocks/buttons.spec.js
@@ -10,6 +10,9 @@ test.describe( 'Buttons', () => {
test( 'has focus on button content', async ( { editor, page } ) => {
await editor.insertBlock( { name: 'core/buttons' } );
+ await expect(
+ editor.canvas.locator( 'role=textbox[name="Button text"i]' )
+ ).toBeFocused();
await page.keyboard.type( 'Content' );
// Check the content.
@@ -50,9 +53,12 @@ test.describe( 'Buttons', () => {
} ) => {
// Regression: https://github.com/WordPress/gutenberg/pull/19885
await editor.insertBlock( { name: 'core/buttons' } );
+ await expect(
+ editor.canvas.locator( 'role=textbox[name="Button text"i]' )
+ ).toBeFocused();
await pageUtils.pressKeys( 'primary+k' );
await expect(
- page.locator( 'role=combobox[name="URL"i]' )
+ page.locator( 'role=combobox[name="Link"i]' )
).toBeFocused();
await page.keyboard.press( 'Escape' );
await expect(
@@ -78,9 +84,12 @@ test.describe( 'Buttons', () => {
} ) => {
// Regression: https://github.com/WordPress/gutenberg/issues/34307
await editor.insertBlock( { name: 'core/buttons' } );
+ await expect(
+ editor.canvas.locator( 'role=textbox[name="Button text"i]' )
+ ).toBeFocused();
await pageUtils.pressKeys( 'primary+k' );
await expect(
- page.locator( 'role=combobox[name="URL"i]' )
+ page.locator( 'role=combobox[name="Link"i]' )
).toBeFocused();
await page.keyboard.type( 'https://example.com' );
await page.keyboard.press( 'Enter' );
@@ -107,9 +116,12 @@ test.describe( 'Buttons', () => {
} ) => {
// Regression: https://github.com/WordPress/gutenberg/issues/34307
await editor.insertBlock( { name: 'core/buttons' } );
+ await expect(
+ editor.canvas.locator( 'role=textbox[name="Button text"i]' )
+ ).toBeFocused();
await pageUtils.pressKeys( 'primary+k' );
- const urlInput = page.locator( 'role=combobox[name="URL"i]' );
+ const urlInput = page.locator( 'role=combobox[name="Link"i]' );
await expect( urlInput ).toBeFocused();
await page.keyboard.type( 'example.com' );
diff --git a/test/e2e/specs/editor/blocks/links.spec.js b/test/e2e/specs/editor/blocks/links.spec.js
index 6493b9effe8aab..8443a04d0417e6 100644
--- a/test/e2e/specs/editor/blocks/links.spec.js
+++ b/test/e2e/specs/editor/blocks/links.spec.js
@@ -28,8 +28,32 @@ test.describe( 'Links', () => {
// Type a URL.
await page.keyboard.type( 'https://wordpress.org/gutenberg' );
+ // Ensure that the contents of the post have not been changed, since at
+ // this point the link is still not inserted.
+ await expect.poll( editor.getBlocks ).toMatchObject( [
+ {
+ name: 'core/paragraph',
+ attributes: { content: 'This is Gutenberg' },
+ },
+ ] );
+
+ await page.keyboard.press( 'Enter' );
+
+ await page.keyboard.press( 'ArrowLeft' );
+ await page.keyboard.press( 'ArrowLeft' );
+
+ // Edit link.
+ await page.getByRole( 'button', { name: 'Edit' } ).click();
+
// Open settings.
- await page.getByRole( 'button', { name: 'Link Settings' } ).click();
+ await page
+ .getByRole( 'region', {
+ name: 'Editor content',
+ } )
+ .getByRole( 'button', {
+ name: 'Advanced',
+ } )
+ .click();
// Navigate to and toggle the "Open in new tab" checkbox.
const checkbox = page.getByLabel( 'Open in new tab' );
@@ -39,15 +63,6 @@ test.describe( 'Links', () => {
await expect( checkbox ).toBeChecked();
await expect( checkbox ).toBeFocused();
- // Ensure that the contents of the post have not been changed, since at
- // this point the link is still not inserted.
- await expect.poll( editor.getBlocks ).toMatchObject( [
- {
- name: 'core/paragraph',
- attributes: { content: 'This is Gutenberg' },
- },
- ] );
-
// Tab back to the Submit and apply the link.
await page
//TODO: change to a better selector when https://github.com/WordPress/gutenberg/issues/51060 is resolved.
@@ -82,11 +97,7 @@ test.describe( 'Links', () => {
await pageUtils.pressKeys( 'primary+k' );
await page.keyboard.type( 'w.org' );
- await page
- //TODO: change to a better selector when https://github.com/WordPress/gutenberg/issues/51060 is resolved.
- .locator( '.block-editor-link-control' )
- .getByRole( 'button', { name: 'Save' } )
- .click();
+ await page.keyboard.press( 'Enter' );
await expect.poll( editor.getBlocks ).toMatchObject( [
{
@@ -107,7 +118,11 @@ test.describe( 'Links', () => {
await page.keyboard.type( 'wordpress.org' );
// Update the link.
- await page.keyboard.press( 'Enter' );
+ await page
+ //TODO: change to a better selector when https://github.com/WordPress/gutenberg/issues/51060 is resolved.
+ .locator( '.block-editor-link-control' )
+ .getByRole( 'button', { name: 'Save' } )
+ .click();
// Navigate back to the popover.
await page.keyboard.press( 'ArrowLeft' );
diff --git a/test/e2e/specs/editor/blocks/navigation.spec.js b/test/e2e/specs/editor/blocks/navigation.spec.js
index 67b48d528adc70..8f45e8ddcf7e34 100644
--- a/test/e2e/specs/editor/blocks/navigation.spec.js
+++ b/test/e2e/specs/editor/blocks/navigation.spec.js
@@ -902,7 +902,7 @@ test.describe( 'Navigation block', () => {
// Immediately dismiss the Link UI thereby not populating the `url` attribute
// of the block.
- await linkControl.pressCancel();
+ await page.keyboard.press( 'Escape' );
// Get the Inspector Tabs.
const blockSettings = page.getByRole( 'region', {
@@ -1263,18 +1263,10 @@ class LinkControl {
getSearchInput() {
return this.page.getByRole( 'combobox', {
- name: 'URL',
+ name: 'Link',
} );
}
- async pressCancel() {
- const cancelButton = this.page.getByRole( 'button', {
- name: 'Cancel',
- } );
-
- return cancelButton.click();
- }
-
async getSearchResults() {
const searchInput = this.getSearchInput();