@wordpress/editor
Version:
Enhanced block editor for WordPress posts.
195 lines (174 loc) • 4.82 kB
JavaScript
/**
* WordPress dependencies
*/
import { useSelect, useDispatch } from '@wordpress/data';
import { RangeControl, Spinner, Button } from '@wordpress/components';
import { store as coreStore } from '@wordpress/core-data';
import { __, sprintf } from '@wordpress/i18n';
import { dateI18n, getSettings as getDateSettings } from '@wordpress/date';
import { useMemo } from '@wordpress/element';
import { chevronLeft, chevronRight } from '@wordpress/icons';
import { Stack } from '@wordpress/ui';
/**
* Internal dependencies
*/
import { store as editorStore } from '../../store';
import { unlock } from '../../lock-unlock';
/**
* Slider component for navigating revisions with pagination.
*
* @return {React.JSX.Element} The revisions slider component.
*/
function RevisionsSlider() {
const {
revisions: rawRevisions,
perPage,
currentRevisionId,
revisionKey,
revisionPage,
totalRevisions,
} = useSelect( ( select ) => {
const {
getCurrentRevisionId,
getRevisionPage,
getPageRevisions,
getRevisionsPerPage,
} = unlock( select( editorStore ) );
const postType = select( editorStore ).getCurrentPostType();
if ( ! postType ) {
return {};
}
const entityConfig = select( coreStore ).getEntityConfig(
'postType',
postType
);
const _revisionKey = entityConfig?.revisionKey || 'id';
const _revisionPage = getRevisionPage();
return {
revisions: getPageRevisions( _revisionPage ),
perPage: getRevisionsPerPage(),
currentRevisionId: getCurrentRevisionId(),
revisionKey: _revisionKey,
revisionPage: _revisionPage,
totalRevisions:
select( editorStore ).getCurrentPostRevisionsCount(),
};
}, [] );
const { setCurrentRevisionId, setRevisionPage } = unlock(
useDispatch( editorStore )
);
const isLoading = ! rawRevisions;
const totalPages = Math.ceil( totalRevisions / perPage ) || 1;
// Reverse desc→asc so the slider reads oldest (left) → newest (right).
const revisions = useMemo(
() => rawRevisions && [ ...rawRevisions ].reverse(),
[ rawRevisions ]
);
const selectedIndex = revisions?.findIndex(
( r ) => r[ revisionKey ] === currentRevisionId
);
const handleSliderChange = ( index ) => {
const revision = revisions?.[ index ];
if ( revision ) {
setCurrentRevisionId( revision[ revisionKey ] );
}
};
// Format date for tooltip.
const dateSettings = getDateSettings();
const renderTooltipContent = ( index ) => {
const revision = revisions?.[ index ];
if ( ! revision ) {
return index;
}
return dateI18n( dateSettings.formats.datetime, revision.date );
};
const showPagination = totalPages > 1;
if ( isLoading && ! showPagination ) {
return <Spinner />;
}
if ( ! isLoading && ! revisions?.length ) {
return (
<span className="editor-revisions-header__no-revisions">
{ __( 'No revisions found.' ) }
</span>
);
}
if ( totalRevisions <= 1 ) {
return (
<span className="editor-revisions-header__no-revisions">
{ __( 'Only one revision found.' ) }
</span>
);
}
const getPageRangeLabel = ( page ) => {
const end = totalRevisions - ( page - 1 ) * perPage;
const start = Math.max( 1, end - perPage + 1 );
return sprintf(
/* translators: 1: first revision number, 2: last revision number */
__( 'Revisions %1$s–%2$s' ),
start,
end
);
};
const sliderOrSpinner =
isLoading || selectedIndex === -1 ? (
<Spinner />
) : (
<RangeControl
__next40pxDefaultSize
aria-valuetext={ renderTooltipContent( selectedIndex ) }
className="editor-revisions-header__slider"
hideLabelFromVision
label={ __( 'Revision' ) }
max={ revisions?.length - 1 }
min={ 0 }
marks
onChange={ handleSliderChange }
renderTooltipContent={ renderTooltipContent }
value={ selectedIndex }
withInputField={ false }
/>
);
if ( ! showPagination ) {
return sliderOrSpinner;
}
return (
<Stack direction="row" gap="sm" align="center" style={ { flex: 1 } }>
<Button
icon={ chevronLeft }
label={
revisionPage < totalPages
? getPageRangeLabel( revisionPage + 1 )
: __( 'No older revisions' )
}
onClick={ () => setRevisionPage( revisionPage + 1 ) }
disabled={ isLoading || revisionPage >= totalPages }
size="compact"
accessibleWhenDisabled
/>
<div
style={ {
flex: 1,
minWidth: 0,
display: 'flex',
justifyContent: 'center',
} }
>
{ sliderOrSpinner }
</div>
<Button
icon={ chevronRight }
label={
revisionPage > 1
? getPageRangeLabel( revisionPage - 1 )
: __( 'No newer revisions' )
}
onClick={ () => setRevisionPage( revisionPage - 1 ) }
disabled={ isLoading || revisionPage <= 1 }
size="compact"
accessibleWhenDisabled
/>
</Stack>
);
}
export default RevisionsSlider;