-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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 block-level keyboard shortcuts #4436
Conversation
f851af9
to
f25e33d
Compare
Working a bit more on this...
So far the heading shortcut should work well, the rest is still in the works. |
The paragraph both has text align and block align toolbars. Which should the shortcuts app to? |
Ideally adding a component such as |
@iseulde Maybe you can use a Slot/Fill to add the shortcode in |
@youknowriad Yeah, I was thinking about a portal, but ideally it would need to wrap the block. Will play around with it, thanks. :) |
I think we'll have to tie it to the document instead, because this is also a problem on the block list when the focus is in the inspector. |
Hm, that won't work either because the component won't be mounted when typing. |
I mean, neither attaching to the document, nor the portal will work, because the alignment toolbar won't be mounted at all. It will have to be added as settings I think... |
448e1fa
to
fc83895
Compare
This is ready for an initial review (for my own sanity). |
Some notes:
|
blocks/library/paragraph/index.js
Outdated
@@ -248,6 +249,21 @@ registerBlockType( 'core/paragraph', { | |||
), | |||
}, | |||
], | |||
to: [ 'left', 'center', 'right' ].map( ( value ) => ( { | |||
type: 'shortcut', | |||
shortcut: value.charAt( 0 ), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be worth adding an inline comment; this is giving me clever code vibes.
Aside: Could this be value[ 0 ]
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I'll do map( { left: 'l' } )
etc. instead then... :) What do you mean with value[ 0 ]
? It's not an array?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per MDN (string, §Character access), array-like access was introduced in ES5, so I assume it safe to use. Both forms should be equivalent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had no idea this was possible. :)
blocks/library/paragraph/index.js
Outdated
shortcut: value.charAt( 0 ), | ||
transform( attributes ) { | ||
const firstAlign = first( attributes ).align; | ||
const isSame = attributes.every( ( { align } ) => align === firstAlign ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My unitiated perspective: What is the shape of attributes
? I would have expected an object for a single block, but this looks to be an array. Are these an array for blocks in a multi-selection? A bit unfortunate overloading of the term attributes
between an object of a single block, and an array of multiple blocks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it's similar in other transforms. Elsewhere it has been named blockAttributes
, which doesn't really feel any better... Any ideas?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I rambled on about the same thing in a different hunk. :) See #4436 (comment)
@@ -179,6 +182,7 @@ class Tooltip extends Component { | |||
aria-hidden="true" | |||
> | |||
{ text } | |||
{ shortcut && <span className="components-tooltip__shortcut">{ getAccessCombination( shortcut ) }</span> } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the concept of a keyboard shortcut be baked into a general tooltip UI component?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think so, as it has distinct styles. See also #4411.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think so, as it has distinct styles. See also #4411.
The question was intended as less "Do we need tooltips in the editor to have shortcut-specific behavior?" and more in the abstract "When I use a Tooltip on some page in the admin, do I have the expectation that it supports keyboard shortcut functionality?"
(With the expectation that all of components
is meant to be purely generic)
In these cases I might like if we could create a wrapper component, similar to the separation between IconButton
and Button
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make more sense if the getAccessCombination
piece is part of IconButton
, which would otherwise this new wrapper component?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see any inherent relationship between an icon button and keyboard combinations, so no, it doesn't really make sense to me.
*/ | ||
const { userAgent } = window.navigator; | ||
|
||
const isMac = userAgent.indexOf( 'Mac' ) !== -1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We use a different test elsewhere, and should seek to consolidate or create a shared utility:
const isMac = window.navigator.platform.toUpperCase().indexOf( 'MAC' ) >= 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, did not realise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commented on #3755 (comment). I wouldn't like us to have a lot of different keyboard combinations that are not rememberable.
/** | ||
* Browser dependencies | ||
*/ | ||
const { userAgent } = window.navigator; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the destructuring worthwhile if we're using it in one spot?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a bit strange indeed if the use immediately follows, but I find it clear to state browser dependencies.
@@ -62,15 +70,45 @@ class BlockList extends Component { | |||
document.addEventListener( 'copy', this.onCopy ); | |||
document.addEventListener( 'cut', this.onCut ); | |||
window.addEventListener( 'mousemove', this.setLastClientY ); | |||
// Needs document to also work in inspector. | |||
// In other words, if there is selection, but no focus. | |||
document.addEventListener( 'keydown', this.onKeyDown ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it viable to use the KeyboardShortcuts
component instead?
https://github.com/WordPress/gutenberg/tree/master/components/keyboard-shortcuts
Might also help with the platform normalization:
Mousetrap 1.4 introduced a generic mod helper which lets you set cross platform shortcuts.
Mousetrap.bind('mod+s', _saveDraft);
On Mac this ends up mapping to command+s whereas on Windows and Linux it maps to ctrl+s.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do we dynamically change those? Rebind as the selection changes? There's also no concept of access
in Mousetrap, unlike TinyMCE.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, we're also not using this component anywhere else, so I'm wondering why now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, we're also not using this component anywhere else, so I'm wondering why now.
We are:
gutenberg/editor/components/navigable-toolbar/index.js
Lines 60 to 66 in 2e276ad
<KeyboardShortcuts | |
bindGlobal | |
eventName="keyup" | |
shortcuts={ { | |
'alt+f10': this.focusToolbar, | |
} } | |
/> |
gutenberg/editor/edit-post/modes/keyboard-shortcuts/index.js
Lines 33 to 35 in 2e276ad
<KeyboardShortcuts shortcuts={ { | |
[ shortcuts.toggleEditorMode.value ]: this.toggleMode, | |
} } /> |
|
||
// Check if we received blocks or attributes. | ||
if ( result.uid || Array.isArray( result ) ) { | ||
onReplace( this.blocks.map( ( { uid } ) => uid ), castArray( result ) ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: Lodash's _.map
property shorthand can be nice for this sort of thing:
map( this.blocks, 'uid' )
return; | ||
} | ||
|
||
if ( ! isAccess( event ) ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason not to merge into previous condition?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No :)
} | ||
|
||
componentWillReceiveProps( nextProps ) { | ||
const prevCommonName = this.commonName; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we consider moving the logic for handling the shortcuts to a different component? This doesn't seem particularly relevant to the block listing, and would be easy enough to transport into a separate (non-visual) component which is rendered as a child of the BlockList
root return value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will, if the general direction of this PR seems good.
blocks/api/factory.js
Outdated
export function getPossibleShortcutTransformations( name ) { | ||
const transformsFrom = getBlockTypes() | ||
.reduce( ( acc, blockType ) => [ ...acc, ...get( blockType, 'transforms.from', [] ) ], [] ) | ||
.filter( isTransformForBlockSource( name, 'shortcut', false ) ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That reduction is actually of a specific kind: it's a mapping.
- .reduce( ( acc, blockType ) => [ ...acc, ...get( blockType, 'transforms.from', [] ) ], [] )
+ .map( ( blockType ) => get( blockType, 'transforms.into' ) )
My second point was more relevant before realizing the reduce
can just become a cheaper map
, but: instead of filtering the reduction for things that are applicable transforms, can we instead first filter the block types for things that have applicable transforms, and then construct the transforms set?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, those two are not equal. Is that what you mean in the second point then? I'm find either way. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, yes. It's flatMap
, actually.
My second point was above whether there's an efficiency gain in filtering first.
blocks/library/heading/index.js
Outdated
...'23456'.split( '' ).map( ( level ) => ( { | ||
type: 'shortcut', | ||
shortcut: level, | ||
transform( attributes ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The term attributes
is misleading, as everywhere else in Gutenberg it means "the set of attributes for a single block or block type", whereas here it's "the sets of attributes", plural, one for each block.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From an API design standpoint, we're reaching a tough spot. On one hand, it's easy to see why we'd want a set of sets of attributes, since we'd like to support keyboard shortcuts that affect multiple blocks. On the other hand, merely from looking at a block type's transforms
, there is nothing intrinsically setting apart 'shortcut'
from other transform types in such a way that it's obvious that it should receive a set of sets of attributes while the other transform types receive a single set of attributes.
A simple solution could be to pass blocks
rather than map( blocks, 'attributes' )
to the transform, since that would make the transform more legible:
transform( blocks ) {
const firstNodeName = first( blocks ).attributes.nodeName; // and so on
Side thought: if we decided that we wanted a simpler and less permissive API that only allowed a 1:1 mapping from selected block to transformed block, then the transform
here could be rewritten to operate on a single block. In that case, passing attributes
would be consistent in that it's a single set of attributes. The transform would look like:
transform( attributes ) {
const foo = computeFrom( attributes );
return createBlock( foo.name, foo.attributes );
}
The transform caller (as of now, BlockList
) would be the one calling the transform for each selected block:
- const result = transform.transform( map( this.blocks, 'attributes' ) );
+ const result = this.blocks.map( transform.transform );
However, the current, more feature-complete implementation requires more than that, so the point is moot.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. I was following what had been done before for multi selection transform on e.g. lists, where an array of attributes was passed as opposed to an array of blocks. See #3357 (cc @jorgefilipecosta @youknowriad). I'm fine with passing blocks instead of an array of attribute sets.
blocks/library/list/index.js
Outdated
...[ 'OL', 'UL' ].map( ( tag ) => ( { | ||
type: 'shortcut', | ||
blocks: [ 'core/paragraph' ], | ||
shortcut: tag.charAt( 0 ).toLowerCase(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unless we centralize shortcut declarations in one place, perhaps add a line comment spelling out which shortcuts this adds, to assist the reader and to improve codebase searchability: // Keyboard shortcut: access+o, access+u
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will do the same as the alignment here, for readability.
blocks/library/list/index.js
Outdated
// Merge list. | ||
return createBlock( 'core/list', { | ||
nodeName: tag, | ||
values: attributes.reduce( ( acc, { values } ) => [ ...acc, ...values ], [] ), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe a good place for lodash#flatMap
, per #3185, even though this isn't a hot path like that of the mentioned PR.
blocks/library/paragraph/index.js
Outdated
@@ -248,6 +249,21 @@ registerBlockType( 'core/paragraph', { | |||
), | |||
}, | |||
], | |||
to: [ 'left', 'center', 'right' ].map( ( value ) => ( { | |||
type: 'shortcut', | |||
shortcut: value.charAt( 0 ), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per MDN (string, §Character access), array-like access was introduced in ES5, so I assume it safe to use. Both forms should be equivalent.
blocks/library/paragraph/index.js
Outdated
shortcut: value.charAt( 0 ), | ||
transform( attributes ) { | ||
const firstAlign = first( attributes ).align; | ||
const isSame = attributes.every( ( { align } ) => align === firstAlign ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I rambled on about the same thing in a different hunk. :) See #4436 (comment)
this.commonName = firstName; | ||
} else { | ||
delete this.commonName; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if we want to right-align a selection of paragraphs and images?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, this is getting complicated. :) Transforms on different block types have not been done before, but it doesn't sound like a bad idea in some cases. In the case of paragraphs and images though, it means something different (align vs text-align).
}, | ||
onChange( uid, attributes ) { | ||
dispatch( updateBlockAttributes( uid, attributes ) ); | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tangent to the PR, but I really dislike ( dispatch ) => ( { onBlah( x, y, z ) { dispatch( doBlah( x, y, z ) ); } } )
when we have { onBlah: doBlah }
.
utils/keycodes.js
Outdated
export function isAccess( event, character ) { | ||
if ( isMac ) { | ||
if ( ! event.ctrlKey || ! event.altKey ) { | ||
return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Though it makes no real difference, strictly speaking this should be return false
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, spotted that earlier on too :)
utils/keycodes.js
Outdated
} | ||
|
||
return character ? event.keyCode === character.toUpperCase().charCodeAt( 0 ) : true; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two optional refactors:
const modifierKey = isMac ? 'ctrlKey' : 'shiftKey';
if ( ! event[ modifierKey ] || ! event.altKey ) {
return false;
}
return ! character || ( event.keyCode === character.toUpperCase().charCodeAt( 0 ) );
utils/keycodes.js
Outdated
return false; | ||
} | ||
|
||
return character ? event.keyCode === character.toUpperCase().charCodeAt( 0 ) : true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: can extract function toKeyCode( char ) { return char.toUpperCase().charCodeAt( 0 ); }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Readability? Or for what reason?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, merely that. My personal preference, anyway. The function name acts as documentation, essentially.
@mcsf Ah, that's the case in master too. The shortcut is present in TinyMCE too, so it should be disabled. |
1b01ec5
to
f61c0a3
Compare
I think this is ready for another look. :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the last time, I'm running into some bugs:
-
If I add a paragraph, then do
access+2
, it converts it to a heading with no issues. From there, I can keep changing levels withaccess+3
, etc., or revert to paragraph. -
However, if I add a Heading (via Inserter or
##
), then pressaccess+3
, the level is changed but the text is lost. -
Same with lists: start one with
-
, add one or more items, then try the shortcuts to convert between ordered/unordered or back to paragraph. Content is lost in all these cases. Content is not lost if using multi-selection of paragraphs, or if I have partial text selection of a list's items.
blocks/alignment-toolbar/index.js
Outdated
@@ -8,16 +8,19 @@ const ALIGNMENT_CONTROLS = [ | |||
{ | |||
icon: 'editor-alignleft', | |||
title: __( 'Align left' ), | |||
shortcut: 'l', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if blocks/alignment-shortcuts
exported the following constant:
export const shortcuts = { left: 'l', … };
export default map( shortcuts, ( shortcut, value ) => …
… so that, here, we could just reuse shortcuts.left
, etc., instead of duplicating constants?
(Same goes for blocks/block-alignment-toolbar
.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice idea!
blocks/editable/index.js
Outdated
@@ -192,6 +192,9 @@ export default class Editable extends Component { | |||
onInit() { | |||
this.updateFocus(); | |||
this.registerCustomFormatters(); | |||
|
|||
// Remove all default block-level shortcuts. | |||
'123456789'.split( '' ).forEach( ( number ) => this.editor.shortcuts.remove( `access+${ number }` ) ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know TinyMCE enough, but are we to assume from this hunk that there isn't a way to avoid the shortcuts being set up in the first place?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can try to adjust the valid elements in the instance though, and maybe it just becomes a no-op.
@@ -79,6 +85,19 @@ registerBlockType( 'core/heading', { | |||
} ); | |||
}, | |||
}, | |||
...'23456'.split( '' ).map( ( level ) => ( { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Curious, why is h1
excluded? It's still offered as an option in the inspector.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, H1 should be equivalent to the title. I have no idea why it is an option in the inspector.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So in the future, if the title is a block, access+1
should convert to a title block, if there isn't one already.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds great.
blocks/library/quote/index.js
Outdated
|
||
return acc; | ||
}, [] ); | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personal taste, but IMO this is a great place for a flatMap
too:
return flatMap( blocks, ( { attributes: { value, citation } } ) => [
...value.forEach( ( paragraph ) => createBlock( … ) ),
...( citation ? [ createBlock( … ) ] : [] ),
] );
<BlockListShortcuts | ||
selectedBlock={ selectedBlock } | ||
multiSelectedBlocks={ multiSelectedBlocks } | ||
/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
||
const { getAccessCombination } = keycodes; | ||
|
||
const combination = getAccessCombination( 'm' ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This won't scale if more shortcuts are added to the module. I don't really mind for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not immediately sure what solution there is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Off the top of my mind:
const shortcuts = {
toggleEditorMode: 'access+m',
};
const modifiers = {
access: getAccessCombination,
}
const computed = reduce( shortcuts, ( acc, shortcut, shortcutName ) => {
const keys = shortcut.split( '+' );
// assumes only one modifier:
const [ modifier, ...chars ] = keys;
const combination = modifiers[ modifier ]( ...chars ); // obvs should check existence first
acc[ shortcutName ] = {
value: combination.toLowerCase(),
label: combination,
};
return acc;
// but could be:
// const [ modifiers, chars ] = partition( keys, isModifier );
// and somewhere:
// const combination = combine( eligibleModifiers )( ...chars )
} );
export default computed;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not entirely sure now what you mean with scaling. We should only have two possible combinations in the future: access+CHARACTER
and meta+CHARACTER
, the former could be used across Gutenberg and plugins, the latter is only the overwrite default behaviour or implement well-known combinations (limited amount).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant if more shortcuts are added to that file.
Only having access
and meta
as modifiers is good. I wondered if any other combo with shift
could creep in, hence the convoluted suggestion at the end of my code snippet.
@mcsf Haha, that's because the |
Is the error related? I can't seem to reproduce. |
@mcsf I'm also not entirely sure how to fix that, other than waiting for a fix for the syncing, or dirty fix by forcing a sync on |
@@ -52,7 +53,10 @@ function getEmbedBlockSettings( { title, icon, category = 'embed', transforms, k | |||
}, | |||
}, | |||
|
|||
transforms, | |||
transforms: { | |||
from: transforms.from, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if someone passes transforms
with a to
? Shouldn't we use ...transforms, to: { ...transforms.to, bla }
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not extensible outside of this file, so if more are added, the code can be adjusted? Either way, I'm fine with changing it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not extensible outside of this file
Yeah, disregard then. :)
The
The sync forcing does solve the problem for me. I'm not totally confident assessing whether that fix could be problematic, but we do have precedents in Editable, so I'm open to it. |
6bc21e8
to
99c70d7
Compare
Rebased |
If I understand correctly, by implementing these as transforms, are we replacing a block with a new variation when in many cases these are merely attributes changes? (Should transforms accommodate this usage?) |
@@ -529,6 +532,10 @@ export default class RichText extends Component { | |||
const dom = this.editor.dom; | |||
const rootNode = this.editor.getBody(); | |||
|
|||
if ( isAccess( event ) ) { | |||
this.fireChange(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haven't followed the logic, but in what way is an access keydown a change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Otherwise the state would not be up to date at the time of the command. This Is an ugly fix. There are PRs in the works that sync RichText
state continuously though, and then this would no longer be needed.
Is it likely this will be resumed, or can it be closed? |
Closing as stale without response. It can be reopened if development is expected to continue, or a new pull request can be submitted. |
Description
This PR aims to add all block-level shortcuts mentioned in #71.
^⌥C
^⌥L
^⌥R
^⌥U
^⌥O
^⌥1-6
^⌥Q
These are block level shortcuts, as opposed to
Editable
shortcuts, because they change block attributes other than theEditable
value.How Has This Been Tested?
Screenshots (jpeg or gifs if applicable):
Types of changes
Checklist: