Skip to content

Commit

Permalink
Editor: Use hooks instead of HoCs in 'DocumentOutline'
Browse files Browse the repository at this point in the history
  • Loading branch information
Mamaduka committed Feb 22, 2024
1 parent efe7d2e commit 1ba6eef
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 40 deletions.
18 changes: 8 additions & 10 deletions packages/editor/src/components/document-outline/check.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
/**
* WordPress dependencies
*/
import { withSelect } from '@wordpress/data';
import { useSelect } from '@wordpress/data';
import { store as blockEditorStore } from '@wordpress/block-editor';

function DocumentOutlineCheck( { blocks, children } ) {
const headings = blocks.filter(
( block ) => block.name === 'core/heading'
);
export default function DocumentOutlineCheck( { children } ) {
const hasHeadings = useSelect( ( select ) => {
const { getGlobalBlockCount } = select( blockEditorStore );

if ( headings.length < 1 ) {
return getGlobalBlockCount( 'core/heading' ) > 0;
} );

if ( hasHeadings ) {
return null;
}

return children;
}

export default withSelect( ( select ) => ( {
blocks: select( blockEditorStore ).getBlocks(),
} ) )( DocumentOutlineCheck );
41 changes: 18 additions & 23 deletions packages/editor/src/components/document-outline/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { compose } from '@wordpress/compose';
import { withSelect, useDispatch } from '@wordpress/data';
import { useDispatch, useSelect } from '@wordpress/data';
import { create, getTextContent } from '@wordpress/rich-text';
import { store as blockEditorStore } from '@wordpress/block-editor';
import { store as coreStore } from '@wordpress/core-data';
Expand Down Expand Up @@ -98,15 +97,26 @@ const computeOutlineHeadings = ( blocks = [] ) => {
const isEmptyHeading = ( heading ) =>
! heading.attributes.content || heading.attributes.content.length === 0;

export const DocumentOutline = ( {
blocks = [],
title,
export default function DocumentOutline( {
onSelect,
isTitleSupported,
hasOutlineItemsDisabled,
} ) => {
const headings = computeOutlineHeadings( blocks );
} ) {
const { selectBlock } = useDispatch( blockEditorStore );
const { blocks, title } = useSelect( ( select ) => {
const { getBlocks } = select( blockEditorStore );
const { getEditedPostAttribute } = select( editorStore );
const { getPostType } = select( coreStore );
const postType = getPostType( getEditedPostAttribute( 'type' ) );

return {
title: getEditedPostAttribute( 'title' ),
blocks: getBlocks(),
isTitleSupported: postType?.supports?.title ?? false,
};
} );

const headings = computeOutlineHeadings( blocks );
if ( headings.length < 1 ) {
return (
<div className="editor-document-outline has-no-headings">
Expand Down Expand Up @@ -194,19 +204,4 @@ export const DocumentOutline = ( {
</ul>
</div>
);
};

export default compose(
withSelect( ( select ) => {
const { getBlocks } = select( blockEditorStore );
const { getEditedPostAttribute } = select( editorStore );
const { getPostType } = select( coreStore );
const postType = getPostType( getEditedPostAttribute( 'type' ) );

return {
title: getEditedPostAttribute( 'title' ),
blocks: getBlocks(),
isTitleSupported: postType?.supports?.title ?? false,
};
} )
)( DocumentOutline );
}
33 changes: 26 additions & 7 deletions packages/editor/src/components/document-outline/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,27 @@ import {
registerBlockType,
unregisterBlockType,
} from '@wordpress/blocks';
import { useSelect } from '@wordpress/data';

/**
* Internal dependencies
*/
import { DocumentOutline } from '../';
import DocumentOutline from '../';

jest.mock( '@wordpress/block-editor', () => ( {
BlockTitle: () => 'Block Title',
} ) );
jest.mock( '@wordpress/data/src/components/use-select', () => jest.fn() );

function setupMockSelect( blocks ) {
useSelect.mockImplementation( ( mapSelect ) => {
return mapSelect( () => ( {
getBlocks: () => blocks,
getEditedPostAttribute: () => null,
getPostType: () => null,
} ) );
} );
}

describe( 'DocumentOutline', () => {
let paragraph, headingH1, headingH2, headingH3, nestedHeading;
Expand Down Expand Up @@ -77,6 +89,7 @@ describe( 'DocumentOutline', () => {

describe( 'no header blocks present', () => {
it( 'should not render when no blocks provided', () => {
setupMockSelect( [] );
render( <DocumentOutline /> );

expect( screen.queryByRole( 'list' ) ).not.toBeInTheDocument();
Expand All @@ -87,7 +100,8 @@ describe( 'DocumentOutline', () => {
// Set client IDs to a predictable value.
return { ...block, clientId: `clientId_${ index }` };
} );
render( <DocumentOutline blocks={ blocks } /> );
setupMockSelect( blocks );
render( <DocumentOutline /> );

expect( screen.queryByRole( 'list' ) ).not.toBeInTheDocument();
} );
Expand All @@ -99,14 +113,16 @@ describe( 'DocumentOutline', () => {
// Set client IDs to a predictable value.
return { ...block, clientId: `clientId_${ index }` };
} );
render( <DocumentOutline blocks={ blocks } /> );
setupMockSelect( blocks );
render( <DocumentOutline /> );

expect( screen.getByRole( 'list' ) ).toMatchSnapshot();
} );

it( 'should render an item when only one heading provided', () => {
const blocks = [ headingH2 ];
render( <DocumentOutline blocks={ blocks } /> );
setupMockSelect( blocks );
render( <DocumentOutline /> );

const tableOfContentItem = within(
screen.getByRole( 'list' )
Expand All @@ -123,7 +139,8 @@ describe( 'DocumentOutline', () => {
headingH3,
paragraph,
];
render( <DocumentOutline blocks={ blocks } /> );
setupMockSelect( blocks );
render( <DocumentOutline /> );

expect(
within( screen.getByRole( 'list' ) ).getAllByRole( 'listitem' )
Expand All @@ -137,7 +154,8 @@ describe( 'DocumentOutline', () => {
return { ...block, clientId: `clientId_${ index }` };
}
);
render( <DocumentOutline blocks={ blocks } /> );
setupMockSelect( blocks );
render( <DocumentOutline /> );

expect( screen.getByRole( 'list' ) ).toMatchSnapshot();
} );
Expand All @@ -146,7 +164,8 @@ describe( 'DocumentOutline', () => {
describe( 'nested headings', () => {
it( 'should render even if the heading is nested', () => {
const blocks = [ headingH2, nestedHeading ];
render( <DocumentOutline blocks={ blocks } /> );
setupMockSelect( blocks );
render( <DocumentOutline /> );

// Unnested heading and nested heading should appear as items.
const tableOfContentItems = within(
Expand Down

0 comments on commit 1ba6eef

Please sign in to comment.