Skip to content

Commit

Permalink
Refine rename flow for blocks with overrides (WordPress#60234)
Browse files Browse the repository at this point in the history
Co-authored-by: kevin940726 <[email protected]>
Co-authored-by: talldan <[email protected]>
Co-authored-by: fabiankaegy <[email protected]>
Co-authored-by: jasmussen <[email protected]>
Co-authored-by: SaxonF <[email protected]>
Co-authored-by: richtabor <[email protected]>
Co-authored-by: jameskoster <[email protected]>

* Refine renaming flow for blocks with overrides

* Design feedback

* Restore block rename field

* Add comment about the warning

* Address code reviews

* Apply suggestions from code review

Co-authored-by: Daniel Richards <[email protected]>

* Fix tests

---------

Co-authored-by: Daniel Richards <[email protected]>
  • Loading branch information
kevin940726 and talldan authored Apr 12, 2024
1 parent 727f350 commit 7fc8973
Show file tree
Hide file tree
Showing 15 changed files with 339 additions and 167 deletions.
30 changes: 17 additions & 13 deletions packages/block-editor/src/components/block-rename/modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ import {
TextControl,
Modal,
} from '@wordpress/components';
import { useInstanceId } from '@wordpress/compose';
import { __, sprintf } from '@wordpress/i18n';
import { useState } from '@wordpress/element';
import { useState, useId } from '@wordpress/element';
import { speak } from '@wordpress/a11y';

/**
Expand All @@ -23,8 +22,12 @@ export default function BlockRenameModal( {
originalBlockName,
onClose,
onSave,
// Pattern Overrides is a WordPress-only feature but it also uses the Block Binding API.
// Ideally this should not be inside the block editor package, but we keep it here for simplicity.
hasOverridesWarning,
} ) {
const [ editedBlockName, setEditedBlockName ] = useState( blockName );
const descriptionId = useId();

const nameHasChanged = editedBlockName !== blockName;
const nameIsOriginal = editedBlockName === originalBlockName;
Expand All @@ -34,11 +37,6 @@ export default function BlockRenameModal( {

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

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

const handleSubmit = () => {
const message =
nameIsOriginal || nameIsEmpty
Expand Down Expand Up @@ -66,14 +64,10 @@ export default function BlockRenameModal( {
title={ __( 'Rename' ) }
onRequestClose={ onClose }
overlayClassName="block-editor-block-rename-modal"
aria={ {
describedby: dialogDescription,
} }
focusOnMount="firstContentElement"
aria={ { describedby: descriptionId } }
size="small"
>
<p id={ dialogDescription }>
{ __( 'Enter a custom name for this block.' ) }
</p>
<form
onSubmit={ ( e ) => {
e.preventDefault();
Expand All @@ -85,13 +79,23 @@ export default function BlockRenameModal( {
handleSubmit();
} }
>
<p id={ descriptionId }>
{ __( 'Enter a custom name for this block.' ) }
</p>
<VStack spacing="3">
<TextControl
__nextHasNoMarginBottom
__next40pxDefaultSize
value={ editedBlockName }
label={ __( 'Block name' ) }
hideLabelFromVision
help={
hasOverridesWarning
? __(
'This block allows overrides. Changing the name can cause problems with content entered into instances of this pattern.'
)
: undefined
}
placeholder={ originalBlockName }
onChange={ setEditedBlockName }
onFocus={ autoSelectInputText }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,17 @@ export default function BlockRenameControl( { clientId } ) {
const { updateBlockAttributes } = useDispatch( blockEditorStore );

const customName = metadata?.name;
const hasPatternOverrides =
!! customName &&
!! metadata?.bindings &&
Object.values( metadata.bindings ).some(
( binding ) => binding.source === 'core/pattern-overrides'
);

function onChange( newName ) {
updateBlockAttributes( [ clientId ], {
metadata: {
...( metadata && metadata ),
...metadata,
name: newName,
},
} );
Expand All @@ -59,6 +65,7 @@ export default function BlockRenameControl( { clientId } ) {
<BlockRenameModal
blockName={ customName || '' }
originalBlockName={ blockInformation?.title }
hasOverridesWarning={ hasPatternOverrides }
onClose={ () => setRenamingBlock( false ) }
onSave={ ( newName ) => {
// If the new value is the block's original name (e.g. `Group`)
Expand Down
2 changes: 2 additions & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
- `ProgressBar`: Move the indicator width styles from emotion to a CSS variable ([#60388](https://github.com/WordPress/gutenberg/pull/60388)).
- `Text`: Add `text-wrap: pretty;` to improve wrapping. ([#60164](https://github.com/WordPress/gutenberg/pull/60164)).
- `Navigator`: Navigation to the active path doesn't create a new location history. ([#60561](https://github.com/WordPress/gutenberg/pull/60561))
- `FormToggle`: Forwards ref to input. ([#60234](https://github.com/WordPress/gutenberg/pull/60234)).
- `ToggleControl`: Forwards ref to FormToggle. ([#60234](https://github.com/WordPress/gutenberg/pull/60234)).

### Bug Fix

Expand Down
12 changes: 10 additions & 2 deletions packages/components/src/form-toggle/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
* External dependencies
*/
import classnames from 'classnames';
import type { ForwardedRef } from 'react';

/**
* WordPress dependencies
*/
import { forwardRef } from '@wordpress/element';

/**
* Internal dependencies
Expand Down Expand Up @@ -31,7 +37,8 @@ export const noop = () => {};
* ```
*/
export function FormToggle(
props: WordPressComponentProps< FormToggleProps, 'input', false >
props: WordPressComponentProps< FormToggleProps, 'input', false >,
ref: ForwardedRef< HTMLInputElement >
) {
const {
className,
Expand All @@ -56,11 +63,12 @@ export function FormToggle(
onChange={ onChange }
disabled={ disabled }
{ ...additionalProps }
ref={ ref }
/>
<span className="components-form-toggle__track"></span>
<span className="components-form-toggle__thumb"></span>
</span>
);
}

export default FormToggle;
export default forwardRef( FormToggle );
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { useState } from '@wordpress/element';
/**
* Internal dependencies
*/
import { FormToggle } from '..';
import FormToggle from '..';

const meta: Meta< typeof FormToggle > = {
component: FormToggle,
Expand Down
27 changes: 16 additions & 11 deletions packages/components/src/toggle-control/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
/**
* External dependencies
*/
import type { ChangeEvent } from 'react';
import type { ChangeEvent, ForwardedRef } from 'react';
import { css } from '@emotion/react';

/**
* WordPress dependencies
*/
import { forwardRef } from '@wordpress/element';
import { useInstanceId } from '@wordpress/compose';

/**
Expand Down Expand Up @@ -41,15 +42,18 @@ import { space } from '../utils/space';
* };
* ```
*/
export function ToggleControl( {
__nextHasNoMarginBottom,
label,
checked,
help,
className,
onChange,
disabled,
}: WordPressComponentProps< ToggleControlProps, 'input', false > ) {
export function ToggleControl(
{
__nextHasNoMarginBottom,
label,
checked,
help,
className,
onChange,
disabled,
}: WordPressComponentProps< ToggleControlProps, 'input', false >,
ref: ForwardedRef< HTMLInputElement >
) {
function onChangeToggle( event: ChangeEvent< HTMLInputElement > ) {
onChange( event.target.checked );
}
Expand Down Expand Up @@ -94,6 +98,7 @@ export function ToggleControl( {
onChange={ onChangeToggle }
aria-describedby={ describedBy }
disabled={ disabled }
ref={ ref }
/>
<FlexBlock
as="label"
Expand All @@ -107,4 +112,4 @@ export function ToggleControl( {
);
}

export default ToggleControl;
export default forwardRef( ToggleControl );
39 changes: 25 additions & 14 deletions packages/editor/src/hooks/pattern-overrides.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { privateApis as patternsPrivateApis } from '@wordpress/patterns';
import { createHigherOrderComponent } from '@wordpress/compose';
import { useBlockEditingMode } from '@wordpress/block-editor';
import { useSelect } from '@wordpress/data';
import { store as blocksStore } from '@wordpress/blocks';

/**
* Internal dependencies
Expand All @@ -14,7 +15,7 @@ import { store as editorStore } from '../store';
import { unlock } from '../lock-unlock';

const {
useSetPatternBindings,
PatternOverridesControls,
ResetOverridesControl,
PATTERN_TYPES,
PARTIAL_SYNCING_SUPPORTED_BLOCKS,
Expand All @@ -38,7 +39,6 @@ const withPatternOverrideControls = createHigherOrderComponent(
return (
<>
<BlockEdit { ...props } />
{ isSupportedBlock && <BindingUpdater { ...props } /> }
{ props.isSelected && isSupportedBlock && (
<ControlsWithStoreSubscription { ...props } />
) }
Expand All @@ -47,22 +47,24 @@ const withPatternOverrideControls = createHigherOrderComponent(
}
);

function BindingUpdater( props ) {
const postType = useSelect(
( select ) => select( editorStore ).getCurrentPostType(),
[]
);
useSetPatternBindings( props, postType );
return null;
}

// Split into a separate component to avoid a store subscription
// on every block.
function ControlsWithStoreSubscription( props ) {
const blockEditingMode = useBlockEditingMode();
const isEditingPattern = useSelect(
( select ) =>
select( editorStore ).getCurrentPostType() === PATTERN_TYPES.user,
const { hasPatternOverridesSource, isEditingPattern } = useSelect(
( select ) => {
const { getBlockBindingsSource } = unlock( select( blocksStore ) );

return {
// For editing link to the site editor if the theme and user permissions support it.
hasPatternOverridesSource: !! getBlockBindingsSource(
'core/pattern-overrides'
),
isEditingPattern:
select( editorStore ).getCurrentPostType() ===
PATTERN_TYPES.user,
};
},
[]
);

Expand All @@ -73,14 +75,23 @@ function ControlsWithStoreSubscription( props ) {
( binding ) => binding.source === 'core/pattern-overrides'
);

const shouldShowPatternOverridesControls =
isEditingPattern && blockEditingMode === 'default';
const shouldShowResetOverridesControl =
! isEditingPattern &&
!! props.attributes.metadata?.name &&
blockEditingMode !== 'disabled' &&
hasPatternBindings;

if ( ! hasPatternOverridesSource ) {
return null;
}

return (
<>
{ shouldShowPatternOverridesControls && (
<PatternOverridesControls { ...props } />
) }
{ shouldShowResetOverridesControl && (
<ResetOverridesControl { ...props } />
) }
Expand Down
1 change: 1 addition & 0 deletions packages/patterns/src/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export function isOverridableBlock( block ) {
Object.keys( PARTIAL_SYNCING_SUPPORTED_BLOCKS ).includes(
block.name
) &&
!! block.attributes.metadata?.name &&
!! block.attributes.metadata?.bindings &&
Object.values( block.attributes.metadata.bindings ).some(
( binding ) => binding.source === 'core/pattern-overrides'
Expand Down
Loading

0 comments on commit 7fc8973

Please sign in to comment.