Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update LinkControl component to utilitse dynamic settings for additional settings "drawer" #18285

Merged
merged 10 commits into from
Nov 6, 2019
38 changes: 35 additions & 3 deletions packages/block-editor/src/components/link-control/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,20 @@

### currentSettings

- Type: `Object`
- Required: Yes
- Type: `Array`
- Required: No
- Default:
```
[
{
id: 'newTab',
title: 'Open in New Tab',
checked: false,
},
];
```

An array of settings objects. Each object will used to render a `ToggleControl` for that setting. See also `onSettingsChange`.

### fetchSearchSuggestions

Expand Down Expand Up @@ -71,7 +83,27 @@ The function callback will receive the selected item, or Null.
/>
```

### onSettingChange
### onSettingsChange

- Type: `Function`
- Required: No
- Args:
- `id` - the `id` property of the setting that changed (eg: `newTab`).
- `value` - the `checked` value of the control.
- `settings` - the current settings object.

Called when any of the settings supplied as `currentSettings` are changed/toggled. May be used to attribute a Block's `attributes` with the current state of the control.

```
<LinkControl
currentSettings={ [
{
id: 'opensInNewTab',
title: __( 'Open in New Tab' ),
checked: attributes.opensInNewTab, // Block attributes persist control state
},
] }
onSettingsChange={ ( setting, value ) => setAttributes( { [ setting ]: value } ) }
/>
```

2 changes: 1 addition & 1 deletion packages/block-editor/src/components/link-control/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ function LinkControl( {
onKeyDown = noop,
onKeyPress = noop,
onLinkChange = noop,
onSettingsChange = { noop },
onSettingsChange = noop,
} ) {
// State
const [ inputValue, setInputValue ] = useState( '' );
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
import { partial } from 'lodash';
import { noop } from 'lodash';

/**
* WordPress dependencies
Expand All @@ -11,18 +11,39 @@ import {
ToggleControl,
} from '@wordpress/components';

const LinkControlSettingsDrawer = ( { settings, onSettingChange } ) => {
if ( ! settings || settings.length ) {
const defaultSettings = [
{
id: 'newTab',
title: __( 'Open in New Tab' ),
checked: false,
},
];

const LinkControlSettingsDrawer = ( { settings = defaultSettings, onSettingChange = noop } ) => {
if ( ! settings || ! settings.length ) {
return null;
}

const handleSettingChange = ( setting ) => ( value ) => {
onSettingChange( setting.id, value, settings );
};

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

return (
<div className="block-editor-link-control__settings">
<ToggleControl
label={ __( 'Open in New Tab' ) }
onChange={ partial( onSettingChange, 'new-tab' ) }
checked={ settings[ 'new-tab' ] } />
</div>
<fieldset className="block-editor-link-control__settings">
<legend className="screen-reader-text">
{ __( 'Currently selected link settings' ) }
</legend>
{ theSettings }
</fieldset>
);
};

Expand Down
8 changes: 8 additions & 0 deletions packages/block-editor/src/components/link-control/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,14 @@
}
}

.block-editor-link-control__setting {
margin-bottom: $grid-size-large;

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

.block-editor-link-control .block-editor-link-control__search-input .components-spinner {
display: block;
z-index: 100;
Expand Down
91 changes: 91 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 @@ -536,3 +536,94 @@ describe( 'Selecting links', () => {
} );
} );
} );

describe( 'Addition Settings UI', () => {
it( 'should display "New Tab" setting (in "off" mode) by default when a link is selected', async () => {
const selectedLink = first( fauxEntitySuggestions );
const expectedSettingText = 'Open in New Tab';

const LinkControlConsumer = () => {
const [ link ] = useState( selectedLink );

return (
<LinkControl
currentLink={ link }
fetchSearchSuggestions={ fetchFauxEntitySuggestions }
/>
);
};

act( () => {
render(
<LinkControlConsumer />, container
);
} );

// console.log( container.innerHTML );

const newTabSettingLabel = Array.from( container.querySelectorAll( 'label' ) ).find( ( label ) => label.innerHTML && label.innerHTML.includes( expectedSettingText ) );
expect( newTabSettingLabel ).not.toBeUndefined(); // find() returns "undefined" if not found

const newTabSettingLabelForAttr = newTabSettingLabel.getAttribute( 'for' );
const newTabSettingInput = container.querySelector( `#${ newTabSettingLabelForAttr }` );
expect( newTabSettingInput ).not.toBeNull();
expect( newTabSettingInput.checked ).toBe( false );
} );

it( 'should display a setting control with correct default state for each of the custom settings provided', async () => {
const selectedLink = first( fauxEntitySuggestions );

const customSettings = [
{
id: 'newTab',
title: 'Open in New Tab',
checked: false,
},
{
id: 'noFollow',
title: 'No follow',
checked: true,
},
];

const customSettingsLabelsText = customSettings.map( ( setting ) => setting.title );

const LinkControlConsumer = () => {
const [ link ] = useState( selectedLink );

return (
<LinkControl
currentLink={ link }
fetchSearchSuggestions={ fetchFauxEntitySuggestions }
currentSettings={ customSettings }
/>
);
};

act( () => {
render(
<LinkControlConsumer />, container
);
} );

// Grab the elements using user perceivable DOM queries
const settingsLegend = Array.from( container.querySelectorAll( 'legend' ) ).find( ( legend ) => legend.innerHTML && legend.innerHTML.includes( 'Currently selected link settings' ) );
const settingsFieldset = settingsLegend.closest( 'fieldset' );
const settingControlsLabels = Array.from( settingsFieldset.querySelectorAll( 'label' ) );
const settingControlsInputs = settingControlsLabels.map( ( label ) => {
return settingsFieldset.querySelector( `#${ label.getAttribute( 'for' ) }` );
} );

const settingControlLabelsText = Array.from( settingControlsLabels ).map( ( label ) => label.innerHTML );

// Check we have the correct number of controls
expect( settingControlsLabels ).toHaveLength( 2 );

// Check the labels match
expect( settingControlLabelsText ).toEqual( expect.arrayContaining( customSettingsLabelsText ) );

// Assert the default "checked" states match the expected
expect( settingControlsInputs[ 0 ].checked ).toEqual( false );
expect( settingControlsInputs[ 1 ].checked ).toEqual( true );
} );
} );
12 changes: 8 additions & 4 deletions packages/block-library/src/navigation-menu-item/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,7 @@ import { Fragment, useState, useEffect } from '@wordpress/element';
* @param {Function} setter Setter attribute function.
*/
const updateLinkSetting = ( setter ) => ( setting, value ) => {
if ( setting === 'new-tab' ) {
setter( { opensInNewTab: value } );
}
setter( { [ setting ]: value } );
};

/**
Expand Down Expand Up @@ -217,7 +215,13 @@ function NavigationMenuItemEdit( {
onClose={ () => {
onCloseTimerId = setTimeout( () => setIsLinkOpen( false ), 100 );
} }
currentSettings={ { 'new-tab': opensInNewTab } }
currentSettings={ [
{
id: 'opensInNewTab',
title: __( 'Open in New Tab' ),
checked: opensInNewTab,
},
] }
onSettingsChange={ updateLinkSetting( setAttributes ) }
/>
) }
Expand Down