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

SwatchTooltip component #956

Merged
merged 21 commits into from
Mar 26, 2019
Merged

SwatchTooltip component #956

merged 21 commits into from
Mar 26, 2019

Conversation

supernova-at
Copy link
Contributor

@supernova-at supernova-at commented Feb 25, 2019

Description

This PR adds a new SwatchTooltip component and uses it in the ProductOptions views (product page and edit mini cart item).

It updates the closed #712.

Related Issue

Closes #700 .

Motivation and Context

There was a UAT ticket for providing these tooltips.

How Has This Been Tested?

yarn test and manually on the product pages (PDPs) and in the mini-cart edit item dialog.

Screenshots (if appropriate):

image

Proposed Labels for Change Type/Package

FEATURE

venia-concept

Checklist:

  • I have read the CONTRIBUTING document.
  • I have linked an issue to this PR.
  • I have indicated the change type and relevant package(s).
  • I have updated the documentation accordingly.
  • I have added tests to cover my changes.
  • All new and existing tests passed.
  • All CI checks are green (linting, build/deploy, etc).
  • At least one core contributor has approved this PR.

@coveralls
Copy link

coveralls commented Feb 25, 2019

Coverage Status

Coverage decreased (-0.1%) to 76.533% when pulling 1518dc2 on supernova/700 into 1272fe7 on develop.

Copy link

@soumya-ashok soumya-ashok left a comment

Choose a reason for hiding this comment

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

Had a look at the implementation. The left and right padding around the label needs to be reduced, and the vertical padding increased. On second thought, off-center tip makes the tooltip look unbalanced.

Would centering the tip cause any issues with display when the tooltip needs to appear on the swatch at the left edge of the screen?

screen shot 2019-02-28 at 10 16 50 am

@supernova-at supernova-at changed the base branch from release/2.0 to develop March 6, 2019 17:05
Copy link
Contributor

@zetlen zetlen left a comment

Choose a reason for hiding this comment

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

Confirmed that this looks great in:

  • Chrome
  • Safari
  • Firefox
  • Edge
  • iOS Simulator
  • Android Emulator

One little prop type issue and then this is good to merge.

@supernova-at
Copy link
Contributor Author

Had a look at the implementation. The left and right padding around the label needs to be reduced, and the vertical padding increased. On second thought, off-center tip makes the tooltip look unbalanced.

Totally agree.

Would centering the tip cause any issues with display when the tooltip needs to appear on the swatch at the left edge of the screen?

It would, yeah. Would you mind if we merged this now and I create a follow up ticket to address these concerns?

@soumya-ashok
Copy link

soumya-ashok commented Mar 14, 2019

@supernova-at Sure, as long as we fix the issues I'm fine with changes being addressed in a follow-up ticket. I changed the status to "approved" for my review.

soumya-ashok
soumya-ashok previously approved these changes Mar 14, 2019
@supernova-at
Copy link
Contributor Author

As long as we fix the issues I'm fine with changes being addressed in a follow-up ticket.

@soumya-ashok Awesome - created #1024 for follow up.

Copy link
Contributor

@sirugh sirugh left a comment

Choose a reason for hiding this comment

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

This looks good, but I think we have an opportunity for an a11y win here. Below are some basic guidelines for tooltips from WAI-ARIA.

  • The tooltip never receives focus. Focus stays on the textbox.
  • The tooltip widget can shown via keyboard focus or by the onmouse event.
  • The tooltip widget can be hidden by removing focus from the text box or by moving the mouse off the textbox.
  • The tooltip widget can be hidden by pressing the Escape key
  • The tooltip is only hidden via JavaScript and CSS selectors. If JavaScript is not available the tooltip is shown.
  • The element that serves as the tooltip container has role tooltip.
  • The element that triggers the tooltip references the tooltip element with aria-describedby.

@supernova-at
Copy link
Contributor Author

we have an opportunity for an a11y win here

Any chance I could convince you to allow this in the followup ticket? 😄

@sirugh
Copy link
Contributor

sirugh commented Mar 14, 2019

Any chance I could convince you to allow this in the followup ticket?

I don't think it's that much work to add. role="tooltip" and aria-describedby="<id>" are easy enough. The focus things are also easy I think, probably just removing z-index. Heck I've got downtime so I could look into it tomorrow if you want. Just let me know :D

@jimbo
Copy link
Contributor

jimbo commented Mar 14, 2019

Had a look at the implementation. The left and right padding around the label needs to be reduced, and the vertical padding increased. On second thought, off-center tip makes the tooltip look unbalanced.

Agreed on all points.

@supernova-at
Copy link
Contributor Author

supernova-at commented Mar 18, 2019

In progress....

  • The tooltip never receives focus. Focus stays on the textbox.

  • The tooltip widget can shown via keyboard focus or by the onmouse event.
    This one's a little weird at first because you could have focus on one element and be mousing over another, causing two tooltips to show simultaneously.

  • The tooltip widget can be hidden by removing focus from the text box or by moving the mouse off the textbox.

  • The tooltip widget can be hidden by pressing the Escape key

  • The tooltip is only hidden via JavaScript and CSS selectors. If JavaScript is not available the tooltip is shown.
    Venia depends entirely on JavaScript being available so this one is invalid for us.

  • The element that serves as the tooltip container has role tooltip.

  • The element that triggers the tooltip references the tooltip element with aria-describedby.

@vercel
Copy link

vercel bot commented Mar 20, 2019

This pull request is automatically deployed with Now.
To access deployments, click Details below or on the icon next to each push.

};

onKeyDown = event => {
if (event.key === 'Escape') {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
if (event.key === 'Escape') {
if (event.key === 'Escape' || event.key === 'Tab') {

This would also hide it if you are moused in and then press tab. This could present an issue wherein there are focusable children within the button, imagine some text within the swatch, and pressing Tab should move focus to the text and keep the tooltip above the swatch.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This suggestion would help solve the problem of multiple tooltips showing at the same time. This occurs when one Swatch has focus and another is being moused over.

But it may not be worth the effort.

  1. We'd have to add logic to SwatchTooltip to workaround the new issue that it would present, which would be duplicating a lot of what blur is supposed to tell us.
  2. Since this isn't a form, users usually aren't navigating with keyboard and mouse.

We could add some sort of TooltipController component that ensures that only one tooltip is showing at a time, but that seems like overkill too.

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree, it's not worth the effort. The intentions are good here—accessibility is important—but reimplementing keyboard navigation is generally a sign that we're using the wrong elements in the first place.

Rather than a list of <button> elements, product options (including swatches) should really be radio buttons, in part because this really is a form. The native mechanisms browsers have for navigating forms are actually really comprehensive, and we should be using them.

Copy link
Contributor

Choose a reason for hiding this comment

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

Generally speaking, if the expected behavior is that only one tooltip can be open at a time, then it's not local state: it's shared state. So it sounds like this situation does call for a "controller". Context is good for this purpose.

Copy link
Contributor

Choose a reason for hiding this comment

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

At my last company we had a FocusManager component that handled this sort of thing. Probably a bit overkill for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jimbo great points all around.

if the expected behavior is that only one tooltip can be open at a time

This is the piece I'm iffy about. I mean, it sounds right but it is also a pretty rare occurrence so I lean towards "out of scope" here. When this thing makes it into Peregrine we can definitely generalize and make improvements to it.

What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

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

When this thing makes it into Peregrine we can definitely generalize and make improvements to it.

Yeah, that's probably the right approach.

…in the SwatchTooltip component.

- Also updates affected snapshots
@supernova-at
Copy link
Contributor Author

PR Updated:

  • Removes erroneous className composition during cloneElement

sirugh
sirugh previously approved these changes Mar 20, 2019
};

onKeyDown = event => {
if (event.key === 'Escape') {
Copy link
Contributor

Choose a reason for hiding this comment

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

I agree, it's not worth the effort. The intentions are good here—accessibility is important—but reimplementing keyboard navigation is generally a sign that we're using the wrong elements in the first place.

Rather than a list of <button> elements, product options (including swatches) should really be radio buttons, in part because this really is a form. The native mechanisms browsers have for navigating forms are actually really comprehensive, and we should be using them.

onMouseLeave: over([
child.props.onMouseLeave,
this.onMouseLeave
])
Copy link
Contributor

Choose a reason for hiding this comment

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

I've never seen this pattern before. Ordinarily, you would call the props callback from the class handler. Any reason we shouldn't do that here?

Also, by convention, class handlers are named handleEvent rather than onEvent.

class Foo extends Component {
  handleClick = event => {
    const { id, onClick } = this.props

    // this component's business
    event.preventDefault()

    // its parent's business
    // note: event object is treated as private
    // callback gets only what it needs
    if (typeof onClick === "function") {
      onClick(id)
    }
  }

  render() {
    const { handleClick } = this

    return <button onClick={handleClick} />
  }
}

Copy link
Contributor Author

@supernova-at supernova-at Mar 21, 2019

Choose a reason for hiding this comment

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

Yeah that's a good call - the reason this particular case is different is because this SwatchTooltip component is the parent, not the child.

In other words:

<SwatchTooltip>
  <Swatch />
</SwatchTooltip>

So for a given event handler - let's say onClick - SwatchTooltip (the parent) wants its handler executed while also executing the Swatch (child)'s handler.

I suppose I could do something like

    onMouseOver = () => {
        // parent business.
        this.setState({ isShowing: true });

        // child business.
        const child = this.getChild(); // some logic that uses React.Children to get the right one
        if (child.props.onMouseOver) {
          child.props.onMouseOver();
        }
    };

and repeat that pattern for each event handler.

I'm mostly just trying to avoid tightly coupling these components.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm mostly just trying to avoid tightly coupling these components.

Why's that? It seems to me that the tooltip should be a child of the Swatch, rendered by Swatch, and pretty coupled to it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why's that? It seems to me that the tooltip should be a child of the Swatch, rendered by Swatch, and pretty coupled to it.

Good point, that would definitely make things much simpler here. In the future we may want a generic Tooltip component like this, but that's out of scope here.

};

onKeyDown = event => {
if (event.key === 'Escape') {
Copy link
Contributor

Choose a reason for hiding this comment

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

Generally speaking, if the expected behavior is that only one tooltip can be open at a time, then it's not local state: it's shared state. So it sounds like this situation does call for a "controller". Context is good for this purpose.

}

/* The tooltip triangle that points down. */
.tooltip:before {
Copy link
Contributor

Choose a reason for hiding this comment

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

Love me some pseudo-element triangles.

@sirugh sirugh removed their assignment Mar 21, 2019
@sirugh
Copy link
Contributor

sirugh commented Mar 25, 2019

We're going to merge this with the caveat that we try to figure out how to invert the parent-child relationship of the ToolTip component.

@vercel vercel bot temporarily deployed to staging March 26, 2019 14:28 Inactive
@sirugh sirugh merged commit 48dabc1 into develop Mar 26, 2019
@sirugh sirugh deleted the supernova/700 branch March 26, 2019 16:00
@sirugh sirugh removed their assignment Mar 26, 2019
@sirugh sirugh mentioned this pull request Mar 27, 2019
8 tasks
@sirugh sirugh added the version: Minor This changeset includes functionality added in a backwards compatible manner. label May 24, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
version: Minor This changeset includes functionality added in a backwards compatible manner.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

UAT: Color Swatches Missing Tooltips
8 participants