Skip to content

Commit

Permalink
Use standard select element for small number of authors. (#26426)
Browse files Browse the repository at this point in the history
* Use standard select element for small number of authors.

* Restore changed file.

* restore changed file

* Rename post-author to post-author-combobox.

* Reintroduce HTML select based post author selector.

* Introduce top level PostAuthor displays PostAuthorSelect or PostAuthorCombobox.

* Reduce post author check query size.

* Restore file from master.

* Refactor PostAuthorSelect as functional component.

* Restore packages/editor/src/components/post-author/check.js from master.

* Small tweaks

Co-authored-by: Riad Benguella <[email protected]>
  • Loading branch information
adamsilverstein and youknowriad authored Jan 3, 2021
1 parent 5f61405 commit 8be8de1
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 100 deletions.
108 changes: 108 additions & 0 deletions packages/editor/src/components/post-author/combobox.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/**
* External dependencies
*/
import { debounce } from 'lodash';

/**
* WordPress dependencies
*/
import { useState, useMemo, useEffect } from '@wordpress/element';
import { useSelect, useDispatch } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
import { ComboboxControl } from '@wordpress/components';

function PostAuthorCombobox() {
const [ fieldValue, setFieldValue ] = useState();

const { authorId, isLoading, authors, postAuthor } = useSelect(
( select ) => {
const { __unstableGetAuthor, getAuthors, isResolving } = select(
'core'
);
const { getEditedPostAttribute } = select( 'core/editor' );
const author = __unstableGetAuthor(
getEditedPostAttribute( 'author' )
);
const query =
! fieldValue || '' === fieldValue ? {} : { search: fieldValue };
return {
authorId: getEditedPostAttribute( 'author' ),
postAuthor: author,
authors: getAuthors( query ),
isLoading: isResolving( 'core', 'getAuthors', [ query ] ),
};
},
[ fieldValue ]
);
const { editPost } = useDispatch( 'core/editor' );

const authorOptions = useMemo( () => {
const fetchedAuthors = ( authors ?? [] ).map( ( author ) => {
return {
value: author.id,
label: author.name,
};
} );

// Ensure the current author is included in the dropdown list.
const foundAuthor = fetchedAuthors.findIndex(
( { value } ) => postAuthor?.id === value
);

if ( foundAuthor < 0 && postAuthor ) {
return [
{ value: postAuthor.id, label: postAuthor.name },
...fetchedAuthors,
];
}

return fetchedAuthors;
}, [ authors, postAuthor ] );

// Initializes the post author properly
// Also ensures external changes are reflected.
useEffect( () => {
if ( postAuthor ) {
setFieldValue( postAuthor.name );
}
}, [ postAuthor ] );

/**
* Handle author selection.
*
* @param {number} postAuthorId The selected Author.
*/
const handleSelect = ( postAuthorId ) => {
if ( ! postAuthorId ) {
return;
}
editPost( { author: postAuthorId } );
};

/**
* Handle user input.
*
* @param {string} inputValue The current value of the input field.
*/
const handleKeydown = ( inputValue ) => {
setFieldValue( inputValue );
};

if ( ! postAuthor ) {
return null;
}

return (
<ComboboxControl
label={ __( 'Author' ) }
options={ authorOptions }
value={ authorId }
onFilterValueChange={ debounce( handleKeydown, 300 ) }
onChange={ handleSelect }
isLoading={ isLoading }
allowReset={ false }
/>
);
}

export default PostAuthorCombobox;
114 changes: 14 additions & 100 deletions packages/editor/src/components/post-author/index.js
Original file line number Diff line number Diff line change
@@ -1,115 +1,29 @@
/**
* External dependencies
*/
import { debounce } from 'lodash';

/**
* WordPress dependencies
*/
import { useState, useMemo, useEffect } from '@wordpress/element';
import { useSelect, useDispatch } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
import { ComboboxControl } from '@wordpress/components';
import { useSelect } from '@wordpress/data';

/**
* Internal dependencies
*/
import PostAuthorCheck from './check';
import PostAuthorCombobox from './combobox';
import PostAuthorSelect from './select';

function PostAuthor() {
const [ fieldValue, setFieldValue ] = useState();
const minimumUsersForCombobox = 25;

const { authorId, isLoading, authors, postAuthor } = useSelect(
( select ) => {
const { __unstableGetAuthor, getAuthors, isResolving } = select(
'core'
);
const { getEditedPostAttribute } = select( 'core/editor' );
const author = __unstableGetAuthor(
getEditedPostAttribute( 'author' )
);
const query =
! fieldValue || '' === fieldValue ? {} : { search: fieldValue };
return {
authorId: getEditedPostAttribute( 'author' ),
postAuthor: author,
authors: getAuthors( query ),
isLoading: isResolving( 'core', 'getAuthors', [ query ] ),
};
},
[ fieldValue ]
);
const { editPost } = useDispatch( 'core/editor' );

const authorOptions = useMemo( () => {
const fetchedAuthors = ( authors ?? [] ).map( ( author ) => {
return {
value: author.id,
label: author.name,
};
function PostAuthor() {
const showCombobox = useSelect( ( select ) => {
const authors = select( 'core' ).getUsers( {
who: 'authors',
per_page: minimumUsersForCombobox + 1,
} );
return authors?.length >= minimumUsersForCombobox;
}, [] );

// Ensure the current author is included in the dropdown list.
const foundAuthor = fetchedAuthors.findIndex(
( { value } ) => postAuthor?.id === value
);

if ( foundAuthor < 0 && postAuthor ) {
return [
{ value: postAuthor.id, label: postAuthor.name },
...fetchedAuthors,
];
}

return fetchedAuthors;
}, [ authors, postAuthor ] );

// Initializes the post author properly
// Also ensures external changes are reflected.
useEffect( () => {
if ( postAuthor ) {
setFieldValue( postAuthor.name );
}
}, [ postAuthor ] );

/**
* Handle author selection.
*
* @param {number} postAuthorId The selected Author.
*/
const handleSelect = ( postAuthorId ) => {
if ( ! postAuthorId ) {
return;
}
editPost( { author: postAuthorId } );
};

/**
* Handle user input.
*
* @param {string} inputValue The current value of the input field.
*/
const handleKeydown = ( inputValue ) => {
setFieldValue( inputValue );
};

if ( ! postAuthor ) {
return null;
if ( showCombobox ) {
return <PostAuthorCombobox />;
}

return (
<PostAuthorCheck>
<ComboboxControl
label={ __( 'Author' ) }
options={ authorOptions }
value={ authorId }
onFilterValueChange={ debounce( handleKeydown, 300 ) }
onChange={ handleSelect }
isLoading={ isLoading }
allowReset={ false }
/>
</PostAuthorCheck>
);
return <PostAuthorSelect />;
}

export default PostAuthor;
40 changes: 40 additions & 0 deletions packages/editor/src/components/post-author/select.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { useSelect, useDispatch } from '@wordpress/data';
import { decodeEntities } from '@wordpress/html-entities';
import { SelectControl } from '@wordpress/components';

function PostAuthorSelect() {
const { editPost } = useDispatch( 'core/editor' );
const { postAuthor, authors } = useSelect( ( select ) => {
const authorsFromAPI = select( 'core' ).getAuthors();
return {
postAuthor: select( 'core/editor' ).getEditedPostAttribute(
'author'
),
authors: authorsFromAPI.map( ( author ) => ( {
label: decodeEntities( author.name ),
value: author.id,
} ) ),
};
}, [] );

const setAuthorId = ( value ) => {
const author = Number( value );
editPost( { author } );
};

return (
<SelectControl
className="post-author-selector"
label={ __( 'Author' ) }
options={ authors }
onChange={ setAuthorId }
value={ postAuthor }
/>
);
}

export default PostAuthorSelect;

0 comments on commit 8be8de1

Please sign in to comment.