Skip to content

Commit

Permalink
Editor: Use hooks instead of HoCs in 'DocumentOutline' (#59209)
Browse files Browse the repository at this point in the history
Co-authored-by: Mamaduka <[email protected]>
Co-authored-by: t-hamano <[email protected]>
  • Loading branch information
3 people authored Feb 22, 2024
1 parent efe7d2e commit 568d766
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

1 comment on commit 568d766

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flaky tests detected in 568d766.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/8000518778
📝 Reported issues:

Please sign in to comment.