-
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
Quote Block: Support Block Switcher #484
Conversation
Works well, nice work!
How hard would it be to convert multiple paragraphs in a quote to multiple headings? By the way I can't get the citation to save. Probably not part of this PR but thought I'd mention. |
This is doable, not that hard, we could imagine that returning an array from a transformation means we're creating multiple blocks. But I don't know how I feel about it, I feel it's a not really necessary to add this complexity to the API. Could this be confusing a bit for the user? Also, this can have implications on the merge API #461. Curious to have others (@aduth @nylen) opinion on this.
This is happening when editing an empty citation right? I'll try to fix this in a separate PR. |
I have mixed filling concerning the continuous block, it feels like we'll be adding a global TinyMCE prototype inside the per-block prototype. We'll need to duplicate the work being done for all the different APIs (switching, controls, moving, ...). |
These are things the tiny group is working on regardless, we'll see how that coalesces. |
blocks/library/quote/index.js
Outdated
{ | ||
type: 'block', | ||
blocks: [ 'core/heading' ], | ||
transform: ( { content = '' } ) => { |
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.
content
is no longer a string as of #466
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.
waiting for concatChildren
from #461 to fix this
blocks/library/quote/index.js
Outdated
blocks: [ 'core/text' ], | ||
transform: ( { value, citation } ) => { | ||
let content = value ? value : []; | ||
content = citation && citation.trim() ? content.concat( citation ) : content; |
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.
Similarly, content
and citation
are no longer strings here.
IMHO, we shouldn't remove the content. Maybe the citation can be added as another paragraph to the blockquote paragraphs? |
Big -1 to any block switch removing content. I still think it would be better to disable the switch with an appropriate warning message indicating how to resolve the data loss, as I tried in #465. |
I'll update to append the citation as another block. Just waiting for #461 which provides concatChildren. The reason I chose to take the first paragraph only was consistency with the text block. I'll update both. |
7c6fa4f
to
d8d6992
Compare
PR updated, Quote to heading and text to heading concat paragraph content instead of picking the first paragraph to avoid data loss. |
blocks/library/heading/index.js
Outdated
// TODO reject the switch if more than one paragraph | ||
content = content[ 0 ]; | ||
content = wp.element.concatChildren( content.map( ( elt ) => | ||
! elt || isString( elt ) || elt.type !== 'p' ? elt : elt.props.children |
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.
Quite unfortunate that the heading transform needs to be aware for text forms as an array, as a falsey value, as a string, as an element of paragraph type, or other element type 😕
In order to understand what is going on here, it's necessary to have a pretty deep understanding of how the editor works, and this isn't something that we can expect of users. Especially with longer content, the current result is still a pretty poor user experience: Text blockSwitch to heading blockSwitch back to text blockAlternatives
|
From James' alternatives above, I like option 1 and 3 (split into one heading and succeeding paragraphs & convert multiple headings). |
In c040210 I've implemented the proposal 3 from James. So now a block author can return an array from a transformation which will create several blocks of the same type. I think the proposal 1 is better but if we want to build it, we have two choices:
I'm leaning towards the second, I don't feel strongly about giving that much freedom in choosing block types for the block author but this means the block author is aware that only the first block is the transformed block. Curious to have your ideas and thoughts on this @aduth @nylen |
If I understand correctly, this won't work... here are the 3 cases we need to handle:
This should be the way forward anyway... it is more explicit. The other option - "Assume that if a transform returns an array, the first value of the array is the switched block" - seems too "magical" to me. |
Trying to think globally here. I think the answer to the following question would help us choose the best answer here (and probably a lot more similar debates): Do we want to build a good text editor showing different controls depending on the current selection OR Do we want to build an editor based on a solid block concept that is used in different places including the editor The first assumes the user don't know about the concept of The answer to this question can be different from a person to another but I strongly think we're doing the second thing where the user is aware of the block concept because the user can insert the blocks manually from the inserter and also, the user can use these blocks outside the editor in the customizer etc... That said, let's get back to our issue, I think the behavior your proposing @nylen where the block switcher behaves differently depending on the current selection is verry confusing. As a user aware of blocks, I won't understand what's happening. The more I think about it, the more I find that switching a block should produce a unique block, and transforming the text a bit (spaces instead of new paragraphs etc...) is a good tradeoff. As a user, I don't see myself using the switcher a lot in "text" blocks, that's why I'm not too concerned with this. I think the switcher makes a lot of sense for "media" blocks for example where we could use third party blocks of different styling and stuff like that. That said, I think we should revert to the behavior here #484 (comment) and improve it by adding spaces between the merged paragraphs. If I try to think as a user not aware of "blocks", I do see the issues you're showing with the examples above, but I just don't think that's the way we should go and we should educate the users about the concept of block because this concept will be central to the WordPress content (same as the widgets, shortcodes etc... now, The user is already aware of those and we're replacing them) |
Just a quick note — tried this today, and I feel like it worked really well and felt predictable. Only hiccup was transforming a single heading to a quote, and back to a heading again — this created a superfluous extra empty heading block below, presumably from the empty cite. Barring that, I think we should merge this in and keep moving. It works really well as is, and though I can definitely understand the theoretical issues, I see these more like improvements that can be made in the future if during testing we find that they pose a problem. |
blocks/api/factory.js
Outdated
const transformtionResult = castArray( transformation.transform( block.attributes ) ); | ||
|
||
return transformtionResult.map( ( attributes, index ) => | ||
Object.assign( { |
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.
Why is this an assign if there's only one argument?
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 :P
} | ||
index = state.indexOf( action.uids[ 0 ] ); | ||
return state.reduce( ( memo, uid ) => { | ||
if ( uid === action.uids[ 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.
I see the need to support replacing multiple blocks, but it feels strange that we necessarily assume that if there are multiple blocks to be replaced, they're guaranteed to be in consecutive order. Do you think it would be any better in REPLACE_BLOCKS
that we only specify a single uid
to be replaced, and in the block.js
we call to REMOVE_BLOCK
the remainder of the blocks to be replaced?
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 assuming they are in a consecutive order, I'm just inserting the new blocks in a consecutive order at the place of the first old block.
But I'm not sure I'll keep this implementation for now. My preference would be to transform one block into another block (1-1) transformation but we'll see with the discussion.
c040210
to
48524bc
Compare
Per Slack discussion, I updated this to switch only the first paragraph. We can not set this to be aware of the selected paragraph while applying the switch for now. This needs the current selection to be selected in Redux in a unique way no matter the block type and being able to match this selection against the block attributes. |
…ren object - Avoid data loss while switching blocks
48524bc
to
5469c9a
Compare
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 still not convinced this is the best UX, but it seems to work as intended, and I understand the pieces aren't in place yet to build what I was thinking of. Also, this approach should be flexible enough to support transformations into an arbitrary array of blocks later on.
I added several other validation checks and unit tests for the new cases introduced here. If all of that looks OK, then let's merge it.
blocks/api/factory.js
Outdated
const firstSwitchedBlock = findIndex( transformationResults, ( result ) => result.blockType === blockType ); | ||
|
||
// Ensure that at least one block object returned by the transformation has |
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.
Great to see some more comments
it( 'should insert after the specified block uid', () => { | ||
const original = blocks( undefined, { | ||
it( 'should replace the selected block', () => { | ||
const original = deepFreeze( { uid: 'chicken', typing: false, focus: { editable: 'citation' } } ); |
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 didn't catch this before it was merged, but this really should have been split out into separate lines.
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 should use prettier
and don't care about this stuff anymore
refs #419
This PR adds the support for the block switcher to the quote block.
Question:
While switching from a quote to heading, this PR is taking the first Paragraph of the quote only, we'll lose the other paragraphs and the citation. We should take a decision whether or not this is acceptable. The alternatives are:
We should take a decision here to make this behaviour consistent for all the "Multi-paragraph" to "Single paragraph" switches. @jasmussen. This is also addressed in Add quote↔text block switching; add block switcher validation #465 for the text block.