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

Implement image alignment controls #416

Merged
merged 3 commits into from
Apr 26, 2017
Merged

Implement image alignment controls #416

merged 3 commits into from
Apr 26, 2017

Conversation

aduth
Copy link
Member

@aduth aduth commented Apr 12, 2017

This pull request seeks to implement alignment controls for the image block.

image alignment

Implementation notes:

  • Image was extracted to a top-of-file common control to more easily maintain common behaviors between edit and save variations
  • Parsing align from the className is a bit ugly with the current setup. I'm very inclined to change this to a comment-serialized attribute and support legacy class-based alignment with a compatibility layer like the one explored in Propose block APIs for backwards compatibility #413
  • Styling is very ugly when performing the alignment

Testing instructions:

  1. Navigate to the Gutenberg admin screen.
  2. Click the first image
  3. Note a toolbar with alignment controls is shown
  4. Note the "No alignment" button is active
  5. Click an alignment button
  6. Note the alignment of the image changes accordingly
  7. Note the clicked alignment button is now active
  8. Click the same button
  9. Note that alignment resets to "No alignment"

@aduth aduth added [Feature] Blocks Overall functionality of blocks Framework Issues related to broader framework topics, especially as it relates to javascript labels Apr 12, 2017
@jasmussen
Copy link
Contributor

Nice!

Seems like we're missing a few of the niceties from the multi instance prototype. Here's a video:

https://cloudup.com/cCULEOFR95p

Essentially — as soon as the image is floated, the block boundaries look weird on the floated element. Also, the text block takes focus when clicking — I think we did some z-indexing to fix this in the multi instance prototype. @youknowriad do you have more info?

@youknowriad
Copy link
Contributor

youknowriad commented Apr 13, 2017

This is a really hard task IMO. In the current implementation, only the block itself is aware of this attribute. This is problematic because we can not update the styling of the parent .editor-visual-editor__block is not updated properly and I think this is the div that should be floated once we use these controls. Floating this div automattically float its content, and all the attached controls.

Two options here if we want to apply the styling to the container div .editor-visual-editor__block:

  • Move the rendering of the controls and this div inside the edit of each block. This was the option chosen in the multi-instance prototype. It has the advantage of flexibility because the block author has the control of everything but the problem here is that it adds a lot of things to the block author to think of.

  • The second option (the one we should consider IMO) is having "global controls". The global controls are controls (and attributes) the editor can be aware of. And these controls can be applied to any blockType no matter its internal implementation. I think the "alignments controls" here (floating) can be applied to any block and thus can be considered "global controls" and we'll have a "reserved attribute name" for these controls.

Edit: There's a third option (an enhancement of the first one) where we can have an optional form property when defining the block. This property is responsible of rendering the surroundings ( the '.editor-visual-editor__blockand its controls ) and calling theeditproperty. If a block don't define theform` attribute, we use the default one (the one we already have).

@mtias mtias added the [Feature] Block API API that allows to express the block paradigm. label Apr 13, 2017
},

controls: [
{
Copy link
Member

Choose a reason for hiding this comment

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

Is the full-bleed or whatever we call that missing?

Choose a reason for hiding this comment

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

No, it's not an alignment. It's a width manipulation.

Copy link
Member

Choose a reason for hiding this comment

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

But it's a control.

@@ -6,6 +6,22 @@ import Editable from 'components/editable';

const { attr, html } = query;

function Image( { url, alt, align } ) {
Copy link
Member

Choose a reason for hiding this comment

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

Probably useful to document here.

@mtias
Copy link
Member

mtias commented Apr 13, 2017

I'm ok merging this as a first path and exploring the improvements/solutions separately.

@aduth
Copy link
Member Author

aduth commented Apr 25, 2017

I've rebased to resolve conflicts and address a few points of the feedback.

Handling the float is particularly challenging, as @youknowriad highlighted earlier. Floated content in general can be difficult, but especially so in our case of trying to shield the block implementation from too much of the editor rendering details. I've tried to hack on a few ideas this afternoon on how the block alone might be able to render its contents as floated while preserving padding, margins, z-index, and border of the surrounding controls, but have struggled to come to any universal solution.

We'd likely need some way for the block listing to become aware that there is floated content. @youknowriad's form property is one idea, but moves significant rendering burden to the block implementation. A few other ideas I've considered:

  • Recursively iterate the rendered block's children to find if any have a float style applied
  • Similar to above, simply querySelector the rendered block for [style*="float:"] and assume that the edit render will specify this style
  • Create a set of generic wrapper elements like <Floated float="left"> and modify the behavior of the list wrapper dependant on its existence
  • Allow a block to define a callback which returns attributes to be applied to the wrapper
  • Measure the content and manually draw borders and overlays
  • Encode the block's attributes into attributes of the block wrapper and apply styles based on their presence (e.g. <div data-type="core/image" data-align="left">)

None of these I'm particularly happy with. Of course, the ideal case is that through some CSS wizardry we could allow the block's content to be floated.

@youknowriad
Copy link
Contributor

@aduth there's also the Global controls solution explored in #443

@aduth
Copy link
Member Author

aduth commented Apr 25, 2017

@aduth there's also the Global controls solution explored in #443

Yeah, I'd say this is on about a similar level as some of the ideas in my previous comment. The issue with all of these is trying to seek a good balance where neither the block nor the block listing needs to have excessive knowledge about the other. In many of these examples, we're very much targeting alignment/floating as being a common characteristic of a block, and therefore engrain this knowledge into the block list rendering. But... I don't know that we necessarily want to make that assumption.

Another couple ideas to make this generic:

@ellatrix ellatrix added this to the Prototype Parity milestone Apr 26, 2017
@@ -148,6 +167,8 @@ class VisualEditorBlock extends wp.element.Component {
onMouseMove={ this.maybeHover }
onMouseLeave={ onMouseLeave }
className={ className }
data-type={ block.blockType }
{ ...getBlockAttributesAsProps( block.attributes ) }
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice workaround :)

I think we should propose an opt-in behaviour (maybe leave it undocumented until needed) and use it in core blocks. I'm a bit concerned with the too many data-* attributes we'll end up with.

Copy link
Contributor

Choose a reason for hiding this comment

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

In all cases, blocks should be aware of the existence of a wrapper div, thus, I think we should move the getBlockAttributesAsProps function to the block API. Each block could decide to add any attribute to its parent div.

Copy link
Member Author

Choose a reason for hiding this comment

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

In all cases, blocks should be aware of the existence of a wrapper div, thus, I think we should move the getBlockAttributesAsProps function to the block API. Each block could decide to add any attribute to its parent div.

Yeah, I considered that, and it makes more sense now that I reflect on how the styles already make it clear that the block must be aware of the wrapper element. Your suggestion also addresses worries of computing and assigning attributes unnecessarily, dealing with complex attribute types (more accurately, not dealing with), and lends more flexibility to the block to define different / additional props to apply.

Copy link
Member Author

Choose a reason for hiding this comment

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

I bounced back and forth on a few names, or whether this could somehow be integrated into the edit function itself (via callback, or a special shaped return value including metadata).

How does getEditWrapperProps sound to you?

Copy link
Contributor

Choose a reason for hiding this comment

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

It's a good name for now but could be changed later if we settle on changing the edit name

@aduth
Copy link
Member Author

aduth commented Apr 26, 2017

The approach I took in 7fd79a1 is to encode block attributes as data-* attributes of the wrapper element, applying float styles from the image block's stylesheet. I'm not totally sold on this; styles must be aware of existence and class syntax of wrapper, can't encode non-simple types, etc. But I think it's a good compromise to grant some additional wrapper control options to the block.

So now there's float-y goodness:

float

@aduth aduth merged commit d2dd9f7 into master Apr 26, 2017
@aduth aduth deleted the update/image-alignment branch April 26, 2017 18:58
* @param {string} align Alignment value
* @return {Function} Attribute setter
*/
function applyOrUnset( align ) {
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't this just be toggle? :D

Copy link
Member Author

@aduth aduth Apr 26, 2017

Choose a reason for hiding this comment

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

You're too slow @mtias *! But yeah, toggle is appropriate too.

Edit: * Re: Having been merged seconds prior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Block API API that allows to express the block paradigm. [Feature] Blocks Overall functionality of blocks 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.

6 participants