Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Site Editor: Fix the tooltip and shortcut for the global save button #48282

Merged
merged 1 commit into from
Feb 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions packages/edit-site/src/components/editor/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { __, sprintf } from '@wordpress/i18n';
import { SidebarComplementaryAreaFills } from '../sidebar-edit-mode';
import BlockEditor from '../block-editor';
import CodeEditor from '../code-editor';
import KeyboardShortcuts from '../keyboard-shortcuts';
import KeyboardShortcutsEditMode from '../keyboard-shortcuts/edit-mode';
import InserterSidebar from '../secondary-sidebar/inserter-sidebar';
import ListViewSidebar from '../secondary-sidebar/list-view-sidebar';
import WelcomeGuide from '../welcome-guide';
Expand Down Expand Up @@ -151,7 +151,6 @@ export default function Editor() {
return (
<>
{ isEditMode && <WelcomeGuide /> }
<KeyboardShortcuts.Register />
<EntityProvider kind="root" type="site">
<EntityProvider
kind="postType"
Expand Down Expand Up @@ -188,7 +187,9 @@ export default function Editor() {
) }
</Notice>
) }
{ isEditMode && <KeyboardShortcuts /> }
{ isEditMode && (
<KeyboardShortcutsEditMode />
) }
</>
}
secondarySidebar={
Expand Down
116 changes: 116 additions & 0 deletions packages/edit-site/src/components/keyboard-shortcuts/edit-mode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/**
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I didn't make any change to these three files, I just split the previous "index.js" file into three components in order to be able to insert them in different contexts. That way we can always make sure that the "save shortcut" works in all modes.

* WordPress dependencies
*/
import { useShortcut } from '@wordpress/keyboard-shortcuts';
import { useDispatch, useSelect } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';
import { store as blockEditorStore } from '@wordpress/block-editor';
import { store as interfaceStore } from '@wordpress/interface';
import { createBlock } from '@wordpress/blocks';

/**
* Internal dependencies
*/
import { store as editSiteStore } from '../../store';
import { SIDEBAR_BLOCK } from '../sidebar-edit-mode/constants';
import { STORE_NAME } from '../../store/constants';

function KeyboardShortcutsEditMode() {
const { getEditorMode } = useSelect( editSiteStore );
const isListViewOpen = useSelect(
( select ) => select( editSiteStore ).isListViewOpened(),
[]
);
const isBlockInspectorOpen = useSelect(
( select ) =>
select( interfaceStore ).getActiveComplementaryArea(
editSiteStore.name
) === SIDEBAR_BLOCK,
[]
);
const { redo, undo } = useDispatch( coreStore );
const { setIsListViewOpened, switchEditorMode } =
useDispatch( editSiteStore );
const { enableComplementaryArea, disableComplementaryArea } =
useDispatch( interfaceStore );

const { replaceBlocks } = useDispatch( blockEditorStore );
const { getBlockName, getSelectedBlockClientId, getBlockAttributes } =
useSelect( blockEditorStore );

const handleTextLevelShortcut = ( event, level ) => {
event.preventDefault();
const destinationBlockName =
level === 0 ? 'core/paragraph' : 'core/heading';
const currentClientId = getSelectedBlockClientId();
if ( currentClientId === null ) {
return;
}
const blockName = getBlockName( currentClientId );
if ( blockName !== 'core/paragraph' && blockName !== 'core/heading' ) {
return;
}
const attributes = getBlockAttributes( currentClientId );
const textAlign =
blockName === 'core/paragraph' ? 'align' : 'textAlign';
const destinationTextAlign =
destinationBlockName === 'core/paragraph' ? 'align' : 'textAlign';

replaceBlocks(
currentClientId,
createBlock( destinationBlockName, {
level,
content: attributes.content,
...{ [ destinationTextAlign ]: attributes[ textAlign ] },
} )
);
};

useShortcut( 'core/edit-site/undo', ( event ) => {
undo();
event.preventDefault();
} );

useShortcut( 'core/edit-site/redo', ( event ) => {
redo();
event.preventDefault();
} );

useShortcut( 'core/edit-site/toggle-list-view', () => {
setIsListViewOpened( ! isListViewOpen );
} );

useShortcut( 'core/edit-site/toggle-block-settings-sidebar', ( event ) => {
// This shortcut has no known clashes, but use preventDefault to prevent any
// obscure shortcuts from triggering.
event.preventDefault();

if ( isBlockInspectorOpen ) {
disableComplementaryArea( STORE_NAME );
} else {
enableComplementaryArea( STORE_NAME, SIDEBAR_BLOCK );
}
} );

useShortcut( 'core/edit-site/toggle-mode', () => {
switchEditorMode( getEditorMode() === 'visual' ? 'text' : 'visual' );
} );

useShortcut( 'core/edit-site/transform-heading-to-paragraph', ( event ) =>
handleTextLevelShortcut( event, 0 )
);

[ 1, 2, 3, 4, 5, 6 ].forEach( ( level ) => {
//the loop is based off on a constant therefore
//the hook will execute the same way every time
//eslint-disable-next-line react-hooks/rules-of-hooks
useShortcut(
`core/edit-site/transform-paragraph-to-heading-${ level }`,
( event ) => handleTextLevelShortcut( event, level )
);
} );

return null;
}

export default KeyboardShortcutsEditMode;
35 changes: 35 additions & 0 deletions packages/edit-site/src/components/keyboard-shortcuts/global.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* WordPress dependencies
*/
import { useShortcut } from '@wordpress/keyboard-shortcuts';
import { useDispatch, useSelect } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';

/**
* Internal dependencies
*/
import { store as editSiteStore } from '../../store';

function KeyboardShortcutsGlobal() {
const { __experimentalGetDirtyEntityRecords, isSavingEntityRecord } =
useSelect( coreStore );
const { setIsSaveViewOpened } = useDispatch( editSiteStore );

useShortcut( 'core/edit-site/save', ( event ) => {
event.preventDefault();

const dirtyEntityRecords = __experimentalGetDirtyEntityRecords();
const isDirty = !! dirtyEntityRecords.length;
const isSaving = dirtyEntityRecords.some( ( record ) =>
isSavingEntityRecord( record.kind, record.name, record.key )
);

if ( ! isSaving && isDirty ) {
setIsSaveViewOpened( true );
}
} );

return null;
}

export default KeyboardShortcutsGlobal;
157 changes: 157 additions & 0 deletions packages/edit-site/src/components/keyboard-shortcuts/register.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/**
* WordPress dependencies
*/
import { useEffect } from '@wordpress/element';
import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts';
import { isAppleOS } from '@wordpress/keycodes';
import { useDispatch } from '@wordpress/data';
import { __ } from '@wordpress/i18n';

function KeyboardShortcutsRegister() {
// Registering the shortcuts.
const { registerShortcut } = useDispatch( keyboardShortcutsStore );
useEffect( () => {
registerShortcut( {
name: 'core/edit-site/save',
category: 'global',
description: __( 'Save your changes.' ),
keyCombination: {
modifier: 'primary',
character: 's',
},
} );

registerShortcut( {
name: 'core/edit-site/undo',
category: 'global',
description: __( 'Undo your last changes.' ),
keyCombination: {
modifier: 'primary',
character: 'z',
},
} );

registerShortcut( {
name: 'core/edit-site/redo',
category: 'global',
description: __( 'Redo your last undo.' ),
keyCombination: {
modifier: 'primaryShift',
character: 'z',
},
// Disable on Apple OS because it conflicts with the browser's
// history shortcut. It's a fine alias for both Windows and Linux.
// Since there's no conflict for Ctrl+Shift+Z on both Windows and
// Linux, we keep it as the default for consistency.
aliases: isAppleOS()
? []
: [
{
modifier: 'primary',
character: 'y',
},
],
} );

registerShortcut( {
name: 'core/edit-site/toggle-list-view',
category: 'global',
description: __( 'Open the block list view.' ),
keyCombination: {
modifier: 'access',
character: 'o',
},
} );

registerShortcut( {
name: 'core/edit-site/toggle-block-settings-sidebar',
category: 'global',
description: __( 'Show or hide the block settings sidebar.' ),
keyCombination: {
modifier: 'primaryShift',
character: ',',
},
} );

registerShortcut( {
name: 'core/edit-site/keyboard-shortcuts',
category: 'main',
description: __( 'Display these keyboard shortcuts.' ),
keyCombination: {
modifier: 'access',
character: 'h',
},
} );

registerShortcut( {
name: 'core/edit-site/next-region',
category: 'global',
description: __( 'Navigate to the next part of the editor.' ),
keyCombination: {
modifier: 'ctrl',
character: '`',
},
aliases: [
{
modifier: 'access',
character: 'n',
},
],
} );

registerShortcut( {
name: 'core/edit-site/previous-region',
category: 'global',
description: __( 'Navigate to the previous part of the editor.' ),
keyCombination: {
modifier: 'ctrlShift',
character: '`',
},
aliases: [
{
modifier: 'access',
character: 'p',
},
{
modifier: 'ctrlShift',
character: '~',
},
],
} );
registerShortcut( {
name: 'core/edit-site/toggle-mode',
category: 'global',
description: __( 'Switch between visual editor and code editor.' ),
keyCombination: {
modifier: 'secondary',
character: 'm',
},
} );

registerShortcut( {
name: `core/edit-site/transform-heading-to-paragraph`,
category: 'block-library',
description: __( 'Transform heading to paragraph.' ),
keyCombination: {
modifier: 'access',
character: `0`,
},
} );

[ 1, 2, 3, 4, 5, 6 ].forEach( ( level ) => {
registerShortcut( {
name: `core/edit-site/transform-paragraph-to-heading-${ level }`,
category: 'block-library',
description: __( 'Transform paragraph to heading.' ),
keyCombination: {
modifier: 'access',
character: `${ level }`,
},
} );
} );
}, [ registerShortcut ] );

return null;
}

export default KeyboardShortcutsRegister;
4 changes: 4 additions & 0 deletions packages/edit-site/src/components/layout/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ import ResizeHandle from '../block-editor/resize-handle';
import useSyncCanvasModeWithURL from '../sync-state-with-url/use-sync-canvas-mode-with-url';
import { unlock } from '../../private-apis';
import SavePanel from '../save-panel';
import KeyboardShortcutsRegister from '../keyboard-shortcuts/register';
import KeyboardShortcutsGlobal from '../keyboard-shortcuts/global';

const ANIMATION_DURATION = 0.5;
const emptyResizeHandleStyles = {
Expand Down Expand Up @@ -121,6 +123,8 @@ export default function Layout() {

return (
<>
<KeyboardShortcutsRegister />
<KeyboardShortcutsGlobal />
{ fullResizer }
<div
{ ...navigateRegionsProps }
Expand Down
4 changes: 2 additions & 2 deletions packages/edit-site/src/components/save-button/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { displayShortcut } from '@wordpress/keycodes';
*/
import { store as editSiteStore } from '../../store';

export default function SaveButton() {
export default function SaveButton( { showTooltip = true } ) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a reason for keeping the tooltip in the header Save button when is disabled?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, there is. In the post editor we want to force the tooltip to show regardless of whether there's a shortcut.

const { isDirty, isSaving, isSaveViewOpen } = useSelect( ( select ) => {
const { __experimentalGetDirtyEntityRecords, isSavingEntityRecord } =
select( coreStore );
Expand Down Expand Up @@ -52,7 +52,7 @@ export default function SaveButton() {
* of the button that we want to avoid. By setting `showTooltip`,
& the tooltip is always rendered even when there's no keyboard shortcut.
*/
showTooltip
showTooltip={ showTooltip }
>
{ label }
</Button>
Expand Down
2 changes: 1 addition & 1 deletion packages/edit-site/src/components/sidebar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ function Sidebar() {
</NavigatorProvider>

<div className="edit-site-sidebar__footer">
<SaveButton />
<SaveButton showTooltip={ false } />
</div>
</>
);
Expand Down