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

Block API: try separate controls registration #60779

Draft
wants to merge 1 commit into
base: trunk
Choose a base branch
from
Draft
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
25 changes: 24 additions & 1 deletion packages/block-editor/src/components/block-edit/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ import {
getBlockType,
} from '@wordpress/blocks';
import { useContext, useMemo } from '@wordpress/element';
/**
* Internal dependencies
*/
import { InspectorControls, BlockControls } from '../../components';

/**
* Internal dependencies
Expand All @@ -37,12 +41,31 @@ const Edit = ( props ) => {
return null;
}

const controls = [];

if ( blockType.attributeControls?.length > 0 ) {
for ( const control of blockType.attributeControls ) {
const Wrapper =
control.type === 'toolbar' ? BlockControls : InspectorControls;

controls.push(
<Wrapper group={ control.group } key={ control.key }>
<control.Control { ...props } />
</Wrapper>
);
}
}

// `edit` and `save` are functions or components describing the markup
// with which a block is displayed. If `blockType` is valid, assign
// them preferentially as the render value for the block.
const Component = blockType.edit || blockType.save;

return <Component { ...props } />;
return [
<Component { ...props } key="content">
{ controls }
</Component>,
];
};

const EditWithFilters = withFilters( 'editor.BlockEdit' )( Edit );
Expand Down
183 changes: 40 additions & 143 deletions packages/block-library/src/paragraph/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,9 @@ import classnames from 'classnames';
/**
* WordPress dependencies
*/
import { __, _x, isRTL } from '@wordpress/i18n';
import {
ToolbarButton,
ToggleControl,
__experimentalToolsPanelItem as ToolsPanelItem,
} from '@wordpress/components';
import {
AlignmentControl,
BlockControls,
InspectorControls,
RichText,
useBlockProps,
useSettings,
useBlockEditingMode,
} from '@wordpress/block-editor';
import { __, isRTL } from '@wordpress/i18n';
import { RichText, useBlockProps } from '@wordpress/block-editor';
import { createBlock } from '@wordpress/blocks';
import { formatLtr } from '@wordpress/icons';

/**
* Internal dependencies
Expand All @@ -31,67 +17,10 @@ import { useOnEnter } from './use-enter';

const name = 'core/paragraph';

function ParagraphRTLControl( { direction, setDirection } ) {
return (
isRTL() && (
<ToolbarButton
icon={ formatLtr }
title={ _x( 'Left to right', 'editor button' ) }
isActive={ direction === 'ltr' }
onClick={ () => {
setDirection( direction === 'ltr' ? undefined : 'ltr' );
} }
/>
)
);
}

function hasDropCapDisabled( align ) {
return align === ( isRTL() ? 'left' : 'right' ) || align === 'center';
}

function DropCapControl( { clientId, attributes, setAttributes } ) {
// Please do not add a useSelect call to the paragraph block unconditionally.
// Every useSelect added to a (frequently used) block will degrade load
// and type performance. By moving it within InspectorControls, the subscription is
// now only added for the selected block(s).
const [ isDropCapFeatureEnabled ] = useSettings( 'typography.dropCap' );

if ( ! isDropCapFeatureEnabled ) {
return null;
}

const { align, dropCap } = attributes;

let helpText;
if ( hasDropCapDisabled( align ) ) {
helpText = __( 'Not available for aligned text.' );
} else if ( dropCap ) {
helpText = __( 'Showing large initial letter.' );
} else {
helpText = __( 'Toggle to show a large initial letter.' );
}

return (
<ToolsPanelItem
hasValue={ () => !! dropCap }
label={ __( 'Drop cap' ) }
onDeselect={ () => setAttributes( { dropCap: undefined } ) }
resetAllFilter={ () => ( { dropCap: undefined } ) }
panelId={ clientId }
>
<ToggleControl
__nextHasNoMarginBottom
label={ __( 'Drop cap' ) }
checked={ !! dropCap }
onChange={ () => setAttributes( { dropCap: ! dropCap } ) }
help={ helpText }
disabled={ hasDropCapDisabled( align ) ? true : false }
/>
</ToolsPanelItem>
);
}

function ParagraphBlock( {
attributes,
mergeBlocks,
Expand All @@ -109,81 +38,49 @@ function ParagraphBlock( {
} ),
style: { direction },
} );
const blockEditingMode = useBlockEditingMode();

return (
<>
{ blockEditingMode === 'default' && (
<BlockControls group="block">
<AlignmentControl
value={ align }
onChange={ ( newAlign ) =>
setAttributes( {
align: newAlign,
dropCap: hasDropCapDisabled( newAlign )
? false
: dropCap,
} )
}
/>
<ParagraphRTLControl
direction={ direction }
setDirection={ ( newDirection ) =>
setAttributes( { direction: newDirection } )
}
/>
</BlockControls>
) }
<InspectorControls group="typography">
<DropCapControl
clientId={ clientId }
attributes={ attributes }
setAttributes={ setAttributes }
/>
</InspectorControls>
<RichText
identifier="content"
tagName="p"
{ ...blockProps }
value={ content }
onChange={ ( newContent ) =>
setAttributes( { content: newContent } )
<RichText
identifier="content"
tagName="p"
{ ...blockProps }
value={ content }
onChange={ ( newContent ) =>
setAttributes( { content: newContent } )
}
onSplit={ ( value, isOriginal ) => {
let newAttributes;

if ( isOriginal || value ) {
newAttributes = {
...attributes,
content: value,
};
}
onSplit={ ( value, isOriginal ) => {
let newAttributes;

if ( isOriginal || value ) {
newAttributes = {
...attributes,
content: value,
};
}

const block = createBlock( name, newAttributes );
const block = createBlock( name, newAttributes );

if ( isOriginal ) {
block.clientId = clientId;
}

return block;
} }
onMerge={ mergeBlocks }
onReplace={ onReplace }
onRemove={ onRemove }
aria-label={
RichText.isEmpty( content )
? __(
'Empty block; start writing or type forward slash to choose a block'
)
: __( 'Block: Paragraph' )
if ( isOriginal ) {
block.clientId = clientId;
}
data-empty={ RichText.isEmpty( content ) }
placeholder={ placeholder || __( 'Type / to choose a block' ) }
data-custom-placeholder={ placeholder ? true : undefined }
__unstableEmbedURLOnPaste
__unstableAllowPrefixTransformations
/>
</>

return block;
} }
onMerge={ mergeBlocks }
onReplace={ onReplace }
onRemove={ onRemove }
aria-label={
RichText.isEmpty( content )
? __(
'Empty block; start writing or type forward slash to choose a block'
)
: __( 'Block: Paragraph' )
}
data-empty={ RichText.isEmpty( content ) }
placeholder={ placeholder || __( 'Type / to choose a block' ) }
data-custom-placeholder={ placeholder ? true : undefined }
__unstableEmbedURLOnPaste
__unstableAllowPrefixTransformations
/>
);
}

Expand Down
109 changes: 107 additions & 2 deletions packages/block-library/src/paragraph/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { paragraph as icon } from '@wordpress/icons';
import { __, _x, isRTL } from '@wordpress/i18n';
import { paragraph as icon, formatLtr } from '@wordpress/icons';
import { AlignmentControl, useSettings } from '@wordpress/block-editor';
import {
ToolbarButton,
ToggleControl,
__experimentalToolsPanelItem as ToolsPanelItem,
} from '@wordpress/components';

/**
* Internal dependencies
Expand All @@ -18,6 +24,10 @@ const { name } = metadata;

export { metadata, name };

function hasDropCapDisabled( align ) {
return align === ( isRTL() ? 'left' : 'right' ) || align === 'center';
}

export const settings = {
icon,
example: {
Expand Down Expand Up @@ -54,6 +64,101 @@ export const settings = {
},
edit,
save,
attributeControls: [
{
key: 'align',
type: 'toolbar',
group: 'block',
Control( { attributes, setAttributes } ) {
const { align, dropCap } = attributes;
return (
<AlignmentControl
value={ align }
onChange={ ( newAlign ) =>
setAttributes( {
align: newAlign,
dropCap: hasDropCapDisabled( newAlign )
? false
: dropCap,
} )
}
/>
);
},
},
{
key: 'direction',
type: 'toolbar',
group: 'block',
Control( { attributes, setAttributes } ) {
const { direction } = attributes;
return (
isRTL() && (
<ToolbarButton
icon={ formatLtr }
title={ _x( 'Left to right', 'editor button' ) }
isActive={ direction === 'ltr' }
onClick={ () => {
setAttributes( {
direction:
direction === 'ltr' ? undefined : 'ltr',
} );
} }
/>
)
);
},
},
{
key: 'dropCap',
type: 'inspector',
group: 'typography',
Control( { attributes, setAttributes, clientId } ) {
const [ isDropCapFeatureEnabled ] =
useSettings( 'typography.dropCap' );

if ( ! isDropCapFeatureEnabled ) {
return null;
}

const { align, dropCap } = attributes;

let helpText;
if ( hasDropCapDisabled( align ) ) {
helpText = __( 'Not available for aligned text.' );
} else if ( dropCap ) {
helpText = __( 'Showing large initial letter.' );
} else {
helpText = __( 'Toggle to show a large initial letter.' );
}

return (
<ToolsPanelItem
hasValue={ () => !! dropCap }
label={ __( 'Drop cap' ) }
onDeselect={ () =>
setAttributes( { dropCap: undefined } )
}
resetAllFilter={ () => ( { dropCap: undefined } ) }
panelId={ clientId }
>
<ToggleControl
__nextHasNoMarginBottom
label={ __( 'Drop cap' ) }
checked={ !! dropCap }
onChange={ () =>
setAttributes( { dropCap: ! dropCap } )
}
help={ helpText }
disabled={
hasDropCapDisabled( align ) ? true : false
}
/>
</ToolsPanelItem>
);
},
},
],
};

export const init = () => initBlock( { name, metadata, settings } );
Loading