Skip to content

Commit

Permalink
Add a control per block to reset pattern overrides
Browse files Browse the repository at this point in the history
  • Loading branch information
kevin940726 committed Jan 17, 2024
1 parent 2881d64 commit d8e58d6
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 2 deletions.
17 changes: 15 additions & 2 deletions packages/block-library/src/block/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
} from '@wordpress/block-editor';
import { privateApis as patternsPrivateApis } from '@wordpress/patterns';
import { parse, cloneBlock } from '@wordpress/blocks';
import { RichTextData } from '@wordpress/rich-text';

/**
* Internal dependencies
Expand Down Expand Up @@ -117,6 +118,16 @@ function applyInitialOverrides( blocks, overrides = {}, defaultValues ) {
} );
}

function isAttributeEqual( attribute1, attribute2 ) {
if (
attribute1 instanceof RichTextData &&
attribute2 instanceof RichTextData
) {
return attribute1.toString() === attribute2.toString();
}
return attribute1 === attribute2;
}

function getOverridesFromBlocks( blocks, defaultValues ) {
/** @type {Record<string, Record<string, unknown>>} */
const overrides = {};
Expand All @@ -130,8 +141,10 @@ function getOverridesFromBlocks( blocks, defaultValues ) {
const attributes = getPartiallySyncedAttributes( block );
for ( const attributeKey of attributes ) {
if (
block.attributes[ attributeKey ] !==
defaultValues[ blockId ][ attributeKey ]
! isAttributeEqual(
block.attributes[ attributeKey ],
defaultValues[ blockId ][ attributeKey ]
)
) {
overrides[ blockId ] ??= {};
// TODO: We need a way to represent `undefined` in the serialized overrides.
Expand Down
42 changes: 42 additions & 0 deletions packages/editor/src/hooks/pattern-partial-syncing.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { unlock } from '../lock-unlock';

const {
PartialSyncingControls,
ResetOverridesControl,
PATTERN_TYPES,
PARTIAL_SYNCING_SUPPORTED_BLOCKS,
} = unlock( patternsPrivateApis );
Expand Down Expand Up @@ -57,10 +58,51 @@ const withPartialSyncingControls = createHigherOrderComponent(
}
);

const withResetPatternOverrides = createHigherOrderComponent(
( BlockEdit ) => ( props ) => {
const bindings = props.attributes.metadata?.bindings;
const hasPatternBindings =
!! bindings &&
Object.values( bindings ).some(
( binding ) => binding.source?.name === 'pattern_attributes'
);
const isEditingPattern = useSelect(
( select ) =>
select( editorStore ).getCurrentPostType() ===
PATTERN_TYPES.user,
[]
);

const shouldShowResetOverridesControl =
props.isSelected &&
! isEditingPattern &&
!! props.attributes.metadata?.id &&
hasPatternBindings &&
Object.keys( PARTIAL_SYNCING_SUPPORTED_BLOCKS ).includes(
props.name
);

return (
<>
<BlockEdit { ...props } />
{ shouldShowResetOverridesControl && (
<ResetOverridesControl { ...props } />
) }
</>
);
}
);

if ( window.__experimentalPatternPartialSyncing ) {
addFilter(
'editor.BlockEdit',
'core/editor/with-partial-syncing-controls',
withPartialSyncingControls
);

addFilter(
'editor.BlockEdit',
'core/editor/with-reset-pattern-overrides',
withResetPatternOverrides
);
}
75 changes: 75 additions & 0 deletions packages/patterns/src/components/reset-overrides-control.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/**
* WordPress dependencies
*/
import {
store as blockEditorStore,
BlockControls,
} from '@wordpress/block-editor';
import { ToolbarButton, ToolbarGroup } from '@wordpress/components';
import { useSelect, useRegistry } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';
import { parse } from '@wordpress/blocks';
import { __ } from '@wordpress/i18n';

function recursivelyFindBlockWithId( blocks, id ) {
return blocks.find( ( block ) => {
if ( block.attributes.metadata?.id === id ) {
return block;
}

return recursivelyFindBlockWithId( block.innerBlocks, id );
} );
}

export default function ResetOverridesControl( props ) {
const registry = useRegistry();
const id = props.attributes.metadata?.id;
const patternWithOverrides = useSelect(
( select ) => {
if ( ! id ) {
return undefined;
}

const { getBlockParentsByBlockName, getBlocksByClientId } =
select( blockEditorStore );
const patternBlock = getBlocksByClientId(
getBlockParentsByBlockName( props.clientId, 'core/block' )
)[ 0 ];

if ( ! patternBlock?.attributes.overrides?.[ id ] ) {
return undefined;
}

return patternBlock;
},
[ props.clientId, id ]
);

const resetOverrides = async () => {
const editedRecord = await registry
.resolveSelect( coreStore )
.getEditedEntityRecord(
'postType',
'wp_block',
patternWithOverrides.attributes.ref
);
const blocks = editedRecord.blocks ?? parse( editedRecord.content );
const block = recursivelyFindBlockWithId( blocks, id );

props.setAttributes( block.attributes );
};

return (
<BlockControls>
<ToolbarGroup>
<ToolbarButton
onClick={ resetOverrides }
disabled={ ! patternWithOverrides }
__experimentalIsFocusable
>
{ __( 'Reset to original' ) }
</ToolbarButton>
</ToolbarGroup>
</BlockControls>
);
}
2 changes: 2 additions & 0 deletions packages/patterns/src/private-apis.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import RenamePatternModal from './components/rename-pattern-modal';
import PatternsMenuItems from './components';
import RenamePatternCategoryModal from './components/rename-pattern-category-modal';
import PartialSyncingControls from './components/partial-syncing-controls';
import ResetOverridesControl from './components/reset-overrides-control';
import {
PATTERN_TYPES,
PATTERN_DEFAULT_CATEGORY,
Expand All @@ -33,6 +34,7 @@ lock( privateApis, {
PatternsMenuItems,
RenamePatternCategoryModal,
PartialSyncingControls,
ResetOverridesControl,
PATTERN_TYPES,
PATTERN_DEFAULT_CATEGORY,
PATTERN_USER_CATEGORY,
Expand Down

0 comments on commit d8e58d6

Please sign in to comment.