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

Blocks: Adding the quote block #419

Merged
merged 3 commits into from
Apr 17, 2017
Merged

Blocks: Adding the quote block #419

merged 3 commits into from
Apr 17, 2017

Conversation

youknowriad
Copy link
Contributor

This is a follow-up PR to #327 which tries to add a quote block. refs #311

Props to @BE-Webdesign

@youknowriad youknowriad added the Framework Issues related to broader framework topics, especially as it relates to javascript label Apr 13, 2017
@youknowriad youknowriad self-assigned this Apr 13, 2017
<Editable
value={ value }
onChange={ ( newValue ) => setAttributes( { value: newValue } ) } />
<footer>
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 wanted to hide this when the citation is empty and we're not focusing the block but it's not possible for now, because the isSelected is not enough for this. We need a distinct isFocused which stays active even if we start typing.

Copy link
Member

Choose a reason for hiding this comment

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

We need a distinct isFocused which stays active even if we start typing.

Should we create an issue to track this, or do you plan to tackle this in the near future?

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 planing to take a look at this (but don't know really when) Let's create an issue for this :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

import { registerBlock, query as hpq } from 'api';
import Editable from 'components/editable';

const { html, query } = hpq;
Copy link
Member

Choose a reason for hiding this comment

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

Ah yes, the shadow conflict. It's been on my mind lately whether we should rename wp.blocks.query to something else. I thought perhaps parse being the default exported function with other methods as properties available via destructuring, but I'm not sure I like the idea of block implementers thinking of this as a parse action (even if it is 😄 ).

Copy link
Member

Choose a reason for hiding this comment

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

Or we could simply reference hpq as a proper external dependency and expect plugin authors to enqueue it themselves as a preloaded dependency. I quite liked masking the underlying implementation detail and providing a single unified interface for blocks though.

category: 'common',

attributes: {
value: ( node ) => query( 'blockquote > p', html() )( node ).join(),
Copy link
Member

Choose a reason for hiding this comment

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

Won't this disallow multiple paragraphs in a single quote? Instead maybe we want to retrieve paragraphs as an array of HTML?

Roughly:

attributes: {
	value: html( 'p' )
}

save( { value } ) {
	return <blockquote>{ value.map( ( paragraph ) => <p>{ paragraph }</p> ) }</blockquote>;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The above will retrieve all the paragraphs and join them, so no it won't disallow multiple paragraphs. I wanted to have a unique string to pass to the Editable inside the edit instead of having to duplicate the join logic in edit and save.

Also worth noting that the footer can contain p elements, so that's why I'm using blockquote > p

Copy link
Member

Choose a reason for hiding this comment

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

The above will retrieve all the paragraphs and join them, so no it won't disallow multiple paragraphs.

But html retrieves the innerHTML so it would lose the tag and become a single joined string.

I wanted to have a unique string to pass to the Editable inside the edit instead of having to duplicate the join logic in edit and save.

I guess I'm more on the side of using attributes to get the raw-est data possible even if that's not necessarily the most useful, and assume that edit and save will form it into whatever's most applicable, perhaps sharing logic with common components if need be.

Also worth noting that the footer can contain p elements

Is this "can" as in: technically possible per spec, or something we want to support?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point! What about adding a div wrapper inside the blockquote to separate the footer from the content properly. This will also resolve the dangerouslySetInnerHTML issue?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is this "can" as in: technically possible per spec, or something we want to support?

I don't know :P. What I know is that TinyMCE (current implementation) adds p automatically around text (we could avoid it passing a tagName, but we create other limits by doing so). Also the current post content sample contains the p

margin-left: 1.3em;
position: relative;

&:after {
Copy link
Member

Choose a reason for hiding this comment

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

Not that it really matters much here, but if it's shown effectively before the cite, should we apply as :before for semantic's sake?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍

save( attributes ) {
const { value, citation } = attributes;
return (
<blockquote>
Copy link
Member

Choose a reason for hiding this comment

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

I think we'll need some dangerouslySetInnerHTML throughout here.

Copy link
Contributor Author

@youknowriad youknowriad Apr 13, 2017

Choose a reason for hiding this comment

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

🤔 How do we apply the dangerouslySetInnerHTML without a wrapper?

Copy link
Member

Choose a reason for hiding this comment

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

🤔 How do we apply the dangerouslySetInnerHTML without a wrapper?

Yeah, we ought to be thinking about this, because I don't think it's particularly obvious and the "dangerous" terminology is quite off-putting.

Perhaps we can walk the tree returned from the function and manually revise string children as dangerouslySetInnerHTML? 😬

@youknowriad
Copy link
Contributor Author

@aduth you're gonna hate it but in 12db3e9 I've used what's currently possible to address the multi-paragraph issue and the dangerouslySetInnerHTML without changing the markup.

(Return a string from the save and do the <p> concat while parsing)

@aduth
Copy link
Member

aduth commented Apr 13, 2017

@youknowriad I put together an example of what I was proposing at f25da1a, where the raw attribute value of a quote is an array of the paragraphs' HTML.

I've observed a few sticking points in this conversation I think we'll need to sort through to set good conventions for block implementers:

  • Just how much parsing should we expect the implementer to be doing in attributes?
  • Should string return values from save be allowed? Seems inevitable if we allow them that they'll be leaned upon heavily. How would we protect against escaping issues if it were to become a preferred approach?
  • f25da1a highlights a more desperate need to think of another solution for dangerouslySetInnerHTML in the save function. I've opened an issue at Alternative to dangerouslySetInnerHTML in block save #421 to explore this.

@youknowriad
Copy link
Contributor Author

@aduth Pros and cons I can see in f25da1a

Pros:

  • attributes parsing is simple
  • fix the dangerouslySetInnerHTML while still returning an Element

Cons:

  • We're parsing the value obtained from the Editable. I think one of the goals of our architecture is to avoid parsing for block authors (aside the attributes)

My POV is that we should parse all what can be parsed before hitting the edit method to simplify it the most. You may advocate the opposite? Maybe we should think of this issue in terms for block's state. What's the most logic for a quote block: Having a value as an array of paragraph contents, or having a unique content value. "A quote have a content and a citation" makes more sense to me.

@youknowriad
Copy link
Contributor Author

I've included your commit @aduth The two approaches have flaws. I do prefer returning only strings from the save method, but we can move forward for now. And see how this performs with other blocks. This is an easy enough change (can be revisited later).

@aduth
Copy link
Member

aduth commented Apr 17, 2017

You may advocate the opposite?

I don't necessarily see it as one extreme or the other, but I do think it's reasonable for the block implementer to think of the block's attribute state in terms of what's most appropriate to accommodate the underlying values, ideally with as little markup as possible. If this means they have to parse content on the Editable's onChange handler, I'm fine with that. I think part of the problem is that we're trying to reconcile two competing approaches, one which tries to abstract the block as an object of raw values, and another which is okay with representing some of that state as markup. I have a preference toward the former, but it's complicated by the Editable containing nested nodes, the consequences of which are that we must do more parsing on its change handler and apply dangerouslySetInnerHTML in save.

Copy link
Member

@aduth aduth left a comment

Choose a reason for hiding this comment

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

Looks good 👍

.blocks-quote {
margin: 0;
box-shadow: inset 0px 0px 0px 0px $light-gray-500;
transition: all .2s ease;
Copy link
Member

Choose a reason for hiding this comment

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

What's the effect we're trying to achieve with the transition? At least in my browser, the border width effect feels a little janky when switching between styles.

Copy link
Contributor

Choose a reason for hiding this comment

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

Agree, let's remove that one. Though the idea of "transitioning between styles" is interesting, I think that will get old quickly, and it likely won't scale to other block transformations either.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Framework Issues related to broader framework topics, especially as it relates to javascript
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants