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

Add keyboard shortcuts for moving blocks #23276

Merged
merged 14 commits into from Jun 25, 2020

Conversation

ntsekouras
Copy link
Contributor

@ntsekouras ntsekouras commented Jun 18, 2020

Description

Resolves #10455

This PR adds keyboard shortcuts for moving blocks up and down.

Keyboard combinations for macOS:

  • Move up: T
  • Move down: Y

Windows/Linux:

  • Move up: Ctrl+Alt+Shift+T
  • Move down: Ctrl+Alt+Shift+Y

How has this been tested?

Screenshots

Types of changes

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • My code follows the accessibility standards.
  • My code has proper inline documentation.
  • I've included developer documentation if appropriate.
  • I've updated all React Native files affected by any refactorings/renamings in this PR.

@ntsekouras ntsekouras self-assigned this Jun 18, 2020
@ntsekouras ntsekouras added [a11y] Keyboard & Focus [Type] Enhancement A suggestion for improvement. [Focus] Accessibility (a11y) Changes that impact accessibility and need corresponding review (e.g. markup changes). labels Jun 18, 2020
@github-actions
Copy link

github-actions bot commented Jun 18, 2020

Size Change: +112 B (0%)

Total Size: 1.13 MB

Filename Size Change
build/block-editor/index.js 108 kB +112 B (0%)
ℹ️ View Unchanged
Filename Size Change
build/a11y/index.js 1.14 kB 0 B
build/annotations/index.js 3.62 kB 0 B
build/api-fetch/index.js 3.4 kB 0 B
build/autop/index.js 2.82 kB 0 B
build/blob/index.js 620 B 0 B
build/block-directory/index.js 7.37 kB 0 B
build/block-directory/style-rtl.css 941 B 0 B
build/block-directory/style.css 942 B 0 B
build/block-editor/style-rtl.css 10.7 kB 0 B
build/block-editor/style.css 10.7 kB 0 B
build/block-library/editor-rtl.css 7.59 kB 0 B
build/block-library/editor.css 7.6 kB 0 B
build/block-library/index.js 129 kB 0 B
build/block-library/style-rtl.css 8.04 kB 0 B
build/block-library/style.css 8.04 kB 0 B
build/block-library/theme-rtl.css 730 B 0 B
build/block-library/theme.css 732 B 0 B
build/block-serialization-default-parser/index.js 1.88 kB 0 B
build/block-serialization-spec-parser/index.js 3.1 kB 0 B
build/blocks/index.js 48.2 kB 0 B
build/components/index.js 197 kB 0 B
build/components/style-rtl.css 15.8 kB 0 B
build/components/style.css 15.8 kB 0 B
build/compose/index.js 9.62 kB 0 B
build/core-data/index.js 11.4 kB 0 B
build/data-controls/index.js 1.29 kB 0 B
build/data/index.js 8.44 kB 0 B
build/date/index.js 5.47 kB 0 B
build/deprecated/index.js 772 B 0 B
build/dom-ready/index.js 569 B 0 B
build/dom/index.js 3.19 kB 0 B
build/edit-navigation/index.js 9.87 kB 0 B
build/edit-navigation/style-rtl.css 1.02 kB 0 B
build/edit-navigation/style.css 1.02 kB 0 B
build/edit-post/index.js 303 kB 0 B
build/edit-post/style-rtl.css 5.5 kB 0 B
build/edit-post/style.css 5.5 kB 0 B
build/edit-site/index.js 16.6 kB 0 B
build/edit-site/style-rtl.css 3.02 kB 0 B
build/edit-site/style.css 3.02 kB 0 B
build/edit-widgets/index.js 9.32 kB 0 B
build/edit-widgets/style-rtl.css 2.42 kB 0 B
build/edit-widgets/style.css 2.42 kB 0 B
build/editor/editor-styles-rtl.css 537 B 0 B
build/editor/editor-styles.css 539 B 0 B
build/editor/index.js 44.9 kB 0 B
build/editor/style-rtl.css 3.81 kB 0 B
build/editor/style.css 3.81 kB 0 B
build/element/index.js 4.65 kB 0 B
build/escape-html/index.js 733 B 0 B
build/format-library/index.js 7.73 kB 0 B
build/format-library/style-rtl.css 547 B 0 B
build/format-library/style.css 548 B 0 B
build/hooks/index.js 2.13 kB 0 B
build/html-entities/index.js 622 B 0 B
build/i18n/index.js 3.56 kB 0 B
build/is-shallow-equal/index.js 710 B 0 B
build/keyboard-shortcuts/index.js 2.51 kB 0 B
build/keycodes/index.js 1.94 kB 0 B
build/list-reusable-blocks/index.js 3.13 kB 0 B
build/list-reusable-blocks/style-rtl.css 450 B 0 B
build/list-reusable-blocks/style.css 451 B 0 B
build/media-utils/index.js 5.29 kB 0 B
build/notices/index.js 1.79 kB 0 B
build/nux/index.js 3.4 kB 0 B
build/nux/style-rtl.css 663 B 0 B
build/nux/style.css 660 B 0 B
build/plugins/index.js 2.56 kB 0 B
build/primitives/index.js 1.5 kB 0 B
build/priority-queue/index.js 789 B 0 B
build/redux-routine/index.js 2.85 kB 0 B
build/rich-text/index.js 14 kB 0 B
build/server-side-render/index.js 2.68 kB 0 B
build/shortcode/index.js 1.7 kB 0 B
build/token-list/index.js 1.27 kB 0 B
build/url/index.js 4.06 kB 0 B
build/viewport/index.js 1.85 kB 0 B
build/warning/index.js 1.14 kB 0 B
build/wordcount/index.js 1.17 kB 0 B

compressed-size-action

@ntsekouras ntsekouras force-pushed the add/keyboard-support-for-moving-blocks branch from 5da21af to b210e44 Compare June 22, 2020 13:18
@ntsekouras ntsekouras marked this pull request as ready for review June 22, 2020 13:21
@youknowriad
Copy link
Contributor

This is a really cool PR. I agree that we need to find better key combinations. cc @mcsf maybe.

I got this on safari because of the current shortcuts

Capture d’écran 2020-06-22 à 2 28 44 PM

@ntsekouras
Copy link
Contributor Author

Thank you @youknowriad! I will change them for now to something that works for all ( Mac, Linux, Windows ), just for testing purposes.

I will search first and then make a proposal for key combination, but everyone is welcome to share their thoughts.

@mcsf

* @param {string} start Identifier of the start block.
* @param {string} end Identifier of the end block.
*/
export async function multiSelectBlocks( start, end ) {
Copy link
Member

Choose a reason for hiding this comment

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

Good idea 👍

Do you think multiSelectBlocks could be further abstracted, at the moment it’s only a proxy call to data layer and there is a helper for that already:

export function wpDataSelect( store, selector, ...parameters ) {

It would be nice if someone using this new public API wouldn’t have to get ids but could pass something simpler like number of blocks to select.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There is still the need for having a starting reference. For example select from selectMulti( 2, 5 ) that would select from the second block. I'll look into it! Nice idea @gziolo. I should also improve it by selecting the start block here.

@ntsekouras ntsekouras force-pushed the add/keyboard-support-for-moving-blocks branch from 3db4999 to 8328582 Compare June 23, 2020 10:11
@mcsf
Copy link
Contributor

I will change them for now to something that works for all ( Mac, Linux, Windows ), just for testing purposes.

I will search first and then make a proposal for key combination, but everyone is welcome to share their thoughts.

Gutenberg already has shortcuts for "Insert a new block before the selected block(s)." (++T) and "Insert a new block after the selected block(s)." (++Y). Could we reuse this pattern of T representing "above" and Y "below"? Maybe be adding a Shift to the shortcuts?


_Usage_

// selects three blocks -- from the second block to fourth (2, 3, 4).
Copy link
Member

Choose a reason for hiding this comment

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

Something is wrong with the example in JSDoc.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks! Fixed it.

@ntsekouras
Copy link
Contributor Author

Could we reuse this pattern of T representing "above" and Y "below"? Maybe be adding a Shift to the shortcuts?

@mcsf I believe this is great idea, as it would be intuitive to the user. I implemented this for test drive :)

@ntsekouras ntsekouras force-pushed the add/keyboard-support-for-moving-blocks branch 2 times, most recently from 15d0be0 to 7717169 Compare June 23, 2020 11:40
getBlockRootClientId,
} = select( 'core/block-editor' );
const selectedClientIds = getSelectedBlockClientIds();
const normalizedClientIds = castArray( selectedClientIds );
Copy link
Contributor

Choose a reason for hiding this comment

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

Looking at getSelectedBlockClientIds, it always returns an array. Any reason to array-cast into a new variable?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're right! Thanks! I removed it.

Comment on lines +182 to +187
<td>Move the selected block(s) up.</td>
<td><kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>Shift</kbd>+<kbd>T</kbd></td>
<td><kbd>⌥</kbd><kbd>⌘</kbd><kbd>⇧</kbd><kbd>T</kbd></td>
</tr>
<tr>
<td>Move the selected block(s) down.</td>
Copy link
Contributor

Choose a reason for hiding this comment

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

See below suggestions for revised labels.

@@ -35,6 +35,10 @@ export { installPlugin } from './install-plugin';
export { isCurrentURL } from './is-current-url';
export { isInDefaultBlock } from './is-in-default-block';
export { loginUser } from './login-user';
export {
multiSelectBlocksByIds,
Copy link
Member

Choose a reason for hiding this comment

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

Could we consolidate those two methods into one API? Those methods are exposed as public API and added to the documentation. We will have to maintain them for long because the 3rd party project will use it.

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 was talking with @mcsf about making the e2e tests more user interactive and not multi select programmatically, so I'll remove them as they will not be used. Do you think it has any value to keep them for now, if not used?

Copy link
Member

Choose a reason for hiding this comment

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

Not at all, we shouldn't keep methods that aren't used (unless they were part of public API previously).

Comment on lines 52 to 54
* multiSelectBlocksByRange( 2, 3 );
* ```
* // selects three blocks -- from the second block to fourth (2, 3, 4).
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
* multiSelectBlocksByRange( 2, 3 );
* ```
* // selects three blocks -- from the second block to fourth (2, 3, 4).
* multiSelectBlocksByRange( 2, 4 );
* // selects blocks at index 2, 3, 4

How about we change the API to passing startIndex and endIndex to remove the need to use code comments to explain how it works?

*/
export function arePrePublishChecksEnabled() {
export async function arePrePublishChecksEnabled() {
Copy link
Member

Choose a reason for hiding this comment

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

Good catch 👍

*/
export function wpDataSelect( store, selector, ...parameters ) {
export async function wpDataSelect( store, selector, ...parameters ) {
Copy link
Member

Choose a reason for hiding this comment

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

Great catch, page.evaluate that is used is async:

https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#pageevaluatepagefunction-args

It might make some tests more stable. /cc @youknowriad

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think it makes any difference to add "async" here since page.evalute returns a promise already

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It doesn't make any difference but it's explicit that returns a Promise. So someone would know they have to await.

Copy link
Contributor

Choose a reason for hiding this comment

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

In any case, the function signature was wrong, so this is a good catch.

@ntsekouras ntsekouras force-pushed the add/keyboard-support-for-moving-blocks branch from dde125e to 5dfe5c2 Compare June 24, 2020 07:32
Copy link
Contributor

@mcsf mcsf left a comment

Choose a reason for hiding this comment

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

The tests look much better, thanks for improving them. :)

it( 'should move the block up', async () => {
await createTestParagraphBlocks();
expect( await getEditedPostContent() ).toMatchSnapshot();
await Promise.all( [ moveUp(), moveUp() ] ); // press twice
Copy link
Contributor

Choose a reason for hiding this comment

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

Since we want testing to reflect real usage, we can't have parallel effects, so we need to split the effects out in sequence:

await moveUp();
await moveUp();

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks! Good note!

Comment on lines 28 to 32
const multiSelectBlocks = async () => {
await page.keyboard.down( 'Shift' );
await page.keyboard.press( 'ArrowUp' );
await page.keyboard.up( 'Shift' );
};
Copy link
Contributor

Choose a reason for hiding this comment

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

moveUp and moveDown are unequivocal in their effects, and there is only one possible means to trigger each of them, so they can make sense as functions.

In contrast, multiSelectBlocks isn't unique: there are many ways to cause multiple blocks to be selected, and so this function depends on specific motions (in this case, upward). This means that when a particular test calls multiSelectBlocks, it's not clear for the reader what is happening in terms of editor state, unless they go up to read the definition of multiSelectBlocks.

This isn't a hard "no", but it's my own interpretation of what can improve the readability of tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're not wrong about this. I changed it be more readable.

@ntsekouras ntsekouras force-pushed the add/keyboard-support-for-moving-blocks branch from a6653e0 to e6d6960 Compare June 24, 2020 11:12
@ntsekouras ntsekouras requested review from gziolo and mcsf June 24, 2020 12:02
@paaljoachim
Copy link
Contributor

paaljoachim commented Jun 24, 2020

Here is an associated PR which just got merged:
Prototype: move blocks between levels with keyboard
#22453

Copy link
Contributor

@mcsf mcsf left a comment

Choose a reason for hiding this comment

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

Nice work!

@mcsf
Copy link
Contributor

Here is an associated PR which just got merged:
Prototype: move blocks between levels with keyboard
#22453

As the title suggests, there's still some stuff to iron out around the "Move to …" feature. The two PRs aren't mutually exclusive, so let's merge this one.

I see #22453 as more compelling as an accessibility improvement and as a QoL improvement when editing complex arrangements with nested blocks. Meanwhile, this PR falls more in the writing flow category, satisfying the need for quick motion around the selected block.

@ntsekouras ntsekouras merged commit 8c2cdfd into master Jun 25, 2020
@ntsekouras ntsekouras deleted the add/keyboard-support-for-moving-blocks branch June 25, 2020 10:52
@github-actions github-actions bot added this to the Gutenberg 8.5 milestone Jun 25, 2020
@m0rg5
Copy link

was this abandoned?

@ntsekouras
Copy link
Contributor Author

was this abandoned?

@m0rg5 this has been merged for a while now..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Focus] Accessibility (a11y) Changes that impact accessibility and need corresponding review (e.g. markup changes). [Type] Enhancement A suggestion for improvement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add keyboard shortcuts for moving blocks
6 participants