Skip to content

Commit

Permalink
Add settings "drawer" to Link Control (#47328)
Browse files Browse the repository at this point in the history
* Add basic panel toggle

* Implement drawer like effect

* Implement basic animation

* Update to have drawer below button

* Update timing to 0.2s

* Fix janky animation

* Close settings drawer when editing is stopped

* Fix input overflowing in settings drawer

* Disable animations when user requests reduced motion

* Force no animations in component tests

* Fix text input tests broken due to move into settings drawer

* Fix remaining tests broken by settings drawer

* speed up animation

* Move drawer to dedicated component

* Add test for settings drawer with unique ID

* Check for aria expanded attribute

* Avoid extra div when reduced motion is active

* Don’t show settings unless in edit mode

* Add test for link settings toggle not being displayed unless editing

* Fix e2e tests due to change of text input location

* Fix more e2e tests

* Fix final e2e test

* Fix e2e test that arrived following rebase

---------

Co-authored-by: scruffian <ben@escruffian.com>
  • Loading branch information
getdave and scruffian authored Feb 7, 2023
1 parent b66cf58 commit d142cb0
Show file tree
Hide file tree
Showing 6 changed files with 326 additions and 76 deletions.
44 changes: 22 additions & 22 deletions packages/block-editor/src/components/link-control/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import classnames from 'classnames';
/**
* WordPress dependencies
*/
import { Button, Spinner, Notice, TextControl } from '@wordpress/components';
import { Button, Spinner, Notice } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { useRef, useState, useEffect } from '@wordpress/element';
import { focus } from '@wordpress/dom';
Expand Down Expand Up @@ -136,6 +136,8 @@ function LinkControl( {
const textInputRef = useRef();
const isEndingEditWithFocus = useRef( false );

const [ settingsOpen, setSettingsOpen ] = useState( false );

const [ internalUrlInputValue, setInternalUrlInputValue ] =
useInternalInputValue( value?.url || '' );

Expand Down Expand Up @@ -201,6 +203,7 @@ function LinkControl( {
wrapperNode.current.ownerDocument.activeElement
);

setSettingsOpen( false );
setIsEditingLink( false );
};

Expand Down Expand Up @@ -267,14 +270,15 @@ function LinkControl( {
const shownUnlinkControl =
onRemove && value && ! isEditingLink && ! isCreatingPage;

const showSettingsDrawer = !! settings?.length;
const showSettings = !! settings?.length;

// Only show text control once a URL value has been committed
// and it isn't just empty whitespace.
// See https://github.com/WordPress/gutenberg/pull/33849/#issuecomment-932194927.
const showTextControl = hasLinkValue && hasTextControl;

const isEditing = ( isEditingLink || ! value ) && ! isCreatingPage;

return (
<div
tabIndex={ -1 }
Expand All @@ -295,18 +299,6 @@ function LinkControl( {
'has-text-control': showTextControl,
} ) }
>
{ showTextControl && (
<TextControl
__nextHasNoMarginBottom
ref={ textInputRef }
className="block-editor-link-control__field block-editor-link-control__text-content"
label="Text"
value={ internalTextInputValue }
onChange={ setInternalTextInputValue }
onKeyDown={ handleSubmitWithEnter }
/>
) }

<LinkControlSearchInput
currentLink={ value }
className="block-editor-link-control__field block-editor-link-control__search-input"
Expand Down Expand Up @@ -350,18 +342,26 @@ function LinkControl( {
/>
) }

<div className="block-editor-link-control__drawer">
{ showSettingsDrawer && (
<div className="block-editor-link-control__tools">
{ isEditing && (
<div className="block-editor-link-control__tools">
{ ( showSettings || showTextControl ) && (
<LinkControlSettingsDrawer
settingsOpen={ settingsOpen }
setSettingsOpen={ setSettingsOpen }
showTextControl={ showTextControl }
showSettings={ showSettings }
textInputRef={ textInputRef }
internalTextInputValue={ internalTextInputValue }
setInternalTextInputValue={
setInternalTextInputValue
}
handleSubmitWithEnter={ handleSubmitWithEnter }
value={ value }
settings={ settings }
onChange={ onChange }
/>
</div>
) }
) }

{ isEditing && (
<div className="block-editor-link-control__search-actions">
<Button
variant="primary"
Expand All @@ -375,8 +375,8 @@ function LinkControl( {
{ __( 'Cancel' ) }
</Button>
</div>
) }
</div>
</div>
) }

{ renderControlBottom && renderControlBottom() }
</div>
Expand Down
115 changes: 85 additions & 30 deletions packages/block-editor/src/components/link-control/settings-drawer.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,96 @@
/**
* WordPress dependencies
*/
import {
Button,
TextControl,
__unstableMotion as motion,
__unstableAnimatePresence as AnimatePresence,
} from '@wordpress/components';
import { settings as settingsIcon } from '@wordpress/icons';
import { useReducedMotion, useInstanceId } from '@wordpress/compose';
import { __ } from '@wordpress/i18n';
import { ToggleControl, VisuallyHidden } from '@wordpress/components';

const noop = () => {};
import { Fragment } from '@wordpress/element';
/**
* Internal dependencies
*/
import Settings from './settings';

const LinkControlSettingsDrawer = ( { value, onChange = noop, settings } ) => {
if ( ! settings || ! settings.length ) {
return null;
}
function LinkSettingsDrawer( {
settingsOpen,
setSettingsOpen,
showTextControl,
showSettings,
textInputRef,
internalTextInputValue,
setInternalTextInputValue,
handleSubmitWithEnter,
value,
settings,
onChange,
} ) {
const prefersReducedMotion = useReducedMotion();
const MaybeAnimatePresence = prefersReducedMotion
? Fragment
: AnimatePresence;
const MaybeMotionDiv = prefersReducedMotion ? 'div' : motion.div;

const handleSettingChange = ( setting ) => ( newValue ) => {
onChange( {
...value,
[ setting.id ]: newValue,
} );
};
const id = useInstanceId( LinkSettingsDrawer );

const theSettings = settings.map( ( setting ) => (
<ToggleControl
className="block-editor-link-control__setting"
key={ setting.id }
label={ setting.title }
onChange={ handleSettingChange( setting ) }
checked={ value ? !! value[ setting.id ] : false }
/>
) );
const settingsDrawerId = `link-control-settings-drawer-${ id }`;

return (
<fieldset className="block-editor-link-control__settings">
<VisuallyHidden as="legend">
{ __( 'Currently selected link settings' ) }
</VisuallyHidden>
{ theSettings }
</fieldset>
<>
<Button
className="block-editor-link-control__drawer-toggle"
aria-expanded={ settingsOpen }
onClick={ () => setSettingsOpen( ! settingsOpen ) }
icon={ settingsIcon }
label={ __( 'Toggle link settings' ) }
aria-controls={ settingsDrawerId }
/>
<MaybeAnimatePresence>
{ settingsOpen && (
<MaybeMotionDiv
className="block-editor-link-control__drawer"
hidden={ ! settingsOpen }
id={ settingsDrawerId }
initial="collapsed"
animate="open"
exit="collapsed"
variants={ {
open: { opacity: 1, height: 'auto' },
collapsed: { opacity: 0, height: 0 },
} }
transition={ {
duration: 0.1,
} }
>
<div className="block-editor-link-control__drawer-inner">
{ showTextControl && (
<TextControl
__nextHasNoMarginBottom
ref={ textInputRef }
className="block-editor-link-control__setting block-editor-link-control__text-content"
label="Text"
value={ internalTextInputValue }
onChange={ setInternalTextInputValue }
onKeyDown={ handleSubmitWithEnter }
/>
) }
{ showSettings && (
<Settings
value={ value }
settings={ settings }
onChange={ onChange }
/>
) }
</div>
</MaybeMotionDiv>
) }
</MaybeAnimatePresence>
</>
);
};
}

export default LinkControlSettingsDrawer;
export default LinkSettingsDrawer;
41 changes: 41 additions & 0 deletions packages/block-editor/src/components/link-control/settings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { ToggleControl, VisuallyHidden } from '@wordpress/components';

const noop = () => {};

const LinkControlSettings = ( { value, onChange = noop, settings } ) => {
if ( ! settings || ! settings.length ) {
return null;
}

const handleSettingChange = ( setting ) => ( newValue ) => {
onChange( {
...value,
[ setting.id ]: newValue,
} );
};

const theSettings = settings.map( ( setting ) => (
<ToggleControl
className="block-editor-link-control__setting"
key={ setting.id }
label={ setting.title }
onChange={ handleSettingChange( setting ) }
checked={ value ? !! value[ setting.id ] : false }
/>
) );

return (
<fieldset className="block-editor-link-control__settings">
<VisuallyHidden as="legend">
{ __( 'Currently selected link settings' ) }
</VisuallyHidden>
{ theSettings }
</fieldset>
);
};

export default LinkControlSettings;
40 changes: 33 additions & 7 deletions packages/block-editor/src/components/link-control/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ $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;
order: 20;
}

.components-button .block-editor-link-control__search-submit .has-icon {
Expand Down Expand Up @@ -427,12 +428,42 @@ $preview-image-height: 140px;
}

.block-editor-link-control__drawer {
display: flex; // allow for ordering.
order: 30;
flex-direction: column;
flex-basis: 100%; // occupy full width.
}

// Inner div required to avoid padding/margin
// causing janky animation.
.block-editor-link-control__drawer-inner {
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;
border-top: $border-width solid $gray-300;
margin: 0;
padding: $grid-unit-20;
padding-top: 0;
}

.block-editor-link-control__unlink {
Expand All @@ -444,11 +475,6 @@ $preview-image-height: 140px;
flex: 1;
margin: 0;


:last-child {
margin-bottom: 0;
}

.is-alternate & {
border-top: $border-width solid $gray-900;
}
Expand All @@ -457,7 +483,7 @@ $preview-image-height: 140px;
.block-editor-link-control__setting {
margin-bottom: $grid-unit-20;

:last-child {
&.block-editor-link-control__setting:last-child {
margin-bottom: 0;
}
}
Expand Down
Loading

1 comment on commit d142cb0

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flaky tests detected in d142cb0.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/4112641351
📝 Reported issues:

Please sign in to comment.