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

Smart block appender #16708

Merged
merged 34 commits into from
Oct 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
a1d158b
if thre is only one there is only one
draganescu Jul 22, 2019
1f5081b
made a new insertion point selector, some code review refactoring
draganescu Aug 3, 2019
06d44c1
better handling of inserter
draganescu Aug 3, 2019
05c1ebf
refactoring and named block insertion
draganescu Aug 3, 2019
525385c
updates to the appender
draganescu Sep 24, 2019
2e904e1
update snapshots
draganescu Sep 30, 2019
4d89b0b
update docs
draganescu Sep 30, 2019
d80fc7f
default inserter label is used in so many tests
draganescu Oct 1, 2019
55f3f95
fixed allowed blocks test
draganescu Oct 1, 2019
ec1eecc
snapshot updated
draganescu Oct 2, 2019
07b652c
better naming and removed the need for es-lint disabling
draganescu Oct 17, 2019
ce0ec9d
improved the inserter label construction
draganescu Oct 17, 2019
3bf7909
improved the doc of getTheOnlyAllowedItem selector
draganescu Oct 17, 2019
c977baf
reverting test patches becasue patching without understanding is bad,…
draganescu Oct 17, 2019
d2fda6e
moved getInsertionIndex out of selectos and back into each component …
draganescu Oct 18, 2019
157097b
docs generated
draganescu Oct 18, 2019
02edd01
added experimental labels to new selectors, added es-lint comment back
draganescu Oct 18, 2019
e451afd
updated docs
draganescu Oct 18, 2019
bb2bd63
Update packages/block-editor/src/store/selectors.js
draganescu Oct 24, 2019
97dac6e
Update packages/block-editor/src/store/selectors.js
draganescu Oct 24, 2019
134d182
refactored and fixed some coding errors
draganescu Oct 24, 2019
b2f709a
small code move
draganescu Oct 24, 2019
1a40731
small code move
draganescu Oct 24, 2019
7049dc4
removes aria attrs for autoinserted items
draganescu Oct 25, 2019
9910348
fixes typo, adds translators comment
draganescu Oct 25, 2019
4832f45
simplifies the intserter logic
draganescu Oct 25, 2019
36de754
fix for the simplification
draganescu Oct 25, 2019
3f0d68e
simplifies by using one selector and passing props in compose
draganescu Oct 25, 2019
e82ba8f
small code updates
draganescu Oct 27, 2019
65a4b58
lint
draganescu Oct 27, 2019
a3d9ad6
renamed insertedBlock
draganescu Oct 27, 2019
50b2637
small doc update
draganescu Oct 27, 2019
488aa5c
adds tooltip to the default button appender
draganescu Oct 28, 2019
b2c27f6
refactores for more self documenting varnames
draganescu Oct 28, 2019
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
40 changes: 27 additions & 13 deletions packages/block-editor/src/components/button-block-appender/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import classnames from 'classnames';
/**
* WordPress dependencies
*/
import { Button, Icon } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { Button, Icon, Tooltip } from '@wordpress/components';
import { _x, sprintf } from '@wordpress/i18n';

/**
* Internal dependencies
Expand All @@ -21,17 +21,31 @@ function ButtonBlockAppender( { rootClientId, className } ) {
<BlockDropZone rootClientId={ rootClientId } />
<Inserter
rootClientId={ rootClientId }
renderToggle={ ( { onToggle, disabled, isOpen } ) => (
<Button
className={ classnames( className, 'block-editor-button-block-appender' ) }
onClick={ onToggle }
aria-expanded={ isOpen }
disabled={ disabled }
>
<span className="screen-reader-text">{ __( 'Add Block' ) }</span>
<Icon icon="insert" />
</Button>
) }
renderToggle={ ( { onToggle, disabled, isOpen, blockTitle, hasSingleBlockType } ) => {
let label;
if ( hasSingleBlockType ) {
// translators: %s: the name of the block when there is only one
label = sprintf( _x( 'Add %s', 'directly add the only allowed block' ), blockTitle );
} else {
label = _x( 'Add block', 'Generic label for block inserter button' );
}
const isToggleButton = ! hasSingleBlockType;
return (
<Tooltip text={ label }>
<Button
className={ classnames( className, 'block-editor-button-block-appender' ) }
onClick={ onToggle }
aria-haspopup={ isToggleButton ? 'true' : undefined }
aria-expanded={ isToggleButton ? isOpen : undefined }
disabled={ disabled }
label={ label }
>
<span className="screen-reader-text">{ label }</span>
<Icon icon="insert" />
</Button>
</Tooltip>
);
Comment on lines +33 to +47
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, this button with an icon and a tooltip is now looking exactly like an IconButton 😄
https://github.com/WordPress/gutenberg/blob/master/packages/components/src/icon-button/index.js

} }
isAppender
/>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ exports[`DefaultBlockAppender should append a default block when input focused 1
rows={1}
value="Start writing or type / to choose a block"
/>
<WithSelect(IfCondition(Inserter))
<WithSelect(WithDispatch(IfCondition(Inserter)))
isAppender={true}
position="top right"
/>
Expand All @@ -53,7 +53,7 @@ exports[`DefaultBlockAppender should match snapshot 1`] = `
rows={1}
value="Start writing or type / to choose a block"
/>
<WithSelect(IfCondition(Inserter))
<WithSelect(WithDispatch(IfCondition(Inserter)))
isAppender={true}
position="top right"
/>
Expand All @@ -77,7 +77,7 @@ exports[`DefaultBlockAppender should optionally show without prompt 1`] = `
rows={1}
value=""
/>
<WithSelect(IfCondition(Inserter))
<WithSelect(WithDispatch(IfCondition(Inserter)))
isAppender={true}
position="top right"
/>
Expand Down
118 changes: 100 additions & 18 deletions packages/block-editor/src/components/inserter/index.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,46 @@
/**
* External dependencies
*/
import { get } from 'lodash';
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { __, _x, sprintf } from '@wordpress/i18n';
import { Dropdown, IconButton } from '@wordpress/components';
import { Component } from '@wordpress/element';
import { withSelect } from '@wordpress/data';
import { withDispatch, withSelect } from '@wordpress/data';
import { compose, ifCondition } from '@wordpress/compose';
import {
createBlock,
getBlockType,
} from '@wordpress/blocks';

/**
* Internal dependencies
*/
import InserterMenu from './menu';

const defaultRenderToggle = ( { onToggle, disabled, isOpen } ) => (
<IconButton
icon="insert"
label={ __( 'Add block' ) }
labelPosition="bottom"
onClick={ onToggle }
className="editor-inserter__toggle block-editor-inserter__toggle"
aria-haspopup="true"
aria-expanded={ isOpen }
disabled={ disabled }
/>
);
const defaultRenderToggle = ( { onToggle, disabled, isOpen, blockTitle, hasSingleBlockType } ) => {
let label;
if ( hasSingleBlockType ) {
// translators: %s: the name of the block when there is only one
label = sprintf( _x( 'Add %s', 'directly add the only allowed block' ), blockTitle );
} else {
label = _x( 'Add block', 'Generic label for block inserter button' );
}
draganescu marked this conversation as resolved.
Show resolved Hide resolved
return (
<IconButton
icon="insert"
label={ label }
labelPosition="bottom"
onClick={ onToggle }
className="editor-inserter__toggle block-editor-inserter__toggle"
aria-haspopup={ ! hasSingleBlockType ? 'true' : false }
aria-expanded={ ! hasSingleBlockType ? isOpen : false }
disabled={ disabled }
/>
);
};

class Inserter extends Component {
constructor() {
Expand Down Expand Up @@ -56,10 +73,12 @@ class Inserter extends Component {
renderToggle( { onToggle, isOpen } ) {
const {
disabled,
blockTitle,
hasSingleBlockType,
renderToggle = defaultRenderToggle,
} = this.props;

return renderToggle( { onToggle, isOpen, disabled } );
return renderToggle( { onToggle, isOpen, disabled, blockTitle, hasSingleBlockType } );
}

/**
Expand All @@ -86,8 +105,10 @@ class Inserter extends Component {
}

render() {
const { position } = this.props;

const { position, hasSingleBlockType, insertOnlyAllowedBlock } = this.props;
if ( hasSingleBlockType ) {
return this.renderToggle( { onToggle: insertOnlyAllowedBlock } );
}
return (
<Dropdown
className="editor-inserter block-editor-inserter"
Expand All @@ -105,10 +126,71 @@ class Inserter extends Component {

export default compose( [
withSelect( ( select, { rootClientId } ) => {
const { hasInserterItems } = select( 'core/block-editor' );
const {
hasInserterItems,
__experimentalGetAllowedBlocks,
} = select( 'core/block-editor' );

const allowedBlocks = __experimentalGetAllowedBlocks( rootClientId );

const hasSingleBlockType = allowedBlocks && ( get( allowedBlocks, [ 'length' ], 0 ) === 1 );
let allowedBlockType = false;
if ( hasSingleBlockType ) {
allowedBlockType = getBlockType( allowedBlocks );
}
return {
hasItems: hasInserterItems( rootClientId ),
hasSingleBlockType,
blockTitle: allowedBlockType ? allowedBlockType.title : '',
allowedBlockType,
};
} ),
withDispatch( ( dispatch, ownProps, { select } ) => {
return {
insertOnlyAllowedBlock() {
const { rootClientId, clientId, isAppender, destinationRootClientId } = ownProps;
const {
hasSingleBlockType,
allowedBlockType,
} = ownProps;

if ( ! hasSingleBlockType ) {
return;
}

function getInsertionIndex() {
draganescu marked this conversation as resolved.
Show resolved Hide resolved
const {
getBlockIndex,
getBlockSelectionEnd,
getBlockOrder,
} = select( 'core/block-editor' );

// If the clientId is defined, we insert at the position of the block.
if ( clientId ) {
return getBlockIndex( clientId, destinationRootClientId );
}

// If there a selected block, we insert after the selected block.
const end = getBlockSelectionEnd();
if ( ! isAppender && end ) {
return getBlockIndex( end, destinationRootClientId ) + 1;
}

// Otherwise, we insert at the end of the current rootClientId
return getBlockOrder( destinationRootClientId ).length;
}

const {
insertBlock,
} = dispatch( 'core/block-editor' );

const blockToInsert = createBlock( allowedBlockType.name );
insertBlock(
blockToInsert,
getInsertionIndex(),
rootClientId
);
},
};
} ),
ifCondition( ( { hasItems } ) => hasItems ),
Expand Down
16 changes: 16 additions & 0 deletions packages/block-editor/src/store/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -1284,6 +1284,22 @@ export const hasInserterItems = createSelector(
],
);

/**
* Returns the list of allowed inserter blocks for inner blocks children
*
* @param {Object} state Editor state.
* @param {?string} rootClientId Optional root client ID of block list.
*
* @return {Array?} The list of allowed block types or false.
*/
export const __experimentalGetAllowedBlocks = ( state, rootClientId = null ) => {
if ( ! rootClientId ) {
return false;
}
const { allowedBlocks } = getBlockListSettings( state, rootClientId );
return allowedBlocks;
};
draganescu marked this conversation as resolved.
Show resolved Hide resolved
draganescu marked this conversation as resolved.
Show resolved Hide resolved

/**
* Returns the Block List settings of a block, if any exist.
*
Expand Down