Skip to content

Commit

Permalink
Add Unlink button to LinkControl popover (#32541)
Browse files Browse the repository at this point in the history
* Adds initial Unlink button

* Add dedicated opt in prop for removing links

* Add tests

* Update docs

* Focus PR by removing unneeded onChange handler change

* Use more accessible query for button

Resolves #32541 (comment)

* Remove checking if onRemove is a function.
  • Loading branch information
getdave authored Jun 30, 2021
1 parent 2f79891 commit 6eac4a2
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 6 deletions.
8 changes: 8 additions & 0 deletions packages/block-editor/src/components/link-control/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,14 @@ This `suggestion` will then be _automatically_ passed to the `onChange` handler

As a result of the above, this prop is often used to allow on the fly creation of new entities (eg: `Posts`, `Pages`) based on the text the user has entered into the link search UI. As an example, the Navigation Block uses `createSuggestion` to create Pages on the fly from within the Block itself.

### onRemove

- Type: `Function`
- Required: No
- Default: null

An optional handler, which when passed will trigger the display of an `Unlink` UI within the control. This handler is expected to remove the current `value` of the control thus resetting it back to a default state. The key use case for this is allowing users to remove a link from the control without relying on there being an "unlink" control in the block toolbar.

#### Search `suggestion` values

A `suggestion` should have the following shape:
Expand Down
23 changes: 18 additions & 5 deletions packages/block-editor/src/components/link-control/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ function LinkControl( {
value,
settings,
onChange = noop,
onRemove,
noDirectEntry = false,
showSuggestions = true,
showInitialSuggestions,
Expand Down Expand Up @@ -260,11 +261,23 @@ function LinkControl( {
/>
) }

<LinkControlSettingsDrawer
value={ value }
settings={ settings }
onChange={ onChange }
/>
<div className="block-editor-link-control__tools">
<LinkControlSettingsDrawer
value={ value }
settings={ settings }
onChange={ onChange }
/>
{ onRemove && value && ! isEditingLink && ! isCreatingPage && (
<Button
className="block-editor-link-control__unlink"
isDestructive
variant="link"
onClick={ onRemove }
>
{ __( 'Unlink' ) }
</Button>
) }
</div>
</div>
);
}
Expand Down
15 changes: 14 additions & 1 deletion packages/block-editor/src/components/link-control/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -380,10 +380,23 @@ $preview-image-height: 140px;
padding: 10px;
}

.block-editor-link-control__settings {
.block-editor-link-control__tools {
display: flex;
align-items: center;
border-top: $border-width solid $gray-300;
margin: 0;
padding: $grid-unit-20 $grid-unit-30;
}

.block-editor-link-control__unlink {
padding-left: $grid-unit-20;
padding-right: $grid-unit-20;
}

.block-editor-link-control__settings {
flex: 1;
margin: 0;


:last-child {
margin-bottom: 0;
Expand Down
43 changes: 43 additions & 0 deletions packages/block-editor/src/components/link-control/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,49 @@ describe( 'Basic rendering', () => {
expect( isEditing() ).toBe( false );
} );
} );

describe( 'Unlinking', () => {
it( 'should not show "Unlink" button if no onRemove handler is provided', () => {
act( () => {
render(
<LinkControl value={ { url: 'https://example.com' } } />,
container
);
} );

const unLinkButton = queryByRole( container, 'button', {
name: 'Unlink',
} );

expect( unLinkButton ).toBeNull();
expect( unLinkButton ).not.toBeInTheDocument();
} );

it( 'should show "Unlink" button if a onRemove handler is provided', () => {
const mockOnRemove = jest.fn();
act( () => {
render(
<LinkControl
value={ { url: 'https://example.com' } }
onRemove={ mockOnRemove }
/>,
container
);
} );

const unLinkButton = queryByRole( container, 'button', {
name: 'Unlink',
} );
expect( unLinkButton ).toBeTruthy();
expect( unLinkButton ).toBeInTheDocument();

act( () => {
Simulate.click( unLinkButton );
} );

expect( mockOnRemove ).toHaveBeenCalled();
} );
} );
} );

describe( 'Searching for a link', () => {
Expand Down
9 changes: 9 additions & 0 deletions packages/format-library/src/link/inline.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
isCollapsed,
applyFormat,
useAnchorRef,
removeFormat,
} from '@wordpress/rich-text';
import { __experimentalLinkControl as LinkControl } from '@wordpress/block-editor';

Expand Down Expand Up @@ -48,6 +49,13 @@ function InlineLinkUI( {
...nextLinkValue,
};

function removeLink() {
const newValue = removeFormat( value, 'core/link' );
onChange( newValue );
stopAddingLink();
speak( __( 'Link removed.' ), 'assertive' );
}

function onChangeLink( nextValue ) {
// Merge with values from state, both for the purpose of assigning the
// next state value, and for use in constructing the new link format if
Expand Down Expand Up @@ -139,6 +147,7 @@ function InlineLinkUI( {
<LinkControl
value={ linkValue }
onChange={ onChangeLink }
onRemove={ removeLink }
forceIsEditingLink={ addingLink }
hasRichPreviews
/>
Expand Down

0 comments on commit 6eac4a2

Please sign in to comment.