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

Added contrast verification to paragraph colors #3483

Merged
merged 5 commits into from
Nov 24, 2017

Conversation

jorgefilipecosta
Copy link
Member

Description

This PR aims to address the remaining part of #2381, by adding a contrast checking following WCAG 2.0- AA (https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-contrast.html) to the paragraph.

How Has This Been Tested?

Test some colors in the paragraph and verify that when contrast is high no message, in low contrast color pairs a message appear.
Verify that when the background is darker than text, we suggest making the background darker and/or the text lighter and when text is darker we suggest making the text darker and/or background lighter.
Verify that for some color pairs e.g. background #C46161 and black text or our blue with no background the message does not appear, if the font size is equal or larger than 18 and the message appears if the font size is smaller.

Screenshots (jpeg or gifs if applicable):

nov-14-2017 17-07-04
nov-14-2017 17-07-19

@jorgefilipecosta jorgefilipecosta added the [Status] In Progress Tracking issues with work in progress label Nov 14, 2017
@jorgefilipecosta jorgefilipecosta self-assigned this Nov 14, 2017
@jorgefilipecosta jorgefilipecosta changed the title Added contrast verification paragraph Added contrast verification to paragraph colors Nov 14, 2017
this.grabTextColor();
}

grabTextColor() {
Copy link
Member

Choose a reason for hiding this comment

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

@jorgefilipecosta have you considered factoring out color related logic into a higher-order component? It looks very familiar to the implementation of the button. In both cases, we have text color and background color that are compared. From what I see this wrapper component could handle:

  • node
  • editableRef
  • state
  • bindRef
  • grabTextColor
  • componentDidMount & componentDidUpdate

</PanelBody>
<ContrastChecker
textColor={ textColor || fallbackTextColor }
backgroundColor={ backgroundColor || '#fff' }
Copy link
Member

Choose a reason for hiding this comment

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

Is there a plan to add fallback logic to backgroundColor, too? Or maybe it is always white anyway :)

Copy link
Member Author

Choose a reason for hiding this comment

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

That's a nice question, I used a logic for background color but, the getComputeStyle always returned black, while the background is white If background color was explicitly set the getComputedSyle returned correctly. So I assumed the background when not explicitly set is white.

Copy link
Member

@gziolo gziolo Nov 15, 2017

Choose a reason for hiding this comment

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

Better try to change it using CSS. It is possible that an external plugin would apply such change.

@gziolo
Copy link
Member

gziolo commented Nov 15, 2017

This is a really cool feature 💯 The code looks good from what I can see, I left a suggestion to extract a higher order component to hide the logic related to the color pickers. Anyway if you feel that the current solution works better in this case, let me know and I will do more in-depth code check.

@jorgefilipecosta jorgefilipecosta force-pushed the add/contrast-verification-paragraph branch 6 times, most recently from c7bdf26 to 4d03540 Compare November 15, 2017 22:18
@jorgefilipecosta
Copy link
Member Author

Hi @gziolo, I followed your advice and I created a High Order Component to abstract part of the common logic withFallbackStyles. Some parts change from block to block and I was not able to abstract.
If we decide to follow this approach I will add a readme and tests to the HoC. Feel free to have a new look :)

const ButtonBlockFallbackStyles = withFallbackStyles( ( node, ownProps ) => {
const { textColor, color } = ownProps.attributes;
return {
fallbackBackgroundColor: color ? undefined : getComputedStyle( node.querySelector( `.${ ownProps.className }` ) ).backgroundColor,
Copy link
Member

Choose a reason for hiding this comment

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

Alternatively, you can use span[key="button"] as a query selector.

Copy link
Member Author

Choose a reason for hiding this comment

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

Hi @gziolo, I tried this approach, but unfortunately react element keys are not passed to the dom (possible to confirm using browser dev tools), so this query selector was not returning and I end up not applying this change.

Copy link
Member

Choose a reason for hiding this comment

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

Fair enough 👍

const { textColor, backgroundColor } = ownProps.attributes;
const computedStyles = ( ! textColor || ! backgroundColor ) ? getComputedStyle( node.querySelector( '[contenteditable="true"]' ) ) : null;
return {
fallbackBackgroundColor: backgroundColor ? undefined : computedStyles.backgroundColor,
Copy link
Member

Choose a reason for hiding this comment

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

Can you explain why we set undefined when color is passed as a prop? From what I can see we can safely set it, but it will be ignored. It would make reading code easier if we would always compute it even when it's not used. Unless I missed something.

Copy link
Member Author

Choose a reason for hiding this comment

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

If there are custom colors set the fallbackColors will be equal to the custom colors set. As we have a logic that stops grabbing colors when we have all fallbackColors needed, if later we remove the custom colors, the fallbackColors are not updated and would still be equal to the custom colors set the first time instead of the colors that appear when no custom color is selected.

@@ -18,3 +18,7 @@ p.has-drop-cap:not( :focus ) {
p.has-background {
padding: 20px 30px;
}

.wp-block-paragraph {
Copy link
Member

Choose a reason for hiding this comment

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

@jasmussen or @karmatosed, is it okey to set it explicitly here?


grabFallbackStyles() {
const { grabStylesCompleted, fallbackStyles } = this.state;
if ( this.nodeRef && ! grabStylesCompleted ) {
Copy link
Member

Choose a reason for hiding this comment

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

Can you explain why we need to use grabStylesCompleted in here? Can we check if fallbackStyles is still undefined instead? It looks like you can always compute grabStylesCompleted using the existing variables.

Copy link
Member Author

Choose a reason for hiding this comment

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

Hi @gziolo, for example in button we may have set a custom text color, so we can not compute the fallbackTextColor but we can compute the fallbackBackgroudColor. So our mapNodeToProps returns undefined for the properties it cannot compute the fallback color (fallbackTextColor). When there is no undefined value ( ! findKey( newFallbackStyles, ( obj ) => obj === undefined ) ) = true we know we don't need to grab colors anymore. The value of this is saved in grabStylesCompleted so we are not running this line with findKey all the time.

Another advantage is when inserting a component no custom colors are set so all fallback colors are immediately saved and logic to grab color is just executed one time.

Copy link
Member

@gziolo gziolo Nov 16, 2017

Choose a reason for hiding this comment

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

Would it work if you would use every from lodash instead of findKey:

every( newFallbackStyles )

It might better express intent.

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 agree using "every" would make things simpler to understand, but I think we can not use it here. Every works on a collection here we are working a single object and we just want to make sure there is no key/property of that object that is undefined.

Copy link
Member

@gziolo gziolo Nov 17, 2017

Choose a reason for hiding this comment

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

This is a perfectly fine usage

every( { a: true, b: 1, c: undefined } );

It works with with both arrays and objects:

collection (Array|Object): The collection to iterate over.

Some utility methods that operate on collections, work with strings, too. See includes.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thank you for your suggestion @gziolo you were right and your suggestion was applied before merging.

@gziolo
Copy link
Member

gziolo commented Nov 16, 2017

It works perfectly fine, great job. Thanks for doing all refinements.

Now, seeing all that logic extracted, I started to think if we can take a slightly different approach and wrap HOC directly on < ContrastChecker /> component.

What if you would be able to use it as follows:

<ContrastCheckerWithFallbackStyles
	node={ this.nodeRef } 
	textColor={ textColor }
	backgroundColor={ backgroundColor }
	isLargeText={ true }
	/>

This way the contrast checker would only have a reference to the node to compute fallbacks when necessary.

Anyway, I'm also fine with what we aleady have here. 👍

@jorgefilipecosta jorgefilipecosta force-pushed the add/contrast-verification-paragraph branch 2 times, most recently from 4564831 to 54ac133 Compare November 16, 2017 13:18
@codecov
Copy link

codecov bot commented Nov 16, 2017

Codecov Report

Merging #3483 into master will decrease coverage by 0.05%.
The diff coverage is 8.92%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #3483      +/-   ##
==========================================
- Coverage   37.15%   37.09%   -0.06%     
==========================================
  Files         275      276       +1     
  Lines        6629     6653      +24     
  Branches     1202     1210       +8     
==========================================
+ Hits         2463     2468       +5     
- Misses       3517     3528      +11     
- Partials      649      657       +8
Impacted Files Coverage Δ
blocks/contrast-checker/index.js 0% <0%> (ø) ⬆️
...ponents/higher-order/with-fallback-styles/index.js 11.11% <11.11%> (ø)
blocks/library/button/index.js 14.7% <14.28%> (+5.4%) ⬆️
blocks/library/paragraph/index.js 23.07% <7.14%> (-6.09%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update bccede6...22d59ba. Read the comment docs.

@jorgefilipecosta
Copy link
Member Author

jorgefilipecosta commented Nov 16, 2017

Now, seeing all that logic extracted, I started to think if we can take a slightly different approach and wrap HOC directly on < ContrastChecker /> component.

Hi @gziolo, I did a new commit that uses this approach instead :) It has the advantage of not color grabbing logic being executed at all if contrast verification is not needed. No changes were needed in our HoC, and the only change applied in the contrast verifier was adding the fallbackColors properties directly to it (optional props).

Copy link
Member

@gziolo gziolo left a comment

Choose a reason for hiding this comment

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

I’ll test again tomorrow, it looks great at the moment. I really like how independent contrast checker component became 👏

Copy link
Member

@gziolo gziolo left a comment

Choose a reason for hiding this comment

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

Code wise looks good to me. It also works as advertised.

I would also suggest asking @afercia or @nic-bertino to verify if it works as expected before you merge it.

@jorgefilipecosta jorgefilipecosta added Needs Design Feedback Needs general design feedback. [Type] Enhancement A suggestion for improvement. and removed [Status] In Progress Tracking issues with work in progress labels Nov 20, 2017
@karmatosed
Copy link
Member

Let's get the conflicts resolved on this and then merge, it's better than what we have right now so worth getting in.

@jorgefilipecosta jorgefilipecosta force-pushed the add/contrast-verification-paragraph branch 3 times, most recently from e9bd575 to 5e7d630 Compare November 24, 2017 16:17
@jorgefilipecosta jorgefilipecosta force-pushed the add/contrast-verification-paragraph branch from 5e7d630 to 22d59ba Compare November 24, 2017 16:35
@jorgefilipecosta jorgefilipecosta merged commit a432882 into master Nov 24, 2017
@jorgefilipecosta jorgefilipecosta deleted the add/contrast-verification-paragraph branch November 24, 2017 16:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs Design Feedback Needs general design feedback. [Type] Enhancement A suggestion for improvement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants