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

Adjust allow pattern overrides UX flow #60769

Merged
merged 7 commits into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
94 changes: 76 additions & 18 deletions packages/patterns/src/components/allow-overrides-modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,28 @@ import { __, sprintf } from '@wordpress/i18n';
import { useState, useId } from '@wordpress/element';
import { speak } from '@wordpress/a11y';

export default function AllowOverridesModal( {
export function AllowOverridesModal( {
placeholder,
initialName = '',
onClose,
onSave,
} ) {
const [ editedBlockName, setEditedBlockName ] = useState( '' );
const [ editedBlockName, setEditedBlockName ] = useState( initialName );
const descriptionId = useId();

const isNameValid = !! editedBlockName.trim();

const handleSubmit = () => {
const message = sprintf(
/* translators: %s: new name/label for the block */
__( 'Block name changed to: "%s".' ),
editedBlockName
);
if ( editedBlockName !== initialName ) {
const message = 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' );
// Must be assertive to immediately announce change.
speak( message, 'assertive' );
}
onSave( editedBlockName );

// Immediate close avoids ability to hit save multiple times.
Expand All @@ -39,7 +42,7 @@ export default function AllowOverridesModal( {

return (
<Modal
title={ __( 'Allow overrides' ) }
title={ __( 'Enable overrides' ) }
onRequestClose={ onClose }
overlayClassName="block-editor-block-allow-overrides-modal"
focusOnMount="firstContentElement"
Expand All @@ -57,18 +60,22 @@ export default function AllowOverridesModal( {
handleSubmit();
} }
>
<p id={ descriptionId }>
{ __( 'Enter a custom name for this block.' ) }
</p>
<VStack spacing="3">
<VStack spacing="6">
<p
id={ descriptionId }
className="block-editor-block-allow-overrides-modal__description"
>
{ __(
'Overrides are changes you make to a block within a synced pattern instance. Use overrides to customize a synced pattern instance to suit its new context. Name this block to specify an override.'
) }
</p>
richtabor marked this conversation as resolved.
Show resolved Hide resolved
<TextControl
__nextHasNoMarginBottom
__next40pxDefaultSize
value={ editedBlockName }
label={ __( 'Block name' ) }
hideLabelFromVision
label={ __( 'Name' ) }
help={ __(
'This name will be used to denote the override wherever the synced pattern is used. The name here will help people understand its purpose. E.g. if you\'re creating a recipe pattern, it can be "Recipe Title", "Recipe Description", etc.'
'For example, if you are creating a recipe pattern, you use "Recipe Title", "Recipe Description", etc.'
) }
placeholder={ placeholder }
onChange={ setEditedBlockName }
Expand All @@ -88,7 +95,58 @@ export default function AllowOverridesModal( {
variant="primary"
type="submit"
>
{ __( 'Save' ) }
{ __( 'Enable overrides' ) }
</Button>
</HStack>
</VStack>
</form>
</Modal>
);
}

export function DisallowOverridesModal( { onClose, onSave } ) {
const descriptionId = useId();

return (
<Modal
title={ __( 'Disable overrides' ) }
onRequestClose={ onClose }
overlayClassName="block-editor-block-disallow-overrides-modal"
aria={ { describedby: descriptionId } }
size="small"
>
<form
onSubmit={ ( event ) => {
event.preventDefault();
onSave();
onClose();
} }
>
<VStack spacing="6">
<p
id={ descriptionId }
className="block-editor-block-allow-overrides-modal__description"
>
{ __(
'Are you sure you want to disable overrides? Disabling overrides will revert all applied overrides for this block throughout instances of this pattern.'
) }
</p>

<HStack justify="right">
<Button
__next40pxDefaultSize
variant="tertiary"
onClick={ onClose }
>
{ __( 'Cancel' ) }
</Button>

<Button
__next40pxDefaultSize
variant="primary"
type="submit"
>
{ __( 'Disable overrides' ) }
</Button>
</HStack>
</VStack>
Expand Down
70 changes: 38 additions & 32 deletions packages/patterns/src/components/pattern-overrides-controls.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/**
* WordPress dependencies
*/
import { useState, useId, useRef, flushSync } from '@wordpress/element';
import { useState, useId } from '@wordpress/element';
import { InspectorControls } from '@wordpress/block-editor';
import { ToggleControl, BaseControl, Button } from '@wordpress/components';
import { BaseControl, Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';

/**
Expand All @@ -13,7 +13,10 @@ import {
PARTIAL_SYNCING_SUPPORTED_BLOCKS,
PATTERN_OVERRIDES_BINDING_SOURCE,
} from '../constants';
import AllowOverridesModal from './allow-overrides-modal';
import {
AllowOverridesModal,
DisallowOverridesModal,
} from './allow-overrides-modal';

function removeBindings( bindings, syncedAttributes ) {
let updatedBindings = {};
Expand Down Expand Up @@ -47,9 +50,10 @@ function addBindings( bindings, syncedAttributes ) {

function PatternOverridesControls( { attributes, name, setAttributes } ) {
const controlId = useId();
const toggleRef = useRef();
const [ showAllowOverridesModal, setShowAllowOverridesModal ] =
useState( false );
const [ showDisallowOverridesModal, setShowDisallowOverridesModal ] =
useState( false );

const syncedAttributes = PARTIAL_SYNCING_SUPPORTED_BLOCKS[ name ];
const attributeSources = syncedAttributes.map(
Expand Down Expand Up @@ -83,7 +87,12 @@ function PatternOverridesControls( { attributes, name, setAttributes } ) {
// Avoid overwriting other (e.g. meta) bindings.
if ( isConnectedToOtherSources ) return null;

const hasName = attributes.metadata?.name;
const hasName = !! attributes.metadata?.name;
const allowOverrides =
hasName &&
attributeSources.some(
( source ) => source === PATTERN_OVERRIDES_BINDING_SOURCE
);

return (
<>
Expand All @@ -92,45 +101,42 @@ function PatternOverridesControls( { attributes, name, setAttributes } ) {
id={ controlId }
label={ __( 'Overrides' ) }
help={ __(
'Allow attributes within this block to be overridden by pattern instances.'
'Allow changes to this block throughout instances of this pattern.'
) }
>
{ hasName ? (
<ToggleControl
__nextHasNoMarginBottom
label={ __( 'Allow overrides' ) }
checked={ attributeSources.some(
( source ) =>
source === PATTERN_OVERRIDES_BINDING_SOURCE
) }
onChange={ ( isChecked ) => {
updateBindings( isChecked );
} }
ref={ toggleRef }
/>
) : (
<Button
className="pattern-overrides-control__allow-overrides-button"
variant="secondary"
onClick={ () => setShowAllowOverridesModal( true ) }
>
{ __( 'Allow overrides' ) }
</Button>
) }
<Button
kevin940726 marked this conversation as resolved.
Show resolved Hide resolved
className="pattern-overrides-control__allow-overrides-button"
variant="secondary"
onClick={ () => {
if ( allowOverrides ) {
setShowDisallowOverridesModal( true );
} else {
setShowAllowOverridesModal( true );
}
} }
>
{ allowOverrides
? __( 'Disable overrides' )
: __( 'Enable overrides' ) }
</Button>
</BaseControl>
</InspectorControls>

{ showAllowOverridesModal && (
<AllowOverridesModal
initialName={ attributes.metadata?.name }
onClose={ () => setShowAllowOverridesModal( false ) }
onSave={ ( newName ) => {
flushSync( () => {
updateBindings( true, newName );
} );
toggleRef.current?.focus();
updateBindings( true, newName );
} }
/>
) }
{ showDisallowOverridesModal && (
<DisallowOverridesModal
onClose={ () => setShowDisallowOverridesModal( false ) }
onSave={ () => updateBindings( false ) }
/>
) }
</>
);
}
Expand Down
4 changes: 4 additions & 0 deletions packages/patterns/src/components/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,7 @@
width: 100%;
justify-content: center;
}

.block-editor-block-allow-overrides-modal__description {
margin: 0;
}
8 changes: 6 additions & 2 deletions test/e2e/specs/editor/various/pattern-overrides.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,12 @@ test.describe( 'Pattern Overrides', () => {
.getByRole( 'button', { name: 'Advanced' } )
.click();
await editorSettings
.getByRole( 'checkbox', { name: 'Allow overrides' } )
.setChecked( true );
.getByRole( 'button', { name: 'Enable overrides' } )
.click();
await page
.getByRole( 'dialog', { name: 'Enable overrides' } )
.getByRole( 'button', { name: 'Enable overrides' } )
.click();

await expect.poll( editor.getBlocks ).toMatchObject( [
{
Expand Down
Loading