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

Try: Rewrite Block Rename UI with hooks #55629

Closed
wants to merge 3 commits into from
Closed
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
3 changes: 3 additions & 0 deletions packages/block-editor/src/components/block-rename/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { default as BlockRenameMenuItem } from './menu-item';
export { default as BlockRenameModal } from './modal';
export { default as useBlockRename } from './use-block-rename';
43 changes: 43 additions & 0 deletions packages/block-editor/src/components/block-rename/menu-item.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { useReducer } from '@wordpress/element';
import { MenuItem } from '@wordpress/components';

/**
* Internal dependencies
*/
import useBlockRename from './use-block-rename';
import BlockRenameModal from './modal';

export default function BlockRenameMenuItem( { clientId } ) {
const { canRename } = useBlockRename( clientId );

const [ isModalOpen, toggleModal ] = useReducer(
( isActive ) => ! isActive,
false
);

if ( ! canRename ) {
return null;
}

return (
<>
<MenuItem
onClick={ toggleModal }
aria-expanded={ isModalOpen }
aria-haspopup="dialog"
>
{ __( 'Rename' ) }
</MenuItem>
{ isModalOpen && (
<BlockRenameModal
clientId={ clientId }
onClose={ toggleModal }
/>
) }
</>
);
}
139 changes: 139 additions & 0 deletions packages/block-editor/src/components/block-rename/modal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/**
* WordPress dependencies
*/
import { useInstanceId } from '@wordpress/compose';
import { __, sprintf } from '@wordpress/i18n';
import {
__experimentalHStack as HStack,
__experimentalVStack as VStack,
Button,
TextControl,
Modal,
} from '@wordpress/components';
import { useState } from '@wordpress/element';
import { speak } from '@wordpress/a11y';
import { useDispatch, useSelect } from '@wordpress/data';

/**
* Internal dependencies
*/
import { store as blockEditorStore } from '../../store';
import useBlockDisplayInformation from '../use-block-display-information';

const emptyString = ( testString ) => testString?.trim()?.length === 0;

export default function BlockRenameModal( { clientId, onClose } ) {
const blockInformation = useBlockDisplayInformation( clientId );
const originalBlockName = blockInformation?.title;

const metadata = useSelect(
( select ) => {
const { getBlockAttributes } = select( blockEditorStore );
return getBlockAttributes( clientId )?.metadata;
},
[ clientId ]
);
const { updateBlockAttributes } = useDispatch( blockEditorStore );
const blockName = metadata?.name || '';
const [ editedBlockName, setEditedBlockName ] = useState( blockName );

const nameHasChanged = editedBlockName !== blockName;
const nameIsOriginal = editedBlockName === originalBlockName;
const nameIsEmpty = emptyString( editedBlockName );

const isNameValid = nameHasChanged || nameIsOriginal;

const autoSelectInputText = ( event ) => event.target.select();

const dialogDescription = useInstanceId(
BlockRenameModal,
`block-editor-rename-modal__description`
);

const handleSubmit = () => {
const message =
nameIsOriginal || nameIsEmpty
? sprintf(
/* translators: %s: new name/label for the block */
__( 'Block name reset to: "%s".' ),
editedBlockName
)
: sprintf(
/* translators: %s: new name/label for the block */
__( 'Block name changed to: "%s".' ),
editedBlockName
);

// Must be assertive to immediately announce change.
speak( message, 'assertive' );

updateBlockAttributes( [ clientId ], {
metadata: {
...metadata,
name:
// If the new value is the block's original name (e.g. `Group`)
// or it is an empty string then assume the intent is to reset
// the value. Therefore reset the metadata.
editedBlockName === blockInformation?.title ||
emptyString( editedBlockName )
? undefined
: editedBlockName,
},
} );

// Immediate close avoids ability to hit save multiple times.
onClose();
};

return (
<Modal
title={ __( 'Rename' ) }
onRequestClose={ onClose }
overlayClassName="block-editor-block-rename-modal"
aria={ {
describedby: dialogDescription,
} }
focusOnMount="firstContentElement"
>
<p id={ dialogDescription }>
{ __( 'Enter a custom name for this block.' ) }
</p>
<form
onSubmit={ ( e ) => {
e.preventDefault();

if ( ! isNameValid ) {
return;
}

handleSubmit();
} }
>
<VStack spacing="3">
<TextControl
__nextHasNoMarginBottom
value={ editedBlockName }
label={ __( 'Block name' ) }
hideLabelFromVision={ true }
placeholder={ originalBlockName }
onChange={ setEditedBlockName }
onFocus={ autoSelectInputText }
/>
<HStack justify="right">
<Button variant="tertiary" onClick={ onClose }>
{ __( 'Cancel' ) }
</Button>

<Button
aria-disabled={ ! isNameValid }
variant="primary"
type="submit"
>
{ __( 'Save' ) }
</Button>
</HStack>
</VStack>
</form>
</Modal>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* WordPress dependencies
*/
import { useSelect } from '@wordpress/data';
import { store as blocksStore } from '@wordpress/blocks';

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

/**
* Return details about the block renaming status.
*
* @param {string} clientId The block client Id.
*
* @return {Object} Block renaming status
*/
export default function useBlockRename( clientId ) {
return useSelect(
( select ) => {
const { getBlockName } = select( blockEditorStore );
const { hasBlockSupport } = select( blocksStore );

return {
canRename: hasBlockSupport(
getBlockName( clientId ),
'renaming',
true
),
};
},
[ clientId ]
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
ConvertToGroupButton,
} from '../convert-to-group-buttons';
import { BlockLockMenuItem, useBlockLock } from '../block-lock';
import { BlockRenameMenuItem, useBlockRename } from '../block-rename';
import { store as blockEditorStore } from '../../store';
import BlockModeToggle from '../block-settings-menu/block-mode-toggle';

Expand All @@ -45,6 +46,8 @@ const BlockSettingsMenuControlsSlot = ( {

const { canLock } = useBlockLock( selectedClientIds[ 0 ] );
const showLockButton = selectedClientIds.length === 1 && canLock;
const { canRename } = useBlockRename( selectedClientIds[ 0 ] );
const showRenameButton = selectedClientIds.length === 1 && canRename;

// Check if current selection of blocks is Groupable or Ungroupable
// and pass this props down to ConvertToGroupButton.
Expand Down Expand Up @@ -84,6 +87,11 @@ const BlockSettingsMenuControlsSlot = ( {
clientId={ selectedClientIds[ 0 ] }
/>
) }
{ showRenameButton && (
<BlockRenameMenuItem
clientId={ selectedClientIds[ 0 ] }
/>
) }
{ fills }
{ fillProps?.canMove && ! fillProps?.onlyBlock && (
<MenuItem
Expand Down
Loading
Loading