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

Fix insertion point in Widgets editors #33802

Merged
merged 3 commits into from
Aug 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions packages/customize-widgets/src/components/inserter/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,22 @@ import { __ } from '@wordpress/i18n';
import { __experimentalLibrary as Library } from '@wordpress/block-editor';
import { Button } from '@wordpress/components';
import { useInstanceId } from '@wordpress/compose';
import { useSelect } from '@wordpress/data';
import { closeSmall } from '@wordpress/icons';

/**
* Internal dependencies
*/
import { store as customizeWidgetsStore } from '../../store';

function Inserter( { setIsOpened } ) {
const inserterTitleId = useInstanceId(
Inserter,
'customize-widget-layout__inserter-panel-title'
);
const insertionPoint = useSelect( ( select ) =>
select( customizeWidgetsStore ).__experimentalGetInsertionPoint()
);

return (
<div
Expand All @@ -34,6 +43,10 @@ function Inserter( { setIsOpened } ) {
</div>
<div className="customize-widgets-layout__inserter-panel-content">
<Library
rootClientId={ insertionPoint.rootClientId }
__experimentalInsertionIndex={
insertionPoint.insertionIndex
}
showInserterHelpPanel
onSelect={ () => setIsOpened( false ) }
/>
Expand Down
33 changes: 21 additions & 12 deletions packages/customize-widgets/src/components/inserter/use-inserter.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,42 @@
/**
* WordPress dependencies
*/
import { useState, useEffect, useCallback } from '@wordpress/element';
import { useEffect, useCallback } from '@wordpress/element';
import { useSelect, useDispatch, select as selectStore } from '@wordpress/data';

/**
* Internal dependencies
*/
import { store as customizeWidgetsStore } from '../../store';

export default function useInserter( inserter ) {
const [ isInserterOpened, setIsInserterOpened ] = useState(
() => inserter.isOpen
const isInserterOpened = useSelect( ( select ) =>
select( customizeWidgetsStore ).isInserterOpened()
);
const { setIsInserterOpened } = useDispatch( customizeWidgetsStore );

useEffect( () => {
return inserter.subscribe( setIsInserterOpened );
}, [ inserter ] );
if ( isInserterOpened ) {
inserter.open();
} else {
inserter.close();
}
}, [ inserter, isInserterOpened ] );

return [
isInserterOpened,
useCallback(
( updater ) => {
let isOpen = updater;
if ( typeof updater === 'function' ) {
isOpen = updater( inserter.isOpen );
isOpen = updater(
selectStore( customizeWidgetsStore ).isInserterOpened()
);
}

if ( isOpen ) {
inserter.open();
} else {
inserter.close();
}
setIsInserterOpened( isOpen );
},
[ inserter ]
[ setIsInserterOpened ]
),
];
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ export default function SidebarBlockEditor( {
blockEditorSettings,
isFixedToolbarActive,
keepCaretInsideBlock,
setIsInserterOpened,
] );

if ( isWelcomeGuideActive ) {
Expand Down
40 changes: 29 additions & 11 deletions packages/customize-widgets/src/controls/inserter-outer-section.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
*/
import { ESCAPE } from '@wordpress/keycodes';
import { focus } from '@wordpress/dom';
import { dispatch } from '@wordpress/data';

/**
* Internal dependencies
*/
import { store as customizeWidgetsStore } from '../store';

export default function getInserterOuterSection() {
const {
Expand Down Expand Up @@ -52,35 +58,45 @@ export default function getInserterOuterSection() {
'keydown',
( event ) => {
if (
this.isOpen &&
this.expanded() &&
( event.keyCode === ESCAPE ||
event.code === 'Escape' ) &&
! event.defaultPrevented
) {
event.preventDefault();
event.stopPropagation();
this.close();
dispatch( customizeWidgetsStore ).setIsInserterOpened(
false
);
}
},
// Use capture mode to make this run before other event listeners.
true
);

this.contentContainer.addClass( 'widgets-inserter' );
}
get isOpen() {
return this.expanded();
}
subscribe( handler ) {
this.expanded.bind( handler );
return () => this.expanded.unbind( handler );

// Set a flag if the state is being changed from open() or close().
// Don't propagate the event if it's an internal action to prevent infinite loop.
this.isFromInternalAction = false;
this.expanded.bind( () => {
if ( ! this.isFromInternalAction ) {
// Propagate the event to React to sync the state.
dispatch( customizeWidgetsStore ).setIsInserterOpened(
this.expanded()
);
}
this.isFromInternalAction = false;
} );
}
open() {
if ( ! this.isOpen ) {
if ( ! this.expanded() ) {
const contentContainer = this.contentContainer[ 0 ];
this.activeElementBeforeExpanded =
contentContainer.ownerDocument.activeElement;

this.isFromInternalAction = true;

this.expand( {
completeCallback() {
// We have to do this in a "completeCallback" or else the elements will not yet be visible/tabbable.
Expand All @@ -97,11 +113,13 @@ export default function getInserterOuterSection() {
}
}
close() {
if ( this.isOpen ) {
if ( this.expanded() ) {
const contentContainer = this.contentContainer[ 0 ];
const activeElement =
contentContainer.ownerDocument.activeElement;

this.isFromInternalAction = true;

this.collapse( {
completeCallback() {
// Return back the focus when closing the inserter.
Expand Down
10 changes: 9 additions & 1 deletion packages/customize-widgets/src/controls/sidebar-control.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
/**
* WordPress dependencies
*/
import { dispatch } from '@wordpress/data';

/**
* Internal dependencies
*/
import SidebarAdapter from '../components/sidebar-block-editor/sidebar-adapter';
import getInserterOuterSection from './inserter-outer-section';
import { store as customizeWidgetsStore } from '../store';

const getInserterId = ( controlId ) => `widgets-inserter-${ controlId }`;

Expand Down Expand Up @@ -45,7 +51,9 @@ export default function getSidebarControl() {
if ( ! args.unchanged ) {
// Close the inserter when the section collapses.
if ( ! expanded ) {
this.inserter.close();
dispatch( customizeWidgetsStore ).setIsInserterOpened(
false
);
}

this.subscribers.forEach( ( subscriber ) =>
Expand Down
19 changes: 19 additions & 0 deletions packages/customize-widgets/src/store/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,22 @@ export function __unstableToggleFeature( feature ) {
feature,
};
}

/**
* Returns an action object used to open/close the inserter.
*
* @param {boolean|Object} value Whether the inserter should be
* opened (true) or closed (false).
* To specify an insertion point,
* use an object.
* @param {string} value.rootClientId The root client ID to insert at.
* @param {number} value.insertionIndex The index to insert at.
*
* @return {Object} Action object.
*/
export function setIsInserterOpened( value ) {
return {
type: 'SET_IS_INSERTER_OPENED',
value,
};
}
15 changes: 15 additions & 0 deletions packages/customize-widgets/src/store/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,20 @@ const createWithInitialState = ( initialState ) => ( reducer ) => {
return ( state = initialState, action ) => reducer( state, action );
};

/**
* Reducer tracking whether the inserter is open.
*
* @param {boolean|Object} state
* @param {Object} action
*/
function blockInserterPanel( state = false, action ) {
switch ( action.type ) {
case 'SET_IS_INSERTER_OPENED':
return action.value;
}
return state;
}

/**
* Reducer returning the user preferences.
*
Expand All @@ -50,5 +64,6 @@ export const preferences = flow( [
} );

export default combineReducers( {
blockInserterPanel,
preferences,
} );
23 changes: 23 additions & 0 deletions packages/customize-widgets/src/store/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,26 @@ import { get } from 'lodash';
export function __unstableIsFeatureActive( state, feature ) {
return get( state.preferences.features, [ feature ], false );
}

/**
* Returns true if the inserter is opened.
*
* @param {Object} state Global application state.
*
* @return {boolean} Whether the inserter is opened.
*/
export function isInserterOpened( state ) {
return !! state.blockInserterPanel;
}

/**
* Get the insertion point for the inserter.
*
* @param {Object} state Global application state.
*
* @return {Object} The root client ID and index to insert at.
*/
export function __experimentalGetInsertionPoint( state ) {
const { rootClientId, insertionIndex } = state.blockInserterPanel;
return { rootClientId, insertionIndex };
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { store as coreStore } from '@wordpress/core-data';
/**
* Internal dependencies
*/
import { store as editWidgetsStore } from '../store';
import { buildWidgetAreasPostId, KIND, POST_TYPE } from '../store/utils';

const useWidgetLibraryInsertionPoint = () => {
Expand All @@ -31,6 +32,16 @@ const useWidgetLibraryInsertionPoint = () => {
getBlockIndex,
} = select( blockEditorStore );

const insertionPoint = select(
editWidgetsStore
).__experimentalGetInsertionPoint();

// "Browse all" in the quick inserter will set the rootClientId to the current block.
// Otherwise, it will just be undefined, and we'll have to handle it differently below.
if ( insertionPoint.rootClientId ) {
return insertionPoint;
}

const clientId = getBlockSelectionEnd() || firstRootId;
const rootClientId = getBlockRootClientId( clientId );

Expand Down
12 changes: 12 additions & 0 deletions packages/edit-widgets/src/store/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,18 @@ export function isInserterOpened( state ) {
return !! state.blockInserterPanel;
}

/**
* Get the insertion point for the inserter.
*
* @param {Object} state Global application state.
*
* @return {Object} The root client ID and index to insert at.
*/
export function __experimentalGetInsertionPoint( state ) {
const { rootClientId, insertionIndex } = state.blockInserterPanel;
return { rootClientId, insertionIndex };
}

/**
* Returns true if a block can be inserted into a widget area.
*
Expand Down